From 873a0209592090e84799f45dcb14b3c5a7f2189d Mon Sep 17 00:00:00 2001 From: Ilia Mashkov Date: Thu, 1 Jan 2026 15:48:45 +0300 Subject: [PATCH] feature(createFilterStore): create fiter store generator --- src/shared/store/createFilterStore.ts | 189 ++++++++++++++++++++++++++ 1 file changed, 189 insertions(+) create mode 100644 src/shared/store/createFilterStore.ts diff --git a/src/shared/store/createFilterStore.ts b/src/shared/store/createFilterStore.ts new file mode 100644 index 0000000..b632f53 --- /dev/null +++ b/src/shared/store/createFilterStore.ts @@ -0,0 +1,189 @@ +import { derived, Readable, Writable, writable } from 'svelte/store'; + +export interface Category { + /** + * Category identifier + */ + id: string; + /** + * Category name + */ + name: string; + /** + * Category selected state + */ + selected: boolean; +} + +export interface FilterModel { + /** + * Search query + */ + searchQuery?: string; + /** + * Categories + */ + categories: Category[]; +} + +/** + * Model for reusable filter store with search support and category selection + */ +export interface FilterStore extends Writable { + /** + * Get the store. + * @returns Readable store with filter data + */ + getStore: () => Readable; + /** + * Get the selected categories. + * @returns Readable store with selected categories + */ + getSelectedCategories: () => Readable; + /** + * Get the filtered categories. + * @returns Readable store with filtered categories + */ + getFilteredCategories: () => Readable; + /** + * Update the search query filter. + * + * @param searchQuery - Search text (undefined to clear) + */ + setSearchQuery: (searchQuery: string | undefined) => void; + /** + * Clear the search query filter. + */ + clearSearchQuery: () => void; + /** + * Select a category. + * + * @param category - Category to select + */ + selectCategory: (categoryId: string) => void; + /** + * Deselect a category. + * + * @param category - Category to deselect + */ + deselectCategory: (categoryId: string) => void; + /** + * Select all categories. + */ + selectAllCategories: () => void; + /** + * Deselect all categories. + */ + deselectAllCategories: () => void; +} + +/** + * Create a filter store. + * @param initialState - Initial state of the filter store + * @returns FilterStore + */ +export function createFilterStore( + initialState: T, +): FilterStore { + const { subscribe, set, update } = writable(initialState); + + return { + /* + * Expose subscribe, set, and update from Writable. + * This makes FilterStore compatible with Writable interface. + */ + subscribe, + set, + update, + /** + * Get the current state of the filter store. + */ + getStore: () => { + return { + subscribe, + }; + }, + /** + * Get the selected categories. + */ + getSelectedCategories: () => { + return derived({ subscribe }, $store => { + return $store.categories.filter(category => category.selected); + }); + }, + /** + * Get the filtered categories. + */ + getFilteredCategories: () => { + return derived({ subscribe }, $store => { + return $store.categories.filter(category => + category.name.includes($store.searchQuery || '') + ); + }); + }, + /** + * Update the search query filter. + * + * @param searchQuery - Search text (undefined to clear) + */ + setSearchQuery: (searchQuery: string | undefined) => { + update(state => ({ + ...state, + searchQuery: searchQuery || undefined, + })); + }, + /** + * Clear the search query filter. + */ + clearSearchQuery: () => { + update(state => ({ + ...state, + searchQuery: undefined, + })); + }, + /** + * Select a category. + * + * @param categoryId - Category ID + */ + selectCategory: (categoryId: string) => { + update(state => ({ + ...state, + categories: state.categories.map(c => + c.id === categoryId ? { ...c, selected: true } : c + ), + })); + }, + /** + * Deselect a category. + * + * @param categoryId - Category ID + */ + deselectCategory: (categoryId: string) => { + update(state => ({ + ...state, + categories: state.categories.map(c => + c.id === categoryId ? { ...c, selected: false } : c + ), + })); + }, + /** + * Select all categories + */ + selectAllCategories: () => { + update(state => ({ + ...state, + categories: state.categories.map(c => ({ ...c, selected: true })), + })); + }, + /** + * Deselect all categories + */ + deselectAllCategories: () => { + update(state => ({ + ...state, + categories: state.categories.map(c => ({ ...c, selected: false })), + })); + }, + }; +}