import HelpOutlineIcon from "@mui/icons-material/HelpOutlined"; import { Button, FormControlLabel, IconButton, Menu, MenuItem, Stack, Switch } from "@mui/material"; import Grid from '@mui/material/Grid'; import Tooltip from "@mui/material/Tooltip"; import { DatePicker, LocalizationProvider } from "@mui/x-date-pickers"; import { AdapterLuxon } from "@mui/x-date-pickers/AdapterLuxon"; import { WgerTextField } from "@/core/forms/WgerTextField"; import { useProfileQuery } from "@/components/User"; import { DESCRIPTION_MAX_LENGTH, MAX_WORKOUT_DURATION, MIN_WORKOUT_DURATION, NAME_MAX_LENGTH, NAME_MIN_LENGTH, Routine } from "@/components/Routines/models/Routine"; import { useAddRoutineQuery, useEditRoutineQuery } from "@/components/Routines/queries/routines"; import { SlotEntryRoundingField } from "@/components/Routines/widgets/forms/SlotEntryForm"; import { Form, Formik } from "formik"; import { DateTime } from "luxon"; import React, { useState } from 'react'; import { useTranslation } from "react-i18next"; import { useNavigate } from "react-router-dom"; import { makeLink, WgerLink } from "@/core/lib/url"; import * as yup from 'yup'; interface RoutineFormProps { existingRoutine?: Routine, isTemplate?: boolean, isPublicTemplate?: boolean, closeFn?: () => void, } export const RoutineForm = ({ existingRoutine, isTemplate = false, isPublicTemplate = false, closeFn }: RoutineFormProps) => { const [t, i18n] = useTranslation(); const addRoutineQuery = useAddRoutineQuery(); const editRoutineQuery = useEditRoutineQuery(existingRoutine?.id ?? -1); const navigate = useNavigate(); const routine = existingRoutine ? Routine.clone(existingRoutine) : new Routine({ isTemplate: isTemplate, isPublic: isPublicTemplate }); /* * Note: Controlling the state of the dates manually, otherwise some undebuggable errors * about missing properties occur deep within formik. */ const [startDate, setStartDate] = useState(DateTime.fromJSDate(routine.start)); const [endDate, setEndDate] = useState(DateTime.fromJSDate(routine.end)); const duration = endDate.diff(startDate, ['weeks', 'days']); const durationWeeks = Math.floor(duration.weeks); const durationDays = Math.floor(duration.days); const validationSchema = yup.object({ name: yup .string() .required() .max(NAME_MAX_LENGTH, t('forms.maxLength', { chars: NAME_MAX_LENGTH })) .min(NAME_MIN_LENGTH, t('forms.minLength', { chars: NAME_MIN_LENGTH })), description: yup .string() .max(DESCRIPTION_MAX_LENGTH, t('forms.maxLength', { chars: DESCRIPTION_MAX_LENGTH })), start: yup .date() .required(), end: yup .date() .required() .min( yup.ref('start'), t('forms.endBeforeStart') ) .test( 'hasMinimumDuration', t('routines.minLengthRoutine', { number: MIN_WORKOUT_DURATION }), function (value) { const startDate = this.parent.start; if (startDate && value) { const startDateTime = DateTime.fromJSDate(startDate); const endDateTime = DateTime.fromJSDate(value); return endDateTime.diff(startDateTime, 'weeks').weeks >= MIN_WORKOUT_DURATION; } return true; } ) .test( 'hasMaximumDuration', t('routines.maxLengthRoutine', { number: MAX_WORKOUT_DURATION }), function (value) { const startDate = this.parent.start; if (startDate && value) { const startDateTime = DateTime.fromJSDate(startDate); const endDateTime = DateTime.fromJSDate(value); return endDateTime.diff(startDateTime, 'weeks').weeks <= MAX_WORKOUT_DURATION; } return true; } ), fitInWeek: yup.boolean() }); return ( ( { routine.name = values.name; routine.description = values.description; routine.fitInWeek = values.fitInWeek; routine.start = values.start!.toJSDate(); routine.end = values.end!.toJSDate(); if (routine.id !== null) { editRoutineQuery.mutate(routine); } else { const result = await addRoutineQuery.mutateAsync(routine); navigate(makeLink(WgerLink.ROUTINE_EDIT, i18n.language, { id: result.id! })); if (closeFn) { closeFn(); } } }} > {formik => (
{ if (newValue) { formik.setFieldValue('start', newValue); setStartDate(newValue); } }} slotProps={{ textField: { variant: "standard", fullWidth: true, error: formik.touched.start && Boolean(formik.errors.start), helperText: formik.touched.start && formik.errors.start ? String(formik.errors.start) : '' } }} /> { if (newValue) { formik.setFieldValue('end', newValue); setEndDate(newValue); } }} slotProps={{ textField: { variant: "standard", fullWidth: true, error: formik.touched.end && Boolean(formik.errors.end), helperText: formik.touched.end && formik.errors.end ? String(formik.errors.end) : '' } }} /> {durationDays === 0 ? t('durationWeeks', { number: durationWeeks }) : t('durationWeeksDays', { nrWeeks: durationWeeks, nrDays: durationDays })} } label={t('routines.fitDaysInWeek')} />
)}
) ); }; export const DefaultRoundingMenu = (props: { routineId: number }) => { const userProfileQuery = useProfileQuery(); const { t } = useTranslation(); const [anchorEl, setAnchorEl] = React.useState(null); const open = Boolean(anchorEl); const handleClick = (event: React.MouseEvent) => { setAnchorEl(event.currentTarget); }; const handleClose = () => { setAnchorEl(null); }; return ( { }}> ); };