diff --git a/package-lock.json b/package-lock.json index b4d28b4..ce1c8d1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -22,6 +22,7 @@ "clsx": "^2.1.1", "drizzle-orm": "^0.29.4", "geist": "^1.3.0", + "immer": "^10.1.1", "lucide-react": "^0.379.0", "next": "^15.0.0-rc.0", "postgres": "^3.4.3", @@ -5229,6 +5230,15 @@ "node": ">= 4" } }, + "node_modules/immer": { + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/immer/-/immer-10.1.1.tgz", + "integrity": "sha512-s2MPrmjovJcoMaHtx6K11Ra7oD05NT97w1IC5zpMkT6Atjr7H8LjaDd81iIxUYpMKSRRNMJE703M1Fhr/TctHw==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/immer" + } + }, "node_modules/import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", diff --git a/package.json b/package.json index 208c3ab..7323307 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,7 @@ "clsx": "^2.1.1", "drizzle-orm": "^0.29.4", "geist": "^1.3.0", + "immer": "^10.1.1", "lucide-react": "^0.379.0", "next": "^15.0.0-rc.0", "postgres": "^3.4.3", diff --git a/src/app/store.ts b/src/app/store.ts new file mode 100644 index 0000000..04ea7f2 --- /dev/null +++ b/src/app/store.ts @@ -0,0 +1,144 @@ +import { create } from "zustand"; +import { produce } from "immer"; + +interface FilterState { + filters: Filters; +} + +interface Filters { + regions: string[]; + countries: string[]; + producers: string[]; + price: Price; + type: WineType; +} + +interface Price { + min: number; + max: number; +} + +interface WineType { + sparkling: boolean; + white: boolean; + red: boolean; + sweet: boolean; + other: boolean; +} + +type FilterActions = { + addRegion: (region: string) => void; + removeRegion: (region: string) => void; + addCountry: (country: string) => void; + removeCountry: (country: string) => void; + addProducer: (producer: string) => void; + removeProducer: (producer: string) => void; + setPrice: (min: number, max: number) => void; + setType: (type: keyof WineType, value: boolean) => void; + resetFilters: () => void; +}; + +const initialFilters: Filters = { + regions: [], + countries: [], + producers: [], + price: { + min: 0, + max: 9999, + }, + type: { + sparkling: false, + white: false, + red: false, + sweet: false, + other: false, + }, +}; + +const useFilterStore = create()((set) => ({ + filters: { + regions: [], + countries: [], + producers: [], + price: { + min: 0, + max: 9999, + }, + type: { + sparkling: false, + white: false, + red: false, + sweet: false, + other: false, + }, + }, + addRegion: (region) => + set( + produce((state: FilterState) => { + if (!state.filters.regions.includes(region)) { + state.filters.regions.push(region); + } + }), + ), + removeRegion: (region) => + set( + produce((state: FilterState) => { + state.filters.regions = state.filters.regions.filter( + (r) => r !== region, + ); + }), + ), + addCountry: (country) => + set( + produce((state: FilterState) => { + if (!state.filters.countries.includes(country)) { + state.filters.countries.push(country); + } + }), + ), + removeCountry: (country) => + set( + produce((state: FilterState) => { + state.filters.countries = state.filters.countries.filter( + (c) => c !== country, + ); + }), + ), + addProducer: (producer) => + set( + produce((state: FilterState) => { + if (!state.filters.producers.includes(producer)) { + state.filters.producers.push(producer); + } + }), + ), + removeProducer: (producer) => + set( + produce((state: FilterState) => { + state.filters.producers = state.filters.producers.filter( + (p) => p !== producer, + ); + }), + ), + setPrice: (min, max) => + set( + produce((state: FilterState) => { + state.filters.price.min = min; + state.filters.price.max = max; + }), + ), + setType: (type, value) => + set( + produce((state: FilterState) => { + state.filters.type[type] = value; + }), + ), + resetFilters: () => + set( + produce((state: FilterState) => { + state.filters = initialFilters; + }), + ), +})); + +export default useFilterStore;