|
|
@@ -29,6 +29,9 @@ 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"; |
|
|
|
import Holidays from "date-holidays"; |
|
|
|
import moment from "moment"; |
|
|
|
import {fetchTeamCombo, fetchweeklyTeamTotalManhours, fetchmonthlyTeamTotalManhours,fetchTotalManhoursByGrade,fetchWeeklyUnsubmit,fetchMonthlyUnsubmit} from "@/app/api/staffUtilization"; |
|
|
|
|
|
|
|
dayjs.extend(isBetweenPlugin); |
|
|
|
interface CustomPickerDayProps extends PickersDayProps<Dayjs> { |
|
|
@@ -174,25 +177,31 @@ const StaffUtilization: React.FC = () => { |
|
|
|
const [ |
|
|
|
teamTotalManhoursSpentPlanData, |
|
|
|
setTeamTotalManhoursSpentPlanData, |
|
|
|
]: any[] = React.useState([42, 42, 42, 42, 42, 0, 0]); |
|
|
|
]: any[] = React.useState([0, 0, 0, 0, 0, 0, 0]); |
|
|
|
const [ |
|
|
|
teamTotalManhoursSpentActualData, |
|
|
|
setTeamTotalManhoursSpentActualData, |
|
|
|
]: any[] = React.useState([45, 42, 60, 42, 58, 0, 0]); |
|
|
|
]: any[] = React.useState([0, 0, 0, 0, 0, 0, 0]); |
|
|
|
const [hoveredDay, setHoveredDay] = React.useState<Dayjs | null>(null); |
|
|
|
const [value, setValue] = React.useState<Dayjs | null>(dayjs()); |
|
|
|
const [value, setValue] = React.useState<Dayjs>(dayjs().startOf('week')); |
|
|
|
const [weeklyValueByStaffGrade, setWeeklyValueByStaffGrade] = |
|
|
|
React.useState<Dayjs | null>(dayjs()); |
|
|
|
React.useState<Dayjs>(dayjs().startOf('week')); |
|
|
|
const [weeklyToValueByStaffGrade, setWeeklyToValueByStaffGrade] = |
|
|
|
React.useState<Dayjs>(dayjs().startOf('week').add(6, 'day')); |
|
|
|
const [weeklyValueByIndividualStaff, setWeeklyValueByIndividualStaff] = |
|
|
|
React.useState<Dayjs | null>(dayjs()); |
|
|
|
React.useState<Dayjs>(dayjs().startOf('week')); |
|
|
|
const [weeklyUnsubmittedTimeSheet, setWeeklyUnsubmittedTimeSheet ] = |
|
|
|
React.useState<Dayjs | null>(dayjs()); |
|
|
|
React.useState<Dayjs>(dayjs().startOf('week')); |
|
|
|
const [staffGradeManhoursSpentValue, setStaffGradeManhoursSpentValue] = |
|
|
|
React.useState<Dayjs | null>(dayjs()); |
|
|
|
React.useState<Dayjs>(dayjs()); |
|
|
|
const [totalManHoursMonthlyFromValue, setTotalManHoursMonthlyFromValue] = |
|
|
|
React.useState<Dayjs>(dayjs(new Date()).subtract(6, "month")); |
|
|
|
const [totalManHoursMonthlyToValue, setTotalManHoursMonthlyToValue] = |
|
|
|
React.useState<Dayjs>(dayjs()); |
|
|
|
const [unsubmitMonthlyFromValue, setUnsubmitMonthlyFromValue] = |
|
|
|
React.useState<Dayjs>(dayjs(new Date()).subtract(6, "month")); |
|
|
|
const [unsubmitMonthlyToValue, setUnsubmitMonthlyToValue] = |
|
|
|
React.useState<Dayjs>(dayjs()); |
|
|
|
const [ |
|
|
|
totalManHoursByStaffGradeMonthlyFromValue, |
|
|
|
setTotalManHoursByStaffGradeMonthlyFromValue, |
|
|
@@ -217,7 +226,284 @@ const StaffUtilization: React.FC = () => { |
|
|
|
totalManHoursByIndividualStaffDailyToValue, |
|
|
|
setTotalManHoursByIndividualStaffDailyToValue, |
|
|
|
] = React.useState<Dayjs>(dayjs()); |
|
|
|
const [totalManHoursMaxValue, setTotalManHoursMaxValue] = React.useState(75); |
|
|
|
const hd = new Holidays('HK'); |
|
|
|
const currentYear = new Date().getFullYear(); |
|
|
|
const years = [currentYear -2, currentYear - 1, currentYear, currentYear + 1, currentYear + 2]; |
|
|
|
let allHolidays: any[] = []; |
|
|
|
years.forEach(year => { |
|
|
|
const holidays = hd.getHolidays(year); |
|
|
|
allHolidays = allHolidays.concat(holidays); |
|
|
|
}); |
|
|
|
const holidayDates = allHolidays.map(holiday => moment(holiday.date).format('YYYY-MM-DD')).join(','); |
|
|
|
const [totalManHoursMaxValue, setTotalManHoursMaxValue] = React.useState(5); |
|
|
|
const [totalManHoursByGradeMaxValue, setTotalManHoursByGradeMaxValue] = React.useState(5); |
|
|
|
const [totalManhourByGradeActualManhours, setTotalManhourByGradeActualManhours]:any[] = React.useState([]); |
|
|
|
const [totalManhourByGradePlannedManhours, setTotalManhourByGradePlannedManhours]:any[] = React.useState([]); |
|
|
|
const [gradeNameList, setGradeNameList]:any[] = React.useState([]); |
|
|
|
const [teamManhoursTeamOptions, setTeamManhoursTeamOptions]: any[] = React.useState([]); |
|
|
|
const [teamManhoursTeamId, setTeamManhoursTeamId]: any[] = React.useState(0); |
|
|
|
const [teamUnsubmitTeamId, setTeamUnsubmitTeamId]: any[] = React.useState(0); |
|
|
|
const [unsubmitCount, setUnsubmitCount]: any[] = React.useState([]); |
|
|
|
const [unsubmitStaffList, setUnsubmitStaffList]: any[] = React.useState([]); |
|
|
|
const fetchComboData = async () => { |
|
|
|
const teamComboList = [] |
|
|
|
const teamCombo = await fetchTeamCombo(); |
|
|
|
for (var i = 0; i < teamCombo.records.length; i++) { |
|
|
|
teamComboList.push({value: teamCombo.records[i].id, label: teamCombo.records[i].label}) |
|
|
|
} |
|
|
|
setTeamManhoursTeamOptions(teamComboList) |
|
|
|
} |
|
|
|
|
|
|
|
const fetchWeeklyTeamManhourSpentData = async () => { |
|
|
|
const fetchResult = await fetchweeklyTeamTotalManhours(teamManhoursTeamId,value.format('YYYY-MM-DD')); |
|
|
|
const weeklyActual = fetchResult[0].weeklyActualTeamTotalManhoursSpent |
|
|
|
const weeklyPlanned = fetchResult[0].weeklyPlannedTeamTotalManhoursSpent |
|
|
|
const weeklyActualList = [] |
|
|
|
const weeklyPlannedList = [] |
|
|
|
var chartMax = 5 |
|
|
|
for (var i = 0; i < weeklyActual.length; i++) { |
|
|
|
if (chartMax < weeklyActual[i].TotalManhourConsumed) { |
|
|
|
chartMax = weeklyActual[i].TotalManhourConsumed |
|
|
|
} |
|
|
|
weeklyActualList.push(weeklyActual[i].TotalManhourConsumed) |
|
|
|
} |
|
|
|
if (weekDates.length > 0) { |
|
|
|
for (var i = 0; i < weeklyPlanned.length; i++) { |
|
|
|
const weeklyPlannedSubList = [] |
|
|
|
const startCount = weeklyPlanned[i].startCount |
|
|
|
const endCount = weeklyPlanned[i].endCount |
|
|
|
for (var j = 0; j < weeklyPlanned[i].searchDuration; j++) { |
|
|
|
if (j >= startCount && j < endCount) { |
|
|
|
weeklyPlannedSubList.push(weeklyPlanned[i].AverageManhours) |
|
|
|
} else { |
|
|
|
weeklyPlannedSubList.push(0) |
|
|
|
} |
|
|
|
} |
|
|
|
weeklyPlannedList.push(weeklyPlannedSubList) |
|
|
|
} |
|
|
|
if (weeklyPlannedList.length > 0) { |
|
|
|
const result = new Array(weeklyPlannedList[0].length).fill(0); |
|
|
|
for (const arr of weeklyPlannedList) { |
|
|
|
for (let i = 0; i < arr.length; i++) { |
|
|
|
result[i] += arr[i]; |
|
|
|
if (chartMax < result[i]) { |
|
|
|
chartMax = result[i] |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
setTeamTotalManhoursSpentPlanData(result) |
|
|
|
} |
|
|
|
} |
|
|
|
setTeamTotalManhoursSpentActualData(weeklyActualList); |
|
|
|
setTotalManHoursMaxValue(chartMax) |
|
|
|
} |
|
|
|
const fetchMonthlyTeamManhourSpentData = async () => { |
|
|
|
const fetchResult = await fetchmonthlyTeamTotalManhours(teamManhoursTeamId, totalManHoursMonthlyFromValue.format('YYYY-MM-DD'), totalManHoursMonthlyToValue.endOf('month').format('YYYY-MM-DD')); |
|
|
|
const weeklyActual = fetchResult[0].monthlyActualTeamTotalManhoursSpent |
|
|
|
const weeklyPlanned = fetchResult[0].monthlyPlannedTeamTotalManhoursSpent |
|
|
|
const weeklyActualList = [] |
|
|
|
const weeklyPlannedList = [] |
|
|
|
var chartMax = 5 |
|
|
|
for (var i = 0; i < weeklyActual.length; i++) { |
|
|
|
if (chartMax < weeklyActual[i].TotalManhourConsumed) { |
|
|
|
chartMax = weeklyActual[i].TotalManhourConsumed |
|
|
|
} |
|
|
|
weeklyActualList.push(weeklyActual[i].TotalManhourConsumed) |
|
|
|
} |
|
|
|
if (weekDates.length > 0) { |
|
|
|
for (var i = 0; i < weeklyPlanned.length; i++) { |
|
|
|
const weeklyPlannedSubList = [] |
|
|
|
const startCount = weeklyPlanned[i].startCount |
|
|
|
const endCount = weeklyPlanned[i].endCount |
|
|
|
for (var j = 0; j < weeklyPlanned[i].searchDuration; j++) { |
|
|
|
if (j >= startCount && j < endCount) { |
|
|
|
weeklyPlannedSubList.push(weeklyPlanned[i].AverageManhours) |
|
|
|
} else { |
|
|
|
weeklyPlannedSubList.push(0) |
|
|
|
} |
|
|
|
} |
|
|
|
weeklyPlannedList.push(weeklyPlannedSubList) |
|
|
|
} |
|
|
|
if (weeklyPlannedList.length > 0) { |
|
|
|
const result = new Array(weeklyPlannedList[0].length).fill(0); |
|
|
|
for (const arr of weeklyPlannedList) { |
|
|
|
for (let i = 0; i < arr.length; i++) { |
|
|
|
result[i] += arr[i]; |
|
|
|
if (chartMax < result[i]) { |
|
|
|
chartMax = result[i] |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
setTeamTotalManhoursSpentPlanData(result) |
|
|
|
} |
|
|
|
} |
|
|
|
setTeamTotalManhoursSpentActualData(weeklyActualList); |
|
|
|
setTotalManHoursMaxValue(chartMax) |
|
|
|
} |
|
|
|
|
|
|
|
const fetchTotalManhoursByGradeData = async () => { |
|
|
|
const fetchResult = await fetchTotalManhoursByGrade(weeklyValueByStaffGrade.format('YYYY-MM-DD'), weeklyToValueByStaffGrade.format('YYYY-MM-DD')); |
|
|
|
const actualManhours = fetchResult[0].staffGradeTotalManhours |
|
|
|
const plannedManhours = fetchResult[0].staffGradeTotalPlannedManhours |
|
|
|
var chartMax = 5 |
|
|
|
const gradeList = [] |
|
|
|
const actualList = [] |
|
|
|
const plannedList = [] |
|
|
|
|
|
|
|
var manhours = 0 |
|
|
|
for (var i = 0; i < actualManhours.length; i++) { |
|
|
|
actualList.push(actualManhours[i].manhours.toFixed(2)) |
|
|
|
gradeList.push(actualManhours[i].gradeName) |
|
|
|
if (chartMax < actualManhours[i].manhours) { |
|
|
|
chartMax = actualManhours[i].manhours |
|
|
|
} |
|
|
|
} |
|
|
|
if (plannedManhours.length > 0) { |
|
|
|
var gradeId = plannedManhours[0].id |
|
|
|
for (var i = 0; i < plannedManhours.length; i++) { |
|
|
|
if (plannedManhours[i].id === gradeId) { |
|
|
|
manhours += (plannedManhours[i].searchDuration - plannedManhours[i].startDiff - plannedManhours[i].endDiff) * plannedManhours[i].avgGradeManhour |
|
|
|
if (chartMax < manhours) { |
|
|
|
chartMax = manhours |
|
|
|
} |
|
|
|
if (i === plannedManhours.length - 1) { |
|
|
|
plannedList.push(manhours.toFixed(2)) |
|
|
|
} |
|
|
|
} else { |
|
|
|
plannedList.push(manhours.toFixed(2)) |
|
|
|
manhours = 0 |
|
|
|
gradeId = plannedManhours[i].id |
|
|
|
manhours += (plannedManhours[i].searchDuration - plannedManhours[i].startDiff - plannedManhours[i].endDiff) * plannedManhours[i].avgGradeManhour |
|
|
|
if (chartMax < manhours) { |
|
|
|
chartMax = manhours |
|
|
|
} |
|
|
|
if (i === plannedManhours.length - 1) { |
|
|
|
plannedList.push(manhours.toFixed(2)) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
setGradeNameList(gradeList) |
|
|
|
setTotalManhourByGradePlannedManhours(plannedList) |
|
|
|
setTotalManhourByGradeActualManhours(actualList); |
|
|
|
setTotalManHoursByGradeMaxValue(chartMax) |
|
|
|
} |
|
|
|
const fetchMonthlyTotalManhoursByGradeData = async () => { |
|
|
|
const fetchResult = await fetchTotalManhoursByGrade(totalManHoursMonthlyFromValue.format('YYYY-MM-DD'), totalManHoursMonthlyToValue.endOf('month').format('YYYY-MM-DD')); |
|
|
|
const actualManhours = fetchResult[0].staffGradeTotalManhours |
|
|
|
const plannedManhours = fetchResult[0].staffGradeTotalPlannedManhours |
|
|
|
var chartMax = 5 |
|
|
|
const gradeList = [] |
|
|
|
const actualList = [] |
|
|
|
const plannedList = [] |
|
|
|
|
|
|
|
var manhours = 0 |
|
|
|
for (var i = 0; i < actualManhours.length; i++) { |
|
|
|
actualList.push(actualManhours[i].manhours.toFixed(2)) |
|
|
|
gradeList.push(actualManhours[i].gradeName) |
|
|
|
if (chartMax < actualManhours[i].manhours) { |
|
|
|
chartMax = actualManhours[i].manhours |
|
|
|
} |
|
|
|
} |
|
|
|
if (plannedManhours.length > 0) { |
|
|
|
var gradeId = plannedManhours[0].id |
|
|
|
for (var i = 0; i < plannedManhours.length; i++) { |
|
|
|
if (plannedManhours[i].id === gradeId) { |
|
|
|
manhours += (plannedManhours[i].searchDuration - plannedManhours[i].startDiff - plannedManhours[i].endDiff) * plannedManhours[i].avgGradeManhour |
|
|
|
if (chartMax < manhours) { |
|
|
|
chartMax = manhours |
|
|
|
} |
|
|
|
if (i === plannedManhours.length - 1) { |
|
|
|
plannedList.push(manhours.toFixed(2)) |
|
|
|
} |
|
|
|
} else { |
|
|
|
plannedList.push(manhours.toFixed(2)) |
|
|
|
manhours = 0 |
|
|
|
gradeId = plannedManhours[i].id |
|
|
|
manhours += (plannedManhours[i].searchDuration - plannedManhours[i].startDiff - plannedManhours[i].endDiff) * plannedManhours[i].avgGradeManhour |
|
|
|
if (chartMax < manhours) { |
|
|
|
chartMax = manhours |
|
|
|
} |
|
|
|
if (i === plannedManhours.length - 1) { |
|
|
|
plannedList.push(manhours.toFixed(2)) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
setGradeNameList(gradeList) |
|
|
|
setTotalManhourByGradePlannedManhours(plannedList) |
|
|
|
setTotalManhourByGradeActualManhours(actualList); |
|
|
|
setTotalManHoursByGradeMaxValue(chartMax) |
|
|
|
} |
|
|
|
const fetchWeeklyUnsubmittedData = async () => { |
|
|
|
const fetchResult = await fetchWeeklyUnsubmit(teamUnsubmitTeamId, weeklyUnsubmittedTimeSheet.format('YYYY-MM-DD'), holidayDates); |
|
|
|
const result = [] |
|
|
|
const staffList = [] |
|
|
|
for (var i = 0; i < fetchResult.length; i++) { |
|
|
|
result.push(fetchResult[i].UnsubmittedCount) |
|
|
|
staffList.push(fetchResult[i].name) |
|
|
|
} |
|
|
|
setUnsubmitCount(result) |
|
|
|
setUnsubmitStaffList(staffList) |
|
|
|
} |
|
|
|
const fetchMonthlyUnsubmittedData = async () => { |
|
|
|
const fetchResult = await fetchMonthlyUnsubmit(teamUnsubmitTeamId, unsubmitMonthlyFromValue.format('YYYY-MM-DD'), unsubmitMonthlyToValue.endOf('month').format('YYYY-MM-DD'), holidayDates); |
|
|
|
console.log(fetchResult) |
|
|
|
const result = [] |
|
|
|
const staffList = [] |
|
|
|
for (var i = 0; i < fetchResult.length; i++) { |
|
|
|
result.push(fetchResult[i].UnsubmittedCount) |
|
|
|
staffList.push(fetchResult[i].name) |
|
|
|
} |
|
|
|
setUnsubmitCount(result) |
|
|
|
setUnsubmitStaffList(staffList) |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
useEffect(() => { |
|
|
|
fetchComboData() |
|
|
|
}, []); |
|
|
|
|
|
|
|
|
|
|
|
useEffect(() => { |
|
|
|
if (teamTotalManhoursSpentSelect === "Weekly"){ |
|
|
|
fetchWeeklyTeamManhourSpentData() |
|
|
|
} |
|
|
|
}, [value,teamManhoursTeamId]); |
|
|
|
|
|
|
|
useEffect(() => { |
|
|
|
if (teamTotalManhoursSpentSelect === "Monthly"){ |
|
|
|
fetchMonthlyTeamManhourSpentData() |
|
|
|
} |
|
|
|
}, [totalManHoursMonthlyFromValue,totalManHoursMonthlyToValue,teamManhoursTeamId]); |
|
|
|
|
|
|
|
useEffect(() => { |
|
|
|
if (staffGradeManhoursSpentSelect === "Weekly"){ |
|
|
|
fetchTotalManhoursByGradeData() |
|
|
|
} |
|
|
|
}, [weeklyValueByStaffGrade,weeklyToValueByStaffGrade]); |
|
|
|
|
|
|
|
useEffect(() => { |
|
|
|
if (staffGradeManhoursSpentSelect === "Monthly"){ |
|
|
|
fetchMonthlyTotalManhoursByGradeData() |
|
|
|
} |
|
|
|
}, [totalManHoursMonthlyFromValue,totalManHoursMonthlyToValue]); |
|
|
|
|
|
|
|
useEffect(() => { |
|
|
|
if (unsubmittedTimeSheetSelect === "Weekly"){ |
|
|
|
fetchWeeklyUnsubmittedData() |
|
|
|
} |
|
|
|
}, [teamUnsubmitTeamId, weeklyUnsubmittedTimeSheet]); |
|
|
|
|
|
|
|
useEffect(() => { |
|
|
|
if (unsubmittedTimeSheetSelect === "Monthly"){ |
|
|
|
fetchMonthlyUnsubmittedData() |
|
|
|
} |
|
|
|
}, [unsubmitMonthlyFromValue, unsubmitMonthlyToValue]); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const teamOptions = [ |
|
|
|
{ value: 1, label: "XXX Team" }, |
|
|
@@ -344,13 +630,7 @@ const StaffUtilization: React.FC = () => { |
|
|
|
enabled: true, |
|
|
|
}, |
|
|
|
xaxis: { |
|
|
|
categories: [ |
|
|
|
"Grade 1: A. QS / QS Trainee", |
|
|
|
"Grade 2: QS", |
|
|
|
"Grade 3: Senior QS", |
|
|
|
"Grade 4: Manager", |
|
|
|
"Grade 5: Director", |
|
|
|
], |
|
|
|
categories: gradeNameList, |
|
|
|
}, |
|
|
|
yaxis: [ |
|
|
|
{ |
|
|
@@ -358,7 +638,7 @@ const StaffUtilization: React.FC = () => { |
|
|
|
text: "Staff Grade", |
|
|
|
}, |
|
|
|
min: 0, |
|
|
|
max: 60, |
|
|
|
max: totalManHoursByGradeMaxValue, |
|
|
|
tickAmount: 5, |
|
|
|
}, |
|
|
|
], |
|
|
@@ -371,13 +651,13 @@ const StaffUtilization: React.FC = () => { |
|
|
|
name: "Planned", |
|
|
|
type: "bar", |
|
|
|
color: "#efbe7d", |
|
|
|
data: [35, 45, 35, 20, 10], |
|
|
|
data: totalManhourByGradePlannedManhours, |
|
|
|
}, |
|
|
|
{ |
|
|
|
name: "Actual", |
|
|
|
type: "bar", |
|
|
|
color: "#00acb1", |
|
|
|
data: [25, 26, 33, 20, 11], |
|
|
|
data: totalManhourByGradeActualManhours, |
|
|
|
}, |
|
|
|
], |
|
|
|
}; |
|
|
@@ -450,13 +730,7 @@ const StaffUtilization: React.FC = () => { |
|
|
|
enabled: true, |
|
|
|
}, |
|
|
|
xaxis: { |
|
|
|
categories: [ |
|
|
|
"001-Staff A", |
|
|
|
"002-Staff B", |
|
|
|
"005-Staff E", |
|
|
|
"006-Staff F", |
|
|
|
"007-Staff G", |
|
|
|
], |
|
|
|
categories: unsubmitStaffList, |
|
|
|
}, |
|
|
|
yaxis: [ |
|
|
|
{ |
|
|
@@ -464,7 +738,7 @@ const StaffUtilization: React.FC = () => { |
|
|
|
text: "Staff", |
|
|
|
}, |
|
|
|
min: 0, |
|
|
|
max: 12, |
|
|
|
max: 5, |
|
|
|
tickAmount: 5, |
|
|
|
}, |
|
|
|
], |
|
|
@@ -477,7 +751,7 @@ const StaffUtilization: React.FC = () => { |
|
|
|
name: "Unsubmitted Time Sheet", |
|
|
|
type: "bar", |
|
|
|
color: "#00acb1", |
|
|
|
data: [2, 2, 1, 5, 1], |
|
|
|
data: unsubmitCount, |
|
|
|
}, |
|
|
|
], |
|
|
|
}; |
|
|
@@ -485,16 +759,12 @@ const StaffUtilization: React.FC = () => { |
|
|
|
const teamTotalManhoursSpentOnClick = (r: any) => { |
|
|
|
setTeamTotalManhoursSpentSelect(r); |
|
|
|
if (r === "Weekly") { |
|
|
|
setValue(dayjs(new Date())); |
|
|
|
fetchWeeklyTeamManhourSpentData() |
|
|
|
setValue(dayjs().startOf('week')); |
|
|
|
setTeamTotalManhoursSpentPeriod(weekDates); |
|
|
|
setTeamTotalManhoursSpentPlanData([42, 42, 42, 42, 42, 0, 0]); |
|
|
|
setTeamTotalManhoursSpentActualData([45, 42, 60, 42, 58, 0, 0]); |
|
|
|
setTotalManHoursMaxValue(75); |
|
|
|
} else if (r === "Monthly") { |
|
|
|
fetchMonthlyTeamManhourSpentData() |
|
|
|
setTeamTotalManhoursSpentPeriod(monthDates); |
|
|
|
setTeamTotalManhoursSpentPlanData([840, 840, 840, 840, 840, 840]); |
|
|
|
setTeamTotalManhoursSpentActualData([900, 840, 1200, 840, 1160, 840]); |
|
|
|
setTotalManHoursMaxValue(1250); |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
@@ -520,9 +790,10 @@ const StaffUtilization: React.FC = () => { |
|
|
|
|
|
|
|
const selectWeeklyPeriod = (r: any) => { |
|
|
|
const selectDate = new Date(r); |
|
|
|
const firstDayOfWeek = new Date(); |
|
|
|
const firstDayOfWeek = selectDate; |
|
|
|
firstDayOfWeek.setDate(selectDate.getDate() - selectDate.getDay() + 0); |
|
|
|
const weekDates: any[] = []; |
|
|
|
const weekFirstDate = new Date(firstDayOfWeek); |
|
|
|
for (let i = 0; i < 7; i++) { |
|
|
|
const currentDate = new Date(firstDayOfWeek); |
|
|
|
currentDate.setDate(firstDayOfWeek.getDate() + i); |
|
|
@@ -535,7 +806,7 @@ const StaffUtilization: React.FC = () => { |
|
|
|
|
|
|
|
const selectWeeklyPeriodByStaffGrade = (r: any) => { |
|
|
|
const selectDate = new Date(r); |
|
|
|
const firstDayOfWeek = new Date(); |
|
|
|
const firstDayOfWeek = selectDate |
|
|
|
firstDayOfWeek.setDate(selectDate.getDate() - selectDate.getDay() + 0); |
|
|
|
const weekDates: any[] = []; |
|
|
|
for (let i = 0; i < 7; i++) { |
|
|
@@ -546,11 +817,12 @@ const StaffUtilization: React.FC = () => { |
|
|
|
} |
|
|
|
setTeamTotalManhoursByStaffGrade(weekDates); |
|
|
|
setWeeklyValueByStaffGrade(dayjs(firstDayOfWeek)); |
|
|
|
setWeeklyToValueByStaffGrade(dayjs(firstDayOfWeek).add(6, 'day')) |
|
|
|
}; |
|
|
|
|
|
|
|
const selectWeeklyPeriodUnsubmittedTimeSheet = (r: any) => { |
|
|
|
const selectDate = new Date(r); |
|
|
|
const firstDayOfWeek = new Date(); |
|
|
|
const firstDayOfWeek = selectDate; |
|
|
|
firstDayOfWeek.setDate(selectDate.getDate() - selectDate.getDay() + 0); |
|
|
|
const weekDates: any[] = []; |
|
|
|
for (let i = 0; i < 7; i++) { |
|
|
@@ -579,6 +851,7 @@ const StaffUtilization: React.FC = () => { |
|
|
|
}; |
|
|
|
|
|
|
|
const selectMonthlyPeriodFrom = (r: any) => { |
|
|
|
setTotalManHoursMonthlyFromValue(r) |
|
|
|
const monthDates: any[] = []; |
|
|
|
const monthPlanData: any[] = []; |
|
|
|
const monthActualData: any[] = []; |
|
|
@@ -601,6 +874,7 @@ const StaffUtilization: React.FC = () => { |
|
|
|
}; |
|
|
|
|
|
|
|
const selectMonthlyPeriodTo = (r: any) => { |
|
|
|
setTotalManHoursMonthlyToValue(r) |
|
|
|
const monthDates: any[] = []; |
|
|
|
const monthPlanData: any[] = []; |
|
|
|
const monthActualData: any[] = []; |
|
|
@@ -623,6 +897,7 @@ const StaffUtilization: React.FC = () => { |
|
|
|
}; |
|
|
|
|
|
|
|
const selectStaffGradeMonthlyPeriodFrom = (r: any) => { |
|
|
|
setTotalManHoursMonthlyFromValue(r) |
|
|
|
const monthDates: any[] = []; |
|
|
|
const monthPlanData: any[] = []; |
|
|
|
const monthActualData: any[] = []; |
|
|
@@ -645,6 +920,7 @@ const StaffUtilization: React.FC = () => { |
|
|
|
}; |
|
|
|
|
|
|
|
const selectStaffGradeMonthlyPeriodTo = (r: any) => { |
|
|
|
setTotalManHoursMonthlyToValue(r) |
|
|
|
const monthDates: any[] = []; |
|
|
|
const monthPlanData: any[] = []; |
|
|
|
const monthActualData: any[] = []; |
|
|
@@ -667,20 +943,21 @@ const StaffUtilization: React.FC = () => { |
|
|
|
}; |
|
|
|
|
|
|
|
const selectUnsubmittedTimeSheetMonthlyPeriodFrom = (r: any) => { |
|
|
|
setUnsubmitMonthlyFromValue(r) |
|
|
|
const monthDates: any[] = []; |
|
|
|
const monthPlanData: any[] = []; |
|
|
|
const monthActualData: any[] = []; |
|
|
|
const selectFromDate = dayjs(r); |
|
|
|
for ( |
|
|
|
let date = selectFromDate.clone(); |
|
|
|
date.isBefore(totalManHoursMonthlyToValue, "month"); |
|
|
|
date.isBefore(unsubmitMonthlyToValue, "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")); |
|
|
|
monthDates.push(selectFromDate.format("MM-YYYY")); |
|
|
|
monthPlanData.push(840); |
|
|
|
monthActualData.push(Math.floor(Math.random() * (1200 - 840) + 840)); |
|
|
|
// setTeamTotalManhoursSpentPlanData(monthPlanData) |
|
|
@@ -689,6 +966,7 @@ const StaffUtilization: React.FC = () => { |
|
|
|
}; |
|
|
|
|
|
|
|
const selectIndividualStaffMonthlyPeriodFrom = (r: any) => { |
|
|
|
setTotalManHoursMonthlyFromValue(r) |
|
|
|
const monthDates: any[] = []; |
|
|
|
const monthPlanData: any[] = []; |
|
|
|
const monthActualData: any[] = []; |
|
|
@@ -699,24 +977,25 @@ const StaffUtilization: React.FC = () => { |
|
|
|
date = date.add(1, "month") |
|
|
|
) { |
|
|
|
monthDates.push(date.format("MM-YYYY")); |
|
|
|
monthPlanData.push(840); |
|
|
|
monthActualData.push(Math.floor(Math.random() * (1200 - 840) + 840)); |
|
|
|
// 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)); |
|
|
|
monthDates.push(selectFromDate.format("MM-YYYY")); |
|
|
|
// monthPlanData.push(840); |
|
|
|
// monthActualData.push(Math.floor(Math.random() * (1200 - 840) + 840)); |
|
|
|
// setTeamTotalManhoursSpentPlanData(monthPlanData) |
|
|
|
// setTeamTotalManhoursSpentActualData(monthActualData) |
|
|
|
setIndividualStaffManhoursSpentPeriod(weekDates); |
|
|
|
}; |
|
|
|
|
|
|
|
const selectUnsubmittedTimeSheetMonthlyPeriodTo = (r: any) => { |
|
|
|
setUnsubmitMonthlyToValue(r) |
|
|
|
const monthDates: any[] = []; |
|
|
|
const monthPlanData: any[] = []; |
|
|
|
const monthActualData: any[] = []; |
|
|
|
const selectToDate = dayjs(r); |
|
|
|
for ( |
|
|
|
let date = totalManHoursMonthlyFromValue.clone(); |
|
|
|
let date = unsubmitMonthlyFromValue.clone(); |
|
|
|
date.isBefore(selectToDate, "month"); |
|
|
|
date = date.add(1, "month") |
|
|
|
) { |
|
|
@@ -733,6 +1012,7 @@ const StaffUtilization: React.FC = () => { |
|
|
|
}; |
|
|
|
|
|
|
|
const selectIndividualStaffMonthlyPeriodTo = (r: any) => { |
|
|
|
setTotalManHoursMonthlyToValue(r) |
|
|
|
const monthDates: any[] = []; |
|
|
|
const monthPlanData: any[] = []; |
|
|
|
const monthActualData: any[] = []; |
|
|
@@ -859,9 +1139,16 @@ const StaffUtilization: React.FC = () => { |
|
|
|
</div> |
|
|
|
<div className="inline-block ml-1 w-60"> |
|
|
|
<Select |
|
|
|
placeholder="All Team" |
|
|
|
options={teamOptions} |
|
|
|
placeholder="Please select a team" |
|
|
|
options={teamManhoursTeamOptions} |
|
|
|
isClearable={true} |
|
|
|
onChange={(selectedOption:any) => { |
|
|
|
if (selectedOption === null) { |
|
|
|
setTeamManhoursTeamId(null); |
|
|
|
} else { |
|
|
|
setTeamManhoursTeamId(selectedOption.value); |
|
|
|
} |
|
|
|
}} |
|
|
|
/> |
|
|
|
</div> |
|
|
|
<div className="ml-6 mt-2" style={{ verticalAlign: "top" }}> |
|
|
@@ -875,9 +1162,10 @@ const StaffUtilization: React.FC = () => { |
|
|
|
label="Period:" |
|
|
|
value={value} |
|
|
|
format="DD-MM-YYYY" |
|
|
|
onChange={(newValue) => |
|
|
|
onChange={(newValue) => { |
|
|
|
selectWeeklyPeriod(newValue) |
|
|
|
} |
|
|
|
} |
|
|
|
showDaysOutsideCurrentMonth |
|
|
|
displayWeekNumber |
|
|
|
slots={{ day: Day }} |
|
|
@@ -944,8 +1232,10 @@ const StaffUtilization: React.FC = () => { |
|
|
|
Weekly |
|
|
|
</button> |
|
|
|
<button |
|
|
|
onClick={() => |
|
|
|
onClick={() => { |
|
|
|
setStaffGradeManhoursSpentSelect("Monthly") |
|
|
|
fetchMonthlyTotalManhoursByGradeData() |
|
|
|
} |
|
|
|
} |
|
|
|
className="hover:cursor-pointer hover:bg-violet-50 text-lg bg-transparent border-violet-500 text-violet-500 border-solid rounded-r-md w-48" |
|
|
|
> |
|
|
@@ -956,8 +1246,10 @@ const StaffUtilization: React.FC = () => { |
|
|
|
{staffGradeManhoursSpentSelect === "Monthly" && ( |
|
|
|
<> |
|
|
|
<button |
|
|
|
onClick={() => |
|
|
|
onClick={() => { |
|
|
|
setStaffGradeManhoursSpentSelect("Weekly") |
|
|
|
fetchTotalManhoursByGradeData() |
|
|
|
} |
|
|
|
} |
|
|
|
className="hover:cursor-pointer hover:bg-violet-50 text-lg bg-transparent border-violet-500 text-violet-500 border-solid rounded-l-md w-32" |
|
|
|
> |
|
|
@@ -976,7 +1268,7 @@ const StaffUtilization: React.FC = () => { |
|
|
|
<DatePicker |
|
|
|
className="w-72 h-10 align-top" |
|
|
|
label="Period:" |
|
|
|
value={value} |
|
|
|
value={weeklyValueByStaffGrade} |
|
|
|
format="DD-MM-YYYY" |
|
|
|
onChange={(newValue) => |
|
|
|
selectWeeklyPeriodByStaffGrade(newValue) |
|
|
@@ -1069,7 +1361,10 @@ const StaffUtilization: React.FC = () => { |
|
|
|
</button> |
|
|
|
<button |
|
|
|
onClick={() => |
|
|
|
{ |
|
|
|
unsubmittedTimeSheetOnClick("Monthly") |
|
|
|
fetchMonthlyUnsubmittedData() |
|
|
|
} |
|
|
|
} |
|
|
|
className="hover:cursor-pointer hover:bg-violet-50 text-lg bg-transparent border-violet-500 text-violet-500 border-solid rounded-r-md w-32" |
|
|
|
> |
|
|
@@ -1081,7 +1376,10 @@ const StaffUtilization: React.FC = () => { |
|
|
|
<> |
|
|
|
<button |
|
|
|
onClick={() => |
|
|
|
{ |
|
|
|
unsubmittedTimeSheetOnClick("Weekly") |
|
|
|
fetchWeeklyUnsubmittedData() |
|
|
|
} |
|
|
|
} |
|
|
|
className="hover:cursor-pointer hover:bg-violet-50 text-lg bg-transparent border-violet-500 text-violet-500 border-solid w-32" |
|
|
|
> |
|
|
@@ -1101,9 +1399,16 @@ const StaffUtilization: React.FC = () => { |
|
|
|
</div> |
|
|
|
<div className="inline-block ml-1 w-60"> |
|
|
|
<Select |
|
|
|
placeholder="Team" |
|
|
|
options={teamOptions} |
|
|
|
placeholder="Please select a team" |
|
|
|
options={teamManhoursTeamOptions} |
|
|
|
isClearable={true} |
|
|
|
onChange={(selectedOption:any) => { |
|
|
|
if (selectedOption === null) { |
|
|
|
setTeamUnsubmitTeamId(null); |
|
|
|
} else { |
|
|
|
setTeamUnsubmitTeamId(selectedOption.value); |
|
|
|
} |
|
|
|
}} |
|
|
|
/> |
|
|
|
</div> |
|
|
|
<div className="ml-6 mt-2" style={{ verticalAlign: "top" }}> |
|
|
@@ -1259,9 +1564,16 @@ const StaffUtilization: React.FC = () => { |
|
|
|
</div> |
|
|
|
<div className="inline-block ml-1 w-60"> |
|
|
|
<Select |
|
|
|
placeholder="00338-Chris Wong" |
|
|
|
options={teamOptions} |
|
|
|
placeholder="Please select a team" |
|
|
|
options={teamManhoursTeamOptions} |
|
|
|
isClearable={true} |
|
|
|
onChange={(selectedOption:any) => { |
|
|
|
if (selectedOption === null) { |
|
|
|
setTeamUnsubmitTeamId(null); |
|
|
|
} else { |
|
|
|
setTeamUnsubmitTeamId(selectedOption.value); |
|
|
|
} |
|
|
|
}} |
|
|
|
/> |
|
|
|
</div> |
|
|
|
<div className="ml-6 mt-2" style={{ verticalAlign: "top" }}> |
|
|
|