diff --git a/app/db.ts b/app/db.ts index 3e77c80..10a6525 100644 --- a/app/db.ts +++ b/app/db.ts @@ -1,41 +1,21 @@ +import axios from "axios"; + import { Location } from "@/interfaces/Location"; import { FrontEndReviews } from "@/interfaces/Review"; const backend = "http://localhost:8000"; export async function fetchLocations(): Promise { - const res = await fetch("http://localhost:8000/api/locations", { - method: "GET", - next: { - revalidate: 1800, // every 30 minutes - }, - mode: "cors", - headers: { - "Access-Control-Allow-Origin": "*", - }, - }); - const data: { locations: Location[] } = await res.json(); - return data.locations; + const res = await axios.get(`${backend}/api/locations`); + return res.data.locations; } export async function fetchFoodReviewsBulk(data: { food_names: string[]; user_id: string | null; }): Promise { - const res = await fetch("http://localhost:8000/api/get_ratings_bulk/", { - method: "POST", - headers: { - "Content-Type": "application/json", - "Access-Control-Allow-Origin": "*", - }, - body: JSON.stringify(data), - next: { - revalidate: 5, // every 5 seconds - }, - mode: "cors", - }); - const response_json = await res.json(); - return response_json; + const res = await axios.post(`${backend}/api/get_ratings_bulk/`, data); + return res.data; } export async function updateReview(data: { @@ -43,15 +23,6 @@ export async function updateReview(data: { user_id: string; food_rating: number; }): Promise<{ average: number | null }> { - const res = await fetch("http://localhost:8000/api/rating_update/", { - method: "POST", - headers: { - "Content-Type": "application/json", - "Access-Control-Allow-Origin": "*", - }, - body: JSON.stringify(data), - mode: "cors", - }); - const response_json = await res.json(); - return response_json; + const res = await axios.post(`${backend}/api/rating_update/`, data); + return res.data; } diff --git a/app/locations/[location]/DH_Search/page.tsx b/app/locations/[location]/DH_Search/page.tsx index 600ba3f..6ebff92 100644 --- a/app/locations/[location]/DH_Search/page.tsx +++ b/app/locations/[location]/DH_Search/page.tsx @@ -1,31 +1,15 @@ "use client"; -import React, { useEffect, useState } from "react"; -import axios from "axios"; -import styles from "../Search.module.css"; +import { useEffect, useState } from "react"; import Image from "next/image"; -// Define the Food interface -interface Food { - name: string; - restrictions: string[]; -} - -// Define the subCategory interface -interface subCategory { - name: string; - foods: Array; -} +import { fetchLocations } from "@/app/db"; -// Define the Category interface -interface Category { - name: string; - sub_categories: Array; -} +import { Location, Food } from "@/interfaces/Location"; +import Link from "next/link"; -// Define the DiningHall interface -interface DiningHall { - name: string; - categories: Array; +interface FoodWithCategory { + food: Food; + category: string; } // Map of restriction images @@ -47,337 +31,438 @@ const restrictionImageMap: { [key: string]: string } = { alcohol: "/Images/alcohol.jpg", }; -const HelloWorld: React.FC = () => { - const [filteredFoods, setFilteredFoods] = useState< - { food: Food; dhName: string; categoryName: string }[] - >([]); - const [showSearchResults, setShowSearchResults] = useState(false); - const [noFoodsFound, setNoFoodsFound] = useState(false); - const [diningHall, setDiningHall] = useState(null); +// const HelloWorld: React.FC = () => { +// const [filteredFoods, setFilteredFoods] = useState< +// { food: Food; dhName: string; categoryName: string }[] +// >([]); +// const [showSearchResults, setShowSearchResults] = useState(false); +// const [noFoodsFound, setNoFoodsFound] = useState(false); +// const [diningHall, setDiningHall] = useState(null); +// const [searchInput, setSearchInput] = useState(""); +// const [searchResults, setSearchResults] = useState([]); + +// // Retrieve the dining hall name from localStorage when the component mounts +// useEffect(() => { +// const storedDiningHall = localStorage.getItem("diningHall"); +// setDiningHall(storedDiningHall); +// }, []); + +// // Handle search logic +// const handleSearch = () => { +// const currentDiningHallName = localStorage.getItem("diningHall"); + +// // Filter the dining halls to find the current one +// const currentDiningHall = dhs.find( +// (dh) => dh.name === currentDiningHallName +// ); + +// if (currentDiningHall) { +// const allFoods: { food: Food; dhName: string; categoryName: string }[] = +// []; + +// // Collect all foods from the current dining hall only +// currentDiningHall.categories.forEach((category) => { +// category.sub_categories.forEach((subCategory) => { +// subCategory.foods.forEach((food) => { +// allFoods.push({ +// food, +// dhName: currentDiningHall.name, +// categoryName: category.name, +// }); +// }); +// }); +// }); + +// // Filter the collected foods based on the search input +// const filtered = allFoods.filter(({ food }) => +// food.name.toLowerCase().includes(searchInput.toLowerCase()) +// ); + +// // Check if all boxes are unchecked +// const allBoxesUnchecked = +// selectedShowAllergies.length === 0 && +// selectedHideAllergies.length === 0; + +// let finalFilteredFoods = filtered; +// if (!allBoxesUnchecked) { +// // Filter foods based on selectedShowAllergies and selectedHideAllergies +// finalFilteredFoods = filtered.filter(({ food }) => { +// const hasShowAllergy = +// selectedShowAllergies.length === 0 || +// selectedShowAllergies.every((allergy) => +// food.name.toLowerCase().includes(allergy.toLowerCase()) +// ); +// const hasHideAllergy = selectedHideAllergies.some( +// (allergy) => food.restrictions.includes(allergy.toLowerCase()) // Check if food's restrictions include the hide allergy +// ); +// return hasShowAllergy && !hasHideAllergy; +// }); +// } + +// // Update the state based on the search results +// setNoFoodsFound(finalFilteredFoods.length === 0); +// setFilteredFoods(finalFilteredFoods); +// setShowSearchResults(true); +// } else { +// // Handle case where the current dining hall is not found +// setFilteredFoods([]); +// setShowSearchResults(false); +// setNoFoodsFound(true); +// } +// }; + +// return ( +//
+//

+// {diningHall ? diningHall : "Dining Hall not found"} +//

+//
+// setSearchInput(e.target.value)} +// className="border border-gray-400 p-2 rounded" +// /> +// +//
+// {searchResults.length > 0 && ( +//
+//

{searchResults[0].categoryName}:

+//
    +// {searchResults.map((food: any, index: number) => ( +//
  • +//
    +// +// {food.name} - {food.categoryName} ({diningHall}) +// +//
    +// {food.restrictions.map( +// (restriction: string, index: number) => ( +// {restriction} +// ) +// )} +//
    +//
    +//
  • +// ))} +//
+//
+// )} +//
+// ); +// }; + +// const BarebonesComponent: React.FC = () => { +// const [dhs, setDhs] = useState([]); +// const [searchInput, setSearchInput] = useState(""); +// const [filteredFoods, setFilteredFoods] = useState< +// { food: Food; dhName: string; categoryName: string }[] +// >([]); +// const [showSearchResults, setShowSearchResults] = useState(false); +// const [noFoodsFound, setNoFoodsFound] = useState(false); + +// // Retrieve hide and show allergies from local storage +// const [selectedHideAllergies, setSelectedHideAllergies] = useState( +// () => { +// const storedHideAllergies = localStorage.getItem("hideAllergies"); +// return storedHideAllergies ? JSON.parse(storedHideAllergies) : []; +// } +// ); + +// const [selectedShowAllergies, setSelectedShowAllergies] = useState( +// () => { +// const storedShowAllergies = localStorage.getItem("showAllergies"); +// return storedShowAllergies ? JSON.parse(storedShowAllergies) : []; +// } +// ); + +// // Fetch dining hall data from the API when the component mounts +// useInsertionEffect(() => { +// fetchLocations().then((locations: Location[]) => { +// setDhs(locations); +// }); +// }, []); + +// // Handle search input change +// const handleSearchInputChange = ( +// event: React.ChangeEvent +// ) => { +// setSearchInput(event.target.value); +// }; + +// // Handle filter button click +// const handleFilter = () => { +// window.location.href = "Filter-Window"; +// }; + +// // Handle search logic +// const handleSearch = () => { +// const currentDiningHallName = localStorage.getItem("diningHall"); + +// // Filter the dining halls to find the current one +// const currentDiningHall = dhs.find( +// (dh) => dh.name === currentDiningHallName +// ); + +// if (currentDiningHall) { +// const allFoods: { food: Food; dhName: string; categoryName: string }[] = +// []; + +// // Collect all foods from the current dining hall only +// currentDiningHall.categories.forEach((category) => { +// category.sub_categories.forEach((subCategory) => { +// subCategory.foods.forEach((food) => { +// allFoods.push({ +// food, +// dhName: currentDiningHall.name, +// categoryName: category.name, +// }); +// }); +// }); +// }); + +// // Filter the collected foods based on the search input +// const filtered = allFoods.filter(({ food }) => +// food.name.toLowerCase().includes(searchInput.toLowerCase()) +// ); + +// // Check if all boxes are unchecked +// const allBoxesUnchecked = +// selectedShowAllergies.length === 0 && +// selectedHideAllergies.length === 0; + +// let finalFilteredFoods = filtered; +// if (!allBoxesUnchecked) { +// // Filter foods based on selectedShowAllergies and selectedHideAllergies +// finalFilteredFoods = filtered.filter(({ food }) => { +// const hasShowAllergy = +// selectedShowAllergies.length === 0 || +// selectedShowAllergies.every((allergy) => +// food.name.toLowerCase().includes(allergy.toLowerCase()) +// ); +// const hasHideAllergy = selectedHideAllergies.some( +// (allergy) => food.restrictions.includes(allergy.toLowerCase()) // Check if food's restrictions include the hide allergy +// ); +// return hasShowAllergy && !hasHideAllergy; +// }); +// } + +// // Update the state based on the search results +// setNoFoodsFound(finalFilteredFoods.length === 0); +// setFilteredFoods(finalFilteredFoods); +// setShowSearchResults(true); +// } else { +// // Handle case where the current dining hall is not found +// setFilteredFoods([]); +// setShowSearchResults(false); +// setNoFoodsFound(true); +// } +// }; + +// return ( +//
+// {/* Title and Search bar */} +//
+//

+// {localStorage.getItem("diningHall")} +//

+ +//
+// +// +// {/* Filter button */} +//
+// Filter +//
+//
+//
+ +// {/* Display search results if button clicked */} +// {showSearchResults && ( +//
+//

Search Results:

+//
    +// {filteredFoods.map(({ food, dhName, categoryName }, index) => ( +//
  • +// {food.name} - {categoryName} ({dhName}) +//
    +// {food.restrictions.map((restriction, index) => ( +// {restriction} +// ))} +//
    +//
  • +// ))} +//
+//
+// )} + +// {noFoodsFound && ( +//
+//

No foods found at this dining hall.

+//
+// )} +//
+// ); +// }; + +// export default BarebonesComponent; + +// import Link from "next/link"; + +export default function Page({ params }: { params: { location: number } }) { + const [location, setLocation] = useState(null); + const [foods, setFoods] = useState([]); const [searchInput, setSearchInput] = useState(""); - const [searchResults, setSearchResults] = useState([]); + const [foundFoods, setFoundFoods] = useState([]); - // Retrieve the dining hall name from localStorage when the component mounts useEffect(() => { - const storedDiningHall = localStorage.getItem("diningHall"); - setDiningHall(storedDiningHall); - }, []); - - // Handle search logic - const handleSearch = () => { - const currentDiningHallName = localStorage.getItem("diningHall"); - - // Filter the dining halls to find the current one - const currentDiningHall = dhs.find( - (dh) => dh.name === currentDiningHallName, - ); - - if (currentDiningHall) { - const allFoods: { food: Food; dhName: string; categoryName: string }[] = - []; - - // Collect all foods from the current dining hall only - currentDiningHall.categories.forEach((category) => { - category.sub_categories.forEach((subCategory) => { - subCategory.foods.forEach((food) => { - allFoods.push({ - food, - dhName: currentDiningHall.name, - categoryName: category.name, - }); - }); - }); - }); - - // Filter the collected foods based on the search input - const filtered = allFoods.filter(({ food }) => - food.name.toLowerCase().includes(searchInput.toLowerCase()), - ); - - // Check if all boxes are unchecked - const allBoxesUnchecked = - selectedShowAllergies.length === 0 && - selectedHideAllergies.length === 0; - - let finalFilteredFoods = filtered; - if (!allBoxesUnchecked) { - // Filter foods based on selectedShowAllergies and selectedHideAllergies - finalFilteredFoods = filtered.filter(({ food }) => { - const hasShowAllergy = - selectedShowAllergies.length === 0 || - selectedShowAllergies.every((allergy) => - food.name.toLowerCase().includes(allergy.toLowerCase()), - ); - const hasHideAllergy = selectedHideAllergies.some( - (allergy) => food.restrictions.includes(allergy.toLowerCase()), // Check if food's restrictions include the hide allergy - ); - return hasShowAllergy && !hasHideAllergy; - }); + fetchLocations().then((locations: Location[]) => { + if (params.location < 0 || params.location >= locations.length) { + return

Location not found

; } + const location: Location = locations[params.location]; + setLocation(location); + + const foods_db = location.categories.flatMap((category) => + category.sub_categories.flatMap((sub_category) => + sub_category.foods.map((food) => ({ + food: food, + category: category.name, + })) + ) + ); + setFoods(foods_db); + }); + }, [params.location]); - // Update the state based on the search results - setNoFoodsFound(finalFilteredFoods.length === 0); - setFilteredFoods(finalFilteredFoods); - setShowSearchResults(true); - } else { - // Handle case where the current dining hall is not found - setFilteredFoods([]); - setShowSearchResults(false); - setNoFoodsFound(true); - } - }; - - return ( -
-

- {diningHall ? diningHall : "Dining Hall not found"} -

-
- setSearchInput(e.target.value)} - className="border border-gray-400 p-2 rounded" - /> - -
- {searchResults.length > 0 && ( -
-

{searchResults[0].categoryName}:

-
    - {searchResults.map((food: any, index: number) => ( -
  • -
    - - {food.name} - {food.categoryName} ({diningHall}) - -
    - {food.restrictions.map( - (restriction: string, index: number) => ( - {restriction} - ), - )} -
    -
    -
  • - ))} -
-
- )} -
- ); -}; - -const BarebonesComponent: React.FC = () => { - const [dhs, setDhs] = useState([]); - const [searchInput, setSearchInput] = useState(""); - const [filteredFoods, setFilteredFoods] = useState< - { food: Food; dhName: string; categoryName: string }[] - >([]); - const [showSearchResults, setShowSearchResults] = useState(false); - const [noFoodsFound, setNoFoodsFound] = useState(false); - - // Retrieve hide and show allergies from local storage - const [selectedHideAllergies, setSelectedHideAllergies] = useState( - () => { - const storedHideAllergies = localStorage.getItem("hideAllergies"); - return storedHideAllergies ? JSON.parse(storedHideAllergies) : []; - }, - ); - - const [selectedShowAllergies, setSelectedShowAllergies] = useState( - () => { - const storedShowAllergies = localStorage.getItem("showAllergies"); - return storedShowAllergies ? JSON.parse(storedShowAllergies) : []; - }, - ); + if (!location || !foods) { + return

Loading...

; + } - // Fetch dining hall data from the API when the component mounts - useEffect(() => { - axios - .get("http://localhost:8000/myapi/locations/") - .then((response) => { - const dhsData: DiningHall[] = response.data.locations; - setDhs(dhsData); - }) - .catch((error) => { - console.log(error); - }); - }, []); - - // Handle search input change - const handleSearchInputChange = ( - event: React.ChangeEvent, - ) => { - setSearchInput(event.target.value); - }; - - // Handle filter button click - const handleFilter = () => { - window.location.href = "Filter-Window"; - }; + // const filterFoods; - // Handle search logic - const handleSearch = () => { - const currentDiningHallName = localStorage.getItem("diningHall"); - - // Filter the dining halls to find the current one - const currentDiningHall = dhs.find( - (dh) => dh.name === currentDiningHallName, + const searchForFood = (food_name: string) => { + // search for food + const foundFoods = foods.filter((foodWithCategory) => + foodWithCategory.food.name.toLowerCase().includes(food_name.toLowerCase()) ); - if (currentDiningHall) { - const allFoods: { food: Food; dhName: string; categoryName: string }[] = - []; - - // Collect all foods from the current dining hall only - currentDiningHall.categories.forEach((category) => { - category.sub_categories.forEach((subCategory) => { - subCategory.foods.forEach((food) => { - allFoods.push({ - food, - dhName: currentDiningHall.name, - categoryName: category.name, - }); - }); - }); - }); - - // Filter the collected foods based on the search input - const filtered = allFoods.filter(({ food }) => - food.name.toLowerCase().includes(searchInput.toLowerCase()), - ); - - // Check if all boxes are unchecked - const allBoxesUnchecked = - selectedShowAllergies.length === 0 && - selectedHideAllergies.length === 0; - - let finalFilteredFoods = filtered; - if (!allBoxesUnchecked) { - // Filter foods based on selectedShowAllergies and selectedHideAllergies - finalFilteredFoods = filtered.filter(({ food }) => { - const hasShowAllergy = - selectedShowAllergies.length === 0 || - selectedShowAllergies.every((allergy) => - food.name.toLowerCase().includes(allergy.toLowerCase()), - ); - const hasHideAllergy = selectedHideAllergies.some( - (allergy) => food.restrictions.includes(allergy.toLowerCase()), // Check if food's restrictions include the hide allergy - ); - return hasShowAllergy && !hasHideAllergy; - }); - } + // apply filters - // Update the state based on the search results - setNoFoodsFound(finalFilteredFoods.length === 0); - setFilteredFoods(finalFilteredFoods); - setShowSearchResults(true); - } else { - // Handle case where the current dining hall is not found - setFilteredFoods([]); - setShowSearchResults(false); - setNoFoodsFound(true); - } + setFoundFoods(foundFoods); }; return ( -
- {/* Title and Search bar */} -
-

- {localStorage.getItem("diningHall")} -

- -
+
+
+
+

+ {location.name} +

+
+ +
setSearchInput(e.target.value)} /> - - {/* Filter button */} -
searchForFood(searchInput)} + className="ml-2 px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600" > - Filter -
+ Search +
-
- {/* Display search results if button clicked */} - {showSearchResults && (
-

Search Results:

-
    - {filteredFoods.map(({ food, dhName, categoryName }, index) => ( -
  • - {food.name} - {categoryName} ({dhName}) -
    - {food.restrictions.map((restriction, index) => ( - {restriction} - ))} -
    -
  • + {foundFoods.length > 0 && + foundFoods.map((foodWithCategory, index) => ( +
    + +

    {foodWithCategory.food.name}

    +
    + {foodWithCategory.category} +
    + +
      + {foodWithCategory.food.restrictions.map( + (restriction, index) => ( +
    • + {restriction} +
    • + ) + )} +
    +
    ))} -
-
- )} - - {noFoodsFound && ( -
-

No foods found at this dining hall.

- )} -
+
+ ); -}; - -export default BarebonesComponent; +} diff --git a/interfaces/Location.ts b/interfaces/Location.ts index 54a1da2..5d2fa41 100644 --- a/interfaces/Location.ts +++ b/interfaces/Location.ts @@ -1,14 +1,14 @@ -interface Food { +export interface Food { name: string; restrictions: Array; } -interface subCategory { +export interface subCategory { name: string; foods: Array; } -interface Category { +export interface Category { name: string; sub_categories: Array; } diff --git a/package.json b/package.json index 4836101..7b064da 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,8 @@ "prettier": "^3.2.5", "react": "^18", "react-dom": "^18", - "react-router-dom": "^6.23.0" + "react-router-dom": "^6.23.0", + "supports-color": "8.1.1" }, "devDependencies": { "@types/node": "^20",