diff --git a/src/pages/ProductGroupDetails.tsx b/src/pages/ProductGroupDetails.tsx index 55861b3..4a74d73 100644 --- a/src/pages/ProductGroupDetails.tsx +++ b/src/pages/ProductGroupDetails.tsx @@ -3,9 +3,10 @@ import { Link, useOutletContext, useParams } from 'react-router-dom'; import { DollarSign, Package, Palette, Ruler, TrendingDown, TrendingUp, Warehouse } from 'lucide-react'; import BackButton from '../components/BackButton'; import DateRangePicker from '../components/DateRangePicker'; +import PaginationControls from '../components/PaginationControls'; import RefreshStatus from '../components/RefreshStatus'; import { fetchProductAnalytics } from '../dataService'; -import { decodeProductGroupKey, normalizeProductText, parseProductName, sortProductSizes } from '../productParsing'; +import { decodeProductGroupKey, normalizeProductText, parseProductName } from '../productParsing'; import type { DateRange, ProductAnalyticsItem } from '../types'; type VariantRow = ProductAnalyticsItem & { @@ -23,6 +24,8 @@ type BreakdownRow = { skuCount: number; }; +const BREAKDOWN_LIMIT = 12; + const COLOR_SWATCHES: Array<{ pattern: string; color: string }> = [ { pattern: 'preto', color: '#171717' }, { pattern: 'branco', color: '#f8fafc' }, @@ -69,6 +72,21 @@ const getSwatchColor = (label: string) => { return COLOR_SWATCHES.find(item => normalizedLabel.includes(item.pattern.normalize('NFD').replace(/\p{Diacritic}/gu, '')))?.color || '#64748b'; }; +const getBarColor = (label: string) => { + const color = getSwatchColor(label); + return `color-mix(in srgb, ${color} 74%, var(--color-dark-text) 26%)`; +}; + +const ColorSwatch = ({ label, className = 'h-2.5 w-2.5' }: { label: string; className?: string }) => ( + +); + const buildBreakdown = (rows: VariantRow[], field: 'color' | 'size') => { const totals = new Map(); @@ -84,16 +102,7 @@ const buildBreakdown = (rows: VariantRow[], field: 'color' | 'size') => { }); }); - const values = [...totals.values()]; - if (field === 'size') { - return values.sort((a, b) => { - const [sortedA, sortedB] = sortProductSizes([a.label, b.label]); - if (sortedA === a.label && sortedB === b.label) return 0; - return sortedA === a.label ? -1 : 1; - }); - } - - return values.sort((a, b) => b.quantitySold - a.quantitySold); + return [...totals.values()].sort((a, b) => b.quantitySold - a.quantitySold); }; const BreakdownPanel = ({ @@ -108,6 +117,8 @@ const BreakdownPanel = ({ type: 'color' | 'size'; }) => { const maxSold = Math.max(...rows.map(row => row.quantitySold), 0); + const visibleRows = rows.slice(0, BREAKDOWN_LIMIT); + const hiddenCount = Math.max(0, rows.length - visibleRows.length); return (
@@ -129,25 +140,22 @@ const BreakdownPanel = ({
) : (
- {rows.map(row => { + {visibleRows.map(row => { const width = maxSold ? Math.max(4, (row.quantitySold / maxSold) * 100) : 0; - const swatchColor = type === 'color' ? getSwatchColor(row.label) : '#25c2ff'; + const barColor = type === 'color' ? getBarColor(row.label) : '#25c2ff'; return ( -
+
- + {type === 'color' ? : } {type === 'size' && row.label !== 'Sem tamanho' ? `Tam. ${row.label}` : row.label}
-
+
@@ -157,6 +165,11 @@ const BreakdownPanel = ({
); })} + {hiddenCount > 0 && ( +
+ +{formatNumber(hiddenCount)} itens fora do top {BREAKDOWN_LIMIT} +
+ )}
)}
@@ -195,6 +208,8 @@ const ProductGroupDetails = () => { }>(); const [products, setProducts] = useState([]); const [isLoading, setIsLoading] = useState(true); + const [currentPage, setCurrentPage] = useState(1); + const [itemsPerPage, setItemsPerPage] = useState(20); const groupName = useMemo(() => { if (!groupKey) return ''; @@ -271,6 +286,10 @@ const ProductGroupDetails = () => { const colorBreakdown = useMemo(() => buildBreakdown(groupRows, 'color'), [groupRows]); const sizeBreakdown = useMemo(() => buildBreakdown(groupRows, 'size'), [groupRows]); const isRefreshing = isLoading && products.length > 0; + const totalPages = Math.ceil(groupRows.length / itemsPerPage); + const safeCurrentPage = Math.min(currentPage, totalPages || 1); + const startIndex = (safeCurrentPage - 1) * itemsPerPage; + const paginatedRows = groupRows.slice(startIndex, startIndex + itemsPerPage); if (isLoading && products.length === 0) { return ; @@ -306,7 +325,13 @@ const ProductGroupDetails = () => {
- + { + setDateRange(range); + setCurrentPage(1); + }} + />
@@ -370,9 +395,14 @@ const ProductGroupDetails = () => {
-
-

Variações do grupo

-

SKUs, cores e tamanhos que formam este grupo.

+
+
+

Variações do grupo

+

SKUs, cores e tamanhos que formam este grupo.

+
+ + {formatNumber(groupRows.length)} SKUs +
@@ -401,7 +431,7 @@ const ProductGroupDetails = () => { - {groupRows.map(row => ( + {paginatedRows.map(row => ( @@ -445,6 +472,22 @@ const ProductGroupDetails = () => {
#{row.id} @@ -410,10 +440,7 @@ const ProductGroupDetails = () => { - + {row.color || '-'}
+ { + setItemsPerPage(pageSize); + setCurrentPage(1); + }} + />