feat: import jen některých dnů

feat: násobení jídel/cviků
feat: refaktor napojování šablon
This commit is contained in:
Ondřej Anděl committed 2026-09-30 19:10:54 +02:00
1 parent c3990d80f8
commit 8dac67bdd1
37 files changed
+2314 -481

No files matched your search

+39
View File
@@ -73,3 +73,42 @@ export function listDatesInRange(from: string, to: string): string[] {
}
return dates;
}
/** Nejvyšší povolený násobek porce nebo aktivity — pojistka proti překlepu. */
const MAX_MULTIPLIER = 100;
/**
* Ověří násobek porce nebo aktivity a zaokrouhlí ho na setiny.
*
* Násobek 1 je výchozí stav, proto se vrací jako undefined a neukládá se —
* stejně jako jedna série u aktivit.
*
* @param value vstupní hodnota
*/
export const normalizeMultiplier = (value: unknown): number | undefined => {
if (value == null) return undefined;
if (typeof value !== 'number' || !Number.isFinite(value)) {
throw new BadRequestError("Násobek musí být číslo");
}
const rounded = Math.round(value * 100) / 100;
if (rounded <= 0) {
throw new BadRequestError("Násobek musí být kladné číslo");
}
if (rounded > MAX_MULTIPLIER) {
throw new BadRequestError(`Násobek může být nejvýše ${MAX_MULTIPLIER}`);
}
return rounded === 1 ? undefined : rounded;
};
/**
* Vrátí kalorie záznamu po započtení násobku.
*
* Uložené kalorie jsou vždy za jednu porci (jedno provedení), aby šlo násobek
* měnit tam a zpět bez ztráty přesnosti zaokrouhlováním. Klient má stejnou
* funkci v `Utils.tsx` — musí dávat stejné výsledky.
*
* @param calories kcal jedné porce
* @param multiplier násobek, nevyplněný znamená 1
*/
export const applyMultiplier = (calories: number | undefined, multiplier?: number): number | undefined =>
calories == null ? undefined : Math.round(calories * (multiplier ?? 1));