From 2c81ffffaaee816f271b1bfe488e64d0288050fc Mon Sep 17 00:00:00 2001
From: nsfisis <nsfisis@gmail.com>
Date: Sat, 8 Nov 2025 16:09:01 +0900
Subject: fix(frontend): Don't discard GraphQL error

---
 frontend/src/contexts/AuthContext.tsx | 55 +++++++++++++++++++++++++----------
 1 file changed, 40 insertions(+), 15 deletions(-)

(limited to 'frontend/src/contexts/AuthContext.tsx')

diff --git a/frontend/src/contexts/AuthContext.tsx b/frontend/src/contexts/AuthContext.tsx
index fc6b237..e43a1ec 100644
--- a/frontend/src/contexts/AuthContext.tsx
+++ b/frontend/src/contexts/AuthContext.tsx
@@ -8,19 +8,20 @@ import {
 import { useMutation, useQuery } from "urql";
 import {
 	GetCurrentUserDocument,
+	type GetCurrentUserQuery,
 	LoginDocument,
 	LogoutDocument,
 } from "../graphql/generated/graphql";
 
-interface User {
-	id: string;
-	username: string;
-}
+type User = NonNullable<GetCurrentUserQuery["currentUser"]>;
+
+type LoginResult = { success: true } | { success: false; error: string };
 
 interface AuthContextType {
 	user: User | null;
 	isLoading: boolean;
-	login: (username: string, password: string) => Promise<boolean>;
+	error: string | null;
+	login: (username: string, password: string) => Promise<LoginResult>;
 	logout: () => Promise<void>;
 }
 
@@ -29,6 +30,7 @@ const AuthContext = createContext<AuthContextType | undefined>(undefined);
 export function AuthProvider({ children }: { children: ReactNode }) {
 	const [user, setUser] = useState<User | null>(null);
 	const [isLoading, setIsLoading] = useState(true);
+	const [error, setError] = useState<string | null>(null);
 
 	const [, executeLogin] = useMutation(LoginDocument);
 	const [, executeLogout] = useMutation(LogoutDocument);
@@ -40,49 +42,72 @@ export function AuthProvider({ children }: { children: ReactNode }) {
 	useEffect(() => {
 		if (currentUserResult.data?.currentUser) {
 			setUser(currentUserResult.data.currentUser);
+			setError(null);
 		} else {
 			setUser(null);
 		}
+
+		if (currentUserResult.error) {
+			setError(currentUserResult.error.message);
+		}
+
 		if (!currentUserResult.fetching) {
 			setIsLoading(false);
 		}
-	}, [currentUserResult.data, currentUserResult.fetching]);
+	}, [
+		currentUserResult.data,
+		currentUserResult.fetching,
+		currentUserResult.error,
+	]);
 
 	const login = async (
 		username: string,
 		password: string,
-	): Promise<boolean> => {
+	): Promise<LoginResult> => {
+		setError(null);
+
 		try {
 			const result = await executeLogin({ username, password });
 
+			if (result.error) {
+				const errorMessage =
+					result.error.graphQLErrors[0]?.message || result.error.message;
+				setError(errorMessage);
+				return { success: false, error: errorMessage };
+			}
+
 			if (result.data?.login?.user) {
-				setUser(result.data.login.user);
 				// Refetch CurrentUser query to ensure session is established
 				reexecuteCurrentUser({ requestPolicy: "network-only" });
-				return true;
+				return { success: true };
 			}
 
-			return false;
+			const errorMessage = "Invalid username or password";
+			setError(errorMessage);
+			return { success: false, error: errorMessage };
 		} catch (error) {
+			const errorMessage =
+				error instanceof Error ? error.message : "An unknown error occurred";
 			console.error("Login failed:", error);
-			return false;
+			setError(errorMessage);
+			return { success: false, error: errorMessage };
 		}
 	};
 
 	const logout = async () => {
 		try {
 			await executeLogout({});
+			// Refetch CurrentUser query to ensure session is cleared
+			reexecuteCurrentUser({ requestPolicy: "network-only" });
 		} catch (error) {
 			console.error("Logout failed:", error);
-		} finally {
-			setUser(null);
-			// Refetch CurrentUser query to ensure session is cleared
+			// Even on error, refetch to get the latest state
 			reexecuteCurrentUser({ requestPolicy: "network-only" });
 		}
 	};
 
 	return (
-		<AuthContext.Provider value={{ user, isLoading, login, logout }}>
+		<AuthContext.Provider value={{ user, isLoading, error, login, logout }}>
 			{children}
 		</AuthContext.Provider>
 	);
-- 
cgit v1.2.3-70-g09d2

