import React, { useEffect, useState } from 'react'; import { useAuth } from '../contexts/AuthContext' import { useLanguage } from '../contexts/LanguageContext' import { t } from '../i18n/translations' import HeaderBar from './landing/HeaderBar' import { getSystemConfig } from '../lib/config'; export function LoginPage() { const { language } = useLanguage() const { login, loginAdmin, verifyOTP } = useAuth() const [step, setStep] = useState<'login' | 'otp'>('login') const [email, setEmail] = useState('') const [password, setPassword] = useState('') const [otpCode, setOtpCode] = useState('') const [userID, setUserID] = useState('') const [error, setError] = useState('') const [loading, setLoading] = useState(false) const [adminPassword, setAdminPassword] = useState(''); const [adminMode, setAdminMode] = useState(null); useEffect(() => { getSystemConfig() .then((cfg) => { setAdminMode(!!cfg.admin_mode); }) .catch(() => { setAdminMode(false); }); }, []); const handleAdminLogin = async (e: React.FormEvent) => { e.preventDefault(); setError(''); setLoading(true); const result = await loginAdmin(adminPassword); if (!result.success) { setError(result.message || t('loginFailed', language)); } setLoading(false); }; const handleLogin = async (e: React.FormEvent) => { e.preventDefault() setError('') setLoading(true) const result = await login(email, password) if (result.success) { if (result.requiresOTP && result.userID) { setUserID(result.userID) setStep('otp') } } else { setError(result.message || t('loginFailed', language)) } setLoading(false) } const handleOTPVerify = async (e: React.FormEvent) => { e.preventDefault() setError('') setLoading(true) const result = await verifyOTP(userID, otpCode) if (!result.success) { setError(result.message || t('verificationFailed', language)) } // 成功的话AuthContext会自动处理登录状态 setLoading(false) } return (
{}} isLoggedIn={false} isHomePage={false} currentPage="login" language={language} onLanguageChange={() => {}} onPageChange={(page) => { console.log('LoginPage onPageChange called with:', page) if (page === 'competition') { window.location.href = '/competition' } }} />
{/* Logo */}
NoFx Logo

登录 NOFX

{step === 'login' ? '请输入您的邮箱和密码' : '请输入两步验证码'}

{/* Login Form */}
{adminMode ? (
setAdminPassword(e.target.value)} className="w-full px-3 py-2 rounded" style={{ background: 'var(--brand-black)', border: '1px solid var(--panel-border)', color: 'var(--brand-light-gray)' }} placeholder="请输入管理员密码" required />
{error && (
{error}
)}
) : step === 'login' ? (
setEmail(e.target.value)} className="w-full px-3 py-2 rounded" style={{ background: 'var(--brand-black)', border: '1px solid var(--panel-border)', color: 'var(--brand-light-gray)', }} placeholder={t('emailPlaceholder', language)} required />
setPassword(e.target.value)} className="w-full px-3 py-2 rounded" style={{ background: 'var(--brand-black)', border: '1px solid var(--panel-border)', color: 'var(--brand-light-gray)', }} placeholder={t('passwordPlaceholder', language)} required />
{error && (
{error}
)}
) : (
📱

{t('scanQRCodeInstructions', language)}
{t('enterOTPCode', language)}

setOtpCode(e.target.value.replace(/\D/g, '').slice(0, 6)) } className="w-full px-3 py-2 rounded text-center text-2xl font-mono" style={{ background: 'var(--brand-black)', border: '1px solid var(--panel-border)', color: 'var(--brand-light-gray)', }} placeholder={t('otpPlaceholder', language)} maxLength={6} required />
{error && (
{error}
)}
)}
{/* Register Link */} {!adminMode && (

还没有账户?{' '}

)}
) }