import React, { Dispatch, SetStateAction } from "react"; import { QueryObserverResult } from "react-query"; import { FormInstance, FormProps } from "antd"; import { useResourceWithRoute, useRouterContext } from "@hooks"; import { useCreateForm, useCreateFormProps } from "./useCreateForm"; import { useEditForm, useEditFormProps } from "./useEditForm"; import { useCloneForm, useCloneFormProps } from "./useCloneForm"; import { ButtonProps } from "../../components/antd"; import { BaseRecord, GetOneResponse, HttpError, LiveModeProps, ResourceRouterParams, } from "../../interfaces"; import { UseUpdateReturnType } from "../data/useUpdate"; import { UseCreateReturnType } from "../data/useCreate"; export type ActionParams = { action?: "edit" | "create" | "clone"; }; type ActionFormProps< TData extends BaseRecord = BaseRecord, TError extends HttpError = HttpError, TVariables = {}, > = useCreateFormProps & useEditFormProps & useCloneFormProps; type ResourcelessActionFormProps< TData extends BaseRecord = BaseRecord, TError extends HttpError = HttpError, TVariables = {}, > = Omit, "resource">; export type useFormProps< TData extends BaseRecord = BaseRecord, TError extends HttpError = HttpError, TVariables = {}, > = ActionParams & { resource?: string; } & ResourcelessActionFormProps & LiveModeProps; export type UseFormReturnType< TData extends BaseRecord = BaseRecord, TError extends HttpError = HttpError, TVariables = {}, > = { form: FormInstance; formProps: FormProps; editId?: string; setEditId?: Dispatch>; saveButtonProps: ButtonProps & { onClick: () => void; }; queryResult?: QueryObserverResult>; mutationResult: | UseUpdateReturnType | UseCreateReturnType; formLoading: boolean; setCloneId?: Dispatch>; cloneId?: string; }; /** * `useForm` is used to manage forms. It uses Ant Design {@link https://ant.design/components/form/ Form} data scope management under the hood and returns the required props for managing the form actions. * * @see {@link https://refine.dev/docs/api-references/hooks/form/useForm} for more details. * * @typeParam TData - Result data of the query extends {@link https://refine.dev/docs/api-references/interfaceReferences#baserecord `BaseRecord`} * @typeParam TError - Custom error object that extends {@link https://refine.dev/docs/api-references/interfaceReferences#httperror `HttpError`} * @typeParam TVariables - Values for params. default `{}` * * */ export const useForm = < TData extends BaseRecord = BaseRecord, TError extends HttpError = HttpError, TVariables = {}, >({ action: actionFromProps, resource: resourceFromProps, ...rest }: useFormProps = {}): UseFormReturnType< TData, TError, TVariables > => { // id state is needed to determine selected record in addition to id parameter from route // this could be moved to a custom hook that encapsulates both create and clone form hooks. const [cloneId, setCloneId] = React.useState(); const resourceWithRoute = useResourceWithRoute(); const { useParams } = useRouterContext(); const { resource: resourceFromParams, action: actionFromRoute, id, } = useParams(); const resourceType = resourceFromProps ?? resourceFromParams; const action = actionFromProps ?? actionFromRoute; const resource = resourceWithRoute(resourceType); const editForm = useEditForm({ ...rest, resource, action, } as useEditFormProps); const createForm = useCreateForm({ ...rest, resource, action, } as useCreateFormProps); const cloneForm = useCloneForm({ ...rest, resource, cloneId, action, } as useCloneFormProps); switch (action) { case "create": return { ...createForm }; case "edit": return editForm; case "clone": // setCloneId and cloneId needs to be returned from both clone and create cases. // It is needed to make them accessible in useModalForm to be able to manage id state. return { ...cloneForm, setCloneId, cloneId }; default: return createForm; } };