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

+43 -2
View File
@@ -1,7 +1,7 @@
import { randomUUID } from 'crypto';
import { ActivityDay, ActivityEntry, ActivityUnit } from "../../types/gen/types.gen";
import getStorage from "./storage";
import { BadRequestError, NotFoundError, isValidIsoDate } from "./utils";
import { BadRequestError, NotFoundError, applyMultiplier, isValidIsoDate, normalizeMultiplier } from "./utils";
const storage = getStorage();
@@ -33,7 +33,7 @@ export function buildActivityDay(date: string, entries: ActivityEntry[]): Activi
return {
date,
entries: sorted,
totalCalories: sorted.reduce((sum, entry) => sum + (entry.calories ?? 0), 0),
totalCalories: sorted.reduce((sum, entry) => sum + (applyMultiplier(entry.calories, entry.multiplier) ?? 0), 0),
};
}
@@ -87,6 +87,9 @@ export type NormalizedActivityInput = {
caloriesPer100Units?: number;
calories?: number;
note?: string;
/** Dodatečná zátěž v gramech — jen informace, kalorie nemění. */
extraWeightGrams?: number;
multiplier?: number;
};
/**
@@ -140,6 +143,8 @@ export function normalizeActivityInput(input: unknown): NormalizedActivityInput
caloriesPer100Units: normalizeNumber(value.caloriesPer100Units, 'caloriesPer100Units'),
calories: normalizeNumber(value.calories, 'calories'),
note: normalizeText(value.note, 'note'),
extraWeightGrams: normalizeNumber(value.extraWeightGrams, 'extraWeightGrams') || undefined,
multiplier: normalizeMultiplier(value.multiplier),
});
}
@@ -214,6 +219,8 @@ export async function updateActivity(login: string, id: unknown, input: unknown)
caloriesPer100Units: normalized.caloriesPer100Units,
calories: normalized.calories,
note: normalized.note,
extraWeightGrams: normalized.extraWeightGrams,
multiplier: normalized.multiplier,
updatedAt: new Date().toISOString(),
};
await storage.updateData<ActivityEntry[]>(
@@ -248,6 +255,40 @@ export async function deleteActivity(login: string, id: unknown, date: unknown):
return date;
}
/**
* Nastaví násobek aktivity přímo z přehledu dne. Ostatní údaje zůstanou beze změny.
*
* @param login přihlašovací jméno uživatele
* @param id identifikátor záznamu
* @param date datum záznamu (YYYY-MM-DD)
* @param multiplier nový násobek; 1 násobek zruší
* @returns datum, ve kterém aktivita je
*/
export async function setActivityMultiplier(login: string, id: unknown, date: unknown, multiplier: unknown): Promise<string> {
if (typeof id !== 'string' || !id.length) {
throw new BadRequestError("Nebyl předán identifikátor záznamu");
}
if (!isValidIsoDate(date)) {
throw new BadRequestError("Nebylo předáno platné datum ve formátu YYYY-MM-DD");
}
if (multiplier == null) {
throw new BadRequestError("Nebyl předán násobek");
}
const normalized = normalizeMultiplier(multiplier);
let found = false;
await storage.updateData<ActivityEntry[]>(getDayKey(login, date), current => (current ?? []).map(entry => {
if (entry.id !== id) return entry;
found = true;
const updated: ActivityEntry = { ...entry, multiplier: normalized, updatedAt: new Date().toISOString() };
if (normalized == null) delete updated.multiplier;
return updated;
}));
if (!found) {
throw new NotFoundError("Aktivita nebyla nalezena");
}
return date;
}
/** Najde datum, pod kterým je aktivita uložená. Úprava totiž může měnit i datum. */
async function findActivityDate(login: string, id: string, expectedDate: string): Promise<string | undefined> {
const expected = await storage.getData<ActivityEntry[]>(getDayKey(login, expectedDate));