Refine pending data tables
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 2m27s

This commit is contained in:
Cauê Faleiros
2026-08-17 12:38:27 -03:00
parent 36981c9ac5
commit a9cae33ca0

View File

@@ -8,7 +8,6 @@ import RefreshStatus from '../components/RefreshStatus';
import SkuPlanningModal from '../components/SkuPlanningModal';
import { classifyCutFamily, CUT_FAMILY_RULES, type CutFamilyKey } from '../analytics/cutting';
import { fetchCuttingSettings, fetchProductAnalytics, fetchStock, fetchSupplySummary, saveCuttingSettings } from '../dataService';
import { buildConsumptionReferencePath } from '../catalogLinks';
import { getProductTypeConfig, resolveProductType, type ProductTypeKey } from '../productClassification';
import { parseProductName } from '../productParsing';
import type { CutProductOverride, CuttingSettings, DateRange, ProductAnalyticsItem, StockData, SupplySummary } from '../types';
@@ -157,7 +156,7 @@ const PlanningIssues = () => {
const [editingProduct, setEditingProduct] = useState<PlanningIssueRow | null>(null);
const [isSaving, setIsSaving] = useState(false);
const [currentPage, setCurrentPage] = useState(1);
const [itemsPerPage, setItemsPerPage] = useState(20);
const [itemsPerPage, setItemsPerPage] = useState(10);
useEffect(() => {
let isMounted = true;
@@ -594,32 +593,28 @@ const PlanningIssues = () => {
) : activeQueue === 'negative_stock' ? (
visibleNegativeStockRows.length ? (
<div className="overflow-hidden rounded-2xl border border-dark-border bg-dark-card shadow-sm">
<div className="border-b border-dark-border px-5 py-4">
<h2 className="text-base font-bold text-dark-text">Saldos negativos</h2>
<p className="mt-1 text-sm font-semibold text-dark-muted">São exibidos para conferência, mas contam como zero disponível no planejamento.</p>
<div className="flex flex-col gap-1 border-b border-dark-border px-5 py-4 sm:flex-row sm:items-center sm:justify-between">
<div><h2 className="text-base font-bold text-dark-text">Saldos negativos</h2><p className="mt-1 text-sm font-semibold text-dark-muted">Visíveis para auditoria; o planejamento considera saldo disponível igual a zero.</p></div>
<span className="w-fit rounded-full border border-red-400/25 bg-red-400/10 px-2.5 py-1 text-xs font-bold text-red-300">{formatNumber(visibleNegativeStockRows.length)} materiais</span>
</div>
<div className="overflow-x-auto">
<table className="w-full min-w-[860px] text-left text-sm">
<table className="w-full min-w-[680px] text-left text-sm">
<thead className="border-b border-dark-border bg-dark-header text-dark-muted">
<tr>
<th className="px-5 py-4 text-[10px] font-bold uppercase tracking-wider">SKU</th>
<th className="px-5 py-4 text-[10px] font-bold uppercase tracking-wider">Material</th>
<th className="px-5 py-4 text-right text-[10px] font-bold uppercase tracking-wider">Saldo informado</th>
<th className="px-5 py-4 text-[10px] font-bold uppercase tracking-wider">Tratamento no plano</th>
<th className="px-5 py-4 text-right text-[10px] font-bold uppercase tracking-wider">Ação</th>
<th className="px-5 py-3 text-[10px] font-bold uppercase tracking-wider">Material</th>
<th className="px-5 py-3 text-right text-[10px] font-bold uppercase tracking-wider">Saldo informado</th>
<th className="px-5 py-3 text-[10px] font-bold uppercase tracking-wider">Planejamento</th>
<th className="px-5 py-3 text-right text-[10px] font-bold uppercase tracking-wider">Ações</th>
</tr>
</thead>
<tbody className="divide-y divide-dark-border">
{paginatedNegativeStockRows.map(row => (
<tr key={row.produto_id} className="transition-colors hover:bg-dark-input/50">
<td className="px-5 py-3 font-mono text-xs font-semibold text-dark-muted">#{row.produto_id}</td>
<td className="max-w-[420px] px-5 py-3"><p className="truncate font-bold text-dark-text" title={row.nome}>{row.nome}</p></td>
<td className="px-5 py-3 text-right font-bold text-red-300">{formatNumber(Number(row.saldo), 2)} un.</td>
<td className="px-5 py-3"><span className="inline-flex rounded-full border border-dark-border bg-dark-input px-2.5 py-1 text-xs font-bold text-dark-muted">0 disponível</span></td>
<td className="max-w-0 px-5 py-3"><p className="truncate font-bold text-dark-text" title={row.nome}>{row.nome}</p><p className="mt-1 font-mono text-[11px] font-semibold text-dark-muted">#{row.produto_id}</p></td>
<td className="px-5 py-3 text-right"><p className="font-bold text-red-300">{formatNumber(Number(row.saldo), 2)} un.</p><p className="mt-1 text-[11px] font-semibold text-dark-muted">informado no Tiny</p></td>
<td className="px-5 py-3"><span className="inline-flex rounded-full border border-dark-border bg-dark-input px-2.5 py-1 text-xs font-bold text-dark-muted">Usa 0 disponível</span></td>
<td className="px-5 py-3 text-right">
<Link to="/supplies/inventory?tab=stock" className="inline-flex h-8 items-center gap-1.5 rounded-lg bg-dark-input px-2.5 text-xs font-bold text-dark-text transition-colors hover:bg-dark-border cursor-pointer">
Conferir <Eye className="h-3.5 w-3.5" />
</Link>
<Link to="/supplies/inventory?tab=stock" title={`Conferir ${row.nome} no estoque`} aria-label={`Conferir ${row.nome} no estoque`} className="inline-flex h-8 w-8 items-center justify-center rounded-lg border border-dark-border bg-dark-input text-brand-primary transition-colors hover:border-brand-primary cursor-pointer"><Eye className="h-3.5 w-3.5" /></Link>
</td>
</tr>
))}
@@ -648,33 +643,31 @@ const PlanningIssues = () => {
)
) : visibleMissingCompositionRows.length ? (
<div className="overflow-hidden rounded-2xl border border-dark-border bg-dark-card shadow-sm">
<div className="border-b border-dark-border px-5 py-4">
<h2 className="text-base font-bold text-dark-text">SKUs sem composição</h2>
<p className="mt-1 text-sm font-semibold text-dark-muted">Estes produtos continuam operando, mas não geram demanda de material até receberem composição.</p>
<div className="flex flex-col gap-1 border-b border-dark-border px-5 py-4 sm:flex-row sm:items-center sm:justify-between">
<div><h2 className="text-base font-bold text-dark-text">SKUs sem composição</h2><p className="mt-1 text-sm font-semibold text-dark-muted">Continuam operando, mas não entram na necessidade de materiais até receberem uma composição.</p></div>
<span className="w-fit rounded-full border border-sky-400/25 bg-sky-400/10 px-2.5 py-1 text-xs font-bold text-sky-300">{formatNumber(visibleMissingCompositionRows.length)} SKUs</span>
</div>
<div className="overflow-x-auto">
<table className="w-full min-w-[940px] text-left text-sm">
<table className="w-full min-w-[760px] text-left text-sm">
<thead className="border-b border-dark-border bg-dark-header text-dark-muted">
<tr>
<th className="px-5 py-4 text-[10px] font-bold uppercase tracking-wider">SKU</th>
<th className="px-5 py-4 text-[10px] font-bold uppercase tracking-wider">Produto</th>
<th className="px-5 py-4 text-right text-[10px] font-bold uppercase tracking-wider">Vendido</th>
<th className="px-5 py-4 text-right text-[10px] font-bold uppercase tracking-wider">Estoque</th>
<th className="px-5 py-4 text-right text-[10px] font-bold uppercase tracking-wider">Sugestão de corte</th>
<th className="px-5 py-4 text-right text-[10px] font-bold uppercase tracking-wider">Ações</th>
<th className="px-5 py-3 text-[10px] font-bold uppercase tracking-wider">Produto</th>
<th className="px-5 py-3 text-right text-[10px] font-bold uppercase tracking-wider">Vendido</th>
<th className="px-5 py-3 text-right text-[10px] font-bold uppercase tracking-wider">Estoque</th>
<th className="px-5 py-3 text-right text-[10px] font-bold uppercase tracking-wider">Cortar agora</th>
<th className="px-5 py-3 text-right text-[10px] font-bold uppercase tracking-wider">Ações</th>
</tr>
</thead>
<tbody className="divide-y divide-dark-border">
{paginatedMissingCompositionRows.map(row => (
<tr key={row.productId} className="transition-colors hover:bg-dark-input/50">
<td className="px-5 py-3 font-mono text-xs font-semibold text-dark-muted">#{row.productId}</td>
<td className="max-w-[420px] px-5 py-3"><p className="truncate font-bold text-dark-text" title={row.name}>{row.name}</p></td>
<td className="max-w-0 px-5 py-3"><p className="truncate font-bold text-dark-text" title={row.name}>{row.name}</p><p className="mt-1 font-mono text-[11px] font-semibold text-dark-muted">#{row.productId}</p></td>
<td className="px-5 py-3 text-right font-bold text-dark-text">{formatNumber(row.quantitySold)} un.</td>
<td className="px-5 py-3 text-right font-bold text-dark-text">{formatNumber(row.stockQuantity)} un.</td>
<td className="px-5 py-3 text-right font-bold text-amber-300">{formatNumber(row.suggestedQuantity)} un.</td>
<td className="px-5 py-3 text-right">
<div className="flex justify-end gap-2">
<Link to={buildConsumptionReferencePath({ sku: row.productId, name: row.name })} className="inline-flex h-8 w-8 items-center justify-center rounded-lg bg-dark-input text-dark-text transition-colors hover:bg-dark-border cursor-pointer" title="Cadastrar composição" aria-label={`Cadastrar composição de ${row.name}`}><Pencil className="h-3.5 w-3.5" /></Link>
<Link to={`/products/${row.productId}`} className="inline-flex h-8 w-8 items-center justify-center rounded-lg border border-dark-border bg-dark-input text-dark-text transition-colors hover:border-brand-primary cursor-pointer" title="Cadastrar composição" aria-label={`Cadastrar composição de ${row.name}`}><Pencil className="h-3.5 w-3.5" /></Link>
<Link to={`/products/${row.productId}`} className="inline-flex h-8 w-8 items-center justify-center rounded-lg bg-brand-primary/10 text-brand-primary transition-opacity hover:opacity-80 cursor-pointer" title="Ver produto" aria-label={`Ver produto ${row.name}`}><Eye className="h-3.5 w-3.5" /></Link>
</div>
</td>