feat: split jídel

feat: graf příjmů
This commit is contained in:
Ondřej Anděl committed 2026-10-09 15:15:04 +02:00
1 parent bc85a37fc0
commit b880b36edd
32 files changed
+2048 -262

No files matched your search

+22 -3
View File
@@ -75,16 +75,18 @@ cd client && yarn build # tsc --noEmit + vite build → client/dist
- **Pages:** `pages/` — `DayPage` (přehled dne se záložkami Příjem/Výdej),
`TemplatesPage` (šablony tréninků a recepty), `ProfilePage` (Profil — ukazatele,
vývoj hmotnosti, tělesné údaje, cíle a klidový výdej),
`StatsPage` (statistiky příjmu a výdeje + import; výdej v `ActivityStatsPanel`),
`StatsPage` (statistiky se záložkami Příjem / Výdej / Útrata a import; panely
`IntakeStatsPanel`, `ActivityStatsPanel`, `SpendingStatsPanel`),
`MealGroupsPage` (`/statistiky/doplneni` — hromadné doplnění údajů jídel)
- **Components:** `components/` (Header, CalorieLookup, MealSuggestions, NutrientsFieldset)
a `components/modals/` (MealModal, ActivityModal, ApplyWorkoutModal, ApplyMealModal —
výběr z historie a receptů, SettingsModal, ImportModal)
- **Klientské enumy** patří do `enums.ts` jako TypeScript `enum` s mapou popisků,
ne jako inline union u komponenty (`DayTab`, `StatsRange`)
ne jako inline union u komponenty (`DayTab`, `StatsTab`, `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é
je potřebuje a kruhový import by je nechal nedefinované. Přehled dne čte datum
z parametru `?datum=YYYY-MM-DD` (`getDayUrl`), na konkrétní den se tak dá odkázat
- **Styling:** Bootstrap 5 + React Bootstrap + SCSS; design systém a proměnné
`--ft-*` jsou v `App.scss`, stránkové styly co-located vedle komponent
- **API:** přes OpenAPI SDK z `types/gen/`
@@ -250,6 +252,14 @@ stejný cvik dvakrát. Smazání všech cviků šablony ve dni `dropOrphanedPlan
bere jako vrácené použití a plán zahodí. Aktivity ze šablony bez plánu (cvik
přesunutý z jiného dne) se počítají jako splněné přesně dle plánu.
**Statistiky příjmu** (`getIntakeStats`, `GET /api/stats/intake`) jsou protějšek
výdeje: příjem po chodech a zdrojích, živiny a porovnání s výdejem. Výdej
a bilance se počítají **jen za dny, kdy má aspoň jedno jídlo kalorie**
(`caloriesDayCount`) — den bez zápisu nebo s jídly z importu bez kalorií by jinak
vypadal jako deficit celého výdeje. Ze stejného důvodu z nich vycházejí průměry.
Klidový výdej je k hmotnosti platné v daný den (`getBasalOn` v `dayOverview.ts`).
Peníze za jídlo jsou na samostatné záložce Útrata (`getFoodStats`, `/api/stats/summary`).
`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.
@@ -279,6 +289,8 @@ ostatních jídel stejného názvu, která je nemají (`fillSameNameMeals`,
**Hromadné doplnění** (`MealGroupsPage`, odkaz ze Statistik → Příjem) seskupí
jídla podle znormalizovaného názvu **a zdroje** (`getMealGroups`,
`GET /api/meals/groups`) a ukáže, kolika chybí kalorie, gramáž a živiny.
Skupina nese i dny, kdy se jídlo jedlo (`MealGroup.days`, s příznakem neúplných
údajů), a stránka je nabízí jako odkazy na přehled dne v nové záložce.
`fillMealGroup` (`POST /api/meals/fillGroup`) doplní do skupiny **jen chybějící
hodnoty**: gramáž ne tam, kde jde dopočítat z vlastní ceny a sazby, energii jen
jídlům bez kalorií (jinak by dopočet přepsal ručně zadané kalorie), živiny po
@@ -343,6 +355,13 @@ ve všech třech formátech, které Luncher exportuje (XLSX, CSV, JSON — viz
dnech jsou (`existing`). Uživatel v něm řádky odškrtá a ostrý import dostane
jen `selectedKeys`.
Jídlo, které Luncher zapsal jako jedno ("Chicken tikka massala+garlic nun"),
jde v přehledu dne rozdělit (`MealSplitModal`, `splitMeal`, `POST /api/meals/split`)
— import se kvůli tomu nekomplikuje. Původní záznam si nechá `importKey`, takže
ho režim PRIDAT znovu nezaloží; odštěpená část dostane jen `importSource`, aby ji
režim NAHRADIT odebral spolu s původním a nevzniklo jídlo dvakrát. Cena se mezi
části nedopočítává, rozdělí se jen na vyžádání (napůl).
**Když se změní formát exportu v Luncheru, je potřeba upravit i tento parser**
a testy v `server/src/tests/luncherImport.test.ts`, které si export sestavují
přesně tak, jak ho Luncher generuje.