From 070c1d3377f6661d4ec86c403208da8a6d17776a Mon Sep 17 00:00:00 2001 From: Wayne Date: Fri, 9 Feb 2024 18:21:47 +0900 Subject: [PATCH] Add form provider for create project --- src/app/api/projects/actions.ts | 50 ++++++ .../CreateProject/CreateProject.tsx | 66 +++++--- .../CreateProject/CreateProjectWrapper.tsx | 2 +- .../CreateProject/ProjectClientDetails.tsx | 51 +++++- .../CreateProject/ResourceMilestone.tsx | 150 ++++++++++++++---- .../CreateProject/StaffAllocation.tsx | 57 ++++--- src/components/CreateProject/TaskSetup.tsx | 48 ++++-- src/components/TransferList/TransferList.tsx | 18 ++- 8 files changed, 339 insertions(+), 103 deletions(-) create mode 100644 src/app/api/projects/actions.ts diff --git a/src/app/api/projects/actions.ts b/src/app/api/projects/actions.ts new file mode 100644 index 0000000..47efb34 --- /dev/null +++ b/src/app/api/projects/actions.ts @@ -0,0 +1,50 @@ +"use server"; + +import { serverFetchJson } from "@/app/utils/fetchUtil"; +import { BASE_API_URL } from "@/config/api"; +import { Task, TaskGroup } from "../tasks"; + +export interface CreateProjectInputs { + // Project details + projectCode: string; + projectSubcode: string; + projectName: string; + projectCategory: string; + projectDescription: string; + + // Client details + clientCode: string; + clientName: string; + clientPhone: string; + clientEmail: string; + clientSubsidiary: string; + + // Tasks + tasks: { + [taskId: Task["id"]]: { + manhourAllocation: { + [grade: string]: number; + }; + }; + }; + + // Staff + allocatedStaffIds: number[]; + + // Milestones + milestones: { + [taskGroupId: TaskGroup["id"]]: { + startDate: string; + endDate: string; + payments: []; + }; + }; +} + +export const saveProject = async (data: CreateProjectInputs) => { + return serverFetchJson(`${BASE_API_URL}/projects/new`, { + method: "POST", + body: JSON.stringify(data), + headers: { "Content-Type": "application/json" }, + }); +}; diff --git a/src/components/CreateProject/CreateProject.tsx b/src/components/CreateProject/CreateProject.tsx index 622205e..326ea02 100644 --- a/src/components/CreateProject/CreateProject.tsx +++ b/src/components/CreateProject/CreateProject.tsx @@ -14,12 +14,14 @@ import TaskSetup from "./TaskSetup"; import StaffAllocation from "./StaffAllocation"; import ResourceMilestone from "./ResourceMilestone"; import { Task } from "@/app/api/tasks"; +import { FormProvider, SubmitHandler, useForm } from "react-hook-form"; +import { CreateProjectInputs } from "@/app/api/projects/actions"; export interface Props { - mockTasks: Task[]; + allTasks: Task[]; } -const CreateProject: React.FC = ({ mockTasks }) => { +const CreateProject: React.FC = ({ allTasks }) => { const [tabIndex, setTabIndex] = useState(0); const { t } = useTranslation(); const router = useRouter(); @@ -35,27 +37,49 @@ const CreateProject: React.FC = ({ mockTasks }) => { [], ); + const onSubmit = useCallback>((data) => { + console.log(data); + }, []); + + const formProps = useForm({ + defaultValues: { + tasks: {}, + allocatedStaffIds: [], + milestones: {}, + }, + }); + return ( - <> - - - - - - - {tabIndex === 0 && } - {tabIndex === 1 && } - {tabIndex === 2 && } - {tabIndex === 3 && } - - - + + + + + + + + + {tabIndex === 0 && } + {tabIndex === 1 && } + {tabIndex === 2 && } + {tabIndex === 3 && } + + + + - + ); }; diff --git a/src/components/CreateProject/CreateProjectWrapper.tsx b/src/components/CreateProject/CreateProjectWrapper.tsx index c281e9a..f5fbb5a 100644 --- a/src/components/CreateProject/CreateProjectWrapper.tsx +++ b/src/components/CreateProject/CreateProjectWrapper.tsx @@ -4,7 +4,7 @@ import CreateProject from "./CreateProject"; const CreateProjectWrapper: React.FC = async () => { const tasks = await fetchAllTasks(); - return ; + return ; }; export default CreateProjectWrapper; diff --git a/src/components/CreateProject/ProjectClientDetails.tsx b/src/components/CreateProject/ProjectClientDetails.tsx index 06074b5..34b4c77 100644 --- a/src/components/CreateProject/ProjectClientDetails.tsx +++ b/src/components/CreateProject/ProjectClientDetails.tsx @@ -15,9 +15,12 @@ import { useTranslation } from "react-i18next"; import CardActions from "@mui/material/CardActions"; import RestartAlt from "@mui/icons-material/RestartAlt"; import Button from "@mui/material/Button"; +import { useFormContext } from "react-hook-form"; +import { CreateProjectInputs } from "@/app/api/projects/actions"; const ProjectClientDetails: React.FC = () => { const { t } = useTranslation(); + const { register } = useFormContext(); return ( @@ -28,13 +31,25 @@ const ProjectClientDetails: React.FC = () => { - + - + - + @@ -60,7 +75,11 @@ const ProjectClientDetails: React.FC = () => { - + @@ -71,16 +90,32 @@ const ProjectClientDetails: React.FC = () => { - + - + - + - + diff --git a/src/components/CreateProject/ResourceMilestone.tsx b/src/components/CreateProject/ResourceMilestone.tsx index 9f0c404..d2bfbf1 100644 --- a/src/components/CreateProject/ResourceMilestone.tsx +++ b/src/components/CreateProject/ResourceMilestone.tsx @@ -5,18 +5,24 @@ import CardContent from "@mui/material/CardContent"; import Typography from "@mui/material/Typography"; import { useTranslation } from "react-i18next"; import Button from "@mui/material/Button"; -import React, { useCallback, useMemo, useState } from "react"; +import React, { useCallback, useEffect, useMemo, useState } from "react"; import CardActions from "@mui/material/CardActions"; import RestartAlt from "@mui/icons-material/RestartAlt"; import { Alert, + Box, FormControl, Grid, InputLabel, + List, + ListItemButton, + ListItemText, MenuItem, + Paper, Select, SelectChangeEvent, Stack, + TextField, } from "@mui/material"; import { Task, TaskGroup } from "@/app/api/tasks"; import uniqBy from "lodash/uniqBy"; @@ -24,13 +30,26 @@ import { moneyFormatter } from "@/app/utils/formatUtil"; import { DatePicker, LocalizationProvider } from "@mui/x-date-pickers"; import { AdapterDayjs } from "@mui/x-date-pickers/AdapterDayjs"; import dayjs from "dayjs"; +import { useFormContext } from "react-hook-form"; +import { CreateProjectInputs } from "@/app/api/projects/actions"; interface Props { + allTasks: Task[]; +} + +interface ResourceSectionProps { tasks: Task[]; + defaultManhourBreakdownByGrade: { [grade: string]: number }; + onSetManhours: (hours: number, taskId: Task["id"]) => void; + onAllocateManhours: () => void; } -const ResourceMilestone: React.FC = ({ tasks }) => { +const ResourceMilestone: React.FC = ({ allTasks }) => { const { t } = useTranslation(); + const { getValues } = useFormContext(); + const tasks = useMemo(() => { + return allTasks.filter((task) => getValues("tasks")[task.id]); + }, [allTasks, getValues]); const taskGroups = useMemo(() => { return uniqBy( @@ -41,18 +60,23 @@ const ResourceMilestone: React.FC = ({ tasks }) => { const [currentTaskGroupId, setCurrentTaskGroupId] = useState( taskGroups[0].id, ); + const [currentTasks, setCurrentTasks] = useState( + tasks.filter((t) => t.taskGroup.id === currentTaskGroupId), + ); const onSelectTaskGroup = useCallback( (event: SelectChangeEvent) => { const id = event.target.value; - setCurrentTaskGroupId(typeof id === "string" ? parseInt(id) : id); + const newTaksGroupId = typeof id === "string" ? parseInt(id) : id; + setCurrentTaskGroupId(newTaksGroupId); + setCurrentTasks(tasks.filter((t) => t.taskGroup.id === newTaksGroupId)); }, - [], + [tasks], ); return ( <> - + {t("Task Stage")} - - {t("Resource")} - - - {t("Milestone")} - - - - - - - - - - - - - - - + {}} + onAllocateManhours={() => {}} + /> +