fix: graf cena per zdroj nahrazen koláčem
feat: stránka doplnit údaje předělána na samostatnou stránku jídel + přidáno přejmenování
This commit is contained in:
1 parent
b880b36edd
commit
efed5e6e86
30 files changed
+514
-153
No files matched your search
@@ -0,0 +1,98 @@
|
||||
import { useState } from "react";
|
||||
import { Alert, Button, Form } from "react-bootstrap";
|
||||
import { toast } from "react-toastify";
|
||||
import { MealGroup, renameMealGroup } from "../../../types";
|
||||
import { getMealKey } from "../Utils";
|
||||
import SourceInput from "./SourceInput";
|
||||
|
||||
type Props = {
|
||||
group: MealGroup,
|
||||
/** Ostatní skupiny — podle nich se pozná, že se jídla po přejmenování s některou sloučí. */
|
||||
groupList: MealGroup[],
|
||||
onRenamed: () => void,
|
||||
onCancel: () => void,
|
||||
};
|
||||
|
||||
/** Popisek výsledku přejmenování se skloňovaným počtem jídel. */
|
||||
const describeRenamed = (count: number): string => {
|
||||
if (!count) return 'Název i zdroj už jídla mají, nic se nezměnilo.';
|
||||
if (count === 1) return 'Změněno 1 jídlo.';
|
||||
if (count < 5) return `Změněna ${count} jídla.`;
|
||||
return `Změněno ${count} jídel.`;
|
||||
};
|
||||
|
||||
/**
|
||||
* Hromadná změna názvu a zdroje všech jídel jedné skupiny ve všech dnech.
|
||||
*
|
||||
* Na rozdíl od doplnění údajů přepisuje, proto je to samostatná akce. Když nový
|
||||
* název a zdroj patří jiné skupině, jídla se do ní sloučí — formulář na to upozorní.
|
||||
*/
|
||||
const MealGroupRenameForm = ({ group, groupList, onRenamed, onCancel }: Readonly<Props>) => {
|
||||
const [name, setName] = useState(group.name);
|
||||
const [source, setSource] = useState(group.source ?? '');
|
||||
const [saving, setSaving] = useState(false);
|
||||
|
||||
const targetKey = getMealKey({ name, source });
|
||||
const mergeGroup = targetKey !== getMealKey(group)
|
||||
? groupList.find(item => getMealKey(item) === targetKey)
|
||||
: undefined;
|
||||
const unchanged = name.trim() === group.name && source.trim() === (group.source ?? '');
|
||||
const canSave = !!name.trim().length && !unchanged && !saving;
|
||||
|
||||
const save = async () => {
|
||||
if (!canSave) return;
|
||||
setSaving(true);
|
||||
const response = await renameMealGroup({
|
||||
body: {
|
||||
name: group.name,
|
||||
source: group.source,
|
||||
newName: name.trim(),
|
||||
...(source.trim().length ? { newSource: source.trim() } : {}),
|
||||
},
|
||||
});
|
||||
setSaving(false);
|
||||
if (response.data) {
|
||||
toast.success(describeRenamed(response.data.count));
|
||||
onRenamed();
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Form className="meal-group-form" onSubmit={event => { event.preventDefault(); save(); }}>
|
||||
<p className="text-body-secondary small">
|
||||
{group.count === 1
|
||||
? 'Změní se jen u tohoto jídla.'
|
||||
: `Změní se u všech ${group.count} jídel ve všech dnech, kdy se jedla.`} Ostatní údaje zůstanou.
|
||||
</p>
|
||||
<div className="row g-3 mb-3">
|
||||
<div className="col-sm-7">
|
||||
<Form.Label>Název</Form.Label>
|
||||
<Form.Control
|
||||
autoFocus
|
||||
value={name}
|
||||
isInvalid={!name.trim().length}
|
||||
onChange={event => setName(event.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<div className="col-sm-5">
|
||||
<Form.Label>Zdroj</Form.Label>
|
||||
<SourceInput value={source} placeholder="bez zdroje" onChange={value => setSource(value)} />
|
||||
</div>
|
||||
</div>
|
||||
{mergeGroup && (
|
||||
<Alert variant="warning" className="py-2 small">
|
||||
Jídlo „{mergeGroup.name}“{mergeGroup.source ? ` (${mergeGroup.source})` : ' bez zdroje'} už
|
||||
v seznamu je ({mergeGroup.count}×), jídla se s ním sloučí.
|
||||
</Alert>
|
||||
)}
|
||||
<div className="d-flex justify-content-end gap-2">
|
||||
<Button variant="outline-secondary" onClick={() => onCancel()}>Zrušit</Button>
|
||||
<Button type="submit" disabled={!canSave}>
|
||||
{saving ? 'Ukládám…' : 'Změnit u všech jídel'}
|
||||
</Button>
|
||||
</div>
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
|
||||
export default MealGroupRenameForm;
|
||||
Reference in new issue
Block a user