From 25104da4248e62efa970f404cc3f271ef3313600 Mon Sep 17 00:00:00 2001 From: "gpt-engineer-app[bot]" <159125892+gpt-engineer-app[bot]@users.noreply.github.com> Date: Tue, 26 May 2026 16:01:02 +0000 Subject: [PATCH 01/20] Changes Co-authored-by: adm01-debug <231131902+adm01-debug@users.noreply.github.com> --- src/components/products/ColumnSelector.tsx | 49 ++++++++++++---------- 1 file changed, 28 insertions(+), 21 deletions(-) diff --git a/src/components/products/ColumnSelector.tsx b/src/components/products/ColumnSelector.tsx index d7e9f6a2e..3ea47a35c 100644 --- a/src/components/products/ColumnSelector.tsx +++ b/src/components/products/ColumnSelector.tsx @@ -2,10 +2,18 @@ import { useEffect, useState } from "react"; import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip"; import { cn } from "@/lib/utils"; -const STORAGE_KEY = "product-grid-columns"; +export const STORAGE_KEY = "product-grid-columns"; export type ColumnCount = 3 | 4 | 5 | 6 | 8; +export const COLUMN_CLASSES: Record = { + 3: "grid-cols-3", + 4: "grid-cols-2 sm:grid-cols-3 md:grid-cols-4", + 5: "grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5", + 6: "grid-cols-3 sm:grid-cols-4 md:grid-cols-5 lg:grid-cols-6", + 8: "grid-cols-4 sm:grid-cols-5 md:grid-cols-6 lg:grid-cols-8", +}; + function GridIcon({ cols, rows = 2 }: { cols: number; rows?: number }) { const size = 18; const gap = 2; @@ -43,12 +51,6 @@ interface ColumnOption { minWidth: number; } -// Breakpoints alinhados com responsividade do grid de produtos: -// - 3 colunas: sempre disponível (mobile-first) -// - 4 colunas: ≥768px (md tailwind) -// - 5 colunas: ≥1024px (lg tailwind) -// - 6 colunas: ≥1280px (xl tailwind) -// - 8 colunas: ≥1536px (2xl tailwind) const columnOptions: ColumnOption[] = [ { value: 3, label: "3 colunas", cols: 3, rows: 2, minWidth: 0 }, { value: 4, label: "4 colunas", cols: 4, rows: 2, minWidth: 768 }, @@ -61,7 +63,7 @@ function getAvailableOptions(screenWidth: number): ColumnOption[] { return columnOptions.filter((opt) => screenWidth >= opt.minWidth); } -function getDefaultColumns(): ColumnCount { +export function getDefaultColumns(): ColumnCount { try { const saved = localStorage.getItem(STORAGE_KEY); if (saved) { @@ -83,7 +85,6 @@ interface ColumnSelectorProps { } export function ColumnSelector({ value, onChange, className }: ColumnSelectorProps) { - // Track window width to filter options responsively. const [screenWidth, setScreenWidth] = useState(() => typeof window !== "undefined" ? window.innerWidth : 1600, ); @@ -97,9 +98,6 @@ export function ColumnSelector({ value, onChange, className }: ColumnSelectorPro const available = getAvailableOptions(screenWidth); - // Clamping: se o valor controlado ultrapassa o máximo disponível para a - // largura atual, dispara onChange para o maior valor permitido. Mantém - // a UI consistente quando a tela encolhe ou o valor vem maior do esperado. useEffect(() => { if (available.length === 0) return; const maxAvailable = available[available.length - 1].value; @@ -108,14 +106,17 @@ export function ColumnSelector({ value, onChange, className }: ColumnSelectorPro } }, [value, available, onChange]); - // Quando só sobra 1 opção (ou nenhuma), o seletor não tem utilidade. if (available.length <= 1) return null; return ( -
+
{available.map((opt) => { const isActive = value === opt.value; return ( @@ -123,14 +124,22 @@ export function ColumnSelector({ value, onChange, className }: ColumnSelectorPro
); } - -export { getDefaultColumns, STORAGE_KEY }; From db8e8657820aad3a6964d19417bc8347f237409f Mon Sep 17 00:00:00 2001 From: "gpt-engineer-app[bot]" <159125892+gpt-engineer-app[bot]@users.noreply.github.com> Date: Tue, 26 May 2026 16:01:07 +0000 Subject: [PATCH 02/20] Changes Co-authored-by: adm01-debug <231131902+adm01-debug@users.noreply.github.com> --- src/components/products/ProductGrid.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/products/ProductGrid.tsx b/src/components/products/ProductGrid.tsx index b6d6638df..cf5307cff 100644 --- a/src/components/products/ProductGrid.tsx +++ b/src/components/products/ProductGrid.tsx @@ -5,6 +5,7 @@ import { useEffect, useState, useRef } from "react"; import { useReducedMotion } from "@/hooks/ui/useReducedMotion"; import { SelectionCheckbox } from "@/components/common/SelectionCheckbox"; import { cn } from "@/lib/utils"; +import { COLUMN_CLASSES, type ColumnCount } from "./ColumnSelector"; import { ProductCardSkeleton } from "./ProductCardSkeleton"; export interface ProductGridProps { From bf22a7be235a5cbf0ea34a1cde1d7f2c0c24dd12 Mon Sep 17 00:00:00 2001 From: "gpt-engineer-app[bot]" <159125892+gpt-engineer-app[bot]@users.noreply.github.com> Date: Tue, 26 May 2026 16:01:12 +0000 Subject: [PATCH 03/20] Changes Co-authored-by: adm01-debug <231131902+adm01-debug@users.noreply.github.com> --- src/components/products/ProductGrid.tsx | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/components/products/ProductGrid.tsx b/src/components/products/ProductGrid.tsx index cf5307cff..9b33b4416 100644 --- a/src/components/products/ProductGrid.tsx +++ b/src/components/products/ProductGrid.tsx @@ -139,13 +139,8 @@ function ProductCardWrapper({ ); } -const columnClasses: Record = { - 3: "grid-cols-2 sm:grid-cols-3", - 4: "grid-cols-2 sm:grid-cols-3 lg:grid-cols-4", - 5: "grid-cols-2 sm:grid-cols-3 lg:grid-cols-4 xl:grid-cols-5", - 6: "grid-cols-3 sm:grid-cols-4 lg:grid-cols-5 xl:grid-cols-6", - 8: "grid-cols-3 sm:grid-cols-4 lg:grid-cols-6 xl:grid-cols-8", -}; +// Usando as classes centralizadas para garantir consistência em todos os grids do sistema. +const columnClasses = COLUMN_CLASSES; export function ProductGrid({ products, From 5b163d60044b664b20f9dac74594416b884929e9 Mon Sep 17 00:00:00 2001 From: "gpt-engineer-app[bot]" <159125892+gpt-engineer-app[bot]@users.noreply.github.com> Date: Tue, 26 May 2026 16:01:15 +0000 Subject: [PATCH 04/20] Changes Co-authored-by: adm01-debug <231131902+adm01-debug@users.noreply.github.com> --- src/pages/products/FavoritesPage.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/products/FavoritesPage.tsx b/src/pages/products/FavoritesPage.tsx index 624a0c91b..3ae9b8a01 100644 --- a/src/pages/products/FavoritesPage.tsx +++ b/src/pages/products/FavoritesPage.tsx @@ -51,7 +51,7 @@ import type { FavoritesSort } from '@/components/favorites/FavoritesSortBar'; type ViewMode = 'grid' | 'list' | 'table'; const VIEW_MODE_KEY = 'favorites-view-mode'; -const GRID_COLS_KEY = 'favorites-grid-cols'; +import { STORAGE_KEY as GRID_COLS_KEY, getDefaultColumns, type ColumnCount } from '@/components/products/ColumnSelector'; const SELECTED_LIST_KEY = 'favorites-selected-list-id'; const SORT_KEY = 'favorites-sort'; const PRICE_DROP_FILTER_KEY = 'favorites-only-drops'; From 41d6daaf368ce4b4780e0b6a2f622a0294f229c5 Mon Sep 17 00:00:00 2001 From: "gpt-engineer-app[bot]" <159125892+gpt-engineer-app[bot]@users.noreply.github.com> Date: Tue, 26 May 2026 16:01:22 +0000 Subject: [PATCH 05/20] Changes Co-authored-by: adm01-debug <231131902+adm01-debug@users.noreply.github.com> --- src/pages/products/FavoritesPage.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/products/FavoritesPage.tsx b/src/pages/products/FavoritesPage.tsx index 3ae9b8a01..147bcbe0d 100644 --- a/src/pages/products/FavoritesPage.tsx +++ b/src/pages/products/FavoritesPage.tsx @@ -14,7 +14,7 @@ import { ProductCard } from '@/components/products/ProductCard'; import { ProductListItem } from '@/components/products/ProductListItem'; import { ProductTableView } from '@/components/products/ProductTableView'; import { LayoutPopover } from '@/components/products/LayoutPopover'; -import { getDefaultColumns, type ColumnCount } from '@/components/products/ColumnSelector'; +import { STORAGE_KEY as GRID_COLS_KEY, getDefaultColumns, type ColumnCount } from '@/components/products/ColumnSelector'; import { getGridColsClass, getGridGapClass } from '@/components/replenishments/grid-layout'; import { Button } from '@/components/ui/button'; import { Badge } from '@/components/ui/badge'; From ef2ce89656739b1fee8490f6a18f7afbf88a10b0 Mon Sep 17 00:00:00 2001 From: "gpt-engineer-app[bot]" <159125892+gpt-engineer-app[bot]@users.noreply.github.com> Date: Tue, 26 May 2026 16:01:26 +0000 Subject: [PATCH 06/20] Changes Co-authored-by: adm01-debug <231131902+adm01-debug@users.noreply.github.com> --- src/pages/products/FavoritesPage.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/pages/products/FavoritesPage.tsx b/src/pages/products/FavoritesPage.tsx index 147bcbe0d..91a4f7d88 100644 --- a/src/pages/products/FavoritesPage.tsx +++ b/src/pages/products/FavoritesPage.tsx @@ -51,7 +51,6 @@ import type { FavoritesSort } from '@/components/favorites/FavoritesSortBar'; type ViewMode = 'grid' | 'list' | 'table'; const VIEW_MODE_KEY = 'favorites-view-mode'; -import { STORAGE_KEY as GRID_COLS_KEY, getDefaultColumns, type ColumnCount } from '@/components/products/ColumnSelector'; const SELECTED_LIST_KEY = 'favorites-selected-list-id'; const SORT_KEY = 'favorites-sort'; const PRICE_DROP_FILTER_KEY = 'favorites-only-drops'; From 8c49ea2092462b9c10c92dc19ed85e06f39b9861 Mon Sep 17 00:00:00 2001 From: "gpt-engineer-app[bot]" <159125892+gpt-engineer-app[bot]@users.noreply.github.com> Date: Tue, 26 May 2026 16:01:52 +0000 Subject: [PATCH 07/20] Changes Co-authored-by: adm01-debug <231131902+adm01-debug@users.noreply.github.com> --- src/components/novelties/NoveltyProductGrid.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/novelties/NoveltyProductGrid.tsx b/src/components/novelties/NoveltyProductGrid.tsx index 8ca40d1d5..106e3d693 100644 --- a/src/components/novelties/NoveltyProductGrid.tsx +++ b/src/components/novelties/NoveltyProductGrid.tsx @@ -24,7 +24,7 @@ import { import { useNoveltiesSelectionMode, useNoveltiesWithDetails } from '@/hooks/products'; import { ProductCardSkeleton } from '@/components/products/ProductCardSkeleton'; import { LayoutPopover } from '@/components/products/LayoutPopover'; -import { getDefaultColumns, type ColumnCount } from '@/components/products/ColumnSelector'; +import { getDefaultColumns, type ColumnCount, COLUMN_CLASSES } from '@/components/products/ColumnSelector'; import { BulkActionBar } from '@/components/products/BulkActionBar'; import { BulkVariantWizard } from '@/components/catalog/BulkVariantWizard'; import { BulkAddToCartModal } from '@/components/catalog/BulkAddToCartModal'; From f45f14f00326f66ae630366d07debc524f439dd4 Mon Sep 17 00:00:00 2001 From: "gpt-engineer-app[bot]" <159125892+gpt-engineer-app[bot]@users.noreply.github.com> Date: Tue, 26 May 2026 16:01:58 +0000 Subject: [PATCH 08/20] Changes Co-authored-by: adm01-debug <231131902+adm01-debug@users.noreply.github.com> --- src/components/novelties/NoveltyProductGrid.tsx | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/src/components/novelties/NoveltyProductGrid.tsx b/src/components/novelties/NoveltyProductGrid.tsx index 106e3d693..84d93207d 100644 --- a/src/components/novelties/NoveltyProductGrid.tsx +++ b/src/components/novelties/NoveltyProductGrid.tsx @@ -48,20 +48,7 @@ type SortMode = | 'best-seller-promo'; function getGridColsClass(cols: ColumnCount): string { - switch (cols) { - case 3: - return 'grid-cols-2 sm:grid-cols-3'; - case 4: - return 'grid-cols-2 sm:grid-cols-3 lg:grid-cols-4'; - case 5: - return 'grid-cols-2 sm:grid-cols-3 lg:grid-cols-4 xl:grid-cols-5'; - case 6: - return 'grid-cols-3 sm:grid-cols-4 lg:grid-cols-5 xl:grid-cols-6'; - case 8: - return 'grid-cols-3 sm:grid-cols-4 lg:grid-cols-6 xl:grid-cols-8'; - default: - return 'grid-cols-2 sm:grid-cols-3 lg:grid-cols-4 xl:grid-cols-5'; - } + return COLUMN_CLASSES[cols] || COLUMN_CLASSES[5]; } function getGridGapClass(cols: ColumnCount): string { From 7a57136b3ec4e4c0cce2b568541e92b78edddca8 Mon Sep 17 00:00:00 2001 From: "gpt-engineer-app[bot]" <159125892+gpt-engineer-app[bot]@users.noreply.github.com> Date: Tue, 26 May 2026 16:02:06 +0000 Subject: [PATCH 09/20] Changes Co-authored-by: adm01-debug <231131902+adm01-debug@users.noreply.github.com> --- src/components/replenishments/grid-layout.ts | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/src/components/replenishments/grid-layout.ts b/src/components/replenishments/grid-layout.ts index 234edef6c..8d41c9da8 100644 --- a/src/components/replenishments/grid-layout.ts +++ b/src/components/replenishments/grid-layout.ts @@ -1,19 +1,11 @@ -import type { ColumnCount } from "@/components/products/ColumnSelector"; +import { COLUMN_CLASSES, type ColumnCount } from "@/components/products/ColumnSelector"; export function colsToNum(cols: ColumnCount): number { return typeof cols === "number" ? cols : 5; } export function getGridColsClass(cols: ColumnCount): string { - const map: Record = { - 3: "grid-cols-2 sm:grid-cols-3", - 4: "grid-cols-2 sm:grid-cols-3 lg:grid-cols-4", - 5: "grid-cols-2 sm:grid-cols-3 lg:grid-cols-4 xl:grid-cols-5", - 6: "grid-cols-3 sm:grid-cols-4 lg:grid-cols-5 xl:grid-cols-6", - 8: "grid-cols-3 sm:grid-cols-4 lg:grid-cols-6 xl:grid-cols-8", - }; - - return map[cols] ?? map[5]; + return COLUMN_CLASSES[cols] ?? COLUMN_CLASSES[5]; } export function getGridGapClass(cols: ColumnCount): string { From f529e6d8ed87852cc705dae384fb2f96de1200c0 Mon Sep 17 00:00:00 2001 From: "gpt-engineer-app[bot]" <159125892+gpt-engineer-app[bot]@users.noreply.github.com> Date: Tue, 26 May 2026 16:02:15 +0000 Subject: [PATCH 10/20] Changes Co-authored-by: adm01-debug <231131902+adm01-debug@users.noreply.github.com> --- .../products/ColumnSelector.test.tsx | 123 ++++++++++++++++++ 1 file changed, 123 insertions(+) create mode 100644 src/components/products/ColumnSelector.test.tsx diff --git a/src/components/products/ColumnSelector.test.tsx b/src/components/products/ColumnSelector.test.tsx new file mode 100644 index 000000000..4f769e324 --- /dev/null +++ b/src/components/products/ColumnSelector.test.tsx @@ -0,0 +1,123 @@ +import { render, screen, fireEvent, waitFor, act } from "@testing-library/react"; +import { describe, it, expect, vi, beforeEach } from "vitest"; +import { ColumnSelector, STORAGE_KEY } from "./ColumnSelector"; +import { TooltipProvider } from "@/components/ui/tooltip"; + +// Mock screen width +const setScreenWidth = (width: number) => { + act(() => { + Object.defineProperty(window, 'innerWidth', { + writable: true, + configurable: true, + value: width, + }); + window.dispatchEvent(new Event('resize')); + }); +}; + +describe("ColumnSelector", () => { + beforeEach(() => { + localStorage.clear(); + vi.clearAllMocks(); + setScreenWidth(1600); // Desktop size with all options + }); + + const renderSelector = (value: any = 5, onChange = vi.fn()) => { + return render( + + + + ); + }; + + it("renders all column options on desktop with correct accessibility roles", () => { + renderSelector(); + expect(screen.getByRole("radiogroup", { name: /Número de colunas/i })).toBeInTheDocument(); + + const options = [3, 4, 5, 6, 8]; + options.forEach(cols => { + expect(screen.getByRole("radio", { name: `${cols} colunas` })).toBeInTheDocument(); + }); + }); + + it("calls onChange and updates localStorage when an option is clicked", () => { + const onChange = vi.fn(); + renderSelector(5, onChange); + + const button3 = screen.getByRole("radio", { name: "3 colunas" }); + fireEvent.click(button3); + + expect(onChange).toHaveBeenCalledWith(3); + expect(localStorage.getItem(STORAGE_KEY)).toBe("3"); + }); + + it("persists selection in localStorage across re-renders with aria-checked", () => { + const { rerender } = renderSelector(5); + const button8 = screen.getByRole("radio", { name: "8 colunas" }); + + fireEvent.click(button8); + expect(localStorage.getItem(STORAGE_KEY)).toBe("8"); + + rerender( + + + + ); + + expect(screen.getByRole("radio", { name: "8 colunas" })).toHaveAttribute("aria-checked", "true"); + }); + + it("filters options based on screen width", () => { + // Tablet size + setScreenWidth(800); + const { rerender } = renderSelector(3); + + // At 800px, only 3 and 4 columns should be available (minWidth: 0 and 768) + expect(screen.getByRole("radio", { name: "3 colunas" })).toBeInTheDocument(); + expect(screen.getByRole("radio", { name: "4 colunas" })).toBeInTheDocument(); + expect(screen.queryByRole("radio", { name: "5 colunas" })).not.toBeInTheDocument(); + + // Mobile size + setScreenWidth(375); + rerender( + + + + ); + + // Only 1 option available (3 columns) -> should return null + expect(screen.queryByRole("radiogroup")).not.toBeInTheDocument(); + }); + + it("automatically clamps value if screen size shrinks", async () => { + const onChange = vi.fn(); + const { rerender } = renderSelector(8, onChange); + + // Shrink to tablet (max 4 columns) + setScreenWidth(800); + + rerender( + + + + ); + + await waitFor(() => { + expect(onChange).toHaveBeenCalledWith(4); + }); + }); + + it("supports keyboard navigation with Enter/Space", () => { + const onChange = vi.fn(); + renderSelector(5, onChange); + + const button3 = screen.getByRole("radio", { name: "3 colunas" }); + + fireEvent.focus(button3); + fireEvent.keyDown(button3, { key: "Enter" }); + expect(onChange).toHaveBeenCalledWith(3); + + fireEvent.keyDown(button3, { key: " " }); + expect(onChange).toHaveBeenCalledTimes(2); + }); +}); From c8248dc4bf2aa0bace5a94911f3a989f4cb45dcd Mon Sep 17 00:00:00 2001 From: "gpt-engineer-app[bot]" <159125892+gpt-engineer-app[bot]@users.noreply.github.com> Date: Tue, 26 May 2026 16:02:30 +0000 Subject: [PATCH 11/20] Changes Co-authored-by: adm01-debug <231131902+adm01-debug@users.noreply.github.com> --- src/pages/filters/useFiltersPageState.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/filters/useFiltersPageState.ts b/src/pages/filters/useFiltersPageState.ts index 33af6b5cf..8adf577fd 100644 --- a/src/pages/filters/useFiltersPageState.ts +++ b/src/pages/filters/useFiltersPageState.ts @@ -1,7 +1,7 @@ import { useState, useMemo, useCallback, useEffect, useRef } from 'react'; import { useSearchParams } from 'react-router-dom'; import { type FilterState, defaultFilters } from '@/components/filters/FilterPanel'; -import { getDefaultColumns, type ColumnCount } from '@/components/products/ColumnSelector'; +import { STORAGE_KEY as GRID_COLS_KEY, getDefaultColumns, type ColumnCount } from '@/components/products/ColumnSelector'; import { useColorEnrichment } from '@/hooks/products/useColorEnrichment'; import { useProductFuzzySearch } from '@/hooks/products/useProductFuzzySearch'; import { useProductsByCategory } from '@/hooks/products/useProductsByCategory'; From 082289301c863c1cb367ff88a43de5b78a4e93ee Mon Sep 17 00:00:00 2001 From: "gpt-engineer-app[bot]" <159125892+gpt-engineer-app[bot]@users.noreply.github.com> Date: Tue, 26 May 2026 16:02:34 +0000 Subject: [PATCH 12/20] Changes Co-authored-by: adm01-debug <231131902+adm01-debug@users.noreply.github.com> --- src/pages/filters/useFiltersPageState.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/pages/filters/useFiltersPageState.ts b/src/pages/filters/useFiltersPageState.ts index 8adf577fd..18f5a840e 100644 --- a/src/pages/filters/useFiltersPageState.ts +++ b/src/pages/filters/useFiltersPageState.ts @@ -184,7 +184,13 @@ export function useFiltersPageState() { const [activePresetId, setActivePresetId] = useState(); const [viewMode, setViewMode] = useState<'grid' | 'list' | 'table'>('grid'); const [selectionMode, setSelectionMode] = useState(false); - const [gridColumns, setGridColumns] = useState(getDefaultColumns); + const [gridColumns, setGridColumnsState] = useState(getDefaultColumns); + const setGridColumns = useCallback((cols: ColumnCount) => { + setGridColumnsState(cols); + try { + localStorage.setItem(GRID_COLS_KEY, String(cols)); + } catch { /* empty */ } + }, []); // Responsive clamp: force appropriate columns on small screens useEffect(() => { From 2983724522e86f2e7437bb71863fe8617cc19afa Mon Sep 17 00:00:00 2001 From: "gpt-engineer-app[bot]" <159125892+gpt-engineer-app[bot]@users.noreply.github.com> Date: Tue, 26 May 2026 16:02:51 +0000 Subject: [PATCH 13/20] Changes Co-authored-by: adm01-debug <231131902+adm01-debug@users.noreply.github.com> --- src/pages/collections/useCollectionsPageState.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/collections/useCollectionsPageState.ts b/src/pages/collections/useCollectionsPageState.ts index c1dc75f78..600937c45 100644 --- a/src/pages/collections/useCollectionsPageState.ts +++ b/src/pages/collections/useCollectionsPageState.ts @@ -10,7 +10,7 @@ import { useExternalCollectionProductCounts, } from '@/hooks/collections'; import { toast } from 'sonner'; -import { getDefaultColumns, type ColumnCount } from '@/components/products/ColumnSelector'; +import { STORAGE_KEY as GRID_COLS_KEY, getDefaultColumns, type ColumnCount } from '@/components/products/ColumnSelector'; import type { ViewMode } from '@/hooks/products'; export function useCollectionsPageState() { From b6f4f3fe343e64acaac1f3cdb83b9cd669551225 Mon Sep 17 00:00:00 2001 From: "gpt-engineer-app[bot]" <159125892+gpt-engineer-app[bot]@users.noreply.github.com> Date: Tue, 26 May 2026 16:02:55 +0000 Subject: [PATCH 14/20] Changes Co-authored-by: adm01-debug <231131902+adm01-debug@users.noreply.github.com> --- src/pages/collections/useCollectionsPageState.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/pages/collections/useCollectionsPageState.ts b/src/pages/collections/useCollectionsPageState.ts index 600937c45..1cf9fd931 100644 --- a/src/pages/collections/useCollectionsPageState.ts +++ b/src/pages/collections/useCollectionsPageState.ts @@ -42,7 +42,13 @@ export function useCollectionsPageState() { const [deleteConfirm, setDeleteConfirm] = useState(null); const [searchQuery, setSearchQuery] = useState(''); const [viewMode, setViewMode] = useState('grid'); - const [gridColumns, setGridColumns] = useState(getDefaultColumns); + const [gridColumns, setGridColumnsState] = useState(getDefaultColumns); + const setGridColumns = useCallback((cols: ColumnCount) => { + setGridColumnsState(cols); + try { + localStorage.setItem(GRID_COLS_KEY, String(cols)); + } catch { /* empty */ } + }, []); const [selectedCollectionIds, setSelectedCollectionIds] = useState>(new Set()); const [hintDismissed, setHintDismissed] = useState(false); const [formData, setFormData] = useState<{ From 7d47b2890bb7a8ae9156d392cc5bdbc203bc8852 Mon Sep 17 00:00:00 2001 From: "gpt-engineer-app[bot]" <159125892+gpt-engineer-app[bot]@users.noreply.github.com> Date: Tue, 26 May 2026 16:02:59 +0000 Subject: [PATCH 15/20] Changes Co-authored-by: adm01-debug <231131902+adm01-debug@users.noreply.github.com> --- src/components/novelties/NoveltyProductGrid.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/novelties/NoveltyProductGrid.tsx b/src/components/novelties/NoveltyProductGrid.tsx index 84d93207d..2705b2c10 100644 --- a/src/components/novelties/NoveltyProductGrid.tsx +++ b/src/components/novelties/NoveltyProductGrid.tsx @@ -24,7 +24,7 @@ import { import { useNoveltiesSelectionMode, useNoveltiesWithDetails } from '@/hooks/products'; import { ProductCardSkeleton } from '@/components/products/ProductCardSkeleton'; import { LayoutPopover } from '@/components/products/LayoutPopover'; -import { getDefaultColumns, type ColumnCount, COLUMN_CLASSES } from '@/components/products/ColumnSelector'; +import { STORAGE_KEY as GRID_COLS_KEY, getDefaultColumns, type ColumnCount, COLUMN_CLASSES } from '@/components/products/ColumnSelector'; import { BulkActionBar } from '@/components/products/BulkActionBar'; import { BulkVariantWizard } from '@/components/catalog/BulkVariantWizard'; import { BulkAddToCartModal } from '@/components/catalog/BulkAddToCartModal'; From 7fbc4d6e6a9ea4bb8c59fbe8d9379cacd99a4478 Mon Sep 17 00:00:00 2001 From: "gpt-engineer-app[bot]" <159125892+gpt-engineer-app[bot]@users.noreply.github.com> Date: Tue, 26 May 2026 16:03:04 +0000 Subject: [PATCH 16/20] Changes Co-authored-by: adm01-debug <231131902+adm01-debug@users.noreply.github.com> --- src/components/novelties/NoveltyProductGrid.tsx | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/components/novelties/NoveltyProductGrid.tsx b/src/components/novelties/NoveltyProductGrid.tsx index 2705b2c10..649a41edf 100644 --- a/src/components/novelties/NoveltyProductGrid.tsx +++ b/src/components/novelties/NoveltyProductGrid.tsx @@ -60,7 +60,13 @@ function getGridGapClass(cols: ColumnCount): string { export function NoveltyProductGrid() { const navigate = useNavigate(); const [viewMode, setViewMode] = useState('grid'); - const [gridColumns, setGridColumns] = useState(getDefaultColumns); + const [gridColumns, setGridColumnsState] = useState(getDefaultColumns); + const setGridColumns = useCallback((cols: ColumnCount) => { + setGridColumnsState(cols); + try { + localStorage.setItem(GRID_COLS_KEY, String(cols)); + } catch { /* empty */ } + }, []); const [sortMode, setSortMode] = useState('newest'); const [selectedSupplier, setSelectedSupplier] = useState('all'); const [selectedCategory, setSelectedCategory] = useState('all'); From c204dbe662330f3940101f5caf22714a3c7e1746 Mon Sep 17 00:00:00 2001 From: "gpt-engineer-app[bot]" <159125892+gpt-engineer-app[bot]@users.noreply.github.com> Date: Tue, 26 May 2026 16:03:20 +0000 Subject: [PATCH 17/20] Changes Co-authored-by: adm01-debug <231131902+adm01-debug@users.noreply.github.com> --- src/components/replenishments/ReplenishmentProductGrid.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/replenishments/ReplenishmentProductGrid.tsx b/src/components/replenishments/ReplenishmentProductGrid.tsx index 23a916aab..999b74710 100644 --- a/src/components/replenishments/ReplenishmentProductGrid.tsx +++ b/src/components/replenishments/ReplenishmentProductGrid.tsx @@ -8,7 +8,7 @@ import { useReplenishmentsSelectionMode, useReplenishmentsWithDetails, } from '@/hooks/products'; -import { getDefaultColumns, type ColumnCount } from '@/components/products/ColumnSelector'; +import { STORAGE_KEY as GRID_COLS_KEY, getDefaultColumns, type ColumnCount } from '@/components/products/ColumnSelector'; import { BulkActionBar } from '@/components/products/BulkActionBar'; import { BulkVariantWizard } from '@/components/catalog/BulkVariantWizard'; import { BulkAddToCartModal } from '@/components/catalog/BulkAddToCartModal'; From 97e4d989ceaa3277a26274df12ffb6aefef77357 Mon Sep 17 00:00:00 2001 From: "gpt-engineer-app[bot]" <159125892+gpt-engineer-app[bot]@users.noreply.github.com> Date: Tue, 26 May 2026 16:03:24 +0000 Subject: [PATCH 18/20] Changes Co-authored-by: adm01-debug <231131902+adm01-debug@users.noreply.github.com> --- .../replenishments/ReplenishmentProductGrid.tsx | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/components/replenishments/ReplenishmentProductGrid.tsx b/src/components/replenishments/ReplenishmentProductGrid.tsx index 999b74710..4c5cc485d 100644 --- a/src/components/replenishments/ReplenishmentProductGrid.tsx +++ b/src/components/replenishments/ReplenishmentProductGrid.tsx @@ -59,7 +59,13 @@ function useLoadingProgress(isLoading: boolean): number { export function ReplenishmentProductGrid() { const navigate = useNavigate(); const [viewMode, setViewMode] = useState('grid'); - const [gridColumns, setGridColumns] = useState(getDefaultColumns); + const [gridColumns, setGridColumnsState] = useState(getDefaultColumns); + const setGridColumns = useCallback((cols: ColumnCount) => { + setGridColumnsState(cols); + try { + localStorage.setItem(GRID_COLS_KEY, String(cols)); + } catch { /* empty */ } + }, []); const [sortMode, setSortMode] = useState('newest'); const [selectedSupplier, setSelectedSupplier] = useState('all'); const [selectedCategory, setSelectedCategory] = useState('all'); From c867023b8f7ff3582846a4da421403bfdb2dd451 Mon Sep 17 00:00:00 2001 From: "gpt-engineer-app[bot]" <159125892+gpt-engineer-app[bot]@users.noreply.github.com> Date: Tue, 26 May 2026 16:03:35 +0000 Subject: [PATCH 19/20] Changes Co-authored-by: adm01-debug <231131902+adm01-debug@users.noreply.github.com> --- src/hooks/products/useCatalogState.ts | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/hooks/products/useCatalogState.ts b/src/hooks/products/useCatalogState.ts index ea5709ffd..cadafe7b3 100644 --- a/src/hooks/products/useCatalogState.ts +++ b/src/hooks/products/useCatalogState.ts @@ -107,20 +107,25 @@ export function useCatalogState() { }); }, []); - // Responsive clamp + // Responsive clamp: garante que o número de colunas não ultrapasse o disponível + // para a largura atual da tela, mantendo a consistência visual. useEffect(() => { const handleResize = () => { const w = window.innerWidth; - if (w < 640 && gridColumns > 1) { - setGridColumnsState(3 as ColumnCount); - } else if (w >= 640 && w < 768 && gridColumns > 2) { - setGridColumnsState(3 as ColumnCount); + let maxCols: ColumnCount = 3; + if (w >= 1536) maxCols = 8; + else if (w >= 1280) maxCols = 6; + else if (w >= 1024) maxCols = 5; + else if (w >= 768) maxCols = 4; + + if (gridColumns > maxCols) { + setGridColumns(maxCols); } }; handleResize(); window.addEventListener('resize', handleResize); return () => window.removeEventListener('resize', handleResize); - }, [gridColumns]); + }, [gridColumns, setGridColumns]); const [filterSheetOpen, setFilterSheetOpen] = useState(false); const [searchQuery, setSearchQuery] = useState(searchQueryFromUrl); From da9eefc80ceb0126d0880064203e3b9f695b927a Mon Sep 17 00:00:00 2001 From: "gpt-engineer-app[bot]" <159125892+gpt-engineer-app[bot]@users.noreply.github.com> Date: Tue, 26 May 2026 16:03:40 +0000 Subject: [PATCH 20/20] Changes Co-authored-by: adm01-debug <231131902+adm01-debug@users.noreply.github.com> --- src/pages/filters/useFiltersPageState.ts | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/pages/filters/useFiltersPageState.ts b/src/pages/filters/useFiltersPageState.ts index 18f5a840e..8ca28f9d5 100644 --- a/src/pages/filters/useFiltersPageState.ts +++ b/src/pages/filters/useFiltersPageState.ts @@ -196,14 +196,20 @@ export function useFiltersPageState() { useEffect(() => { const handleResize = () => { const w = window.innerWidth; - if (w < 768 && gridColumns > 3) { - setGridColumns(3); + let maxCols: ColumnCount = 3; + if (w >= 1536) maxCols = 8; + else if (w >= 1280) maxCols = 6; + else if (w >= 1024) maxCols = 5; + else if (w >= 768) maxCols = 4; + + if (gridColumns > maxCols) { + setGridColumns(maxCols); } }; handleResize(); window.addEventListener('resize', handleResize); return () => window.removeEventListener('resize', handleResize); - }, [gridColumns]); + }, [gridColumns, setGridColumns]); const [voiceOverlayOpen, setVoiceOverlayOpen] = useState(false); const [commandAction, setCommandAction] = useState(null); const [appliedFilters, setAppliedFilters] = useState<