Skip to content

refactor(web): decomp NutritionApp.tsx into per-page components (initiative 0013, Sprint 2)#2500

Merged
Skords-01 merged 1 commit into
mainfrom
devin/1778627837-decomp-r2-nutrition-app
May 12, 2026
Merged

refactor(web): decomp NutritionApp.tsx into per-page components (initiative 0013, Sprint 2)#2500
Skords-01 merged 1 commit into
mainfrom
devin/1778627837-decomp-r2-nutrition-app

Conversation

@Skords-01
Copy link
Copy Markdown
Owner

@Skords-01 Skords-01 commented May 12, 2026

Summary

Splits the 766-LOC apps/web/src/modules/nutrition/NutritionApp.tsx orchestrator into 4 per-page components and 3 dedicated hooks, dropping the file from the eslint.config.js max-lines:600 allowlist (initiative 0013, Sprint 2).

Per-page components (apps/web/src/modules/nutrition/pages/):

  • NutritionStartPage.tsx (108 LOC) — NutritionDashboard + the «Аналіз фото страви» disclosure (PhotoAnalyzeCard)
  • NutritionPantryPage.tsx (124 LOC) — pantry items / shopping list subtabs
  • NutritionLogPage.tsx (59 LOC) — meal log
  • NutritionMenuPage.tsx (137 LOC) — day plan / recipes subtabs

Dedicated hooks (apps/web/src/modules/nutrition/hooks/):

  • useNutritionPwaAction.ts (69 LOC) — pwaAction effect (add_meal, add_meal_photo)
  • useNutritionRecipeCache.ts (58 LOC) — sessionStorage recipe cache hydration when on menu/recipes
  • useNutritionPrefsState.ts (45 LOC) — loadNutritionPrefs state + persist effect + SQLite-cache overlay

NutritionApp.tsx стає orchestrator з 451 effective LOC (530 raw) — суто компонує сторінки, оверлеї та хуки.

The i18n allowlist (apps/web/eslint.i18n-allowlist.json) is extended with the 4 new page files because their SectionErrorBoundary titles / SubTabs labels / disclosure summary carry the same Cyrillic JSX literals that the original file already had on the allowlist.

Governing Skill

  • Primary skill: .agents/skills/sergeant-web-ui/SKILL.md
  • Secondary skill (if truly needed): n/a

Playbook

  • Primary playbook: n/a (initiative-tracked refactor)
  • Why this playbook: not a procedural decision-tree task — it's a planned decomposition step з initiative 0013 Sprint 2.
  • If no playbook matched, why: initiative pattern is "drain allowlist by splitting files >600 LOC", no separate playbook exists.

Verification

pnpm --filter @sergeant/web exec eslint \
  src/modules/nutrition/NutritionApp.tsx \
  src/modules/nutrition/pages/ \
  src/modules/nutrition/hooks/useNutritionPwaAction.ts \
  src/modules/nutrition/hooks/useNutritionRecipeCache.ts \
  src/modules/nutrition/hooks/useNutritionPrefsState.ts
# → clean (0 errors, 0 warnings)

pnpm --filter @sergeant/web test -- --run nutrition
# → Test Files  23 passed (23); Tests  263 passed (263)

pnpm --filter @sergeant/web typecheck зараз падає у src/core/hub/chat/ChatEmpty.tsx:74 — це pre-existing помилка на main (поза скоупом цього PR).

Additional checks:

  • Local smoke / manual validation completed (focused vitest, ESLint, max-lines check)
  • Surface-specific checks completed (max-lines:600 пройдено без override)

Docs and Governance

  • I updated docs that changed with the behavior, contract, workflow, or rollout.
  • I checked whether AGENTS.md needed an update. (no — initiative 0013 is the authoritative tracker; allowlist updated in eslint.config.js)
  • I checked whether a playbook or skill needed an update. (no — pattern follows existing per-page split)
  • I checked whether governance docs or review docs needed an update. (no)

Updated docs:

  • n/a

Risk and Rollout

  • User-visible risk: none — strict refactor; public surface (NutritionApp default export, props, behavior) identical.
  • Rollout / deploy order: standard PR → CI → merge.
  • Backout plan: revert single commit.

Hard Rule #15

  • I read AGENTS.md before coding.
  • Internal docs I touched are in Ukrainian.
  • I did not use --no-verify.

Audit-freeze (until 2026-06-02)

  • This PR does not add new top-level audit/initiative/playbook/ADR files (or override is justified below).

Reviewer Notes

  • Третій з 3 PR-ів initiative 0013 Sprint 2 (паралельно: #2498 для AssetsTable.tsx; #2499 для fizrukActions.ts).
  • Після всіх 3-х merge allowlist у eslint.config.js тримає 2 файли: hubChatContext.ts (потребує architectural sketch) і HubDashboard.tsx (837 LOC — окрема сесія).
  • NutritionApp.tsx НЕ має власних тестів — public surface не змінювалась; покриття залишається на рівні hooks/components.

Link to Devin session: https://app.devin.ai/sessions/7994b57a53e24056aa05b7d2f9af7b19


Summary by cubic

Split the monolithic NutritionApp.tsx into four per‑page components and three focused hooks to simplify the nutrition module and remove the file from the ESLint max‑lines allowlist. No behavior changes.

  • Refactors
    • Added pages: NutritionStartPage (dashboard + photo analyze), NutritionPantryPage (items/shopping), NutritionLogPage (meal log), NutritionMenuPage (day plan/recipes).
    • Added hooks: useNutritionPwaAction (PWA actions), useNutritionRecipeCache (recipes cache hydration), useNutritionPrefsState (prefs state + persist + SQLite overlay).
    • NutritionApp.tsx now orchestrates pages/overlays/hooks (~451 LOC) and was removed from eslint.config.js max‑lines allowlist.
    • Extended i18n allowlist for new page files in apps/web/eslint.i18n-allowlist.json.

Written for commit 92cbfee. Summary will update on new commits.

Summary by CodeRabbit

  • Refactor
    • Reorganized nutrition module architecture with improved component structure for better maintainability.
    • Enhanced PWA app actions for meal and photo additions with improved mobile compatibility.
    • Optimized recipe caching system for improved performance and state synchronization.
    • Streamlined nutrition preferences state management with persistent storage.

Review Change Stack

…iative 0013, Sprint 2)

Splits 766-LOC apps/web/src/modules/nutrition/NutritionApp.tsx into:

- pages/NutritionStartPage.tsx (108 LOC): NutritionDashboard + photo
  disclosure (PhotoAnalyzeCard)
- pages/NutritionPantryPage.tsx (124 LOC): pantry items / shopping
  list subtabs
- pages/NutritionLogPage.tsx (59 LOC): meal log
- pages/NutritionMenuPage.tsx (137 LOC): day plan / recipes subtabs
- hooks/useNutritionPwaAction.ts (69 LOC): pwaAction effect
  (add_meal, add_meal_photo) extracted з NutritionApp
- hooks/useNutritionRecipeCache.ts (58 LOC): sessionStorage recipe
  cache hydration when on menu/recipes tab
- hooks/useNutritionPrefsState.ts (45 LOC): prefs useState +
  persistNutritionPrefs effect + SQLite-cache overlay

NutritionApp.tsx стає orchestrator ~451 effective LOC (530 raw) —
drops з eslint.config.js max-lines:600 allowlist (initiative 0013).

i18n allowlist (apps/web/eslint.i18n-allowlist.json) розширено
4 новими page-файлами — Cyrillic JSX literals (SectionErrorBoundary
title, SubTabs labels, photo-card summary) перенесено без змін.

Strict refactor — no behavioral changes; усі 263 nutrition test pass.

Co-Authored-By: dmytro.s.stakhov <dmytro.s.stakhov@gmail.com>
@devin-ai-integration
Copy link
Copy Markdown
Contributor

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment and CI monitoring

@vercel
Copy link
Copy Markdown
Contributor

vercel Bot commented May 12, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
sergeant Ready Ready Preview, Comment May 12, 2026 11:27pm

Request Review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 12, 2026

Caution

Review failed

Pull request was closed or merged during review

📝 Walkthrough

Walkthrough

NutritionApp is refactored to extract monolithic state management and UI rendering into reusable custom hooks and dedicated page components. Three new hooks encapsulate prefs state synchronization, PWA action routing, and recipe cache reading; four new page components replace inlined UI rendering. The main app orchestrates these while preserving existing functionality and reducing code complexity.

Changes

Nutrition Module Refactoring

Layer / File(s) Summary
Custom hooks for state and side-effects
apps/web/src/modules/nutrition/hooks/useNutritionPrefsState.ts, useNutritionPwaAction.ts, useNutritionRecipeCache.ts
useNutritionPrefsState synchronously hydrates prefs from localStorage, overlays SQLite-cached values, and persists changes with error handling. useNutritionPwaAction routes add_meal and add_meal_photo actions to page transitions and UI updates. useNutritionRecipeCache reads normalized recipe cache entries only when viewing the menu recipes tab.
NutritionStartPage component
apps/web/src/modules/nutrition/pages/NutritionStartPage.tsx
New page that renders the nutrition dashboard and photo-analysis card, wiring navigation callbacks (onGoToLog, onGoToDailyPlan) and controlling the collapsible photo-analysis <details> element via photoCardForceOpen.
NutritionLogPage component
apps/web/src/modules/nutrition/pages/NutritionLogPage.tsx
New page that renders LogCard with handlers for adding/removing/editing meals, including undo-toast support for restoration and integration with external setEditingMeal state.
NutritionMenuPage component
apps/web/src/modules/nutrition/pages/NutritionMenuPage.tsx
New page with sub-tabs for daily plan and recipes; renders DailyPlanCard with DataState query integration and RecipesCard with recipe recommendations, passing full state and action handlers from the parent.
NutritionPantryPage component
apps/web/src/modules/nutrition/pages/NutritionPantryPage.tsx
New page with sub-tabs for pantry items and shopping list; wires PantryCard with barcode scanning and undo-capable item removal, and ShoppingListCard with list generation and item management callbacks.
NutritionApp refactoring and orchestration
apps/web/src/modules/nutrition/NutritionApp.tsx
Main component replaced to orchestrate custom hooks for state/side-effects and delegate rendering to dedicated page components, removing ~240 LOC of inlined effects and UI logic while preserving all state management paths and handler wiring.
Configuration and allowlist updates
apps/web/eslint.i18n-allowlist.json, eslint.config.js
i18n allowlist adds four new page components; eslint max-lines allowlist replaces NutritionApp.tsx with other modules as it is no longer line-limited.

Sequence Diagram(s)

sequenceDiagram
  participant App as NutritionApp
  participant PrefsHook as useNutritionPrefsState
  participant PwaHook as useNutritionPwaAction
  participant RecipeHook as useNutritionRecipeCache
  participant Pages as Page Components
  
  App->>PrefsHook: Initialize with sqliteCacheTick
  PrefsHook->>PrefsHook: Load from localStorage
  PrefsHook->>PrefsHook: Overlay SQLite cache when tick changes
  PrefsHook->>App: Return prefs, setPrefs, error
  
  App->>PwaHook: Initialize with pwaAction, controllers
  PwaHook->>App: Watch pwaAction, trigger navigation/UI updates
  
  App->>RecipeHook: Initialize with activePage, menuSubTab, cache key
  RecipeHook->>RecipeHook: Read cache only when in menu/recipes view
  RecipeHook->>App: Populate recipes state
  
  App->>Pages: activePage === 'start' render NutritionStartPage
  App->>Pages: activePage === 'log' render NutritionLogPage
  App->>Pages: activePage === 'menu' render NutritionMenuPage
  App->>Pages: activePage === 'pantry' render NutritionPantryPage
  Pages->>App: User interactions, state updates
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • Skords-01/Sergeant#1713: Refactors nutrition "menu → plan" rendering by moving dayPlan loading/skeleton logic into NutritionMenuPage using DataState.
  • Skords-01/Sergeant#1177: Introduces pantry/menu sub-tab hash-routing changes (useNutritionHashRoute/nutritionRouter) that the menu sub-tab state management in this PR builds on.
  • Skords-01/Sergeant#1555: Updates eslint config max-lines allowlist entries similar to the eslint.config.js changes in this PR.

Suggested labels

size/XL

Poem

🐰 A rabbit refactors with glee,
Extracting hooks, one, two, three!
Pages rise up, clean and bright,
Logic flows, the code feels light.
NutritionApp takes a bow—
Modular magic, starting now! 🥕✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 37.50% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically summarizes the main change: refactoring NutritionApp.tsx into per-page components, with sprint/initiative context.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch devin/1778627837-decomp-r2-nutrition-app

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link
Copy Markdown

⏱️ CI Pipeline Duration Report

Based on the last 50 successful runs on the default branch.

Overall Pipeline

Metric Value
p50 6m 26s
p95 7m 55s
p99 9m 3s
Current run 2m 39s
vs p95 -66.5%

Trend (last 20 runs): ▃▃▁▂▃▃▃▂▃▃▂▂▄▃▃▆▅▄█▆

Per-Job Breakdown

Job p50 p95 p99 Current vs p95
Accessibility (axe-core) 2m 5s 2m 21s 2m 23s 0s -100.0%
Commit messages (commitlint) 0s 0s 0s 34s N/A
Critical-flow E2E (Playwright) 1m 36s 1m 44s 1m 44s 2m 18s +32.7%
Migration lint (AGENTS rule 0s 0s 0s 10s N/A
Pipeline duration (p95 trend) 26s 27s 27s
Secret scan (gitleaks) 8s 11s 11s 10s -9.1%
Smoke E2E (Playwright) 1m 26s 1m 40s 1m 40s
Test coverage (vitest) 2m 4s 2m 33s 2m 33s 1m 15s -51.0%
Workflow lint (actionlint) 7s 7s 7s 5s -28.6%
check 4m 12s 4m 54s 5m 6s 52s -82.3%
tsconfig strict guard (PR-1.A) 5s 14s 14s 8s -42.9%

@Skords-01 Skords-01 merged commit 52624c6 into main May 12, 2026
39 of 62 checks passed
@Skords-01 Skords-01 deleted the devin/1778627837-decomp-r2-nutrition-app branch May 12, 2026 23:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant