refactor(former): 🔄 restructure form components and stores
* Remove unused FormLayout and SuperForm stores. * Consolidate form logic into Former component. * Implement new Former layout and types. * Update stories for new Former component. * Clean up unused styles and types across the project.
This commit is contained in:
188
src/Former/Former.store.tsx
Normal file
188
src/Former/Former.store.tsx
Normal file
@@ -0,0 +1,188 @@
|
||||
import { createSyncStore } from '@warkypublic/zustandsyncstore';
|
||||
import { produce } from 'immer';
|
||||
|
||||
import type { FormerProps, FormerState } from './Former.types';
|
||||
|
||||
const { Provider: FormerProvider, useStore: useFormerStore } = createSyncStore<
|
||||
FormerState<any> & Partial<FormerProps<any>>,
|
||||
FormerProps<any>
|
||||
>(
|
||||
(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<object, any, any> | 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<void>((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 }) => {
|
||||
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 },
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
export { FormerProvider };
|
||||
export { useFormerStore };
|
||||
Reference in New Issue
Block a user