diff --git a/app/layout.tsx b/app/layout.tsx index 702197b..92db6b9 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -6,6 +6,7 @@ import { ThemeProvider } from '@/components/theme-provider'; import { Toaster } from '@/components/ui/toaster'; import { TooltipProvider } from '@/components/ui/tooltip'; import { cn } from '@/lib/utils'; +import StoreProvider from '@/stores/store-provider'; const inter = Inter({ subsets: ['latin'] }); @@ -29,9 +30,11 @@ export default function RootLayout({ enableSystem disableTransitionOnChange > - - - {children} + + + + {children} + diff --git a/stores/store-provider.tsx b/stores/store-provider.tsx new file mode 100644 index 0000000..6bfbc95 --- /dev/null +++ b/stores/store-provider.tsx @@ -0,0 +1,20 @@ +import { type PropsWithChildren, useRef } from 'react'; +import type { StoreInterface, StoreType } from './store'; +import { initializeStore, StoreContextProvider } from './store'; + +export default function StoreProvider({ + children, + ...props +}: PropsWithChildren) { + const storeRef = useRef(); + + if (!storeRef.current) { + storeRef.current = initializeStore(props); + } + + return ( + + {children} + + ); +} diff --git a/stores/store.ts b/stores/store.ts new file mode 100644 index 0000000..c5c7672 --- /dev/null +++ b/stores/store.ts @@ -0,0 +1,59 @@ +import { createContext, useContext } from 'react'; +import { createStore, useStore as useZustandStore } from 'zustand'; +import { PreloadedStoreInterface } from './store-provider'; + +export interface StoreInterface { + lastUpdate: number; + light: boolean; + count: number; + tick: (lastUpdate: number) => void; + increment: () => void; + decrement: () => void; + reset: () => void; +} + +function getDefaultInitialState() { + return { + lastUpdate: new Date(1970, 1, 1).getTime(), + light: false, + count: 0, + } as const; +} + +export type StoreType = ReturnType; + +const storeContext = createContext(null); + +export const StoreContextProvider = storeContext.Provider; + +export function useStore(selector: (state: StoreInterface) => T) { + const store = useContext(storeContext); + + if (!store) throw new Error('Store is missing the provider'); + + return useZustandStore(store, selector); +} + +export const initializeStore = (preloadedState: PreloadedStoreInterface) => { + return createStore((set, get) => ({ + ...getDefaultInitialState(), + ...preloadedState, + tick: (lastUpdate) => + set({ + lastUpdate, + light: !get().light, + }), + increment: () => + set({ + count: get().count + 1, + }), + decrement: () => + set({ + count: get().count - 1, + }), + reset: () => + set({ + count: getDefaultInitialState().count, + }), + })); +};