Skip to content

feat: enhance meal recommendation system and update profile handling - #62

Closed
NorhanElyann wants to merge 3 commits into
mainfrom
feature/recommend
Closed

feat: enhance meal recommendation system and update profile handling#62
NorhanElyann wants to merge 3 commits into
mainfrom
feature/recommend

Conversation

@NorhanElyann

@NorhanElyann NorhanElyann commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Summary by CodeRabbit

  • New Features
    • Added an authenticated meal recommendations grid with category-based filtering.
    • For guests, introduced a “Suggested For You” teaser with a sign-in prompt.
    • Expanded profile flow to support scoped profile loading/updating and profile picture management.
  • Bug Fixes
    • Improved session refresh handling and queued request retries for more reliable authentication.
    • Updated environment selection so production is the default.
  • Tests
    • Added coverage for profile page rendering and profile store fetching behavior.

@netlify

netlify Bot commented Jul 7, 2026

Copy link
Copy Markdown

Deploy Preview for revive-front-end failed.

Name Link
🔨 Latest commit b987bbe
🔍 Latest deploy log https://app.netlify.com/projects/revive-front-end/deploys/6a4cf9f59ed81d000862fa53

@vercel

vercel Bot commented Jul 7, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
revive-front-end Error Error Jul 7, 2026 1:07pm

@coderabbitai

coderabbitai Bot commented Jul 7, 2026

Copy link
Copy Markdown

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 0a109f7d-a84c-4ced-89fd-46b359fdee58

📥 Commits

Reviewing files that changed from the base of the PR and between 76027e3 and b987bbe.

📒 Files selected for processing (12)
  • src/pages/Home/Home.jsx
  • src/pages/Home/Sections/SuggestedMeals.jsx
  • src/pages/Home/Sections/SuggestedMealsTeaser.jsx
  • src/pages/Menu/Menu.jsx
  • src/pages/Profile/Profile.jsx
  • src/pages/Profile/Profile.test.jsx
  • src/services/api.js
  • src/services/recommendation.service.js
  • src/services/user.service.js
  • src/store/__tests__/profileStore.test.js
  • src/store/profileStore.js
  • src/store/recommendationStore.js

📝 Walkthrough

Walkthrough

The PR updates environment-based API selection, rewires suggested meals around an authenticated AI recommendation flow with a guest teaser, migrates profile APIs and store access to id-scoped client endpoints, and changes Axios request and 401 refresh handling.

Changes

Recommendations, profile, and auth refactor

Layer / File(s) Summary
Environment selection
.env
VITE_ENV is changed from local to prod while the environment URLs remain unchanged.
AI recommendation flow
src/services/recommendation.service.js, src/store/recommendationStore.js, src/pages/Home/Sections/SuggestedMeals.jsx, src/pages/Home/Sections/SuggestedMealsTeaser.jsx, src/pages/Home/Home.jsx, src/pages/Menu/Menu.jsx
getSuggestedMeals now derives the authenticated user, fetches profile and menu data, posts them to the AI endpoint, and returns enriched meal recommendations; the recommendation store now gates fetching by client role and the home/menu suggested-meals components render the new recommendation and teaser states.
Profile APIs and store
src/services/user.service.js, src/store/profileStore.js, src/pages/Profile/Profile.jsx, src/pages/Profile/Profile.test.jsx, src/store/__tests__/profileStore.test.js
user.service.js moves profile operations to /api/clients/profile endpoints with id-scoped fetch, update, delete, and picture actions; profileStore uses the authenticated user id for fetching and updating; Profile.jsx fetches on mount and rewires profile and form props; the profile test verifies join-date rendering and the store test verifies id-scoped fetching.
API client auth refresh
src/services/api.js
api.js switches to static environment base URLs, reads auth state synchronously for request headers, and rewrites 401 handling to queue retries during refresh and replay them with the latest access token.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant HomeOrMenu
  participant RecommendationStore
  participant RecommendationService
  participant MenuAPI
  participant AIAPI

  HomeOrMenu->>RecommendationStore: fetchRecommendations()
  RecommendationStore->>RecommendationService: getSuggestedMeals()
  RecommendationService->>MenuAPI: getMenu() and profile lookup
  RecommendationService->>AIAPI: POST user, meals, top_n
  AIAPI-->>RecommendationService: recommendations
  RecommendationService-->>RecommendationStore: enriched meals
Loading
sequenceDiagram
  participant Client
  participant ApiClient
  participant AuthStore
  participant RefreshService

  Client->>ApiClient: request
  ApiClient-->>Client: 401 response
  ApiClient->>AuthStore: check refresh state and tokens
  ApiClient->>RefreshService: restoreSessionService()
  RefreshService-->>ApiClient: new token
  ApiClient->>AuthStore: setAccessToken(..., expiresAt)
  ApiClient-->>Client: retry queued request
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main changes: recommendation enhancements and profile handling updates.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.
✨ 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 feature/recommend

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 11

🧹 Nitpick comments (2)
src/store/recommendationStore.js (1)

27-33: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Stale JSDoc and vestigial role argument.

The docstring still describes the removed param/userId-or-object contract, and getSuggestedMeals(role) passes an argument the service function (no-arg signature per recommendation.service.js) silently ignores. Update the doc and drop the unused argument for clarity.

📝 Suggested fix
       /**
        * Fetch AI recommendations / suggested meals from backend.
-       * Can be passed a userId directly, an object containing userId/id,
-       * or will fallback to the currently authenticated user in authStore.
-       *
-       * `@param` {string|number|Object} [param] - userId or context object
+       * Derives the current user's role from authStore; requires an
+       * eligible authenticated user before fetching.
        */
       fetchRecommendations: async () => {
         ...
-          const response = await getSuggestedMeals(role);
+          const response = await getSuggestedMeals();

Also applies to: 45-45

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/store/recommendationStore.js` around lines 27 - 33, The JSDoc above the
recommendation store method is stale and still describes the removed
param/userId-or-object behavior, and the `getSuggestedMeals` call in
`recommendationStore` is passing a vestigial `role` argument to a no-arg service
function. Update the documentation to match the current API, and remove the
unused argument from the `getSuggestedMeals` call so the store aligns with
`recommendation.service.js` and the method names stay clear.
src/services/recommendation.service.js (1)

6-7: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Hardcoded external AI endpoint URL.

The AI endpoint URL is hardcoded rather than sourced from an environment variable, inconsistent with the env-driven config approach used elsewhere in this PR stack (e.g., api.js's BASE_URLS keyed by VITE_ENV). This makes it hard to point at a staging/mock AI backend without a code change.

♻️ Suggested fix
-const AI_API_URL =
-  "https://youssef-ashraf-healthy-meal-ai-api.hf.space/recommend";
+const AI_API_URL =
+  import.meta.env.VITE_AI_RECOMMENDATION_URL ??
+  "https://youssef-ashraf-healthy-meal-ai-api.hf.space/recommend";
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/services/recommendation.service.js` around lines 6 - 7, The AI endpoint
in recommendation.service.js is hardcoded, so update the AI_API_URL constant to
read from an environment-driven config instead of a fixed URL. Follow the same
pattern used in api.js with BASE_URLS and VITE_ENV so the recommendation service
can target staging or mock backends without code changes; keep the fallback
behavior explicit if the env var is missing.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.env:
- Line 6: The committed .env default is pointing local/dev runs at the
production backend because VITE_ENV is set to prod and is consumed by
src/services/api.js for the Axios baseURL. Change the default environment value
in .env to a local-safe option like local or dev, and ensure prod is only
supplied through deployment-specific environment configuration. Keep the fix
scoped to the VITE_ENV setting so the API client behavior remains driven by the
environment value.

In `@src/pages/Home/Sections/SuggestedMeals.jsx`:
- Around line 24-26: The useEffect in SuggestedMeals returns early when
user?.role is missing, which leaves loading stuck at true and the spinner
visible forever. Update the effect so the no-role path still resolves the
loading state by calling setLoading(false) before returning, and make sure any
other early-exit paths in this effect also clear loading. Keep the fix within
the SuggestedMeals useEffect logic that controls loading.

In `@src/pages/Profile/Profile.jsx`:
- Around line 25-29: The Profile page is passing only user into InfoGrid, but
InfoGrid.jsx reads all display fields from its profile prop and defaults to an
empty object, so the health/profile values render as placeholders. Update the
Profile component to pass the same data into InfoGrid via profile={user} (or
equivalent) while keeping user as needed, matching how HealthForm uses
initial={user} and reads the fields directly from user.
- Line 21: ProfileHeader is still rendering joinDate but Profile.jsx only passes
onEdit, so the join date field will be blank. Update the ProfileHeader usage in
Profile and/or the ProfileHeader component so joinDate is passed and rendered
again, keeping the prop name consistent with the destructuring in ProfileHeader.

In `@src/services/api.js`:
- Around line 65-66: Skip the 401 refresh flow for auth endpoints in the api
interceptor so invalid login/signup responses don’t trigger
restoreSessionService(). Update the 401 handling in api.js to check the original
request URL/path before retrying, and bypass the token refresh logic for
/auth/login and /auth/signup. Use the existing interceptor block around
originalRequest._retry and the 401 branch to keep the original auth error
visible to callers.
- Around line 37-43: The request interceptor in api.js is setting X-User-Role
from useAuthStore/user.role, which is mutable client state and should not be
trusted for authorization or scoping. Remove this header assignment from the API
client and ensure any role-based decision comes from the server-side session or
access token instead, keeping only the authenticated bearer token logic in the
interceptor.

In `@src/services/recommendation.service.js`:
- Around line 19-29: In recommendation.service.js, the Promise.allSettled flow
in the profile/meals fetch needs two fixes: fail fast when
useAuthStore.getState().user?.id is missing instead of calling api.get with an
undefined id, and preserve the original rejection details when a request fails.
Update the fetch logic around the api.get call and the Promise.allSettled checks
so the profile request is only made with a valid user id, and when profileRes or
mealsRes is rejected, surface profileRes.reason or mealsRes.reason in the thrown
error from this function rather than replacing it with a generic message.
- Around line 34-40: Add a timeout to the AI request in recommendation service
and access the response defensively. In `recommendation.service.js`, update the
`axios.post` call used for `AI_API_URL` so a slow external Space cannot hang the
flow, then validate `aiResponse.data` before reading `recommendations` in the
same `recommendations` assignment path. If the payload is null or malformed,
fall back to an empty list rather than assuming `data.recommendations` exists.

In `@src/services/user.service.js`:
- Around line 23-30: The uploadProfilePicture helper is setting a manual
multipart Content-Type header on a FormData request, which can prevent the
browser/Axios from adding the required boundary. Update uploadProfilePicture to
send the FormData without an explicit Content-Type header so the multipart
request is constructed correctly.

In `@src/store/profileStore.js`:
- Around line 12-16: Bind the profile cache to the current auth user in
fetchProfile. The early return in profileStore should not reuse get().user
unless its id matches useAuthStore.getState().user?.id, otherwise a persisted
profile from a previous session can leak across logins. Update the fetchProfile
flow in profileStore to compare the cached profile against the active auth user
before short-circuiting, or clear the profile store from authStore.logout so
stale data cannot be reused.

In `@src/store/recommendationStore.js`:
- Around line 35-45: The fetch gate in fetchRecommendations currently only
checks that a user role exists, so non-client users can still reach the
client-only profile endpoint through getSuggestedMeals(). Update the role check
in recommendationStore’s fetchRecommendations flow to allow only client accounts
to proceed, and for staff/admin (or any non-client role) return early with
recommendations cleared and loading stopped before calling getSuggestedMeals().
Use the existing fetchRecommendations and getSuggestedMeals symbols to place the
guard in the right spot.

---

Nitpick comments:
In `@src/services/recommendation.service.js`:
- Around line 6-7: The AI endpoint in recommendation.service.js is hardcoded, so
update the AI_API_URL constant to read from an environment-driven config instead
of a fixed URL. Follow the same pattern used in api.js with BASE_URLS and
VITE_ENV so the recommendation service can target staging or mock backends
without code changes; keep the fallback behavior explicit if the env var is
missing.

In `@src/store/recommendationStore.js`:
- Around line 27-33: The JSDoc above the recommendation store method is stale
and still describes the removed param/userId-or-object behavior, and the
`getSuggestedMeals` call in `recommendationStore` is passing a vestigial `role`
argument to a no-arg service function. Update the documentation to match the
current API, and remove the unused argument from the `getSuggestedMeals` call so
the store aligns with `recommendation.service.js` and the method names stay
clear.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 099ababf-7955-4a06-a261-fa71bc27c66d

📥 Commits

Reviewing files that changed from the base of the PR and between 898c4cf and 76027e3.

📒 Files selected for processing (8)
  • .env
  • src/pages/Home/Sections/SuggestedMeals.jsx
  • src/pages/Profile/Profile.jsx
  • src/services/api.js
  • src/services/recommendation.service.js
  • src/services/user.service.js
  • src/store/profileStore.js
  • src/store/recommendationStore.js

Comment thread .env

# Set environment to local, dev, or prod
VITE_ENV=local
VITE_ENV=prod

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify which env files define VITE_ENV and API URLs.
fd -H '^\.env' . -x sh -c 'echo "### $1"; sed -n "1,80p" "$1"' sh {}
rg -n 'VITE_ENV|VITE_API_URL_' .

Repository: Revive-Graduation-Project/Revive-Front-End

Length of output: 32560


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '## package.json\n'
sed -n '1,220p' package.json

printf '\n## .gitignore\n'
sed -n '1,220p' .gitignore

printf '\n## README.md (env references)\n'
rg -n 'VITE_ENV|\.env|VITE_API_URL|local|prod|dev' README.md docs . 2>/dev/null | head -n 200

printf '\n## src/services/api.js\n'
sed -n '1,140p' src/services/api.js

Repository: Revive-Graduation-Project/Revive-Front-End

Length of output: 50400


Keep the committed .env default local-safe.
.env:6 sets VITE_ENV=prod, and src/services/api.js uses that to pick Axios baseURL, so local/dev runs will point at the production backend. Set the committed default to local/dev and move prod to deployment-specific env config.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.env at line 6, The committed .env default is pointing local/dev runs at the
production backend because VITE_ENV is set to prod and is consumed by
src/services/api.js for the Axios baseURL. Change the default environment value
in .env to a local-safe option like local or dev, and ensure prod is only
supplied through deployment-specific environment configuration. Keep the fix
scoped to the VITE_ENV setting so the API client behavior remains driven by the
environment value.

Comment thread src/pages/Home/Sections/SuggestedMeals.jsx Outdated
Comment thread src/pages/Profile/Profile.jsx Outdated
Comment thread src/pages/Profile/Profile.jsx
Comment thread src/services/api.js Outdated
Comment on lines +19 to +29
const [profileRes, mealsRes] = await Promise.allSettled([
api.get(`/api/clients/profile/${useAuthStore.getState().user?.id}`),
getMenu(),
]);

if (profileRes.status !== "fulfilled") {
throw new Error("Failed to fetch user profile");
}
if (mealsRes.status !== "fulfilled") {
throw new Error("Failed to fetch meals");
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

No guard for missing user id; original fetch errors are discarded.

If useAuthStore.getState().user?.id is undefined, the request is fired against /api/clients/profile/undefined instead of failing fast. Also, the thrown errors on lines 25/28 discard profileRes.reason/mealsRes.reason, hiding the actual cause (network error vs 404 vs auth failure) from callers/logs.

🛡️ Suggested fix
+  const userId = useAuthStore.getState().user?.id;
+  if (!userId) {
+    throw new Error("User is not authenticated");
+  }
+
   const [profileRes, mealsRes] = await Promise.allSettled([
-    api.get(`/api/clients/profile/${useAuthStore.getState().user?.id}`),
+    api.get(`/api/clients/profile/${userId}`),
     getMenu(),
   ]);

   if (profileRes.status !== "fulfilled") {
-    throw new Error("Failed to fetch user profile");
+    throw new Error(profileRes.reason?.message || "Failed to fetch user profile");
   }
   if (mealsRes.status !== "fulfilled") {
-    throw new Error("Failed to fetch meals");
+    throw new Error(mealsRes.reason?.message || "Failed to fetch meals");
   }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const [profileRes, mealsRes] = await Promise.allSettled([
api.get(`/api/clients/profile/${useAuthStore.getState().user?.id}`),
getMenu(),
]);
if (profileRes.status !== "fulfilled") {
throw new Error("Failed to fetch user profile");
}
if (mealsRes.status !== "fulfilled") {
throw new Error("Failed to fetch meals");
}
const userId = useAuthStore.getState().user?.id;
if (!userId) {
throw new Error("User is not authenticated");
}
const [profileRes, mealsRes] = await Promise.allSettled([
api.get(`/api/clients/profile/${userId}`),
getMenu(),
]);
if (profileRes.status !== "fulfilled") {
throw new Error(profileRes.reason?.message || "Failed to fetch user profile");
}
if (mealsRes.status !== "fulfilled") {
throw new Error(mealsRes.reason?.message || "Failed to fetch meals");
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/services/recommendation.service.js` around lines 19 - 29, In
recommendation.service.js, the Promise.allSettled flow in the profile/meals
fetch needs two fixes: fail fast when useAuthStore.getState().user?.id is
missing instead of calling api.get with an undefined id, and preserve the
original rejection details when a request fails. Update the fetch logic around
the api.get call and the Promise.allSettled checks so the profile request is
only made with a valid user id, and when profileRes or mealsRes is rejected,
surface profileRes.reason or mealsRes.reason in the thrown error from this
function rather than replacing it with a generic message.

Comment thread src/services/recommendation.service.js Outdated
Comment thread src/services/user.service.js
Comment thread src/store/profileStore.js
Comment thread src/store/recommendationStore.js
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant