From 43632c9aa5d5908ba4f9b6658163584bd01bbf80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cau=C3=AA=20Faleiros?= Date: Tue, 4 Aug 2026 12:51:17 -0300 Subject: [PATCH] Link supply blockers to actionable queues --- src/pages/Supplies.tsx | 52 +++++++++++++++++++++++++++++------------- 1 file changed, 36 insertions(+), 16 deletions(-) diff --git a/src/pages/Supplies.tsx b/src/pages/Supplies.tsx index 91cab03..edf8db6 100644 --- a/src/pages/Supplies.tsx +++ b/src/pages/Supplies.tsx @@ -1,5 +1,5 @@ import { type FormEvent, useEffect, useMemo, useState } from 'react'; -import { Link as RouterLink, Navigate, useOutletContext, useParams } from 'react-router-dom'; +import { Link as RouterLink, Navigate, useOutletContext, useParams, useSearchParams } from 'react-router-dom'; import { AlertTriangle, ArrowLeft, @@ -313,7 +313,7 @@ const SuppliesHub = () => { description: 'Estoque negativo distorce a compra sugerida e pode liberar corte sem material físico.', meta: 'Abrir compra de materiais', icon: AlertTriangle, - to: '/supplies/purchase-needs', + to: '/supplies/purchase-needs?tab=materials&filter=negative_balance', tone: 'critical' as const, } : mappingSkuCount > 0 @@ -323,7 +323,7 @@ const SuppliesHub = () => { description: 'Sem composição confiável, a necessidade de compra e o corte não representam a demanda real.', meta: 'Abrir pendências de composição', icon: LinkIcon, - to: '/supplies/purchase-needs', + to: '/supplies/purchase-needs?tab=mapping', tone: 'info' as const, } : materialPurchaseNeeds.length > 0 @@ -333,7 +333,7 @@ const SuppliesHub = () => { description: 'A necessidade já desconta saldo e recebimentos para apoiar a decisão de compra.', meta: 'Ver lista de compra', icon: BarChart3, - to: '/supplies/purchase-needs', + to: '/supplies/purchase-needs?tab=materials&filter=to_buy', tone: 'attention' as const, } : activeProductionCount > 0 @@ -413,9 +413,9 @@ const SuppliesHub = () => {

Resolva estes pontos antes de confiar no plano.

- - - + + +
@@ -425,8 +425,8 @@ const SuppliesHub = () => {

Da necessidade de material até a produção acompanhada.

- 0 ? 'critical' : materialPurchaseNeeds.length > 0 ? 'attention' : 'ready'} meta={negativeMaterialNeeds.length > 0 ? `${formatNumber(negativeMaterialNeeds.length, 0)} saldos negativos` : materialPurchaseNeeds.length > 0 ? `${formatNumber(materialPurchaseNeeds.length, 0)} materiais para comprar` : 'Materiais cobertos'} /> - 0 ? 'attention' : 'default'} meta={mappingSkuCount > 0 ? `${formatNumber(mappingSkuCount, 0)} SKUs precisam de mapeamento` : 'Abrir plano de corte'} /> + 0 ? '/supplies/purchase-needs?tab=materials&filter=negative_balance' : materialPurchaseNeeds.length > 0 ? '/supplies/purchase-needs?tab=materials&filter=to_buy' : mappingSkuCount > 0 ? '/supplies/purchase-needs?tab=mapping' : '/supplies/purchase-needs?tab=materials&filter=all'} tone={negativeMaterialNeeds.length > 0 ? 'critical' : materialPurchaseNeeds.length > 0 ? 'attention' : mappingSkuCount > 0 ? 'attention' : 'ready'} meta={negativeMaterialNeeds.length > 0 ? `${formatNumber(negativeMaterialNeeds.length, 0)} saldos negativos` : materialPurchaseNeeds.length > 0 ? `${formatNumber(materialPurchaseNeeds.length, 0)} materiais para comprar` : mappingSkuCount > 0 ? 'Sem falta calculada · dados pendentes' : 'Materiais cobertos'} /> + 0 ? '/supplies/purchase-needs?tab=mapping' : '/cutting'} tone={mappingSkuCount > 0 ? 'attention' : 'default'} meta={mappingSkuCount > 0 ? `${formatNumber(mappingSkuCount, 0)} SKUs precisam de mapeamento` : 'Abrir plano de corte'} /> 0 ? 'ready' : 'default'} meta={activeProductionCount > 0 ? `${formatNumber(productionCounts.open, 0)} abertas · ${formatNumber(productionCounts.inProgress, 0)} em andamento` : 'Nenhuma OP em execução'} />
@@ -2240,11 +2240,14 @@ const PurchaseMappingQueue = ({ needs }: { needs: SupplyPurchaseNeed[] }) => ( ); const PurchaseNeedsScreen = () => { + const [searchParams, setSearchParams] = useSearchParams(); const [summary, setSummary] = useState(emptySupplySummary); const [isLoading, setIsLoading] = useState(true); const [search, setSearch] = useState(''); - const [activeTab, setActiveTab] = useState('materials'); - const [materialFilter, setMaterialFilter] = useState('to_buy'); + const initialTab = searchParams.get('tab'); + const initialFilter = searchParams.get('filter'); + const [activeTab, setActiveTab] = useState(initialTab === 'services' || initialTab === 'mapping' ? initialTab : 'materials'); + const [materialFilter, setMaterialFilter] = useState(initialFilter === 'negative_balance' || initialFilter === 'no_stock' || initialFilter === 'all' ? initialFilter : 'to_buy'); const [currentPage, setCurrentPage] = useState(1); const [itemsPerPage, setItemsPerPage] = useState(10); @@ -2273,6 +2276,23 @@ const PurchaseNeedsScreen = () => { }; }, []); + useEffect(() => { + const tab = searchParams.get('tab'); + const filter = searchParams.get('filter'); + setActiveTab(tab === 'services' || tab === 'mapping' ? tab : 'materials'); + setMaterialFilter(filter === 'negative_balance' || filter === 'no_stock' || filter === 'all' ? filter : 'to_buy'); + setSearch(''); + setCurrentPage(1); + }, [searchParams]); + + const openQueue = (tab: PurchaseNeedTab, filter: MaterialPurchaseFilter = 'to_buy') => { + setActiveTab(tab); + setMaterialFilter(filter); + setSearch(''); + setCurrentPage(1); + setSearchParams(tab === 'materials' ? { tab, filter } : { tab }); + }; + const materialNeeds = summary.purchaseNeeds.filter(need => !need.missingReference && !isServicePurchaseNeed(need)); const serviceNeeds = summary.purchaseNeeds.filter(need => !need.missingReference && isServicePurchaseNeed(need)); const mappingNeeds = summary.purchaseNeeds.filter(need => need.missingReference); @@ -2325,7 +2345,7 @@ const PurchaseNeedsScreen = () => {
))} @@ -2417,7 +2437,7 @@ const PurchaseNeedsScreen = () => {