import { SlotEntry, SlotEntryType } from "@/components/Routines/models/SlotEntry"; import { useEditSlotEntryQuery, useFetchRoutineRepUnitsQuery, useFetchRoutineWeighUnitsQuery } from "@/components/Routines/queries"; import { useEditProfileQuery, useProfileQuery } from "@/components/User"; import { DEBOUNCE_ROUTINE_FORMS } from "@/core/lib/consts"; import { LoadingProgressIcon } from "@/core/ui/LoadingWidget/LoadingWidget"; import { MenuItem, TextField } from "@mui/material"; import debounce from "lodash/debounce"; import React, { useEffect, useMemo, useRef, useState } from "react"; import { useTranslation } from "react-i18next"; export const SlotEntryTypeField = (props: { slotEntry: SlotEntry, routineId: number }) => { const { t } = useTranslation(); const editQuery = useEditSlotEntryQuery(props.routineId); const options = [ { value: 'normal', label: t('routines.set.normalSet'), }, { value: 'warmup', label: t('routines.set.warmup'), }, { value: 'dropset', label: t('routines.set.dropSet'), }, { value: 'myo', label: t('routines.set.myo'), }, { value: 'partial', label: t('routines.set.partial'), }, { value: 'forced', label: t('routines.set.forced'), }, { value: 'tut', label: t('routines.set.tut'), }, { value: 'iso', label: t('routines.set.iso'), }, { value: 'jump', label: t('routines.set.jump'), } ] as const; const handleOnChange = (newValue: string) => { editQuery.mutate(SlotEntry.clone(props.slotEntry, { type: newValue as SlotEntryType })); }; return <> handleOnChange(e.target.value)} > {options!.map((option) => ( {option.value.toUpperCase()} - {option.label} ))} ; }; export const SlotEntryRepetitionUnitField = (props: { slotEntry: SlotEntry, routineId: number }) => { const { t } = useTranslation(); const editSlotEntryQuery = useEditSlotEntryQuery(props.routineId); const repUnitsQuery = useFetchRoutineRepUnitsQuery(); if (repUnitsQuery.isLoading) { return ; } const options = repUnitsQuery.data?.map((unit) => ({ value: unit.id, label: unit.name, })); const handleOnChange = (newValue: string) => { editSlotEntryQuery.mutate(SlotEntry.clone(props.slotEntry, { repetitionUnitId: parseInt(newValue) })); }; return <> handleOnChange(e.target.value)} > {options!.map((option) => ( {option.label} ))} ; }; export const SlotEntryWeightUnitField = (props: { slotEntry: SlotEntry, routineId: number }) => { const { t } = useTranslation(); const editSlotEntryQuery = useEditSlotEntryQuery(props.routineId); const weightUnitsQuery = useFetchRoutineWeighUnitsQuery(); const userProfileQuery = useProfileQuery(); if (weightUnitsQuery.isLoading || userProfileQuery.isLoading) { return ; } const options = weightUnitsQuery.data?.map((unit) => ({ value: unit.id, label: unit.name, })); const handleOnChange = (newValue: string) => { editSlotEntryQuery.mutate(SlotEntry.clone(props.slotEntry, { weightUnitId: parseInt(newValue) })); }; return <> handleOnChange(e.target.value)} > {options!.map((option) => ( {option.label} ))} ; }; type BaseSlotEntryRoundingFieldProps = { initialValue: number | null; rounding: 'weight' | 'reps'; routineId: number; }; type SlotEntryRoundingFieldProps = | (BaseSlotEntryRoundingFieldProps & { editProfile: true }) | (BaseSlotEntryRoundingFieldProps & { editProfile: false; slotEntry: SlotEntry }); export const SlotEntryRoundingField = (props: SlotEntryRoundingFieldProps) => { const { t } = useTranslation(); const editSlotEntryQuery = useEditSlotEntryQuery(props.routineId); const editProfileQuery = useEditProfileQuery(); const [value, setValue] = useState(props.initialValue === null ? '' : props.initialValue); // Hold the latest save logic in a ref so the debounced wrapper always // uses current props/queries instead of values captured on first render. const saveRef = useRef<(newValue: string) => void>(() => { }); saveRef.current = (newValue: string) => { const parsedValue = isNaN(Number(newValue)) ? null : parseFloat(newValue); const data = props.rounding === 'weight' ? { weightRounding: parsedValue } : { repetitionRounding: parsedValue }; if (props.editProfile) { editProfileQuery.mutate(data); } else { editSlotEntryQuery.mutate(SlotEntry.clone(props.slotEntry, data)); } }; const debouncedSave = useMemo( () => debounce((newValue: string) => saveRef.current(newValue), DEBOUNCE_ROUTINE_FORMS), [] ); useEffect(() => () => debouncedSave.cancel(), [debouncedSave]); const handleOnChange = (newValue: string) => { setValue(newValue); debouncedSave(newValue); }; return ( handleOnChange(e.target.value)} slotProps={{ htmlInput: { inputMode: 'decimal' } }} /> ); };