import { useState, useEffect, useRef, useCallback } from "react"; import { Link, Navigate, useNavigate } from "react-router-dom"; import { Eye, EyeOff } from "lucide-react"; import { BrandLogo } from "../../components/brand/BrandLogo"; import { Button } from "../../components/ui/button"; import { Input } from "../../components/ui/input"; import { login, loginWithGoogle } from "../../api/auth.api"; import type { LoginRequest } from "../../types/auth.types"; import type { LoginResult } from "../../api/auth.api"; import { toast } from "sonner"; declare global { interface Window { google?: { accounts: { id: { initialize: (config: { client_id: string; callback: (response: { credential: string }) => void; auto_select?: boolean; }) => void; renderButton: ( element: HTMLElement, config: { theme?: string; size?: string; width?: number; text?: string; shape?: string; logo_alignment?: string; } ) => void; }; }; }; } } function GoogleIcon({ className }: { className?: string }) { return ( ); } export function LoginPage() { const navigate = useNavigate(); const token = localStorage.getItem("access_token"); if (token) { return ; } const [showPassword, setShowPassword] = useState(false); const [email, setEmail] = useState(""); const [password, setPassword] = useState(""); const [loading, setLoading] = useState(false); const [googleLoading, setGoogleLoading] = useState(false); const [error, setError] = useState(null); const [googleReady, setGoogleReady] = useState(false); const [fieldErrors, setFieldErrors] = useState<{ email?: string; password?: string }>({}); const googleBtnRef = useRef(null); const storeTokensAndRedirect = useCallback( (result: LoginResult) => { localStorage.setItem("access_token", result.accessToken); localStorage.setItem("refresh_token", result.refreshToken); localStorage.setItem("role", result.role); localStorage.setItem("member_id", result.memberId.toString()); toast.success("Welcome back!", { description: "You have signed in successfully.", }); navigate("/dashboard"); }, [navigate] ); const handleGoogleCallback = useCallback( async (response: { credential: string }) => { setError(null); setGoogleLoading(true); try { const result = await loginWithGoogle(response.credential); storeTokensAndRedirect(result); } catch (err: any) { setError( err.response?.data?.message || "Google sign-in failed. Please try again." ); } finally { setGoogleLoading(false); } }, [storeTokensAndRedirect] ); // Load Google Identity Services script useEffect(() => { const clientId = import.meta.env.VITE_GOOGLE_CLIENT_ID; if (!clientId) return; // If already loaded if (window.google?.accounts) { setGoogleReady(true); return; } const script = document.createElement("script"); script.src = "https://accounts.google.com/gsi/client"; script.async = true; script.defer = true; script.onload = () => setGoogleReady(true); document.head.appendChild(script); return () => { // Cleanup only if we added it if (document.head.contains(script)) { document.head.removeChild(script); } }; }, []); // Initialize Google button once ready useEffect(() => { const clientId = import.meta.env.VITE_GOOGLE_CLIENT_ID; if (!googleReady || !clientId || !window.google?.accounts) return; window.google.accounts.id.initialize({ client_id: clientId, callback: handleGoogleCallback, }); if (googleBtnRef.current) { // Render the hidden native button (we use our own styled button) window.google.accounts.id.renderButton(googleBtnRef.current, { theme: "outline", size: "large", width: 400, text: "signin_with", shape: "rectangular", }); } }, [googleReady, handleGoogleCallback]); const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); const errors: { email?: string; password?: string } = {}; if (!email.trim()) errors.email = "Please enter your email address"; if (!password) errors.password = "Please enter your password"; if (Object.keys(errors).length > 0) { setFieldErrors(errors); return; } setFieldErrors({}); setError(null); setLoading(true); const payload: LoginRequest = { email, password }; try { const res: LoginResult = await login(payload); storeTokensAndRedirect(res); } catch (err: any) { setError(err.response?.data?.message || "Invalid email or password"); } finally { setLoading(false); } }; const handleGoogleClick = () => { // Click the hidden Google button to trigger the native popup const iframe = googleBtnRef.current?.querySelector("iframe"); const innerBtn = googleBtnRef.current?.querySelector('[role="button"]') as HTMLElement | null; if (innerBtn) { innerBtn.click(); } else if (iframe) { // Fallback: the native button may render as an iframe iframe.click(); } }; const googleClientId = import.meta.env.VITE_GOOGLE_CLIENT_ID; return (
{/* Decorative left panel */}
{/* Abstract decorative shapes */}
{/* Large brand icon */}

Yimaru Academy

Manage your academy, track student progress, and streamline operations — all from one powerful dashboard.

{/* Right panel – login form */}
{/* Mobile-only logo */}
{/* Header */}

Admin Portal

Welcome back

Sign in to your account to continue

{/* Error */} {error && (
{error}
)} {/* Google Sign-In Button */} {googleClientId && ( <> {/* Hidden native Google button */}
); }