Feature/recommend - #66
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
📝 WalkthroughWalkthroughThis 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. ChangesSuggested Meals Feature
Estimated code review effort: 3 (Moderate) | ~25 minutes Profile Data Refactor
Estimated code review effort: 3 (Moderate) | ~20 minutes API Base URL and Auth Interceptor Refactor
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
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
Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 inconclusive)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
|
@coderabbitai review |
✅ Action performedReview finished.
|
There was a problem hiding this comment.
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 liftScope persisted recommendations per user
recommendationsis stored under a single global persist key andSuggestedMeals.jsxonly 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. WireclearRecommendations()into the logout flow or key the cache by user id.Also update the stale JSDoc for
fetchRecommendationsatsrc/store/recommendationStore.js:27-33; it no longer accepts aparam.🤖 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 valueNon-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 winHardcoded external endpoint bypasses the project's env-based config convention.
api.jsselects its base URL from aBASE_URLSmap keyed byVITE_ENV.AI_API_URLis 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 winDuplicate "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
📒 Files selected for processing (12)
src/pages/Home/Home.jsxsrc/pages/Home/Sections/SuggestedMeals.jsxsrc/pages/Home/Sections/SuggestedMealsTeaser.jsxsrc/pages/Menu/Menu.jsxsrc/pages/Profile/Profile.jsxsrc/pages/Profile/Profile.test.jsxsrc/services/api.jssrc/services/recommendation.service.jssrc/services/user.service.jssrc/store/__tests__/profileStore.test.jssrc/store/profileStore.jssrc/store/recommendationStore.js
| <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> |
There was a problem hiding this comment.
🎯 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.
| <ProfileHeader | ||
| joinDate={user?.createdAt} | ||
| onEdit={() => setEditing(true)} | ||
| /> |
There was a problem hiding this comment.
🎯 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.
| <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.
| // If 401 → attempt token refresh | ||
| if (error.response?.status === 401 && !originalRequest._retry) { |
There was a problem hiding this comment.
🩺 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/servicesRepository: 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())
PYRepository: 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/servicesRepository: 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 -nRepository: 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.
| /** | ||
| * 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 () => { |
There was a problem hiding this comment.
🎯 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.
| 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 | ||
| : []; |
There was a problem hiding this comment.
🔒 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 || trueRepository: 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.jsRepository: 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/...).
| 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(); |
There was a problem hiding this comment.
🎯 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.jsRepository: 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 -nRepository: 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.
| 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.
Summary by CodeRabbit
New Features
Bug Fixes
Tests