import { useEffect, useState, useCallback } from 'react'; import { useParams, Link } from 'react-router-dom'; import { api } from '../api'; export default function OrderDetail() { const { id } = useParams(); const [order, setOrder] = useState(null); const [products, setProducts] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [editing, setEditing] = useState(false); const [status, setStatus] = useState('pending'); const [notes, setNotes] = useState(''); const [paymentMethod, setPaymentMethod] = useState(''); const [amountPaid, setAmountPaid] = useState(''); const [items, setItems] = useState([]); const load = useCallback(() => { Promise.all([ api(`/orders/${id}`).then((r) => (r.ok ? r.json() : Promise.reject(new Error('Not found')))), api('/products').then((r) => r.json()), ]) .then(([o, p]) => { setOrder(o); setProducts(p); setStatus(o.status); setNotes(o.notes || ''); setPaymentMethod(o.payment_method || ''); setAmountPaid(o.amount_paid != null ? String(o.amount_paid) : '0'); setItems(o.items?.map((i) => ({ product_id: i.product_id, quantity: i.quantity, price_at_sale: i.price_at_sale })) || []); }) .catch((e) => setError(e.message)) .finally(() => setLoading(false)); }, [id]); useEffect(() => { load(); }, [load]); function handleUpdate(e) { e.preventDefault(); const payload = { status, payment_method: paymentMethod || null, amount_paid: amountPaid !== '' ? Number(amountPaid) : 0, notes: notes.trim() || null, items: items.map((line) => ({ product_id: line.product_id, quantity: Number(line.quantity) || 0, price_at_sale: line.price_at_sale, })).filter((line) => line.quantity > 0), }; if (payload.items.length === 0) { setError('Order must have at least one item.'); return; } api(`/orders/${id}`, { method: 'PUT', body: payload, }) .then((r) => { if (!r.ok) return r.json().then((e) => Promise.reject(new Error(e.error || 'Failed'))); return r.json(); }) .then(setOrder) .then(() => setEditing(false)) .then(load) .catch((e) => setError(e.message)); } function addLine() { const productId = products[0]?.id; if (!productId) return; const p = products.find((x) => x.id === productId); setItems((prev) => [...prev, { product_id: productId, quantity: 1, price_at_sale: p?.price }]); } function updateLine(index, field, value) { setItems((prev) => prev.map((line, i) => (i === index ? { ...line, [field]: value } : line))); } function removeLine(index) { setItems((prev) => prev.filter((_, i) => i !== index)); } if (loading) return
Loading...
; if (error && !order) return{error}
; if (!order) return null; const productById = Object.fromEntries(products.map((p) => [p.id, p])); let total = 0; for (const line of items) { const price = line.price_at_sale != null ? line.price_at_sale : productById[line.product_id]?.price; total += (price || 0) * (Number(line.quantity) || 0); } return ( <>{error}
} {!editing ? (Customer: {order.customer_id ? (order.customer_name || `#${order.customer_id}`) : 'Walk-in'}
Status: {order.status}
Created: {new Date(order.created_at).toLocaleString()}
{order.notes &&Notes: {order.notes}
}Payment: {order.payment_method ? order.payment_method.charAt(0).toUpperCase() + order.payment_method.slice(1) : 'Not set'}
Amount paid: ${Number(order.amount_paid || 0).toFixed(2)}
{(() => { const orderTotal = (order.items || []).reduce((s, i) => s + i.quantity * i.price_at_sale, 0); const balance = orderTotal - (order.amount_paid || 0); return balance > 0.005 ?Balance due: ${balance.toFixed(2)}
: null; })()}| Product | Qty | Price | Subtotal |
|---|---|---|---|
| {line.product_name} | {line.quantity} | ${Number(line.price_at_sale).toFixed(2)} | ${(line.quantity * line.price_at_sale).toFixed(2)} |
Total: ${(order.items || []).reduce((s, i) => s + i.quantity * i.price_at_sale, 0).toFixed(2)}