62 lines
1.9 KiB
TypeScript
62 lines
1.9 KiB
TypeScript
"use client"
|
|
|
|
import { useEffect } from "react"
|
|
import { useForm, type DefaultValues, type FieldValues, type UseFormReturn } from "react-hook-form"
|
|
import { zodResolver } from "@hookform/resolvers/zod"
|
|
import { useQuery, type QueryKey } from "@tanstack/react-query"
|
|
import type { ZodType } from "zod"
|
|
|
|
type UseResourceFormOptions<TFormValues extends FieldValues, TApiData = unknown> = {
|
|
schema: ZodType<TFormValues, any, any>
|
|
defaultValues: DefaultValues<TFormValues>
|
|
resourceId?: string | null
|
|
initialize?: (id: string) => Promise<TApiData>
|
|
mapToFormValues: (data: TApiData) => TFormValues
|
|
initialData?: TApiData | null
|
|
queryKey?: QueryKey
|
|
}
|
|
|
|
type UseResourceFormReturn<TFormValues extends FieldValues> = {
|
|
form: UseFormReturn<TFormValues>
|
|
isEditing: boolean
|
|
isInitializing: boolean
|
|
}
|
|
|
|
export function useResourceForm<TFormValues extends FieldValues, TApiData = unknown>({
|
|
schema,
|
|
defaultValues,
|
|
resourceId,
|
|
initialize,
|
|
mapToFormValues,
|
|
initialData,
|
|
queryKey,
|
|
}: UseResourceFormOptions<TFormValues, TApiData>): UseResourceFormReturn<TFormValues> {
|
|
const isEditing = !!resourceId
|
|
|
|
const { data: queriedData, isLoading: isQueryLoading } = useQuery<TApiData>({
|
|
queryKey: queryKey ?? ["resource", resourceId],
|
|
queryFn: () => initialize!(resourceId!),
|
|
enabled: isEditing && !!initialize,
|
|
})
|
|
|
|
const resolvedData = queriedData ?? (isEditing ? initialData : undefined)
|
|
|
|
const form = useForm<TFormValues>({
|
|
resolver: zodResolver(schema) as any,
|
|
defaultValues,
|
|
})
|
|
|
|
useEffect(() => {
|
|
if (!isEditing) {
|
|
form.reset(defaultValues)
|
|
return
|
|
}
|
|
|
|
if (resolvedData) {
|
|
form.reset(mapToFormValues(resolvedData) as any)
|
|
}
|
|
}, [isEditing, resolvedData]) // eslint-disable-line react-hooks/exhaustive-deps
|
|
|
|
return { form, isEditing, isInitializing: isEditing && !!initialize && isQueryLoading }
|
|
}
|