import { Autocomplete, Button, InputAdornment, MenuItem, Select, Stack, TextField } from "@mui/material"; import { DateTimePicker, LocalizationProvider } from "@mui/x-date-pickers"; import { AdapterLuxon } from "@mui/x-date-pickers/AdapterLuxon"; import { DiaryEntry } from "@/components/Nutrition/models/diaryEntry"; import { Ingredient } from "@/components/Nutrition/models/Ingredient"; import { Meal } from "@/components/Nutrition/models/meal"; import { NutritionWeightUnit } from "@/components/Nutrition/models/weightUnit"; import { useAddDiaryEntryQuery, useEditDiaryEntryQuery } from "@/components/Nutrition/queries"; import { IngredientAutocompleter } from "@/components/Nutrition/widgets/IngredientAutocompleter"; import { Form, Formik } from "formik"; import { DateTime } from "luxon"; import React, { useState } from 'react'; import { useTranslation } from "react-i18next"; import { dateToYYYYMMDD } from "@/core/lib/date"; import * as yup from "yup"; const GRAM_UNIT_VALUE = 'g'; type NutritionDiaryEntryFormProps = { planId: string, entry?: DiaryEntry, mealId?: string | null, meals?: Meal[], closeFn?: () => void, } export const NutritionDiaryEntryForm = ({ planId, entry, mealId, meals, closeFn }: NutritionDiaryEntryFormProps) => { const meal = mealId === undefined ? null : mealId; const mealObjs = meals === undefined ? [] : meals; const [t, i18n] = useTranslation(); const addDiaryQuery = useAddDiaryEntryQuery(planId); const editDiaryQuery = useEditDiaryEntryQuery(planId); const [dateValue, setDateValue] = useState(entry ? DateTime.fromJSDate(entry.datetime) : DateTime.now()); const [selectedMeal, setSelectedMeal] = useState(meal); const [selectedUnit, setSelectedUnit] = useState(entry?.weightUnit ?? null); const [weightUnits, setWeightUnits] = useState(entry?.ingredient?.weightUnits ?? []); const validationSchema = yup.object({ amount: yup .number() .required(t('forms.fieldRequired')) .max(1000, t('forms.maxValue', { value: '1000' })) .min(1, t('forms.minValue', { value: '1' })), ingredient: yup .number() .nullable() .moreThan(0, t('forms.fieldRequired')) .required(t('forms.fieldRequired')), datetime: yup .date() .required(t('forms.fieldRequired')), }); const handleUnitChange = (value: string) => { if (value === GRAM_UNIT_VALUE) { setSelectedUnit(null); } else { const unit = weightUnits.find(u => u.id === Number(value)); setSelectedUnit(unit ?? null); } }; return ( ( { // Make sure "amount" is a number const newAmount = Number(values.amount); if (entry) { // Edit const newDiaryEntry = DiaryEntry.clone(entry, { mealId: selectedMeal, planId: planId, amount: newAmount, datetime: values.datetime, ingredientId: values.ingredient!, weightUnitId: selectedUnit?.id ?? null, weightUnit: selectedUnit, }); editDiaryQuery.mutate(newDiaryEntry); } else { // Add addDiaryQuery.mutate(new DiaryEntry({ planId: planId, amount: newAmount, datetime: values.datetime, ingredientId: values.ingredient!, mealId: selectedMeal, weightUnitId: selectedUnit?.id ?? null, weightUnit: selectedUnit, })); } // if closeFn is defined, close the modal (this form does not have to be displayed in one) if (closeFn) { closeFn(); } }} > {formik => (
{ formik.setFieldTouched('ingredient', true); formik.setFieldValue('ingredient', value?.id ?? null); setWeightUnits(value?.weightUnits ?? []); setSelectedUnit(null); }} /> {formik.touched.ingredient && formik.errors.ingredient && (
{formik.errors.ingredient}
)} {weightUnits.length > 0 ? ( ) : ( t('nutrition.gramShort') )} ) }, htmlInput: { inputMode: 'decimal' } }} error={formik.touched.amount && Boolean(formik.errors.amount)} helperText={formik.touched.amount && formik.errors.amount} {...formik.getFieldProps('amount')} /> {mealObjs.length > 0 && e.id)} getOptionLabel={option => mealObjs.find(e => e.id === option)!.displayName!} onChange={(event, newValue) => setSelectedMeal(newValue)} renderInput={params => ( )} />} { formik.setFieldValue('datetime', newValue?.toJSDate()); setDateValue(newValue); }} shouldDisableDate={(date) => { // Allow the date of the current weight entry, since we are editing it // @ts-ignore - date is a Luxon DateTime! if (entry && dateToYYYYMMDD(entry.datetime) === dateToYYYYMMDD(date.toJSDate())) { return false; } // all other dates are allowed return false; }} /> {closeFn !== undefined && }
)}
) ); };