import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; import PhotoIcon from '@mui/icons-material/Photo'; import SearchIcon from '@mui/icons-material/Search'; import { Avatar, AvatarGroup, InputAdornment, List, ListItem, ListItemButton, ListItemIcon, ListItemText, Paper, Switch, TextField, } from "@mui/material"; import Grid from '@mui/material/Grid'; import { LoadingPlaceholder } from "@/core/ui/LoadingWidget/LoadingWidget"; import { Exercise } from "@/components/Exercises/models/exercise"; import { useExercisesQuery } from "@/components/Exercises/queries"; import React, { useState } from "react"; import { useTranslation } from "react-i18next"; /* * Groups a list of objects by a property */ function groupBy(list: T[], keyGetter: (item: T) => K): Map { const map = new Map(); list.forEach((item: T) => { const key = keyGetter(item); const collection = map.get(key); if (!collection) { map.set(key, [item]); } else { collection.push(item); } }); return map; } interface ExerciseInfoListItemProps { exercises: Exercise[]; selectedVariationId: string | null; selectedNewVariationExerciseId: number | null; onToggle: (variationId: string | null, newVariationId: number | null) => void; highlight?: boolean; } const ExerciseInfoListItem = ({ exercises, selectedVariationId, selectedNewVariationExerciseId, onToggle, highlight = false, }: ExerciseInfoListItemProps) => { const MAX_EXERCISE_IMAGES = 4; const MAX_EXERCISE_NAMES = 5; const variationId = exercises[0].variationGroup; const exerciseId = exercises[0].id; const [showMore, setShowMore] = useState(false); const handleToggle = () => { let newVarId = variationId; let newExId: number | null = exerciseId; if (newVarId !== null) { newExId = null; if (newVarId === selectedVariationId) { newVarId = null; } } else { newVarId = null; if (newExId === selectedNewVariationExerciseId) { newExId = null; } } onToggle(newVarId, newExId); }; let isChecked; if (variationId === null) { isChecked = selectedNewVariationExerciseId === exerciseId; } else { isChecked = variationId === selectedVariationId; } return ( {exercises.map((base) => base.mainImage ? : )}

{exercise.getTranslation().name}

)} /> {!showMore && exercises.length > MAX_EXERCISE_NAMES ? setShowMore(true)} /> : null }
); }; export interface VariationSelectProps { exerciseId?: number; selectedVariationId: string | null; selectedNewVariationExerciseId: number | null; onChangeVariationId: (id: string | null) => void; onChangeNewVariationExerciseId: (id: number | null) => void; } export function VariationSelect({ exerciseId, selectedVariationId, selectedNewVariationExerciseId, onChangeVariationId, onChangeNewVariationExerciseId, }: VariationSelectProps) { const [t] = useTranslation(); const exercisesQuery = useExercisesQuery(); const [searchTerm, setSearchTerms] = useState(''); // Group exercises by variationId let exercises: Exercise[] = []; let groupedExercises = new Map(); if (exercisesQuery.isSuccess) { let allExercises: Exercise[] = exercisesQuery.data; if (searchTerm !== '') { allExercises = allExercises.filter((base) => base.getTranslation().name.toLowerCase().includes(searchTerm.toLowerCase())); } // Group first (including current exercise, so groups show all members) groupedExercises = groupBy(allExercises.filter(b => b.variationGroup !== null), (b: Exercise) => b.variationGroup as string); // Filter out the current exercise only for the standalone list exercises = exerciseId ? allExercises.filter((e) => e.id !== exerciseId) : allExercises; } const handleToggle = (variationId: string | null, newVariationId: number | null) => { if (newVariationId !== null) { onChangeNewVariationExerciseId(newVariationId); } else { onChangeVariationId(variationId); } }; return <> setSearchTerms(event.target.value)} slotProps={{ input: { startAdornment: ( ), } }} /> {exercisesQuery.isLoading ? : {/* Show the current variation group first */} {selectedVariationId !== null && groupedExercises.has(selectedVariationId) && ( )} {/* Remaining variation groups */} {[...groupedExercises.keys()] .filter(id => id !== selectedVariationId) .map(variationId => )} {/* Standalone exercises (no variation group) */} {exercises.filter(b => b.variationGroup === null).map(exercise => )} } ; }