Simplify cutting plan layout
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 47s

This commit is contained in:
Cauê Faleiros
2026-08-11 10:01:22 -03:00
parent a93068e86b
commit f274616b80

View File

@@ -1040,58 +1040,47 @@ const Cutting = () => {
</div>
)}
<div className="grid grid-cols-1 gap-4 md:grid-cols-4">
<div className="rounded-2xl border border-dark-border bg-dark-card p-5 shadow-sm">
<div className="flex items-start justify-between gap-4">
<div>
<p className="text-xs font-bold uppercase tracking-widest text-dark-muted">Necessidade bruta</p>
<p className="mt-2 text-3xl font-bold text-red-300">{formatNumber(cutExecutionSummary.rawUnits)}</p>
<p className="mt-1 text-xs font-semibold text-dark-muted">{formatNumber(cutPlan.summary.skuCount)} SKUs com necessidade</p>
</div>
<div className="rounded-xl border border-red-400/25 bg-red-400/10 p-3 text-red-300">
<Scissors className="h-5 w-5" />
</div>
</div>
<div className="rounded-2xl border border-dark-border bg-dark-card p-1.5 shadow-sm">
<div className="flex flex-wrap gap-1.5">
<button type="button" onClick={() => setActiveCuttingView('plan')} aria-pressed={activeCuttingView === 'plan'} className={`inline-flex h-10 items-center gap-2 rounded-xl px-3 text-sm font-bold transition-colors cursor-pointer ${activeCuttingView === 'plan' ? 'bg-brand-primary/15 text-brand-primary' : 'text-dark-muted hover:bg-dark-input hover:text-dark-text'}`}>
<Scissors className="h-4 w-4" /> Necessidades <span className="text-xs opacity-80">{formatNumber(cutPlan.summary.skuCount)}</span>
</button>
<button type="button" onClick={() => setActiveCuttingView('families')} aria-pressed={activeCuttingView === 'families'} className={`inline-flex h-10 items-center gap-2 rounded-xl px-3 text-sm font-bold transition-colors cursor-pointer ${activeCuttingView === 'families' ? 'bg-brand-primary/15 text-brand-primary' : 'text-dark-muted hover:bg-dark-input hover:text-dark-text'}`}>
<Layers3 className="h-4 w-4" /> Famílias <span className="text-xs opacity-80">{formatNumber(cutPlan.familySummaries.length)}</span>
</button>
<button type="button" onClick={() => setActiveCuttingView('issues')} aria-pressed={activeCuttingView === 'issues'} className={`inline-flex h-10 items-center gap-2 rounded-xl px-3 text-sm font-bold transition-colors cursor-pointer ${activeCuttingView === 'issues' ? 'bg-amber-400/10 text-amber-300' : 'text-dark-muted hover:bg-dark-input hover:text-dark-text'}`}>
<AlertTriangle className="h-4 w-4" /> Pendências <span className="text-xs opacity-80">{formatNumber(cutPlan.summary.rowsWithIssues)}</span>
</button>
</div>
</div>
<div className="rounded-2xl border border-dark-border bg-dark-card p-5 shadow-sm">
<div className="flex items-start justify-between gap-4">
<div>
<p className="text-xs font-bold uppercase tracking-widest text-dark-muted">Pronto para corte</p>
<p className="mt-2 text-3xl font-bold text-emerald-300">{formatNumber(cutExecutionSummary.readyUnits)}</p>
<p className="mt-1 text-xs font-semibold text-dark-muted">{formatNumber(cutExecutionSummary.readyRows)} SKUs liberados para gerar OP</p>
</div>
<div className="rounded-xl border border-brand-primary/25 bg-brand-primary/10 p-3 text-brand-primary">
<Layers3 className="h-5 w-5" />
</div>
</div>
</div>
<div className="rounded-2xl border border-dark-border bg-dark-card p-5 shadow-sm">
<div className="flex items-start justify-between gap-4">
<div>
<p className="text-xs font-bold uppercase tracking-widest text-dark-muted">Bloqueios</p>
<p className="mt-2 text-3xl font-bold text-amber-300">{formatNumber(cutExecutionSummary.blockedRows)}</p>
<p className="mt-1 text-xs font-semibold text-dark-muted">{formatNumber(cutExecutionSummary.blockedByMaterial)} material · {formatNumber(cutExecutionSummary.blockedByData)} dados</p>
</div>
<div className="rounded-xl border border-amber-400/25 bg-amber-400/10 p-3 text-amber-300">
<AlertTriangle className="h-5 w-5" />
</div>
</div>
</div>
<div className="rounded-2xl border border-dark-border bg-dark-card p-5 shadow-sm">
<div className="flex items-start justify-between gap-4">
<div>
<p className="text-xs font-bold uppercase tracking-widest text-dark-muted">Famílias</p>
<p className="mt-2 text-3xl font-bold text-brand-primary">{formatNumber(cutPlan.summary.familiesWithNeed)}</p>
<p className="mt-1 text-xs font-semibold text-dark-muted">{cutPlan.summary.estimatedRolls === null ? 'Rendimento ainda não configurado' : `${formatNumber(cutPlan.summary.estimatedRolls)} rolos estimados`}</p>
</div>
<div className="rounded-xl border border-brand-primary/25 bg-brand-primary/10 p-3 text-brand-primary">
<Layers3 className="h-5 w-5" />
</div>
</div>
</div>
<div className="grid grid-cols-2 divide-x divide-y divide-dark-border overflow-hidden rounded-2xl border border-dark-border bg-dark-card shadow-sm lg:grid-cols-4 lg:divide-y-0">
{[
{ id: 'all', label: 'Necessidade', value: `${formatNumber(cutExecutionSummary.rawUnits)} un.`, detail: `${formatNumber(cutPlan.summary.skuCount)} SKUs`, tone: 'text-dark-text' },
{ id: 'ready', label: 'Pronto para corte', value: `${formatNumber(cutExecutionSummary.readyUnits)} un.`, detail: `${formatNumber(cutExecutionSummary.readyRows)} SKUs liberados`, tone: 'text-emerald-300' },
{ id: 'blocked', label: 'Bloqueados', value: formatNumber(cutExecutionSummary.blockedRows), detail: `${formatNumber(cutExecutionSummary.blockedByMaterial)} material · ${formatNumber(cutExecutionSummary.blockedByData)} dados`, tone: cutExecutionSummary.blockedRows ? 'text-amber-300' : 'text-dark-text' },
{ id: 'families', label: 'Famílias', value: formatNumber(cutPlan.summary.familiesWithNeed), detail: cutPlan.summary.estimatedRolls === null ? 'Rendimento a configurar' : `${formatNumber(cutPlan.summary.estimatedRolls)} rolos estimados`, tone: 'text-dark-text' }
].map(metric => (
<button
key={metric.id}
type="button"
onClick={() => {
if (metric.id === 'families') {
setActiveCuttingView('families');
return;
}
setActiveCuttingView('plan');
setExecutionFilter(metric.id as ExecutionFilter);
setCutFilter('need');
setCurrentPage(1);
}}
className={`p-4 text-left transition-colors hover:bg-dark-input/60 cursor-pointer sm:px-5 ${metric.id === 'families' ? activeCuttingView === 'families' ? 'bg-brand-primary/[0.07]' : '' : activeCuttingView === 'plan' && executionFilter === metric.id ? 'bg-brand-primary/[0.07]' : ''}`}
>
<p className="text-[10px] font-bold uppercase tracking-widest text-dark-muted">{metric.label}</p>
<p className={`mt-1 text-xl font-bold ${metric.tone}`}>{metric.value}</p>
<p className="mt-1 truncate text-xs font-semibold text-dark-muted">{metric.detail}</p>
</button>
))}
</div>
{cutExecutionSummary.rawUnits > 0 && cutExecutionSummary.readyUnits === 0 && (
@@ -1104,58 +1093,6 @@ const Cutting = () => {
</div>
)}
<div className="rounded-2xl border border-dark-border bg-dark-card p-2 shadow-sm">
<div className="grid grid-cols-1 gap-2 md:grid-cols-3">
<button
type="button"
onClick={() => setActiveCuttingView('plan')}
aria-pressed={activeCuttingView === 'plan'}
className={`flex items-center justify-between gap-3 rounded-xl border px-4 py-3 text-left transition-colors cursor-pointer ${activeCuttingView === 'plan' ? 'border-brand-primary/40 bg-brand-primary/15 text-brand-primary' : 'border-transparent text-dark-muted hover:bg-dark-input hover:text-dark-text'}`}
>
<span className="flex items-center gap-3">
<Scissors className="h-4 w-4" />
<span>
<span className="block text-sm font-bold">Necessidades</span>
<span className="block text-xs font-semibold opacity-80">Demanda por SKU</span>
</span>
</span>
<span className="text-sm font-bold">{formatNumber(cutPlan.summary.skuCount)}</span>
</button>
<button
type="button"
onClick={() => setActiveCuttingView('families')}
aria-pressed={activeCuttingView === 'families'}
className={`flex items-center justify-between gap-3 rounded-xl border px-4 py-3 text-left transition-colors cursor-pointer ${activeCuttingView === 'families' ? 'border-brand-primary/40 bg-brand-primary/15 text-brand-primary' : 'border-transparent text-dark-muted hover:bg-dark-input hover:text-dark-text'}`}
>
<span className="flex items-center gap-3">
<Layers3 className="h-4 w-4" />
<span>
<span className="block text-sm font-bold">Famílias</span>
<span className="block text-xs font-semibold opacity-80">Resumo de corte</span>
</span>
</span>
<span className="text-sm font-bold">{formatNumber(cutPlan.familySummaries.length)}</span>
</button>
<button
type="button"
onClick={() => setActiveCuttingView('issues')}
aria-pressed={activeCuttingView === 'issues'}
className={`flex items-center justify-between gap-3 rounded-xl border px-4 py-3 text-left transition-colors cursor-pointer ${activeCuttingView === 'issues' ? 'border-amber-400/40 bg-amber-400/10 text-amber-300' : 'border-transparent text-dark-muted hover:bg-dark-input hover:text-dark-text'}`}
>
<span className="flex items-center gap-3">
<AlertTriangle className="h-4 w-4" />
<span>
<span className="block text-sm font-bold">Pendências</span>
<span className="block text-xs font-semibold opacity-80">Dados a revisar</span>
</span>
</span>
<span className="text-sm font-bold">{formatNumber(cutPlan.summary.rowsWithIssues)}</span>
</button>
</div>
</div>
{activeCuttingView === 'issues' && (
<div className="rounded-2xl border border-dark-border bg-dark-card p-4 shadow-sm">
<div className="mb-3 flex flex-col gap-3 md:flex-row md:items-center md:justify-between">
@@ -1260,29 +1197,6 @@ const Cutting = () => {
{activeCuttingView === 'plan' && (
<>
<div className="grid grid-cols-2 gap-3 xl:grid-cols-4">
{[
{ id: 'all' as const, label: 'Fila de corte', detail: `${formatNumber(cutPlan.summary.skuCount)} SKUs com necessidade`, value: cutExecutionSummary.rawUnits, tone: 'default' },
{ id: 'ready' as const, label: 'Pronto para cortar', detail: `${formatNumber(cutExecutionSummary.readyRows)} SKUs liberados`, value: cutExecutionSummary.readyUnits, tone: 'ready' },
{ id: 'blocked' as const, label: 'Falta material', detail: `${formatNumber(cutExecutionSummary.blockedByMaterial)} SKUs bloqueados`, value: cutExecutionSummary.blockedByMaterial, tone: 'blocked' },
{ id: 'data' as const, label: 'Dados pendentes', detail: 'Material disponível, cadastro incompleto', value: cutExecutionSummary.blockedByData, tone: 'data' },
].map(option => (
<button
key={option.id}
type="button"
onClick={() => {
setExecutionFilter(option.id);
setCutFilter('need');
setCurrentPage(1);
}}
className={`rounded-2xl border p-4 text-left shadow-sm transition-colors cursor-pointer ${executionFilter === option.id ? option.tone === 'ready' ? 'border-emerald-400/45 bg-emerald-400/[0.07]' : option.tone === 'blocked' ? 'border-red-400/45 bg-red-400/[0.07]' : option.tone === 'data' ? 'border-amber-400/45 bg-amber-400/[0.07]' : 'border-brand-primary/45 bg-brand-primary/[0.07]' : 'border-dark-border bg-dark-card hover:border-brand-primary/35'}`}
>
<p className="text-xs font-bold uppercase tracking-widest text-dark-muted">{option.label}</p>
<p className={`mt-2 text-2xl font-bold ${option.tone === 'ready' ? 'text-emerald-300' : option.tone === 'blocked' ? 'text-red-300' : option.tone === 'data' ? 'text-amber-300' : 'text-dark-text'}`}>{formatNumber(option.value)}{option.id === 'all' || option.id === 'ready' ? ' un.' : ''}</p>
<p className="mt-1 truncate text-xs font-semibold text-dark-muted">{option.detail}</p>
</button>
))}
</div>
<div className="grid grid-cols-1 gap-3 rounded-2xl border border-dark-border bg-dark-card p-4 shadow-sm xl:grid-cols-[1fr_170px_170px_170px_190px]">
<div className="relative">
<Search className="absolute left-3 top-1/2 h-5 w-5 -translate-y-1/2 text-zinc-400 dark:text-dark-muted" />