Add SKU edit actions
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 2m18s
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 2m18s
This commit is contained in:
14
src/catalogLinks.ts
Normal file
14
src/catalogLinks.ts
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
type SkuEditParams = {
|
||||||
|
sku: string;
|
||||||
|
name?: string;
|
||||||
|
color?: string;
|
||||||
|
size?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const buildSkuEditPath = ({ sku, name = '', color = '', size = '' }: SkuEditParams) => {
|
||||||
|
const params = new URLSearchParams({ tab: 'products', sku });
|
||||||
|
if (name) params.set('name', name);
|
||||||
|
if (color) params.set('color', color);
|
||||||
|
if (size) params.set('size', size);
|
||||||
|
return `/registrations?${params.toString()}`;
|
||||||
|
};
|
||||||
@@ -1,10 +1,11 @@
|
|||||||
import { useEffect, useMemo, useState } from 'react';
|
import { useEffect, useMemo, useState } from 'react';
|
||||||
import { Link, useOutletContext } from 'react-router-dom';
|
import { Link, useOutletContext } from 'react-router-dom';
|
||||||
import { AlertTriangle, ArrowLeft, ClipboardList, Download, Layers3, Package, Palette, RotateCcw, Ruler, Save as SaveIcon, Scissors, Search, Settings2, X } from 'lucide-react';
|
import { AlertTriangle, ArrowLeft, ClipboardList, Download, Eye, Layers3, Palette, Pencil, RotateCcw, Ruler, Save as SaveIcon, Scissors, Search, Settings2, X } from 'lucide-react';
|
||||||
import DateRangePicker from '../components/DateRangePicker';
|
import DateRangePicker from '../components/DateRangePicker';
|
||||||
import PaginationControls from '../components/PaginationControls';
|
import PaginationControls from '../components/PaginationControls';
|
||||||
import ProductColorBadge from '../components/ProductColorBadge';
|
import ProductColorBadge from '../components/ProductColorBadge';
|
||||||
import RefreshStatus from '../components/RefreshStatus';
|
import RefreshStatus from '../components/RefreshStatus';
|
||||||
|
import { buildSkuEditPath } from '../catalogLinks';
|
||||||
import { CUT_FAMILY_RULES, buildCutPlan, buildOpenProductionByProductId, type CutFamilyKey, type CutIssue, type CutPlanSkuRow, type CutProductOverride } from '../analytics/cutting';
|
import { CUT_FAMILY_RULES, buildCutPlan, buildOpenProductionByProductId, type CutFamilyKey, type CutIssue, type CutPlanSkuRow, type CutProductOverride } from '../analytics/cutting';
|
||||||
import { exportToCSV, fetchCuttingSettings, fetchProductAnalytics, fetchProductionOrders, saveCuttingSettings } from '../dataService';
|
import { exportToCSV, fetchCuttingSettings, fetchProductAnalytics, fetchProductionOrders, saveCuttingSettings } from '../dataService';
|
||||||
import type { CuttingSettings, DateRange, ProductAnalyticsItem, ProductionOrderItem } from '../types';
|
import type { CuttingSettings, DateRange, ProductAnalyticsItem, ProductionOrderItem } from '../types';
|
||||||
@@ -945,13 +946,24 @@ const Cutting = () => {
|
|||||||
</td>
|
</td>
|
||||||
<td className="px-4 py-2.5">{renderIssueBadge(row)}</td>
|
<td className="px-4 py-2.5">{renderIssueBadge(row)}</td>
|
||||||
<td className="px-4 py-2.5 text-right">
|
<td className="px-4 py-2.5 text-right">
|
||||||
<Link
|
<div className="flex justify-end gap-2">
|
||||||
to={`/products/${row.id}`}
|
<Link
|
||||||
className="inline-flex items-center whitespace-nowrap rounded-lg bg-brand-primary/10 px-3 py-1.5 text-xs font-bold text-brand-primary transition-opacity hover:opacity-80"
|
to={buildSkuEditPath({ sku: row.id, name: row.name, color: row.color, size: row.size })}
|
||||||
>
|
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"
|
||||||
<Package className="mr-1.5 h-3.5 w-3.5" />
|
title={`Editar SKU ${row.id}`}
|
||||||
Ver SKU
|
aria-label={`Editar SKU ${row.id}`}
|
||||||
</Link>
|
>
|
||||||
|
<Pencil className="h-3.5 w-3.5" />
|
||||||
|
</Link>
|
||||||
|
<Link
|
||||||
|
to={`/products/${row.id}`}
|
||||||
|
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"
|
||||||
|
title={`Ver SKU ${row.id}`}
|
||||||
|
aria-label={`Ver SKU ${row.id}`}
|
||||||
|
>
|
||||||
|
<Eye className="h-3.5 w-3.5" />
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
))}
|
))}
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
import { useEffect, useMemo, useState } from 'react';
|
import { useEffect, useMemo, useState } from 'react';
|
||||||
import { Link, useOutletContext, useParams } from 'react-router-dom';
|
import { Link, useOutletContext, useParams } from 'react-router-dom';
|
||||||
import { DollarSign, Package, Palette, Ruler, TrendingDown, TrendingUp, Warehouse } from 'lucide-react';
|
import { DollarSign, Eye, Package, Palette, Pencil, Ruler, TrendingDown, Warehouse } from 'lucide-react';
|
||||||
import BackButton from '../components/BackButton';
|
import BackButton from '../components/BackButton';
|
||||||
import DateRangePicker from '../components/DateRangePicker';
|
import DateRangePicker from '../components/DateRangePicker';
|
||||||
import PaginationControls from '../components/PaginationControls';
|
import PaginationControls from '../components/PaginationControls';
|
||||||
import ProductColorBadge, { ProductColorSwatch } from '../components/ProductColorBadge';
|
import ProductColorBadge, { ProductColorSwatch } from '../components/ProductColorBadge';
|
||||||
import RefreshStatus from '../components/RefreshStatus';
|
import RefreshStatus from '../components/RefreshStatus';
|
||||||
|
import { buildSkuEditPath } from '../catalogLinks';
|
||||||
import { buildOpenProductionByProductId } from '../analytics/cutting';
|
import { buildOpenProductionByProductId } from '../analytics/cutting';
|
||||||
import { fetchProductAnalytics, fetchProductionOrders } from '../dataService';
|
import { fetchProductAnalytics, fetchProductionOrders } from '../dataService';
|
||||||
import { decodeProductGroupKey, normalizeProductText, parseProductName } from '../productParsing';
|
import { decodeProductGroupKey, normalizeProductText, parseProductName } from '../productParsing';
|
||||||
@@ -541,13 +542,24 @@ const ProductGroupDetails = () => {
|
|||||||
<td className="px-6 py-2.5 whitespace-nowrap text-zinc-500 dark:text-dark-muted">{formatNumber(row.dailySales, 2)} un./dia</td>
|
<td className="px-6 py-2.5 whitespace-nowrap text-zinc-500 dark:text-dark-muted">{formatNumber(row.dailySales, 2)} un./dia</td>
|
||||||
<td className="px-6 py-2.5 whitespace-nowrap font-bold text-brand-primary">{formatCurrency(row.revenue)}</td>
|
<td className="px-6 py-2.5 whitespace-nowrap font-bold text-brand-primary">{formatCurrency(row.revenue)}</td>
|
||||||
<td className="px-4 py-2.5 text-right">
|
<td className="px-4 py-2.5 text-right">
|
||||||
<Link
|
<div className="flex justify-end gap-2">
|
||||||
to={`/products/${row.id}`}
|
<Link
|
||||||
className="inline-flex items-center whitespace-nowrap rounded-lg bg-brand-primary/10 px-3 py-1.5 text-xs font-bold text-brand-primary transition-opacity hover:opacity-80"
|
to={buildSkuEditPath({ sku: row.id, name: row.name, color: row.color, size: row.size })}
|
||||||
>
|
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"
|
||||||
<TrendingUp className="mr-1.5 h-3.5 w-3.5" />
|
title={`Editar SKU ${row.id}`}
|
||||||
Ver SKU
|
aria-label={`Editar SKU ${row.id}`}
|
||||||
</Link>
|
>
|
||||||
|
<Pencil className="h-3.5 w-3.5" />
|
||||||
|
</Link>
|
||||||
|
<Link
|
||||||
|
to={`/products/${row.id}`}
|
||||||
|
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"
|
||||||
|
title={`Ver SKU ${row.id}`}
|
||||||
|
aria-label={`Ver SKU ${row.id}`}
|
||||||
|
>
|
||||||
|
<Eye className="h-3.5 w-3.5" />
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
))}
|
))}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { useEffect, useMemo, useRef, useState } from 'react';
|
import { useEffect, useMemo, useRef, useState } from 'react';
|
||||||
import { Link, useOutletContext } from 'react-router-dom';
|
import { Link, useOutletContext } from 'react-router-dom';
|
||||||
import { Download, Filter, Package, PackageCheck, Search, TrendingDown, TrendingUp, X } from 'lucide-react';
|
import { Download, Eye, Filter, Package, PackageCheck, Pencil, Search, TrendingDown, X } from 'lucide-react';
|
||||||
|
import { buildSkuEditPath } from '../catalogLinks';
|
||||||
import DateRangePicker from '../components/DateRangePicker';
|
import DateRangePicker from '../components/DateRangePicker';
|
||||||
import PaginationControls from '../components/PaginationControls';
|
import PaginationControls from '../components/PaginationControls';
|
||||||
import RefreshStatus from '../components/RefreshStatus';
|
import RefreshStatus from '../components/RefreshStatus';
|
||||||
@@ -630,7 +631,7 @@ const Products = () => {
|
|||||||
<col className="w-[130px]" />
|
<col className="w-[130px]" />
|
||||||
<col className="w-[130px]" />
|
<col className="w-[130px]" />
|
||||||
<col className="w-[140px]" />
|
<col className="w-[140px]" />
|
||||||
<col className="w-[150px]" />
|
<col className="w-[120px]" />
|
||||||
</colgroup>
|
</colgroup>
|
||||||
<thead className="bg-zinc-50 dark:bg-dark-header border-b border-zinc-100 dark:border-dark-border text-zinc-500 dark:text-dark-muted">
|
<thead className="bg-zinc-50 dark:bg-dark-header border-b border-zinc-100 dark:border-dark-border text-zinc-500 dark:text-dark-muted">
|
||||||
<tr>
|
<tr>
|
||||||
@@ -684,13 +685,26 @@ const Products = () => {
|
|||||||
</td>
|
</td>
|
||||||
<td className="px-6 py-2.5 text-brand-primary font-bold whitespace-nowrap">{formatCurrency(product.revenue)}</td>
|
<td className="px-6 py-2.5 text-brand-primary font-bold whitespace-nowrap">{formatCurrency(product.revenue)}</td>
|
||||||
<td className="px-4 py-2.5 text-right">
|
<td className="px-4 py-2.5 text-right">
|
||||||
<Link
|
<div className="flex justify-end gap-2">
|
||||||
to={viewMode === 'group' ? `/products/groups/${product.groupKey}` : `/products/${product.id}`}
|
{viewMode === 'sku' && (
|
||||||
className="inline-flex items-center whitespace-nowrap text-xs font-bold text-brand-primary hover:opacity-80 transition-opacity bg-brand-primary/10 px-3 py-1.5 rounded-lg cursor-pointer"
|
<Link
|
||||||
>
|
to={buildSkuEditPath({ sku: product.id, name: product.name, color: product.color, size: product.size })}
|
||||||
<TrendingUp className="w-3.5 h-3.5 mr-1.5" />
|
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"
|
||||||
{viewMode === 'group' ? 'Ver Grupo' : 'Ver Gráfico'}
|
title={`Editar SKU ${product.id}`}
|
||||||
</Link>
|
aria-label={`Editar SKU ${product.id}`}
|
||||||
|
>
|
||||||
|
<Pencil className="h-3.5 w-3.5" />
|
||||||
|
</Link>
|
||||||
|
)}
|
||||||
|
<Link
|
||||||
|
to={viewMode === 'group' ? `/products/groups/${product.groupKey}` : `/products/${product.id}`}
|
||||||
|
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={viewMode === 'group' ? `Ver grupo ${product.name}` : `Ver SKU ${product.id}`}
|
||||||
|
aria-label={viewMode === 'group' ? `Ver grupo ${product.name}` : `Ver SKU ${product.id}`}
|
||||||
|
>
|
||||||
|
<Eye className="h-3.5 w-3.5" />
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { useEffect, useMemo, useState } from 'react';
|
import { useEffect, useMemo, useRef, useState } from 'react';
|
||||||
|
import { useSearchParams } from 'react-router-dom';
|
||||||
import { Loader2, Package, RefreshCw, Ruler, Save, Tags, Trash2 } from 'lucide-react';
|
import { Loader2, Package, RefreshCw, Ruler, Save, Tags, Trash2 } from 'lucide-react';
|
||||||
import {
|
import {
|
||||||
deleteCatalogCategory,
|
deleteCatalogCategory,
|
||||||
@@ -35,6 +36,21 @@ const defaultSizeAreas: Record<string, string> = {
|
|||||||
G5: '1.40'
|
G5: '1.40'
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const defaultProductForm = {
|
||||||
|
type: 'finished_product' as CatalogProductType,
|
||||||
|
sku: '',
|
||||||
|
name: '',
|
||||||
|
categoryId: '',
|
||||||
|
composition: '',
|
||||||
|
notes: '',
|
||||||
|
gramature: '',
|
||||||
|
materialYield: '',
|
||||||
|
widthCm: '',
|
||||||
|
color: '',
|
||||||
|
subcategory: 'malha',
|
||||||
|
sizes: ['P', 'M', 'G', 'GG'] as string[]
|
||||||
|
};
|
||||||
|
|
||||||
const rawMaterialSubcategories = [
|
const rawMaterialSubcategories = [
|
||||||
{ value: 'fio', label: 'Fio' },
|
{ value: 'fio', label: 'Fio' },
|
||||||
{ value: 'malha', label: 'Malha' },
|
{ value: 'malha', label: 'Malha' },
|
||||||
@@ -77,28 +93,17 @@ const getAverageYield = (reference: ConsumptionReference) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const Registrations = () => {
|
const Registrations = () => {
|
||||||
|
const [searchParams] = useSearchParams();
|
||||||
const [catalog, setCatalog] = useState<CatalogSummary>(emptyCatalog);
|
const [catalog, setCatalog] = useState<CatalogSummary>(emptyCatalog);
|
||||||
const [isLoading, setIsLoading] = useState(true);
|
const [isLoading, setIsLoading] = useState(true);
|
||||||
const [activeTab, setActiveTab] = useState<RegistrationTab>('products');
|
const [activeTab, setActiveTab] = useState<RegistrationTab>('products');
|
||||||
const [productFilter, setProductFilter] = useState<'all' | CatalogProductType>('all');
|
const [productFilter, setProductFilter] = useState<'all' | CatalogProductType>('all');
|
||||||
const [status, setStatus] = useState<SaveStatus>('idle');
|
const [status, setStatus] = useState<SaveStatus>('idle');
|
||||||
const [feedback, setFeedback] = useState('');
|
const [feedback, setFeedback] = useState('');
|
||||||
|
const appliedSkuPrefillRef = useRef('');
|
||||||
|
|
||||||
const [categoryForm, setCategoryForm] = useState({ name: '', description: '' });
|
const [categoryForm, setCategoryForm] = useState({ name: '', description: '' });
|
||||||
const [productForm, setProductForm] = useState({
|
const [productForm, setProductForm] = useState(defaultProductForm);
|
||||||
type: 'finished_product' as CatalogProductType,
|
|
||||||
sku: '',
|
|
||||||
name: '',
|
|
||||||
categoryId: '',
|
|
||||||
composition: '',
|
|
||||||
notes: '',
|
|
||||||
gramature: '',
|
|
||||||
materialYield: '',
|
|
||||||
widthCm: '',
|
|
||||||
color: '',
|
|
||||||
subcategory: 'malha',
|
|
||||||
sizes: ['P', 'M', 'G', 'GG'] as string[]
|
|
||||||
});
|
|
||||||
const [referenceForm, setReferenceForm] = useState({
|
const [referenceForm, setReferenceForm] = useState({
|
||||||
productId: '',
|
productId: '',
|
||||||
materialProductId: '',
|
materialProductId: '',
|
||||||
@@ -136,6 +141,58 @@ const Registrations = () => {
|
|||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const requestedTab = searchParams.get('tab');
|
||||||
|
const sku = (searchParams.get('sku') || '').trim();
|
||||||
|
if (!sku && !(requestedTab === 'products' || requestedTab === 'categories' || requestedTab === 'references')) return;
|
||||||
|
|
||||||
|
const prefillKey = `${sku}|${searchParams.get('name') || ''}|${catalog.products.length}`;
|
||||||
|
if (appliedSkuPrefillRef.current === prefillKey) return;
|
||||||
|
appliedSkuPrefillRef.current = prefillKey;
|
||||||
|
|
||||||
|
queueMicrotask(() => {
|
||||||
|
if (requestedTab === 'products' || requestedTab === 'categories' || requestedTab === 'references') {
|
||||||
|
setActiveTab(requestedTab);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!sku) return;
|
||||||
|
|
||||||
|
const existingProduct = catalog.products.find(product => product.sku.toLowerCase() === sku.toLowerCase());
|
||||||
|
setActiveTab('products');
|
||||||
|
setProductFilter('all');
|
||||||
|
setStatus('idle');
|
||||||
|
|
||||||
|
if (existingProduct) {
|
||||||
|
setProductForm({
|
||||||
|
type: existingProduct.type,
|
||||||
|
sku: existingProduct.sku,
|
||||||
|
name: existingProduct.name,
|
||||||
|
categoryId: existingProduct.categoryId ? String(existingProduct.categoryId) : '',
|
||||||
|
composition: existingProduct.composition || '',
|
||||||
|
notes: existingProduct.notes || '',
|
||||||
|
gramature: existingProduct.gramature ? String(existingProduct.gramature) : '',
|
||||||
|
materialYield: existingProduct.materialYield ? String(existingProduct.materialYield) : '',
|
||||||
|
widthCm: existingProduct.widthCm ? String(existingProduct.widthCm) : '',
|
||||||
|
color: existingProduct.color || searchParams.get('color') || '',
|
||||||
|
subcategory: existingProduct.subcategory || 'malha',
|
||||||
|
sizes: existingProduct.sizes?.length ? existingProduct.sizes : defaultProductForm.sizes
|
||||||
|
});
|
||||||
|
setFeedback(`Editando SKU ${existingProduct.sku}.`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const requestedSize = (searchParams.get('size') || '').trim().toUpperCase();
|
||||||
|
setProductForm({
|
||||||
|
...defaultProductForm,
|
||||||
|
sku,
|
||||||
|
name: searchParams.get('name') || '',
|
||||||
|
color: searchParams.get('color') || '',
|
||||||
|
sizes: requestedSize ? [requestedSize] : defaultProductForm.sizes
|
||||||
|
});
|
||||||
|
setFeedback(`Novo cadastro para SKU ${sku}.`);
|
||||||
|
});
|
||||||
|
}, [catalog.products, searchParams]);
|
||||||
|
|
||||||
const finishedProducts = useMemo(
|
const finishedProducts = useMemo(
|
||||||
() => catalog.products.filter(product => product.type === 'finished_product'),
|
() => catalog.products.filter(product => product.type === 'finished_product'),
|
||||||
[catalog.products]
|
[catalog.products]
|
||||||
@@ -464,21 +521,32 @@ const Registrations = () => {
|
|||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<div>
|
<>
|
||||||
<p className="mb-2 text-xs font-bold text-dark-muted">Tamanhos disponiveis</p>
|
<label className={`block ${labelClassName}`}>
|
||||||
<div className="flex flex-wrap gap-2">
|
Cor
|
||||||
{sizeOptions.map(size => (
|
<input
|
||||||
<button
|
value={productForm.color}
|
||||||
key={size}
|
onChange={(event) => setProductForm(current => ({ ...current, color: event.target.value }))}
|
||||||
type="button"
|
placeholder="ex: Preto"
|
||||||
onClick={() => toggleProductSize(size)}
|
className={inputClassName}
|
||||||
className={`rounded-full border px-3 py-1.5 text-xs font-bold transition-colors cursor-pointer ${productForm.sizes.includes(size) ? 'border-brand-primary bg-brand-primary/15 text-brand-primary' : 'border-dark-border bg-dark-input text-dark-muted hover:text-dark-text'}`}
|
/>
|
||||||
>
|
</label>
|
||||||
{size}
|
<div>
|
||||||
</button>
|
<p className="mb-2 text-xs font-bold text-dark-muted">Tamanhos disponiveis</p>
|
||||||
))}
|
<div className="flex flex-wrap gap-2">
|
||||||
|
{sizeOptions.map(size => (
|
||||||
|
<button
|
||||||
|
key={size}
|
||||||
|
type="button"
|
||||||
|
onClick={() => toggleProductSize(size)}
|
||||||
|
className={`rounded-full border px-3 py-1.5 text-xs font-bold transition-colors cursor-pointer ${productForm.sizes.includes(size) ? 'border-brand-primary bg-brand-primary/15 text-brand-primary' : 'border-dark-border bg-dark-input text-dark-muted hover:text-dark-text'}`}
|
||||||
|
>
|
||||||
|
{size}
|
||||||
|
</button>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<label className={`block ${labelClassName}`}>
|
<label className={`block ${labelClassName}`}>
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
import { useEffect, useMemo, useState } from 'react';
|
import { useEffect, useMemo, useState } from 'react';
|
||||||
import { Link, useOutletContext, useSearchParams } from 'react-router-dom';
|
import { Link, useOutletContext, useSearchParams } from 'react-router-dom';
|
||||||
import { AlertTriangle, ArrowLeft, CheckCircle2, Download, Package, Search, TrendingUp } from 'lucide-react';
|
import { AlertTriangle, ArrowLeft, CheckCircle2, Download, Eye, Package, Pencil, Search, TrendingUp } from 'lucide-react';
|
||||||
import DateRangePicker from '../components/DateRangePicker';
|
import DateRangePicker from '../components/DateRangePicker';
|
||||||
import PaginationControls from '../components/PaginationControls';
|
import PaginationControls from '../components/PaginationControls';
|
||||||
import RefreshStatus from '../components/RefreshStatus';
|
import RefreshStatus from '../components/RefreshStatus';
|
||||||
|
import { buildSkuEditPath } from '../catalogLinks';
|
||||||
import { buildOpenProductionByProductId } from '../analytics/cutting';
|
import { buildOpenProductionByProductId } from '../analytics/cutting';
|
||||||
import type { DateRange, ProductAnalyticsItem, ProductionOrderItem } from '../types';
|
import type { DateRange, ProductAnalyticsItem, ProductionOrderItem } from '../types';
|
||||||
import { exportToCSV, fetchProductAnalytics, fetchProductionOrders } from '../dataService';
|
import { exportToCSV, fetchProductAnalytics, fetchProductionOrders } from '../dataService';
|
||||||
@@ -572,12 +573,26 @@ const Replenishment = () => {
|
|||||||
</td>
|
</td>
|
||||||
<td className="px-6 py-2.5 font-bold text-zinc-900 dark:text-dark-text whitespace-nowrap">{formatDays(row.daysOfCover)}</td>
|
<td className="px-6 py-2.5 font-bold text-zinc-900 dark:text-dark-text whitespace-nowrap">{formatDays(row.daysOfCover)}</td>
|
||||||
<td className="px-4 py-2.5 text-right">
|
<td className="px-4 py-2.5 text-right">
|
||||||
<Link
|
<div className="flex justify-end gap-2">
|
||||||
to={viewMode === 'group' ? `/products/groups/${encodeProductGroupKey(row.baseName)}` : `/products/${row.id}`}
|
{viewMode === 'sku' && (
|
||||||
className="inline-flex items-center whitespace-nowrap text-xs font-bold text-brand-primary hover:opacity-80 transition-opacity bg-brand-primary/10 px-3 py-1.5 rounded-lg cursor-pointer"
|
<Link
|
||||||
>
|
to={buildSkuEditPath({ sku: row.id, name: row.name, color: row.color, size: row.size })}
|
||||||
{viewMode === 'group' ? 'Ver grupo' : 'Ver produto'}
|
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"
|
||||||
</Link>
|
title={`Editar SKU ${row.id}`}
|
||||||
|
aria-label={`Editar SKU ${row.id}`}
|
||||||
|
>
|
||||||
|
<Pencil className="h-3.5 w-3.5" />
|
||||||
|
</Link>
|
||||||
|
)}
|
||||||
|
<Link
|
||||||
|
to={viewMode === 'group' ? `/products/groups/${encodeProductGroupKey(row.baseName)}` : `/products/${row.id}`}
|
||||||
|
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={viewMode === 'group' ? `Ver grupo ${row.baseName}` : `Ver SKU ${row.id}`}
|
||||||
|
aria-label={viewMode === 'group' ? `Ver grupo ${row.baseName}` : `Ver SKU ${row.id}`}
|
||||||
|
>
|
||||||
|
<Eye className="h-3.5 w-3.5" />
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user