Skip to content

Commit

Permalink
Allow setting the start and end dates for new routines
Browse files Browse the repository at this point in the history
  • Loading branch information
rolandgeider committed Oct 25, 2024
1 parent 72e808f commit d01bd2c
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 11 deletions.
1 change: 1 addition & 0 deletions src/components/Measurements/widgets/EntryForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ export const EntryForm = ({ entry, closeFn, categoryId }: EntryFormProps) => {
label={t('date')}
value={dateValue}
disableFuture={true}

onChange={(newValue) => {
if (newValue) {
formik.setFieldValue('date', newValue.toJSDate());
Expand Down
102 changes: 91 additions & 11 deletions src/components/WorkoutRoutines/widgets/forms/RoutineForm.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import { Button } from "@mui/material";
import Grid from '@mui/material/Grid2';
import { DatePicker, LocalizationProvider } from "@mui/x-date-pickers";
import { AdapterLuxon } from "@mui/x-date-pickers/AdapterLuxon";
import { WgerTextField } from "components/Common/forms/WgerTextField";
import { Routine } from "components/WorkoutRoutines/models/Routine";
import { useAddRoutineQuery, useEditRoutineQuery } from "components/WorkoutRoutines/queries/routines";
import { Form, Formik } from "formik";
import React from 'react';
import { DateTime } from "luxon";
import React, { useState } from 'react';
import { useTranslation } from "react-i18next";
import { dateToYYYYMMDD } from "utils/date";
import { DEFAULT_WORKOUT_DURATION, MIN_WORKOUT_DURATION } from "utils/consts";
import * as yup from 'yup';

interface RoutineFormProps {
Expand All @@ -16,9 +19,18 @@ interface RoutineFormProps {

export const RoutineForm = ({ routine, closeFn }: RoutineFormProps) => {

const [t] = useTranslation();
const [t, i18n] = useTranslation();
const addRoutineQuery = useAddRoutineQuery();
const editRoutineQuery = useEditRoutineQuery(routine?.id!);

/*
* Note: Controlling the state of the dates manually, otherwise some undebuggable errors
* about missing properties occur deep within formik.
*/
const [startValue, setStartValue] = useState<DateTime | null>(routine ? DateTime.fromJSDate(routine.start) : DateTime.now());
const [endValue, setEndValue] = useState<DateTime | null>(routine ? DateTime.fromJSDate(routine.end) : DateTime.now().plus({ weeks: DEFAULT_WORKOUT_DURATION }));


const validationSchema = yup.object({
name: yup
.string()
Expand All @@ -34,6 +46,24 @@ export const RoutineForm = ({ routine, closeFn }: RoutineFormProps) => {
end: yup
.date()
.required()
.min(
yup.ref('start'),
"end date must be after start date"
)
.test(
'hasMinimumDuration',
"the workout needs to be at least 2 weeks long",
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;
}
),
});


Expand All @@ -42,18 +72,28 @@ export const RoutineForm = ({ routine, closeFn }: RoutineFormProps) => {
initialValues={{
name: routine ? routine.name : '',
description: routine ? routine.description : '',
start: routine ? routine.start : dateToYYYYMMDD(new Date()),
end: routine ? routine.end : dateToYYYYMMDD(new Date()),
// eslint-disable-next-line camelcase
start: startValue,
end: endValue,
}}

validationSchema={validationSchema}
onSubmit={async (values) => {

console.log(values);

if (routine) {
editRoutineQuery.mutate({ ...values, id: routine.id });
editRoutineQuery.mutate({
...values,
start: values.start?.toISODate()!,
end: values.end?.toISODate()!,
id: routine.id
});
} else {
addRoutineQuery.mutate(values);
addRoutineQuery.mutate({
...values,
start: values.start?.toISODate()!,
end: values.end?.toISODate()!,
});
}

// if closeFn is defined, close the modal (this form does not have to be displayed in one)
Expand All @@ -64,15 +104,55 @@ export const RoutineForm = ({ routine, closeFn }: RoutineFormProps) => {
>
{formik => (
<Form>
<Grid container>
<Grid container spacing={2}>
<Grid size={6}>
<WgerTextField fieldName="name" title={t('name')} />
</Grid>
<Grid size={3}>
<WgerTextField fieldName="start" title={'start'} />
<LocalizationProvider dateAdapter={AdapterLuxon} adapterLocale={i18n.language}>
<DatePicker
defaultValue={DateTime.now()}
label={'start'}
value={startValue}
onChange={(newValue) => {
if (newValue) {
formik.setFieldValue('start', newValue);
}
setStartValue(newValue);
}}
slotProps={{
textField: {
variant: "standard",
fullWidth: true,
error: formik.touched.start && Boolean(formik.errors.start),
helperText: formik.touched.start && formik.errors.start
}
}}
/>
</LocalizationProvider>
</Grid>
<Grid size={3}>
<WgerTextField fieldName="end" title={'end'} />
<LocalizationProvider dateAdapter={AdapterLuxon} adapterLocale={i18n.language}>
<DatePicker
defaultValue={DateTime.now()}
label={'end'}
value={endValue}
onChange={(newValue) => {
if (newValue) {
formik.setFieldValue('end', newValue);
}
setEndValue(newValue);
}}
slotProps={{
textField: {
variant: "standard",
fullWidth: true,
error: formik.touched.end && Boolean(formik.errors.end),
helperText: formik.touched.end && formik.errors.end
}
}}
/>
</LocalizationProvider>
</Grid>
<Grid size={12}>
<WgerTextField fieldName="description" title={t('description')} />
Expand Down
7 changes: 7 additions & 0 deletions src/utils/consts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@ export const ENGLISH_LANGUAGE_CODE = 'en';

export const MIN_ACCOUNT_AGE = MIN_ACCOUNT_AGE_TO_TRUST || 21;

// Duration in weeks
export const MIN_WORKOUT_DURATION = 2;

// Duration in weeks
export const DEFAULT_WORKOUT_DURATION = 12;


export const REP_UNIT_REPETITIONS = 1;
export const REP_UNIT_TILL_FAILURE = 2;

Expand Down

0 comments on commit d01bd2c

Please sign in to comment.