import { TimeEntry } from "@/app/api/timesheets/actions"; import { Check, Delete } from "@mui/icons-material"; import { Box, Button, FormControl, InputLabel, Modal, ModalProps, Paper, SxProps, TextField, } from "@mui/material"; import React, { useCallback, useEffect, useMemo } from "react"; import { Controller, useForm } from "react-hook-form"; import { useTranslation } from "react-i18next"; import ProjectSelect from "./ProjectSelect"; import { AssignedProject, ProjectWithTasks } from "@/app/api/projects"; import TaskGroupSelect from "./TaskGroupSelect"; import TaskSelect from "./TaskSelect"; import { TaskGroup } from "@/app/api/tasks"; import uniqBy from "lodash/uniqBy"; export interface Props extends Omit { onSave: (leaveEntry: TimeEntry) => void; onDelete?: () => void; defaultValues?: Partial; allProjects: ProjectWithTasks[]; assignedProjects: AssignedProject[]; } const modalSx: SxProps = { position: "absolute", top: "50%", left: "50%", transform: "translate(-50%, -50%)", width: "90%", maxHeight: "90%", padding: 3, display: "flex", flexDirection: "column", gap: 2, }; const TimesheetEditModal: React.FC = ({ onSave, onDelete, open, onClose, defaultValues, allProjects, assignedProjects, }) => { const { t } = useTranslation("home"); const taskGroupsByProject = useMemo(() => { return allProjects.reduce<{ [projectId: AssignedProject["id"]]: { value: TaskGroup["id"]; label: string; }[]; }>((acc, project) => { return { ...acc, [project.id]: uniqBy( project.tasks.map((t) => ({ value: t.taskGroup.id, label: t.taskGroup.name, })), "value", ), }; }, {}); }, [allProjects]); const { register, control, reset, getValues, setValue, trigger, formState, watch, } = useForm(); useEffect(() => { reset(defaultValues ?? { id: Date.now() }); }, [defaultValues, reset]); const saveHandler = useCallback(async () => { const valid = await trigger(); if (valid) { onSave(getValues()); reset(); } }, [getValues, onSave, reset, trigger]); const closeHandler = useCallback>( (...args) => { onClose?.(...args); reset(); }, [onClose, reset], ); const projectId = watch("projectId"); const taskGroupId = watch("taskGroupId"); const otHours = watch("otHours"); return ( {t("Project Code and Name")} ( { field.onChange(newId ?? null); const firstTaskGroup = ( typeof newId === "number" ? taskGroupsByProject[newId] : [] )[0]; setValue("taskGroupId", firstTaskGroup?.value); setValue("taskId", undefined); }} /> )} rules={{ deps: ["taskGroupId", "taskId"] }} /> {t("Stage")} ( { field.onChange(newId ?? null); }} /> )} rules={{ validate: (id) => { if (!projectId) { return !id; } const taskGroups = taskGroupsByProject[projectId]; return taskGroups.some((tg) => tg.value === id); }, deps: ["taskId"], }} /> {t("Task")} ( { field.onChange(newId ?? null); }} /> )} rules={{ validate: (id) => { if (!projectId) { return !id; } const projectTasks = allProjects.find((p) => p.id === projectId) ?.tasks; return Boolean(projectTasks?.some((task) => task.id === id)); }, }} /> Boolean(value || otHours), })} error={Boolean(formState.errors.inputHours)} /> Boolean(projectId || value), })} /> {onDelete && ( )} ); }; export default TimesheetEditModal;