import React, { useEffect } from "react"; import { useRouter } from "next/router"; import { useForm } from "react-hook-form"; import { mutate } from "swr"; // services import estimatesService from "services/estimates.service"; // headless ui import { Dialog, Transition } from "@headlessui/react"; // hooks import useToast from "hooks/use-toast"; // ui import { Input, PrimaryButton, SecondaryButton } from "components/ui"; // types import type { IEstimate, IEstimatePoint } from "types"; // fetch-keys import { ESTIMATE_POINTS_LIST } from "constants/fetch-keys"; type Props = { isOpen: boolean; data?: IEstimatePoint[]; estimate: IEstimate | null; onClose: () => void; }; interface FormValues { value1: string; value2: string; value3: string; value4: string; value5: string; value6: string; } const defaultValues: FormValues = { value1: "", value2: "", value3: "", value4: "", value5: "", value6: "", }; export const EstimatePointsModal: React.FC<Props> = ({ isOpen, data, estimate, onClose }) => { const router = useRouter(); const { workspaceSlug, projectId } = router.query; const { setToastAlert } = useToast(); const { register, formState: { isSubmitting }, handleSubmit, reset, } = useForm<FormValues>({ defaultValues }); const handleClose = () => { onClose(); reset(); }; const createEstimatePoints = async (formData: FormValues) => { if (!workspaceSlug || !projectId) return; const payload = { estimate_points: [ { key: 0, value: formData.value1, }, { key: 1, value: formData.value2, }, { key: 2, value: formData.value3, }, { key: 3, value: formData.value4, }, { key: 4, value: formData.value5, }, { key: 5, value: formData.value6, }, ], }; await estimatesService .createEstimatePoints( workspaceSlug as string, projectId as string, estimate?.id as string, payload ) .then(() => { handleClose(); }) .catch(() => { setToastAlert({ type: "error", title: "Error!", message: "Estimate points could not be created. Please try again.", }); }); }; const updateEstimatePoints = async (formData: FormValues) => { if (!workspaceSlug || !projectId || !data || data.length === 0) return; const payload = { estimate_points: data.map((d, index) => ({ id: d.id, value: (formData as any)[`value${index + 1}`], })), }; await estimatesService .patchEstimatePoints( workspaceSlug as string, projectId as string, estimate?.id as string, payload ) .then(() => { handleClose(); }) .catch(() => { setToastAlert({ type: "error", title: "Error!", message: "Estimate points could not be created. Please try again.", }); }); }; const onSubmit = async (formData: FormValues) => { let c = 0; Object.keys(formData).map((key) => { if (formData[key as keyof FormValues] === "") c++; }); if (c !== 0) { setToastAlert({ type: "error", title: "Error!", message: "Please fill all the fields.", }); return; } if (data && data.length !== 0) await updateEstimatePoints(formData); else await createEstimatePoints(formData); if (estimate) mutate(ESTIMATE_POINTS_LIST(estimate.id)); }; useEffect(() => { if (!data || data.length < 6) return; reset({ ...defaultValues, value1: data[0].value, value2: data[1].value, value3: data[2].value, value4: data[3].value, value5: data[4].value, value6: data[5].value, }); }, [data, reset]); return ( <Transition.Root show={isOpen} as={React.Fragment}> <Dialog as="div" className="relative z-20" onClose={() => handleClose()}> <Transition.Child as={React.Fragment} enter="ease-out duration-300" enterFrom="opacity-0" enterTo="opacity-100" leave="ease-in duration-200" leaveFrom="opacity-100" leaveTo="opacity-0" > <div className="fixed inset-0 bg-gray-500 bg-opacity-75 transition-opacity" /> </Transition.Child> <div className="fixed inset-0 z-20 overflow-y-auto"> <div className="flex min-h-full items-center justify-center p-4 text-center sm:p-0"> <Transition.Child as={React.Fragment} enter="ease-out duration-300" enterFrom="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95" enterTo="opacity-100 translate-y-0 sm:scale-100" leave="ease-in duration-200" leaveFrom="opacity-100 translate-y-0 sm:scale-100" leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95" > <Dialog.Panel className="relative transform rounded-lg bg-white px-5 py-8 text-left shadow-xl transition-all sm:my-8 sm:w-full sm:max-w-2xl sm:p-6"> <form onSubmit={handleSubmit(onSubmit)}> <div className="space-y-3"> <div className="flex flex-col gap-3"> <h4 className="text-lg font-medium leading-6"> {data && data.length > 0 ? "Update" : "Create"} Estimate Points </h4> <div className="grid grid-cols-3 gap-3"> <div className="flex items-center"> <span className="bg-gray-100 h-full flex items-center rounded-lg"> <span className="px-2 rounded-lg text-sm text-gray-600">1</span> <span className="bg-white rounded-lg"> <Input id="name" name="value1" type="name" placeholder="Point 1" autoComplete="off" register={register} /> </span> </span> </div> <div className="flex items-center"> <span className="bg-gray-100 h-full flex items-center rounded-lg"> <span className="px-2 rounded-lg text-sm text-gray-600">2</span> <span className="bg-white rounded-lg"> <Input id="name" name="value2" type="name" placeholder="Point 2" autoComplete="off" register={register} /> </span> </span> </div> <div className="flex items-center"> <span className="bg-gray-100 h-full flex items-center rounded-lg"> <span className="px-2 rounded-lg text-sm text-gray-600">3</span> <span className="bg-white rounded-lg"> <Input id="name" name="value3" type="name" placeholder="Point 3" autoComplete="off" register={register} /> </span> </span> </div> <div className="flex items-center"> <span className="bg-gray-100 h-full flex items-center rounded-lg"> <span className="px-2 rounded-lg text-sm text-gray-600">4</span> <span className="bg-white rounded-lg"> <Input id="name" name="value4" type="name" placeholder="Point 4" autoComplete="off" register={register} /> </span> </span> </div> <div className="flex items-center"> <span className="bg-gray-100 h-full flex items-center rounded-lg"> <span className="px-2 rounded-lg text-sm text-gray-600">5</span> <span className="bg-white rounded-lg"> <Input id="name" name="value5" type="name" placeholder="Point 5" autoComplete="off" register={register} /> </span> </span> </div> <div className="flex items-center"> <span className="bg-gray-100 h-full flex items-center rounded-lg"> <span className="px-2 rounded-lg text-sm text-gray-600">6</span> <span className="bg-white rounded-lg"> <Input id="name" name="value6" type="name" placeholder="Point 6" autoComplete="off" register={register} /> </span> </span> </div> </div> </div> </div> <div className="mt-5 flex justify-end gap-2"> <SecondaryButton onClick={() => handleClose()}>Cancel</SecondaryButton> <PrimaryButton type="submit" loading={isSubmitting}> {data && data.length > 0 ? isSubmitting ? "Updating Points..." : "Update Points" : isSubmitting ? "Creating Points..." : "Create Points"} </PrimaryButton> </div> </form> </Dialog.Panel> </Transition.Child> </div> </div> </Dialog> </Transition.Root> ); };