"use client"; import { useState, useMemo, useCallback, useEffect } from "react"; import Link from "next/link"; import { useSearchParams } from "next/navigation"; import { markPickupComplete } from "@/actions/pickup"; import { createAdminOrder, type AdminCreateOrderItem } from "@/actions/orders/create-admin-order"; import { formatDate } from "@/lib/format-date"; import AdminBadge from "./design-system/AdminBadge"; import { AdminButton, AdminSearchInput, AdminFilterTabs, AdminIconButton, useToast, AdminInput, AdminTextInput, AdminSelect } 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[]; initialProducts?: Array<{ id: string; name: string; price: number; type?: string | null; active?: boolean }>; 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, initialProducts = [], brandId, }: AdminOrdersPanelProps) { const { success: showSuccess, error: showError } = useToast(); const searchParams = useSearchParams(); const [orders, setOrders] = useState(initialOrders); const [stops] = useState(initialStops); const [products] = useState(initialProducts); const [search, setSearch] = useState(""); const [activeTab, setActiveTab] = useState("all"); const [selectedStops, setSelectedStops] = useState([]); // New Order modal state (triggered by ?new=true from dashboard or quick actions) const [showNewOrderModal, setShowNewOrderModal] = useState(false); const [newOrderCustomerName, setNewOrderCustomerName] = useState(""); const [newOrderCustomerEmail, setNewOrderCustomerEmail] = useState(""); const [newOrderCustomerPhone, setNewOrderCustomerPhone] = useState(""); const [newOrderStopId, setNewOrderStopId] = useState(""); const [newOrderItems, setNewOrderItems] = useState>([]); const [newOrderSubmitting, setNewOrderSubmitting] = useState(false); const [newOrderError, setNewOrderError] = useState(null); // Open the New Order modal when dashboard links here with ?new=true useEffect(() => { const init = async () => { if (searchParams?.get("new") === "true") { setShowNewOrderModal(true); } }; init(); }, [searchParams]); // --- New Order (admin manual create) helpers --- function openNewOrderModal() { setShowNewOrderModal(true); setNewOrderError(null); } function closeNewOrderModal() { setShowNewOrderModal(false); // reset form setNewOrderCustomerName(""); setNewOrderCustomerEmail(""); setNewOrderCustomerPhone(""); setNewOrderStopId(""); setNewOrderItems([]); setNewOrderError(null); } function addNewOrderItem(productId: string) { const prod = products.find((p) => p.id === productId); if (!prod) return; setNewOrderItems((prev) => [ ...prev, { product_id: prod.id, quantity: 1, price: Number(prod.price), fulfillment: "pickup", }, ]); } function updateNewOrderItem(index: number, patch: Partial<{ quantity: number; price: number; fulfillment: "pickup" | "ship" }>) { setNewOrderItems((prev) => prev.map((it, i) => (i === index ? { ...it, ...patch } : it))); } function removeNewOrderItem(index: number) { setNewOrderItems((prev) => prev.filter((_, i) => i !== index)); } const newOrderTotal = newOrderItems.reduce((sum, it) => sum + it.price * it.quantity, 0); async function handleCreateAdminOrder() { if (!newOrderCustomerName.trim()) { setNewOrderError("Customer name is required"); return; } if (newOrderItems.length === 0) { setNewOrderError("Add at least one product"); return; } setNewOrderSubmitting(true); setNewOrderError(null); const result = await createAdminOrder(brandId, { customer_name: newOrderCustomerName.trim(), customer_email: newOrderCustomerEmail.trim() || null, customer_phone: newOrderCustomerPhone.trim() || null, stop_id: newOrderStopId || null, items: newOrderItems.map((i) => ({ product_id: i.product_id, quantity: i.quantity, price: i.price, fulfillment: i.fulfillment, })), }); setNewOrderSubmitting(false); if (result.success) { showSuccess(`Order created: ${result.orderId.slice(0, 8).toUpperCase()}`); closeNewOrderModal(); // Navigate to clean orders list (removes ?new=true and shows the new order after refresh) window.location.href = "/admin/orders"; } else { setNewOrderError(result.error ?? "Failed to create order"); } } 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(() => { // eslint-disable-next-line react-hooks/set-state-in-effect 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 )} + New Order
{/* 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")}
)}
{/* New Order Modal (admin manual entry) - sibling to the main panel content */} {showNewOrderModal && (

New Order (Admin)

Manual entry for testing / phone orders

{newOrderError && (
{newOrderError}
)} {/* Customer */}
setNewOrderCustomerName(e.target.value)} placeholder="Jane Doe" /> setNewOrderCustomerEmail(e.target.value)} placeholder="jane@example.com" type="email" /> setNewOrderCustomerPhone(e.target.value)} placeholder="(555) 123-4567" />
{/* Stop */} setNewOrderStopId(e.target.value)} options={[ { value: "", label: "— No stop (ship / manual fulfillment) —" }, ...stops.map((s) => ({ value: s.id, label: `${s.city}, ${s.state} — ${formatDate(s.date)}`, })), ]} /> {/* Items */}
Total: ${newOrderTotal.toFixed(2)}
{products.length > 0 ? (
{ if (e.target.value) addNewOrderItem(e.target.value); }} options={[ { value: "", label: "— Add a product —" }, ...products.map((p) => ({ value: p.id, label: `${p.name} — $${Number(p.price).toFixed(2)}` })), ]} />
) : (

No products loaded for this brand. You can still enter custom items if the action supports it.

)} {newOrderItems.length === 0 && (

No items yet. Use the selector above.

)} {newOrderItems.length > 0 && (
{newOrderItems.map((item, idx) => { const prod = products.find((p) => p.id === item.product_id); return (
{prod?.name ?? item.product_id}
updateNewOrderItem(idx, { quantity: Math.max(1, parseInt(e.target.value) || 1) })} className="w-full rounded border px-2 py-1 text-sm" />
updateNewOrderItem(idx, { price: parseFloat(e.target.value) || 0 })} className="w-full rounded border px-2 py-1 text-sm" />
); })}
)}
Cancel {newOrderSubmitting ? "Creating..." : `Create Order — $${newOrderTotal.toFixed(2)}`}
)} ); }