"use client"; import Stack from "@mui/material/Stack"; import Box from "@mui/material/Box"; import Card from "@mui/material/Card"; import CardContent from "@mui/material/CardContent"; import Grid from "@mui/material/Grid"; import TextField from "@mui/material/TextField"; import { NumericFormat } from 'react-number-format'; import Typography from "@mui/material/Typography"; import { useTranslation } from "react-i18next"; import Button from "@mui/material/Button"; import { Controller, useFormContext } from "react-hook-form"; import { CreateProjectInputs } from "@/app/api/projects/actions"; import { BuildingType, ContractType, FundingType, LocationType, MainProject, ProjectCategory, ServiceType, WorkNature, } from "@/app/api/projects"; import { StaffResult } from "@/app/api/staff"; import { Contact, Customer, CustomerType, Subsidiary, } from "@/app/api/customer"; import Link from "next/link"; import React, { useEffect, useMemo, useState } from "react"; import { fetchCustomer } from "@/app/api/customer/actions"; import uniq from "lodash/uniq"; import ControlledAutoComplete from "../ControlledAutoComplete/ControlledAutoComplete"; import { DatePicker, LocalizationProvider } from "@mui/x-date-pickers"; import { AdapterDayjs } from "@mui/x-date-pickers/AdapterDayjs"; import dayjs, { Dayjs } from 'dayjs'; import { INPUT_DATE_FORMAT } from "@/app/utils/formatUtil"; interface Props { isActive: boolean; isSubProject: boolean; isEditMode: boolean; mainProjects?: MainProject[]; projectCategories: ProjectCategory[]; teamLeads: StaffResult[]; allCustomers: Customer[]; allSubsidiaries: Subsidiary[]; serviceTypes: ServiceType[]; contractTypes: ContractType[]; fundingTypes: FundingType[]; locationTypes: LocationType[]; buildingTypes: BuildingType[]; workNatures: WorkNature[]; customerTypes: CustomerType[]; } const ProjectClientDetails: React.FC = ({ isActive, isSubProject, isEditMode, mainProjects, projectCategories, teamLeads, allCustomers, allSubsidiaries, serviceTypes, contractTypes, fundingTypes, locationTypes, buildingTypes, customerTypes, workNatures, }) => { const { t, i18n: { language }, } = useTranslation(); const { register, formState: { errors, defaultValues, touchedFields }, watch, control, setValue, getValues, reset, resetField, setError, clearErrors } = useFormContext(); const subsidiaryMap = useMemo<{ [id: Subsidiary["id"]]: Subsidiary; }>( () => allSubsidiaries.reduce((acc, sub) => ({ ...acc, [sub.id]: sub }), {}), [allSubsidiaries], ); const selectedCustomerId = watch("clientId"); const [customerContacts, setCustomerContacts] = useState([]); const [subsidiaryContacts, setSubsidiaryContacts] = useState([]); const [customerSubsidiaryIds, setCustomerSubsidiaryIds] = useState( [], ); const selectedCustomerContactId = watch("clientContactId"); const selectedCustomerContact = useMemo( () => subsidiaryContacts.length > 0 ? subsidiaryContacts.find( (contact) => contact.id === selectedCustomerContactId, ) : customerContacts.find( (contact) => contact.id === selectedCustomerContactId, ), [subsidiaryContacts, customerContacts, selectedCustomerContactId], ); // get customer (client) contact combo const clientSubsidiaryId = watch("clientSubsidiaryId"); useEffect(() => { if (selectedCustomerId !== undefined) { fetchCustomer(selectedCustomerId).then( ({ contacts, subsidiaryIds, customer }) => { // console.log(contacts) // console.log(subsidiaryIds) setCustomerContacts(contacts); setCustomerSubsidiaryIds(subsidiaryIds); setValue( "clientTypeId", touchedFields["clientTypeId"] ? customer.customerType.id : defaultValues?.clientTypeId || customer.customerType.id, { shouldTouch: isEditMode, }, ); if (subsidiaryIds.length > 0) setValue( "clientSubsidiaryId", clientSubsidiaryId !== undefined && clientSubsidiaryId !== null ? subsidiaryIds.includes(clientSubsidiaryId) ? clientSubsidiaryId : null : null, ); // if (contacts.length > 0) setValue("clientContactId", contacts[0].id) // else setValue("clientContactId", undefined) }, ); } }, [selectedCustomerId]); useEffect(() => { if (Boolean(clientSubsidiaryId)) { // get subsidiary contact combo const contacts = allSubsidiaries.find( (subsidiary) => subsidiary.id === clientSubsidiaryId, )!.subsidiaryContacts; setSubsidiaryContacts(() => contacts); setValue( "clientContactId", selectedCustomerId === defaultValues?.clientId && Boolean(defaultValues?.clientSubsidiaryId) ? contacts.find( (contact) => contact?.id === defaultValues?.clientContactId, )?.id ?? contacts[0]?.id : contacts[0]?.id, ); setValue("isSubsidiaryContact", true); } else if (customerContacts?.length > 0) { setSubsidiaryContacts(() => []); setValue( "clientContactId", selectedCustomerId === defaultValues?.clientId && !Boolean(defaultValues?.clientSubsidiaryId) ? customerContacts.find( (contact) => contact.id === defaultValues.clientContactId, )?.id ?? customerContacts[0].id : customerContacts[0].id, ); setValue("isSubsidiaryContact", false); } }, [customerContacts, clientSubsidiaryId, selectedCustomerId]); // Automatically add the team lead to the allocated staff list const selectedTeamLeadId = watch("projectLeadId"); useEffect(() => { if (selectedTeamLeadId !== undefined) { const currentStaffIds = getValues("allocatedStaffIds"); const newList = uniq([...currentStaffIds, selectedTeamLeadId]); setValue("allocatedStaffIds", newList); } }, [getValues, selectedTeamLeadId, setValue]); // Automatically update the project & client details whene select a main project const mainProjectId = watch("mainProjectId"); useEffect(() => { if ( mainProjectId !== undefined && mainProjects !== undefined && !isEditMode ) { const mainProject = mainProjects.find( (project) => project.projectId === mainProjectId, ); if (mainProject !== undefined) { const teamLeadIds = teamLeads.map((teamLead) => teamLead.id) setValue("projectName", mainProject.projectName); setValue("projectCategoryId", mainProject.projectCategoryId); // set project lead id to the first team lead id if the main project lead id is not in the team lead list setValue("projectLeadId", teamLeadIds.find((id) => id === mainProject.projectLeadId) ? mainProject.projectLeadId : teamLeadIds[0] ?? mainProject.projectLeadId); setValue("serviceTypeId", mainProject.serviceTypeId); setValue("fundingTypeId", mainProject.fundingTypeId); setValue("contractTypeId", mainProject.contractTypeId); setValue("locationId", mainProject.locationId); setValue("buildingTypeIds", mainProject.buildingTypeIds); setValue("workNatureIds", mainProject.workNatureIds); setValue("projectDescription", mainProject.projectDescription); setValue("expectedProjectFee", mainProject.expectedProjectFee); setValue("subContractFee", mainProject.subContractFee); setValue("isClpProject", mainProject.isClpProject); setValue("clientId", mainProject.clientId); setValue("clientSubsidiaryId", mainProject.clientSubsidiaryId); setValue("clientContactId", mainProject.clientContactId); } } }, [getValues, mainProjectId, setValue, isEditMode]); // const buildingTypeIdNameMap = buildingTypes.reduce<{ [id: number]: string }>( // (acc, building) => ({ ...acc, [building.id]: building.name }), // {}, // ); // const workNatureIdNameMap = workNatures.reduce<{ [id: number]: string }>( // (acc, wn) => ({ ...acc, [wn.id]: wn.name }), // {}, // ); const planStart = watch("projectPlanStart") const planEnd = watch("projectPlanEnd") useEffect(() => { let hasErrors = false if( !planStart || new Date(planStart) > new Date(planEnd) ){ hasErrors = true; } if( !planEnd || new Date(planStart) > new Date(planEnd) ){ hasErrors = true; } if(hasErrors){ setError("projectPlanStart", { message: "Project Plan Start date is not valid", type: "required", }); setError("projectPlanEnd", { message: "Project Plan End date is not valid", type: "required", }); }else{ clearErrors("projectPlanStart") clearErrors("projectPlanEnd") } },[planStart, planEnd]) return ( {t("Project Details")} {isSubProject && mainProjects !== undefined && ( <> ({ id: mainProject.projectId, label: `${mainProject.projectCode} - ${mainProject.projectName}`, })), ]} name="mainProjectId" label={t("Main Project")} noOptionsText={t("No Main Project")} disabled={isEditMode} /> )} { if (!date) return; setValue("projectPlanStart", date.format(INPUT_DATE_FORMAT)); }} slotProps={{ textField: { // required: true, error: // Boolean(errors.projectPlanStart) // || new Date(planStart) > new Date(planEnd) || Boolean(errors.projectPlanStart) , }, }} /> { if (!date) return; setValue("projectPlanEnd", date.format(INPUT_DATE_FORMAT)); }} slotProps={{ textField: { // required: true, error: // Boolean(errors.projectPlanEnd) // || new Date(planStart) > new Date(planEnd) || Boolean(errors.projectPlanEnd) , }, }} /> ({ ...staff, label: `${staff.staffId} - ${staff.name} (${staff.team})`, }))} name="projectLeadId" label={t("Team Lead")} noOptionsText={t("No Team Lead")} /> ( { // console.log(values) onChange(values.floatValue) }} customInput={TextField} thousandSeparator valueIsNumericString decimalScale={2} fixedDecimalScale name={name} value={value} onBlur={onBlur} inputRef={ref} /> )} /> {/* */} ( { // console.log(values) onChange(values.floatValue) }} customInput={TextField} thousandSeparator valueIsNumericString decimalScale={2} fixedDecimalScale name={name} value={value} onBlur={onBlur} inputRef={ref} /> )} /> {/* */} {/* {t("CLP Project")} */} {t("Client Details")} {/* */} ({ ...customer, label: `${customer.name}`, // label: `${customer.code} - ${customer.name}`, }))} name="clientId" label={t("Client")} noOptionsText={t("No Client")} rules={{ required: "Please select a client", }} /> {/* */} {customerContacts.length > 0 && ( {t("Subsidiary Details")} subsidiaryMap[subId]) .map((subsidiaryId, index) => { const subsidiary = subsidiaryMap[subsidiaryId]; return { id: subsidiary.id, label: `${subsidiary.name}`, // label: `${subsidiary.code} - ${subsidiary.name}`, }; }), ]} name="clientSubsidiaryId" label={t("Client Subsidiary")} noOptionsText={t("No Client Subsidiary")} /> { if ( customerContacts.length > 0 && !customerContacts.find( (contact) => contact.id === value, ) && subsidiaryContacts?.length > 0 && !subsidiaryContacts.find( (contact) => contact.id === value, ) ) { return t("Please provide a valid contact"); } else return true; }, }} /> )} {/* */} {/* */} ); }; export default ProjectClientDetails;