Skip to content

Commit

Permalink
Searching for all games fixed, added form validation and style update
Browse files Browse the repository at this point in the history
  • Loading branch information
pmAdriaan committed Feb 17, 2024
1 parent 7aa9dd4 commit 25f81cd
Show file tree
Hide file tree
Showing 5 changed files with 163 additions and 53 deletions.
12 changes: 12 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"dependencies": {
"@fontsource/montserrat": "^5.0.16",
"axios": "^1.6.7",
"debounce": "^2.0.0",
"dotenv": "^16.4.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
Expand Down
196 changes: 145 additions & 51 deletions src/components/Header.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React, { useContext, useState, useEffect } from "react";
import { useLocation } from "react-router-dom";
import { useLocation, Link } from "react-router-dom";
import _debounce from "debounce";
import { ThemeContext } from "../context/ThemeContext";
import whiteLogo from "./../assets/images/zog-logo-white.png";
import blackLogo from "./../assets/images/zog-logo-black.png";
Expand All @@ -18,6 +19,8 @@ const Header = () => {
const [searchQuery, setSearchQuery] = useState("");
const [filteredGames, setFilteredGames] = useState([]);
const [showSuggestions, setShowSuggestions] = useState(false);
const [selectedSuggestion, setSelectedSuggestion] = useState(0);


useEffect(() => {
// Determine the active index based on the pathname
Expand All @@ -37,25 +40,31 @@ const Header = () => {
setActiveIndex(getActiveIndex());
}, [location]); // Re-run the effect when the location changes

useEffect(() => {
const fetchGameList = async () => {
try {
const response = await rawgApi.getGamesList;
const fetchGameList = async () => {
try {
if (searchQuery.trim() !== "") {
const response = await rawgApi.getSearchAllGames(searchQuery);
setGameList(response?.data?.results || []);
} catch (error) {
console.error("Error fetching game list:", error);
} else {
setGameList([]);
}
};
} catch (error) {
console.error("Error fetching game list:", error);
}
};

fetchGameList();
}, []);
const debouncedFetchGameList = _debounce(fetchGameList, 300);

useEffect(() => {
// Filter games based on search query
const filtered = gameList.filter((game) => game.name.toLowerCase().includes(searchQuery.toLowerCase()));
debouncedFetchGameList();
return debouncedFetchGameList.cancel;
}, [searchQuery]);

useEffect(() => {
const filtered = gameList.filter((game) =>
game.name.toLowerCase().includes(searchQuery.toLowerCase())
);
setFilteredGames(filtered);
// Show suggestions only if there are filtered games
// and search query is not empty
setShowSuggestions(searchQuery !== "" && filtered.length > 0);
}, [searchQuery, gameList]);

Expand All @@ -64,92 +73,164 @@ const Header = () => {
};

const handleSuggestionClick = (gameName) => {
// Set search query to the clicked game name
setSearchQuery(gameName);
// Hide suggestions
setShowSuggestions(false);
};

const handleEnterPress = (event, gameId) => {
if (event.key === "Enter") {
// Navigate to the selected game page
if (event.key === "Enter" && searchQuery.trim() !== "" && filteredGames.length > 0) {
window.location.href = `/games/${gameId}`;
}
};

const handleArrowKeyPress = (event) => {
if (event.key === "ArrowDown" && selectedSuggestion < filteredGames.length - 1) {
setSelectedSuggestion(selectedSuggestion + 1);
} else if (event.key === "ArrowUp" && selectedSuggestion > 0) {
setSelectedSuggestion(selectedSuggestion - 1);
}
};

const handleSearchSubmit = (gameId) => {
if (searchQuery.trim() !== "" && filteredGames.length > 0) {
window.location.href = `/games/${gameId}`;
}
};

return (
<div className="flex items-center p-3 border-b-2 border-accent">
<a href="/">
<img className="hover:scale-125 transition duration-200 ease-in-out ml-1" src={logoSrc} width={100} height={50} alt="Logo image" />
<img
className="hover:scale-125 transition duration-200 ease-in-out ml-1"
src={logoSrc}
width={100}
height={50}
alt="Logo image"
/>
</a>

<div className="flex bg-slate-200 p-2 w-screen mx-5 rounded-full items-center relative">
{" "}
{/* Add relative positioning */}
<IoSearchSharp />
<input
required
type="text"
placeholder="Search Games..."
className="px-2 bg-transparent outline-none w-full"
value={searchQuery}
onChange={handleSearchChange}
onKeyDown={(event) => handleEnterPress(event, filteredGames.length > 0 ? filteredGames[0].id : "")}
onKeyDown={(event) => {
handleArrowKeyPress(event);
handleEnterPress(event, filteredGames.length > 0 ? filteredGames[selectedSuggestion].id : "");
}}
/>
{showSuggestions && (
<div className="absolute top-full left-0 w-3/4 bg-white rounded-xl z-10">
{" "}
{/* Position suggestions below the input */}
{filteredGames.map((game) => (
<div key={game.id} className="p-2 border-b border-gray-200 rounded-xl hover:bg-accent cursor-pointer" onClick={() => handleSuggestionClick(game.name)}>
{" "}
{/* Make suggestions clickable */}
<div className="absolute top-full left-0 w-3/4 bg-white rounded-xl z-10 mt-2">
{filteredGames.map((game, index) => (
<div
key={game.id}
className={`p-3 border-b border-gray-200 rounded-xl hover:bg-accent cursor-pointer ${index === selectedSuggestion ? "bg-accent text-white" : ""
}`}
onClick={() => {
handleSuggestionClick(game.name);
handleSearchSubmit(game.id);
}}
>
{game.name}
</div>
))}
</div>
)}
{/* Search button/icon */}
<div
className={`cursor-pointer ml-2 ${searchQuery.trim() === "" || filteredGames.length === 0 ? "cursor-not-allowed" : ""}`}
onClick={(event) => {
event.preventDefault();
handleSearchSubmit(filteredGames.length > 0 ? filteredGames[selectedSuggestion].id : "");
}}
>
<svg
className={`w-6 h-6 text-accent hover:text-accent-dark transition duration-200 ${searchQuery.trim() === "" || filteredGames.length === 0 ? "text-gray-500" : ""}`}
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
strokeWidth="2"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
d="M5 12h14M12 5l7 7-7 7"
/>
</svg>
</div>
</div>
<button
onClick={() => setOpenMenu(!openMenu)}
className="inline-flex items-center p-2 md:hidden text-text hover:bg-accent hover:text-white rounded-md px-3 py-2 text-sm font-bold cursor-pointer"
>
<svg className="w-6 h-6" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth="2">
<path strokeLinecap="round" strokeLinejoin="round" d="M4 6h16M4 12h16M4 18h16" />
<svg
className="w-6 h-6"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
strokeWidth="2"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
d="M4 6h16M4 12h16M4 18h16"
/>
</svg>
</button>

<div className={`fixed rounded-xl top-0 w-max right-0 z-50 py-5 pr-10 dark:bg-primary bg-white shadow-md md:hidden ${openMenu ? "block" : "hidden"}`}>
<button onClick={() => setOpenMenu(false)} className="absolute top-2 right-2 text-gray-600 hover:text-gray-800">
<div
className={`fixed rounded-xl top-0 w-max right-0 z-50 py-5 pr-10 dark:bg-primary bg-white shadow-md md:hidden ${openMenu ? "block" : "hidden"
}`}
>
<button
onClick={() => setOpenMenu(false)}
className="absolute top-2 right-2 text-gray-600 hover:text-gray-800"
>
<IoCloseOutline className="text-2xl font-bold" />
</button>
<ul className="space-y-2">
<li>
<a
href="/"
className={`flex items-center text-text hover:bg-accent hover:text-white rounded-md px-3 py-2 text-sm font-bold ${activeIndex === 0 ? "border-b-4 border-accent" : ""}`}
<Link
to="/"
alt= "Home Page"
title= "Go back home"
className={`flex items-center text-text hover:bg-accent hover:text-white rounded-md px-3 py-2 text-sm font-bold ${activeIndex === 0 ? "border-b-4 border-accent" : ""
}`}
aria-current="page"
>
<FaHome className="mr-2" />
Home
</a>
</Link>
</li>
<li>
<a
href="/about"
className={`flex items-center text-text hover:bg-accent hover:text-white rounded-md px-3 py-2 text-sm font-bold ${activeIndex === 1 ? "border-b-4 border-accent" : ""}`}
<Link
to="/about"
alt= "About Page"
title="About Page"
className={`flex items-center text-text hover:bg-accent hover:text-white rounded-md px-3 py-2 text-sm font-bold ${activeIndex === 1 ? "border-b-4 border-accent" : ""
}`}
>
<FaInfoCircle className="mr-2" />
About
</a>
</Link>
</li>
<li>
<a
href="/contact"
className={`flex items-center text-text hover:bg-accent hover:text-white rounded-md px-3 py-2 text-sm font-bold ${activeIndex === 2 ? "border-b-4 border-accent" : ""}`}
<Link
to="/contact"
alt= "Contact Page"
title="Contact Page"
className={`flex items-center text-text hover:bg-accent hover:text-white rounded-md px-3 py-2 text-sm font-bold ${activeIndex === 2 ? "border-b-4 border-accent" : ""
}`}
>
<FaAddressBook className="mr-2" />
Contact
</a>
</Link>
</li>

<button
Expand All @@ -160,8 +241,14 @@ const Header = () => {
}}
className="flex items-center bg-slate-200 text-black px-3 py-1 ml-2 rounded-full cursor-pointer"
>
{theme === "light" ? <MdDarkMode className="text-[25px]" /> : <MdLightMode className="text-[25px]" />}
<span className="text-sm dark:text-black pl-2 font-bold text-text">{theme === "light" ? "Dark" : "Light"}</span>
{theme === "light" ? (
<MdDarkMode className="text-[25px]" />
) : (
<MdLightMode className="text-[25px]" />
)}
<span className="text-sm dark:text-black pl-2 font-bold text-text">
{theme === "light" ? "Dark" : "Light"}
</span>
</button>
</ul>
</div>
Expand All @@ -170,22 +257,25 @@ const Header = () => {
<div className="flex space-x-5">
<a
href="/"
className={`flex items-center text-text hover:bg-accent hover:text-white rounded-md px-3 py-2 text-sm font-bold ${activeIndex === 0 ? "border-b-4 border-accent" : ""}`}
className={`flex items-center text-text hover:bg-accent hover:text-white rounded-md px-3 py-2 text-sm font-bold ${activeIndex === 0 ? "border-b-4 border-accent" : ""
}`}
aria-current="page"
>
<FaHome className="mr-2" />
Home
</a>
<a
href="/about"
className={`flex items-center text-text hover:bg-accent hover:text-white rounded-md px-3 py-2 text-sm font-bold ${activeIndex === 1 ? "border-b-4 border-accent" : ""}`}
className={`flex items-center text-text hover:bg-accent hover:text-white rounded-md px-3 py-2 text-sm font-bold ${activeIndex === 1 ? "border-b-4 border-accent" : ""
}`}
>
<FaInfoCircle className="mr-2" />
About
</a>
<a
href="/contact"
className={`flex items-center text-text hover:bg-accent hover:text-white rounded-md px-3 py-2 text-sm font-bold ${activeIndex === 2 ? "border-b-4 border-accent" : ""}`}
className={`flex items-center text-text hover:bg-accent hover:text-white rounded-md px-3 py-2 text-sm font-bold ${activeIndex === 2 ? "border-b-4 border-accent" : ""
}`}
>
<FaAddressBook className="mr-2" />
Contact
Expand All @@ -198,7 +288,11 @@ const Header = () => {
}}
className="bg-slate-200 dark:text-white hover:scale-125 transition duration-200 ease-in-out bg-transparent cursor-pointer"
>
{theme === "light" ? <MdDarkMode className="text-[30px]" /> : <MdLightMode className="text-[30px] mr-1" />}
{theme === "light" ? (
<MdDarkMode className="text-[30px]" />
) : (
<MdLightMode className="text-[30px] mr-1" />
)}
</button>
</div>
</div>
Expand Down
2 changes: 0 additions & 2 deletions src/pages/games/top/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ const RawgTopRatedGames = lazy(() => import(
// API
import rawgApi from "../../../services/rawgApi";



const TopRatedGames = () => {
// State for top games list from RAWG Api
const [allGamesList, setAllGamesList] = useState([]);
Expand Down
5 changes: 5 additions & 0 deletions src/services/rawgApi.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ const getPlatformList = axiosCreateRawgApi.get(
const getGamesList = axiosCreateRawgApi.get(
"/games?key=" + import.meta.env.VITE_RAWG_API_KEY
);
const getSearchAllGames = (query) => axiosCreateRawgApi.get(
"/games?key=" + import.meta.env.VITE_RAWG_API_KEY +
"&search=" + query
);
const getGameData = (gId) => axiosCreateRawgApi.get(
"/games/" + gId +
"?key=" + import.meta.env.VITE_RAWG_API_KEY
Expand All @@ -37,4 +41,5 @@ export default {
getGameData,
getGamesByGenreIdAndPlatformId,
getGamesByPlatform,
getSearchAllGames,
};

0 comments on commit 25f81cd

Please sign in to comment.