diff --git a/src/App.tsx b/src/App.tsx
index 4d00613..71b5d0f 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -3,10 +3,12 @@ import { useQuery } from "@tanstack/react-query";
import { getPokemonByID } from "./api/pokemon";
import { PokemonCard } from "./components/PokemonCard/PokemonCard";
import { Favorite } from "./components/Favorite/Favorite";
+import { useFavorites } from "./controllers/useFavorites";
export default function App() {
// Start at a default ID
const [pokemonId, setPokemonId] = useState(1);
+ const { isFavorite, toggleFavorite } = useFavorites();
const query = useQuery({
queryKey: ["pokemon", pokemonId],
@@ -58,7 +60,10 @@ export default function App() {
{query.isPending &&
Loading...
}
{query.isError && Failed to load Pokemon
}
{query.data && }
-
+ toggleFavorite(pokemonId)}
+ />
);
}
diff --git a/src/components/Favorite/Favorite.test.tsx b/src/components/Favorite/Favorite.test.tsx
new file mode 100644
index 0000000..ce3e580
--- /dev/null
+++ b/src/components/Favorite/Favorite.test.tsx
@@ -0,0 +1,39 @@
+import { describe, expect, test, vi } from "vitest";
+import { fireEvent, render, screen } from "@testing-library/react";
+import { Favorite } from "./Favorite";
+
+describe("Favorite Component", () => {
+ test("shows empty heart when not favorite", () => {
+ render( {}} />);
+
+ const button = screen.getByRole("button", { name: "Add to favorites" });
+ expect(button.textContent).toBe("🤍");
+ expect(button.getAttribute("aria-pressed")).toBe("false");
+ });
+
+ test("shows filled heart when favorite", () => {
+ render( {}} />);
+
+ const button = screen.getByRole("button", {
+ name: "Remove from favorites",
+ });
+ expect(button.textContent).toBe("❤️");
+ expect(button.getAttribute("aria-pressed")).toBe("true");
+ });
+
+ test("calls onToggle when clicked", () => {
+ const handleToggle = vi.fn();
+ render();
+
+ fireEvent.click(screen.getByRole("button"));
+
+ expect(handleToggle).toHaveBeenCalledTimes(1);
+ });
+
+ test("matches snapshot", () => {
+ const { asFragment } = render(
+ {}} />,
+ );
+ expect(asFragment()).toMatchSnapshot();
+ });
+});
diff --git a/src/components/Favorite/Favorite.tsx b/src/components/Favorite/Favorite.tsx
index 408588e..11c4f3a 100644
--- a/src/components/Favorite/Favorite.tsx
+++ b/src/components/Favorite/Favorite.tsx
@@ -1,42 +1,15 @@
-import { useState } from "react";
import "./Favorite.css";
type FavoriteProps = {
- pokemonId: number;
+ isFavorite: boolean;
+ onToggle: () => void;
};
-export function Favorite({ pokemonId }: FavoriteProps) {
- // 1. Lazy initialization from localStorage
- const [favorites, setFavorites] = useState(() => {
- try {
- const storedFavorites = window.localStorage.getItem("favorites");
- return storedFavorites ? JSON.parse(storedFavorites) : [];
- } catch (error) {
- console.error("Error reading localStorage", error);
- return [];
- }
- });
-
- const isFavorite = favorites.includes(pokemonId);
-
- // 2. The click handler syncing State and Storage
- const toggleFavorite = () => {
- let updatedFavorites: number[];
-
- if (isFavorite) {
- updatedFavorites = favorites.filter((id) => id !== pokemonId);
- } else {
- updatedFavorites = [...favorites, pokemonId];
- }
-
- setFavorites(updatedFavorites);
- window.localStorage.setItem("favorites", JSON.stringify(updatedFavorites));
- };
-
- // 3. Accessible UI rendering
+export function Favorite({ isFavorite, onToggle }: FavoriteProps) {
return (