From 5b6783c49b0cc13b83c2629996df35eab7cec923 Mon Sep 17 00:00:00 2001 From: Emma Fredriksen Date: Fri, 18 Sep 2026 09:35:28 +0200 Subject: [PATCH 1/8] chore: add coverage/ to gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index a547bf3..21f6c6f 100644 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,4 @@ dist-ssr *.njsproj *.sln *.sw? +coverage/ From e484c64b820be44ddd99de2788bf4117f5b04529 Mon Sep 17 00:00:00 2001 From: Emma Fredriksen Date: Fri, 18 Sep 2026 10:56:11 +0200 Subject: [PATCH 2/8] feat: create footer --- src/components/Footer.css | 12 ++++++++++++ src/components/Footer.tsx | 9 +++++++++ 2 files changed, 21 insertions(+) create mode 100644 src/components/Footer.css create mode 100644 src/components/Footer.tsx diff --git a/src/components/Footer.css b/src/components/Footer.css new file mode 100644 index 0000000..20ff95e --- /dev/null +++ b/src/components/Footer.css @@ -0,0 +1,12 @@ +.footer { + width: 100%; + height: 6rem; + background-color: #161616; + color: white; + font-size: medium; + margin-inline: auto; + display: flex; + align-items: center; + justify-content: center; + text-align: center; +} diff --git a/src/components/Footer.tsx b/src/components/Footer.tsx new file mode 100644 index 0000000..89fff4e --- /dev/null +++ b/src/components/Footer.tsx @@ -0,0 +1,9 @@ +import "./Footer.css"; + +export default function Footer() { + return ( +
+ ©2026 Rick and Morty Character Explorer. All rights reserved. +
+ ); +} From c45e4f90dfe54162024c896f61ac103ebbc27154 Mon Sep 17 00:00:00 2001 From: Emma Fredriksen Date: Fri, 18 Sep 2026 10:56:51 +0200 Subject: [PATCH 3/8] feat: add functionality to close detailcard with "esc" --- src/components/CharacterDetailCard.test.tsx | 19 ++++++++++++++++++- src/components/CharacterDetailCard.tsx | 15 +++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/src/components/CharacterDetailCard.test.tsx b/src/components/CharacterDetailCard.test.tsx index 9e609ef..c43155d 100644 --- a/src/components/CharacterDetailCard.test.tsx +++ b/src/components/CharacterDetailCard.test.tsx @@ -1,5 +1,5 @@ import React from "react"; -import { cleanup, render, screen } from "@testing-library/react"; +import { cleanup, fireEvent, render, screen } from "@testing-library/react"; import "@testing-library/jest-dom/vitest"; import { afterEach, describe, expect, it, vi } from "vitest"; import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; @@ -209,4 +209,21 @@ describe("CharacterDetailCard", () => { expect(onPrevious).toHaveBeenCalledOnce(); }); + + it("closes the detail card when 'esc' is pressed", () => { + const onClose = vi.fn(); + renderWithQueryClient( + , + ); + fireEvent.keyDown(window, { key: "Escape" }); + + expect(onClose).toHaveBeenCalledTimes(1); + }); }); diff --git a/src/components/CharacterDetailCard.tsx b/src/components/CharacterDetailCard.tsx index 46781a5..8b60415 100644 --- a/src/components/CharacterDetailCard.tsx +++ b/src/components/CharacterDetailCard.tsx @@ -12,6 +12,7 @@ import UserRound from "../assets/user-round.svg"; import X from "../assets/X.svg"; import Star from "../assets/star.svg"; import StarFilled from "../assets/star-filled.svg"; +import { useEffect } from "react"; type CharacterDetailCardProps = { character: Character; @@ -60,6 +61,20 @@ export default function CharacterDetailCard({ queryFn: () => fetchEpisodes(character), }); + // Closes detailcard when "esc" is pressed + useEffect(() => { + const handleKeyDown = (event: KeyboardEvent) => { + if (event.key === "Escape") { + onClose(); + } + }; + + window.addEventListener("keydown", handleKeyDown); + return () => { + window.removeEventListener("keydown", handleKeyDown); + }; + }, [onClose]); + return (
Date: Fri, 18 Sep 2026 10:57:46 +0200 Subject: [PATCH 4/8] fix: fix test bug from having two female filters and typos --- src/pages/CharactersPage.css | 6 +++--- src/pages/CharactersPage.test.tsx | 10 +++++----- src/pages/CharactersPage.tsx | 26 ++++++++++++++++++-------- 3 files changed, 26 insertions(+), 16 deletions(-) diff --git a/src/pages/CharactersPage.css b/src/pages/CharactersPage.css index 28a6924..dfc87f7 100644 --- a/src/pages/CharactersPage.css +++ b/src/pages/CharactersPage.css @@ -1,4 +1,5 @@ .content { + min-height: 100vh; display: flex; flex-direction: column; gap: 1.5rem; @@ -51,7 +52,7 @@ min-width: 0; } -.character-cards>* { +.character-cards > * { justify-self: center; } @@ -192,8 +193,7 @@ } .character-cards { - grid-template-columns: - repeat(auto-fill, minmax(min(100%, 12rem), 1fr)); + grid-template-columns: repeat(auto-fill, minmax(min(100%, 12rem), 1fr)); } .filter-options, diff --git a/src/pages/CharactersPage.test.tsx b/src/pages/CharactersPage.test.tsx index e17a84c..5006623 100644 --- a/src/pages/CharactersPage.test.tsx +++ b/src/pages/CharactersPage.test.tsx @@ -244,11 +244,11 @@ describe("CharactersPage", () => { await screen.findByText("Rick Sanchez"); - await user.click( - screen.getByRole("checkbox", { - name: "Female", - }), - ); + const femaleCheckboxes = screen.getAllByRole("checkbox", { + name: "Female", + }); + + await user.click(femaleCheckboxes[0]); expect(screen.getByText("Summer Smith")).toBeInTheDocument(); diff --git a/src/pages/CharactersPage.tsx b/src/pages/CharactersPage.tsx index ec36921..bb82d10 100644 --- a/src/pages/CharactersPage.tsx +++ b/src/pages/CharactersPage.tsx @@ -16,10 +16,10 @@ import { } from "../utils/filterCharacters"; const filters: { title: string; key: FilterCategory; options: string[] }[] = [ - { title: "Favorite", key: "favorite", options: ["My favorites"] }, + { title: "Favorites", key: "favorite", options: ["My favorites"] }, { title: "Gender", key: "gender", options: ["Female", "Male", "Unknown"] }, { title: "Species", key: "species", options: ["Human", "Alien", "Unknown"] }, - { title: "Status", key: "status", options: ["Alive", "Dead", "Unknown"] } + { title: "Status", key: "status", options: ["Alive", "Dead", "Unknown"] }, ]; // AI was used to create the fetchCharacters function @@ -48,9 +48,17 @@ export default function CharactersPage() { const storedFilters = sessionStorage.getItem("selectedFilters"); if (storedFilters) { - return JSON.parse(storedFilters); + try { + return JSON.parse(storedFilters); + } catch { + return { + favorite: [], + gender: [], + species: [], + status: [], + }; + } } - return { favorite: [], gender: [], @@ -65,7 +73,11 @@ export default function CharactersPage() { const storedFavorites = localStorage.getItem("favoriteCharacterIds"); if (storedFavorites) { - return JSON.parse(storedFavorites); + try { + return JSON.parse(storedFavorites); + } catch { + return []; + } } return []; @@ -197,9 +209,7 @@ export default function CharactersPage() {
{renderFilterOptions()}
- +
{selectedCharacter && ( Date: Fri, 18 Sep 2026 10:58:23 +0200 Subject: [PATCH 5/8] refactor: small changes to documentation and structure --- README.md | 2 +- index.html | 2 +- src/App.tsx | 2 ++ src/pages/HeroPage.tsx | 4 ++-- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 7fc2ab3..51d3fe5 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ The webpage will then be available at the local URL provided in the terminal (lo ## Tests -The project has a test coverage of 88,73%. To measure and review the current test coverage, run the following command in the terminal: +The project has a test line coverage of 90%. To measure and review the current test coverage, run the following command in the terminal: ```bash npm test -- --coverage diff --git a/index.html b/index.html index 5cea164..9d7488d 100644 --- a/index.html +++ b/index.html @@ -4,7 +4,7 @@ - project-1 + Rick and Morty Character Explorer
diff --git a/src/App.tsx b/src/App.tsx index b20edee..9510877 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,11 +1,13 @@ import HeroPage from "./pages/HeroPage"; import CharactersPage from "./pages/CharactersPage"; +import Footer from "./components/Footer"; function App() { return (
+
); } diff --git a/src/pages/HeroPage.tsx b/src/pages/HeroPage.tsx index c861070..c1ac4a1 100644 --- a/src/pages/HeroPage.tsx +++ b/src/pages/HeroPage.tsx @@ -5,7 +5,7 @@ import "./HeroPage.css"; function HeroPage() { return ( -
+
Rick and Morty @@ -32,7 +32,7 @@ function HeroPage() { alt="Rick and Morty characters" />
-
+ ); } From f9adb3de8ab5d3f38c3854b5eb0ca78d55d9a29b Mon Sep 17 00:00:00 2001 From: Emma Fredriksen Date: Fri, 18 Sep 2026 11:17:20 +0200 Subject: [PATCH 6/8] docs: add paragraph about manual testing and Node version --- README.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 51d3fe5..54b5045 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ The API documentation can be found here: ## Get started -Before running the project, make sure you have `Node.js` installed on your machine. Install the project dependencies with: +Before running the project, make sure you have `Node.js v24.6.X+` and `npm v11.+` installed on your machine. Install the project dependencies with: ```bash npm install @@ -44,6 +44,14 @@ Each component has its own test file covering its most important functionality. npm test ``` +We performed manual testing for responiveness and user experience. This was done in both landscape and portrait orientations on the following devices: + +- iPhone 16 +- iPhone 13 +- iPad Air +- Macbook Air +- Macbook Pro + ## Developed by - Emma Fredriksen From a0a93005cdf83702176133ae279b422fe3dee5a3 Mon Sep 17 00:00:00 2001 From: Emma Fredriksen Date: Fri, 18 Sep 2026 11:18:58 +0200 Subject: [PATCH 7/8] docs: remove unused markdown --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 54b5045..7a2c3a8 100644 --- a/README.md +++ b/README.md @@ -82,5 +82,5 @@ The user interface is built with our own React components and plain CSS, without ## Use of AI During development, our use of AI has been limited. Any code written with the assistance of AI is marked with a comment above the relevant code snippet. We chose this approach based on our understanding of AI and our previous experience. AI can be a great accelerator when programming, but using it effectively requires a good understanding of the fundamental principles behind the technology being used. Without this understanding it is hard to evaluate the code produced by AI and make informed decisions. Since we are still developing our understanding of React, TypeScript and the other technologies used in this project, we decided it was better to use AI as a coach rather than a developer. This approach affected our development speed, and we spent more time exploring documentation and other learning resources. However, it also gave us a better understanding of the project as a whole and helped us avoid introducing unnecessary code that we did not fully understand or know how to maintain. -
+ We also found that establishing a shared standard for documenting AI-assisted code made it easier to be transparent about the use of AI and to review each other's work. Knowing which parts were developed with AI assistance made it easier to discuss the reasoning behind the code and evaluate whether we understood and agreed with the proposed solutions. At the same time, we recognize that we could probably have achieved a higher development speed by using AI more actively, and AI might also have helped us identify more efficient solutions in some areas. However, for this project, we felt that the benefits of prioritizing learning, transparency, and understanding outweighed the potential increase in productivity. We therefore intend to continue using this approach while gradually increasing our use of AI as our own knowledge and ability to evaluate its output improve. From fdbad2ca5ae749c1c06b6bd96280643f01c862db Mon Sep 17 00:00:00 2001 From: Emma Fredriksen Date: Fri, 18 Sep 2026 11:30:20 +0200 Subject: [PATCH 8/8] docs: explain choice of dataset --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 7a2c3a8..8c8e446 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ The webpage can be accessed through a virtual machine at: ## Overview -This project collects and displays data from an external REST API for the popular TV show _Rick and Morty_. Users can search for and filter characters using the search bar or filter menu. More detailed information about each character can be viewed by clicking the `Details` button. Each character card also has a star button that allows users to add characters to their favorites. +This project collects and displays data from an external REST API for the popular TV show _Rick and Morty_. To demonstrate the application's functionality and navigation without using an unnecessarily large dataset, only the first page of characters is fetched from the API. Users can search for and filter characters using the search bar or filter menu. More detailed information about each character can be viewed by clicking the `Details` button. Each character card also has a star button that allows users to add characters to their favorites. The API documentation can be found here: @@ -47,6 +47,7 @@ npm test We performed manual testing for responiveness and user experience. This was done in both landscape and portrait orientations on the following devices: - iPhone 16 +- iPhone 17 - iPhone 13 - iPad Air - Macbook Air