packages/core/src/hooks/form/types.ts
import { Dispatch, SetStateAction } from "react";
import { QueryObserverResult, UseQueryOptions } from "@tanstack/react-query";
import {
OptimisticUpdateMapType,
UseUpdateProps,
UseUpdateReturnType,
} from "../data/useUpdate";
import { UseCreateProps, UseCreateReturnType } from "../data/useCreate";
import {
UseLoadingOvertimeOptionsProps,
UseLoadingOvertimeReturnType,
} from "../useLoadingOvertime";
import {
BaseKey,
BaseRecord,
CreateResponse,
GetOneResponse,
HttpError,
IQueryKeys,
MetaQuery,
MutationMode,
UpdateResponse,
} from "../../contexts/data/types";
import { LiveModeProps } from "../../contexts/live/types";
import { SuccessErrorNotification } from "../../contexts/notification/types";
import { Action } from "../../contexts/router/types";
export type FormAction = Extract<Action, "create" | "edit" | "clone">;
export type RedirectAction =
| Extract<Action, "create" | "edit" | "list" | "show">
| false;
/**
* @deprecated use RedirectAction type instead
*/
export type RedirectionTypes = RedirectAction;
export type AutoSaveProps<TVariables> = {
autoSave?: {
enabled: boolean;
debounce?: number;
onFinish?: (values: TVariables) => TVariables;
invalidateOnUnmount?: boolean;
invalidateOnClose?: boolean;
};
};
export type AutoSaveReturnType<
TData extends BaseRecord = BaseRecord,
TError extends HttpError = HttpError,
TVariables = {},
> = {
autoSaveProps: Pick<
UseUpdateReturnType<TData, TError, TVariables>,
"data" | "error" | "status"
>;
onFinishAutoSave: (
values: TVariables,
) => Promise<UpdateResponse<TData> | void>;
};
export type AutoSaveIndicatorElements = Partial<
Record<"success" | "error" | "loading" | "idle", React.ReactNode>
>;
export type ActionParams = {
/**
* Type of the form mode
* @default Action that it reads from route otherwise "create" is used
*/
action?: FormAction;
};
type ActionFormProps<
TQueryFnData extends BaseRecord = BaseRecord,
TError extends HttpError = HttpError,
TVariables = {},
TData extends BaseRecord = TQueryFnData,
TResponse extends BaseRecord = TData,
TResponseError extends HttpError = TError,
> = {
/**
* Resource name for API data interactions
* @default Resource name that it reads from route
*/
resource?: string;
/**
* Record id for fetching
* @default Id that it reads from the URL
*/
id?: BaseKey;
/**
* Page to redirect after a succesfull mutation
* @type `"show" | "edit" | "list" | "create" | false`
* @default `"list"`
*/
redirect?: RedirectAction;
/**
* Metadata query for dataProvider
*/
meta?: MetaQuery;
/**
* Metadata query for dataProvider
* @deprecated `metaData` is deprecated with refine@4, refine will pass `meta` instead, however, we still support `metaData` for backward compatibility.
*/
metaData?: MetaQuery;
/**
* Metadata to pass for the `useOne` query
*/
queryMeta?: MetaQuery;
/**
* Metadata to pass for the mutation (`useCreate` for `create` and `clone` actions, `useUpdate` for `edit` action)
*/
mutationMeta?: MetaQuery;
/**
* [Determines when mutations are executed](/advanced-tutorials/mutation-mode.md)
* @default `"pessimistic"*`
*/
mutationMode?: MutationMode;
/**
* Called when a mutation is successful
*/
onMutationSuccess?: (
data: CreateResponse<TResponse> | UpdateResponse<TResponse>,
variables: TVariables,
context: any,
isAutoSave?: boolean,
) => void;
/**
* Called when a mutation encounters an error
*/
onMutationError?: (
error: TResponseError,
variables: TVariables,
context: any,
isAutoSave?: boolean,
) => void;
/**
* Duration to wait before executing mutations when `mutationMode = "undoable"`
* @default `5000*`
*/
undoableTimeout?: number;
/**
* If there is more than one `dataProvider`, you should use the `dataProviderName` that you will use.
*/
dataProviderName?: string;
/**
* You can use it to manage the invalidations that will occur at the end of the mutation.
* @type `all`, `resourceAll`, `list`, `many`, `detail`, `false`
* @default `["list", "many", "detail"]`
*/
invalidates?: Array<keyof IQueryKeys>;
/**
* react-query's [useQuery](https://tanstack.com/query/v4/docs/reference/useQuery) options of useOne hook used while in edit mode.
*/
queryOptions?: UseQueryOptions<
GetOneResponse<TQueryFnData>,
TError,
GetOneResponse<TData>
>;
/**
* react-query's [useMutation](https://tanstack.com/query/v4/docs/reference/useMutation) options of useCreate hook used while submitting in create and clone modes.
*/
createMutationOptions?: UseCreateProps<
TResponse,
TResponseError,
TVariables
>["mutationOptions"];
/**
* react-query's [useMutation](https://tanstack.com/query/v4/docs/reference/useMutation) options of useUpdate hook used while submitting in edit mode.
*/
updateMutationOptions?: UseUpdateProps<
TResponse,
TResponseError,
TVariables
>["mutationOptions"];
/**
* If you customize the [`optimisticUpdateMap`](https://refine.dev/docs/api-reference/core/hooks/data/useUpdateMany/#optimisticupdatemap) option, you can use it to manage the invalidations that will occur at the end of the mutation.
* @default {
* list: true,
* many: true,
* detail: true,
* }
*/
optimisticUpdateMap?: OptimisticUpdateMapType<TResponse, TVariables>;
} & SuccessErrorNotification<
UpdateResponse<TResponse> | CreateResponse<TResponse>,
TResponseError,
{ id: BaseKey; values: TVariables } | TVariables
> &
ActionParams &
LiveModeProps;
export type UseFormProps<
TQueryFnData extends BaseRecord = BaseRecord,
TError extends HttpError = HttpError,
TVariables = {},
TData extends BaseRecord = TQueryFnData,
TResponse extends BaseRecord = TData,
TResponseError extends HttpError = TError,
> = ActionFormProps<
TQueryFnData,
TError,
TVariables,
TData,
TResponse,
TResponseError
> &
ActionParams &
LiveModeProps &
UseLoadingOvertimeOptionsProps &
AutoSaveProps<TVariables>;
export type UseFormReturnType<
TQueryFnData extends BaseRecord = BaseRecord,
TError extends HttpError = HttpError,
TVariables = {},
TData extends BaseRecord = TQueryFnData,
TResponse extends BaseRecord = TData,
TResponseError extends HttpError = TError,
> = {
id?: BaseKey;
setId: Dispatch<SetStateAction<BaseKey | undefined>>;
queryResult?: QueryObserverResult<GetOneResponse<TData>, TError>;
mutationResult:
| UseUpdateReturnType<TResponse, TResponseError, TVariables>
| UseCreateReturnType<TResponse, TResponseError, TVariables>;
formLoading: boolean;
onFinish: (
values: TVariables,
) => Promise<CreateResponse<TResponse> | UpdateResponse<TResponse> | void>;
redirect: (
redirect: RedirectAction,
idFromFunction?: BaseKey | undefined,
routeParams?: Record<string, string | number>,
) => void;
} & UseLoadingOvertimeReturnType &
AutoSaveReturnType<TResponse, TResponseError, TVariables>;
export type FormWithSyncWithLocationParams = {
/**
* If true, the form will be synced with the location.
* If an object is passed, the key property will be used as the key for the query params.
* By default, query params are placed under the key, `${resource.name}-${action}`.
*/
syncWithLocation?: boolean | { key?: string; syncId?: boolean };
};