import { createSyncStore } from '@warkypublic/zustandsyncstore'; import { produce } from 'immer'; import type { FormerProps, FormerState } from './Former.types'; import { newUUID } from '@warkypublic/artemis-kit'; const { Provider: FormerProvider, useStore: useFormerStore } = createSyncStore< FormerState & Partial>, FormerProps >( (set, get) => ({ getState: (key) => { const current = get(); return current?.[key]; }, load: async (reset?: boolean) => { try { set({ loading: true }); const keyName = get()?.apiKeyField || 'id'; const keyValue = (get().values as any)?.[keyName] ?? (get().primeData as any)?.[keyName]; if (get().onAPICall && keyValue !== undefined) { let data = await get().onAPICall!( 'read', get().request || 'insert', get().values, keyValue ); if (get().afterGet) { data = await get().afterGet!({ ...data }); } set({ loading: false, values: data }); get().onChange?.(data); } if (reset && get().getFormMethods) { const formMethods = get().getFormMethods!(); formMethods.reset(); } } catch (e) { set({ error: (e as Error)?.message ?? e, loading: false }); } set({ loading: false }); }, onChange: (values) => { set({ values }); }, request: 'insert', reset: async () => { const state = get(); if (state.getFormMethods) { if (state.request !== 'insert') { await state.load(true); } const formMethods = state.getFormMethods!(); formMethods.reset({ ...state.values, ...state.primeData }); } }, save: async (e?: React.BaseSyntheticEvent | undefined) => { try { const keepOpen = get().keepOpen ?? false; set({ loading: true }); if (get().getFormMethods) { const formMethods = get().getFormMethods!(); let data = formMethods.getValues(); if (get().beforeSave) { const newData = await get().beforeSave!(data); data = newData; } let exit = false; const handler = formMethods.handleSubmit( (newdata) => { data = newdata; }, (errors) => { set({ error: errors.root?.message || 'Validation errors', loading: false }); exit = true; } ); await handler(e); //console.log('Former.store.tsx save called', success, e, data, get().getFormMethods); if (exit) { set({ loading: false }); return undefined; } if (get().request === 'delete' && !get().deleteConfirmed) { const confirmed = (await get().onConfirmDelete?.(data)) ?? false; if (!confirmed) { set({ loading: false }); return undefined; } } if (get().onAPICall) { const keyName = get()?.apiKeyField || 'id'; const keyValue = (get().values as any)?.[keyName] ?? (get().primeData as any)?.[keyName]; const savedData = await get().onAPICall!( 'mutate', get().request || 'insert', data, keyValue ); if (get().afterSave) { await get().afterSave!(savedData); } set({ loading: false, values: savedData }); get().onChange?.(savedData); if (!keepOpen) { get().onClose?.(savedData); } return savedData; } set({ loading: false, values: data }); get().onChange?.(data); if (!keepOpen) { get().onClose?.(data); } return data; } } catch (e) { set({ error: (e as Error)?.message ?? e, loading: false }); } return undefined; }, setRequest: (request) => { set({ request }); }, setState: (key, value) => { set( produce((state) => { state[key] = value; }) ); }, setStateFN: (key, value) => { const p = new Promise((resolve, reject) => { set( produce((state) => { if (typeof value === 'function') { state[key] = (value as (value: unknown) => unknown)(state[key]); } else { reject(new Error(`Not a function ${value}`)); throw Error(`Not a function ${value}`); } }) ); resolve(); }); return p; }, validate: async () => { if (get().getFormMethods) { const formMethods = get().getFormMethods!(); const isValid = await formMethods.trigger(); return isValid; } return true; }, values: undefined, }), ({ onConfirmDelete, primeData, request, values, id }) => { let _onConfirmDelete = onConfirmDelete; if (!onConfirmDelete) { _onConfirmDelete = async () => { return confirm('Are you sure you want to delete this item?'); }; } return { onConfirmDelete: _onConfirmDelete, primeData, request: request || 'insert', values: { ...primeData, ...values }, id: !id ? newUUID() : id, }; } ); export { FormerProvider }; export { useFormerStore };