1
2import { zodResolver } from "@hookform/resolvers/zod";
3import { UseMutationResult } from "@tanstack/react-query";
4import { useEffect } from "react";
5import { FieldValues, SubmitHandler, useForm } from "react-hook-form";
6import { ZodSchema } from "zod";
7
8interface IMutationDialog<TData, TError = unknown, TVariables = unknown> {
9 entity: TData | null
10 onOpenChange: (s: boolean) => void
11 createMutation: UseMutationResult<TData, TError, TVariables>
12 updateMutation: UseMutationResult<TData, TError, TVariables>
13 schema: ZodSchema
14 getDefaultValue: () => FieldValues
15}
16
17/** useMutationDialog - Dialog mutation hook
18 *
19 * @param entity - Entity value for update, leave empty for creation
20 * @param createMutation - react-query mutation hook for entity creation
21 * @param updateMutation - react-query mutation hook for entity edition
22 * @param entity - Entity value for update, leave empty for creation
23 * @param schema - Entity schema validated by zodResolver
24 * @param getDefaultValue - Default value function return the default value for function
25 * - Must be wrapped in useCallback to avoid infinite useEffect loop
26 * @param onOpenChange - Dialog state callback to change the dialog openness state
27 *
28 * @returns react-hook-form and submit handler
29 *
30 * @template TData - Mutation Type of Schema
31 * @template TError = unknown
32 * @template TVariables = unknown
33 */
34
35export const useMutationDialog = <TData, TError = unknown, TVariables = unknown>({
36 entity,
37 onOpenChange,
38 createMutation,
39 updateMutation,
40 schema,
41 getDefaultValue,
42}: IMutationDialog<TData, TError, TVariables>) => {
43 const form = useForm({
44 defaultValues: entity ? (entity as FieldValues) : (getDefaultValue()),
45 resolver: zodResolver(schema)
46 });
47
48 const submit: SubmitHandler<FieldValues> = async (values) => {
49 if (entity) {
50 updateMutation.mutate(values as TVariables);
51 } else {
52 createMutation.mutate(values as TVariables);
53 }
54 onOpenChange(false);
55 };
56
57 useEffect(() => {
58 if (entity) {
59 form.reset(entity)
60 } else {
61 form.reset(getDefaultValue());
62 }
63 }, [entity, form, getDefaultValue]);
64
65 const handleSubmit = form.handleSubmit(submit as SubmitHandler<FieldValues>);
66
67 return {
68 form,
69 handleSubmit
70 };
71};