pass order store via context

This commit is contained in:
vchikalkin 2025-04-30 18:58:46 +03:00
parent e6f2e6ccaf
commit 7e886172f2
6 changed files with 97 additions and 62 deletions

View File

@ -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<string, JSX.Element> = {
'client-select': <ClientsGrid />,
@ -18,14 +18,8 @@ const STEP_COMPONENTS: Record<string, JSX.Element> = {
'service-select': <ServiceSelect />,
};
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 (
<div className="space-y-4 [&>*]:px-4">
@ -36,7 +30,7 @@ export function OrderForm() {
</div>
</div>
);
}
});
function getStepComponent(step: string) {
return STEP_COMPONENTS[step] ?? null;

View File

@ -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<typeof createOrderStore>;
export const OrderStoreContext = createContext<OrderStoreApi | undefined>(undefined);
export function OrderStoreProvider({ children }: Readonly<PropsWithChildren>) {
const storeRef = useRef<null | OrderStoreApi>(null);
const initialState = useInitialState();
if (storeRef.current === null) {
storeRef.current = createOrderStore(initialState);
}
return <OrderStoreContext value={storeRef.current}>{children}</OrderStoreContext>;
}

View File

@ -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 = <T,>(selector: (store: OrderStore) => T): T => {
const orderStoreContext = useContext(OrderStoreContext);
if (!orderStoreContext) {
throw new Error(`useOrderStore must be used within OrderStoreProvider`);
}
return useStore(orderStoreContext, selector);
};

View File

@ -1 +1,2 @@
export * from './store';
export * from './context';
export { useOrderStore } from './hooks';

View File

@ -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<OrderStore>((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<OrderStore>((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,
}));
}

View File

@ -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;