'use client'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Card, CardContent, CardHeader, CardTitle, CardDescription, } from '@/components/ui/card'; import { LanguageSelector } from '@/components/ui/language-selector'; import { useForm } from 'react-hook-form'; import { zodResolver } from '@hookform/resolvers/zod'; import * as z from 'zod'; import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage, } from '@/components/ui/form'; import { useEffect, useState } from 'react'; import { httpClient, initializeUserInfo } from '@/app/infra/http'; import { useRouter } from 'next/navigation'; import { Mail, Lock, Loader2 } from 'lucide-react'; import langbotIcon from '@/app/assets/langbot-logo.webp'; import { toast } from 'sonner'; import { useTranslation } from 'react-i18next'; import Link from 'next/link'; import { ThemeToggle } from '@/components/ui/theme-toggle'; import { LoadingSpinner } from '@/components/ui/loading-spinner'; const formSchema = (t: (key: string) => string) => z.object({ email: z.string().email(t('common.invalidEmail')), password: z.string().min(1, t('common.emptyPassword')), }); type AccountType = 'local' | 'space'; export default function Login() { const router = useRouter(); const { t } = useTranslation(); const [spaceLoading, setSpaceLoading] = useState(false); const [accountType, setAccountType] = useState(null); const [hasPassword, setHasPassword] = useState(false); const [loading, setLoading] = useState(true); const form = useForm>>({ resolver: zodResolver(formSchema(t)), defaultValues: { email: '', password: '', }, }); useEffect(() => { checkAccountInfo(); }, []); async function checkAccountInfo() { try { const res = await httpClient.getAccountInfo(); if (!res.initialized) { router.push('/register'); return; } setAccountType(res.account_type || 'local'); setHasPassword(res.has_password || false); setLoading(false); // Also check if already logged in checkIfAlreadyLoggedIn(); } catch { setLoading(false); } } function checkIfAlreadyLoggedIn() { httpClient .checkUserToken() .then((res) => { if (res.token) { localStorage.setItem('token', res.token); router.push('/home'); } }) .catch(() => {}); } function onSubmit(values: z.infer>) { handleLogin(values.email, values.password); } function handleLogin(username: string, password: string) { httpClient .authUser(username, password) .then(async (res) => { localStorage.setItem('token', res.token); localStorage.setItem('userEmail', username); await initializeUserInfo(); router.push('/home'); toast.success(t('common.loginSuccess')); }) .catch(() => { toast.error(t('common.loginFailed')); }); } const handleSpaceLoginClick = async () => { setSpaceLoading(true); try { const currentOrigin = window.location.origin; const redirectUri = `${currentOrigin}/auth/space/callback`; const response = await httpClient.getSpaceAuthorizeUrl(redirectUri); window.location.href = response.authorize_url; } catch { toast.error(t('common.spaceLoginFailed')); setSpaceLoading(false); } }; if (loading) { return (
); } // Determine what to show based on account type const showLocalLogin = accountType === 'local' || (accountType === 'space' && hasPassword); const showSpaceLogin = accountType === 'space'; return (
LangBot {t('common.welcome')} {t('common.continueToLogin')}
{/* Space Login - only show for space accounts */} {showSpaceLogin && (
)} {/* Divider - only show if both login methods are available */} {showSpaceLogin && showLocalLogin && (
{t('common.or')}
)} {/* Local Account Login - show for local accounts or space accounts with password */} {showLocalLogin && (
( {t('common.email')}
)} /> (
{t('common.password')} {t('common.forgotPassword')}
)} /> )}

{t('common.agreementNotice')}{' '} {t('common.privacyPolicy')} {' '} {t('common.and')}{' '} {t('common.dataCollectionPolicy')}

); }