diff --git a/src/client/features/keywords/hooks/useLocalKeywordFilters.ts b/src/client/features/keywords/hooks/useLocalKeywordFilters.ts index ea5bd44..e87466a 100644 --- a/src/client/features/keywords/hooks/useLocalKeywordFilters.ts +++ b/src/client/features/keywords/hooks/useLocalKeywordFilters.ts @@ -1,17 +1,58 @@ -import { useCallback } from "react"; +import { useCallback, useEffect } from "react"; import { useForm, useStore } from "@tanstack/react-form"; +import { z } from "zod"; import { EMPTY_FILTERS, type KeywordFilterValues, } from "@/client/features/keywords/keywordResearchTypes"; +const STORAGE_KEY = "keyword-default-filters"; + +const filterValuesSchema = z.object({ + include: z.string(), + exclude: z.string(), + minVol: z.string(), + maxVol: z.string(), + minCpc: z.string(), + maxCpc: z.string(), + minKd: z.string(), + maxKd: z.string(), +}); + +function loadFiltersFromStorage(): KeywordFilterValues { + try { + const raw = localStorage.getItem(STORAGE_KEY); + if (!raw) return EMPTY_FILTERS; + return filterValuesSchema.parse(JSON.parse(raw)); + } catch { + return EMPTY_FILTERS; + } +} + +function saveFiltersToStorage(filters: KeywordFilterValues) { + try { + const hasAnyFilter = Object.values(filters).some((v) => v.trim() !== ""); + if (hasAnyFilter) { + localStorage.setItem(STORAGE_KEY, JSON.stringify(filters)); + } else { + localStorage.removeItem(STORAGE_KEY); + } + } catch { + // storage full or unavailable + } +} + export function useLocalKeywordFilters() { const filtersForm = useForm({ - defaultValues: EMPTY_FILTERS, + defaultValues: loadFiltersFromStorage(), }); const values = useStore(filtersForm.store, (s) => s.values); + useEffect(() => { + saveFiltersToStorage(values); + }, [values]); + const resetFilters = useCallback(() => { const keys: Array = [ "include", diff --git a/src/client/features/keywords/page/KeywordResearchDesktopResults.tsx b/src/client/features/keywords/page/KeywordResearchDesktopResults.tsx index 2bbe8c4..f60c575 100644 --- a/src/client/features/keywords/page/KeywordResearchDesktopResults.tsx +++ b/src/client/features/keywords/page/KeywordResearchDesktopResults.tsx @@ -103,9 +103,16 @@ function DesktopKeywordPanel({ controller }: Props) { } function DesktopTableCard({ controller }: Props) { - const { activeFilterCount, filteredRows, selectedRows, showFilters } = + const { activeFilterCount, filteredRows, rows, selectedRows, showFilters } = controller; + const keywordCountLabel = + selectedRows.size > 0 + ? `${selectedRows.size} of ${filteredRows.length} selected` + : activeFilterCount > 0 + ? `Showing ${filteredRows.length} of ${rows.length} keywords` + : `Showing ${filteredRows.length} keywords`; + return (
@@ -123,9 +130,7 @@ function DesktopTableCard({ controller }: Props) { ) : null} - {selectedRows.size > 0 - ? `${selectedRows.size} of ${filteredRows.length} selected` - : `${filteredRows.length} keywords`} + {keywordCountLabel}
- {selectedRows.size > 0 - ? `${selectedRows.size} selected` - : `${filteredRows.length} keywords`} + {keywordCountLabel}