import { produce } from "immer" import { useContext } from "react" import { create, useStore } from "zustand" import { HotelDataContext } from "@/contexts/HotelData" import { getBasePathNameWithoutFilters, getFilteredHotels, getFiltersFromHotels, getSortedHotels, isValidSortOption, } from "./helper" import type { Filter } from "@/types/components/hotelFilterAndSort" import { SortOption } from "@/types/enums/hotelFilterAndSort" import type { HotelDataState, InitialState } from "@/types/stores/hotel-data" export function createHotelDataStore({ allHotels, searchParams, pathname, filterFromUrl, sortItems, submitCallbackFn, }: InitialState) { const sortFromSearchParams = searchParams.get("sort") const initialFilters = filterFromUrl ? [filterFromUrl] : [] let initialSort = SortOption.Distance if ( sortFromSearchParams && isValidSortOption(sortFromSearchParams, sortItems) ) { initialSort = sortFromSearchParams } const initialFilteredHotels = getFilteredHotels(allHotels, initialFilters) const initialActiveHotels = getSortedHotels( initialFilteredHotels, initialSort ) const allFilters = getFiltersFromHotels(allHotels) const allFilterSlugs = Object.values(allFilters).flatMap((filter: Filter[]) => filter.map((f) => f.slug) ) return create((set) => ({ actions: { submitFiltersAndSort() { return set( produce((state: HotelDataState) => { const sort = state.pendingSort const filters = state.pendingFilters const filteredHotels = getFilteredHotels(state.allHotels, filters) const sortedHotels = getSortedHotels(filteredHotels, sort) state.activeSort = sort state.activeFilters = state.pendingFilters state.activeHotels = sortedHotels state.pendingCount = filteredHotels.length if (submitCallbackFn) { submitCallbackFn({ sort, filters, basePath: state.basePathnameWithoutFilters, }) } }) ) }, setPendingSort(sort) { return set( produce((state: HotelDataState) => { state.pendingSort = sort }) ) }, togglePendingFilter(filter) { return set( produce((state: HotelDataState) => { const isActive = state.pendingFilters.includes(filter) const filters = isActive ? state.pendingFilters.filter((f) => f !== filter) : [...state.pendingFilters, filter] const pendingHotels = getFilteredHotels(state.allHotels, filters) state.pendingFilters = filters state.pendingCount = pendingHotels.length }) ) }, clearPendingFilters() { return set( produce((state: HotelDataState) => { state.pendingFilters = [] state.pendingCount = state.allHotels.length }) ) }, resetPendingValues() { return set( produce((state: HotelDataState) => { state.pendingFilters = state.activeFilters state.pendingSort = state.activeSort state.pendingCount = state.activeHotels.length }) ) }, loadInitialHashFilter(hash) { return set( produce((state: HotelDataState) => { state.initialHashFilterLoaded = true const filters = [] const filtersFromHash = hash.split("&").filter(Boolean) ?? [] if (filterFromUrl) { filters.push(filterFromUrl, ...filtersFromHash) } const filteredHotels = getFilteredHotels(state.allHotels, filters) const sortedHotels = getSortedHotels( filteredHotels, state.activeSort ) state.activeHotels = sortedHotels state.activeFilters = filters state.pendingFilters = filters state.pendingCount = filteredHotels.length }) ) }, }, allHotels, activeHotels: initialActiveHotels, pendingCount: initialActiveHotels.length, activeSort: initialSort, pendingSort: initialSort, activeFilters: initialFilters, pendingFilters: initialFilters, searchParams, allFilters, allFilterSlugs, basePathnameWithoutFilters: getBasePathNameWithoutFilters( pathname, allFilterSlugs ), sortItems, initialHashFilterLoaded: false, })) } export function useHotelDataStore(selector: (store: HotelDataState) => T) { const store = useContext(HotelDataContext) if (!store) { throw new Error("useHotelDataStore must be used within HotelDataProvider") } return useStore(store, selector) }