import { useState } from 'react' import { useQuery } from '@tanstack/react-query' import { useAuth } from '../App' import PurchaseOrderModal from './PurchaseOrderModal' interface PurchaseOrderSummary { id: number supplier_id: number supplier_name: string | null order_date: string order_type: string status: string total_amount: number | null order_reference: string | null created_by_name: string | null created_at: string } const statusColors: Record = { DRAFT: { bg: '#e0e0e0', color: '#555' }, PENDING: { bg: '#e3f2fd', color: '#1565c0' }, LINKED: { bg: '#d4edda', color: '#155724' }, CLOSED: { bg: '#f5f5f5', color: '#666' }, CANCELLED: { bg: '#ffebee', color: '#c62828' }, } export default function PurchaseOrderList() { const { token } = useAuth() const [statusFilter, setStatusFilter] = useState('DRAFT,PENDING') const [supplierFilter, setSupplierFilter] = useState('') const [editPoId, setEditPoId] = useState(null) const [showNewModal, setShowNewModal] = useState(false) // Fetch suppliers for filter const { data: suppliersData } = useQuery<{ suppliers: Array<{ id: number; name: string }> }>({ queryKey: ['suppliers'], queryFn: async () => { const res = await fetch('/kitchen/api/suppliers/', { headers: { Authorization: `Bearer ${token}` }, }) if (!res.ok) throw new Error('Failed to fetch suppliers') return res.json() }, enabled: !!token, }) // Build query string const params = new URLSearchParams() if (statusFilter) params.append('status', statusFilter) if (supplierFilter) params.append('supplier_id', supplierFilter) const { data: poList, refetch } = useQuery({ queryKey: ['purchase-orders', statusFilter, supplierFilter], queryFn: async () => { const res = await fetch(`/kitchen/api/purchase-orders/?${params}`, { headers: { Authorization: `Bearer ${token}` }, }) if (!res.ok) throw new Error('Failed to fetch purchase orders') return res.json() }, enabled: !!token, }) const formatDate = (d: string) => { const dt = new Date(d + 'T00:00:00') return dt.toLocaleDateString('en-GB', { weekday: 'short', day: 'numeric', month: 'short' }) } return (

Purchase Orders

{/* Filter bar */}
{[ { label: 'Open', value: 'DRAFT,PENDING' }, { label: 'All', value: '' }, { label: 'Draft', value: 'DRAFT' }, { label: 'Pending', value: 'PENDING' }, { label: 'Linked', value: 'LINKED' }, { label: 'Closed', value: 'CLOSED' }, ].map(tab => ( ))}
{/* Table */}
{(!poList || poList.length === 0) ? ( ) : ( poList.map(po => { const sc = statusColors[po.status] || statusColors.DRAFT return ( setEditPoId(po.id)} > ) }) )}
Date Supplier Type Reference Total Status Created
No purchase orders found
{formatDate(po.order_date)} {po.supplier_name || '-'} {po.order_type === 'itemised' ? 'Itemised' : 'Single Value'} {po.order_reference || '-'} {po.total_amount != null ? `\u00A3${po.total_amount.toFixed(2)}` : '-'} {po.status} {po.created_by_name || ''}
{/* Modals */} setEditPoId(null)} onSaved={() => refetch()} poId={editPoId} /> setShowNewModal(false)} onSaved={() => refetch()} />
) } const styles: Record = { headerRow: { display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '1.5rem', }, pageTitle: { margin: 0, color: '#1a1a2e', }, newBtn: { padding: '0.6rem 1.2rem', background: '#1a1a2e', color: 'white', border: 'none', borderRadius: '6px', cursor: 'pointer', fontWeight: 600, fontSize: '0.9rem', }, filterBar: { display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '1rem', gap: '1rem', flexWrap: 'wrap', }, statusTabs: { display: 'flex', gap: '0.25rem', }, filterTab: { padding: '0.4rem 0.75rem', border: '1px solid #ddd', borderRadius: '6px', background: 'white', cursor: 'pointer', fontSize: '0.85rem', fontWeight: 500, }, filterTabActive: { background: '#1a1a2e', color: 'white', borderColor: '#1a1a2e', }, filterSelect: { padding: '0.4rem 0.75rem', border: '1px solid #ddd', borderRadius: '6px', fontSize: '0.85rem', }, tableContainer: { background: 'white', borderRadius: '8px', boxShadow: '0 1px 4px rgba(0,0,0,0.08)', overflow: 'auto', }, table: { width: '100%', borderCollapse: 'collapse', }, th: { textAlign: 'left', padding: '0.75rem 1rem', borderBottom: '2px solid #eee', fontWeight: 600, color: '#666', fontSize: '0.85rem', whiteSpace: 'nowrap', }, td: { padding: '0.75rem 1rem', borderBottom: '1px solid #f0f0f0', fontSize: '0.9rem', }, emptyTd: { padding: '2rem', textAlign: 'center', color: '#999', }, row: { cursor: 'pointer', transition: 'background 0.15s', }, statusBadge: { display: 'inline-block', padding: '0.2rem 0.6rem', borderRadius: '12px', fontSize: '0.75rem', fontWeight: 600, }, typeBadge: { fontSize: '0.8rem', color: '#666', }, }