-
Notifications
You must be signed in to change notification settings - Fork 1
fix menu issue by removing the presist bad logic and update it to use… #53
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,21 +1,20 @@ | ||
| import { useEffect } from "react"; | ||
| import { useRestaurantStore } from "../store"; | ||
| import { useQueryClient } from "@tanstack/react-query"; | ||
| import { menuKeys } from "./dashboard/useMenuItems"; | ||
| import { getMenuItems } from "../services/dashboardService"; | ||
|
|
||
| /** | ||
| * Hook to initialize meal data on app load. | ||
| * Hook to prefetch meal data on app load via React Query. | ||
| * Call this in App.jsx on mount. | ||
| * | ||
| * Single-restaurant system — only fetches meals, no restaurant selection. | ||
| * Mock now → real API later (no changes needed here). | ||
| */ | ||
| export const useRestaurantInit = () => { | ||
| const { meals, fetchMeals } = useRestaurantStore(); | ||
| const queryClient = useQueryClient(); | ||
|
|
||
| useEffect(() => { | ||
| // Only fetch if store is empty | ||
| if (meals.length === 0) { | ||
| console.log("🍽️ Fetching menu..."); | ||
| fetchMeals(); | ||
| } | ||
| }, []); | ||
| useEffect(() => { | ||
| queryClient.prefetchQuery({ | ||
| queryKey: menuKeys.items({}), | ||
| queryFn: () => getMenuItems({}), | ||
| }); | ||
| }, [queryClient]); | ||
| }; | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,26 +1,24 @@ | ||
| // src/pages/Home/Sections/RegularFood.jsx | ||
| import { useEffect } from "react"; | ||
| import useRestaurantStore from "../../../store/restaurantStore"; | ||
| import { useMenuItems } from "../../../hooks/dashboard/useMenuItems"; | ||
| import RegularFoodCard from "../../../components/UI/RegularFoodCard"; | ||
| import LoadingSpinner from "../../../components/UI/LoadingSpinner"; | ||
|
|
||
| const RegularFood = ({ items }) => { | ||
| const { meals, fetchMeals, loading, error } = useRestaurantStore(); | ||
|
|
||
| useEffect(() => { | ||
| if (!items && meals.length === 0) fetchMeals(); // ✅ بس لو مفيش items جاي من برا | ||
| }, [meals.length, fetchMeals, items]); | ||
| const { data: meals = [], isLoading: loading, error } = useMenuItems({}, { | ||
| enabled: !items, // Don't fetch if items are passed via prop | ||
| }); | ||
|
Comment on lines
+7
to
+9
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
printf '\n== files ==\n'
git ls-files 'src/pages/Home/Sections/RegularFood.jsx' 'src/hooks/dashboard/useMenuItems.js' 'src/pages/**/Menu.jsx'
printf '\n== outlines ==\n'
for f in src/pages/Home/Sections/RegularFood.jsx src/hooks/dashboard/useMenuItems.js; do
echo "--- $f"
ast-grep outline "$f" --view expanded || true
done
printf '\n== search useMenuItems usages ==\n'
rg -n "useMenuItems\\(" src --glob '!**/node_modules/**' || true
printf '\n== relevant file excerpts ==\n'
for f in src/pages/Home/Sections/RegularFood.jsx src/hooks/dashboard/useMenuItems.js; do
echo "--- $f"
nl -ba "$f" | sed -n '1,220p'
doneRepository: Revive-Graduation-Project/Revive-Front-End Length of output: 1839 🏁 Script executed: #!/bin/bash
set -euo pipefail
for f in src/pages/Home/Sections/RegularFood.jsx src/hooks/dashboard/useMenuItems.js src/pages/Menu/Menu.jsx; do
echo "=== $f ==="
sed -n '1,220p' "$f" | cat -n
echo
doneRepository: Revive-Graduation-Project/Revive-Front-End Length of output: 14521 Pass
🤖 Prompt for AI Agents |
||
|
|
||
| if (loading && !items) return <LoadingSpinner />; | ||
| if (error && !items) return <p>{error}</p>; | ||
| if (error && !items) return <p>{error.message || "Error loading food items"}</p>; | ||
|
|
||
| const displayMeals = items ?? meals; | ||
|
|
||
| const displayMeals = items ?? meals; // ✅ لو في items استخدمها، لو لأ استخدم meals | ||
|
|
||
| return ( | ||
| <section id="regular-food" className="py-12 md:py-16 lg:py-20 bg-gray-50"> | ||
| <div className="container mx-auto px-4 md:px-6 lg:px-8"> | ||
| <div className="text-center mb-10 md:mb-12"> | ||
| <h2 className="text-3xl md:text-4xl lg:text-5xl font-bold text-(--color-green) mb-3"> | ||
| <h2 className="text-3xl md:text-4xl lg:text-5xl font-bold text-green mb-3"> | ||
| OUR REGULAR FOOD | ||
| </h2> | ||
| <p className="text-gray-600 text-lg md:text-xl mb-2"> | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,82 +1,75 @@ | ||
| import { | ||
| useMenuStore, | ||
| useAuthStore, | ||
| useRecommendationStore, | ||
| useMenuStore, | ||
| useAuthStore, | ||
| useRecommendationStore, | ||
| } from "../../store"; | ||
| import useRestaurantStore from "../../store/restaurantStore"; | ||
| import { useMenuItems } from "../../hooks/dashboard/useMenuItems"; | ||
| import { useMemo, useEffect } from "react"; | ||
| import MenuFilter from "./Sections/MenuFilter"; | ||
| import OffersSection from "./Sections/OffersSection"; | ||
| import SuggestedMealsSection from "./Sections/SuggestedMealsSection"; | ||
| import RegularFood from "../Home/Sections/RegularFood"; | ||
|
|
||
| export default function Menu() { | ||
| const { user } = useAuthStore(); | ||
| const { | ||
| recommendations, | ||
| fetchRecommendations, | ||
| } = useRecommendationStore(); | ||
| const { | ||
| meals, | ||
| fetchMeals, | ||
| loading: mealsLoading, | ||
| error: mealsError, | ||
| } = useRestaurantStore(); | ||
| const { selectedCategory } = useMenuStore(); | ||
| const { user } = useAuthStore(); | ||
| const { | ||
| recommendations, | ||
| fetchRecommendations, | ||
| } = useRecommendationStore(); | ||
| const { data: meals = [], isLoading: mealsLoading, error: mealsErrorObj } = useMenuItems({}); | ||
| const mealsError = mealsErrorObj ? (mealsErrorObj.message || "Failed to load meals") : null; | ||
| const { selectedCategory } = useMenuStore(); | ||
|
|
||
| const isGuest = !user; | ||
| const isGuest = !user; | ||
|
|
||
| useEffect(() => { | ||
| // Always fetch meals for the regular menu | ||
| if (meals.length === 0) { | ||
| fetchMeals(); | ||
| } | ||
| // If user is logged in, also fetch personalized recommendations | ||
| if (!isGuest) { | ||
| fetchRecommendations(user?.id); | ||
| } | ||
| }, [user, isGuest, meals.length, fetchMeals, fetchRecommendations]); | ||
| useEffect(() => { | ||
| // If user is logged in, fetch personalized recommendations | ||
| if (!isGuest) { | ||
| fetchRecommendations(user?.id); | ||
| } | ||
| }, [user, isGuest, fetchRecommendations]); | ||
|
|
||
| const filteredMeals = useMemo(() => { | ||
| return meals.filter((item) => { | ||
| return selectedCategory === "All" || item.category === selectedCategory; | ||
| }); | ||
| }, [selectedCategory, meals]); | ||
|
|
||
| const filteredRecommendations = useMemo(() => { | ||
| return (recommendations || []).filter((item) => { | ||
| return selectedCategory === "All" || item.category === selectedCategory; | ||
| }); | ||
| }, [selectedCategory, recommendations]); | ||
| const filteredMeals = useMemo(() => { | ||
| return meals.filter((item) => { | ||
| return selectedCategory === "All" || item.category === selectedCategory; | ||
| }); | ||
| }, [selectedCategory, meals]); | ||
|
|
||
| return ( | ||
| <div className="bg-white min-h-screen px-4 md:px-10 lg:px-20 overflow-hidden"> | ||
| <div className="py-12 md:py-16 lg:py-20 space-y-5 md:space-y-2 lg:space-y-2"> | ||
| <MenuFilter /> | ||
| <OffersSection /> | ||
|
|
||
| {/* Suggested Meals Section (Displayed for logged-in users when recommendations exist) */} | ||
| {!isGuest && ( | ||
| <SuggestedMealsSection items={filteredRecommendations} /> | ||
| )} | ||
| const filteredRecommendations = useMemo(() => { | ||
| return (recommendations || []).filter((item) => { | ||
| return selectedCategory === "All" || item.category === selectedCategory; | ||
| }); | ||
| }, [selectedCategory, recommendations]); | ||
|
|
||
| {/* Regular Food Section (Always displayed for everyone) */} | ||
| {mealsLoading && meals.length === 0 ? ( | ||
| <div className="flex justify-center items-center h-64"> | ||
| <p className="text-lg font-medium text-gray-600">Loading menu...</p> | ||
| </div> | ||
| ) : mealsError && meals.length === 0 ? ( | ||
| <div className="flex justify-center items-center h-64"> | ||
| <p className="text-lg font-medium text-red-500">{mealsError}</p> | ||
| </div> | ||
| ) : filteredMeals.length === 0 ? ( | ||
| <div className="flex justify-center items-center h-64"> | ||
| <p className="text-lg font-medium text-gray-500">No meals available in this category</p> | ||
| </div> | ||
| ) : ( | ||
| <RegularFood items={filteredMeals} /> | ||
| )} | ||
| </div> | ||
| </div> | ||
| ); | ||
| return ( | ||
| <div className="bg-white min-h-screen px-4 md:px-10 lg:px-20 overflow-hidden"> | ||
| <div className="py-12 md:py-16 lg:py-20 space-y-5 md:space-y-2 lg:space-y-2"> | ||
| <MenuFilter /> | ||
| <OffersSection /> | ||
|
|
||
| {/* Suggested Meals Section (Displayed for logged-in users when recommendations exist) */} | ||
| {!isGuest && ( | ||
| <SuggestedMealsSection items={filteredRecommendations} /> | ||
| )} | ||
|
|
||
| {/* Regular Food Section (Always displayed for everyone) */} | ||
| {mealsLoading && meals.length === 0 ? ( | ||
| <div className="flex justify-center items-center h-64"> | ||
| <p className="text-lg font-medium text-gray-600">Loading menu...</p> | ||
| </div> | ||
| ) : mealsError && meals.length === 0 ? ( | ||
| <div className="flex justify-center items-center h-64"> | ||
| <p className="text-lg font-medium text-red-500">{mealsError}</p> | ||
| </div> | ||
| ) : filteredMeals.length === 0 ? ( | ||
| <div className="flex justify-center items-center h-64"> | ||
| <p className="text-lg font-medium text-gray-500">No meals available in this category</p> | ||
| </div> | ||
| ) : ( | ||
| <RegularFood items={filteredMeals} /> | ||
| )} | ||
| </div> | ||
| </div> | ||
| ); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,29 +1,18 @@ | ||
| import { useState, useEffect } from "react"; | ||
| import { useMenuItems } from "../../../hooks/dashboard/useMenuItems"; | ||
| import RegularFoodCard from "../../../components/UI/RegularFoodCard"; | ||
| import { getMenu } from "../../../services/menu.service"; | ||
| import ScrollArrows from "../../../components/UI/ScrollArrows"; | ||
|
|
||
| const OffersSection = () => { | ||
| const [offersMeals, setOffersMeals] = useState([]); | ||
| const [loading, setLoading] = useState(true); | ||
| const [error, setError] = useState(null); | ||
| const { data: offersMeals = [], isLoading: loading, error: queryError } = useMenuItems({ hasDiscount: true }); | ||
| const error = queryError ? (queryError.message || "Failed to load offers") : null; | ||
| const [current, setCurrent] = useState(0); | ||
|
Comment on lines
6
to
9
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
# Map the target file and neighboring components.
printf '\n## OffersSection outline\n'
ast-grep outline src/pages/Menu/Sections/OffersSection.jsx --view expanded || true
printf '\n## RegularFoodCard candidates\n'
fd -a 'RegularFoodCard' src || true
printf '\n## Search for useMenuItems definition/usages\n'
rg -n "useMenuItems|RegularFoodCard|current" src/pages src -g '!**/node_modules/**' || trueRepository: Revive-Graduation-Project/Revive-Front-End Length of output: 24722 🏁 Script executed: #!/bin/bash
set -euo pipefail
# Show the relevant section of OffersSection.jsx with line numbers.
sed -n '1,220p' src/pages/Menu/Sections/OffersSection.jsx | cat -n
# Find the RegularFoodCard implementation and inspect it.
fd -a 'RegularFoodCard.jsx' src || true
fd -a 'RegularFoodCard.*' src || trueRepository: Revive-Graduation-Project/Revive-Front-End Length of output: 5208 🏁 Script executed: #!/bin/bash
set -euo pipefail
printf '\n## OffersSection outline\n'
ast-grep outline src/pages/Menu/Sections/OffersSection.jsx --view expanded || true
printf '\n## OffersSection lines\n'
sed -n '1,220p' src/pages/Menu/Sections/OffersSection.jsx | cat -n
printf '\n## RegularFoodCard candidates\n'
fd -a 'RegularFoodCard.*' src || true
printf '\n## useMenuItems definition/usages\n'
rg -n "useMenuItems|RegularFoodCard|offersMeals\\[" src -g '!**/node_modules/**' || trueRepository: Revive-Graduation-Project/Revive-Front-End Length of output: 8477 🏁 Script executed: #!/bin/bash
set -euo pipefail
printf '\n## useMenuItems hook\n'
sed -n '1,220p' src/hooks/dashboard/useMenuItems.js | cat -n
printf '\n## RegularFoodCard.jsx\n'
sed -n '1,240p' src/components/ui/RegularFoodCard.jsx | cat -nRepository: Revive-Graduation-Project/Revive-Front-End Length of output: 16104 🏁 Script executed: #!/bin/bash
set -euo pipefail
rg -n "setCurrent\\(|currentIndex|offersMeals\\[current\\]|offersMeals\\.length" src/pages src/components -g '!**/node_modules/**' || trueRepository: Revive-Graduation-Project/Revive-Front-End Length of output: 1277 🏁 Script executed: #!/bin/bash
set -euo pipefail
printf '\n## useMenuItems hook\n'
sed -n '1,220p' src/hooks/dashboard/useMenuItems.js | cat -n
printf '\n## RegularFoodCard.jsx\n'
sed -n '1,240p' src/components/ui/RegularFoodCard.jsx | cat -n
printf '\n## Similar index-state patterns\n'
rg -n "setCurrent\\(|currentIndex|offersMeals\\[current\\]|offersMeals\\.length" src/pages src/components -g '!**/node_modules/**' || trueRepository: Revive-Graduation-Project/Revive-Front-End Length of output: 17234 🏁 Script executed: #!/bin/bash
set -euo pipefail
sed -n '1,220p' src/hooks/dashboard/useMenuItems.js | cat -n
printf '\n---\n'
sed -n '1,240p' src/components/ui/RegularFoodCard.jsx | cat -nRepository: Revive-Graduation-Project/Revive-Front-End Length of output: 16063 Clamp 🤖 Prompt for AI Agents |
||
|
|
||
| useEffect(() => { | ||
| const fetchOffers = async () => { | ||
| setLoading(true); | ||
| setError(null); | ||
| try { | ||
| const res = await getMenu(true); // hasDiscount = true | ||
| setOffersMeals(res.data); | ||
| } catch (err) { | ||
| setError(err.message || "Failed to load offers"); | ||
| } finally { | ||
| setLoading(false); | ||
| } | ||
| }; | ||
| fetchOffers(); | ||
| }, []); | ||
| if (offersMeals.length > 0 && current >= offersMeals.length) { | ||
| setCurrent(current % offersMeals.length); | ||
| } | ||
| }, [offersMeals.length, current]); | ||
|
|
||
| if (loading) { | ||
| return ( | ||
|
|
@@ -62,8 +51,9 @@ const OffersSection = () => { | |
| ); | ||
| } | ||
|
|
||
| const prevIndex = (current - 1 + offersMeals.length) % offersMeals.length; | ||
| const nextIndex = (current + 1) % offersMeals.length; | ||
| const safeCurrent = current % offersMeals.length; | ||
| const prevIndex = (safeCurrent - 1 + offersMeals.length) % offersMeals.length; | ||
| const nextIndex = (safeCurrent + 1) % offersMeals.length; | ||
|
|
||
| const goPrev = () => setCurrent(prevIndex); | ||
| const goNext = () => setCurrent(nextIndex); | ||
|
|
@@ -112,7 +102,7 @@ const OffersSection = () => { | |
| <RegularFoodCard meal={offersMeals[prevIndex]} /> | ||
| </div> | ||
| <div className="w-95 lg:w-105 scale-105 opacity-100 -translate-y-4 transition-all duration-300"> | ||
| <RegularFoodCard meal={offersMeals[current]} /> | ||
| <RegularFoodCard meal={offersMeals[safeCurrent]} /> | ||
| </div> | ||
| <div className="w-85 lg:w-90 scale-95 opacity-80 translate-y-6 transition-all duration-300"> | ||
| <RegularFoodCard meal={offersMeals[nextIndex]} /> | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🩺 Stability & Availability | 🔴 Critical | ⚡ Quick win
Rendering the raw
errorobject will crash the component.errorfromuseMenuItems({})is anError/AxiosErrorinstance, not a string. Passing it directly as a JSX child (<p>{error}</p>) throws "Objects are not valid as a React child" and crashes the section on any fetch failure.RegularFood.jsxandOffersSection.jsxcorrectly derive a string viaerror.message— this file wasn't updated to match.🐛 Proposed fix
Also applies to: 41-42
🤖 Prompt for AI Agents