Skip to content

Feature/recommend - #66

Merged
ibrahim607 merged 6 commits into
devfrom
feature/recommend
Jul 12, 2026
Merged

Feature/recommend#66
ibrahim607 merged 6 commits into
devfrom
feature/recommend

Conversation

@NorhanElyann

@NorhanElyann NorhanElyann commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Summary by CodeRabbit

  • New Features

    • Added a teaser version of “Suggested Meals” for signed-out visitors, with sign-in and account creation prompts.
    • Profile pages now refresh user details on load and support updated health/profile information flows.
  • Bug Fixes

    • Suggested meals now adapt to the selected category and display in a responsive grid.
    • Profile data is now loaded for the currently signed-in account, reducing stale or mismatched profile info.
    • Authentication token refresh handling is more reliable for queued requests.
  • Tests

    • Added coverage for profile date display and user-specific profile fetching.

@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 Ready Ready Preview, Comment Jul 7, 2026 11:40pm

@coderabbitai

coderabbitai Bot commented Jul 7, 2026

Copy link
Copy Markdown

Review Change Stack

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: fb9919d7-d5e0-415a-81da-102dd878395b

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This PR gates suggested-meals rendering on authentication (new teaser for unauthenticated users on Home/Menu), rewrites the recommendation service/store to use a client-side AI enrichment pipeline, refactors profile fetching/updating to use ID-based client-profile endpoints, and rewrites the axios base URL selection and 401 token-refresh/queueing logic.

Changes

Suggested Meals Feature

Layer / File(s) Summary
Recommendation service and store rewrite
src/services/recommendation.service.js, src/store/recommendationStore.js
getSuggestedMeals now fetches profile and menu in parallel, posts to an external AI endpoint, and enriches results; fetchRecommendations gates on user role and normalizes the response array.
SuggestedMeals component using store data
src/pages/Home/Sections/SuggestedMeals.jsx
Accepts a selectedCategory prop, filters store recommendations, and renders a grid instead of a scrollable card row.
SuggestedMealsTeaser component
src/pages/Home/Sections/SuggestedMealsTeaser.jsx
New component shows a blurred placeholder grid with a lock overlay and sign-in/sign-up links.
Home page auth gating
src/pages/Home/Home.jsx
Renders SuggestedMeals or SuggestedMealsTeaser based on authentication.
Menu page auth gating
src/pages/Menu/Menu.jsx
Removes recommendation-store effect logic, derives isAuthenticated, and renders SuggestedMeals/SuggestedMealsTeaser accordingly while keeping meal list state handling.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Profile Data Refactor

Layer / File(s) Summary
Client-profile API endpoints
src/services/user.service.js
Replaces /users/me endpoints with /api/clients/profile/{id} endpoints, adding getProfileById, updateProfile(id, data), deleteProfile, uploadProfilePicture, deleteProfilePicture; removes updateHealthProfile and getOrderHistory.
profileStore fetch/update by active user id
src/store/profileStore.js
fetchProfile derives active user id, reuses/clears cache accordingly, and fetches by id; updateUser and updateHealth are updated to use id-based calls.
Profile page wiring and tests
src/pages/Profile/Profile.jsx, src/pages/Profile/Profile.test.jsx, src/store/__tests__/profileStore.test.js
Profile page fetches on mount and passes user directly to child components; new tests cover rendering and per-user cache behavior.

Estimated code review effort: 3 (Moderate) | ~20 minutes

API Base URL and Auth Interceptor Refactor

Layer / File(s) Summary
Base URL map and request interceptor
src/services/api.js
BASE_URLS map keyed by VITE_ENV determines BASE_URL; request interceptor reads the token synchronously from useAuthStore.getState().
401 refresh and request queueing
src/services/api.js
Response interceptor queues requests during refresh, retries with updated Authorization header, and computes a fixed 24-hour expiry.

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

Sequence Diagram(s)

sequenceDiagram
  participant SuggestedMeals
  participant useRecommendationStore
  participant getSuggestedMeals
  participant AIEndpoint

  SuggestedMeals->>useRecommendationStore: fetchRecommendations()
  useRecommendationStore->>useRecommendationStore: check user role === CLIENT
  useRecommendationStore->>getSuggestedMeals: getSuggestedMeals(role)
  getSuggestedMeals->>AIEndpoint: POST user + meals payload
  AIEndpoint-->>getSuggestedMeals: recommendations
  getSuggestedMeals-->>useRecommendationStore: enriched meal data
  useRecommendationStore-->>SuggestedMeals: recommendations, isLoading, error
Loading
sequenceDiagram
  participant OriginalRequest
  participant ResponseInterceptor
  participant useAuthStore
  participant QueuedRequests

  OriginalRequest->>ResponseInterceptor: 401 error
  ResponseInterceptor->>ResponseInterceptor: check isRefreshing
  alt refresh in progress
    ResponseInterceptor->>QueuedRequests: queue request
  else start refresh
    ResponseInterceptor->>useAuthStore: refresh token, set expiry +24h
    useAuthStore-->>ResponseInterceptor: new access token
    ResponseInterceptor->>QueuedRequests: resolve with getAccessToken()
  end
  ResponseInterceptor->>OriginalRequest: retry with Authorization header
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Title check ❓ Inconclusive The title is related to recommendations, but it's too generic to convey the actual scope of the changeset. Use a clearer title like "Refactor meal recommendations and add suggested meals teaser".
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
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 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.

@NorhanElyann

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 7, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@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: 6

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/store/recommendationStore.js (1)

27-48: 🔒 Security & Privacy | 🟠 Major | 🏗️ Heavy lift

Scope persisted recommendations per user

recommendations is stored under a single global persist key and SuggestedMeals.jsx only refetches when the array is empty, so a second CLIENT on a shared device can see the previous user’s recommendations until logout or an explicit clear. Wire clearRecommendations() into the logout flow or key the cache by user id.

Also update the stale JSDoc for fetchRecommendations at src/store/recommendationStore.js:27-33; it no longer accepts a param.

🤖 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 - 48, The recommendation
cache is currently shared across users because `recommendationStore` persists a
single `recommendations` array, and `SuggestedMeals.jsx` only refetches when
that array is empty. Update the logout flow to call `clearRecommendations()` or
change the store to scope cached data by user id so a new CLIENT on the same
device cannot see the previous user’s meals. Also fix the stale JSDoc for
`fetchRecommendations` in `recommendationStore` so it no longer documents a
`param` argument that the function does not accept.
🧹 Nitpick comments (3)
src/store/profileStore.js (1)

58-58: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Non-English inline comment.

Line 58 is written in Arabic. Prefer English comments for maintainability across the team.

🤖 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/profileStore.js` at line 58, The inline comment in profileStore
should be rewritten in English for team readability. Update the comment near the
updateHealth/updateUser logic to keep the same meaning but use clear English
wording, preserving the reference to updateHealth and updateUser so the intent
remains obvious when locating the code.
src/services/recommendation.service.js (1)

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

Hardcoded external endpoint bypasses the project's env-based config convention.

api.js selects its base URL from a BASE_URLS map keyed by VITE_ENV. AI_API_URL is hardcoded here instead, which makes it impossible to point at a staging/mock AI endpoint per environment and hardcodes an external vendor's endpoint directly into the bundle.

♻️ Suggested change
-const AI_API_URL =
-  "https://youssef-ashraf-healthy-meal-ai-api.hf.space/recommend";
+const AI_API_URL = import.meta.env.VITE_AI_API_URL;
🤖 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
recommendation service is bypassing the app’s environment-based endpoint
configuration by hardcoding AI_API_URL. Update the recommendation request logic
to follow the same pattern as api.js: resolve the AI base URL from an
environment-driven config or BASE_URLS-style map keyed by VITE_ENV, and keep the
external endpoint out of the bundle. Make the change in the recommendation
service’s URL constant/usage so it can switch cleanly between local, staging,
mock, and production AI backends.
src/pages/Home/Sections/SuggestedMealsTeaser.jsx (1)

43-107: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Duplicate "Suggested For You" header/section markup with SuggestedMeals.jsx.

The section wrapper, container, and header block (title + emoji) are identical to SuggestedMeals.jsx's markup. Extracting a shared header/section wrapper would avoid the two components drifting out of sync on future design tweaks.

🤖 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/pages/Home/Sections/SuggestedMealsTeaser.jsx` around lines 43 - 107, The
section wrapper and “Suggested For You” header in SuggestedMealsTeaser duplicate
the same markup used in SuggestedMeals, so extract that shared wrapper/header
into a reusable component or helper and use it from both places. Keep the unique
teaser overlay/card blur content in SuggestedMealsTeaser, but move the common
container, title, and emoji block behind a shared symbol so future design
changes stay consistent.
🤖 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 `@src/pages/Home/Sections/SuggestedMealsTeaser.jsx`:
- Around line 56-60: The placeholder meal cards in SuggestedMealsTeaser remain
reachable by keyboard and assistive tech even though they are only decorative.
Update the PLACEHOLDER_MEALS rendering in SuggestedMealsTeaser so the
RegularFoodCard content is removed from the accessibility/focus order, e.g. by
passing the right props or wrapping it to hide interactive descendants from
tabbing and screen readers, while keeping the blurred preview visual only.

In `@src/pages/Profile/Profile.jsx`:
- Around line 21-24: The ProfileHeader is receiving a raw ISO timestamp via
joinDate from Profile, so users see the full date string instead of a friendly
value. Format user?.createdAt in Profile before passing it into ProfileHeader,
using the existing date display logic or a date formatter, and keep the joinDate
prop as the formatted user-facing string.

In `@src/services/api.js`:
- Around line 62-63: The 401 retry logic in api.js should skip the login
endpoint so failed `/auth/login` requests do not trigger
`restoreSessionService()` and a pointless retry. Update the
`error.response?.status === 401 && !originalRequest._retry` branch to also
exclude `/auth/login`, using the existing request URL check alongside the
current `/auth/refresh` short-circuit, so only real session-expiration cases
reach the refresh flow.

In `@src/services/recommendation.service.js`:
- Around line 9-18: The getSuggestedMeals contract is inconsistent: it documents
and is called with a role argument, but the exported function currently ignores
it. Update getSuggestedMeals to either accept and forward role into the AI
payload through the recommendation flow, or remove role from the JSDoc and the
recommendationStore call so the public API matches the implementation. Use the
getSuggestedMeals export and the recommendationStore invocation as the places to
align.
- Around line 19-47: The recommendation flow in recommendation.service.js is
sending the full profile and meal catalog directly from the browser to the
external AI endpoint, which should be routed through your backend instead.
Update the fetch/recommendation path around the Promise.allSettled profile/meals
loading and the axios.post call so the client calls an internal backend
endpoint, and have that backend proxy the request to AI_API_URL. If you keep any
client-side payload, trim it to only the minimum fields needed by the AI and
avoid forwarding the raw profile object from api.get(/api/clients/profile/...).

In `@src/store/__tests__/profileStore.test.js`:
- Around line 14-27: The test setup in useProfileStore is wiping out the store’s
actions by calling setState(..., true), which removes fetchProfile and breaks
the later getState().fetchProfile() call. Update the reset calls in the
profileStore test to set only the data fields on useProfileStore and
useAuthStore without the replace flag, so the store methods remain intact while
state is reset.

---

Outside diff comments:
In `@src/store/recommendationStore.js`:
- Around line 27-48: The recommendation cache is currently shared across users
because `recommendationStore` persists a single `recommendations` array, and
`SuggestedMeals.jsx` only refetches when that array is empty. Update the logout
flow to call `clearRecommendations()` or change the store to scope cached data
by user id so a new CLIENT on the same device cannot see the previous user’s
meals. Also fix the stale JSDoc for `fetchRecommendations` in
`recommendationStore` so it no longer documents a `param` argument that the
function does not accept.

---

Nitpick comments:
In `@src/pages/Home/Sections/SuggestedMealsTeaser.jsx`:
- Around line 43-107: The section wrapper and “Suggested For You” header in
SuggestedMealsTeaser duplicate the same markup used in SuggestedMeals, so
extract that shared wrapper/header into a reusable component or helper and use
it from both places. Keep the unique teaser overlay/card blur content in
SuggestedMealsTeaser, but move the common container, title, and emoji block
behind a shared symbol so future design changes stay consistent.

In `@src/services/recommendation.service.js`:
- Around line 6-7: The recommendation service is bypassing the app’s
environment-based endpoint configuration by hardcoding AI_API_URL. Update the
recommendation request logic to follow the same pattern as api.js: resolve the
AI base URL from an environment-driven config or BASE_URLS-style map keyed by
VITE_ENV, and keep the external endpoint out of the bundle. Make the change in
the recommendation service’s URL constant/usage so it can switch cleanly between
local, staging, mock, and production AI backends.

In `@src/store/profileStore.js`:
- Line 58: The inline comment in profileStore should be rewritten in English for
team readability. Update the comment near the updateHealth/updateUser logic to
keep the same meaning but use clear English wording, preserving the reference to
updateHealth and updateUser so the intent remains obvious when locating the
code.
🪄 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: e553984f-5432-4321-9acb-fee3182971ee

📥 Commits

Reviewing files that changed from the base of the PR and between 5d1d5c2 and 82f4123.

📒 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

Comment on lines +56 to +60
<div className="grid grid-cols-2 md:grid-cols-3 xl:grid-cols-4 gap-2 md:gap-8 blur-[2px] pointer-events-none select-none opacity-60">
{PLACEHOLDER_MEALS.map((meal) => (
<RegularFoodCard key={meal.id} meal={meal} />
))}
</div>

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

Decorative blurred cards remain keyboard/screen-reader focusable.

pointer-events-none prevents mouse clicks but not keyboard tab focus or screen-reader traversal. Keyboard users can still tab into the placeholder cards' heart/add-to-cart buttons, which do nothing meaningful and aren't visually indicated as focused behind the blur/overlay.

♿ Suggested fix
-          <div className="grid grid-cols-2 md:grid-cols-3 xl:grid-cols-4 gap-2 md:gap-8 blur-[2px] pointer-events-none select-none opacity-60">
+          <div
+            aria-hidden="true"
+            className="grid grid-cols-2 md:grid-cols-3 xl:grid-cols-4 gap-2 md:gap-8 blur-[2px] pointer-events-none select-none opacity-60"
+          >
             {PLACEHOLDER_MEALS.map((meal) => (
               <RegularFoodCard key={meal.id} meal={meal} />
             ))}
           </div>
🤖 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/pages/Home/Sections/SuggestedMealsTeaser.jsx` around lines 56 - 60, The
placeholder meal cards in SuggestedMealsTeaser remain reachable by keyboard and
assistive tech even though they are only decorative. Update the
PLACEHOLDER_MEALS rendering in SuggestedMealsTeaser so the RegularFoodCard
content is removed from the accessibility/focus order, e.g. by passing the right
props or wrapping it to hide interactive descendants from tabbing and screen
readers, while keeping the blurred preview visual only.

Comment on lines +21 to +24
<ProfileHeader
joinDate={user?.createdAt}
onEdit={() => setEditing(true)}
/>

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

Unformatted date rendered to users.

user?.createdAt is a raw ISO timestamp (e.g. 2024-01-15T00:00:00.000Z), and ProfileHeader renders joinDate verbatim (Join date : {joinDate}), so users see the full timestamp string. Format it before passing.

Proposed fix
-      <ProfileHeader
-        joinDate={user?.createdAt}
-        onEdit={() => setEditing(true)}
-      />
+      <ProfileHeader
+        joinDate={
+          user?.createdAt
+            ? new Date(user.createdAt).toLocaleDateString()
+            : "-"
+        }
+        onEdit={() => setEditing(true)}
+      />
📝 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
<ProfileHeader
joinDate={user?.createdAt}
onEdit={() => setEditing(true)}
/>
<ProfileHeader
joinDate={
user?.createdAt
? new Date(user.createdAt).toLocaleDateString()
: "-"
}
onEdit={() => setEditing(true)}
/>
🤖 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/pages/Profile/Profile.jsx` around lines 21 - 24, The ProfileHeader is
receiving a raw ISO timestamp via joinDate from Profile, so users see the full
date string instead of a friendly value. Format user?.createdAt in Profile
before passing it into ProfileHeader, using the existing date display logic or a
date formatter, and keep the joinDate prop as the formatted user-facing string.

Comment thread src/services/api.js Outdated
Comment on lines +62 to +63
// If 401 → attempt token refresh
if (error.response?.status === 401 && !originalRequest._retry) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
fd -a 'api.js' -p 'services' | xargs -I{} sh -c 'echo "== {} =="; sed -n "40,120p" "{}"'
fd -a 'auth.service.js' | xargs -I{} sh -c 'echo "== {} =="; rg -n "restoreSessionService|refresh|login" "{}"'

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

Length of output: 826


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Locate the relevant files and inspect the surrounding code with line numbers.
for f in /home/jailuser/git/src/services/api.js /home/jailuser/git/src/services/auth.service.js; do
  echo "== $f =="
  sed -n '1,220p' "$f" | cat -n
  echo
done

# Search for any URL-based exclusions or retry guards around auth endpoints.
rg -n "auth/login|auth/refresh|_retry|restoreSessionService|loginService|interceptor|response\\.interceptors" /home/jailuser/git/src/services

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

Length of output: 7037


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Trace how auth requests are issued and whether the refresh call can be intercepted by the same client.
python3 - <<'PY'
from pathlib import Path
p = Path('/home/jailuser/git/src/services/api.js')
print(p.exists())
PY

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

Length of output: 185


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Show the exact auth-related request paths used by the client.
rg -n 'api\.(post|get|put|patch|delete)\("/auth/[^"]+"' /home/jailuser/git/src/services

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

Length of output: 775


🏁 Script executed:

#!/bin/bash
set -euo pipefail

cd /home/jailuser/git

echo "== matched files =="
git ls-files 'src/services/*'

echo
echo "== src/services/api.js =="
sed -n '1,220p' src/services/api.js | cat -n

echo
echo "== src/services/auth.service.js =="
sed -n '1,220p' src/services/auth.service.js | cat -n

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

Length of output: 6123


Exclude /auth/login from the 401 refresh branch (src/services/api.js:62-63). A failed login currently calls restoreSessionService() and retries the request, which turns invalid-credentials failures into an unnecessary refresh flow. /auth/refresh is already short-circuited above.

🤖 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/api.js` around lines 62 - 63, The 401 retry logic in api.js
should skip the login endpoint so failed `/auth/login` requests do not trigger
`restoreSessionService()` and a pointless retry. Update the
`error.response?.status === 401 && !originalRequest._retry` branch to also
exclude `/auth/login`, using the existing request URL check alongside the
current `/auth/refresh` short-circuit, so only real session-expiration cases
reach the refresh flow.

Comment thread src/services/recommendation.service.js Outdated
Comment on lines +9 to +18
/**
* Fetch AI-suggested meals for the authenticated user from the backend recommendation engine.
* Fetch AI meal recommendations for the authenticated user.
* 1. Fetches client profile + all meals in parallel
* 2. Sends both to the AI recommendation engine
* 3. Enriches the recommendations with imageUrl & nutrients from the original meals
*
* @param {string|number} userId - The authenticated user's ID
* @returns {Promise<import('axios').AxiosResponse>}
* @param {string} role - The authenticated user's role (e.g. "CLIENT")
* @returns {{ data: Array }} - Enriched recommended meals
*/
export const getSuggestedMeals = (userId) => {
return api.get(`/api/menu/recommendations/${userId}`);
export const getSuggestedMeals = async () => {

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 | 🟠 Major | ⚡ Quick win

role parameter is documented but silently dropped.

The JSDoc documents @param {string} role, and recommendationStore.js calls getSuggestedMeals(role) (see src/store/recommendationStore.js:45), but the exported function signature is async () => {} and never uses role. Either the AI payload is missing an intended role field, or the parameter/JSDoc is stale — please confirm which was intended and remove the unused contract on the losing side.

🔧 Proposed fix if role should be forwarded
-export const getSuggestedMeals = async () => {
+export const getSuggestedMeals = async (role) => {
   const [profileRes, mealsRes] = await Promise.allSettled([
     api.get(`/api/clients/profile/${useAuthStore.getState().user?.id}`),
     getMenu(),
   ]);
   ...
   const aiResponse = await axios.post(
     AI_API_URL,
     {
       user,
       meals,
+      role,
       top_n: 5,
     },
     { timeout: 10000 },
   );
🤖 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 9 - 18, The
getSuggestedMeals contract is inconsistent: it documents and is called with a
role argument, but the exported function currently ignores it. Update
getSuggestedMeals to either accept and forward role into the AI payload through
the recommendation flow, or remove role from the JSDoc and the
recommendationStore call so the public API matches the implementation. Use the
getSuggestedMeals export and the recommendationStore invocation as the places to
align.

Comment on lines +19 to +47
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 user = profileRes.value.data;
const meals = mealsRes.value.data;

const aiResponse = await axios.post(
AI_API_URL,
{
user,
meals,
top_n: 5,
},
{ timeout: 10000 },
);

const aiPayload = aiResponse?.data;
const recommendations = Array.isArray(aiPayload?.recommendations)
? aiPayload.recommendations
: [];

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf 'Files of interest:\n'
git ls-files | rg '^(src/services/recommendation\.service\.js|src/.*(api|store|menu|profile).*)$|^(src/.*(recommendation|auth).*)$' || true

printf '\nSearch for AI_API_URL and recommendation service references:\n'
rg -n "AI_API_URL|recommendation.service|getMenu\(|clients/profile|recommend" src || true

printf '\nShow recommendation service with line numbers:\n'
sed -n '1,220p' src/services/recommendation.service.js

printf '\nSearch for profile schema / fields:\n'
rg -n "email|phone|address|diet|health|allerg|gender|age|weight|height|dob|dateOfBirth|birth" src || true

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

Length of output: 50398


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf 'recommendation.service.js:\n'
sed -n '1,120p' src/services/recommendation.service.js

printf '\nuser.service.js:\n'
sed -n '1,120p' src/services/user.service.js

printf '\nmenu.service.js:\n'
sed -n '1,120p' src/services/menu.service.js

printf '\nprofileStore.js:\n'
sed -n '1,140p' src/store/profileStore.js

printf '\nauthStore.js relevant section:\n'
sed -n '180,230p' src/store/authStore.js

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

Length of output: 7489


Route recommendation requests through your backend
The browser posts the full client profile from api.get(\/api/clients/profile/${...}`)plus the meal catalog directly tohttps://youssef-ashraf-healthy-meal-ai-api.hf.space/recommend`. If that profile includes health, contact, or other sensitive fields, they leave your origin and are exposed to a third-party service from the client. Send only the fields the model needs, or proxy this call server-side.

🤖 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 - 47, The
recommendation flow in recommendation.service.js is sending the full profile and
meal catalog directly from the browser to the external AI endpoint, which should
be routed through your backend instead. Update the fetch/recommendation path
around the Promise.allSettled profile/meals loading and the axios.post call so
the client calls an internal backend endpoint, and have that backend proxy the
request to AI_API_URL. If you keep any client-side payload, trim it to only the
minimum fields needed by the AI and avoid forwarding the raw profile object from
api.get(/api/clients/profile/...).

Comment on lines +14 to +27
useProfileStore.setState({ user: null, loading: false, error: null }, true);
useAuthStore.setState(
{ user: { id: 1 }, token: null, expiresAt: null, isAuthenticated: true },
true,
);
vi.clearAllMocks();
});

it("does not reuse a cached profile from a different auth user", async () => {
useProfileStore.setState({ user: { id: 99, firstName: "Old" } }, true);

getProfileById.mockResolvedValue({ data: { id: 1, firstName: "New" } });

const result = await useProfileStore.getState().fetchProfile();

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 | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Confirm actions are defined inside store state (not separately) and that a default export exists
ast-grep outline src/store/profileStore.js --items all
rg -nP 'export default|export const useProfileStore' src/store/profileStore.js

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

Length of output: 483


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '--- profileStore.js (selected ranges) ---'
wc -l src/store/profileStore.js
sed -n '1,140p' src/store/profileStore.js | cat -n

echo '--- profileStore.test.js (selected ranges) ---'
wc -l src/store/__tests__/profileStore.test.js
sed -n '1,140p' src/store/__tests__/profileStore.test.js | cat -n

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

Length of output: 4333


Drop the replace flag from these setState calls. setState(..., true) replaces the whole Zustand state, so these resets remove fetchProfile from the store and useProfileStore.getState().fetchProfile() will fail in the test. Reset only the data fields.

Proposed fix
-    useProfileStore.setState({ user: null, loading: false, error: null }, true);
+    useProfileStore.setState({ user: null, loading: false, error: null });
@@
-    useProfileStore.setState({ user: { id: 99, firstName: "Old" } }, true);
+    useProfileStore.setState({ user: { id: 99, firstName: "Old" } });
📝 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
useProfileStore.setState({ user: null, loading: false, error: null }, true);
useAuthStore.setState(
{ user: { id: 1 }, token: null, expiresAt: null, isAuthenticated: true },
true,
);
vi.clearAllMocks();
});
it("does not reuse a cached profile from a different auth user", async () => {
useProfileStore.setState({ user: { id: 99, firstName: "Old" } }, true);
getProfileById.mockResolvedValue({ data: { id: 1, firstName: "New" } });
const result = await useProfileStore.getState().fetchProfile();
useProfileStore.setState({ user: null, loading: false, error: null });
useAuthStore.setState(
{ user: { id: 1 }, token: null, expiresAt: null, isAuthenticated: true },
true,
);
vi.clearAllMocks();
});
it("does not reuse a cached profile from a different auth user", async () => {
useProfileStore.setState({ user: { id: 99, firstName: "Old" } });
getProfileById.mockResolvedValue({ data: { id: 1, firstName: "New" } });
const result = await useProfileStore.getState().fetchProfile();
🤖 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/__tests__/profileStore.test.js` around lines 14 - 27, The test
setup in useProfileStore is wiping out the store’s actions by calling
setState(..., true), which removes fetchProfile and breaks the later
getState().fetchProfile() call. Update the reset calls in the profileStore test
to set only the data fields on useProfileStore and useAuthStore without the
replace flag, so the store methods remain intact while state is reset.

@ibrahim607
ibrahim607 merged commit 7c4508e into dev Jul 12, 2026
3 checks passed
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.

2 participants