stores/order: split into slices
This commit is contained in:
parent
d8f853180b
commit
4160ed4540
11
apps/web/stores/lib/slices/client-slice.ts
Normal file
11
apps/web/stores/lib/slices/client-slice.ts
Normal file
@ -0,0 +1,11 @@
|
||||
import { type StateCreator } from 'zustand';
|
||||
|
||||
export type ClientSlice = {
|
||||
clientId: null | string;
|
||||
setClientId: (id: null | string) => void;
|
||||
};
|
||||
|
||||
export const createClientSlice: StateCreator<ClientSlice> = (set) => ({
|
||||
clientId: null,
|
||||
setClientId: (id) => set({ clientId: id }),
|
||||
});
|
||||
15
apps/web/stores/lib/slices/datetime-slice.ts
Normal file
15
apps/web/stores/lib/slices/datetime-slice.ts
Normal file
@ -0,0 +1,15 @@
|
||||
import { type StateCreator } from 'zustand';
|
||||
|
||||
export type DateTimeSlice = {
|
||||
date: Date;
|
||||
setDate: (date: Date) => void;
|
||||
setTime: (time: null | string) => void;
|
||||
time: null | string;
|
||||
};
|
||||
|
||||
export const createDateTimeSlice: StateCreator<DateTimeSlice> = (set) => ({
|
||||
date: new Date(),
|
||||
setDate: (date) => set({ date }),
|
||||
setTime: (time) => set({ time }),
|
||||
time: null,
|
||||
});
|
||||
6
apps/web/stores/lib/slices/index.ts
Normal file
6
apps/web/stores/lib/slices/index.ts
Normal file
@ -0,0 +1,6 @@
|
||||
export * from './client-slice';
|
||||
export * from './datetime-slice';
|
||||
export * from './master-slice';
|
||||
export * from './service-slice';
|
||||
export * from './slot-slice';
|
||||
export * from './steps-slice';
|
||||
11
apps/web/stores/lib/slices/master-slice.ts
Normal file
11
apps/web/stores/lib/slices/master-slice.ts
Normal file
@ -0,0 +1,11 @@
|
||||
import { type StateCreator } from 'zustand';
|
||||
|
||||
export type MasterSlice = {
|
||||
masterId: null | string;
|
||||
setMasterId: (id: null | string) => void;
|
||||
};
|
||||
|
||||
export const createMasterSlice: StateCreator<MasterSlice> = (set) => ({
|
||||
masterId: null,
|
||||
setMasterId: (id) => set({ masterId: id }),
|
||||
});
|
||||
11
apps/web/stores/lib/slices/service-slice.ts
Normal file
11
apps/web/stores/lib/slices/service-slice.ts
Normal file
@ -0,0 +1,11 @@
|
||||
import { type StateCreator } from 'zustand';
|
||||
|
||||
export type ServiceSlice = {
|
||||
serviceId: null | string;
|
||||
setServiceId: (id: null | string) => void;
|
||||
};
|
||||
|
||||
export const createServiceSlice: StateCreator<ServiceSlice> = (set) => ({
|
||||
serviceId: null,
|
||||
setServiceId: (id) => set({ serviceId: id }),
|
||||
});
|
||||
11
apps/web/stores/lib/slices/slot-slice.ts
Normal file
11
apps/web/stores/lib/slices/slot-slice.ts
Normal file
@ -0,0 +1,11 @@
|
||||
import { type StateCreator } from 'zustand';
|
||||
|
||||
export type SlotSlice = {
|
||||
setSlotId: (slot: null | string) => void;
|
||||
slotId: null | string;
|
||||
};
|
||||
|
||||
export const createSlotSlice: StateCreator<SlotSlice> = (set) => ({
|
||||
setSlotId: (slot) => set({ slotId: slot }),
|
||||
slotId: null,
|
||||
});
|
||||
41
apps/web/stores/lib/slices/steps-slice.ts
Normal file
41
apps/web/stores/lib/slices/steps-slice.ts
Normal file
@ -0,0 +1,41 @@
|
||||
/* eslint-disable canonical/id-match */
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
import { type StateCreator } from 'zustand';
|
||||
|
||||
export type Steps =
|
||||
| 'client-select'
|
||||
| 'datetime-select'
|
||||
| 'error'
|
||||
| 'loading'
|
||||
| 'master-select'
|
||||
| 'service-select'
|
||||
| 'success';
|
||||
|
||||
export type StepsSlice = {
|
||||
_setStepSequence: (steps: Steps[]) => void;
|
||||
_stepSequence: Steps[];
|
||||
nextStep: () => void;
|
||||
prevStep: () => void;
|
||||
setStep: (step: Steps) => void;
|
||||
step: Steps;
|
||||
};
|
||||
|
||||
export const createStepsSlice: StateCreator<StepsSlice> = (set, get) => ({
|
||||
_setStepSequence: (steps) => set({ _stepSequence: steps }),
|
||||
_stepSequence: [],
|
||||
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 });
|
||||
},
|
||||
setStep: (step) => set({ step }),
|
||||
step: 'loading',
|
||||
});
|
||||
@ -1,17 +1,7 @@
|
||||
'use client';
|
||||
|
||||
import { createOrderStore } from './store';
|
||||
import { createContext, type PropsWithChildren, useRef } from 'react';
|
||||
import { createZustandStore } from '@/utils/zustand/context';
|
||||
|
||||
export type OrderStoreApi = ReturnType<typeof createOrderStore>;
|
||||
const { Provider, useZustandStore } = createZustandStore(createOrderStore);
|
||||
|
||||
export const OrderStoreContext = createContext<OrderStoreApi | undefined>(undefined);
|
||||
|
||||
export function OrderStoreProvider({ children }: Readonly<PropsWithChildren>) {
|
||||
const storeRef = useRef<null | OrderStoreApi>(null);
|
||||
if (storeRef.current === null) {
|
||||
storeRef.current = createOrderStore();
|
||||
}
|
||||
|
||||
return <OrderStoreContext value={storeRef.current}>{children}</OrderStoreContext>;
|
||||
}
|
||||
export { Provider as OrderStoreProvider, useZustandStore as useOrderStore };
|
||||
|
||||
@ -1,22 +1,10 @@
|
||||
/* eslint-disable canonical/id-match */
|
||||
'use client';
|
||||
|
||||
import { OrderStoreContext } from './context';
|
||||
import { type OrderStore, type Steps } from './types';
|
||||
import { useOrderStore } from './context';
|
||||
import { type Steps } from './types';
|
||||
import { useCustomerQuery } from '@/hooks/api/customers';
|
||||
import { Enum_Customer_Role } from '@repo/graphql/types';
|
||||
import { useContext, useEffect } from 'react';
|
||||
import { useStore } from 'zustand';
|
||||
|
||||
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);
|
||||
};
|
||||
import { useEffect } from 'react';
|
||||
|
||||
const STEPS: Steps[] = [
|
||||
'master-select',
|
||||
|
||||
@ -1,2 +1 @@
|
||||
export * from './context';
|
||||
export { useOrderStore } from './hooks';
|
||||
|
||||
@ -1,39 +1,21 @@
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
/* eslint-disable canonical/id-match */
|
||||
import {
|
||||
createClientSlice,
|
||||
createDateTimeSlice,
|
||||
createMasterSlice,
|
||||
createServiceSlice,
|
||||
createSlotSlice,
|
||||
createStepsSlice,
|
||||
} from '../lib/slices';
|
||||
import { type OrderStore } from './types';
|
||||
import { createStore } from 'zustand';
|
||||
|
||||
export function createOrderStore() {
|
||||
return createStore<OrderStore>((set, get) => ({
|
||||
_setStepSequence: (steps) => set({ _stepSequence: steps }),
|
||||
_stepSequence: [],
|
||||
clientId: null,
|
||||
date: new Date(),
|
||||
|
||||
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 }),
|
||||
setSlotId: (id) => set({ slotId: id }),
|
||||
setStep: (step) => set({ step }),
|
||||
setTime: (time) => set({ time }),
|
||||
slotId: null,
|
||||
step: 'loading',
|
||||
time: null,
|
||||
return createStore<OrderStore>((...args) => ({
|
||||
...createClientSlice(...args),
|
||||
...createDateTimeSlice(...args),
|
||||
...createMasterSlice(...args),
|
||||
...createServiceSlice(...args),
|
||||
...createSlotSlice(...args),
|
||||
...createStepsSlice(...args),
|
||||
}));
|
||||
}
|
||||
|
||||
@ -1,29 +1,17 @@
|
||||
export type OrderStore = {
|
||||
_setStepSequence: (steps: Steps[]) => void;
|
||||
_stepSequence: Steps[];
|
||||
clientId: null | string;
|
||||
date: Date;
|
||||
masterId: null | string;
|
||||
nextStep: () => void;
|
||||
prevStep: () => void;
|
||||
serviceId: null | string;
|
||||
setClientId: (id: null | string) => void;
|
||||
setDate: (date: Date) => void;
|
||||
setMasterId: (id: null | string) => void;
|
||||
setServiceId: (id: null | string) => void;
|
||||
setSlotId: (slot: null | string) => void;
|
||||
setStep: (step: Steps) => void;
|
||||
setTime: (time: null | string) => void;
|
||||
slotId: null | string;
|
||||
step: Steps;
|
||||
time: null | string;
|
||||
};
|
||||
import {
|
||||
type ClientSlice,
|
||||
type DateTimeSlice,
|
||||
type MasterSlice,
|
||||
type ServiceSlice,
|
||||
type SlotSlice,
|
||||
type StepsSlice,
|
||||
} from '../lib/slices';
|
||||
|
||||
export type Steps =
|
||||
| 'client-select'
|
||||
| 'datetime-select'
|
||||
| 'error'
|
||||
| 'loading'
|
||||
| 'master-select'
|
||||
| 'service-select'
|
||||
| 'success';
|
||||
export type OrderStore = ClientSlice &
|
||||
DateTimeSlice &
|
||||
MasterSlice &
|
||||
ServiceSlice &
|
||||
SlotSlice &
|
||||
StepsSlice;
|
||||
|
||||
export { type Steps } from '../lib/slices';
|
||||
|
||||
29
apps/web/utils/zustand/context.tsx
Normal file
29
apps/web/utils/zustand/context.tsx
Normal file
@ -0,0 +1,29 @@
|
||||
import { createContext, type PropsWithChildren, useContext, useRef } from 'react';
|
||||
import { type StoreApi, useStore } from 'zustand';
|
||||
|
||||
export function createZustandStore<S>(createStore: () => StoreApi<S>) {
|
||||
type ZustandStoreApi = StoreApi<S>;
|
||||
|
||||
const StoreContext = createContext<undefined | ZustandStoreApi>(undefined);
|
||||
|
||||
function Provider({ children }: Readonly<PropsWithChildren>) {
|
||||
const storeRef = useRef<null | ZustandStoreApi>(null);
|
||||
if (storeRef.current === null) {
|
||||
storeRef.current = createStore();
|
||||
}
|
||||
|
||||
return <StoreContext value={storeRef.current}>{children}</StoreContext>;
|
||||
}
|
||||
|
||||
const useZustandStore = <T,>(selector: (store: S) => T): T => {
|
||||
const orderStoreContext = useContext(StoreContext);
|
||||
|
||||
if (!orderStoreContext) {
|
||||
throw new Error(`useZustandStore must be used within OrderStoreProvider`);
|
||||
}
|
||||
|
||||
return useStore(orderStoreContext, selector);
|
||||
};
|
||||
|
||||
return { Provider, useZustandStore };
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user