diff --git a/src/catalogLinks.ts b/src/catalogLinks.ts
new file mode 100644
index 0000000..c5150a5
--- /dev/null
+++ b/src/catalogLinks.ts
@@ -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()}`;
+};
diff --git a/src/pages/Cutting.tsx b/src/pages/Cutting.tsx
index 1f952c1..4993e58 100644
--- a/src/pages/Cutting.tsx
+++ b/src/pages/Cutting.tsx
@@ -1,10 +1,11 @@
import { useEffect, useMemo, useState } from 'react';
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 PaginationControls from '../components/PaginationControls';
import ProductColorBadge from '../components/ProductColorBadge';
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 { exportToCSV, fetchCuttingSettings, fetchProductAnalytics, fetchProductionOrders, saveCuttingSettings } from '../dataService';
import type { CuttingSettings, DateRange, ProductAnalyticsItem, ProductionOrderItem } from '../types';
@@ -945,13 +946,24 @@ const Cutting = () => {
{renderIssueBadge(row)} |
-
-
- Ver SKU
-
+
|
))}
diff --git a/src/pages/ProductGroupDetails.tsx b/src/pages/ProductGroupDetails.tsx
index 9fd6aae..f03843a 100644
--- a/src/pages/ProductGroupDetails.tsx
+++ b/src/pages/ProductGroupDetails.tsx
@@ -1,11 +1,12 @@
import { useEffect, useMemo, useState } from 'react';
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 DateRangePicker from '../components/DateRangePicker';
import PaginationControls from '../components/PaginationControls';
import ProductColorBadge, { ProductColorSwatch } from '../components/ProductColorBadge';
import RefreshStatus from '../components/RefreshStatus';
+import { buildSkuEditPath } from '../catalogLinks';
import { buildOpenProductionByProductId } from '../analytics/cutting';
import { fetchProductAnalytics, fetchProductionOrders } from '../dataService';
import { decodeProductGroupKey, normalizeProductText, parseProductName } from '../productParsing';
@@ -541,13 +542,24 @@ const ProductGroupDetails = () => {
{formatNumber(row.dailySales, 2)} un./dia |
{formatCurrency(row.revenue)} |
-
-
- Ver SKU
-
+
|
))}
diff --git a/src/pages/Products.tsx b/src/pages/Products.tsx
index f9d92ff..07e9772 100644
--- a/src/pages/Products.tsx
+++ b/src/pages/Products.tsx
@@ -1,6 +1,7 @@
import { useEffect, useMemo, useRef, useState } from 'react';
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 PaginationControls from '../components/PaginationControls';
import RefreshStatus from '../components/RefreshStatus';
@@ -630,7 +631,7 @@ const Products = () => {
-
+
@@ -684,13 +685,26 @@ const Products = () => {
| {formatCurrency(product.revenue)} |
-
-
- {viewMode === 'group' ? 'Ver Grupo' : 'Ver Gráfico'}
-
+
+ {viewMode === 'sku' && (
+
+
+
+ )}
+
+
+
+
|
);
diff --git a/src/pages/Registrations.tsx b/src/pages/Registrations.tsx
index 87b88ab..9c4b361 100644
--- a/src/pages/Registrations.tsx
+++ b/src/pages/Registrations.tsx
@@ -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 {
deleteCatalogCategory,
@@ -35,6 +36,21 @@ const defaultSizeAreas: Record = {
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 = [
{ value: 'fio', label: 'Fio' },
{ value: 'malha', label: 'Malha' },
@@ -77,28 +93,17 @@ const getAverageYield = (reference: ConsumptionReference) => {
};
const Registrations = () => {
+ const [searchParams] = useSearchParams();
const [catalog, setCatalog] = useState(emptyCatalog);
const [isLoading, setIsLoading] = useState(true);
const [activeTab, setActiveTab] = useState('products');
const [productFilter, setProductFilter] = useState<'all' | CatalogProductType>('all');
const [status, setStatus] = useState('idle');
const [feedback, setFeedback] = useState('');
+ const appliedSkuPrefillRef = useRef('');
const [categoryForm, setCategoryForm] = useState({ name: '', description: '' });
- const [productForm, setProductForm] = useState({
- type: 'finished_product' as CatalogProductType,
- sku: '',
- name: '',
- categoryId: '',
- composition: '',
- notes: '',
- gramature: '',
- materialYield: '',
- widthCm: '',
- color: '',
- subcategory: 'malha',
- sizes: ['P', 'M', 'G', 'GG'] as string[]
- });
+ const [productForm, setProductForm] = useState(defaultProductForm);
const [referenceForm, setReferenceForm] = useState({
productId: '',
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(
() => catalog.products.filter(product => product.type === 'finished_product'),
[catalog.products]
@@ -464,21 +521,32 @@ const Registrations = () => {
>
) : (
-
-
Tamanhos disponiveis
-
- {sizeOptions.map(size => (
-
- ))}
+ <>
+
+
+
Tamanhos disponiveis
+
+ {sizeOptions.map(size => (
+
+ ))}
+
-
+ >
)}