"use client"; import { useState, useEffect, useRef } from "react"; import { type SegmentRuleV2, type PreviewResult } from "@/actions/harvest-reach/segments"; // Icon components const Icons = { users: (className: string) => ( ), search: (className: string) => ( ), spinner: (className: string) => ( ), chevronLeft: (className: string) => ( ), chevronRight: (className: string) => ( ), }; const DEBOUNCE_MS = 300; export default function MatchingCustomersPanel({ brandId, rules }: Props) { const [preview, setPreview] = useState(null); const [loading, setLoading] = useState(false); const [search, setSearch] = useState(""); const [page, setPage] = useState(0); const timerRef = useRef>(undefined); useEffect(() => { if (rules.filters.length === 0) { setPreview(null); return; } setLoading(true); clearTimeout(timerRef.current); timerRef.current = setTimeout(async () => { const { previewSegmentWithCustomers } = await import("@/actions/harvest-reach/segments"); const result = await previewSegmentWithCustomers(brandId, rules); setPreview(result); setLoading(false); setPage(0); }, DEBOUNCE_MS); return () => clearTimeout(timerRef.current); }, [brandId, rules]); const PAGE_SIZE = 50; const filtered = preview?.sample_customers ?? []; const searched = search ? filtered.filter( (c) => c.name.toLowerCase().includes(search.toLowerCase()) || c.email.toLowerCase().includes(search.toLowerCase()) ) : filtered; const total = preview?.count ?? 0; const paged = searched.slice(page * PAGE_SIZE, (page + 1) * PAGE_SIZE); return (

Matching Customers

{preview && ( {total.toLocaleString()} total )}
{rules.filters.length === 0 ? (
{Icons.users("w-10 h-10 text-[var(--admin-text-muted)] mx-auto mb-3")}

Add filters to see matching customers

) : loading ? (
{Icons.spinner("h-5 w-5 animate-spin")} Loading…
) : ( <>
{Icons.search("h-4 w-4 text-[var(--admin-text-muted)]")}
{ setSearch(e.target.value); setPage(0); }} className="w-full pl-10 pr-3 py-2 text-sm border border-[var(--admin-border)] rounded-lg bg-white text-[var(--admin-text-primary)] focus:ring-2 focus:ring-emerald-500 focus:border-emerald-500 outline-none" />
{paged.length === 0 ? (

No customers match these filters.

) : (
{paged.map((c) => (
{c.name ? c.name.slice(0, 2).toUpperCase() : "??"}

{c.name || "(no name)"}

{c.email}

{c.tags.length > 0 && (
{c.tags.slice(0, 2).map((tag) => ( {tag} ))}
)}
))}
)} {searched.length > PAGE_SIZE && (
Showing {page * PAGE_SIZE + 1}–{Math.min((page + 1) * PAGE_SIZE, searched.length)} of {searched.length}
)} )}
); } type Props = { brandId: string; rules: SegmentRuleV2; };