"use client"; import { useState, useEffect } from "react"; import { useRouter } from "next/navigation"; import Link from "next/link"; import { login, webauthnAuthOptions, webauthnAuthVerify } from "@/lib/api"; import { useAuth } from "@/lib/auth"; import { useTranslation } from "@/lib/i18n"; export default function LoginPage() { const [email, setEmail] = useState(""); const [password, setPassword] = useState(""); const [showPassword, setShowPassword] = useState(false); const [loading, setLoading] = useState(false); const [biometricLoading, setBiometricLoading] = useState(false); const [error, setError] = useState(""); const [biometricAvailable, setBiometricAvailable] = useState(false); const [savedEmail, setSavedEmail] = useState(""); const { setAuth } = useAuth(); const { t } = useTranslation(); const router = useRouter(); useEffect(() => { // Check if WebAuthn is available if (typeof window !== "undefined" && window.PublicKeyCredential) { window.PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable?.() .then(available => setBiometricAvailable(available)) .catch(() => {}); } // Load last used email for biometric const last = localStorage.getItem("taskteam_biometric_email"); if (last) setSavedEmail(last); }, []); async function handleSubmit(e: React.FormEvent) { e.preventDefault(); if (!email.trim()) { setError(t("auth.email")); return; } setLoading(true); setError(""); try { const result = await login({ email: email.trim(), password: password || undefined }); setAuth(result.data.token, result.data.user); router.push("/tasks"); } catch (err) { setError(err instanceof Error ? err.message : t("common.error")); } finally { setLoading(false); } } async function handleBiometricLogin() { const biometricEmail = email.trim() || savedEmail; if (!biometricEmail) { setError("Zadejte email pro biometricke prihlaseni"); return; } setBiometricLoading(true); setError(""); try { // Get auth options from server const optionsRes = await webauthnAuthOptions(biometricEmail); const options = optionsRes.data; // Create PublicKey credential request const allowCredentials = (options.allowCredentials as Array<{ id: string; type: string }>).map(cred => ({ id: base64urlToBuffer(cred.id), type: cred.type as PublicKeyCredentialType, })); const credential = await navigator.credentials.get({ publicKey: { challenge: base64urlToBuffer(options.challenge as string), allowCredentials, timeout: 60000, userVerification: "required" as UserVerificationRequirement, }, }) as PublicKeyCredential; if (!credential) throw new Error("Biometricke overeni selhalo"); // Send credential_id to server to get JWT const credentialId = bufferToBase64url(credential.rawId); const result = await webauthnAuthVerify(credentialId); // Save email for next time localStorage.setItem("taskteam_biometric_email", biometricEmail); setAuth(result.data.token, result.data.user); router.push("/tasks"); } catch (err) { const msg = err instanceof Error ? err.message : "Biometricke prihlaseni selhalo"; if (msg.includes("No biometric") || msg.includes("not found")) { setError("Pro tento ucet neni nastaveno biometricke prihlaseni. Nastavte ho v Nastaveni."); } else { setError(msg); } } finally { setBiometricLoading(false); } } return (
Posledni ucet: {savedEmail}
)} > )}{t("auth.noAccount")}{" "} {t("auth.registerBtn")}