import { Box, List, Typography } from "@mui/material"; import { InfoProps, responseType, responsesHourChecker } from "interface"; import React, { ReactElement, memo, useEffect } from "react"; import { v4 as uuidv4 } from "uuid"; import { TimeLineRowType } from "../../../../interface/DayOverviewTypes"; import { LunaticMultiSelectionValues } from "../../../../interface/LunaticMultiSelectionValues"; import { DayDetailType, IODataStructure, WeeklyPlannerDataType, } from "../../../../interface/WeeklyPlannerTypes"; import { makeStylesEdt } from "../../../theme"; import { convertTime, generateDateFromStringInput, generateStringInputFromDate, getArrayFromSession, setDateTimeToZero, } from "../../../utils"; import HourChecker from "../../HourChecker"; import ProgressBar from "../../ProgressBar"; import TooltipInfo from "../../TooltipInfo"; import { INTERVAL, transformToIODataStructure } from "../WeeklyPlanner/utils"; export type DayOverviewProps = { date: Date; isDisplayed: boolean; rawTimeLineData: TimeLineRowType[]; activityData: WeeklyPlannerDataType[]; setActivityData(data: WeeklyPlannerDataType[]): void; handleChangeData(value: any): void; infoLabels: InfoProps; datesLabel: string; workSumLabel: string; workedHoursSum: number; getFormatedWorkedSum: (workedHoursSum: number) => string; helpStep?: number; expandLessIcon: ReactElement; expandMoreIcon: ReactElement; expandLessWhiteIcon: ReactElement; expandMoreWhiteIcon: ReactElement; workIcon: ReactElement; handleChange(response: responseType, value: IODataStructure[]): void; saveHours(idSurvey: string, response: responsesHourChecker): void; values: { [key: string]: string[] | IODataStructure[] | boolean[] }; idSurvey: string; variables: Map; }; /** * Converts DayDetail array to values as LunaticMultiSelectionValues * @param details * @returns */ const fromDayDetailsToValues = (details: DayDetailType[]): LunaticMultiSelectionValues => { const values: LunaticMultiSelectionValues = {}; details.forEach(b => { const time: Date = new Date(); const splittedTime = b.start.split("h"); time.setHours(Number(splittedTime[0])); time.setMinutes(Number(splittedTime[1])); for (let i = 0; i < b.duration / INTERVAL; i++) { const key = convertTime(time); values[key] = true; time.setMinutes(time.getMinutes() + INTERVAL); } }); return values; }; const renderHeader = ( isDisplayed: boolean, classes: any, workSumLabel: string, workedHoursSum: number, getFormatedWorkedSum: (workedHoursSum: number) => string, ) => { return !isDisplayed ? ( ) : ( {workSumLabel} {getFormatedWorkedSum(workedHoursSum)} ); }; /** * This component is the one shown inside WeeklyPlanner component when the user choose a day to fullfil. * It shows to the user a list of 24 Hourchecker components corresponding to an entire day. */ const DayOverview = memo((props: DayOverviewProps) => { const { classes, cx } = useStyles(); const { date, isDisplayed, rawTimeLineData, activityData, setActivityData, handleChangeData, handleChange, infoLabels, datesLabel, workSumLabel, workedHoursSum, getFormatedWorkedSum, helpStep, expandLessIcon, expandMoreIcon, expandLessWhiteIcon, expandMoreWhiteIcon, workIcon, saveHours, idSurvey, variables, } = props; const [componentDisplay, setComponentDisplay] = React.useState("none"); const [timeLineData, setTimeLineData] = React.useState(rawTimeLineData); const [initStore, setInitStore] = React.useState([]); // Update timeLineData for HourCheckers from activityData useEffect(() => { const temp: TimeLineRowType[] = JSON.parse(JSON.stringify(rawTimeLineData)); const dayBloc: WeeklyPlannerDataType | undefined = activityData.find( d => setDateTimeToZero(generateDateFromStringInput(d.date)).getTime() === date.getTime(), ); let valuesDetail: LunaticMultiSelectionValues = {}; if (dayBloc) { valuesDetail = fromDayDetailsToValues(dayBloc.detail); } Object.entries(valuesDetail).forEach(v => { const row: TimeLineRowType | undefined = temp.find((t: TimeLineRowType) => { return t.options.find(o => o.response.name === v[0]); }); if (row) { row.value[v[0]] = v[1]; } }); setTimeLineData(temp); updatesValues(variables, date); }, [date]); useEffect(() => { if (activityData.length !== 0 && !isDisplayed) { updateValue(); } isDisplayed ? setComponentDisplay("flex") : setComponentDisplay("none"); }, [isDisplayed]); useEffect(() => { if (activityData.length !== 0 && !isDisplayed) { updateValue(); } isDisplayed ? setComponentDisplay("flex") : setComponentDisplay("none"); }, [location]); useEffect(() => { if (activityData.length !== 0 && !isDisplayed) { updateValue(); } isDisplayed ? setComponentDisplay("flex") : setComponentDisplay("none"); }, [idSurvey]); const updatesValues = (values: Map, date: Date) => { let dates = values.get(datesLabel) as string[]; if (dates == null || dates.length == undefined || dates.length < 7) { dates = getArrayFromSession(datesLabel); } const currentDateIndex = dates?.indexOf(generateStringInputFromDate(date)); rawTimeLineData.forEach(timeLine => { timeLine.options.forEach(option => { const name = option.response.name; const valuesHour = values.get(option.response.name) as string[]; const valueQuartier = valuesHour ? valuesHour[currentDateIndex] : "false"; const valueIndex = valueQuartier === "true"; timeLine.value[name] = valueIndex; }); }); setTimeLineData(rawTimeLineData); }; /** * Callback triggered when a value is changed in one HourChecker * Updates the parent activityData state */ const updateValue = () => { const temp: WeeklyPlannerDataType[] = [...activityData]; let dayBloc: WeeklyPlannerDataType = temp.filter( d => setDateTimeToZero(generateDateFromStringInput(d.date)).getTime() === date.getTime(), )[0]; let valuesList: LunaticMultiSelectionValues = {}; // Create list of all LunaticMultiSelectionValues for this day timeLineData .map(t => t.value) .forEach(t => { Object.entries(t).forEach(([key, value]) => { valuesList[key] = value; }); }); let details: DayDetailType[] = []; let startHour = "start"; let endHour = "end"; let durationTime = 0; Object.entries(valuesList).forEach(([key, value]) => { if (value && startHour === "start") { startHour = key; endHour = key; durationTime = durationTime + INTERVAL; } else if (value) { durationTime = durationTime + INTERVAL; endHour = key; } if (!value && endHour !== "end") { details.push({ start: startHour, end: endHour, duration: durationTime, }); startHour = "start"; endHour = "end"; durationTime = 0; } }); if (endHour !== "end") { details.push({ start: startHour, end: endHour, duration: durationTime, }); } if (dayBloc) dayBloc.detail = details; const toStore = transformToIODataStructure(temp); updatesValues(variables, date); handleChangeData(toStore); setActivityData(temp); setInitStore(toStore[0]); }; const renderRow = (h: TimeLineRowType): any => { const helpPage = (helpStep == 2 && h.label == "3h00") || (helpStep == 3 && h.label == "4h00") || (helpStep == 4 && h.label == "5h00"); let valueSelected: LunaticMultiSelectionValues = {}; if (helpStep == 2) { valueSelected = { "3h15": true, "3h30": true, "3h45": true, "4h0": true, }; } else if (helpStep == 4) { valueSelected = { "5h15": true, "5h30": true, "5h45": false, "6h0": false, }; } return ( {h.label} ); }; return ( {renderHeader( isDisplayed, classes, workSumLabel, workedHoursSum, getFormatedWorkedSum, )} {timeLineData.map(l => renderRow(l))} ); }); const useStyles = makeStylesEdt({ "name": { DayOverview } })(theme => ({ mainContainer: { flexDirection: "column", }, headerContainerBox: { zIndex: "1", position: "relative", width: "100vw !important", overflowX: "hidden", //Orchestrator content width is limited to 350px, 175px correspond to half of it transform: "translateX(calc(175px - 50vw))", }, headerContainer: { backgroundColor: theme.variables.white, width: "100%", paddingBottom: "1rem", }, dayLabel: { color: theme.palette.info.main, fontSize: "14px", padding: "1rem", }, progressBar: { paddingLeft: "1rem", paddingRight: "1rem", }, listContainer: { display: "flex", flexDirection: "column", paddingTop: "2rem", paddingBottom: "6rem", }, rowContainer: { display: "flex", justifyContent: "space-between", marginBottom: "0.5rem", }, rowLabel: { width: "50px", }, hourLabel: { color: theme.palette.info.main, fontSize: "12px", }, textBox: { paddingLeft: "1.5rem", }, workTimeText: { fontSize: "14px", }, bold: { fontWeight: "bold", }, helpRow: { zIndex: "1400", pointerEvents: "none", }, })); export default DayOverview;