"use client"; import { useState } from "react"; import { useRouter } from "next/navigation"; import { updateOrder, updateOrderItem, deleteOrderItem } from "@/actions/orders/update-order"; import { AdminInput, AdminTextInput, AdminTextarea, useToast, AdminButton } 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; discount_amount: number; tax_amount: number | null; tax_rate: number | null; tax_source?: string | null; tax_location: string | null; internal_notes: string | null; discount_reason: string | null; pickup_complete: boolean; pickup_completed_at: string | null; pickup_completed_by: string | null; created_at: string; stops: { city: string; state: string; date: string } | null; order_items: OrderItem[]; }; type OrderEditFormProps = { order: Order; brandId: string | null; }; type EditableItem = { id: string; product_id: string; quantity: number; price: number; productName: string; removed: boolean; }; const currencyFormatter = new Intl.NumberFormat("en-US", { style: "currency", currency: "USD" }); function formatCurrency(amount: number) { return currencyFormatter.format(amount); } export default function OrderEditForm({ order, brandId }: OrderEditFormProps) { const router = useRouter(); const { success: showSuccess, error: showError } = useToast(); const [saving, setSaving] = useState(false); const [error, setError] = useState(null); const [saved, setSaved] = useState(false); // Holds user edits only; missing keys fall back to the current prop so we // never copy the prop into useState. When the prop changes, the fallback // value tracks the new prop automatically. const [draft, setDraft] = useState<{ customer_name?: string; customer_email?: string; customer_phone?: string; discount_amount?: number; discount_reason?: string; internal_notes?: string; status?: string; pickup_complete?: boolean; items?: EditableItem[]; }>({}); const customer_name = draft.customer_name ?? order.customer_name; const customer_email = draft.customer_email ?? order.customer_email ?? ""; const customer_phone = draft.customer_phone ?? order.customer_phone ?? ""; const discount_amount = draft.discount_amount ?? order.discount_amount ?? 0; const discount_reason = draft.discount_reason ?? order.discount_reason ?? ""; const internal_notes = draft.internal_notes ?? order.internal_notes ?? ""; const status = draft.status ?? order.status; const pickup_complete = draft.pickup_complete ?? order.pickup_complete; const setCustomer_name = (v: string | ((prev: string) => string)) => setDraft((d) => ({ ...d, customer_name: typeof v === "function" ? v(d.customer_name ?? order.customer_name) : v, })); const setCustomer_email = (v: string | ((prev: string) => string)) => setDraft((d) => ({ ...d, customer_email: typeof v === "function" ? v(d.customer_email ?? order.customer_email ?? "") : v, })); const setCustomer_phone = (v: string | ((prev: string) => string)) => setDraft((d) => ({ ...d, customer_phone: typeof v === "function" ? v(d.customer_phone ?? order.customer_phone ?? "") : v, })); const setDiscount_amount = (v: number | ((prev: number) => number)) => setDraft((d) => ({ ...d, discount_amount: typeof v === "function" ? v(d.discount_amount ?? order.discount_amount ?? 0) : v, })); const setDiscount_reason = (v: string | ((prev: string) => string)) => setDraft((d) => ({ ...d, discount_reason: typeof v === "function" ? v(d.discount_reason ?? order.discount_reason ?? "") : v, })); const setInternal_notes = (v: string | ((prev: string) => string)) => setDraft((d) => ({ ...d, internal_notes: typeof v === "function" ? v(d.internal_notes ?? order.internal_notes ?? "") : v, })); const setStatus = (v: string | ((prev: string) => string)) => setDraft((d) => ({ ...d, status: typeof v === "function" ? v(d.status ?? order.status) : v, })); const setPickup_complete = (v: boolean | ((prev: boolean) => boolean)) => setDraft((d) => ({ ...d, pickup_complete: typeof v === "function" ? v(d.pickup_complete ?? order.pickup_complete) : v, })); const items = draft.items ?? order.order_items.map((item) => ({ id: item.id, product_id: item.product_id, quantity: item.quantity, price: Number(item.price), productName: item.products?.name ?? "Unknown", removed: false, })); const setItems = (updater: React.SetStateAction) => setDraft((d) => { const currentItems = d.items ?? order.order_items.map((item) => ({ id: item.id, product_id: item.product_id, quantity: item.quantity, price: Number(item.price), productName: item.products?.name ?? "Unknown", removed: false, })); const next = typeof updater === "function" ? (updater as (prev: EditableItem[]) => EditableItem[])(currentItems) : updater; return { ...d, items: next }; }); const visibleItems = items.filter((i) => !i.removed); const subtotal = visibleItems.reduce( (sum, i) => sum + Number(i.price) * i.quantity, 0 ); const total = Math.max(0, subtotal - discount_amount); // Validation const [fieldErrors, setFieldErrors] = useState>({}); function validateForm(): boolean { const errors: Record = {}; if (!customer_name.trim()) { errors.customer_name = "Customer name is required"; } if (discount_amount < 0) { errors.discount_amount = "Discount cannot be negative"; } setFieldErrors(errors); return Object.keys(errors).length === 0; } function updateItem(id: string, field: "quantity" | "price", value: number) { setItems((prev) => prev.map((i) => (i.id === id ? { ...i, [field]: value } : i)) ); // Clear error for the field when changed setFieldErrors((prev) => { const next = { ...prev }; delete next[field]; return next; }); } function removeItem(id: string) { setItems((prev) => prev.map((i) => (i.id === id ? { ...i, removed: true } : i)) ); } async function handleSave() { if (!validateForm()) { showError("Validation failed", "Please fix the errors below"); return; } setSaving(true); setError(null); setSaved(false); const toSave = items.filter((i) => !i.removed); const toRemove = items.filter((i) => i.removed); try { const removeResults = await Promise.all( toRemove.map(async (item) => { try { const result = await deleteOrderItem(item.id); if (result.success) { return { id: item.id, success: true, error: null as string | null }; } return { id: item.id, success: false, error: result.error }; } catch { return { id: item.id, success: false, error: "Network error" }; } }) ); const failedRemoval = removeResults.find((r) => !r.success); if (failedRemoval) { showError("Failed to remove item", failedRemoval.error ?? "Please try again"); setSaving(false); return; } const updateResults = await Promise.all( toSave.map(async (item) => { const orig = order.order_items.find((o) => o.id === item.id); if (!orig) return { id: item.id, success: true, error: null as string | null }; if ( Number(orig.quantity) === item.quantity && Number(orig.price) === item.price ) { return { id: item.id, success: true, error: null as string | null }; } try { const result = await updateOrderItem(item.id, { quantity: item.quantity, price: Number(item.price), }); if (result.success) { return { id: item.id, success: true, error: null as string | null }; } return { id: item.id, success: false, error: result.error }; } catch { return { id: item.id, success: false, error: "Network error" }; } }) ); const failedUpdate = updateResults.find((r) => !r.success); if (failedUpdate) { showError("Failed to update item", failedUpdate.error ?? "Please try again"); setSaving(false); return; } const result = await updateOrder(order.id, brandId, { customer_name, customer_email: customer_email || null, customer_phone: customer_phone || null, discount_amount, discount_reason: discount_reason || null, internal_notes: internal_notes || null, status, pickup_complete, pickup_completed_at: pickup_complete ? new Date().toISOString() : null, subtotal, }); if (!result.success) { showError("Failed to save", result.error ?? "Please try again"); setSaving(false); return; } showSuccess("Order updated", "Changes have been saved"); setSaved(true); setSaving(false); router.refresh(); } catch (err) { showError("Network error", "Please check your connection and try again"); setSaving(false); } } return (
{error && (
{error}
)} {/* Order items */}

Order Items ({visibleItems.length})

{visibleItems.length === 0 ? (

No items

) : (
{visibleItems.map((item) => (

{item.productName}

updateItem(item.id, "quantity", Number(e.target.value)) } className="ha-field-input ha-field-input-mono" />
$ updateItem(item.id, "price", Number(e.target.value)) } className="ha-field-input ha-field-input-mono pl-8 pr-3" />

{formatCurrency(Number(item.price) * item.quantity)}

))}
)}
{/* Pricing */}
$ setDiscount_amount(Number(e.target.value))} className="ha-field-input ha-field-input-mono pl-8 pr-3" style={ fieldErrors.discount_amount ? { borderColor: "var(--admin-danger)", backgroundColor: "var(--admin-danger-soft)" } : undefined } />
{fieldErrors.discount_amount && (

{fieldErrors.discount_amount}

)}
setDiscount_reason(e.target.value)} placeholder="Optional" className="ha-field-input" />
Total {formatCurrency(subtotal + Number(order.tax_amount ?? 0) - discount_amount)}
{/* Customer fields */}
{ setCustomer_name(e.target.value); setFieldErrors((prev) => { const next = { ...prev }; delete next.customer_name; return next; }); }} className="ha-field-input" style={ fieldErrors.customer_name ? { borderColor: "var(--admin-danger)", backgroundColor: "var(--admin-danger-soft)" } : undefined } /> {fieldErrors.customer_name && (

{fieldErrors.customer_name}

)}
setCustomer_email(e.target.value)} /> setCustomer_phone(e.target.value)} />
{/* Status & pickup */}
{["pending", "confirmed", "cancelled"].map((s) => ( ))}
{/* Internal notes */} setInternal_notes(e.target.value)} rows={2} placeholder="Private notes for staff..." /> {saving ? "Saving..." : "Save Changes"}
); }