From a2ad91d0eaffa6c3dc4f827cdf90e9b53779f94a Mon Sep 17 00:00:00 2001 From: Akshat Tiwari Date: Fri, 31 May 2024 16:06:28 -0700 Subject: [PATCH 1/2] Fixed Filter And Adjusted Global Search UI --- app/global_search/Search.module.css | 87 +++++- app/global_search/page.tsx | 95 +++--- app/locations/[location]/DH_Search/page.tsx | 314 +++++++++++++------- db.sqlite3 | Bin 143360 -> 143360 bytes 4 files changed, 310 insertions(+), 186 deletions(-) diff --git a/app/global_search/Search.module.css b/app/global_search/Search.module.css index edf7cf6..a8cfc9a 100644 --- a/app/global_search/Search.module.css +++ b/app/global_search/Search.module.css @@ -1,17 +1,74 @@ -.filterText { - font-size: 3rem; /* Adjust the font size as needed */ - color: #003c6c; /* Set the text color */ - font-weight: 600; /* Set the font weight */ - padding-top: 1.25rem; /* Match the py-5 padding top */ - display: center; /* Match the flex display */ - align-items: center; /* Match the items-center alignment */ - justify-content: center; /* Match the justify-center alignment */ -} - -.filterTopLeft { - position: absolute; +.container { + display: flex; + flex-direction: column; align-items: center; - top: 3rem; /* Adjust the top position as needed */ - left: 80 rem; /* Adjust the left position as needed */ - margin: 0; /* Remove the margin */ +} + +.title { + font-size: 60px; + margin-bottom: 20px; + color: #003c6c; + font-weight: 600; + text-align: center; +} + +.searchBar { + display: flex; + align-items: center; + margin-top: 20px; +} + +.searchInput { + padding: 10px; + font-size: 16px; + border: 1px solid #ccc; + border-radius: 5px; + margin-right: 10px; +} + +.searchButton { + padding: 10px 20px; + background-color: #4caf50; + color: white; + border: none; + border-radius: 5px; + cursor: pointer; +} + +.filterButton { + margin-left: 10px; + padding: 10px 20px; + background-color: #4caf50; + color: white; + cursor: pointer; + border-radius: 5px; +} + +.results { + margin-top: 20px; +} + +.resultList { + list-style-type: none; + padding: 0; +} + +.resultItem { + margin-bottom: 10px; + font-size: 18px; +} + +.restrictionIcons { + display: flex; + flex-wrap: nowrap; +} + +.restrictionIcon { + margin: 5px; +} + +.noResults { + margin-top: 20px; + font-size: 18px; + color: red; } diff --git a/app/global_search/page.tsx b/app/global_search/page.tsx index 9737a0c..cf4fc8e 100644 --- a/app/global_search/page.tsx +++ b/app/global_search/page.tsx @@ -6,7 +6,7 @@ import Image from "next/image"; interface Food { name: string; - restrictions: string[]; // Change to string array + restrictions: string[]; } interface subCategory { @@ -23,11 +23,8 @@ interface DiningHall { name: string; categories: Array; } -interface RestrictionImageMap { - [key: string]: string; -} -const restrictionImageMap = { +const restrictionImageMap: { [key: string]: string } = { eggs: "/Images/egg.jpg", vegan: "/Images/vegan.jpg", fish: "/Images/fish.jpg", @@ -59,14 +56,14 @@ const BarebonesComponent = () => { () => { const storedHideAllergies = localStorage.getItem("hideAllergies"); return storedHideAllergies ? JSON.parse(storedHideAllergies) : []; - }, + } ); const [selectedShowAllergies, setSelectedShowAllergies] = useState( () => { const storedShowAllergies = localStorage.getItem("showAllergies"); return storedShowAllergies ? JSON.parse(storedShowAllergies) : []; - }, + } ); useEffect(() => { @@ -82,7 +79,7 @@ const BarebonesComponent = () => { }, []); const handleSearchInputChange = ( - event: React.ChangeEvent, + event: React.ChangeEvent ) => { setSearchInput(event.target.value); }; @@ -108,7 +105,7 @@ const BarebonesComponent = () => { }); const filtered = allFoods.filter(({ food }) => - food.name.toLowerCase().includes(searchInput.toLowerCase()), + food.name.toLowerCase().includes(searchInput.toLowerCase()) ); // Check if all boxes are unchecked @@ -122,10 +119,10 @@ const BarebonesComponent = () => { const hasShowAllergy = selectedShowAllergies.length === 0 || selectedShowAllergies.every((allergy) => - food.name.toLowerCase().includes(allergy.toLowerCase()), + 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 + const hasHideAllergy = selectedHideAllergies.some((allergy) => + food.restrictions.includes(allergy.toLowerCase()) ); return hasShowAllergy && !hasHideAllergy; }); @@ -137,64 +134,40 @@ const BarebonesComponent = () => { }; return ( -
- {/* Title and Search bar */} -
-

- Global Search -

-
- - - {/* Filter button */} -
- Filter -
+
+

Global Search

+
+ + +
+ 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} ))}
      @@ -205,8 +178,8 @@ const BarebonesComponent = () => { )} {noFoodsFound && ( -
      -

      No foods found at this dining hall.

      +
      +

      No foods found.

      )}
      diff --git a/app/locations/[location]/DH_Search/page.tsx b/app/locations/[location]/DH_Search/page.tsx index afe7418..b000102 100644 --- a/app/locations/[location]/DH_Search/page.tsx +++ b/app/locations/[location]/DH_Search/page.tsx @@ -1,11 +1,10 @@ "use client"; import { useEffect, useState } from "react"; import Image from "next/image"; +import Link from "next/link"; import { fetchLocations } from "@/app/db"; - import { Location, Food } from "@/interfaces/Location"; -import Link from "next/link"; interface FoodWithCategory { food: Food; @@ -31,6 +30,208 @@ const restrictionImageMap: { [key: string]: string } = { alcohol: "/Images/alcohol.jpg", }; +export default function Page({ params }: { params: { location: number } }) { + const [location, setLocation] = useState(null); + const [foods, setFoods] = useState([]); + const [searchInput, setSearchInput] = useState(""); + const [foundFoods, setFoundFoods] = useState([]); + const [selectedRestrictions, setSelectedRestrictions] = useState( + () => { + const storedRestrictions = localStorage.getItem("selectedRestrictions"); + return storedRestrictions ? JSON.parse(storedRestrictions) : []; + } + ); + const [isFilterPopupOpen, setIsFilterPopupOpen] = useState(false); + const [filterApplied, setFilterApplied] = useState(false); + + useEffect(() => { + 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]); + + if (!location || !foods) { + return

      Loading...

      ; + } + + const searchForFood = (food_name: string) => { + const foundFoods = foods.filter((foodWithCategory) => + foodWithCategory.food.name + .toLowerCase() + .includes(food_name.toLowerCase()) + ); + + const filteredFoods = foundFoods.filter(({ food }) => + selectedRestrictions.every((restriction) => + food.restrictions.includes(restriction) + ) + ); + + setFoundFoods(filteredFoods); + }; + + const toggleFilterPopup = () => { + setIsFilterPopupOpen(!isFilterPopupOpen); + }; + + const handleRestrictionChange = (restriction: string, checked: boolean) => { + const newRestrictions = checked + ? [...selectedRestrictions, restriction] + : selectedRestrictions.filter((r) => r !== restriction); + setSelectedRestrictions(newRestrictions); + localStorage.setItem( + "selectedRestrictions", + JSON.stringify(newRestrictions) + ); + }; + + const applyFilter = () => { + setFilterApplied(true); + searchForFood(searchInput); + toggleFilterPopup(); + }; + + return ( +
      +
      +
      +

      + {location.name} +

      +
      + +
      +
      + setSearchInput(e.target.value)} + /> + +
      + +
      + + {isFilterPopupOpen && ( +
      +
      +

      Filter by Restrictions

      +
      + {Object.keys(restrictionImageMap).map((restriction) => ( +
      + + handleRestrictionChange(restriction, e.target.checked) + } + /> + +
      + ))} +
      + + +
      +
      + )} + +
      + {filterApplied && foundFoods.length === 0 ? ( +

      No foods found with the specified allergy constraints

      + ) : ( + foundFoods.map((foodWithCategory, index) => ( +
      + +

      {foodWithCategory.food.name}

      +
      + {foodWithCategory.category} +
      + +
        + {foodWithCategory.food.restrictions.map( + (restriction, index) => ( +
      • + {restriction} +
      • + ) + )} +
      +
      + )) + )} +
      +
      +
      + ); +} + + + + + + + + +// + + // const HelloWorld: React.FC = () => { // const [filteredFoods, setFilteredFoods] = useState< // { food: Food; dhName: string; categoryName: string }[] @@ -360,111 +561,4 @@ const restrictionImageMap: { [key: string]: string } = { // 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 [foundFoods, setFoundFoods] = useState([]); - - useEffect(() => { - 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]); - - if (!location || !foods) { - return

      Loading...

      ; - } - - // const filterFoods; - - const searchForFood = (food_name: string) => { - // search for food - const foundFoods = foods.filter((foodWithCategory) => - foodWithCategory.food.name - .toLowerCase() - .includes(food_name.toLowerCase()), - ); - - // apply filters - - setFoundFoods(foundFoods); - }; - - return ( -
      -
      -
      -

      - {location.name} -

      -
      - -
      - setSearchInput(e.target.value)} - /> - -
      - -
      - {foundFoods.length > 0 && - foundFoods.map((foodWithCategory, index) => ( -
      - -

      {foodWithCategory.food.name}

      -
      - {foodWithCategory.category} -
      - -
        - {foodWithCategory.food.restrictions.map( - (restriction, index) => ( -
      • - {restriction} -
      • - ), - )} -
      -
      - ))} -
      -
      -
      - ); -} +// import Link from "next/link"; \ No newline at end of file diff --git a/db.sqlite3 b/db.sqlite3 index 01261e4d080b25efc7531636a911611cfbf16ea1..21e0d337e211d63525cff2e9a0aed27c162b74d9 100644 GIT binary patch delta 356 zcmZp8z|ru4V}dke)I=F))+h$OvaXFO3+6N1u!l}&U!cjv9=h3Jfik@=q?N!SeyF8d}IQC9w|G-$z#Ibi{ zqb}}Of78Wm>n6XZ`5Ft+WzYYBbT}yFMBBie>C3) zK3?7|o`XDM+=X1nxTHDDI8Jk@v6pUa3})A8)U#prZOnEgMp#!1FrMS<=qC6VDd#Xh-yWl6zamR5$vE>1>?R_5M``GI*QS-K^;x`{zP z`MJrVhMwu=#Xi14CPl8C;0S==2#^~AS&!? Date: Fri, 31 May 2024 16:10:00 -0700 Subject: [PATCH 2/2] Update page.tsx --- app/global_search/page.tsx | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/app/global_search/page.tsx b/app/global_search/page.tsx index cf4fc8e..475a313 100644 --- a/app/global_search/page.tsx +++ b/app/global_search/page.tsx @@ -3,11 +3,10 @@ import React, { useState, useEffect } from "react"; import axios from "axios"; import styles from "./Search.module.css"; import Image from "next/image"; +import { Location, Food } from "@/interfaces/Location"; + + -interface Food { - name: string; - restrictions: string[]; -} interface subCategory { name: string;