"use client"; import { useState, useCallback } from "react"; import { type SegmentRuleV2, type SegmentFilter, type SegmentFilterType, type SegmentFilterParams, } from "@/actions/harvest-reach/segments"; import { AdminButton, AdminSearchInput } from "@/components/admin/design-system"; // Icon components const Icons = { x: (className: string) => ( ), }; type Props = { brandId: string; rules: SegmentRuleV2; onChange: (rules: SegmentRuleV2) => void; onSave: () => void; hasActiveSegment: boolean; }; const FILTER_TYPES: { value: SegmentFilterType; label: string }[] = [ { value: "all_customers", label: "All Customers" }, { value: "stop", label: "Past Stop" }, { value: "upcoming_stop", label: "Upcoming Stop" }, { value: "product", label: "Product Purchased" }, { value: "zip_code", label: "ZIP / City" }, { value: "customer_history", label: "Order History" }, { value: "tags", label: "Tags" }, ]; const ORDER_HISTORY_OPTIONS = [ { value: "all", label: "All customers" }, { value: "first_order", label: "First-time buyers" }, { value: "repeat", label: "Repeat buyers" }, ]; function emptyFilter(type: SegmentFilterType): SegmentFilter { const params: SegmentFilterParams = {}; if (type === "product") params.days_back = 90; if (type === "customer_history") { params.order_history = "all"; params.days_back = 90; } if (type === "stop" || type === "upcoming_stop") { params.date_from = ""; params.date_to = ""; } if (type === "zip_code") { params.zip_codes = []; params.city = ""; } if (type === "tags") params.tags = []; return { type, params }; } export default function SegmentBuilderPanel({ brandId, rules, onChange, onSave, hasActiveSegment }: Props) { const setCombinator = useCallback((combinator: "AND" | "OR") => { onChange({ ...rules, combinator }); }, [rules, onChange]); function updateFilter(index: number, updates: Partial) { const newFilters = rules.filters.map((f, i) => i === index ? { ...f, ...updates, params: { ...f.params, ...(updates.params ?? {}) } } : f ); onChange({ ...rules, filters: newFilters }); } function removeFilter(index: number) { onChange({ ...rules, filters: rules.filters.filter((_, i) => i !== index) }); } function addFilter(type: SegmentFilterType) { onChange({ ...rules, filters: [...rules.filters, emptyFilter(type)] }); } return (
{/* Header */}

Filter Rules

Match
{(["AND", "OR"] as const).map((c) => ( ))}
of the following
{/* Filter blocks */}
{rules.filters.length === 0 && (

No filters yet. Add a filter below to start building your segment.

)} {rules.filters.map((filter, index) => ( updateFilter(index, updates)} onRemove={() => removeFilter(index)} /> ))}
{/* Add filter chips */}
{FILTER_TYPES.map((ft) => ( ))}
{/* Save button */}
{hasActiveSegment ? "Update Segment" : "Save Segment"}
); } // ─── Filter Block ───────────────────────────────────────────── type FilterBlockProps = { brandId: string; filter: SegmentFilter; onChange: (updates: Partial) => void; onRemove: () => void; }; function FilterBlock({ brandId, filter, onChange, onRemove }: FilterBlockProps) { const [products, setProducts] = useState<{ id: string; name: string }[]>([]); const [stops, setStops] = useState<{ id: string; city: string; date: string }[]>([]); const [productsLoaded, setProductsLoaded] = useState(false); const [stopsLoaded, setStopsLoaded] = useState(false); function loadProducts() { if (productsLoaded) return; import("@/actions/harvest-reach/products").then((m) => { m.getProductsForSegmentPicker(brandId).then((data) => { setProducts(data); setProductsLoaded(true); }); }); } function loadStops(past: boolean) { if (stopsLoaded) return; import("@/actions/harvest-reach/stops").then((m) => { m.getStopsForSegmentPicker(brandId).then((data) => { setStops(data.filter((s) => past ? s.is_past : s.is_upcoming)); setStopsLoaded(true); }); }); } return (
{/* Stop / Upcoming Stop */} {(filter.type === "stop" || filter.type === "upcoming_stop") && ( <>
onChange({ params: { ...filter.params, date_from: e.target.value } })} className="border border-[var(--admin-border)] rounded-lg px-3 py-2 text-sm bg-white outline-none focus:ring-2 focus:ring-[var(--admin-accent)] focus:border-[var(--admin-accent)]" /> onChange({ params: { ...filter.params, date_to: e.target.value } })} className="border border-[var(--admin-border)] rounded-lg px-3 py-2 text-sm bg-white outline-none focus:ring-2 focus:ring-[var(--admin-accent)] focus:border-[var(--admin-accent)]" />
)} {/* Product */} {filter.type === "product" && ( <>
onChange({ params: { ...filter.params, days_back: parseInt(e.target.value) } })} className="border border-[var(--admin-border)] rounded-lg px-2.5 py-1.5 text-sm w-20 bg-white outline-none focus:ring-2 focus:ring-[var(--admin-accent)] focus:border-[var(--admin-accent)]" /> days
)} {/* ZIP / City */} {filter.type === "zip_code" && ( <> onChange({ params: { ...filter.params, zip_codes: e.target.value.split(",").map((z) => z.trim()).filter(Boolean), }, }) } className="border border-[var(--admin-border)] rounded-lg px-3 py-2 text-sm bg-white outline-none focus:ring-2 focus:ring-[var(--admin-accent)] focus:border-[var(--admin-accent)]" /> onChange({ params: { ...filter.params, city: e.target.value } })} className="border border-[var(--admin-border)] rounded-lg px-3 py-2 text-sm bg-white outline-none focus:ring-2 focus:ring-[var(--admin-accent)] focus:border-[var(--admin-accent)]" /> )} {/* Customer History */} {filter.type === "customer_history" && (
onChange({ params: { ...filter.params, days_back: parseInt(e.target.value) } })} className="border border-[var(--admin-border)] rounded-lg px-2.5 py-1.5 text-sm w-20 bg-white outline-none focus:ring-2 focus:ring-[var(--admin-accent)] focus:border-[var(--admin-accent)]" /> days
)} {/* Tags */} {filter.type === "tags" && ( onChange({ params: { ...filter.params, tags: e.target.value.split(",").map((t) => t.trim()).filter(Boolean), }, }) } className="border border-[var(--admin-border)] rounded-lg px-3 py-2 text-sm bg-white outline-none focus:ring-2 focus:ring-[var(--admin-accent)] focus:border-[var(--admin-accent)]" /> )} {/* All customers */} {filter.type === "all_customers" && (

Matches all customers in your brand.

)}
); }