From 2b1bb8eda9a81bbc64441a625865c544c570726b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cau=C3=AA=20Faleiros?= Date: Mon, 13 Jul 2026 10:45:50 -0300 Subject: [PATCH] Restore fabric planning in supplies --- src/pages/Supplies.tsx | 168 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 154 insertions(+), 14 deletions(-) diff --git a/src/pages/Supplies.tsx b/src/pages/Supplies.tsx index fb2437d..090e5d5 100644 --- a/src/pages/Supplies.tsx +++ b/src/pages/Supplies.tsx @@ -1,4 +1,4 @@ -import { useState } from 'react'; +import { type FormEvent, useState } from 'react'; import { Link as RouterLink, Navigate, useParams } from 'react-router-dom'; import { AlertTriangle, @@ -14,6 +14,7 @@ import { RefreshCw, Repeat2, Ruler, + Save, Search, Scissors, Truck, @@ -21,6 +22,14 @@ import { } from 'lucide-react'; type InventoryTab = 'dashboard' | 'balance' | 'receipts' | 'inventory' | 'movements'; +type FabricPlan = { + id: string; + material: string; + color: string; + quantityKg: number; + supplier: string; + priority: 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'; @@ -35,6 +44,26 @@ const stats = [ { label: 'Alertas', value: '0' }, ]; +const formatNumber = (value: number, maximumFractionDigits = 2) => ( + new Intl.NumberFormat('pt-BR', { maximumFractionDigits }).format(value) +); + +const parseDecimal = (value: string) => { + const number = Number(value.replace(',', '.')); + return Number.isFinite(number) ? number : 0; +}; + +const loadFabricPlans = (): FabricPlan[] => { + try { + const rawPlans = localStorage.getItem('nexstar_fabric_plans'); + if (!rawPlans) return []; + const parsed = JSON.parse(rawPlans); + 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 }, @@ -100,7 +129,8 @@ const SuppliesHub = () => (
- + +
@@ -271,20 +301,130 @@ const InventoryScreen = () => { ); }; -const FabricPlanningScreen = () => ( -
-
-
-

Planos de malha

-

Fila de matéria-prima para compra, recebimento e abastecimento do corte.

-
- -

Nenhum plano de malha cadastrado

-

Quando houver planos, eles alimentarão recebimentos e corte.

+const FabricPlanningScreen = () => { + const [plans, setPlans] = useState(loadFabricPlans); + const [form, setForm] = useState({ + material: '', + color: '', + quantityKg: '', + supplier: '', + priority: 'Normal', + }); + + const totalKg = plans.reduce((total, plan) => total + plan.quantityKg, 0); + + const savePlans = (nextPlans: FabricPlan[]) => { + setPlans(nextPlans); + localStorage.setItem('nexstar_fabric_plans', JSON.stringify(nextPlans)); + }; + + const handleSubmit = (event: FormEvent) => { + event.preventDefault(); + const material = form.material.trim(); + const quantityKg = parseDecimal(form.quantityKg); + if (!material || quantityKg <= 0) return; + + const nextPlan: FabricPlan = { + id: `${Date.now()}`, + material, + color: form.color.trim() || 'Todas as cores', + quantityKg, + supplier: form.supplier.trim() || 'Sem fornecedor', + priority: form.priority, + }; + + savePlans([nextPlan, ...plans]); + setForm({ material: '', color: '', quantityKg: '', supplier: '', priority: 'Normal' }); + }; + + return ( +
+
+
+
+

Planos ativos

+

{plans.length}

+
+
+

Kg planejado

+

{formatNumber(totalKg)} kg

+
+
+

Críticos

+

{plans.filter(plan => plan.priority === 'Crítico').length}

+
+
+
+
+

Novo plano de malha

+
+ + +
+ + +
+ + +
+
+ +
+
+

Planos de malha

+

Itens planejados para compra ou recebimento.

+
+ {plans.length ? ( +
+ {plans.map(plan => ( +
+
+

{plan.material}

+

{plan.color}

+
+

{plan.supplier}

+

{formatNumber(plan.quantityKg)} kg

+ {plan.priority} + +
+ ))} +
+ ) : ( +
+ +

Nenhum plano de malha cadastrado

+

Cadastre o primeiro plano no formulário ao lado.

+
+ )} +
-
-); + ); +}; const PurchaseNeedsScreen = () => (