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 (
+
+ );
+}
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 (
-
+
{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;
+ });
+}