From 7e886172f283520b87f88c19f24f6ea74ee83ca8 Mon Sep 17 00:00:00 2001 From: vchikalkin Date: Wed, 30 Apr 2025 18:58:46 +0300 Subject: [PATCH] pass order store via context --- apps/web/components/orders/order-form.tsx | 16 ++--- apps/web/stores/order/context.tsx | 18 ++++++ apps/web/stores/order/hooks.tsx | 40 ++++++++++++ apps/web/stores/order/index.tsx | 3 +- apps/web/stores/order/store.ts | 79 +++++++++-------------- apps/web/stores/order/types.tsx | 3 - 6 files changed, 97 insertions(+), 62 deletions(-) create mode 100644 apps/web/stores/order/context.tsx create mode 100644 apps/web/stores/order/hooks.tsx diff --git a/apps/web/components/orders/order-form.tsx b/apps/web/components/orders/order-form.tsx index dfa4944..745a9c6 100644 --- a/apps/web/components/orders/order-form.tsx +++ b/apps/web/components/orders/order-form.tsx @@ -7,9 +7,9 @@ import { ServiceSelect, SubmitButton, } from './components'; -import { useProfileQuery } from '@/hooks/profile'; -import { useOrderStore } from '@/stores/order'; -import { type JSX, useEffect } from 'react'; +import { OrderStoreProvider, useOrderStore } from '@/stores/order'; +import { withContext } from '@/utils/context'; +import { type JSX } from 'react'; const STEP_COMPONENTS: Record = { 'client-select': , @@ -18,14 +18,8 @@ const STEP_COMPONENTS: Record = { 'service-select': , }; -export function OrderForm() { - const { data: customer } = useProfileQuery(); +export const OrderForm = withContext(OrderStoreProvider)(function () { const step = useOrderStore((store) => store.step); - const initStepSequence = useOrderStore((store) => store.initStepSequence); - - useEffect(() => { - initStepSequence(customer?.role); - }, [customer?.role, initStepSequence]); return (
@@ -36,7 +30,7 @@ export function OrderForm() {
); -} +}); function getStepComponent(step: string) { return STEP_COMPONENTS[step] ?? null; diff --git a/apps/web/stores/order/context.tsx b/apps/web/stores/order/context.tsx new file mode 100644 index 0000000..2faaf3a --- /dev/null +++ b/apps/web/stores/order/context.tsx @@ -0,0 +1,18 @@ +'use client'; +import { useInitialState } from './hooks'; +import { createOrderStore } from './store'; +import { createContext, type PropsWithChildren, useRef } from 'react'; + +export type OrderStoreApi = ReturnType; + +export const OrderStoreContext = createContext(undefined); + +export function OrderStoreProvider({ children }: Readonly) { + const storeRef = useRef(null); + const initialState = useInitialState(); + if (storeRef.current === null) { + storeRef.current = createOrderStore(initialState); + } + + return {children}; +} diff --git a/apps/web/stores/order/hooks.tsx b/apps/web/stores/order/hooks.tsx new file mode 100644 index 0000000..cb940d7 --- /dev/null +++ b/apps/web/stores/order/hooks.tsx @@ -0,0 +1,40 @@ +/* eslint-disable canonical/id-match */ +'use client'; +import { OrderStoreContext } from './context'; +import { type OrderStore, type Steps } from './types'; +import { useProfileQuery } from '@/hooks/profile'; +import { Enum_Customer_Role } from '@repo/graphql/types'; +import { useContext } from 'react'; +import { useStore } from 'zustand'; + +export const MASTER_STEPS: Steps[] = [ + 'master-select', + 'client-select', + 'service-select', + 'datetime-select', + 'success', +]; + +export const CLIENT_STEPS: Steps[] = MASTER_STEPS.filter((step) => step !== 'client-select'); + +export function useInitialState() { + const { data } = useProfileQuery(); + const role = data?.role; + const steps = role === Enum_Customer_Role.Master ? MASTER_STEPS : CLIENT_STEPS; + const initialStep = steps[0]; + + return { + _stepSequence: steps, + step: initialStep, + } as OrderStore; +} + +export const useOrderStore = (selector: (store: OrderStore) => T): T => { + const orderStoreContext = useContext(OrderStoreContext); + + if (!orderStoreContext) { + throw new Error(`useOrderStore must be used within OrderStoreProvider`); + } + + return useStore(orderStoreContext, selector); +}; diff --git a/apps/web/stores/order/index.tsx b/apps/web/stores/order/index.tsx index d406816..5cc2357 100644 --- a/apps/web/stores/order/index.tsx +++ b/apps/web/stores/order/index.tsx @@ -1 +1,2 @@ -export * from './store'; +export * from './context'; +export { useOrderStore } from './hooks'; diff --git a/apps/web/stores/order/store.ts b/apps/web/stores/order/store.ts index f2e16dc..88a2693 100644 --- a/apps/web/stores/order/store.ts +++ b/apps/web/stores/order/store.ts @@ -1,52 +1,37 @@ /* eslint-disable @typescript-eslint/naming-convention */ /* eslint-disable canonical/id-match */ -import { type OrderStore, type Steps } from './types'; -import { Enum_Customer_Role } from '@repo/graphql/types'; -import { create } from 'zustand'; +import { type OrderStore } from './types'; +import { createStore } from 'zustand'; -const MASTER_STEPS: Steps[] = [ - 'master-select', - 'client-select', - 'service-select', - 'datetime-select', - 'success', -]; +export function createOrderStore(initState: OrderStore) { + return createStore((set, get) => ({ + ...initState, + _stepSequence: [], + clientId: null, + date: new Date(), -const CLIENT_STEPS: Steps[] = MASTER_STEPS.filter((step) => step !== 'client-select'); + masterId: null, + nextStep: () => { + const { _stepSequence, step } = get(); + const index = _stepSequence.indexOf(step); + const next = _stepSequence[index + 1]; + if (next) set({ step: next }); + }, -export const useOrderStore = create((set, get) => ({ - _stepSequence: [], - clientId: null, - date: new Date(), - initStepSequence: (role) => { - const steps = role === Enum_Customer_Role.Master ? MASTER_STEPS : CLIENT_STEPS; - const initialStep = steps[0]; - set({ _stepSequence: steps, step: initialStep }); - }, - masterId: null, - nextStep: () => { - const { _stepSequence, step } = get(); - const index = _stepSequence.indexOf(step); - const next = _stepSequence[index + 1]; - if (next) set({ step: next }); - }, - prevStep: () => { - const { _stepSequence, step } = get(); - const index = _stepSequence.indexOf(step); - const previous = _stepSequence[index - 1]; - if (previous) set({ step: previous }); - }, - - serviceId: null, - setClientId: (id) => set({ clientId: id }), - setDate: (date) => set({ date }), - setMasterId: (id) => set({ masterId: id }), - setServiceId: (id) => set({ serviceId: id }), - setStep: (step) => set({ step }), - - setTime: (time) => set({ time }), - - step: 'master-select', - - time: null, -})); + prevStep: () => { + const { _stepSequence, step } = get(); + const index = _stepSequence.indexOf(step); + const previous = _stepSequence[index - 1]; + if (previous) set({ step: previous }); + }, + serviceId: null, + setClientId: (id) => set({ clientId: id }), + setDate: (date) => set({ date }), + setMasterId: (id) => set({ masterId: id }), + setServiceId: (id) => set({ serviceId: id }), + setStep: (step) => set({ step }), + setTime: (time) => set({ time }), + step: 'master-select', + time: null, + })); +} diff --git a/apps/web/stores/order/types.tsx b/apps/web/stores/order/types.tsx index 437787a..c311a3b 100644 --- a/apps/web/stores/order/types.tsx +++ b/apps/web/stores/order/types.tsx @@ -1,10 +1,7 @@ -import { type Enum_Customer_Role } from '@repo/graphql/types'; - export type OrderStore = { _stepSequence: Steps[]; clientId: null | string; date: Date; - initStepSequence: (role: Enum_Customer_Role | undefined) => void; masterId: null | string; nextStep: () => void; prevStep: () => void;