Conversation
- Move useFood() hook from Landing to NutritionSection - Remove data/loading/error props from component chain - Simplify FoodHome by removing loading state - Enable lazy data fetching on user interaction instead of mount - Improve component independence and testability
- Add ErrorBoundary class component with reset functionality wrapping the app - Handle edge cases in fetchFood: empty results, unexpected response shape, axios vs non-axios errors with HTTP status messages - Guard per-card missing nutriments in NutritionSection - Switch data source from Open Food Facts to wger Ingredient API - Update types (WgerIngredient, WgerResponse) and fetchFood to return Product[] - Refactor useFood hook state from Product|null to Product[] - Refactor NutritionSection into responsive 3-column card grid
…ng, and tests - guard numeric parsing using tofinite to prevent nan values in nutriments - move wger base url to vite_wger_api_url and pass query params via axios `params` - add `id` to wgeringredient/product models, map through response, and use `product.id` as react list key - fix tailwind class typo (`bg-gradient-to-br`) in nutritionsection.tsx - surface thrown error messages in usefood with safe fallback handling - rename single-letter variables to descriptive names for improved readability - update tests, mocks, and test setup to align with implementation changes; all tests passing
Change SummaryImplements Zustand-backed favorites state management across the nutrition experience, persisting bookmarked product IDs and providing toggleable views. Introduces reusable UI pieces (FoodCard, FavoriteToggleButton, NutritionGrid) plus landing, nutrition, and error boundary compositions for consistent navigation between home and favorites views. Refreshes entry/loading configuration and expands testing coverage for hooks, API service, favorites store, and Button component to capture the new behavior. File Changes
Based on 8200786...d0a9703 |
PR ReviewPR Communication NotesDescription Quality
PR Size & Scope
Commit Messages
Issue NotesCode Correctness & Design Quality
Test Quality & Coverage
Code Readability & Maintainability
💬 Minor Issues (Nitpicks)Code Readability & Maintainability
Based on 8200786...d0a9703 |
| <button | ||
| type={type} | ||
| disabled={disabled} | ||
| onClick={onClick} | ||
| className={clsx(BASE_CLASS, VARIANT_CLASSES[variant])} |
There was a problem hiding this comment.
Severity: 🟠 Major
Button should be composable and accessible: extend native button props (incl. aria-*/data-*/className), forward ...rest to the <button>, and add a visible focus-visible style instead of removing outlines.
export function Button({ variant = "primary", className, ...rest }: ButtonProps) {
return (
<button {...rest} className={clsx(BASE_CLASS, VARIANT_CLASSES[variant], className)} />
);
}| <Button | ||
| variant={isFavorite ? "secondary" : "primary"} | ||
| onClick={() => toggleFavorite(productId)} | ||
| > | ||
| {isFavorite ? "Unfavorite" : "Favorite"} |
There was a problem hiding this comment.
Severity: 🟠 Major
Expose the favorite state to assistive tech by setting aria-pressed on this toggle button (requires Button to forward native props).
<Button
aria-pressed={isFavorite}
variant={isFavorite ? "secondary" : "primary"}
onClick={() => toggleFavorite(productId)}
>| <p className="text-lg"> | ||
| {nutriments?.[key] ?? 0} {unit} | ||
| </p> |
There was a problem hiding this comment.
Severity: 🟠 Major
Don’t render missing nutriments as 0 (unknown ≠ zero); display an explicit placeholder like “—/N\u002fA”, and consider omitting undefined keys when mapping API data to align with strict optional-property semantics.
const value = nutriments[key];
<p className="text-lg">{value == null ? "—" : `${value} ${unit}`}</p>| useEffect(() => { | ||
| const getFood = async () => { | ||
| try { | ||
| const result = await fetchFood(); | ||
| setData(result); |
There was a problem hiding this comment.
Severity: 🟠 Major
Add an abort/cleanup path for the async effect to prevent setState on unmounted components; pass the AbortSignal down to fetchFood (axios supports { signal }).
useEffect(() => {
const controller = new AbortController();
...
return () => controller.abort();
}, []);| onBack: () => void; | ||
| }; | ||
|
|
||
| export function NutritionSection({ onBack }: Props) { |
There was a problem hiding this comment.
Severity: 🟠 Major
Add a component/integration test for favorites wiring (favorite/unfavorite + All Products/Favorites switching) by mocking useFood() to return deterministic products, using userEvent.setup(), and resetting/clearing the zustand persist state between tests.
PR OverviewPR Type: Feature Focus Areas for Architect Review
|
What does this PR do?
Implements favorites state management for food products using Zustand to ensure consistent UI behavior across product listing and favorites view.
useFavoritesStorewith persistedfavoriteProductIds.Buttoncomponent.FoodCardfor product renderingFavoriteToggleButtonfor favorite/unfavorite actionNutritionSectionto reuseFoodCardand reduce duplicated rendering logic.anymocks with typedvi.mocked(...).Manual Testing Steps
Pull Request Standards Checklist
Definition of Done
Testing