'use client' import { useEffect, useState } from 'react' import { type DefaultValues, type FieldValues, type Resolver, useForm, type UseFormReturn } from 'react-hook-form' import { addToast } from '@/lib/toast' import type { ServiceResult } from '@/services/errorHandler' interface UseAdminCrudFormModalOptions { /** Present when editing; absent (undefined) when creating a new entity. */ entity: TEntity | undefined isOpen: boolean emptyValues: TFormValues toFormValues: (entity: TEntity) => TFormValues resolver: Resolver buildPayload: (values: TFormValues) => TPayload create: (payload: TPayload) => Promise> update: (id: TId, payload: TPayload) => Promise> getId: (entity: TEntity) => TId successMessage: { create: string; edit: string } onOpenChange: (isOpen: boolean) => void onSuccess: () => void } interface UseAdminCrudFormModalResult { form: UseFormReturn isEdit: boolean submitting: boolean // react-hook-form's form.handleSubmit(...) is Promise-returning, not // void — declaring void here would be a lying type that trips // @typescript-eslint/no-misused-promises at the return statement below. handleSubmit: () => Promise } /** * Owns the repeated *shape* behind the admin create/edit form modals (tags, * event categories, blog articles, …): a reset-on-open effect plus a * submitting-flag/create-or-update/toast/close/refresh submit flow. Each * modal keeps its own field set (`emptyValues`, `toFormValues`) and payload * shape (`buildPayload`) — this hook never inspects either. */ export default function useAdminCrudFormModal({ entity, isOpen, emptyValues, toFormValues, resolver, buildPayload, create, update, getId, successMessage, onOpenChange, onSuccess, }: UseAdminCrudFormModalOptions): UseAdminCrudFormModalResult { const isEdit = Boolean(entity) const [submitting, setSubmitting] = useState(false) const form = useForm({ resolver, defaultValues: (entity ? toFormValues(entity) : emptyValues) as DefaultValues, }) const { reset } = form // Modal instance is reused across opens, so form state needs an explicit // reset whenever the target entity changes or the modal re-opens. useEffect(() => { if (isOpen) { reset(entity ? toFormValues(entity) : emptyValues) } }, [entity, isOpen, reset, toFormValues, emptyValues]) const onSubmit = async (values: TFormValues) => { setSubmitting(true) const payload = buildPayload(values) const result = isEdit && entity ? await update(getId(entity), payload) : await create(payload) setSubmitting(false) if (!result.ok) return addToast({ title: isEdit ? successMessage.edit : successMessage.create, color: 'success' }) onOpenChange(false) onSuccess() } return { form, isEdit, submitting, handleSubmit: form.handleSubmit(onSubmit) } }