import { createSelector } from 'reselect'; import ModelState, { ModelStateType } from '../../models/model-state'; import { Action, MetaSliceSelectors, SetAction, SliceSetActions, SliceSelectors, SliceStateActions } from '../../types'; import createSliceAdapter from '../../adapters/create-slice-adapter'; import { getISOString } from '../../utils'; import { SetState } from 'zustand'; import { createStateActions } from '../../models/actions-state/ActionsState'; export type ModelSliceSelectors< TAppState extends object, TModel extends object, TSliceActions extends ModelSliceStateActions = ModelSliceStateActions, > = SliceSelectors, TSliceActions> & MetaSliceSelectors & { selectModel: (state: TAppState) => TModel; }; export type ModelSliceSetActions = SliceSetActions & { set: SetAction; update: SetAction; }; export type ModelSliceStateActions = SliceStateActions & { set: Action<[TModel]>; update: Action<[TModel]>; }; export type ModelSliceState = ModelSliceStateActions> = ModelStateType & { actions: TSliceActions }; export type ModelSlice< TAppState extends object, TModel extends object, TSliceActions extends ModelSliceStateActions = ModelSliceStateActions, > = { name: keyof TAppState; actions: ModelSliceSetActions; selectors: ModelSliceSelectors; state: ModelStateType; }; export const createModelSliceState = < TAppState extends object, TModel extends object, TSliceStateActions extends ModelSliceStateActions = ModelSliceStateActions, TSliceSetActions extends ModelSliceSetActions = ModelSliceSetActions, >(set: SetState, state: ModelStateType, actions: TSliceSetActions): ModelSliceState => ({ ...state, actions: createStateActions(set, actions), }); const createModelSlice = < TAppState extends object, TModel extends object, TSliceActions extends ModelSliceStateActions = ModelSliceStateActions, >(options: { name: keyof TAppState; selectSliceState: (appState: TAppState) => ModelSliceState initialState?: Partial> }): ModelSlice => { const initialState = ModelState.create(options?.initialState); const selectors = { selectSliceState: createSelector(options.selectSliceState, (model) => model), selectModel: createSelector(options.selectSliceState, (model) => model.model), selectLastModified: createSelector(options.selectSliceState, (model) => model.lastModified), selectActions: createSelector(options.selectSliceState, (model) => model.actions), }; const sliceAdapter = createSliceAdapter>(); const modifyState = (state: ModelSliceState, lastModified: string | null): ModelSliceState => { return sliceAdapter.setLastModified(state, lastModified); }; const actions: ModelSliceSetActions = { reset: (set) => () => set(state => ({ ...state, [options.name]: { actions: (state[options.name] as unknown as ModelSliceState).actions, ...initialState, }, })), update: (set) => (model) => set(state => ({ ...state, [options.name]: modifyState({ ...state[options.name] as unknown as ModelSliceState, model: model, }, getISOString()), })), set: (set) => (model) => set(state => ({ ...state, [options.name]: modifyState({ ...state[options.name] as unknown as ModelSliceState, model: model, }, getISOString()), })), }; return { name: options.name, actions: actions, selectors: selectors, state: initialState, }; }; export default createModelSlice;