fix: recepty přesnuty k jídlům
feat: přidána podpora fotek
This commit is contained in:
1 parent
efed5e6e86
commit
e13f7ce8e5
39 files changed
+1266
-511
No files matched your search
@@ -1,7 +1,6 @@
|
||||
import { useState } from "react";
|
||||
import { Alert, Button, Form } from "react-bootstrap";
|
||||
import { MealTemplate, MealType, saveMealTemplate } from "../../../types";
|
||||
import { MEAL_TYPES_IN_ORDER, MEAL_TYPE_ICONS, MEAL_TYPE_NAMES } from "../enums";
|
||||
import { MealTemplate, saveMealTemplate } from "../../../types";
|
||||
import { deriveRecipe, formatCalories, formatPrice, formatWeight, parseIntInput } from "../Utils";
|
||||
import SourceInput from "./SourceInput";
|
||||
import RecipeIngredientsEditor, {
|
||||
@@ -11,15 +10,19 @@ import RecipeIngredientsEditor, {
|
||||
type Props = {
|
||||
/** Upravovaný recept. Pokud chybí, zakládá se nový. */
|
||||
template?: MealTemplate,
|
||||
/**
|
||||
* Jídlo ze seznamu jídel, ke kterému recept patří. Název a zdroj pak nejdou
|
||||
* měnit — mění se přejmenováním jídla, aby recept zůstal u svých záznamů.
|
||||
*/
|
||||
meal?: { name: string, source?: string },
|
||||
onSaved: (templates: MealTemplate[]) => void,
|
||||
onCancel: () => void,
|
||||
};
|
||||
|
||||
/** Naplní formulář z receptu, nebo ho nechá prázdný pro nový. */
|
||||
const createForm = (template?: MealTemplate) => ({
|
||||
name: template?.name ?? '',
|
||||
source: template?.source ?? '',
|
||||
mealType: (template?.mealType ?? '') as MealType | '',
|
||||
const createForm = (template?: MealTemplate, meal?: Props['meal']) => ({
|
||||
name: meal?.name ?? template?.name ?? '',
|
||||
source: meal?.source ?? template?.source ?? '',
|
||||
note: template?.note ?? '',
|
||||
servings: template?.servings != null ? String(template.servings) : '',
|
||||
cookedWeight: template?.cookedWeight != null ? String(template.cookedWeight) : '',
|
||||
@@ -29,8 +32,8 @@ const createForm = (template?: MealTemplate) => ({
|
||||
* Formulář receptu — vařeného jídla. Zapisují se suroviny a postup a hodnoty
|
||||
* porce se z nich dopočtou — stejně jako na serveru, tady jen jako živý náhled.
|
||||
*/
|
||||
const MealTemplateForm = ({ template, onSaved, onCancel }: Readonly<Props>) => {
|
||||
const [form, setForm] = useState(() => createForm(template));
|
||||
const MealTemplateForm = ({ template, meal, onSaved, onCancel }: Readonly<Props>) => {
|
||||
const [form, setForm] = useState(() => createForm(template, meal));
|
||||
const [ingredients, setIngredients] = useState<DraftIngredient[]>(() =>
|
||||
template?.ingredients?.length ? template.ingredients.map(toDraftIngredient) : [emptyIngredient()]);
|
||||
const [error, setError] = useState<string | undefined>();
|
||||
@@ -54,7 +57,6 @@ const MealTemplateForm = ({ template, onSaved, onCancel }: Readonly<Props>) => {
|
||||
...(template ? { id: template.id } : {}),
|
||||
name: form.name.trim(),
|
||||
...(form.source.trim() ? { source: form.source.trim() } : {}),
|
||||
...(form.mealType ? { mealType: form.mealType } : {}),
|
||||
...(form.note.trim() ? { note: form.note.trim() } : {}),
|
||||
ingredients: filledIngredients,
|
||||
servings: parseIntInput(form.servings),
|
||||
@@ -75,38 +77,26 @@ const MealTemplateForm = ({ template, onSaved, onCancel }: Readonly<Props>) => {
|
||||
|
||||
{error && <Alert variant="danger" className="py-2 small">{error}</Alert>}
|
||||
|
||||
<div className="row g-3 mb-3">
|
||||
<div className="col-sm-5">
|
||||
<Form.Label>Název</Form.Label>
|
||||
<Form.Control
|
||||
value={form.name}
|
||||
placeholder="Např. Kuřecí rizoto"
|
||||
onChange={event => update({ name: event.target.value })}
|
||||
/>
|
||||
{!meal && (
|
||||
<div className="row g-3 mb-3">
|
||||
<div className="col-sm-7">
|
||||
<Form.Label>Název</Form.Label>
|
||||
<Form.Control
|
||||
value={form.name}
|
||||
placeholder="Např. Kuřecí rizoto"
|
||||
onChange={event => update({ name: event.target.value })}
|
||||
/>
|
||||
</div>
|
||||
<div className="col-sm-5">
|
||||
<Form.Label>Zdroj</Form.Label>
|
||||
<SourceInput
|
||||
value={form.source}
|
||||
placeholder="doma"
|
||||
onChange={source => update({ source })}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-sm-4">
|
||||
<Form.Label>Zdroj</Form.Label>
|
||||
<SourceInput
|
||||
value={form.source}
|
||||
placeholder="doma"
|
||||
onChange={source => update({ source })}
|
||||
/>
|
||||
</div>
|
||||
<div className="col-sm-3">
|
||||
<Form.Label>Chod</Form.Label>
|
||||
<Form.Select
|
||||
value={form.mealType}
|
||||
onChange={event => update({ mealType: event.target.value as MealType | '' })}
|
||||
>
|
||||
<option value="">— vybrat při použití —</option>
|
||||
{MEAL_TYPES_IN_ORDER.map(type => (
|
||||
<option key={type} value={type}>
|
||||
{MEAL_TYPE_ICONS[type]} {MEAL_TYPE_NAMES[type]}
|
||||
</option>
|
||||
))}
|
||||
</Form.Select>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<fieldset className="meal-fieldset mb-3">
|
||||
<legend>Suroviny</legend>
|
||||
@@ -168,9 +158,7 @@ const MealTemplateForm = ({ template, onSaved, onCancel }: Readonly<Props>) => {
|
||||
{recipe.calories != null && (
|
||||
<span className="workout-draft-calories">porce {formatCalories(recipe.calories)}</span>
|
||||
)}
|
||||
{template && (
|
||||
<Button variant="outline-secondary" size="sm" onClick={() => onCancel()}>Zrušit úpravu</Button>
|
||||
)}
|
||||
<Button variant="outline-secondary" size="sm" onClick={() => onCancel()}>Zrušit</Button>
|
||||
<Button size="sm" onClick={() => save()} disabled={!canSave}>
|
||||
{template ? 'Uložit změny' : 'Vytvořit recept'}
|
||||
</Button>
|
||||
|
||||
Reference in new issue
Block a user