From c68d3c7ed4960bf96fd95f2aee2139bee63f26c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cau=C3=AA=20Faleiros?= Date: Mon, 13 Jul 2026 10:58:39 -0300 Subject: [PATCH] Make supply receipts interactive --- src/pages/Supplies.tsx | 249 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 227 insertions(+), 22 deletions(-) diff --git a/src/pages/Supplies.tsx b/src/pages/Supplies.tsx index 090e5d5..c6c75b2 100644 --- a/src/pages/Supplies.tsx +++ b/src/pages/Supplies.tsx @@ -22,6 +22,7 @@ import { } from 'lucide-react'; type InventoryTab = 'dashboard' | 'balance' | 'receipts' | 'inventory' | 'movements'; +type ReceiptView = 'new' | 'pending' | 'history'; type FabricPlan = { id: string; material: string; @@ -30,6 +31,18 @@ type FabricPlan = { supplier: string; priority: string; }; +type SupplyReceipt = { + id: string; + category: string; + product: string; + quantity: number; + unit: string; + supplier: string; + invoice: string; + notes: string; + status: 'pending' | 'approved'; + createdAt: string; +}; const pageClassName = 'mx-auto flex w-full max-w-7xl flex-col gap-6'; const panelClassName = 'rounded-2xl border border-dark-border bg-dark-card shadow-sm'; @@ -64,6 +77,17 @@ const loadFabricPlans = (): FabricPlan[] => { } }; +const loadReceipts = (): SupplyReceipt[] => { + try { + const rawReceipts = localStorage.getItem('nexstar_supply_receipts'); + if (!rawReceipts) return []; + const parsed = JSON.parse(rawReceipts); + return Array.isArray(parsed) ? parsed : []; + } catch { + return []; + } +}; + const inventoryTabs: Array<{ id: InventoryTab; name: string; icon: typeof BarChart3 }> = [ { id: 'dashboard', name: 'Dashboard', icon: Warehouse }, { id: 'balance', name: 'Saldo', icon: BarChart3 }, @@ -72,7 +96,7 @@ const inventoryTabs: Array<{ id: InventoryTab; name: string; icon: typeof BarCha { id: 'movements', name: 'Movimentações', icon: Repeat2 }, ]; -const receiptCategories = [ +const receiptCategories: Array<{ name: string; icon: typeof Package }> = [ { name: 'Malha / Tecido', icon: Ruler }, { name: 'Embalagem', icon: Package }, { name: 'Material de Limpeza', icon: Boxes }, @@ -205,32 +229,213 @@ const BalanceTab = () => ( ); -const ReceiptsTab = () => ( -
-
- {['Novo recebimento', 'Pendentes', 'Histórico'].map((item, index) => ( - - ))} -
-
-

Registrar recebimento

-
- Preencha o que chegou. O financeiro vincula OC/NF e aprova o lançamento. +const ReceiptList = ({ + receipts, + emptyTitle, + onApprove, + onRemove, +}: { + receipts: SupplyReceipt[]; + emptyTitle: string; + onApprove: (receiptId: string) => void; + onRemove: (receiptId: string) => void; +}) => ( +
+ {receipts.length ? ( +
+ {receipts.map(receipt => ( +
+
+

{receipt.product}

+

{receipt.category} · NF {receipt.invoice}

+
+

{formatNumber(receipt.quantity)} {receipt.unit}

+

{receipt.supplier}

+ + {receipt.status === 'approved' ? 'Aprovado' : 'Pendente'} + +
+ {receipt.status === 'pending' && ( + + )} + +
+
+ ))}
-

1. Qual categoria de produto chegou?

-
- {receiptCategories.map(category => ( -
+); + +const ReceiptsTab = () => { + const [activeView, setActiveView] = useState('new'); + const [selectedCategory, setSelectedCategory] = useState(receiptCategories[0].name); + const [receipts, setReceipts] = useState(loadReceipts); + const [form, setForm] = useState({ + product: '', + quantity: '', + unit: 'kg', + supplier: '', + invoice: '', + notes: '', + }); + + const pendingReceipts = receipts.filter(receipt => receipt.status === 'pending'); + const visibleReceipts = activeView === 'pending' ? pendingReceipts : receipts; + + const saveReceipts = (nextReceipts: SupplyReceipt[]) => { + setReceipts(nextReceipts); + localStorage.setItem('nexstar_supply_receipts', JSON.stringify(nextReceipts)); + }; + + const handleReceiptSubmit = (event: FormEvent) => { + event.preventDefault(); + const product = form.product.trim(); + const quantity = parseDecimal(form.quantity); + if (!product || quantity <= 0) return; + + const nextReceipt: SupplyReceipt = { + id: `${Date.now()}`, + category: selectedCategory, + product, + quantity, + unit: form.unit, + supplier: form.supplier.trim() || 'Sem fornecedor', + invoice: form.invoice.trim() || '-', + notes: form.notes.trim(), + status: 'pending', + createdAt: new Date().toISOString(), + }; + + saveReceipts([nextReceipt, ...receipts]); + setForm({ product: '', quantity: '', unit: 'kg', supplier: '', invoice: '', notes: '' }); + setActiveView('pending'); + }; + + const markApproved = (receiptId: string) => { + saveReceipts(receipts.map(receipt => ( + receipt.id === receiptId ? { ...receipt, status: 'approved' } : receipt + ))); + }; + + return ( +
+
+ {[ + { id: 'new', label: 'Novo recebimento' }, + { id: 'pending', label: `Pendentes (${pendingReceipts.length})` }, + { id: 'history', label: `Histórico (${receipts.length})` }, + ].map(item => ( + ))}
+ + {activeView === 'new' && ( +
+

Registrar recebimento

+
+ Preencha o que chegou. O financeiro vincula OC/NF e aprova o lançamento. +
+

1. Qual categoria de produto chegou?

+
+ {receiptCategories.map(category => ( + + ))} +
+ +
+

2. Detalhes do recebimento

+
+ + + + + +