Align supply material actions

This commit is contained in:
Cauê Faleiros
2026-08-10 10:26:53 -03:00
parent 5ed91fa36f
commit 14fe69bb9d

View File

@@ -2110,23 +2110,14 @@ const AffectedProducts = ({ products }: { products: SupplyPurchaseNeed['products
<div className="mt-3 flex flex-wrap items-center gap-2 border-t border-dark-border/70 pt-3">
<span className="text-[10px] font-bold uppercase tracking-widest text-dark-muted">Produtos afetados</span>
{products.slice(0, 3).map(product => (
<div key={product.productId} className="flex max-w-full items-center overflow-hidden rounded-md border border-dark-border bg-dark-input">
<RouterLink
to={`/products/${product.productId}`}
className="min-w-0 cursor-pointer truncate px-2 py-1 text-[11px] font-bold text-dark-muted transition-colors hover:text-brand-primary"
title={product.name}
>
#{product.productId} · {product.name}
</RouterLink>
<RouterLink
to={`/products/${product.productId}`}
className="flex h-7 w-7 shrink-0 items-center justify-center border-l border-dark-border text-brand-primary transition-colors hover:bg-brand-primary/10"
title={`Ver produto ${product.name}`}
aria-label={`Ver produto ${product.name}`}
>
<Eye className="h-3.5 w-3.5" />
</RouterLink>
</div>
<RouterLink
key={product.productId}
to={`/products/${product.productId}`}
className="max-w-full cursor-pointer truncate rounded-md border border-dark-border bg-dark-input px-2 py-1 text-[11px] font-bold text-dark-muted transition-colors hover:border-brand-primary hover:text-brand-primary"
title={product.name}
>
#{product.productId} · {product.name}
</RouterLink>
))}
{products.length > 3 && <span className="text-xs font-bold text-dark-muted">+{products.length - 3} SKUs</span>}
</div>
@@ -2136,10 +2127,11 @@ const AffectedProducts = ({ products }: { products: SupplyPurchaseNeed['products
const PurchaseMaterialQueue = ({ needs, onEditMaterial }: { needs: SupplyPurchaseNeed[]; onEditMaterial: (need: SupplyPurchaseNeed) => void }) => (
<>
<div className="border-b border-dark-border bg-dark-input/40 px-4 py-3">
<div className="grid gap-3 text-[10px] font-bold uppercase tracking-widest text-dark-muted xl:grid-cols-[minmax(300px,1.35fr)_minmax(380px,1fr)_150px]">
<span>Material e impacto</span>
<div className="grid gap-3 text-[10px] font-bold uppercase tracking-widest text-dark-muted xl:grid-cols-[minmax(280px,1.35fr)_minmax(380px,1fr)_150px_88px]">
<span>Material</span>
<span className="hidden xl:block">Como a compra foi calculada</span>
<span className="hidden text-right xl:block">Decisão</span>
<span className="hidden text-right xl:block">Impacto</span>
<span className="hidden text-right xl:block">Ações</span>
</div>
</div>
<div className="divide-y divide-dark-border">
@@ -2166,7 +2158,7 @@ const PurchaseMaterialQueue = ({ needs, onEditMaterial }: { needs: SupplyPurchas
return (
<article key={need.material} className={`border-l-2 ${accent} px-4 py-4 transition-colors hover:bg-dark-input/35`}>
<div className="grid gap-4 xl:grid-cols-[minmax(300px,1.35fr)_minmax(380px,1fr)_150px] xl:items-center">
<div className="grid gap-4 xl:grid-cols-[minmax(280px,1.35fr)_minmax(380px,1fr)_150px_88px] xl:items-center">
<div className="min-w-0">
<div className="flex flex-wrap items-center gap-2">
<h3 className="text-sm font-bold text-dark-text">{getNeedDisplayName(need)}</h3>
@@ -2202,15 +2194,25 @@ const PurchaseMaterialQueue = ({ needs, onEditMaterial }: { needs: SupplyPurchas
<p className="text-[10px] font-bold uppercase tracking-widest text-dark-muted">Impacto</p>
<p className="mt-1 text-sm font-bold text-dark-text">{products.length} {products.length === 1 ? 'SKU' : 'SKUs'} dependem</p>
<p className="mt-1 text-xs font-semibold text-dark-muted">{formatNumber(sumNeedProducts(need, 'suggestedQuantity'))} un. planejadas</p>
</div>
<div className="flex items-center gap-2 xl:justify-self-end">
<button
type="button"
onClick={() => onEditMaterial(need)}
className="mt-3 inline-flex h-8 w-8 cursor-pointer items-center justify-center rounded-lg border border-dark-border bg-dark-input text-sky-300 transition-colors hover:border-sky-400/50 hover:bg-sky-400/10"
className="inline-flex h-8 w-8 cursor-pointer items-center justify-center rounded-lg bg-dark-input text-dark-text transition-colors hover:bg-dark-border"
title={`Editar dados de ${getNeedDisplayName(need)}`}
aria-label={`Editar dados de ${getNeedDisplayName(need)}`}
>
<Pencil className="h-3.5 w-3.5" />
</button>
<RouterLink
to={getMaterialRegistrationPath(need.material)}
className="inline-flex h-8 w-8 cursor-pointer items-center justify-center rounded-lg bg-brand-primary/10 text-brand-primary transition-opacity hover:opacity-80"
title={`Ver cadastro de ${getNeedDisplayName(need)}`}
aria-label={`Ver cadastro de ${getNeedDisplayName(need)}`}
>
<Eye className="h-3.5 w-3.5" />
</RouterLink>
</div>
</div>
@@ -2225,10 +2227,11 @@ const PurchaseMaterialQueue = ({ needs, onEditMaterial }: { needs: SupplyPurchas
const PurchaseServiceQueue = ({ needs, onEditMaterial }: { needs: SupplyPurchaseNeed[]; onEditMaterial: (need: SupplyPurchaseNeed) => void }) => (
<>
<div className="border-b border-dark-border bg-dark-input/40 px-4 py-3">
<div className="grid gap-3 text-[10px] font-bold uppercase tracking-widest text-dark-muted xl:grid-cols-[minmax(320px,1.4fr)_minmax(260px,1fr)_180px]">
<span>Serviço e impacto</span>
<div className="grid gap-3 text-[10px] font-bold uppercase tracking-widest text-dark-muted xl:grid-cols-[minmax(300px,1.4fr)_minmax(260px,1fr)_150px_88px]">
<span>Serviço</span>
<span className="hidden xl:block">Volume a programar</span>
<span className="hidden text-right xl:block">Próximo passo</span>
<span className="hidden text-right xl:block">Impacto</span>
<span className="hidden text-right xl:block">Ações</span>
</div>
</div>
<div className="divide-y divide-dark-border">
@@ -2238,7 +2241,7 @@ const PurchaseServiceQueue = ({ needs, onEditMaterial }: { needs: SupplyPurchase
return (
<article key={need.material} className={`border-l-2 ${isCovered ? 'border-l-emerald-400' : 'border-l-sky-400'} px-4 py-4 transition-colors hover:bg-dark-input/35`}>
<div className="grid gap-4 xl:grid-cols-[minmax(320px,1.4fr)_minmax(260px,1fr)_180px] xl:items-center">
<div className="grid gap-4 xl:grid-cols-[minmax(300px,1.4fr)_minmax(260px,1fr)_150px_88px] xl:items-center">
<div className="min-w-0">
<div className="flex flex-wrap items-center gap-2">
<h3 className="text-sm font-bold text-dark-text">{getNeedDisplayName(need)}</h3>
@@ -2268,15 +2271,25 @@ const PurchaseServiceQueue = ({ needs, onEditMaterial }: { needs: SupplyPurchase
<p className="text-[10px] font-bold uppercase tracking-widest text-dark-muted">Impacto</p>
<p className="mt-1 text-sm font-bold text-dark-text">{products.length} {products.length === 1 ? 'SKU' : 'SKUs'} dependem</p>
<p className="mt-1 text-xs font-semibold text-dark-muted">{formatNumber(sumNeedProducts(need, 'suggestedQuantity'))} un. planejadas</p>
</div>
<div className="flex items-center gap-2 xl:justify-self-end">
<button
type="button"
onClick={() => onEditMaterial(need)}
className="mt-3 inline-flex h-8 w-8 cursor-pointer items-center justify-center rounded-lg border border-dark-border bg-dark-input text-sky-300 transition-colors hover:border-sky-400/50 hover:bg-sky-400/10"
className="inline-flex h-8 w-8 cursor-pointer items-center justify-center rounded-lg bg-dark-input text-dark-text transition-colors hover:bg-dark-border"
title={`Editar dados de ${getNeedDisplayName(need)}`}
aria-label={`Editar dados de ${getNeedDisplayName(need)}`}
>
<Pencil className="h-3.5 w-3.5" />
</button>
<RouterLink
to={getMaterialRegistrationPath(need.material)}
className="inline-flex h-8 w-8 cursor-pointer items-center justify-center rounded-lg bg-brand-primary/10 text-brand-primary transition-opacity hover:opacity-80"
title={`Ver cadastro de ${getNeedDisplayName(need)}`}
aria-label={`Ver cadastro de ${getNeedDisplayName(need)}`}
>
<Eye className="h-3.5 w-3.5" />
</RouterLink>
</div>
</div>
@@ -2293,6 +2306,12 @@ const getMaterialRegistrationSku = (material: string) => {
return /^[A-Z0-9_-]{2,}$/i.test(candidate) ? candidate : '';
};
const getMaterialRegistrationPath = (material: string) => buildSkuEditPath({
sku: getMaterialRegistrationSku(material),
name: material,
type: 'raw_material',
});
const MaterialDetailsModal = ({
need,
onClose,
@@ -2309,11 +2328,7 @@ const MaterialDetailsModal = ({
});
const [isSaving, setIsSaving] = useState(false);
const [error, setError] = useState('');
const registrationPath = buildSkuEditPath({
sku: getMaterialRegistrationSku(need.material),
name: need.material,
type: 'raw_material',
});
const registrationPath = getMaterialRegistrationPath(need.material);
const submit = async (event: FormEvent<HTMLFormElement>) => {
event.preventDefault();