From 3cfa0f5c029113a2ada8e8663767a654150ba8c3 Mon Sep 17 00:00:00 2001
From: nsfisis <nsfisis@gmail.com>
Date: Sun, 7 Dec 2025 23:47:35 +0900
Subject: chore: fix all lint errors and warnings
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

- Remove unused imports in repositories.ts and sync.test.ts
- Replace non-null assertions with type casts in HomePage.test.tsx
- Use semantic <output> element instead of div with role="status"
- Use semantic <button> element instead of div with role="button"
- Remove useless React fragment in StudyPage.tsx
- Fix useCallback dependencies for handleFlip and handleRating

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
---
 src/client/pages/StudyPage.tsx | 135 +++++++++++++++++++++--------------------
 1 file changed, 68 insertions(+), 67 deletions(-)

(limited to 'src/client/pages/StudyPage.tsx')

diff --git a/src/client/pages/StudyPage.tsx b/src/client/pages/StudyPage.tsx
index c6f8665..03cb537 100644
--- a/src/client/pages/StudyPage.tsx
+++ b/src/client/pages/StudyPage.tsx
@@ -119,62 +119,69 @@ export function StudyPage() {
 		fetchData();
 	}, [fetchData]);
 
+	// biome-ignore lint/correctness/useExhaustiveDependencies: Reset timer when card changes
 	useEffect(() => {
 		cardStartTimeRef.current = Date.now();
 	}, [currentIndex]);
 
-	const handleFlip = () => {
+	const handleFlip = useCallback(() => {
 		setIsFlipped(true);
-	};
+	}, []);
 
-	const handleRating = async (rating: Rating) => {
-		if (!deckId || isSubmitting) return;
+	const handleRating = useCallback(
+		async (rating: Rating) => {
+			if (!deckId || isSubmitting) return;
 
-		const currentCard = cards[currentIndex];
-		if (!currentCard) return;
+			const currentCard = cards[currentIndex];
+			if (!currentCard) return;
 
-		setIsSubmitting(true);
-		setError(null);
+			setIsSubmitting(true);
+			setError(null);
 
-		const durationMs = Date.now() - cardStartTimeRef.current;
+			const durationMs = Date.now() - cardStartTimeRef.current;
 
-		try {
-			const authHeader = apiClient.getAuthHeader();
-			if (!authHeader) {
-				throw new ApiClientError("Not authenticated", 401);
-			}
+			try {
+				const authHeader = apiClient.getAuthHeader();
+				if (!authHeader) {
+					throw new ApiClientError("Not authenticated", 401);
+				}
 
-			const res = await fetch(`/api/decks/${deckId}/study/${currentCard.id}`, {
-				method: "POST",
-				headers: {
-					...authHeader,
-					"Content-Type": "application/json",
-				},
-				body: JSON.stringify({ rating, durationMs }),
-			});
-
-			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 res = await fetch(
+					`/api/decks/${deckId}/study/${currentCard.id}`,
+					{
+						method: "POST",
+						headers: {
+							...authHeader,
+							"Content-Type": "application/json",
+						},
+						body: JSON.stringify({ rating, durationMs }),
+					},
 				);
-			}
 
-			setCompletedCount((prev) => prev + 1);
-			setIsFlipped(false);
-			setCurrentIndex((prev) => prev + 1);
-		} catch (err) {
-			if (err instanceof ApiClientError) {
-				setError(err.message);
-			} else {
-				setError("Failed to submit review. Please try again.");
+				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,
+					);
+				}
+
+				setCompletedCount((prev) => prev + 1);
+				setIsFlipped(false);
+				setCurrentIndex((prev) => prev + 1);
+			} catch (err) {
+				if (err instanceof ApiClientError) {
+					setError(err.message);
+				} else {
+					setError("Failed to submit review. Please try again.");
+				}
+			} finally {
+				setIsSubmitting(false);
 			}
-		} finally {
-			setIsSubmitting(false);
-		}
-	};
+		},
+		[deckId, isSubmitting, cards, currentIndex],
+	);
 
 	const handleKeyDown = useCallback(
 		(e: KeyboardEvent) => {
@@ -200,7 +207,7 @@ export function StudyPage() {
 				}
 			}
 		},
-		[isFlipped, isSubmitting],
+		[isFlipped, isSubmitting, handleFlip, handleRating],
 	);
 
 	useEffect(() => {
@@ -328,21 +335,16 @@ export function StudyPage() {
 
 					{currentCard && !isSessionComplete && (
 						<div data-testid="study-card">
-							<div
+							<button
+								type="button"
 								data-testid="card-container"
 								onClick={!isFlipped ? handleFlip : undefined}
-								onKeyDown={(e) => {
-									if (!isFlipped && (e.key === " " || e.key === "Enter")) {
-										e.preventDefault();
-										handleFlip();
-									}
-								}}
-								role="button"
-								tabIndex={0}
 								aria-label={
 									isFlipped ? "Card showing answer" : "Click to reveal answer"
 								}
+								disabled={isFlipped}
 								style={{
+									width: "100%",
 									border: "1px solid #ccc",
 									borderRadius: "8px",
 									padding: "2rem",
@@ -354,6 +356,7 @@ export function StudyPage() {
 									cursor: isFlipped ? "default" : "pointer",
 									backgroundColor: isFlipped ? "#f8f9fa" : "white",
 									transition: "background-color 0.2s",
+									font: "inherit",
 								}}
 							>
 								{!isFlipped ? (
@@ -381,22 +384,20 @@ export function StudyPage() {
 										</p>
 									</>
 								) : (
-									<>
-										<p
-											data-testid="card-back"
-											style={{
-												fontSize: "1.25rem",
-												textAlign: "center",
-												margin: 0,
-												whiteSpace: "pre-wrap",
-												wordBreak: "break-word",
-											}}
-										>
-											{currentCard.back}
-										</p>
-									</>
+									<p
+										data-testid="card-back"
+										style={{
+											fontSize: "1.25rem",
+											textAlign: "center",
+											margin: 0,
+											whiteSpace: "pre-wrap",
+											wordBreak: "break-word",
+										}}
+									>
+										{currentCard.back}
+									</p>
 								)}
-							</div>
+							</button>
 
 							{isFlipped && (
 								<div
-- 
cgit v1.2.3-70-g09d2

