diff options
Diffstat (limited to 'src/client/pages/HomePage.tsx')
| -rw-r--r-- | src/client/pages/HomePage.tsx | 117 |
1 files changed, 115 insertions, 2 deletions
diff --git a/src/client/pages/HomePage.tsx b/src/client/pages/HomePage.tsx index 1d65484..c9d0843 100644 --- a/src/client/pages/HomePage.tsx +++ b/src/client/pages/HomePage.tsx @@ -1,8 +1,121 @@ +import { useCallback, useEffect, useState } from "react"; +import { ApiClientError, apiClient } from "../api"; +import { useAuth } from "../stores"; + +interface Deck { + id: string; + name: string; + description: string | null; + newCardsPerDay: number; + createdAt: string; + updatedAt: string; +} + export function HomePage() { + const { logout } = useAuth(); + const [decks, setDecks] = useState<Deck[]>([]); + const [isLoading, setIsLoading] = useState(true); + const [error, setError] = useState<string | null>(null); + + const fetchDecks = useCallback(async () => { + setIsLoading(true); + setError(null); + + try { + const res = await apiClient.rpc.api.decks.$get(undefined, { + headers: apiClient.getAuthHeader(), + }); + + if (!res.ok) { + const errorBody = await res.json().catch(() => ({})); + throw new ApiClientError( + (errorBody as { error?: string }).error || + `Request failed with status ${res.status}`, + res.status, + ); + } + + const data = await res.json(); + setDecks(data.decks); + } catch (err) { + if (err instanceof ApiClientError) { + setError(err.message); + } else { + setError("Failed to load decks. Please try again."); + } + } finally { + setIsLoading(false); + } + }, []); + + useEffect(() => { + fetchDecks(); + }, [fetchDecks]); + return ( <div> - <h1>Kioku</h1> - <p>Spaced repetition learning app</p> + <header + style={{ + display: "flex", + justifyContent: "space-between", + alignItems: "center", + marginBottom: "1rem", + }} + > + <h1>Kioku</h1> + <button type="button" onClick={logout}> + Logout + </button> + </header> + + <main> + <h2>Your Decks</h2> + + {isLoading && <p>Loading decks...</p>} + + {error && ( + <div role="alert" style={{ color: "red" }}> + {error} + <button + type="button" + onClick={fetchDecks} + style={{ marginLeft: "0.5rem" }} + > + Retry + </button> + </div> + )} + + {!isLoading && !error && decks.length === 0 && ( + <div> + <p>You don't have any decks yet.</p> + <p>Create your first deck to start learning!</p> + </div> + )} + + {!isLoading && !error && decks.length > 0 && ( + <ul style={{ listStyle: "none", padding: 0 }}> + {decks.map((deck) => ( + <li + key={deck.id} + style={{ + border: "1px solid #ccc", + padding: "1rem", + marginBottom: "0.5rem", + borderRadius: "4px", + }} + > + <h3 style={{ margin: 0 }}>{deck.name}</h3> + {deck.description && ( + <p style={{ margin: "0.5rem 0 0 0", color: "#666" }}> + {deck.description} + </p> + )} + </li> + ))} + </ul> + )} + </main> </div> ); } |
