mirror of
https://github.com/usual2970/certimate.git
synced 2025-06-09 05:59:50 +00:00
107 lines
2.8 KiB
TypeScript
107 lines
2.8 KiB
TypeScript
import { useState } from "react";
|
|
import { useDeepCompareEffect } from "ahooks";
|
|
import { Form, type FormInstance, type FormProps } from "antd";
|
|
|
|
export interface UseAntdFormOptions<T extends NonNullable<unknown> = any> {
|
|
form?: FormInstance<T>;
|
|
initialValues?: Partial<T> | (() => Partial<T> | Promise<Partial<T>>);
|
|
onSubmit?: (values: T) => unknown;
|
|
}
|
|
|
|
export interface UseAntdFormReturns<T extends NonNullable<unknown> = any> {
|
|
form: FormInstance<T>;
|
|
formProps: Omit<FormProps<T>, "children">;
|
|
formPending: boolean;
|
|
submit: (values?: T) => Promise<unknown>;
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param {UseAntdFormOptions} options
|
|
* @returns {UseAntdFormReturns}
|
|
*/
|
|
const useAntdForm = <T extends NonNullable<unknown> = any>({ initialValues, form, onSubmit }: UseAntdFormOptions<T>): UseAntdFormReturns<T> => {
|
|
const formInst = form ?? Form["useForm"]()[0];
|
|
const [formInitialValues, setFormInitialValues] = useState<Partial<T>>();
|
|
const [formPending, setFormPending] = useState(false);
|
|
|
|
useDeepCompareEffect(() => {
|
|
let unmounted = false;
|
|
|
|
if (!initialValues) {
|
|
return;
|
|
}
|
|
|
|
let temp: Promise<Partial<T>>;
|
|
if (typeof initialValues === "function") {
|
|
temp = Promise.resolve(initialValues());
|
|
} else {
|
|
temp = Promise.resolve(initialValues);
|
|
}
|
|
|
|
temp.then((temp) => {
|
|
if (!unmounted) {
|
|
type FieldName = Parameters<FormInstance<T>["getFieldValue"]>[0];
|
|
type FieldsValue = Parameters<FormInstance<T>["setFieldsValue"]>[0];
|
|
|
|
const obj = { ...temp };
|
|
Object.keys(temp).forEach((key) => {
|
|
obj[key as keyof T] = formInst!.isFieldTouched(key as FieldName) ? formInst!.getFieldValue(key as FieldName) : temp[key as keyof T];
|
|
});
|
|
|
|
setFormInitialValues(temp);
|
|
formInst!.setFieldsValue(obj as FieldsValue);
|
|
}
|
|
});
|
|
|
|
return () => {
|
|
unmounted = true;
|
|
};
|
|
}, [formInst, initialValues]);
|
|
|
|
const onFinish = (values: T) => {
|
|
if (formPending) return Promise.reject(new Error("Form is pending"));
|
|
|
|
setFormPending(true);
|
|
|
|
return new Promise((resolve, reject) => {
|
|
formInst
|
|
.validateFields()
|
|
.then(() => {
|
|
resolve(
|
|
Promise.resolve(onSubmit?.(values))
|
|
.then((data) => {
|
|
setFormPending(false);
|
|
return data;
|
|
})
|
|
.catch((err) => {
|
|
setFormPending(false);
|
|
throw err;
|
|
})
|
|
);
|
|
})
|
|
.catch((err) => {
|
|
setFormPending(false);
|
|
reject(err);
|
|
});
|
|
});
|
|
};
|
|
|
|
const formProps: FormProps = {
|
|
form: formInst,
|
|
initialValues: formInitialValues,
|
|
onFinish,
|
|
};
|
|
|
|
return {
|
|
form: formInst,
|
|
formProps: formProps,
|
|
formPending: formPending,
|
|
submit: () => {
|
|
return onFinish(formInst.getFieldsValue(true));
|
|
},
|
|
};
|
|
};
|
|
|
|
export default useAntdForm;
|