diff --git a/src/modules/template-search/infrastructure/templateSearchTabPreference.ts b/src/modules/template-search/infrastructure/templateSearchTabPreference.ts index c50665c19..31c5e92ad 100644 --- a/src/modules/template-search/infrastructure/templateSearchTabPreference.ts +++ b/src/modules/template-search/infrastructure/templateSearchTabPreference.ts @@ -12,10 +12,12 @@ import { const STORAGE_KEY = 'macroflows:template-search-tab' -/** - * Default tab to use when no preference is saved. - */ -export const DEFAULT_TAB: TemplateSearchTab = availableTabs.Todos.id +const DEFAULT_TAB: TemplateSearchTab = availableTabs.Todos.id + +type TemplateSearchTabPreference = { + loadTabPreference: () => TemplateSearchTab + saveTabPreference: (tab: TemplateSearchTab) => void +} /** * Checks if a value is a valid TemplateSearchTab. @@ -31,7 +33,7 @@ function isValidTab(value: string): value is TemplateSearchTab { * Loads the saved template search tab preference from localStorage. * @returns The saved tab preference, or the default tab if none is saved or invalid */ -export function loadTabPreference(): TemplateSearchTab { +function loadTabPreference(): TemplateSearchTab { try { const stored = localStorage.getItem(STORAGE_KEY) if (stored !== null && isValidTab(stored)) { @@ -47,7 +49,7 @@ export function loadTabPreference(): TemplateSearchTab { * Saves the template search tab preference to localStorage. * @param tab - The tab to save */ -export function saveTabPreference(tab: TemplateSearchTab): void { +function saveTabPreference(tab: TemplateSearchTab): void { try { // Don't persist the 'hidden' state if (tab !== 'hidden') { @@ -57,3 +59,14 @@ export function saveTabPreference(tab: TemplateSearchTab): void { // localStorage may not be available (SSR, private mode, etc.) } } + +/** + * Creates a localStorage-backed template search tab preference adapter. + * @returns An adapter with methods to load and save the selected tab + */ +export function createTemplateSearchTabPreference(): TemplateSearchTabPreference { + return { + loadTabPreference, + saveTabPreference, + } +} diff --git a/src/modules/template-search/infrastructure/tests/templateSearchTabPreference.test.ts b/src/modules/template-search/infrastructure/tests/templateSearchTabPreference.test.ts index 4b3455564..3774a2b40 100644 --- a/src/modules/template-search/infrastructure/tests/templateSearchTabPreference.test.ts +++ b/src/modules/template-search/infrastructure/tests/templateSearchTabPreference.test.ts @@ -31,9 +31,11 @@ describe('templateSearchTabPreference', () => { describe('loadTabPreference', () => { it('returns default tab when localStorage is empty', async () => { - const { loadTabPreference, DEFAULT_TAB } = + const { createTemplateSearchTabPreference } = await import('~/modules/template-search/infrastructure/templateSearchTabPreference') - expect(loadTabPreference()).toBe(DEFAULT_TAB) + const tabPreference = createTemplateSearchTabPreference() + + expect(tabPreference.loadTabPreference()).toBe(availableTabs.Todos.id) }) it('returns persisted tab from localStorage', async () => { @@ -41,9 +43,11 @@ describe('templateSearchTabPreference', () => { setMockLocalStorage() vi.resetModules() - const { loadTabPreference } = + const { createTemplateSearchTabPreference } = await import('~/modules/template-search/infrastructure/templateSearchTabPreference') - expect(loadTabPreference()).toBe(availableTabs.Favoritos.id) + const tabPreference = createTemplateSearchTabPreference() + + expect(tabPreference.loadTabPreference()).toBe(availableTabs.Favoritos.id) }) it('returns persisted Recentes tab from localStorage', async () => { @@ -51,9 +55,11 @@ describe('templateSearchTabPreference', () => { setMockLocalStorage() vi.resetModules() - const { loadTabPreference } = + const { createTemplateSearchTabPreference } = await import('~/modules/template-search/infrastructure/templateSearchTabPreference') - expect(loadTabPreference()).toBe(availableTabs.Recentes.id) + const tabPreference = createTemplateSearchTabPreference() + + expect(tabPreference.loadTabPreference()).toBe(availableTabs.Recentes.id) }) it('returns persisted Receitas tab from localStorage', async () => { @@ -61,9 +67,11 @@ describe('templateSearchTabPreference', () => { setMockLocalStorage() vi.resetModules() - const { loadTabPreference } = + const { createTemplateSearchTabPreference } = await import('~/modules/template-search/infrastructure/templateSearchTabPreference') - expect(loadTabPreference()).toBe(availableTabs.Receitas.id) + const tabPreference = createTemplateSearchTabPreference() + + expect(tabPreference.loadTabPreference()).toBe(availableTabs.Receitas.id) }) it('returns default tab for invalid stored value', async () => { @@ -71,27 +79,31 @@ describe('templateSearchTabPreference', () => { setMockLocalStorage() vi.resetModules() - const { loadTabPreference, DEFAULT_TAB } = + const { createTemplateSearchTabPreference } = await import('~/modules/template-search/infrastructure/templateSearchTabPreference') - expect(loadTabPreference()).toBe(DEFAULT_TAB) + const tabPreference = createTemplateSearchTabPreference() + + expect(tabPreference.loadTabPreference()).toBe(availableTabs.Todos.id) }) }) describe('saveTabPreference', () => { it('saves tab preference to localStorage', async () => { - const { saveTabPreference } = + const { createTemplateSearchTabPreference } = await import('~/modules/template-search/infrastructure/templateSearchTabPreference') + const tabPreference = createTemplateSearchTabPreference() - saveTabPreference(availableTabs.Favoritos.id) + tabPreference.saveTabPreference(availableTabs.Favoritos.id) expect(localStorageMock[STORAGE_KEY]).toBe(availableTabs.Favoritos.id) }) it('does not persist hidden tab state', async () => { - const { saveTabPreference } = + const { createTemplateSearchTabPreference } = await import('~/modules/template-search/infrastructure/templateSearchTabPreference') + const tabPreference = createTemplateSearchTabPreference() - saveTabPreference('hidden') + tabPreference.saveTabPreference('hidden') expect(localStorageMock[STORAGE_KEY]).toBeUndefined() }) @@ -101,10 +113,11 @@ describe('templateSearchTabPreference', () => { setMockLocalStorage() vi.resetModules() - const { saveTabPreference } = + const { createTemplateSearchTabPreference } = await import('~/modules/template-search/infrastructure/templateSearchTabPreference') + const tabPreference = createTemplateSearchTabPreference() - saveTabPreference(availableTabs.Recentes.id) + tabPreference.saveTabPreference(availableTabs.Recentes.id) expect(localStorageMock[STORAGE_KEY]).toBe(availableTabs.Recentes.id) }) @@ -112,27 +125,35 @@ describe('templateSearchTabPreference', () => { describe('round-trip persistence', () => { it('can save and load tab preference', async () => { - const { saveTabPreference } = + const { createTemplateSearchTabPreference } = await import('~/modules/template-search/infrastructure/templateSearchTabPreference') + const tabPreference = createTemplateSearchTabPreference() // Save a preference - saveTabPreference(availableTabs.Receitas.id) + tabPreference.saveTabPreference(availableTabs.Receitas.id) // Re-import to get fresh module state vi.resetModules() const freshModule = await import('~/modules/template-search/infrastructure/templateSearchTabPreference') + const freshTabPreference = freshModule.createTemplateSearchTabPreference() // Load should return the saved preference - expect(freshModule.loadTabPreference()).toBe(availableTabs.Receitas.id) + expect(freshTabPreference.loadTabPreference()).toBe( + availableTabs.Receitas.id, + ) }) }) - describe('DEFAULT_TAB', () => { - it('is the Todos tab', async () => { - const { DEFAULT_TAB } = + describe('createTemplateSearchTabPreference', () => { + it('returns load and save methods', async () => { + const { createTemplateSearchTabPreference } = await import('~/modules/template-search/infrastructure/templateSearchTabPreference') - expect(DEFAULT_TAB).toBe(availableTabs.Todos.id) + + const tabPreference = createTemplateSearchTabPreference() + + expect(typeof tabPreference.loadTabPreference).toBe('function') + expect(typeof tabPreference.saveTabPreference).toBe('function') }) }) }) diff --git a/src/sections/search/components/TemplateSearchModal.tsx b/src/sections/search/components/TemplateSearchModal.tsx index 8e023c6c4..2d8505270 100644 --- a/src/sections/search/components/TemplateSearchModal.tsx +++ b/src/sections/search/components/TemplateSearchModal.tsx @@ -13,10 +13,7 @@ import { import { type Template } from '~/modules/diet/template/domain/template' import { isTemplateRecipe } from '~/modules/diet/template/domain/template' import { type TemplateItem } from '~/modules/diet/template-item/domain/templateItem' -import { - loadTabPreference, - saveTabPreference, -} from '~/modules/template-search/infrastructure/templateSearchTabPreference' +import { createTemplateSearchTabPreference } from '~/modules/template-search/infrastructure/templateSearchTabPreference' import { showError, showSuccess, @@ -39,6 +36,8 @@ import { } from '~/shared/modal/helpers/modalHelpers' import { logging } from '~/shared/utils/logging' +const templateSearchTabPreference = createTemplateSearchTabPreference() + export type TemplateSearchModalProps = { targetName: string onNewItem?: (item: Item, originalAddedItem: TemplateItem) => void @@ -211,7 +210,7 @@ export function TemplateSearch(props: { // Load persisted tab preference on mount (only once) onMount(() => { - const persistedTab = loadTabPreference() + const persistedTab = templateSearchTabPreference.loadTabPreference() templateSearchState.setTemplateSearchTab(persistedTab) }) @@ -228,7 +227,7 @@ export function TemplateSearch(props: { : tabOrUpdater templateSearchState.setTemplateSearchTab(newTab) - saveTabPreference(newTab) + templateSearchTabPreference.saveTabPreference(newTab) } return (