gitscope
← marzneshin / v0.7.1 / dashboard/src/common/hooks/use-mutation-dialog/index.ts
https://dev.kronoz.win/r/marzneshin.git
dashboard/src/common/hooks/use-mutation-dialog/index.ts · TypeScript
Blame Raw
 1import { useDialog } from "@marzneshin/common/hooks";
 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
 8export interface MutationDialogProps<TData> {
 9    entity: TData | null;
10    onClose: () => void;
11}
12
13interface IMutationDialog<TData, TError = unknown, TVariables = unknown> extends MutationDialogProps<TData> {
14    createMutation: UseMutationResult<TData, TError, TVariables>
15    updateMutation: UseMutationResult<TData, TError, TVariables>
16    schema: ZodSchema
17    defaultValue: FieldValues
18    loadFormtter?: (d: FieldValues) => FieldValues
19}
20
21/** useMutationDialog - Dialog mutation hook
22 *
23 * @param entity - Entity value for update, leave empty for creation 
24 * @param createMutation - react-query mutation hook for entity creation
25 * @param updateMutation - react-query mutation hook for entity edition
26 * @param entity - Entity value for update, leave empty for creation 
27 * @param schema - Entity schema validated by zodResolver
28 * @param onClose - Handler for when the dialog is closed
29 * @param getDefaultValue - Default value function return the default value for function
30 *  - Must be wrapped in useCallback to avoid infinite useEffect loop
31 *
32 * @returns react-hook-form and submit handler plus the dialog open state
33 *
34 * @template TData - Mutation Type of Schema
35 * @template TError = unknown 
36 * @template TVariables = unknown
37 */
38
39export const useMutationDialog = <TData, TError = unknown, TVariables = unknown>({
40    onClose,
41    entity,
42    createMutation,
43    updateMutation,
44    schema,
45    defaultValue,
46    loadFormtter = (s) => s,
47}: IMutationDialog<TData, TError, TVariables>) => {
48    const [open, onOpenChange] = useDialog(true);
49
50    const form = useForm({
51        defaultValues: entity ? loadFormtter(entity) : defaultValue,
52        resolver: zodResolver(schema)
53    });
54
55    const submit: SubmitHandler<FieldValues> = async (values) => {
56        if (entity) {
57            updateMutation.mutate(values as TVariables);
58        } else {
59            createMutation.mutate(values as TVariables);
60        }
61        onOpenChange(false);
62    };
63
64    useEffect(() => {
65        if (entity) {
66            form.reset(loadFormtter(entity))
67        } else {
68            form.reset(defaultValue);
69        }
70        // eslint-disable-next-line
71    }, [entity, defaultValue]);
72
73    useEffect(() => {
74        if (!open) onClose();
75    }, [open, onClose]);
76
77    const handleSubmit = form.handleSubmit(submit as SubmitHandler<FieldValues>);
78
79    return {
80        form,
81        open, onOpenChange,
82        handleSubmit
83    };
84};