import { getLanguageByShortName, Language, useLanguageQuery } from "@/components/Exercises"; import { Day } from "@/components/Routines/models/Day"; import { Routine } from "@/components/Routines/models/Routine"; import { RoutineLogData } from "@/components/Routines/models/RoutineLogData"; import { SetConfigData } from "@/components/Routines/models/SetConfigData"; import { SlotEntry } from "@/components/Routines/models/SlotEntry"; import { WorkoutLog } from "@/components/Routines/models/WorkoutLog"; import { useRoutineDetailQuery, useRoutineLogData } from "@/components/Routines/queries"; import { makeLink, WgerLink } from "@/core/lib/url"; import { WgerContainerFullWidth } from "@/core/ui/Widgets/Container"; import { RenderLoadingQuery } from "@/core/ui/Widgets/RenderLoadingQuery"; import FlagCircleIcon from '@mui/icons-material/FlagCircle'; import NorthEastIcon from "@mui/icons-material/NorthEast"; import SouthEastIcon from "@mui/icons-material/SouthEast"; import { Container, FormControlLabel, Stack, Switch, Table, TableBody, TableCell, TableContainer, TableHead, TableRow, Typography, useTheme } from "@mui/material"; import { styled } from '@mui/material/styles'; import React from "react"; import { useTranslation } from "react-i18next"; import { useParams } from "react-router-dom"; const PREFIX = 'RoutineDetailsTable'; const classes = { stickyColumn: `${PREFIX}-stickyColumn`, stickyHeader: `${PREFIX}-stickyHeader`, whiteBg: `${PREFIX}-whiteBg` }; const StyledContainer = styled(Container)({ [`& .${classes.stickyColumn}`]: { position: 'sticky', left: 0, // background: 'white', zIndex: 1, }, [`& .${classes.stickyHeader}`]: { position: 'sticky', top: 0, zIndex: 2, background: 'white', }, [`& .${classes.whiteBg}`]: { backgroundColor: 'white', } }); export const RoutineDetailsTable = () => { const { t, i18n } = useTranslation(); const params = useParams<{ routineId: string }>(); const routineId = params.routineId ? parseInt(params.routineId) : 0; const routineQuery = useRoutineDetailQuery(routineId); const routineLogDataQuery = useRoutineLogData(routineId); const [showLogs, setShowLogs] = React.useState(false); return setShowLogs(checked)} />} label={t('routines.alsoShowLogs')} /> } />; }; export function compareValue(value: number | null | undefined, from: number | null | undefined, to: number | null | undefined): 'lower' | 'higher' | 'match' | null { if (value === null || value === undefined) { return null; } if (from !== null && from !== undefined && to !== null && to !== undefined) { if (value < from) { return 'lower'; } else if (value > to) { return 'higher'; } else { return 'match'; } } else if (from !== null && from !== undefined) { if (value < from) { return 'lower'; } else if (value > from) { return 'higher'; } else { return 'match'; } } return null; } export const RoutineTable = (props: { routine: Routine, showLogs?: boolean, logData?: RoutineLogData[] }) => { const { t, i18n } = useTranslation(); const theme = useTheme(); const languageQuery = useLanguageQuery(); const showLogs = props.showLogs ?? false; const routineLogData = props.logData ?? []; let language: Language | undefined = undefined; if (languageQuery.isSuccess) { language = getLanguageByShortName( i18n.language, languageQuery.data! ); } const groupedLogs: { [key: number]: WorkoutLog[] } = {}; for (const logData of routineLogData) { for (const log of logData.logs) { if (log.iteration === null) { continue; } if (!groupedLogs[log.iteration]) { groupedLogs[log.iteration] = []; } groupedLogs[log.iteration].push(log); } } const iterations = Object.keys(props.routine.groupedDayDataByIteration).map((iteration) => parseInt(iteration)); function getTableRowHeader() { return {iterations.map((iteration) => { const out = iteration === 1 ? : null; return {out} {t('routines.sets')} {t('routines.reps')} {t('weight')} {t('routines.restTime')} {t('routines.rir')} ; })} ; } function getTableRowWeekTitle() { return {iterations.map((iteration) => { const placeholder = iteration === 1 ? : null; return {placeholder} {props.routine.isWeeklyCycle ? t('routines.weekNr', { number: iteration }) : t('routines.iterationNr', { number: iteration })} ; })} ; } function getTableRowPlanned(slotEntry: SlotEntry, day: Day) { const sx = { borderBottomWidth: showLogs ? 0 : null, minWidth: 40 }; function formatContent(setConfig: SetConfigData | null, value: number | undefined | null, maxValue: number | undefined | null) { return <> {setConfig === null || value === null ? '-/-' : value} {setConfig !== null && maxValue !== null && <> - {maxValue}} ; } return {slotEntry.exercise?.getTranslation(language).name} {iterations.map((iteration) => { const setConfig = props.routine.getSetConfigData(day.id!, iteration, slotEntry.id!); return {formatContent(setConfig, setConfig?.nrOfSets, setConfig?.maxNrOfSets)} {formatContent(setConfig, setConfig?.repetitions, setConfig?.maxRepetitions)} {formatContent(setConfig, setConfig?.weight, setConfig?.maxWeight)} {formatContent(setConfig, setConfig?.restTime, setConfig?.maxRestTime)} {formatContent(setConfig, setConfig?.rir, setConfig?.maxRir)} ; })} ; } function getComparisonIcon(loggedValue: number | null, plannedValue: number | null | undefined, maxPlannedValue: number | null | undefined, higherIsBetter?: boolean) { const comparison = compareValue(loggedValue, plannedValue, maxPlannedValue); const fontSize = 17; // Switch the comparison color since e.g. for RiR lower is better higherIsBetter = higherIsBetter ?? true; if (comparison === null) { return null; } if (comparison === 'lower') { return ; } if (comparison === 'higher') { return ; } return ; } function getTableRowLogged(slotEntry: SlotEntry, day: Day) { return {t('nutrition.logged')} {iterations.map((iteration) => { const setConfig = props.routine.getSetConfigData(day.id!, iteration, slotEntry.id!); const iterationLogs = groupedLogs[iteration] ?? []; const logs = iterationLogs.filter((log) => log.slotEntryId === slotEntry.id); return {logs.map((log) => {log.repetitions ?? '-/-'} {getComparisonIcon(log.repetitions, setConfig?.repetitions, setConfig?.maxRepetitions)} )} {logs.map((log) => {log.weight ?? '-/-'} {getComparisonIcon(log.weight, setConfig?.weight, setConfig?.maxWeight)} )} {logs.map((log) => {log.restTime ?? '-/-'} {getComparisonIcon(log.restTime, setConfig?.restTime, setConfig?.maxRestTime)} )} {logs.map((log) => {log.rir ?? '-/-'} {getComparisonIcon(log.rir, setConfig?.rir, setConfig?.maxRir, false)} )} ; })} ; } function getTableContent() { return <> {props.routine.days.map((day) => { return {day.displayName} {day.slots.map((slot) => { return {slot.entries.map((slotEntry) => { return {getTableRowPlanned(slotEntry, day)} {showLogs && getTableRowLogged(slotEntry, day)} ; })} ; })} ; })} ; } return ( {getTableRowWeekTitle()} {getTableRowHeader()} {getTableContent()}
); };