|
- import {
- RecordLeaveInput,
- RecordTimesheetInput,
- } from "@/app/api/timesheets/actions";
- import {
- Box,
- Card,
- CardActionArea,
- CardContent,
- Stack,
- Typography,
- } from "@mui/material";
- import union from "lodash/union";
- import { useCallback, useEffect, useMemo } from "react";
- import dayjs, { Dayjs } from "dayjs";
- import { getHolidayForDate, getPublicHolidaysForNYears } from "@/app/utils/holidayUtils";
- import { HolidaysResult } from "@/app/api/holidays";
- import { manhourFormatter, shortDateFormatter } from "@/app/utils/formatUtil";
- import { useTranslation } from "react-i18next";
- import pickBy from "lodash/pickBy";
-
- interface Props {
- currentMonth: Dayjs;
- timesheet: RecordTimesheetInput;
- leaves: RecordLeaveInput;
- companyHolidays: HolidaysResult[];
- onDateSelect: (date: string) => void;
- }
-
- const MonthlySummary: React.FC<Props> = ({
- timesheet,
- leaves,
- currentMonth,
- companyHolidays,
- onDateSelect,
- }) => {
- const {
- t,
- i18n: { language },
- } = useTranslation("home");
-
- // calendar related
- const holidays = useMemo(() => {
- const holidays = getPublicHolidaysForNYears(1, currentMonth.year()).map(holiday => holiday.date)
- return holidays.filter(date => {
- return currentMonth.isSame(dayjs(date), "month")
- })
- }, [currentMonth]);
-
- const timesheetForCurrentMonth = useMemo(() => {
- return pickBy(timesheet, (_, date) => {
- return currentMonth.isSame(dayjs(date), "month");
- });
- }, [currentMonth, timesheet]);
-
- const leavesForCurrentMonth = useMemo(() => {
- return pickBy(leaves, (_, date) => {
- return currentMonth.isSame(dayjs(date), "month");
- });
- }, [currentMonth, leaves]);
-
- const days = useMemo(() => {
- return union(
- Object.keys(timesheetForCurrentMonth),
- Object.keys(leavesForCurrentMonth),
- holidays
- );
- }, [timesheetForCurrentMonth, leavesForCurrentMonth, holidays]).sort();
-
- const makeSelectDate = useCallback(
- (date: string) => () => {
- onDateSelect(date);
- },
- [onDateSelect],
- );
-
- useEffect(()=> {
- console.log(holidays)
- console.log(timesheetForCurrentMonth)
- },[currentMonth, timesheetForCurrentMonth])
-
- return (
- <Stack
- gap={2}
- marginBlockEnd={2}
- minWidth={{ sm: 375 }}
- maxHeight={{ sm: 500 }}
- >
- <Typography variant="overline">{t("Monthly Summary")}</Typography>
- <Box sx={{ overflowY: "scroll" }} flex={1}>
- {days.map((day, index) => {
- const dayJsObj = dayjs(day);
-
- const holiday = getHolidayForDate(day, companyHolidays);
- const isHoliday =
- holiday || dayJsObj.day() === 0 || dayJsObj.day() === 6;
-
- const ls = leavesForCurrentMonth[day];
- const leaveHours =
- ls?.reduce((acc, entry) => acc + entry.inputHours, 0) || 0;
-
- const ts = timesheetForCurrentMonth[day];
- const timesheetNormalHours =
- ts?.reduce((acc, entry) => acc + (entry.inputHours || 0), 0) || 0;
- const timesheetOtHours =
- ts?.reduce((acc, entry) => acc + (entry.otHours || 0), 0) || 0;
-
- const timesheetHours = timesheetNormalHours + timesheetOtHours;
-
- return (
- <Card
- key={`${day}-${index}`}
- sx={{ marginBlockEnd: 2, marginInline: 2 }}
- >
- <CardActionArea onClick={makeSelectDate(day)}>
- <CardContent sx={{ padding: 3 }}>
- <Typography
- variant="overline"
- component="div"
- sx={{
- color: isHoliday ? "error.main" : undefined,
- }}
- >
- {shortDateFormatter(language).format(dayJsObj.toDate())}
- {holiday && (
- <Typography
- marginInlineStart={1}
- variant="caption"
- >{`(${holiday.title})`}</Typography>
- )}
- </Typography>
- <Stack spacing={1}>
- <Box
- sx={{
- display: "flex",
- justifyContent: "space-between",
- flexWrap: "wrap",
- alignItems: "baseline",
- }}
- >
- <Typography variant="body2">
- {t("Timesheet Hours")}
- </Typography>
- <Typography>
- {manhourFormatter.format(timesheetHours)}
- </Typography>
- </Box>
- <Box
- sx={{
- display: "flex",
- justifyContent: "space-between",
- flexWrap: "wrap",
- alignItems: "baseline",
- }}
- >
- <Typography variant="body2">
- {t("Leave Hours")}
- </Typography>
- <Typography>
- {manhourFormatter.format(leaveHours)}
- </Typography>
- </Box>
-
- <Box
- sx={{
- display: "flex",
- justifyContent: "space-between",
- flexWrap: "wrap",
- alignItems: "baseline",
- }}
- >
- <Typography variant="body2">
- {t("Daily Total Hours")}
- </Typography>
- <Typography>
- {manhourFormatter.format(timesheetHours + leaveHours)}
- </Typography>
- </Box>
- </Stack>
- </CardContent>
- </CardActionArea>
- </Card>
- );
- })}
- </Box>
- <Typography variant="overline">
- {`${t("Total Monthly Work Hours")}: ${manhourFormatter.format(
- Object.values(timesheetForCurrentMonth)
- .flatMap((entries) => entries)
- .map((entry) => (entry.inputHours ?? 0) + (entry.otHours ?? 0))
- .reduce((acc, cur) => {
- return acc + cur;
- }, 0),
- )}`}
- </Typography>
- <Typography variant="overline">
- {`${t("Total Monthly Leave Hours")}: ${manhourFormatter.format(
- Object.values(leavesForCurrentMonth)
- .flatMap((entries) => entries)
- .map((entry) => entry.inputHours)
- .reduce((acc, cur) => {
- return acc + cur;
- }, 0),
- )}`}
- </Typography>
- </Stack>
- );
- };
-
- export default MonthlySummary;
|