From 7d064c7d95c0b56f3b4b1ccdf779cb6060d1e73e Mon Sep 17 00:00:00 2001 From: Devin Date: Mon, 4 May 2026 16:42:00 +0000 Subject: [PATCH] refactor(web): adopt in nutrition panels Wrap the nutrition Menu "plan" tab skeleton/card path with the unified wrapper so the day-plan generation skeleton flows through the same loading contract that the rest of the web app already uses (initiative 0011 PR 2.6). The visible behaviour is preserved: while `dayPlanBusy` is `true` we render the same SkeletonText + Skeleton + 3x SkeletonMealCard shimmer cluster as before; otherwise is rendered with the existing props (including dayPlan/dayPlanBusy so its internal "regenerate meal" affordances keep working). The recipes sub-tab branch is unchanged. Why DataState here (and not, say, in the meal-sheet food search): NutritionApp.tsx is the only consumer in apps/web/src/modules/nutrition that imports the shared primitives; the food-search `foodBusy`/`offBusy` flags drive inline list states, not panel-level loading swaps, and are already abstracted at the hook layer. --- .../src/modules/nutrition/NutritionApp.tsx | 77 ++++++++++++------- 1 file changed, 48 insertions(+), 29 deletions(-) diff --git a/apps/web/src/modules/nutrition/NutritionApp.tsx b/apps/web/src/modules/nutrition/NutritionApp.tsx index b9440ea26..d7563a915 100644 --- a/apps/web/src/modules/nutrition/NutritionApp.tsx +++ b/apps/web/src/modules/nutrition/NutritionApp.tsx @@ -5,6 +5,11 @@ import { SkeletonText, Skeleton, } from "@shared/components/ui/Skeleton"; +import { + DataState, + type DataStateQueryLike, +} from "@shared/components/ui/DataState"; +import type { NutritionDayPlan } from "./hooks/useNutritionUiState"; import { NutritionHeader } from "./components/NutritionHeader"; import { NutritionBottomNav } from "./components/NutritionBottomNav"; import { SubTabs } from "./components/SubTabs"; @@ -413,6 +418,27 @@ export default function NutritionApp({ toast.error("Не вдалося оновити дані. Перевір з'єднання."); }, [toast]); + const dayPlanQuery: DataStateQueryLike = { + data: dayPlanBusy ? undefined : dayPlan, + isLoading: dayPlanBusy, + }; + + const dayPlanLoadingSkeleton = ( +
+
+ + +
+ {[0, 1, 2].map((i) => ( + + ))} +
+ ); + return ( @@ -624,36 +650,29 @@ export default function NutritionApp({ { id: "recipes", label: "Рецепти" }, ]} /> - {menuSubTab === "plan" && dayPlanBusy ? ( -
-
- - -
- {[0, 1, 2].map((i) => ( - + {() => ( + fetchDayPlan(null)} + regenMeal={(mealType) => fetchDayPlan(mealType)} + addMealToLog={addMealFromPlan} + weekPlan={weekPlan} + weekPlanRaw={weekPlanRaw} + weekPlanBusy={weekPlanBusy} + fetchWeekPlan={fetchWeekPlan} /> - ))} -
- ) : menuSubTab === "plan" ? ( - fetchDayPlan(null)} - regenMeal={(mealType) => fetchDayPlan(mealType)} - addMealToLog={addMealFromPlan} - weekPlan={weekPlan} - weekPlanRaw={weekPlanRaw} - weekPlanBusy={weekPlanBusy} - fetchWeekPlan={fetchWeekPlan} - /> + )} +
) : (