diff --git a/src/App.tsx b/src/App.tsx
index f5e4eec..90e9c5b 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -11,6 +11,7 @@ const ProductGroupDetails = React.lazy(() => import('./pages/ProductGroupDetails
const Replenishment = React.lazy(() => import('./pages/Replenishment'));
const Cutting = React.lazy(() => import('./pages/Cutting'));
const ProductionOrders = React.lazy(() => import('./pages/ProductionOrders'));
+const Supplies = React.lazy(() => import('./pages/Supplies'));
const Clients = React.lazy(() => import('./pages/Clients'));
const ClientDetails = React.lazy(() => import('./pages/ClientDetails'));
const Campaigns = React.lazy(() => import('./pages/Campaigns'));
@@ -53,6 +54,8 @@ function App() {
} />
} />
} />
+ } />
+ } />
} />
} />
} />
diff --git a/src/components/Layout.tsx b/src/components/Layout.tsx
index 30b93c7..5ca84a8 100644
--- a/src/components/Layout.tsx
+++ b/src/components/Layout.tsx
@@ -1,6 +1,6 @@
import { useState, useEffect } from 'react';
import { Outlet, Link, useLocation } from 'react-router-dom';
-import { LayoutDashboard, Users, BarChart3, ChevronLeft, ChevronRight, Package, LogOut, Megaphone, Grid3X3, Shield, Moon, Sun, ClipboardList, ShoppingCart, Scissors, Tags } from 'lucide-react';
+import { LayoutDashboard, Users, BarChart3, ChevronLeft, ChevronRight, Package, LogOut, Megaphone, Grid3X3, Shield, Moon, Sun, Tags, Boxes } from 'lucide-react';
import type { DateRange, OrderData } from '../types';
import { isSuperAdmin, logout } from '../dataService';
import { rangeForLastDays } from '../dateRanges';
@@ -74,9 +74,7 @@ const Layout = () => {
items: [
{ name: 'Produtos', href: '/products', icon: Package },
{ name: 'Cadastros', href: '/registrations', icon: Tags },
- { name: 'Reposição', href: '/replenishment', icon: ShoppingCart },
- { name: 'Corte', href: '/cutting', icon: Scissors },
- { name: 'Ordens de Produção', href: '/production-orders', icon: ClipboardList },
+ { name: 'Suprimentos', href: '/supplies', icon: Boxes },
],
},
{
diff --git a/src/pages/Supplies.tsx b/src/pages/Supplies.tsx
new file mode 100644
index 0000000..1d33371
--- /dev/null
+++ b/src/pages/Supplies.tsx
@@ -0,0 +1,338 @@
+import { useState } from 'react';
+import { Link as RouterLink, Navigate, useParams } from 'react-router-dom';
+import {
+ AlertTriangle,
+ ArrowLeft,
+ ArrowRight,
+ BarChart3,
+ Boxes,
+ ClipboardCheck,
+ ClipboardList,
+ Download,
+ Link as LinkIcon,
+ Package,
+ RefreshCw,
+ Repeat2,
+ Ruler,
+ Search,
+ Scissors,
+ ShoppingCart,
+ Truck,
+ Warehouse,
+} from 'lucide-react';
+
+type InventoryTab = 'dashboard' | 'balance' | 'receipts' | 'inventory' | 'movements';
+
+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';
+const mutedPanelClassName = 'rounded-2xl border border-dark-border bg-dark-card/70 shadow-sm';
+const buttonClassName = 'inline-flex h-10 items-center justify-center gap-2 rounded-lg border border-dark-border bg-dark-input px-3 text-sm font-bold text-dark-text transition-colors hover:border-brand-primary cursor-pointer';
+const inputClassName = 'h-10 w-full rounded-lg border border-dark-border bg-dark-input px-3 text-sm font-semibold text-dark-text outline-none placeholder:text-dark-muted focus:border-brand-primary';
+const emptyStateClassName = 'flex min-h-[190px] flex-col items-center justify-center gap-2 px-4 py-10 text-center';
+
+const stats = [
+ { label: 'Total em estoque', value: '0 kg' },
+ { label: 'Lotes ativos', value: '0' },
+ { label: 'Rolos', value: '0' },
+ { label: 'Alertas', value: '0' },
+];
+
+const inventoryTabs: Array<{ id: InventoryTab; name: string; icon: typeof BarChart3 }> = [
+ { id: 'dashboard', name: 'Dashboard', icon: Warehouse },
+ { id: 'balance', name: 'Saldo', icon: BarChart3 },
+ { id: 'receipts', name: 'Recebimentos', icon: Truck },
+ { id: 'inventory', name: 'Inventário', icon: ClipboardCheck },
+ { id: 'movements', name: 'Movimentações', icon: Repeat2 },
+];
+
+const receiptCategories = [
+ { name: 'Malha / Tecido', icon: Ruler },
+ { name: 'Embalagem', icon: Package },
+ { name: 'Material de Limpeza', icon: Boxes },
+ { name: 'Acessórios / Botões', icon: Warehouse },
+ { name: 'Etiquetas', icon: LinkIcon },
+ { name: 'Outro material', icon: ClipboardList },
+];
+
+const Header = ({ title, subtitle, backTo }: { title: string; subtitle: string; backTo?: string }) => (
+
+ {backTo && (
+
+
+ Suprimentos
+
+ )}
+
+
+);
+
+const ModuleCard = ({
+ title,
+ description,
+ icon: Icon,
+ to,
+ disabled,
+}: {
+ title: string;
+ description: string;
+ icon: typeof Package;
+ to?: string;
+ disabled?: boolean;
+}) => {
+ const content = (
+ <>
+
+
+
+
+
+
{title}
+ {disabled ? (
+
Em breve
+ ) : (
+
+ )}
+
+
{description}
+
+ >
+ );
+
+ if (disabled || !to) {
+ return (
+
+ {content}
+
+ );
+ }
+
+ return (
+
+ {content}
+
+ );
+};
+
+const SuppliesHub = () => (
+
+);
+
+const StatGrid = () => (
+
+ {stats.map(stat => (
+
+
{stat.value}
+
{stat.label}
+
+ ))}
+
+);
+
+const InventoryDashboard = () => (
+
+
+
+
Por categoria de material
+
+ {[
+ { title: 'Malha / Tecido', icon: Ruler },
+ { title: 'Botões / Acessórios', icon: Warehouse },
+ ].map(item => (
+
+
+
{item.title}
+
Em breve
+
Aguardando cadastro
+
Não configurado
+
+ ))}
+
+
+
+
Alertas de estoque
+
Nenhum alerta no momento.
+
+
+
+
Últimas entradas
+
+
+
Nenhuma entrada registrada.
+
+
+);
+
+const BalanceTab = () => (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Saldo por tipo
+ Clique para expandir lotes
+
+
+
+
Nenhum item em estoque
+
Registre entradas para ver o saldo aqui.
+
+
+
+);
+
+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.
+
+
1. Qual categoria de produto chegou?
+
+ {receiptCategories.map(category => (
+
+ ))}
+
+
+
+);
+
+const InventoryCountTab = () => (
+
+
+
+
Inventário físico
+
+ Compare o estoque do sistema com a contagem física. O ajuste gera movimentação com justificativa.
+
+
+
+
+
+
+
+
Nenhum lote para inventariar
+
+
+
+);
+
+const MovementsTab = () => (
+
+
+
+
+
+
+
+
+
+
Nenhuma movimentação ainda
+
+
+
+);
+
+const InventoryScreen = () => {
+ const [activeTab, setActiveTab] = useState('dashboard');
+
+ return (
+
+
+
+ {inventoryTabs.map(tab => (
+
+ ))}
+
+ {activeTab === 'dashboard' &&
}
+ {activeTab === 'balance' &&
}
+ {activeTab === 'receipts' &&
}
+ {activeTab === 'inventory' &&
}
+ {activeTab === 'movements' &&
}
+
+ );
+};
+
+const FabricPlanningScreen = () => (
+
+
+
+
+
+
Planos de malha
+
Entrada operacional preparada para a próxima etapa do módulo.
+
+
Em preparação
+
+
+
+
Nenhum plano de malha cadastrado
+
Quando houver planos, eles alimentarão recebimentos e corte.
+
+
+
+);
+
+const Supplies = () => {
+ const { section } = useParams<{ section?: string }>();
+
+ if (!section) return ;
+ if (section === 'inventory') return ;
+ if (section === 'fabric-planning') return ;
+
+ return ;
+};
+
+export default Supplies;