diff --git a/client/package-lock.json b/client/package-lock.json index 43334ad..b82eb69 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -14,6 +14,7 @@ "chart.js": "^4.4.0", "d3": "^7.8.5", "date-fns": "^2.30.0", + "fuse.js": "^7.0.0", "react": "^18.2.0", "react-chartjs-2": "^5.2.0", "react-dom": "^18.2.0", @@ -9161,6 +9162,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/fuse.js": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/fuse.js/-/fuse.js-7.0.0.tgz", + "integrity": "sha512-14F4hBIxqKvD4Zz/XjDc3y94mNZN6pRv3U13Udo0lNLCWRBUsrMv2xwcF/y/Z5sV6+FQW+/ow68cHpm4sunt8Q==", + "engines": { + "node": ">=10" + } + }, "node_modules/gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", diff --git a/client/package.json b/client/package.json index 307aba4..4cdfbce 100644 --- a/client/package.json +++ b/client/package.json @@ -10,6 +10,7 @@ "chart.js": "^4.4.0", "d3": "^7.8.5", "date-fns": "^2.30.0", + "fuse.js": "^7.0.0", "react": "^18.2.0", "react-chartjs-2": "^5.2.0", "react-dom": "^18.2.0", diff --git a/client/src/components/GameSessionList.tsx b/client/src/components/GameSessionList.tsx index 347a1eb..330bc03 100644 --- a/client/src/components/GameSessionList.tsx +++ b/client/src/components/GameSessionList.tsx @@ -1,24 +1,47 @@ import "../styles/GameSessionList.css"; -import React, { useContext, useState } from "react"; +import React, { useContext, useEffect, useState } from "react"; import GameSessionCard from "./GameSessionCard"; import { GoodplaysContext } from "../models/GoodplaysContextType"; import AddGameSessionModal from "./AddGameSessionModal"; import { fetchGameSessions } from "../AppUtils"; import { faSync } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import Fuse from "fuse.js"; const GameSessionList: React.FC = () => { const { gameSessions, setGameSessions, goodplaysUser } = useContext(GoodplaysContext); + const [search, setSearch] = useState(""); + const [searchResults, setSearchResults] = useState(gameSessions); + + const fuseOptions = { + keys: ['gameName'], + includeScore: true, + threshold: 0.3, + }; + const fuse = new Fuse(gameSessions, fuseOptions); + useEffect(() => { + if (search === '') { + setSearchResults(gameSessions); + } else { + const result = fuse.search(search); + const sortedResults = result.map(({ item }) => item).sort((a, b) => { + // Assuming endTimestamp is a Date object + return new Date(b.endTimestamp).getTime() - new Date(a.endTimestamp).getTime(); + }); + setSearchResults(sortedResults); + } + }, [search, gameSessions]); + const gamesPerPage = 5; - const totalPages = Math.ceil(gameSessions.length / gamesPerPage); + const totalPages = Math.ceil(searchResults.length / gamesPerPage); const paginate = (pageNumber: number) => { const startIndex = (pageNumber - 1) * gamesPerPage; const endIndex = startIndex + gamesPerPage; - return gameSessions.slice(startIndex, endIndex); + return searchResults.slice(startIndex, endIndex); }; const [currentPage, setCurrentPage] = useState(1); @@ -81,6 +104,14 @@ const GameSessionList: React.FC = () => {
+ setSearch(e.target.value)} + placeholder="Search game sessions" + /> +
+ {currentGameSessions.map((session, index) => ( ))}