'use client' import { useState, useMemo } from 'react' import Link from 'next/link' import { Card, CardContent, CardDescription, CardHeader, CardTitle, } from '@/components/ui/card' import { Button } from '@/components/ui/button' import { Input } from '@/components/ui/input' import { useCustomers } from '@/hooks/use-customers' import { UserStatus as ApiUserStatus } from '@/types/api' import { Search, Plus, MoreHorizontal, User, Mail, Building2, Calendar, Server, ExternalLink, ChevronLeft, ChevronRight, Loader2, AlertCircle, RefreshCw, } from 'lucide-react' type UserStatus = 'ACTIVE' | 'SUSPENDED' | 'PENDING_VERIFICATION' type SubscriptionStatus = 'TRIAL' | 'ACTIVE' | 'CANCELED' | 'PAST_DUE' interface Customer { id: string name: string email: string company: string | null status: UserStatus subscription: { plan: string tier: string status: SubscriptionStatus tokensUsed: number tokenLimit: number } | null activeServers: number createdAt: string } // Status badge component function UserStatusBadge({ status }: { status: UserStatus }) { const statusConfig: Record = { ACTIVE: { label: 'Active', className: 'bg-green-100 text-green-800' }, SUSPENDED: { label: 'Suspended', className: 'bg-red-100 text-red-800' }, PENDING_VERIFICATION: { label: 'Pending', className: 'bg-yellow-100 text-yellow-800' }, } const config = statusConfig[status] return ( {config.label} ) } function SubscriptionBadge({ status }: { status: SubscriptionStatus }) { const statusConfig: Record = { TRIAL: { label: 'Trial', className: 'bg-blue-100 text-blue-800' }, ACTIVE: { label: 'Active', className: 'bg-green-100 text-green-800' }, CANCELED: { label: 'Canceled', className: 'bg-gray-100 text-gray-800' }, PAST_DUE: { label: 'Past Due', className: 'bg-red-100 text-red-800' }, } const config = statusConfig[status] return ( {config.label} ) } // Customer table row component function CustomerRow({ customer }: { customer: Customer }) { return (
{customer.name}
{customer.email}
{customer.company ? (
{customer.company}
) : ( - )} {customer.subscription ? (
{customer.subscription.plan.toLowerCase()}
{customer.subscription.tier.replace('_', ' ').toLowerCase()}
) : ( No subscription )} {customer.subscription ? (
{customer.subscription.tokensUsed.toLocaleString()} /{' '} {customer.subscription.tokenLimit.toLocaleString()}
) : ( - )}
{customer.activeServers}
{new Date(customer.createdAt).toLocaleDateString()}
) } export default function CustomersPage() { const [search, setSearch] = useState('') const [statusFilter, setStatusFilter] = useState('all') const [currentPage, setCurrentPage] = useState(1) const itemsPerPage = 10 // Fetch customers from API const { data, isLoading, isError, error, refetch, isFetching, } = useCustomers({ search: search || undefined, status: statusFilter !== 'all' ? statusFilter as ApiUserStatus : undefined, page: currentPage, limit: itemsPerPage, }) // Map API customers to component format const customers = useMemo(() => { if (!data?.customers) return [] return data.customers.map((c) => ({ id: c.id, name: c.name || c.email, email: c.email, company: c.company, status: c.status as UserStatus, subscription: c.subscriptions?.[0] ? { plan: c.subscriptions[0].plan, tier: c.subscriptions[0].tier, status: c.subscriptions[0].status as SubscriptionStatus, tokensUsed: 0, // Not included in list response tokenLimit: 0, // Not included in list response } : null, activeServers: c._count?.orders || 0, createdAt: String(c.createdAt), })) }, [data?.customers]) // Calculate stats from API data const stats = useMemo(() => ({ total: data?.pagination?.total || 0, active: customers.filter((c) => c.status === 'ACTIVE').length, trial: customers.filter((c) => c.subscription?.status === 'TRIAL').length, totalServers: customers.reduce((acc, c) => acc + c.activeServers, 0), }), [customers, data?.pagination?.total]) const totalPages = data?.pagination?.totalPages || 1 // Loading state if (isLoading) { return (

Loading customers...

) } // Error state if (isError) { return (

Failed to load customers

{error instanceof Error ? error.message : 'An error occurred'}

) } return (
{/* Page header */}

Customers

Manage customer accounts and subscriptions

{/* Stats cards */}
{stats.total}

Total Customers

{stats.active}

Active

{stats.trial}

On Trial

{stats.totalServers}

Total Servers

{/* Filters and table */}
All Customers {data?.pagination?.total || 0} customer{(data?.pagination?.total || 0) !== 1 ? 's' : ''} found
{ setSearch(e.target.value) setCurrentPage(1) // Reset to first page on search }} className="pl-9 w-full sm:w-64" />
{customers.length === 0 ? (

No customers found

{(search || statusFilter !== 'all') && ( )}
) : ( <>
{customers.map((customer) => ( ))}
Customer Company Status Subscription Token Usage Servers Joined Actions
{/* Pagination */} {totalPages > 1 && (

Page {currentPage} of {totalPages}

)} )}
) }