Skip to content

Commit

Permalink
Merge pull request #53 from HungrySlugs-CSE115A/searchbar
Browse files Browse the repository at this point in the history
Added slightly buggy search bar to each dining hall page that filters each food
  • Loading branch information
anyazhang17 authored May 6, 2024
2 parents b530eb4 + 4d13fdf commit 70ba251
Show file tree
Hide file tree
Showing 5 changed files with 402 additions and 42 deletions.
98 changes: 83 additions & 15 deletions app/[dh_choice]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
"use client";

import React, { useState, useEffect } from "react";
import React, { useState, useEffect, useRef } from "react";
import axios from "axios";
import './accordian.css';
import Link from "next/link";


interface Food {
Expand All @@ -22,10 +22,10 @@ interface Category {

interface DiningHall {
name: string;
categories: Category;
categories: Category[];
}

function name_to_dh_index(dhName: string, dhArray: Array<DiningHall>) {
function name_to_dh_index(dhName: string, dhArray: DiningHall[]) {
for (let i = 0; i < dhArray.length; i++) {
if (dhArray[i].name === dhName) {
return i;
Expand All @@ -34,21 +34,25 @@ function name_to_dh_index(dhName: string, dhArray: Array<DiningHall>) {
return -1;
}

function Accordion({ category, index }) {
const [isOpen, setIsOpen] = useState(false);
function Accordion({ category, index, isOpen }) {
const [isOpenState, setIsOpenState] = useState(isOpen);

useEffect(() => {
setIsOpenState(isOpen);
}, [isOpen]);

return (
<div className="accordion border border-gray-200 rounded mb-2">
<button
className="accordion-button w-full text-left p-3 focus:outline-none"
onClick={() => setIsOpen(!isOpen)}
onClick={() => setIsOpenState(!isOpenState)}
>
{category.name}
<span className="float-right">
{isOpen ? "▲" : "▼"}
{isOpenState ? "▲" : "▼"}
</span>
</button>
{isOpen && (
{isOpenState && (
<div className="accordion-collapse p-3">
{category.sub_categories.map((sub_category, j) => (
<div key={j} className="mb-2">
Expand All @@ -67,7 +71,13 @@ function Accordion({ category, index }) {
}

export default function Page({ searchParams }) {
const [categories, set_categories] = useState([]);
const [categories, set_categories] = useState<Category[]>([]);
const [searchInput, setSearchInput] = useState('');
const [filteredFoods, setFilteredFoods] = useState<Food[]>([]);
const [expandedCategory, setExpandedCategory] = useState<number | null>(null);
const [noFoodsFound, setNoFoodsFound] = useState(false);
const [searchActive, setSearchActive] = useState(false);
const searchRef = useRef<HTMLDivElement>(null);

useEffect(() => {
axios
Expand All @@ -85,6 +95,11 @@ export default function Page({ searchParams }) {
alert("No food categories found");
return;
}
const timeOfDay = getTimeOfDay();
const timeIndex = a_dh.categories.findIndex(category => category.name.toLowerCase() === timeOfDay);
if (timeIndex !== -1) {
setExpandedCategory(timeIndex);
}
})
.catch((error) => {
console.log(error);
Expand All @@ -93,19 +108,72 @@ export default function Page({ searchParams }) {
console.log(categories)


useEffect(() => {
const timeOfDay = getTimeOfDay();
const timeIndex = categories.findIndex(category => category.name.toLowerCase() === timeOfDay);
if (timeIndex !== -1) {
setExpandedCategory(timeIndex);
}
}, [categories]);

const handleSearchInputChange = (event: React.ChangeEvent<HTMLInputElement>) => {
setSearchInput(event.target.value);
};

function handleSearch() {
const dhChoice = searchParams.name;
const searchResultPageUrl = `/search?diningHall=${encodeURIComponent(searchParams.name)}`;
// Navigate to the search result page
window.location.href = searchResultPageUrl;
localStorage.setItem('diningHall', dhChoice);
}

function getTimeOfDay(): string {
const currentTime = new Date();
const currentHour = currentTime.getHours();

if (currentHour >= 7 && currentHour < 11) {
return "breakfast";
} else if (currentHour >= 11 && currentHour < 16) {
return "lunch";
} else if (currentHour >= 16 && currentHour < 19) {
return "dinner";
} else {
return "late night";
}
}

useEffect(() => {
const handleOutsideClick = (event: MouseEvent) => {
if (searchRef.current && !searchRef.current.contains(event.target as Node)) {
setSearchActive(false);
}
};

document.addEventListener("mousedown", handleOutsideClick);

return () => {
document.removeEventListener("mousedown", handleOutsideClick);
};
}, []);

return (
<main>
<div className="container mx-auto">
<h2 className="text-2xl mb-4">{searchParams.name}</h2>

{/* Search button */}
<div>
<button onClick={handleSearch}>Search</button>
</div>

{/* Categories */}
{categories.map((category, i) => (
<div key={i}>
{/* <h3 className="text-lg">{category.name}</h3> */}
<div>
<Accordion category={category} index={i} />
</div>
<Accordion category={category} index={i} isOpen={expandedCategory === i} />
</div>
))}
</div>
</main>
);
}
}
103 changes: 103 additions & 0 deletions app/global_search/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
"use client";
import React, { useState, useEffect } from 'react';
import axios from 'axios';

interface Food {
name: string;
}

interface subCategory {
name: string;
foods: Array<Food>;
}

interface Category {
name: string;
sub_categories: Array<subCategory>;
}

interface DiningHall {
name: string;
categories: Category[];
}

const BarebonesComponent = () => {
const [dhs, setDhs] = useState<DiningHall[]>([]);
const [searchInput, setSearchInput] = useState<string>('');
const [filteredFoods, setFilteredFoods] = useState<{ food: Food; dhName: string; categoryName: string }[]>([]);
const [showSearchResults, setShowSearchResults] = useState<boolean>(false);
const [noFoodsFound, setNoFoodsFound] = useState<boolean>(false);

useEffect(() => {
axios
.get('http://localhost:8000/myapi/dining-halls/')
.then((response) => {
const dhsData: DiningHall[] = response.data.locations;
setDhs(dhsData);
})
.catch((error) => {
console.log(error);
});
}, []);

const handleSearchInputChange = (event: React.ChangeEvent<HTMLInputElement>) => {
setSearchInput(event.target.value);
};

const handleSearch = () => {
const allFoods: { food: Food; dhName: string; categoryName: string }[] = [];
dhs.forEach((dh) => {
dh.categories.forEach((category) => {
category.sub_categories.forEach((subCategory) => {
subCategory.foods.forEach((food) => {
allFoods.push({ food, dhName: dh.name, categoryName: category.name });
});
});
});
});

const filtered = allFoods.filter(({ food }) => food.name.toLowerCase().includes(searchInput.toLowerCase()));

setNoFoodsFound(filtered.length === 0);
setFilteredFoods(filtered);
setShowSearchResults(true);
};

return (
<div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center' }}>
{/* Title */}
<h1 className="text-8xl">Welcome to Hungry Slugs!</h1>
{/* Search bar */}
<div className="search-bar" style={{ marginTop: '20px' }}> {/* Adjust margin as needed */}
<input
type="text"
placeholder="Search foods..."
value={searchInput}
onChange={handleSearchInputChange}
/>
<button onClick={handleSearch}>Search</button>
</div>
{/* Display search results if button clicked */}
{showSearchResults && (
<div>
<h3>Search Results:</h3>
<ul>
{filteredFoods.map(({ food, dhName, categoryName }, index) => (
<li key={index}>
{food.name} - {categoryName} ({dhName})
</li>
))}
</ul>
</div>
)}

{noFoodsFound && (
<div>
<h3>No foods found at this dining hall.</h3>
</div>
)}
</div>
);
};

export default BarebonesComponent;
98 changes: 75 additions & 23 deletions app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,49 +48,101 @@ function ButtonLink(props: any) {
}

function Home() {
const [dhs_names, set_dhs_names] = useState([""]);
const [dhs, setDhs] = useState<DiningHall[]>([]);
const [searchInput, setSearchInput] = useState('');
const [filteredFoods, setFilteredFoods] = useState<{ food: Food; dhName: string; categoryName: string }[]>([]);
const [showSearchResults, setShowSearchResults] = useState(false);
const [noFoodsFound, setNoFoodsFound] = useState(false);

useEffect(() => {
axios
.get("http://localhost:8000/myapi/dining-halls/")
.then((response) => {
// get the data from the response
const dhs: Array<DiningHall> = response.data["locations"];

// print the data to the console
console.log(dhs);

// extract the names of the dining halls
const dhs_names: string[] = [];
dhs.forEach((dh: DiningHall) => {
dhs_names.push(dh["name"]);
});

// set the state of the dining hall names
set_dhs_names(dhs_names);
const dhs: DiningHall[] = response.data["locations"];
setDhs(dhs);
})
.catch((error) => {
console.log(error);
});
}, []);

const handleSearchInputChange = (event: React.ChangeEvent<HTMLInputElement>) => {
setSearchInput(event.target.value);
};

const handleSearch = () => {
const allFoods: { food: Food; dhName: string; categoryName: string }[] = [];
dhs.forEach((dh) => {
dh.categories.forEach((category) => {
category.sub_categories.forEach((subCategory) => {
subCategory.foods.forEach((food) => {
allFoods.push({ food, dhName: dh.name, categoryName: category.name });
});
});
});
});

const filtered = allFoods
.filter(({ food }) => food.name.toLowerCase().includes(searchInput.toLowerCase()))
// .filter(({ food }, index, self) => self.findIndex(({ food }) => food.name === food.name) === index);

setNoFoodsFound(filtered.length === 0);
setFilteredFoods(filtered);
setShowSearchResults(true);
};

return (
<main>
<div>
{/* Title */}
<h1 className="text-8xl">Welcome to Hungry Slugs!</h1>
{/* Display All of the dinning hall names as links */}
<ul>
{dhs_names.map((dh, i) => (
<li key={i}>
<ButtonLink button_name={dh} name={dh} />
</li>
))}
</ul>
{/* Search bar */}
{/* <div className="search-bar">
<input
type="text"
placeholder="Search foods..."
value={searchInput}
onChange={handleSearchInputChange}
/>
<button onClick={handleSearch}>Search</button>
</div> */}
{/* Display search results if button clicked */}
{showSearchResults && (
<div>
<h3>Search Results:</h3>
<ul>
{filteredFoods.map(({ food, dhName, categoryName }, index) => (
<li key={index}>
{food.name} - {categoryName} ({dhName})
</li>
))}
</ul>
</div>
)}

{noFoodsFound && (
<div>
<h3>No foods found at this dining hall.</h3>
</div>
)}
{/* Display all dining halls */}
<div>
<h2>Dining Halls:</h2>
<ul>
{dhs.map((dh, i) => (
<li key={i}>
<ButtonLink button_name={dh.name} name={dh.name} />
</li>
))}
</ul>
</div>
</div>
</main>
);
}



export default function Page() {
const [user, setUser] = useState<User | null>(null);

Expand Down
Loading

0 comments on commit 70ba251

Please sign in to comment.