feat: zlepšení šablon, přidány osobní údaje a spánkový režim
This commit is contained in:
@@ -60,7 +60,8 @@ cd client && yarn build # tsc --noEmit + vite build → client/dist
|
||||
- **Routes:** `routes/` — `dayRoutes`, `mealRoutes`, `activityRoutes`, `workoutRoutes`,
|
||||
`statsRoutes`, `calorieRoutes`, `settingsRoutes`, `importRoutes`
|
||||
- **Domain:** `meals.ts` (jídlo), `activities.ts` (pohyb), `workouts.ts` (šablony
|
||||
tréninků), `dayOverview.ts` (spojení dne a bilance), `statsService.ts` (agregace),
|
||||
tréninků), `sleep.ts` (spánek), `profile.ts` (tělesné údaje a výpočet BMR),
|
||||
`dayOverview.ts` (spojení dne a bilance), `statsService.ts` (agregace),
|
||||
`luncherImport.ts` (parsování exportů z Luncheru), `settings.ts`, `calories.ts`
|
||||
- **Auth:** `auth.ts` — JWT + volitelná autentizace z hlavičky reverzní proxy
|
||||
- **Storage:** `storage/index.ts` factory dle proměnné `STORAGE`; backendy:
|
||||
@@ -70,9 +71,12 @@ cd client && yarn build # tsc --noEmit + vite build → client/dist
|
||||
### Client (client/src/)
|
||||
- **Entry:** `index.tsx` → `AppRoutes.tsx`; `Login.tsx` je přihlašovací obrazovka
|
||||
- **Pages:** `pages/` — `DayPage` (přehled dne se záložkami Příjem/Výdej),
|
||||
`TemplatesPage` (šablony tréninků), `ProfilePage` (tělesné údaje a klidový výdej),
|
||||
`StatsPage` (statistiky + import)
|
||||
- **Components:** `components/` (Header, CalorieLookup) a `components/modals/`
|
||||
(MealModal, ActivityModal, WorkoutModal, SettingsModal, ImportModal)
|
||||
(MealModal, ActivityModal, ApplyWorkoutModal, SettingsModal, ImportModal)
|
||||
- **Klientské enumy** patří do `enums.ts` jako TypeScript `enum` s mapou popisků,
|
||||
ne jako inline union u komponenty (`DayTab`, `StatsRange`)
|
||||
- **Context:** `context/auth.tsx` (JWT), `context/settings.tsx` (světlý/tmavý motiv)
|
||||
- **Routing:** konstanty adres jsou v `routes.ts`, ne v `AppRoutes.tsx` — hlavička
|
||||
je potřebuje a kruhový import by je nechal nedefinované
|
||||
@@ -140,23 +144,72 @@ Den má dvě strany a `DayPage` je dělí do záložek:
|
||||
- **Výdej** — pohyb (`ActivityEntry`), klíč `activities:<login>:<datum>`
|
||||
|
||||
Aktivita se měří v jednotce (`ActivityUnit`: KROKY, MINUTY, KM, OPAKOVANI) a
|
||||
kalorie se dopočtou jako `quantity / 100 * caloriesPer100Units`. **Sto jednotek,
|
||||
ne jedna** — u kroků by sazba na jeden krok byla zlomek (~0,04 kcal) a aplikace
|
||||
všude pracuje s celými čísly. Stejná konvence jako u energie jídla na 100 g.
|
||||
kalorie se dopočtou jako `getTotalQuantity(quantity, sets) / 100 * caloriesPer100Units`.
|
||||
**Sto jednotek, ne jedna** — u kroků by sazba na jeden krok byla zlomek (~0,04 kcal)
|
||||
a aplikace všude pracuje s celými čísly. Stejná konvence jako u energie jídla na 100 g.
|
||||
|
||||
`WorkoutTemplate` (`workouts.ts`) je pojmenovaný seznam cviků. Použitím vzniknou
|
||||
běžné aktivity s vazbou `templateId` — jsou samostatné, takže úprava založené
|
||||
položky šablonu nemění.
|
||||
`quantity` je množství **na jednu sérii**, `sets` je počet sérií; celkové množství
|
||||
je jejich součin. Drží se odděleně schválně: 3 × 40 opakování s pauzami je jiný
|
||||
trénink než 120 v kuse, i když spálené kalorie vyjdou stejně. Jedna série je
|
||||
výchozí stav a neukládá se.
|
||||
|
||||
Opačný směr k použití šablony je `createWorkoutTemplateFromActivities` —
|
||||
z aktivit odcvičeného dne (všech, nebo vybraných) vznikne šablona. U jídla to
|
||||
umí `createMealTemplateFromMeal`, které navíc **přepíše šablonu stejného názvu**;
|
||||
opakované "uložit jako šablonu" u téhož jídla má dát jednu šablonu, ne několik
|
||||
stejných. Záznamy ve dni zůstanou v obou případech beze změny.
|
||||
|
||||
`WorkoutTemplate` (`workouts.ts`) je pojmenovaný seznam položek. Položka je buď
|
||||
cvik (`kind: CVIK`), nebo odkaz na jinou šablonu (`kind: SABLONA`), jejíž cviky se
|
||||
při použití rozbalí. Použitím vzniknou běžné aktivity s vazbou `templateId` — jsou
|
||||
samostatné, takže úprava založené položky šablonu nemění.
|
||||
|
||||
**Zanoření je povolené jen na jednu úroveň** a `checkNesting` to hlídá z obou stran:
|
||||
šablona nesmí odkazovat na takovou, která sama něco skládá, a zároveň nesmí začít
|
||||
skládat, pokud ji už někdo používá. Bez druhé kontroly by druhá úroveň vznikla
|
||||
oklikou přes úpravu. Smazat nelze šablonu, kterou skládá jiná — zůstal by odkaz
|
||||
do prázdna. Šablony uložené dřív, než skládání přibylo, nemají `kind`; `withKind`
|
||||
jim ho při načtení doplní na `CVIK`.
|
||||
|
||||
`buildEnergyBalance` v `dayOverview.ts` počítá:
|
||||
`bilance = příjem − (klidový výdej + pohyb)`. Záporná hodnota je deficit.
|
||||
Bez nastaveného klidového výdeje (`basalCalories` v nastavení) porovnává bilance
|
||||
jen jídlo proti pohybu — **to není skutečný deficit**, proto se to přes
|
||||
`hasBasal: false` propisuje do UI, aby to číslo nikoho nemátlo.
|
||||
Bez nastaveného klidového výdeje porovnává bilance jen jídlo proti pohybu —
|
||||
**to není skutečný deficit**, proto se to přes `hasBasal: false` propisuje do UI,
|
||||
aby to číslo nikoho nemátlo.
|
||||
|
||||
Klidový výdej se bere z `settings.effectiveBasalCalories`: ručně zadaný
|
||||
`basalCalories` má přednost před hodnotou spočítanou z tělesných údajů
|
||||
(`computeBasalCalories` v `profile.ts`, rovnice Mifflin–St Jeor). Výpočet
|
||||
**záměrně nenásobí koeficientem fyzické aktivity (PAL)**, jak to dělají kalkulačky
|
||||
TDEE — pohyb se eviduje zvlášť a přičítá se, takže vynásobení by ho započítalo
|
||||
dvakrát.
|
||||
|
||||
**Spánek** (`sleep.ts`, klíč `sleep:<login>:<datum>`) se eviduje jako kontext dne
|
||||
a do bilance **nevstupuje**. Klidový výdej je hodnota za celých 24 hodin včetně
|
||||
spánku a žádná ze standardních rovnic délku spánku jako proměnnou nemá — přičítat
|
||||
nebo odečítat za něj kalorie by bylo vymýšlení čísla. Test to hlídá:
|
||||
bilance se po zadání spánku nesmí změnit.
|
||||
|
||||
`GET /api/day?date=` vrací `DayOverview` se vším naráz (jídlo, pohyb, bilance),
|
||||
takže `DayPage` si vystačí s jedním voláním.
|
||||
|
||||
## Šablony jídel
|
||||
|
||||
`MealTemplate` (`mealTemplates.ts`, klíč `mealTemplates:<login>`) je opakovaně
|
||||
jedené jídlo. Na rozdíl od šablon tréninků se **neskládá z jiných** — je to plochý
|
||||
záznam. Použitím vznikne běžný `MealEntry` přes `addMeal`, takže gramáž, cenu
|
||||
i kalorie dopočítá stejná logika jako u ručně zadaného jídla.
|
||||
|
||||
Šablona může nést buď `calories` (celá porce), nebo `caloriesPer100g` + `weight`.
|
||||
Obojí projde `deriveAmounts`, takže stačí vyplnit, co o jídle víte.
|
||||
|
||||
Pole `note` slouží i na postup přípravy u domácích jídel. Strukturované suroviny
|
||||
(recept jako seznam položek s množstvím) mohou přibýt později jako další volitelné
|
||||
pole, aniž by se muselo měnit cokoli stávajícího.
|
||||
|
||||
Kontrakt má vlastní `MealTemplateInput`, kde je `id` volitelné — `MealTemplate`
|
||||
ho vyžaduje a nešlo by jím posílat novou šablonu.
|
||||
|
||||
## Import z Luncheru
|
||||
|
||||
`server/src/luncherImport.ts` čte měsíční přehled ze stránky statistik Luncheru
|
||||
|
||||
Reference in New Issue
Block a user