diff --git a/src/app/(main)/layout.tsx b/src/app/(main)/layout.tsx
index b93ed10..98a0800 100644
--- a/src/app/(main)/layout.tsx
+++ b/src/app/(main)/layout.tsx
@@ -6,6 +6,7 @@ import Box from "@mui/material/Box";
import { NAVIGATION_CONTENT_WIDTH } from "@/config/uiConfig";
import Stack from "@mui/material/Stack";
import Breadcrumb from "@/components/Breadcrumb";
+import { I18nProvider } from "@/i18n";
export default async function MainLayout({
children,
@@ -31,10 +32,12 @@ export default async function MainLayout({
padding: { xs: "1rem", sm: "1.5rem", lg: "3rem" },
}}
>
-
-
- {children}
-
+
+
+
+ {children}
+
+
>
);
diff --git a/src/app/api/customer/index.ts b/src/app/api/customer/index.ts
index 7ed4359..ed4d947 100644
--- a/src/app/api/customer/index.ts
+++ b/src/app/api/customer/index.ts
@@ -11,6 +11,8 @@ export interface Customer {
address: string | null;
district: string | null;
customerType: CustomerType;
+
+ contacts: Contact[];
}
export interface SaveCustomerResponse {
@@ -40,6 +42,7 @@ export interface Subsidiary {
district: string | null;
email: string | null;
subsidiaryType: SubsidiaryType;
+ subsidiaryContacts: Contact[];
}
export interface SubsidiaryTable {
diff --git a/src/app/api/projects/actions.ts b/src/app/api/projects/actions.ts
index c80dff0..c1be476 100644
--- a/src/app/api/projects/actions.ts
+++ b/src/app/api/projects/actions.ts
@@ -20,6 +20,8 @@ export interface CreateProjectInputs {
projectLeadId: number;
projectActualStart: string;
projectActualEnd: string;
+ projectStatus: string;
+ isClpProject: boolean;
// Project info
serviceTypeId: number;
@@ -28,11 +30,14 @@ export interface CreateProjectInputs {
locationId: number;
buildingTypeIds: number[];
workNatureIds: number[];
+ taskTemplateId?: number | "All";
// Client details
clientId: Customer["id"];
- clientContactId: number;
+ clientContactId?: number;
clientSubsidiaryId?: number;
+ subsidiaryContactId: number;
+ isSubsidiaryContact?: boolean;
// Allocation
totalManhour: number;
diff --git a/src/app/api/projects/index.ts b/src/app/api/projects/index.ts
index 30bd385..697ac98 100644
--- a/src/app/api/projects/index.ts
+++ b/src/app/api/projects/index.ts
@@ -12,6 +12,7 @@ export interface ProjectResult {
category: string;
team: string;
client: string;
+ status: string;
}
export interface ProjectCategory {
diff --git a/src/app/api/subsidiary/index.ts b/src/app/api/subsidiary/index.ts
index c83f4db..818bebf 100644
--- a/src/app/api/subsidiary/index.ts
+++ b/src/app/api/subsidiary/index.ts
@@ -10,7 +10,9 @@ export interface Customer {
brNo: string | null;
address: string | null;
district: string | null;
- customerType: CustomerType
+ customerType: CustomerType;
+
+ contacts: Contact[];
}
export interface CustomerTable {
@@ -40,7 +42,9 @@ export interface Subsidiary {
brNo: string | null;
address: string | null;
district: string | null;
- subsidiaryType: SubsidiaryType
+ subsidiaryType: SubsidiaryType;
+
+ contacts: Contact[];
}
export interface SaveSubsidiaryResponse {
diff --git a/src/components/CreateProject/CreateProject.tsx b/src/components/CreateProject/CreateProject.tsx
index c4aa9d5..a54931b 100644
--- a/src/components/CreateProject/CreateProject.tsx
+++ b/src/components/CreateProject/CreateProject.tsx
@@ -76,7 +76,7 @@ const hasErrorsInTab = (
switch (tabIndex) {
case 0:
return (
- errors.projectName || errors.projectCode || errors.projectDescription
+ errors.projectName || errors.projectDescription || errors.clientId
);
case 2:
return (
@@ -114,6 +114,8 @@ const CreateProject: React.FC = ({
const { t } = useTranslation();
const router = useRouter();
+console.log(defaultInputs)
+
const handleCancel = () => {
router.replace("/projects");
};
@@ -219,6 +221,7 @@ const CreateProject: React.FC = ({
data.projectActualEnd = dayjs().format("YYYY-MM-DD");
}
+ data.taskTemplateId = data.taskTemplateId === "All" ? undefined : data.taskTemplateId;
const response = await saveProject(data);
if (response.id > 0) {
@@ -248,7 +251,8 @@ const CreateProject: React.FC = ({
if (
errors.projectName ||
errors.projectDescription ||
- errors.projectCode
+ // errors.projectCode ||
+ errors.clientId
) {
setTabIndex(0);
} else if (errors.totalManhour || errors.manhourPercentageByGrade || errors.taskGroups) {
@@ -266,6 +270,7 @@ const CreateProject: React.FC = ({
allocatedStaffIds: [],
milestones: {},
totalManhour: 0,
+ taskTemplateId: "All",
...defaultInputs,
// manhourPercentageByGrade should have a sensible default
@@ -289,7 +294,8 @@ const CreateProject: React.FC = ({
>
{isEditMode && !(formProps.getValues("projectDeleted") === true) && (
- {!formProps.getValues("projectActualStart") && (
+ {/* {!formProps.getValues("projectActualStart") && ( */}
+ {formProps.getValues("projectStatus") === "Pending to Start" && (
)}
- {formProps.getValues("projectActualStart") &&
- !formProps.getValues("projectActualEnd") && (
+ {/* {formProps.getValues("projectActualStart") &&
+ !formProps.getValues("projectActualEnd") && ( */}
+ {formProps.getValues("projectStatus") === "On-going" && (
)}
{!(
- formProps.getValues("projectActualStart") &&
- formProps.getValues("projectActualEnd")
+ // formProps.getValues("projectActualStart") &&
+ // formProps.getValues("projectActualEnd")
+ formProps.getValues("projectStatus") === "Completed" ||
+ formProps.getValues("projectStatus") === "Deleted"
) && (
-
+
{t("Client")}
(
diff --git a/src/components/CreateProject/TaskSetup.tsx b/src/components/CreateProject/TaskSetup.tsx
index d24da23..dac0698 100644
--- a/src/components/CreateProject/TaskSetup.tsx
+++ b/src/components/CreateProject/TaskSetup.tsx
@@ -33,7 +33,7 @@ const TaskSetup: React.FC = ({
isActive,
}) => {
const { t } = useTranslation();
- const { setValue, watch, clearErrors, setError } = useFormContext();
+ const { setValue, watch, clearErrors, setError, formState: { defaultValues } } = useFormContext();
const currentTaskGroups = watch("taskGroups");
const currentTaskIds = Object.values(currentTaskGroups).reduce(
(acc, group) => {
@@ -48,7 +48,7 @@ const TaskSetup: React.FC = ({
const [selectedTaskTemplateId, setSelectedTaskTemplateId] = useState<
"All" | number
- >("All");
+ >(watch("taskTemplateId") ?? "All");
const onSelectTaskTemplate = useCallback(
(e: SelectChangeEvent) => {
if (e.target.value === "All" || isNumber(e.target.value)) {
@@ -64,7 +64,8 @@ const TaskSetup: React.FC = ({
(template) => template.id === selectedTaskTemplateId,
)
- if (selectedTaskTemplateId !== "All") {
+ if (selectedTaskTemplateId !== "All" && selectedTaskTemplateId !== watch("taskTemplateId")) {
+
// update the "manhour allocation by grade" by task template
const updatedManhourPercentageByGrade: ManhourAllocation = watch("manhourPercentageByGrade")
selectedTaskTemplate?.gradeAllocations.forEach((gradeAllocation) => {
@@ -73,28 +74,30 @@ const TaskSetup: React.FC = ({
setValue("manhourPercentageByGrade", updatedManhourPercentageByGrade)
if (Object.values(updatedManhourPercentageByGrade).reduce((acc, value) => acc + value, 0) === 100) clearErrors("manhourPercentageByGrade")
- else setError("manhourPercentageByGrade", {message: "manhourPercentageByGrade value is not valid", type: "invalid"})
+ else setError("manhourPercentageByGrade", { message: "manhourPercentageByGrade value is not valid", type: "invalid" })
// update the "manhour allocation by grade by stage" by task template
const updatedTaskGroups = watch("taskGroups")
const taskGroupsKeys = Object.keys(updatedTaskGroups)
selectedTaskTemplate?.groupAllocations.forEach((groupAllocation) => {
const taskGroupId = groupAllocation.taskGroup.id
- if(taskGroupsKeys.includes(taskGroupId.toString())) {
- updatedTaskGroups[taskGroupId] = {...updatedTaskGroups[taskGroupId], percentAllocation: groupAllocation?.percentage}
+ if (taskGroupsKeys.includes(taskGroupId.toString())) {
+ updatedTaskGroups[taskGroupId] = { ...updatedTaskGroups[taskGroupId], percentAllocation: groupAllocation?.percentage }
}
})
const percentageToZeroGroupIds = difference(taskGroupsKeys.map(key => parseFloat(key)), selectedTaskTemplate?.groupAllocations.map(groupAllocation => groupAllocation.taskGroup.id)!!)
percentageToZeroGroupIds.forEach((percentageToZeroGroupId) => {
- updatedTaskGroups[percentageToZeroGroupId] = {...updatedTaskGroups[percentageToZeroGroupId], percentAllocation: 0}
+ updatedTaskGroups[percentageToZeroGroupId] = { ...updatedTaskGroups[percentageToZeroGroupId], percentAllocation: 0 }
})
-
+
setValue("taskGroups", updatedTaskGroups)
if (Object.values(updatedTaskGroups).reduce((acc, value) => acc + value.percentAllocation, 0) === 100) clearErrors("taskGroups")
- else setError("taskGroups", {message: "Task Groups value is not invalid", type: "invalid"})
+ else setError("taskGroups", { message: "Task Groups value is not invalid", type: "invalid" })
}
+ setValue("taskTemplateId", selectedTaskTemplateId)
+
const taskList =
selectedTaskTemplateId === "All"
? tasks
@@ -176,7 +179,26 @@ const TaskSetup: React.FC = ({
};
}, {});
- setValue("taskGroups", newTaskGroups);
+ // update the "manhour allocation by grade by stage" by task template
+ const taskGroupsKeys = Object.keys(newTaskGroups)
+ const selectedTaskTemplate = taskTemplates.find(
+ (template) => template.id === selectedTaskTemplateId,
+ )
+ selectedTaskTemplate?.groupAllocations.forEach((groupAllocation) => {
+ const taskGroupId = groupAllocation.taskGroup.id
+ if (taskGroupsKeys.includes(taskGroupId.toString())) {
+ newTaskGroups[taskGroupId] = { ...newTaskGroups[taskGroupId], percentAllocation: groupAllocation?.percentage }
+ }
+ })
+
+ const percentageToZeroGroupIds = difference(taskGroupsKeys.map(key => parseFloat(key)), selectedTaskTemplate?.groupAllocations.map(groupAllocation => groupAllocation.taskGroup.id)!!)
+ percentageToZeroGroupIds.forEach((percentageToZeroGroupId) => {
+ newTaskGroups[percentageToZeroGroupId] = { ...newTaskGroups[percentageToZeroGroupId], percentAllocation: 0 }
+ })
+
+ setValue("taskGroups", newTaskGroups)
+ if (Object.values(newTaskGroups).reduce((acc, value) => acc + value.percentAllocation, 0) === 100) clearErrors("taskGroups")
+ else setError("taskGroups", { message: "Task Groups value is not invalid", type: "invalid" })
}}
allItemsLabel={t("Task Pool")}
selectedItemsLabel={t("Project Task List")}
diff --git a/src/components/ProjectSearch/ProjectSearch.tsx b/src/components/ProjectSearch/ProjectSearch.tsx
index 55b4cc7..79ee51b 100644
--- a/src/components/ProjectSearch/ProjectSearch.tsx
+++ b/src/components/ProjectSearch/ProjectSearch.tsx
@@ -46,6 +46,12 @@ const ProjectSearch: React.FC = ({ projects, projectCategories }) => {
type: "select",
options: uniq(projects.map((project) => project.team)),
},
+ {
+ label: t("Status"),
+ paramName: "status",
+ type: "select",
+ options: uniq(projects.map((project) => project.status)),
+ },
],
[t, projectCategories, projects],
);
@@ -74,6 +80,7 @@ const ProjectSearch: React.FC = ({ projects, projectCategories }) => {
{ name: "category", label: t("Project Category") },
{ name: "team", label: t("Team") },
{ name: "client", label: t("Client") },
+ { name: "status", label: t("Status") },
],
[t, onProjectClick],
);
@@ -90,7 +97,8 @@ const ProjectSearch: React.FC = ({ projects, projectCategories }) => {
p.name.toLowerCase().includes(query.name.toLowerCase()) &&
(query.client === "All" || p.client === query.client) &&
(query.category === "All" || p.category === query.category) &&
- (query.team === "All" || p.team === query.team),
+ (query.team === "All" || p.team === query.team) &&
+ (query.status === "All" || p.status === query.status),
),
);
}}