import Link from "next/link" import { fetchQuery } from "convex/nextjs" import { ContactRound, Search } from "lucide-react" import { api } from "@/convex/_generated/api" import { Badge } from "@/components/ui/badge" import { Button } from "@/components/ui/button" import { Card, CardContent, CardDescription, CardHeader, CardTitle, } from "@/components/ui/card" import { Input } from "@/components/ui/input" type PageProps = { searchParams: Promise<{ search?: string page?: string }> } function formatTimestamp(value?: number) { if (!value) { return "—" } return new Date(value).toLocaleString("en-US", { month: "short", day: "numeric", year: "numeric", hour: "2-digit", minute: "2-digit", }) } function getSyncMessage(sync: any) { if (!sync.ghlConfigured) { return "Connect GHL to load contacts and conversations." } if (sync.stages.contacts.status === "running") { return "Contacts are syncing now." } if (sync.stages.contacts.error) { return "Contacts could not be loaded from GHL yet." } if (!sync.latestSyncAt) { return "No contacts yet." } return "Your contact list stays up to date from forms, calls, and GHL." } export default async function AdminContactsPage({ searchParams }: PageProps) { const params = await searchParams const page = Math.max(1, Number.parseInt(params.page || "1", 10) || 1) const search = params.search?.trim() || undefined const data = await fetchQuery(api.crm.listAdminContacts, { search, page, limit: 25, }) return (

Contacts

All customer contacts in one place.

Sync Status {getSyncMessage(data.sync)} {data.sync.overallStatus} Last sync: {formatTimestamp(data.sync.latestSyncAt || undefined)} {!data.sync.ghlConfigured ? ( GHL is not connected. ) : null} {!data.sync.syncTokenConfigured ? ( Manual sync endpoint is not configured yet. ) : null} {data.sync.stages.contacts.error ? ( {data.sync.stages.contacts.error} ) : null} Contact Directory Search by name, email, phone, company, or tag.
{data.items.length === 0 ? ( ) : ( data.items.map((contact: any) => ( )) )}
Contact Company Status Conversations Leads Last Activity Open
{search ? "No contacts matched this search." : getSyncMessage(data.sync)}
{contact.firstName} {contact.lastName}
{contact.email || "No email"}
{contact.phone || "No phone"}
{contact.company || "—"} {contact.status} {contact.conversationCount} {contact.leadCount} {formatTimestamp(contact.lastActivityAt)}
) } export const metadata = { title: "Contacts | Admin", description: "View Rocky customer contacts", }