I currently have a service listing screen in reactjs that renders two modals with different triggers. I had asked a previous question here on the platform, but someone else helped me solve it. You can take a look at this link: [/questions/78425045/modal-doesnt-close-on-submission/78425265?noredirect=1#comment138283654_78425265]
I used the solution for a large part of my code, but when I went to use the same logic in this part of my code, I had a typing problem when passing the “form” prop to my new service modal:
import { Book, BookOpenCheck } from 'lucide-react'
import { Button } from '@/components/ui/button'
import { Dialog, DialogTrigger } from '@/components/ui/dialog'
import { NewAttendance } from './modals/new-attendance'
import { useNewAttendanceController } from './modals/new-attendance/use-new-attendance-controller'
import { NewMedicalRecords } from './modals/new-medical-records'
import { useNewMedicalRecords } from './modals/new-medical-records/use-new-medical-records-controller'
export function ListOfServices() {
const {
form: formNewMedicalRecords,
onSubmit: onSubmitNewMedicalRecords,
isPending: isPendingNewMedicalRecords,
isNewMedicalRecords,
setIsNewMedicalRecords,
} = useNewMedicalRecords()
const {
form: formNewAttendance,
onSubmit: onSubmitNewAttendance,
isPending: isPendingNewAttendance,
isNewAttendanceModalOpen,
setIsNewAttendanceModalOpen,
} = useNewAttendanceController()
return (
<div className="flex justify-between items-center">
<div className="flex items-center gap-3 w-full">
<Dialog
open={isNewMedicalRecords}
onOpenChange={setIsNewMedicalRecords}
>
<DialogTrigger asChild>
<Button variant="outline" size="xs">
<span>Registrar Prontuário</span>
<BookOpenCheck className="ml-2 w-4 h-4" />
</Button>
</DialogTrigger>
<NewMedicalRecords
form={formNewMedicalRecords}
onSubmit={onSubmitNewMedicalRecords}
isPending={isPendingNewMedicalRecords}
/>
</Dialog>
<Dialog
open={isNewAttendanceModalOpen}
onOpenChange={setIsNewAttendanceModalOpen}
>
<DialogTrigger asChild>
<Button variant="outline" size="xs">
<span>Registrar Atendimento</span>
<Book className="ml-2 w-4 h-4" />
</Button>
</DialogTrigger>
<NewAttendance
form={formNewAttendance}
onSubmit={onSubmitNewAttendance}
isPending={isPendingNewAttendance}
/>
</Dialog>
</div>
</div>
)
}
I’m using the z.input and z.output methods in zod, because initially I have a property that receives a Date and returns it to the API as a string. This is my schema and all the logic of my new service controller:
import { zodResolver } from '@hookform/resolvers/zod'
import { useMutation, useQueryClient } from '@tanstack/react-query'
import { addDays } from 'date-fns'
import { useState } from 'react'
import { useForm } from 'react-hook-form'
import toast from 'react-hot-toast'
import { z } from 'zod'
import attendanceService from '@/services/attendanceService'
export const newAttendanceSchema = z.object({
clientHashId: z.string({ required_error: 'ID do Cliente é obrigatório' }),
employeeHashId: z.string({
required_error: 'ID do Funcionário é obrigatório',
}),
serviceDate: z
.date()
.transform((date) => new Intl.DateTimeFormat().format(date)),
serviceHour: z.string().transform((time) => time.concat(':00')),
})
export type NewAttendanceOutputSchema = z.output<typeof newAttendanceSchema>
export type NewAttendanceInputSchema = z.input<typeof newAttendanceSchema>
export function useNewAttendanceController() {
const [isNewAttendanceModalOpen, setIsNewAttendanceModalOpen] =
useState(false)
const openNewAttendanceModal = () => {
setIsNewAttendanceModalOpen(true)
}
const closeNewAttendanceModal = () => {
setIsNewAttendanceModalOpen(false)
}
const queryClient = useQueryClient()
const { mutateAsync, isPending } = useMutation({
mutationFn: attendanceService.registerService,
onSuccess: () => {
queryClient.invalidateQueries({
queryKey: ['get-attendances'],
})
},
})
const form = useForm<
NewAttendanceInputSchema,
null,
NewAttendanceOutputSchema
>({
resolver: zodResolver(newAttendanceSchema),
defaultValues: {
clientHashId: '',
employeeHashId: '',
serviceDate: addDays(new Date(), 1),
serviceHour: '',
},
})
async function onSubmit(data: NewAttendanceOutputSchema) {
try {
await mutateAsync({
clientHashId: data.clientHashId,
employeeHashId: data.employeeHashId,
serviceDate: data.serviceDate,
serviceHour: data.serviceHour,
})
toast.success('Agendamento cadastrado com sucesso!')
closeNewAttendanceModal()
} catch (error) {
toast.error('Erro ao enviar a requisição')
form.reset({
clientHashId: '',
employeeHashId: '',
serviceDate: addDays(new Date(), 1),
serviceHour: '',
})
}
}
return {
form,
onSubmit,
isPending,
isNewAttendanceModalOpen,
setIsNewAttendanceModalOpen,
openNewAttendanceModal,
closeNewAttendanceModal,
}
}
The error I get is when I give the “form” property to my component:
The type 'UseFormReturn<{ clientHashId: string; employeeHashId: string; serviceDate: Date; serviceHour: string; }, null, { clientHashId: string; employeeHashId: string; serviceDate: string; serviceHour: string; }>' cannot be assigned to the type 'UseFormReturn<{ clientHashId: string; employeeHashId: string; serviceDate: string; serviceHour: string; }>'.
The types returned by 'watch()' are incompatible between these types.
The type '{ clientHashId: string; employeeHashId: string; serviceDate: Date; serviceHour: string; }' cannot be assigned to the type '{ clientHashId: string; employeeHashId: string; serviceDate: string; serviceHour: string; }'.