Skip to content

Commit

Permalink
Merge pull request #8 from scottylabs-labrador/cici-react-frontend
Browse files Browse the repository at this point in the history
added local storage for saved searches and moved search content to be…
  • Loading branch information
qianxuege authored Jul 3, 2024
2 parents da59a2c + 9510920 commit dd1ed7f
Show file tree
Hide file tree
Showing 5 changed files with 229 additions and 142 deletions.
24 changes: 20 additions & 4 deletions src/components/SavedSearches.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,37 @@
import React, { useState } from "react";
import { RxCross1 } from "react-icons/rx";

type ButtonClickHandler = (value:string) => void;

interface ButtonComponentProps {
content: string;
clickStay: boolean;
textSize: string;
clearSingleSavedItems: ButtonClickHandler;
buttonClicked?: boolean;
}

const SavedSearchBtn: React.FC<ButtonComponentProps> = ({ content, clickStay, textSize, buttonClicked }) => {
const SavedSearchBtn: React.FC<ButtonComponentProps> = ({ content, clickStay, textSize, clearSingleSavedItems, buttonClicked }) => {

Check failure on line 14 in src/components/SavedSearches.tsx

View workflow job for this annotation

GitHub Actions / build (20.x)

'buttonClicked' is defined but never used
const [displayx, setDisplayx] = useState(true);
const [greenBg, setGreenBg] = useState(true);

const handleXClick = () => {
// setDisplayx(false);
// setGreenBg(false);
clearSingleSavedItems(content);
}

const handleMainClick = () => {
setDisplayx(true);
setGreenBg(!greenBg);
}

return (
<button className={`rounded-full border border-teal px-4 py-1 flex items-center gap-1 ${textSize} ${
clickStay ? "bg-teal text-white" : ""}`}>
<span>{content}</span>
<RxCross1 className="h-4 w-3 text-gray-200 ml-3 mr-0.5" />
(clickStay && greenBg) ? "bg-teal text-white" : ""} `}>
<span onClick={handleMainClick}>{content}</span>
{displayx && <RxCross1 onClick={handleXClick} className={`h-4 w-3 ${greenBg? "text-gray-200" : ""} ml-3 mr-0.5`} />}

</button>
)

Expand Down
180 changes: 43 additions & 137 deletions src/components/Search.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@ import React, { useEffect, useState } from "react";
// search input
import { IoSearch } from "react-icons/io5";
import { RxCross1 } from "react-icons/rx";
import { SearchCard } from "./SearchCard";
import Fuse from 'fuse.js'
import DropInData from "../../backend/scraper/drop_in.json";
// saved searches
import { saveArrayToLocalStorage, getArrayFromLocalStorage } from "../utils/localStorageUtil";
// for date picker
import dayjs, { Dayjs } from 'dayjs';
import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
Expand All @@ -19,19 +18,12 @@ import Select, { SelectChangeEvent } from '@mui/material/Select';
import Checkbox from '@mui/material/Checkbox';
import { categoryListAcademics, categoryListClubs, categoryListCareer } from "../types";
// selectable dropdown
// import { Dropdown } from "./Dropdown";
import { Button } from "./Button";

import "react-dropdown/style.css";
import "./Search.css";
import { SavedSearchBtn } from "./SavedSearches";
// import useSearch from "../../utils/hooks/useSearch";
import DITData from "../../backend/scraper/drop_in.json";
import PTData from "../../backend/scraper/peer_tutoring.json";
import SIData from "../../backend/scraper/si.json";
import ClubsData from "../../backend/scraper/tartanconnect.json";
import CareerData from "../../backend/scraper/handshake.json";

import SearchContent from "./SearchContent";

// https://plainenglish.io/blog/how-to-implement-a-search-bar-in-react-js

Expand All @@ -44,6 +36,7 @@ const Search: React.FC<SearchComponentProps> = ({ page }) => {
// Chang name to search bar
const [searchInput, setSearchInput] = useState("");
const [categoryName, setCategoryName] = useState<string[]>([]);
const [savedItems, setSavedItems] = useState<string[]>([]);
// search results
// const [data, setData] = useState(null)
// date picker
Expand All @@ -52,16 +45,36 @@ const Search: React.FC<SearchComponentProps> = ({ page }) => {
const showDatePicker = true;


useEffect(()=> {
// const [data, setData] = useState([]);
useEffect(() => {
// Load the array from local storage when the component mounts
const storedItems = getArrayFromLocalStorage<string>('savedSearches');
setSavedItems(storedItems);
// clearSavedItems();
console.log(savedItems);
}, [searchInput]);

const clearSavedItems = () => {

Check failure on line 56 in src/components/Search.tsx

View workflow job for this annotation

GitHub Actions / build (20.x)

'clearSavedItems' is assigned a value but never used
setSavedItems([]);
localStorage.removeItem('savedSearches');
};

// const fuse = new Fuse(SIData, {
// keys: ["course_id", "course_name"],
// });
const clearSingleSavedItems = (value:string) => {
const index:number = savedItems.indexOf(value);
const newArray = savedItems.slice(0,index).concat(savedItems.slice(index+1,-1));
setSavedItems(newArray);
saveArrayToLocalStorage('savedSearches', newArray);
// localStorage.removeItem('savedSearches');
};

const addSavedItem = () => {
if (!savedItems.includes(searchInput)) {
const newItems = [...savedItems, searchInput];
setSavedItems(newItems);
saveArrayToLocalStorage('savedSearches', newItems);
}
console.log(savedItems);
};

// setData([fuse.search(searchInput)]);
getCategoryData(page);
},[categoryName])


// search
Expand All @@ -82,68 +95,6 @@ const Search: React.FC<SearchComponentProps> = ({ page }) => {
);
};

const inDateRange = (date: string) => {
const startDateObj = startDate.toDate();
const endDateObj = endDate.toDate();
const eventDate = new Date(date);
return eventDate >= startDateObj && eventDate <= endDateObj;
}

const getCategoryData = (currPage:string) => {
// console.log("running category data");
switch(currPage) {
case "academics":
const optionsAcademics = { keys: ['resource_type', 'course_id', 'course_name'] }
let combinedData = [...DITData, ...SIData, ...PTData];
const fuseAcademics = new Fuse(combinedData, optionsAcademics);
// const fuse = new Fuse(SIData, options);
if (categoryName.length == 0 || categoryName.length==4) {
return fuseAcademics.search(searchInput);
} else {
if (!categoryName.includes("Supplemental Instructions")) {
fuseAcademics.remove((doc) => {
return doc.resource_type === 'SI';
})
}
if (!categoryName.includes("Drop-in Tutoring")) {
fuseAcademics.remove((doc) => {
return doc.resource_type === 'DIT';
})
}
if (!categoryName.includes("Peer Tutoring")) {
fuseAcademics.remove((doc) => {
return doc.resource_type === 'PT'
})
}
return fuseAcademics.search(searchInput);
}
break;
case "clubs":
const optionsClubs = { keys: ['resource_type', 'event_name', 'event_host', 'categories'] }
const fuseClubs = new Fuse(ClubsData, optionsClubs);
return fuseClubs.search(searchInput);
break;
case "career":
const optionsCareer = { keys: ['resource_type', 'event_name', 'event_host', 'categories'] }
const fuseCareer = new Fuse(CareerData, optionsCareer);
return fuseCareer.search(searchInput);
break;
}
}

const getWeekday = (weekday: number) => {
const today = new Date();
const dayOfWeekToday = today.getDay(); // 0 (Sunday) to 6 (Saturday)
const offSet = dayOfWeekToday - weekday;
if (offSet === 0 || offSet === 7) {
return today.toDateString();
} else {
const targetDay = new Date(today);
targetDay.setDate(today.getDate() - offSet);
return targetDay.toDateString();
}
}

const getNumCategories = () => {
if (page==="academics") {
return categoryListAcademics.length;
Expand Down Expand Up @@ -254,26 +205,17 @@ const Search: React.FC<SearchComponentProps> = ({ page }) => {
);
}

// bogus values
const eventName1 = "Office Hours";
const orgName1 = "15-122 Course Staff";
const startDate1 = "06/17"
const startTime1 = "3PM"
const endDate1 = "06/17"
const endTime1 = "5PM"
const location1 = "POS 146";
// const eventCategory1 = "academic";
// const eventSubcategory1 = "OfficeHour";
return (
<div className="bg-[#F5F5F5] relative -top-2 w-full min-h-screen pl-8 pt-7 text-sans">
<div className="flex flex-col w-11/12 gap-y-2.5">
<div className="no-scroll-bar flex flex-nowrap flex-row gap-x-1.5 overflow-scroll">
<SavedSearchBtn content="15122" clickStay={true} textSize="text-xs"/>
<SavedSearchBtn content="programming" clickStay={true} textSize="text-xs"/>
<SavedSearchBtn content="15122" clickStay={true} textSize="text-xs"/>
<SavedSearchBtn content="15122" clickStay={true} textSize="text-xs"/>
<SavedSearchBtn content="15122" clickStay={true} textSize="text-xs"/>
<SavedSearchBtn content="15122" clickStay={true} textSize="text-xs"/>
{savedItems && savedItems.map((item, index) => {
return (
<SavedSearchBtn key={index} content={item} clickStay={true} clearSingleSavedItems={clearSingleSavedItems} textSize="text-xs"/>
)
})}
{/* <SavedSearchBtn content="15122" clickStay={true} textSize="text-xs"/>
<SavedSearchBtn content="programming" clickStay={true} textSize="text-xs"/> */}
</div>
<div className="bg-gray-200 relative h-12 w-full rounded-md border border-black border-[1.5] flex items-center justify-center">
<input
Expand All @@ -283,23 +225,24 @@ const Search: React.FC<SearchComponentProps> = ({ page }) => {
value={searchInput}
className="bg-gray-200 flex-grow px-4 focus:outline-none"
/>
{/* Search icon. Add onClick function in the future */}
{/* Search icon */}
{searchInput?
<RxCross1 onClick = {()=> setSearchInput("")} className="h-6 w-6 text-gray-500 mr-2" /> :
<IoSearch className="h-6 w-6 text-gray-500 mr-2" />
}

</div>

{/* drop down filter */}
<div className="mt-3 flex w-full items-baseline justify-between">
<div className="w-3/5 items-center flex flex-row justify-between space-x-2">{dateContent}</div>
{/* drop down filter */}
{(page === "academics" || page === "clubs" || page==="career") ? (
<div className="w-2/6">{categoryContent}</div>
) : (
<></>
)}
</div>

{/* <div className="w-full mt-2">{actionsMenuComp}</div> */}
<div className="w-full mt-2 flex justify-between">
{/* <Dropdown/> */}
Expand All @@ -308,45 +251,8 @@ const Search: React.FC<SearchComponentProps> = ({ page }) => {
</div>

<div className="overflow-scroll" style={{height: '70vh'}}>
{searchInput && page==="academics" && getCategoryData(page)?.map( (result) => {
for (let i = 0; i<result.item.events.length; i++) {
if (inDateRange(getWeekday(result.item.events[i].weekday))) {
return (
<SearchCard
key={result.refIndex}
eventName={`${result.item.resource_type} for ${result.item.course_name}`}
orgName={`${result.item.course_id} Staff`}
startDate={getWeekday(result.item.events[i].weekday) || `null`}
startTime={result.item.events[i].start_time}
endDate={getWeekday(result.item.events[i].weekday) || `null`}
endTime={result.item.events[i].end_time}
location={result.item.events[i].location}
/>
)
}
}
})}
{searchInput && (page==="clubs" || page==="career") && getCategoryData(page)?.map( (result) => {
for (let i = 0; i<result.item.events.length; i++) {
if (inDateRange(getWeekday(result.item.events[i].weekday))) {
return (
<SearchCard
key={result.refIndex}
eventName={`${result.item.event_name}`}
orgName={`${result.item.event_host}`}
startDate={getWeekday(result.item.events[i].weekday) || `null`}
startTime={result.item.events[i].start_time}
endDate={getWeekday(result.item.events[i].weekday) || `null`}
endTime={result.item.events[i].end_time}
location={result.item.events[i].location}
/>
)
}
}
})}
{ searchInput && <SearchContent searchInput={searchInput} page={page} categoryName={categoryName} startDate={startDate} endDate={endDate} addToSavedItems={addSavedItem}/>}
</div>



</div>
</div>
Expand Down
11 changes: 10 additions & 1 deletion src/components/SearchCard.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import React, { useState } from "react";
import React, { useEffect, useState } from "react";

Check failure on line 1 in src/components/SearchCard.tsx

View workflow job for this annotation

GitHub Actions / build (20.x)

'useEffect' is defined but never used
import { IoLocationSharp, IoAdd } from "react-icons/io5";
import { FaRegClock, FaCheck } from "react-icons/fa";
import { saveArrayToLocalStorage, getArrayFromLocalStorage } from "../utils/localStorageUtil";

Check failure on line 4 in src/components/SearchCard.tsx

View workflow job for this annotation

GitHub Actions / build (20.x)

'saveArrayToLocalStorage' is defined but never used

type ButtonClickHandler = () => void;

interface SearchCardProps {
eventName: string;
Expand All @@ -10,6 +13,7 @@ interface SearchCardProps {
endDate: string;
endTime: string;
location: string;
addToSavedItems: ButtonClickHandler;
// eventCategory: string;
// eventSubcategory: string;
}
Expand All @@ -22,15 +26,20 @@ const SearchCard: React.FC<SearchCardProps> = ({
endDate,
endTime,
location,
addToSavedItems,
// eventCategory,
// eventSubcategory,
}) => {
const [buttonClicked, setButtonClicked] = useState(false);
const [cardClicked, setCardClicked] = useState(false);

// const [savedItems, setSavedItems] = useState<string[]>([]);


const handleAddToCalendar = () => {
setButtonClicked((prevClicked) => !prevClicked);
// Logic for calling GCal
addToSavedItems();
};

const handleCardClicked = () => {
Expand Down
Loading

0 comments on commit dd1ed7f

Please sign in to comment.