import { createSyncStore } from '@warkypublic/zustandsyncstore'; import { produce } from 'immer'; import type { BoxerProps, BoxerStoreState } from './Boxer.types'; const { Provider: BoxerProvider, useStore: useBoxerStore } = createSyncStore< BoxerStoreState, BoxerProps >( (set, get) => ({ boxerData: [], // Data Actions fetchData: async (search?: string, reset?: boolean) => { const state = get(); // Handle local data if (state.dataSource === 'local' || !state.onAPICall) { const localData = state.data ?? []; if (!search) { set({ boxerData: localData, hasMore: false, total: localData.length }); return; } // Filter local data based on search const filtered = localData.filter((item) => item.label.toLowerCase().includes(search.toLowerCase()) ); set({ boxerData: filtered, hasMore: false, total: filtered.length }); return; } // Handle server-side data if (state.onAPICall) { try { set({ isFetching: true }); const currentPage = reset ? 0 : state.page; const result = await state.onAPICall({ page: currentPage, pageSize: state.pageSize, search, }); set( produce((draft) => { if (reset) { draft.boxerData = result.data; draft.page = 0; } else { draft.boxerData = [...(draft.boxerData ?? []), ...result.data]; } draft.total = result.total; draft.hasMore = draft.boxerData.length < result.total; draft.isFetching = false; }) ); } catch (error) { console.error('Boxer fetchData error:', error); set({ isFetching: false }); } } }, fetchMoreOnBottomReached: (target: HTMLDivElement) => { const state = get(); if (!state.hasMore || state.isFetching) { return; } const scrollPercentage = (target.scrollTop + target.clientHeight) / target.scrollHeight; // Load more when scrolled past 80% if (scrollPercentage > 0.8) { state.loadMore(); } }, // State Management getState: (key) => { const current = get(); return current?.[key]; }, hasMore: true, input: '', isFetching: false, loadMore: async () => { const state = get(); if (!state.hasMore || state.isFetching) { return; } set( produce((draft) => { draft.page = draft.page + 1; }) ); await state.fetchData(state.search); }, // Initial State opened: false, page: 0, pageSize: 50, search: '', selectedOptionIndex: -1, setInput: (input: string) => { set({ input }); }, // Actions setOpened: (opened: boolean) => { set({ opened }); }, setSearch: (search: string) => { set({ search }); }, setSelectedOptionIndex: (index: number) => { set({ selectedOptionIndex: index }); }, setState: (key, value) => { set( produce((state) => { state[key] = value; }) ); }, total: 0, }), ({ data = [], dataSource = 'local', pageSize = 50, ...props }) => { return { ...props, boxerData: data, // Initialize with local data if provided data, dataSource, hasMore: dataSource === 'server', pageSize, total: data.length, }; } ); export { BoxerProvider }; export { useBoxerStore };