"use client"; import { useState, useMemo, useCallback, useEffect } from "react"; import Link from "next/link"; import { markPickupComplete } from "@/actions/pickup"; import { formatDate } from "@/lib/format-date"; import AdminBadge from "./design-system/AdminBadge"; import { AdminButton, AdminSearchInput, AdminFilterTabs, AdminIconButton, useToast } from "./design-system"; import { Skeleton } from "./design-system"; type OrderItem = { id: string; product_id: string; quantity: number; price: number; products: { name: string } | null; }; type Order = { id: string; customer_name: string; customer_email: string | null; customer_phone: string | null; stop_id: string | null; status: string; subtotal: number; pickup_complete: boolean; pickup_completed_at: string | null; pickup_completed_by: string | null; created_at: string; payment_processor: string | null; stops: { id?: string; city: string; state: string; date: string; brand_id?: string; } | null; order_items?: OrderItem[]; }; type Stop = { id: string; city: string; state: string; date: string; brand_id?: string; }; type AdminOrdersPanelProps = { initialOrders: Order[]; initialStops: Stop[]; brandId: string | null; }; type StatusTab = "all" | "pending" | "picked_up"; function shortId(id: string) { return id.slice(0, 8).toUpperCase(); } function formatCurrency(amount: number) { return new Intl.NumberFormat("en-US", { style: "currency", currency: "USD" }).format(amount); } // Icons const Icons = { mapPin: (className: string) => ( ), check: (className: string) => ( ), x: (className: string) => ( ), chevronDown: (className: string) => ( ), chevronLeft: (className: string) => ( ), chevronRight: (className: string) => ( ), package: (className: string) => ( ), selectAll: (className: string) => ( ), }; export default function AdminOrdersPanel({ initialOrders, initialStops, brandId, }: AdminOrdersPanelProps) { const { success: showSuccess, error: showError } = useToast(); const [orders, setOrders] = useState(initialOrders); const [stops] = useState(initialStops); const [search, setSearch] = useState(""); const [activeTab, setActiveTab] = useState("all"); const [selectedStops, setSelectedStops] = useState([]); const [showStopDropdown, setShowStopDropdown] = useState(false); const [pickingUp, setPickingUp] = useState(null); const [page, setPage] = useState(0); const [selectedOrders, setSelectedOrders] = useState>(new Set()); const [bulkMarkingUp, setBulkMarkingUp] = useState(false); const [isLoading, setIsLoading] = useState(false); const PAGE_SIZE = 20; // Simulate loading when orders change useEffect(() => { setIsLoading(true); const timer = setTimeout(() => setIsLoading(false), 300); return () => clearTimeout(timer); }, [page, activeTab, search, selectedStops.length]); const filteredOrders = useMemo(() => { return orders.filter((order) => { if (activeTab === "pending" && order.pickup_complete) return false; if (activeTab === "picked_up" && !order.pickup_complete) return false; if (selectedStops.length > 0 && order.stop_id && !selectedStops.includes(order.stop_id)) return false; if (search.trim()) { const s = search.toLowerCase(); if (!order.customer_name.toLowerCase().includes(s) && !(order.customer_phone ?? "").toLowerCase().includes(s) && !order.id.toLowerCase().includes(s)) return false; } return true; }); }, [orders, activeTab, selectedStops, search]); const totalPages = Math.ceil(filteredOrders.length / PAGE_SIZE); const paginatedOrders = filteredOrders.slice(page * PAGE_SIZE, (page + 1) * PAGE_SIZE); const pendingCount = orders.filter((o) => !o.pickup_complete).length; const pickedUpCount = orders.filter((o) => o.pickup_complete).length; // Bulk selection const toggleSelectAll = useCallback(() => { if (selectedOrders.size === paginatedOrders.length) { setSelectedOrders(new Set()); } else { setSelectedOrders(new Set(paginatedOrders.map(o => o.id))); } }, [selectedOrders.size, paginatedOrders]); const toggleOrderSelection = useCallback((orderId: string) => { setSelectedOrders(prev => { const next = new Set(prev); if (next.has(orderId)) { next.delete(orderId); } else { next.add(orderId); } return next; }); }, []); function toggleStop(stopId: string) { setSelectedStops((prev) => prev.includes(stopId) ? prev.filter((id) => id !== stopId) : [...prev, stopId] ); setPage(0); } function clearStops() { setSelectedStops([]); setPage(0); } async function handleMarkPickup(orderId: string) { setPickingUp(orderId); const result = await markPickupComplete(orderId, brandId); if (result.success) { showSuccess("Pickup confirmed", `${result.pickup_completed_at ? 'Order marked as picked up' : 'Success'}`); setOrders((prev) => prev.map((o) => o.id === orderId ? { ...o, pickup_complete: true, pickup_completed_at: result.pickup_completed_at, pickup_completed_by: result.pickup_completed_by } : o ) ); } else { showError("Failed to mark pickup", result.error ?? "Please try again"); } setPickingUp(null); } async function handleBulkMarkPickup() { if (selectedOrders.size === 0) return; setBulkMarkingUp(true); let successCount = 0; let failCount = 0; for (const orderId of selectedOrders) { const result = await markPickupComplete(orderId, brandId); if (result.success) { successCount++; setOrders((prev) => prev.map((o) => o.id === orderId ? { ...o, pickup_complete: true, pickup_completed_at: result.pickup_completed_at, pickup_completed_by: result.pickup_completed_by } : o ) ); } else { failCount++; } } setBulkMarkingUp(false); setSelectedOrders(new Set()); if (failCount === 0) { showSuccess(`${successCount} order${successCount !== 1 ? 's' : ''} marked as picked up`); } else { showError("Some orders failed", `${successCount} succeeded, ${failCount} failed`); } } return (
{/* Header */}
{Icons.package("h-5 w-5 text-white")}

Orders

{filteredOrders.length} order{filteredOrders.length !== 1 ? "s" : ""}

{brandId && ( Brand scoped )}
{/* Stats Cards */}

Total

{isLoading ? : orders.length}

Pending

{isLoading ? : pendingCount}

Picked Up

{isLoading ? : pickedUpCount}

{/* Filters */}
{/* Status Tabs */} { setActiveTab(value as StatusTab); setPage(0); }} tabs={[ { value: "all", label: "All", count: filteredOrders.length }, { value: "pending", label: "Pending", count: pendingCount }, { value: "picked_up", label: "Picked Up", count: pickedUpCount }, ]} size="md" /> {/* Search */} { setSearch(e.target.value); setPage(0); }} onClear={() => { setSearch(""); setPage(0); }} showClear={true} /> {/* Stop Filter */}
{showStopDropdown && ( <>
setShowStopDropdown(false)} />
Filter by Stop
{stops.map((stop) => ( ))}
)}
{/* Selected stop chips */} {selectedStops.length > 0 && (
{selectedStops.map((stopId) => { const stop = stops.find((s) => s.id === stopId); if (!stop) return null; return ( {stop.city}, {stop.state} ); })}
)} {/* Bulk actions bar */} {selectedOrders.size > 0 && (
{selectedOrders.size} order{selectedOrders.size !== 1 ? 's' : ''} selected
Mark All as Picked Up
)} {/* Orders Table */} {isLoading ? (
{Array.from({ length: 5 }).map((_, i) => (
))}
) : paginatedOrders.length === 0 ? (
{Icons.package("h-8 w-8 text-stone-400")}

No orders found

Try adjusting your filters

) : (
{paginatedOrders.map((order) => ( ))}
0} onChange={toggleSelectAll} className="h-4 w-4 rounded border-stone-300 text-[var(--admin-accent)] focus:ring-[var(--admin-accent)] cursor-pointer" /> Order Customer Stop Date Items Total Status
toggleOrderSelection(order.id)} className="h-4 w-4 rounded border-stone-300 text-[var(--admin-accent)] focus:ring-[var(--admin-accent)] cursor-pointer" /> {shortId(order.id)}
{order.customer_name}
{order.customer_phone &&
{order.customer_phone}
}
{order.stops ? ( {order.stops.city}, {order.stops.state} ) : ( )} {formatDate(order.created_at)} {order.order_items?.length ?? 0} {formatCurrency(order.subtotal)}
{order.pickup_complete ? ( Picked Up ) : ( Pending )} {order.payment_processor === "square" && ( Square )} {!order.pickup_complete && ( handleMarkPickup(order.id)} disabled={pickingUp === order.id} isLoading={pickingUp === order.id} > {pickingUp === order.id ? "..." : "Pick Up"} )}
)} {/* Pagination */} {totalPages > 1 && (

Showing {(page * PAGE_SIZE) + 1} to {Math.min((page + 1) * PAGE_SIZE, filteredOrders.length)} of {filteredOrders.length}

setPage((p) => Math.max(0, p - 1))} disabled={page === 0} className="!rounded-lg" > {Icons.chevronLeft("h-4 w-4")} {page + 1} / {totalPages} setPage((p) => Math.min(totalPages - 1, p + 1))} disabled={page >= totalPages - 1} className="!rounded-lg" > {Icons.chevronRight("h-4 w-4")}
)}
); }