import React, { useEffect, useMemo, useState, useCallback } from 'react'; import { Navigate, useNavigate, useLocation } from 'react-router-dom'; import { useTranslation } from 'react-i18next'; import { Button } from '@/components/ui/Button'; import { Input } from '@/components/ui/Input'; import { IconEye, IconEyeOff } from '@/components/ui/icons'; import { useAuthStore, useLanguageStore, useNotificationStore } from '@/stores'; import { detectApiBaseFromLocation, normalizeApiBase } from '@/utils/connection'; export function LoginPage() { const { t } = useTranslation(); const navigate = useNavigate(); const location = useLocation(); const { showNotification } = useNotificationStore(); const language = useLanguageStore((state) => state.language); const toggleLanguage = useLanguageStore((state) => state.toggleLanguage); const isAuthenticated = useAuthStore((state) => state.isAuthenticated); const login = useAuthStore((state) => state.login); const restoreSession = useAuthStore((state) => state.restoreSession); const storedBase = useAuthStore((state) => state.apiBase); const storedKey = useAuthStore((state) => state.managementKey); const storedRememberPassword = useAuthStore((state) => state.rememberPassword); const [apiBase, setApiBase] = useState(''); const [managementKey, setManagementKey] = useState(''); const [showCustomBase, setShowCustomBase] = useState(false); const [showKey, setShowKey] = useState(false); const [rememberPassword, setRememberPassword] = useState(false); const [loading, setLoading] = useState(false); const [autoLoading, setAutoLoading] = useState(true); const [error, setError] = useState(''); const detectedBase = useMemo(() => detectApiBaseFromLocation(), []); const nextLanguageLabel = language === 'zh-CN' ? t('language.english') : t('language.chinese'); useEffect(() => { const init = async () => { try { const autoLoggedIn = await restoreSession(); if (!autoLoggedIn) { setApiBase(storedBase || detectedBase); setManagementKey(storedKey || ''); setRememberPassword(storedRememberPassword || Boolean(storedKey)); } } finally { setAutoLoading(false); } }; init(); }, [detectedBase, restoreSession, storedBase, storedKey, storedRememberPassword]); if (isAuthenticated) { const redirect = (location.state as any)?.from?.pathname || '/'; return ; } const handleSubmit = async () => { if (!managementKey.trim()) { setError(t('login.error_required')); return; } const baseToUse = apiBase ? normalizeApiBase(apiBase) : detectedBase; setLoading(true); setError(''); try { await login({ apiBase: baseToUse, managementKey: managementKey.trim(), rememberPassword }); showNotification(t('common.connected_status'), 'success'); navigate('/', { replace: true }); } catch (err: any) { const message = err?.message || t('login.error_invalid'); setError(message); showNotification(`${t('notification.login_failed')}: ${message}`, 'error'); } finally { setLoading(false); } }; const handleSubmitKeyDown = useCallback((event: React.KeyboardEvent) => { if (event.key === 'Enter' && !loading) { event.preventDefault(); handleSubmit(); } }, [loading, handleSubmit]); return (
{t('title.login')}
{t('login.subtitle')}
{t('login.connection_current')}
{apiBase || detectedBase}
{t('login.connection_auto_hint')}
setShowCustomBase(e.target.checked)} />
{showCustomBase && ( setApiBase(e.target.value)} hint={t('login.custom_connection_hint')} /> )} setManagementKey(e.target.value)} onKeyDown={handleSubmitKeyDown} rightElement={ } />
setRememberPassword(e.target.checked)} />
{error &&
{error}
} {autoLoading && (
{t('auto_login.title')}
{t('auto_login.message')}
)}
); }