From eef3ffe047044fad9ea847aa1482d1f93be294e8 Mon Sep 17 00:00:00 2001 From: "cyril.tsui" Date: Tue, 28 May 2024 11:17:28 +0800 Subject: [PATCH 01/12] update --- src/components/CreateProject/CreateProject.tsx | 1 + src/components/CreateProject/StaffAllocation.tsx | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/CreateProject/CreateProject.tsx b/src/components/CreateProject/CreateProject.tsx index d115f3a..013250d 100644 --- a/src/components/CreateProject/CreateProject.tsx +++ b/src/components/CreateProject/CreateProject.tsx @@ -277,6 +277,7 @@ const CreateProject: React.FC = ({ projectName: mainProjects !== undefined ? mainProjects[0].projectName : undefined, projectDescription: mainProjects !== undefined ? mainProjects[0].projectDescription : undefined, expectedProjectFee: mainProjects !== undefined ? mainProjects[0].expectedProjectFee : undefined, + clientId: allCustomers !== undefined ? allCustomers[0].id : undefined, ...defaultInputs, // manhourPercentageByGrade should have a sensible default diff --git a/src/components/CreateProject/StaffAllocation.tsx b/src/components/CreateProject/StaffAllocation.tsx index e61f995..cffd45a 100644 --- a/src/components/CreateProject/StaffAllocation.tsx +++ b/src/components/CreateProject/StaffAllocation.tsx @@ -118,7 +118,7 @@ const StaffAllocation: React.FC = ({ }, { label: t("Team"), name: "team" }, { label: t("Grade"), name: "grade" }, - { label: t("Staff ID"), name: "id" }, + { label: t("Staff ID"), name: "staffId" }, { label: t("Staff Name"), name: "name" }, { label: t("Title"), name: "currentPosition" }, ], From b852093821dfdda5d417111ae4a84e379f879139 Mon Sep 17 00:00:00 2001 From: "MSI\\derek" Date: Tue, 28 May 2024 11:23:09 +0800 Subject: [PATCH 02/12] edit group fix --- src/app/(main)/settings/group/edit/page.tsx | 7 +++- src/app/api/group/index.ts | 13 ++++++ .../EditUserGroup/EditUserGroup.tsx | 40 +++++++++---------- .../EditUserGroup/EditUserGroupWrapper.tsx | 17 +++++--- src/components/EditUserGroup/GroupInfo.tsx | 1 + 5 files changed, 49 insertions(+), 29 deletions(-) diff --git a/src/app/(main)/settings/group/edit/page.tsx b/src/app/(main)/settings/group/edit/page.tsx index 9055358..f1bfcbd 100644 --- a/src/app/(main)/settings/group/edit/page.tsx +++ b/src/app/(main)/settings/group/edit/page.tsx @@ -1,3 +1,4 @@ +import { searchParamsProps } from "@/app/utils/fetchUtil"; import EditPosition from "@/components/EditPosition"; import EditUserGroup from "@/components/EditUserGroup"; import { I18nProvider, getServerI18n } from "@/i18n"; @@ -8,7 +9,9 @@ export const metadata: Metadata = { title: "Edit User Group", }; -const Group: React.FC = async () => { +const Group: React.FC = async ({ + searchParams, +}) => { const { t } = await getServerI18n("group"); // Preload necessary dependencies @@ -17,7 +20,7 @@ const Group: React.FC = async () => { <> {/* {t("Edit User Group")} */} - + ); diff --git a/src/app/api/group/index.ts b/src/app/api/group/index.ts index 9dcee9e..082b0f3 100644 --- a/src/app/api/group/index.ts +++ b/src/app/api/group/index.ts @@ -14,8 +14,21 @@ export interface UserGroupResult { description: string; } +export type IndivUserGroup = { + authIds: number[]; + data: any; + userIds: number[]; +} + export const fetchGroup = cache(async () => { return serverFetchJson(`${BASE_API_URL}/group`, { next: { tags: ["group"] }, }); }); + + +export const fetchIndivGroup = cache(async (id: number) => { + return serverFetchJson(`${BASE_API_URL}/group/${id}`, { + next: { tags: ["group"] }, + }); + }); diff --git a/src/components/EditUserGroup/EditUserGroup.tsx b/src/components/EditUserGroup/EditUserGroup.tsx index 1eba351..c523a58 100644 --- a/src/components/EditUserGroup/EditUserGroup.tsx +++ b/src/components/EditUserGroup/EditUserGroup.tsx @@ -1,6 +1,6 @@ "use client"; import { useRouter, useSearchParams } from "next/navigation"; -import { useCallback, useEffect, useMemo, useState } from "react"; +import React, { useCallback, useEffect, useMemo, useState } from "react"; import SearchResults, { Column } from "../SearchResults"; // import { TeamResult } from "@/app/api/team"; import { useTranslation } from "react-i18next"; @@ -16,19 +16,19 @@ import { import { Check, Close, Error } from "@mui/icons-material"; import { StaffResult } from "@/app/api/staff"; import { CreateGroupInputs, auth, fetchAuth, saveGroup } from "@/app/api/group/actions"; -import { UserGroupResult } from "@/app/api/group"; +import { IndivUserGroup, UserGroupResult } from "@/app/api/group"; import { UserResult } from "@/app/api/user"; import GroupInfo from "./GroupInfo"; import AuthorityAllocation from "./AuthorityAllocation"; import UserAllocation from "./UserAllocation"; interface Props { - groups: UserGroupResult[]; -// auths: auth[]; + // groups: UserGroupResult[]; + auths: auth[]; users: UserResult[]; + group: IndivUserGroup } -const EditUserGroup: React.FC = ({ groups, users }) => { - // console.log(users) +const EditUserGroup: React.FC = ({ users, auths, group }) => { const { t } = useTranslation(); const [serverError, setServerError] = useState(""); const formProps = useForm(); @@ -36,7 +36,6 @@ const EditUserGroup: React.FC = ({ groups, users }) => { const id = parseInt(searchParams.get("id") || "0"); const router = useRouter(); const [tabIndex, setTabIndex] = useState(0); - const [auths, setAuths] = useState(); const errors = formProps.formState.errors; @@ -79,22 +78,19 @@ const EditUserGroup: React.FC = ({ groups, users }) => { }, [router] ); + + const resetGroup = React.useCallback(() => { + formProps.reset({ + name: group.data.name, + description: group.data.description, + addAuthIds: group.authIds, + addUserIds: group.userIds, + }) + }, []); + useEffect(() => { - const thisGroup = groups.filter((item) => item.id === id)[0]; - const addUserIds = users.filter((item) => item.groupId === id).map((data) => data.id) - let addAuthIds: number[] = [] - fetchAuth("group", id).then((data) => { - setAuths(data.records) - addAuthIds = data.records.filter((data) => data.v === 1).map((data) => data.id).sort((a, b) => a - b); - formProps.reset({ - name: thisGroup.name, - description: thisGroup.description, - addAuthIds: addAuthIds, - addUserIds: addUserIds, - }); - }); - // console.log(auths) - }, [groups, users]); + resetGroup() + }, [group, users]); return ( <> diff --git a/src/components/EditUserGroup/EditUserGroupWrapper.tsx b/src/components/EditUserGroup/EditUserGroupWrapper.tsx index abec89d..573d0db 100644 --- a/src/components/EditUserGroup/EditUserGroupWrapper.tsx +++ b/src/components/EditUserGroup/EditUserGroupWrapper.tsx @@ -1,24 +1,31 @@ import React from "react"; import EditUserGroup from "./EditUserGroup"; import EditUserGroupLoading from "./EditUserGroupLoading"; -import { fetchGroup } from "@/app/api/group"; +import { fetchGroup, fetchIndivGroup } from "@/app/api/group"; import { fetchUser } from "@/app/api/user"; +import { fetchAuth } from "@/app/api/group/actions"; interface SubComponents { Loading: typeof EditUserGroupLoading; } -const EditUserGroupWrapper: React.FC & SubComponents = async () => { +interface Props { + id: number +} + +const EditUserGroupWrapper: React.FC & SubComponents = async ({ id }) => { const [ - groups, + group, users, + auths, ] = await Promise.all([ - fetchGroup(), + fetchIndivGroup(id), fetchUser(), + fetchAuth("group", id), ]); - return ; + return ; }; EditUserGroupWrapper.Loading = EditUserGroupLoading; diff --git a/src/components/EditUserGroup/GroupInfo.tsx b/src/components/EditUserGroup/GroupInfo.tsx index 3817cec..9578327 100644 --- a/src/components/EditUserGroup/GroupInfo.tsx +++ b/src/components/EditUserGroup/GroupInfo.tsx @@ -43,6 +43,7 @@ const GroupInfo: React.FC = () => { Date: Tue, 28 May 2024 11:45:51 +0800 Subject: [PATCH 03/12] edit user fix --- src/app/api/user/actions.ts | 1 + src/components/EditTeam/EditTeam.tsx | 2 +- src/components/EditUser/EditUser.tsx | 7 +++++-- src/components/EditUser/EditUserWrapper.tsx | 14 ++++++++------ src/components/EditUser/UserDetail.tsx | 4 ++-- src/components/EditUserGroup/EditUserGroup.tsx | 16 ++++++++++++---- 6 files changed, 29 insertions(+), 15 deletions(-) diff --git a/src/app/api/user/actions.ts b/src/app/api/user/actions.ts index b655631..48aaea6 100644 --- a/src/app/api/user/actions.ts +++ b/src/app/api/user/actions.ts @@ -7,6 +7,7 @@ import { UserDetail, UserResult } from "."; import { cache } from "react"; export interface UserInputs { + username: string; name: string; email?: string; addAuthIds?: number[]; diff --git a/src/components/EditTeam/EditTeam.tsx b/src/components/EditTeam/EditTeam.tsx index 79d7ec2..f45d310 100644 --- a/src/components/EditTeam/EditTeam.tsx +++ b/src/components/EditTeam/EditTeam.tsx @@ -175,7 +175,7 @@ const EditTeam: React.FC = async ({ staff, teamInfo }) => { diff --git a/src/components/EditUser/EditUser.tsx b/src/components/EditUser/EditUser.tsx index 1d3c473..9a06b0c 100644 --- a/src/components/EditUser/EditUser.tsx +++ b/src/components/EditUser/EditUser.tsx @@ -50,6 +50,7 @@ interface Props { } const EditUser: React.FC = async ({ user, rules, auths }) => { + console.log(user) const { t } = useTranslation("user"); const formProps = useForm(); const searchParams = useSearchParams(); @@ -79,7 +80,7 @@ const EditUser: React.FC = async ({ user, rules, auths }) => { console.log(addAuthIds); try { formProps.reset({ - name: user.username, + username: user.username, email: user.email, addAuthIds: addAuthIds, removeAuthIds: [], @@ -145,7 +146,8 @@ const EditUser: React.FC = async ({ user, rules, auths }) => { } } const userData = { - name: data.name, + username: data.username, + name: user.name, locked: false, addAuthIds: data.addAuthIds || [], removeAuthIds: data.removeAuthIds || [], @@ -159,6 +161,7 @@ const EditUser: React.FC = async ({ user, rules, auths }) => { return; } console.log("passed"); + console.log(userData); await editUser(id, userData); if (data.password && data.password.length > 0) { await adminChangePassword(pwData); diff --git a/src/components/EditUser/EditUserWrapper.tsx b/src/components/EditUser/EditUserWrapper.tsx index f7d77eb..f62bef7 100644 --- a/src/components/EditUser/EditUserWrapper.tsx +++ b/src/components/EditUser/EditUserWrapper.tsx @@ -15,14 +15,16 @@ interface SubComponents { } const EditUserWrapper: React.FC & SubComponents = async ({ - searchParams + searchParams, }) => { - const id = parseInt(searchParams.id as string) - const pwRule = await fetchPwRules() - const user = await fetchUserDetails(id); - const auths = await fetchAuth("user", id); + const id = parseInt(searchParams.id as string); + const [pwRule, user, auths] = await Promise.all([ + fetchPwRules(), + fetchUserDetails(id), + fetchAuth("user", id), + ]); - return + return ; }; EditUserWrapper.Loading = EditUserLoading; diff --git a/src/components/EditUser/UserDetail.tsx b/src/components/EditUser/UserDetail.tsx index 1d251c4..cb98cdc 100644 --- a/src/components/EditUser/UserDetail.tsx +++ b/src/components/EditUser/UserDetail.tsx @@ -34,10 +34,10 @@ const UserDetail: React.FC = () => { diff --git a/src/components/EditUserGroup/EditUserGroup.tsx b/src/components/EditUserGroup/EditUserGroup.tsx index c523a58..c443b4e 100644 --- a/src/components/EditUserGroup/EditUserGroup.tsx +++ b/src/components/EditUserGroup/EditUserGroup.tsx @@ -13,7 +13,7 @@ import { useForm, useFormContext, } from "react-hook-form"; -import { Check, Close, Error } from "@mui/icons-material"; +import { Check, Close, Error, RestartAlt } from "@mui/icons-material"; import { StaffResult } from "@/app/api/staff"; import { CreateGroupInputs, auth, fetchAuth, saveGroup } from "@/app/api/group/actions"; import { IndivUserGroup, UserGroupResult } from "@/app/api/group"; @@ -86,11 +86,12 @@ const EditUserGroup: React.FC = ({ users, auths, group }) => { addAuthIds: group.authIds, addUserIds: group.userIds, }) - }, []); + }, [group, users]); useEffect(() => { resetGroup() - }, [group, users]); + }, []); + // }, [group, users]); return ( <> @@ -136,10 +137,17 @@ const EditUserGroup: React.FC = ({ users, auths, group }) => { {tabIndex === 1 && } {tabIndex === 2 && } + From 6971c24399965a12f935d8aafef393223d5e60ec Mon Sep 17 00:00:00 2001 From: "MSI\\derek" Date: Tue, 28 May 2024 11:46:12 +0800 Subject: [PATCH 04/12] update --- src/components/EditUser/EditUser.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/EditUser/EditUser.tsx b/src/components/EditUser/EditUser.tsx index 9a06b0c..465c295 100644 --- a/src/components/EditUser/EditUser.tsx +++ b/src/components/EditUser/EditUser.tsx @@ -161,7 +161,6 @@ const EditUser: React.FC = async ({ user, rules, auths }) => { return; } console.log("passed"); - console.log(userData); await editUser(id, userData); if (data.password && data.password.length > 0) { await adminChangePassword(pwData); From 71815797fc0958a6679c41ca9da3b7de230938a4 Mon Sep 17 00:00:00 2001 From: "MSI\\derek" Date: Tue, 28 May 2024 14:16:18 +0800 Subject: [PATCH 05/12] update --- .../(main)/{settings => }/changepassword/page.tsx | 0 src/app/api/reports/index.ts | 2 +- src/app/api/staff/actions.ts | 10 +++++----- src/components/AppBar/Profile.tsx | 2 +- .../GenerateMonthlyWorkHoursReport.tsx | 12 +++++++++--- 5 files changed, 16 insertions(+), 10 deletions(-) rename src/app/(main)/{settings => }/changepassword/page.tsx (100%) diff --git a/src/app/(main)/settings/changepassword/page.tsx b/src/app/(main)/changepassword/page.tsx similarity index 100% rename from src/app/(main)/settings/changepassword/page.tsx rename to src/app/(main)/changepassword/page.tsx diff --git a/src/app/api/reports/index.ts b/src/app/api/reports/index.ts index 555adbd..32e9cee 100644 --- a/src/app/api/reports/index.ts +++ b/src/app/api/reports/index.ts @@ -46,7 +46,7 @@ export interface ProjectPotentialDelayReportRequest { // - Monthly Work Hours Report export interface MonthlyWorkHoursReportFilter { staff: string[]; - date: any; + date: string; } export interface MonthlyWorkHoursReportRequest { diff --git a/src/app/api/staff/actions.ts b/src/app/api/staff/actions.ts index fca9727..1ee9eb4 100644 --- a/src/app/api/staff/actions.ts +++ b/src/app/api/staff/actions.ts @@ -20,17 +20,17 @@ export interface CreateStaffInputs { companyId: number; salaryId: number; skillSetId?: number[]; - joinDate: string; + joinDate?: string; currentPositionId: number; - joinPositionId: number; + joinPositionId?: number; gradeId?: number; teamId?: number - departmentId: number; + departmentId?: number; phone1: string; phone2?: string; email: string; - emergContactName: string; - emergContactPhone: string; + emergContactName?: string; + emergContactPhone?: string; employType: string; departDate?: string; departReason?: string; diff --git a/src/components/AppBar/Profile.tsx b/src/components/AppBar/Profile.tsx index 9fbe8e5..79d116d 100644 --- a/src/components/AppBar/Profile.tsx +++ b/src/components/AppBar/Profile.tsx @@ -63,7 +63,7 @@ const Profile: React.FC = ({ avatarImageSrc, profileName }) => { {profileName} - { router.replace("/settings/changepassword") }}>{t("Change Password")} + { router.replace("/changepassword") }}>{t("Change Password")} {language === "zh" && { onLangClick("en") }}>{t("Change To English Version")}} {language === "en" && { onLangClick("zh") }}>{t("Change To Chinese Version")}} signOut()}>{t("Sign out")} diff --git a/src/components/GenerateMonthlyWorkHoursReport/GenerateMonthlyWorkHoursReport.tsx b/src/components/GenerateMonthlyWorkHoursReport/GenerateMonthlyWorkHoursReport.tsx index c5bffe3..34c7c61 100644 --- a/src/components/GenerateMonthlyWorkHoursReport/GenerateMonthlyWorkHoursReport.tsx +++ b/src/components/GenerateMonthlyWorkHoursReport/GenerateMonthlyWorkHoursReport.tsx @@ -49,11 +49,17 @@ const GenerateMonthlyWorkHoursReport: React.FC = ({ staffs }) => { formType={"download"} criteria={searchCriteria} onSearch={async (query: any) => { + console.log(query); const index = staffCombo.findIndex((staff) => staff === query.staff); - const response = await fetchMonthlyWorkHoursReport({ + let postData = { id: staffs[index].id, - yearMonth: query.date, - }); + yearMonth: dayjs().format("YYYY-MM").toString(), + }; + console.log(query.date.length > 0) + if (query.date.length > 0) { + postData.yearMonth = query.date + } + const response = await fetchMonthlyWorkHoursReport(postData); if (response) { downloadFile( new Uint8Array(response.blobValue), From 2b79edf0a8ef6d4cce298ce72960b6372e226680 Mon Sep 17 00:00:00 2001 From: "cyril.tsui" Date: Tue, 28 May 2024 14:46:10 +0800 Subject: [PATCH 06/12] add bspp (5/29-30) v1 --- src/app/(main)/dashboard/bspp/page.tsx | 21 + src/components/Bspp/Bspp.tsx | 404 ++++++++++++++++++ src/components/Bspp/BsppWrapper.tsx | 10 + src/components/Bspp/index.ts | 1 + .../NavigationContent/NavigationContent.tsx | 7 +- 5 files changed, 442 insertions(+), 1 deletion(-) create mode 100644 src/app/(main)/dashboard/bspp/page.tsx create mode 100644 src/components/Bspp/Bspp.tsx create mode 100644 src/components/Bspp/BsppWrapper.tsx create mode 100644 src/components/Bspp/index.ts diff --git a/src/app/(main)/dashboard/bspp/page.tsx b/src/app/(main)/dashboard/bspp/page.tsx new file mode 100644 index 0000000..a784c18 --- /dev/null +++ b/src/app/(main)/dashboard/bspp/page.tsx @@ -0,0 +1,21 @@ +import { Metadata } from "next"; +import { I18nProvider } from "@/i18n"; +import { Suspense } from "react"; +import Typography from "@mui/material/Typography"; +import Bspp from "@/components/Bspp"; + +export const metadata: Metadata = { + title: "Project Status by Client", +}; + +const CompanyTeamCashFlow: React.FC = () => { + return ( + + + BSPP + + + + ); +}; +export default CompanyTeamCashFlow; diff --git a/src/components/Bspp/Bspp.tsx b/src/components/Bspp/Bspp.tsx new file mode 100644 index 0000000..40eb30a --- /dev/null +++ b/src/components/Bspp/Bspp.tsx @@ -0,0 +1,404 @@ +"use client"; +import * as React from "react"; +import Grid from "@mui/material/Grid"; +import { Card, CardHeader } from "@mui/material"; +import ReactApexChart from "react-apexcharts"; +import { ApexOptions } from "apexcharts"; +import "../../app/global.css"; +import { Input, Label } from "reactstrap"; +import Select, { components } from "react-select"; +import { DatePicker } from "@mui/x-date-pickers/DatePicker"; +import { LocalizationProvider } from "@mui/x-date-pickers/LocalizationProvider"; +import { AdapterDayjs } from "@mui/x-date-pickers/AdapterDayjs"; +import dayjs, { Dayjs } from "dayjs"; +import isBetweenPlugin from "dayjs/plugin/isBetween"; +import { PickersDay, PickersDayProps } from "@mui/x-date-pickers/PickersDay"; +import { styled } from "@mui/material/styles"; + +dayjs.extend(isBetweenPlugin); +interface CustomPickerDayProps extends PickersDayProps { + isSelected: boolean; + isHovered: boolean; +} + +// Style Day +const CustomPickersDay = styled(PickersDay, { + shouldForwardProp: (prop) => prop !== "isSelected" && prop !== "isHovered", +})(({ theme, isSelected, isHovered, day }) => ({ + borderRadius: 0, + ...(isSelected && { + backgroundColor: theme.palette.primary.main, + color: theme.palette.primary.contrastText, + "&:hover, &:focus": { + backgroundColor: theme.palette.primary.main, + }, + }), + ...(isHovered && { + backgroundColor: theme.palette.primary[theme.palette.mode], + "&:hover, &:focus": { + backgroundColor: theme.palette.primary[theme.palette.mode], + }, + }), + ...(day.day() === 0 && { + borderTopLeftRadius: "50%", + borderBottomLeftRadius: "50%", + }), + ...(day.day() === 6 && { + borderTopRightRadius: "50%", + borderBottomRightRadius: "50%", + }), +})) as React.ComponentType; + +const isInSameWeek = (dayA: Dayjs, dayB: Dayjs | null | undefined) => { + if (dayB == null) { + return false; + } + + return dayA.isSame(dayB, "week"); +}; + +function Day( + props: PickersDayProps & { + selectedDay?: Dayjs | null; + hoveredDay?: Dayjs | null; + }, +) { + const { day, selectedDay, hoveredDay, ...other } = props; + + return ( + + ); +} + + + +// Main function +const Bspp: React.FC = () => { + + // Set Date + const todayDate = new Date(); + const firstDayOfWeek = new Date(); + const lastDayOfWeek = new Date(); + firstDayOfWeek.setDate(todayDate.getDate() - todayDate.getDay() + 1); + lastDayOfWeek.setDate(todayDate.getDate() - todayDate.getDay() + 7); + const [teamTotalManhoursSpentSelect, setTeamTotalManhoursSpentSelect]: any = + React.useState("Weekly"); + const weekDates: any[] = []; + const monthDates: any[] = []; + const currentDate = dayjs(); + const sixMonthsAgo = currentDate.subtract(6, "month"); + for (let i = 0; i < 7; i++) { + const currentDate = new Date(firstDayOfWeek); + currentDate.setDate(firstDayOfWeek.getDate() + i); + const formattedDate = dayjs(currentDate).format("DD MMM (ddd)"); + weekDates.push(formattedDate); + } + for ( + let date = sixMonthsAgo.clone(); + date.isBefore(currentDate, "month"); + date = date.add(1, "month") + ) { + monthDates.push(date.format("MM-YYYY")); + } + monthDates.push(currentDate.format("MM-YYYY")); + const [teamTotalManhoursSpentPeriod, setTeamTotalManhoursSpentPeriod]: any[] = + React.useState(weekDates); + + // Set fake Data + const [ + teamTotalManhoursSpentPlanData, + setTeamTotalManhoursSpentPlanData, + ]: any[] = React.useState([42, 42, 42, 42, 42, 0, 0]); + const [ + teamTotalManhoursSpentActualData, + setTeamTotalManhoursSpentActualData, + ]: any[] = React.useState([45, 42, 60, 42, 58, 0, 0]); + const [hoveredDay, setHoveredDay] = React.useState(null); + const [value, setValue] = React.useState(dayjs()); + const [totalManHoursMonthlyFromValue, setTotalManHoursMonthlyFromValue] = + React.useState(dayjs(new Date()).subtract(6, "month")); + const [totalManHoursMonthlyToValue, setTotalManHoursMonthlyToValue] = + React.useState(dayjs()); + const [totalManHoursMaxValue, setTotalManHoursMaxValue] = React.useState(75); + + const teamOptions = [ + { value: 1, label: "XXX Team" }, + { value: 2, label: "YYY Team" }, + { value: 3, label: "ZZZ Team" }, + ]; + + // https://poe.com/ + // https://apexcharts.com/docs/chart-types/line-chart/ + // chart options + const options: ApexOptions = { + chart: { + height: 350, + type: "line", + }, + stroke: { + width: [2, 2], + }, + plotOptions: { + bar: { + horizontal: false, + distributed: false, + }, + }, + dataLabels: { + enabled: true, + }, + xaxis: { + categories: teamTotalManhoursSpentPeriod, + }, + yaxis: [ + { + title: { + text: "Team Total Manhours Spent (Hour)", + }, + min: 0, + max: totalManHoursMaxValue, + tickAmount: 5, + }, + ], + grid: { + borderColor: "#f1f1f1", + }, + annotations: {}, + series: [ + { + name: "Planned", + type: "line", + color: "#efbe7d", + data: teamTotalManhoursSpentPlanData, + }, + { + name: "Actual", + type: "line", + color: "#7cd3f2", + data: teamTotalManhoursSpentActualData, + }, + ], + }; + + // On click function + const teamTotalManhoursSpentOnClick = (r: any) => { + setTeamTotalManhoursSpentSelect(r); + if (r === "Weekly") { + setValue(dayjs(new Date())); + setTeamTotalManhoursSpentPeriod(weekDates); + setTeamTotalManhoursSpentPlanData([42, 42, 42, 42, 42, 0, 0]); + setTeamTotalManhoursSpentActualData([45, 42, 60, 42, 58, 0, 0]); + setTotalManHoursMaxValue(75); + } else if (r === "Monthly") { + setTeamTotalManhoursSpentPeriod(monthDates); + setTeamTotalManhoursSpentPlanData([840, 840, 840, 840, 840, 840]); + setTeamTotalManhoursSpentActualData([900, 840, 1200, 840, 1160, 840]); + setTotalManHoursMaxValue(1250); + } + }; + + const selectWeeklyPeriod = (r: any) => { + const selectDate = new Date(r); + const firstDayOfWeek = new Date(); + firstDayOfWeek.setDate(selectDate.getDate() - selectDate.getDay() + 0); + const weekDates: any[] = []; + for (let i = 0; i < 7; i++) { + const currentDate = new Date(firstDayOfWeek); + currentDate.setDate(firstDayOfWeek.getDate() + i); + const formattedDate = dayjs(currentDate).format("DD MMM (ddd)"); + weekDates.push(formattedDate); + } + setTeamTotalManhoursSpentPeriod(weekDates); + setValue(dayjs(firstDayOfWeek)); + }; + + const selectMonthlyPeriodFrom = (r: any) => { + const monthDates: any[] = []; + const monthPlanData: any[] = []; + const monthActualData: any[] = []; + const selectFromDate = dayjs(r); + for ( + let date = selectFromDate.clone(); + date.isBefore(totalManHoursMonthlyToValue, "month"); + date = date.add(1, "month") + ) { + monthDates.push(date.format("MM-YYYY")); + monthPlanData.push(840); + monthActualData.push(Math.floor(Math.random() * (1200 - 840) + 840)); + } + monthDates.push(totalManHoursMonthlyToValue.format("MM-YYYY")); + monthPlanData.push(840); + monthActualData.push(Math.floor(Math.random() * (1200 - 840) + 840)); + setTeamTotalManhoursSpentPlanData(monthPlanData); + setTeamTotalManhoursSpentActualData(monthActualData); + setTeamTotalManhoursSpentPeriod(monthDates); + }; + + const selectMonthlyPeriodTo = (r: any) => { + const monthDates: any[] = []; + const monthPlanData: any[] = []; + const monthActualData: any[] = []; + const selectToDate = dayjs(r); + for ( + let date = totalManHoursMonthlyFromValue.clone(); + date.isBefore(selectToDate, "month"); + date = date.add(1, "month") + ) { + monthDates.push(date.format("MM-YYYY")); + monthPlanData.push(840); + monthActualData.push(Math.floor(Math.random() * (1200 - 840) + 840)); + } + monthDates.push(selectToDate.format("MM-YYYY")); + monthPlanData.push(840); + monthActualData.push(Math.floor(Math.random() * (1200 - 840) + 840)); + setTeamTotalManhoursSpentPlanData(monthPlanData); + setTeamTotalManhoursSpentActualData(monthActualData); + setTeamTotalManhoursSpentPeriod(monthDates); + }; + + // render + return ( + <> + +
+
+ + + +
+ {/* Weekly / Monthly Button select */} + {/* Different: selected style & on click function */} +
+ {teamTotalManhoursSpentSelect === "Weekly" && ( + <> + + + + )} + {teamTotalManhoursSpentSelect === "Monthly" && ( + <> + + + + )} +
+ + {/* Team combo */} +
+ + {/* Label */} +
+ +
+ + {/* Select Option */} +
+