diff --git a/src/components/Searchbar.tsx b/src/components/Searchbar.tsx new file mode 100644 index 0000000..b123de9 --- /dev/null +++ b/src/components/Searchbar.tsx @@ -0,0 +1,29 @@ +import SearchIcon from "../assets/search.svg"; + +//Values recived from CharactersPage as props +type SearchBarProps = { + searchQuery: string; + onSearchChange: (value: string) => void; +}; + +export default function Searchbar({ + searchQuery, + onSearchChange, +}: SearchBarProps) { + return ( +
event.preventDefault()}> + onSearchChange(event.target.value)} + /> + +
+ ); +} diff --git a/src/pages/CharactersPage.tsx b/src/pages/CharactersPage.tsx index fc16ddd..7eb9710 100644 --- a/src/pages/CharactersPage.tsx +++ b/src/pages/CharactersPage.tsx @@ -1,14 +1,19 @@ import "./CharactersPage.css"; import { useEffect, useState } from "react"; +import { useQuery } from "@tanstack/react-query"; + import CharacterCardSmall from "../components/CharacterCardSmall"; import CharacterDetailCard from "../components/CharacterDetailCard"; -import SearchIcon from "../assets/search.svg"; -import { useQuery } from '@tanstack/react-query'; +import Searchbar from "../components/Searchbar"; import type { Character } from "../types/Character"; -type FilterCategory = "gender" | "species" | "status"; +import { + filterCharacters, + type FilterCategory, + type SelectedFilters, +} from "../utils/filterCharacters"; const filters: { title: string; key: FilterCategory; options: string[] }[] = [ { title: "Gender", key: "gender", options: ["Female", "Male", "Unknown"] }, @@ -18,37 +23,41 @@ const filters: { title: string; key: FilterCategory; options: string[] }[] = [ // AI was used to create the fetchCharacters function async function fetchCharacters(): Promise { - const response = await fetch("https://rickandmortyapi.com/api/character"); + const response = await fetch("https://rickandmortyapi.com/api/character"); - if (!response.ok) { - throw new Error(`Could not fetch characters: ${response.status}`); - } + if (!response.ok) { + throw new Error(`Could not fetch characters: ${response.status}`); + } - const data = await response.json(); - return data.results; + const data = await response.json(); + return data.results; } export default function CharactersPage() { - const {data: characters = []} = useQuery({queryKey: ['characters'], queryFn: fetchCharacters}); + const { data: characters = [] } = useQuery({ + queryKey: ["characters"], + queryFn: fetchCharacters, + }); const [selectedCharacter, setSelectedCharacter] = useState( null, ); - const [searchQuery, setsearchQuery] = useState(""); - const [selectedFilters, setSelectedFilters] = useState< - Record - >(() => { - const storedFilters = sessionStorage.getItem("selectedFilters"); - - if (storedFilters) { - return JSON.parse(storedFilters); - } - - return { - gender: [], - species: [], - status: [], - }; - }); + const [searchQuery, setSearchQuery] = useState(""); + const [selectedFilters, setSelectedFilters] = useState( + () => { + const storedFilters = sessionStorage.getItem("selectedFilters"); + + if (storedFilters) { + return JSON.parse(storedFilters); + } + + return { + gender: [], + species: [], + status: [], + }; + }, + ); + const [favoriteCharacterIds, setFavoriteCharacterIds] = useState( () => { const storedFavorites = localStorage.getItem("favoriteCharacterIds"); @@ -72,22 +81,11 @@ export default function CharactersPage() { ); }, [favoriteCharacterIds]); - const filteredCharacters = characters.filter((character) => { - const matchesSearch = character.name - .toLowerCase() - .includes(searchQuery.toLowerCase()); - const matchesFilters = filters.every((filter) => { - const selectedOptions = selectedFilters[filter.key]; - - if (selectedOptions.length === 0) { - return true; - } - - return selectedOptions.includes(character[filter.key].toLowerCase()); - }); - - return matchesSearch && matchesFilters; - }); + const filteredCharacters = filterCharacters( + characters, + searchQuery, + selectedFilters, + ); function handleFilterChange( category: FilterCategory, @@ -145,23 +143,7 @@ export default function CharactersPage() { return (
-
event.preventDefault()} - > - setsearchQuery(event.target.value)} - /> - -
+
{filteredCharacters.map((character) => ( ; + +export function filterCharacters( + // Takes in all characters, the value in the search field and the chosen filters + characters: Character[], + searchQuery: string, + selectedFilters: SelectedFilters, +): Character[] { + return characters.filter((character) => { + //Checks whether each character's name matches with the search and if the character's gender, specie or status is checked off in the filter + const matchesSearch = character.name + .toLowerCase() + .includes(searchQuery.toLowerCase()); + + const matchesGender = + selectedFilters.gender.length === 0 || + selectedFilters.gender.includes(character.gender.toLowerCase()); + + const matchesSpecies = + selectedFilters.species.length === 0 || + selectedFilters.species.includes(character.species.toLowerCase()); + + const matchesStatus = + selectedFilters.status.length === 0 || + selectedFilters.status.includes(character.status.toLowerCase()); + //Returns the result of the checks mentioned above + return matchesSearch && matchesGender && matchesSpecies && matchesStatus; + }); +}