import React, { useState, useEffect } from 'react' import { useAuth } from '../contexts/AuthContext' import { useLanguage } from '../contexts/LanguageContext' import { t } from '../i18n/translations' import { getSystemConfig } from '../lib/config' import { toast } from 'sonner' import { copyWithToast } from '../lib/clipboard' import { Eye, EyeOff } from 'lucide-react' import { DeepVoidBackground } from './DeepVoidBackground' // import { Input } from './ui/input' // Removed unused import import PasswordChecklist from 'react-password-checklist' import { RegistrationDisabled } from './RegistrationDisabled' import { WhitelistFullPage } from './WhitelistFullPage' export function RegisterPage() { const { language } = useLanguage() const { register, completeRegistration } = useAuth() const [step, setStep] = useState<'register' | 'setup-otp' | 'verify-otp' | 'whitelist-full'>( 'register' ) const [email, setEmail] = useState('') const [password, setPassword] = useState('') const [confirmPassword, setConfirmPassword] = useState('') const [betaCode, setBetaCode] = useState('') const [betaMode, setBetaMode] = useState(false) const [registrationEnabled, setRegistrationEnabled] = useState(true) const [otpCode, setOtpCode] = useState('') const [userID, setUserID] = useState('') const [otpSecret, setOtpSecret] = useState('') const [qrCodeURL, setQrCodeURL] = useState('') const [error, setError] = useState('') const [loading, setLoading] = useState(false) const [passwordValid, setPasswordValid] = useState(false) const [showPassword, setShowPassword] = useState(false) const [showConfirmPassword, setShowConfirmPassword] = useState(false) useEffect(() => { // 获取系统配置,检查是否开启内测模式和注册功能 getSystemConfig() .then((config) => { setBetaMode(config.beta_mode || false) setRegistrationEnabled(config.registration_enabled !== false) }) .catch((err) => { console.error('Failed to fetch system config:', err) }) }, []) // 如果注册功能被禁用,显示注册已关闭页面 if (!registrationEnabled) { return } // 如果白名单已满,显示容量已满页面 if (step === 'whitelist-full') { return setStep('register')} /> } const handleRegister = async (e: React.FormEvent) => { e.preventDefault() setError('') // 使用 PasswordChecklist 的校验结果 if (!passwordValid) { setError(t('passwordNotMeetRequirements', language)) return } if (betaMode && !betaCode.trim()) { setError('内测期间,注册需要提供内测码') return } setLoading(true) try { const result = await register(email, password, betaCode.trim() || undefined) // Helper to check for whitelist errors const isWhitelistError = (msg: string) => { const lowerMsg = msg.toLowerCase() return lowerMsg.includes('whitelist') || lowerMsg.includes('capacity') || lowerMsg.includes('limit') || lowerMsg.includes('permission denied') || lowerMsg.includes('not on whitelist') } if (result.success && result.userID) { setUserID(result.userID) setOtpSecret(result.otpSecret || '') setQrCodeURL(result.qrCodeURL || '') setStep('setup-otp') } else { // Check for whitelist/capacity limit error const msg = result.message || t('registrationFailed', language) if (isWhitelistError(msg)) { setStep('whitelist-full') return } setError(msg) toast.error(msg) } } catch (e) { console.error('Registration error:', e) const errorMsg = e instanceof Error ? e.message : 'Registration failed due to server error' // Check for whitelist error in catch block too const lowerMsg = errorMsg.toLowerCase() if (lowerMsg.includes('whitelist') || lowerMsg.includes('capacity') || lowerMsg.includes('limit') || lowerMsg.includes('permission denied') || lowerMsg.includes('not on whitelist')) { setStep('whitelist-full') return } setError(errorMsg) toast.error(errorMsg) } finally { setLoading(false) } } const handleSetupComplete = () => { setStep('verify-otp') } const handleOTPVerify = async (e: React.FormEvent) => { e.preventDefault() setError('') setLoading(true) const result = await completeRegistration(userID, otpCode) if (!result.success) { const msg = result.message || t('registrationFailed', language) setError(msg) toast.error(msg) } // 成功的话AuthContext会自动处理登录状态 setLoading(false) } const copyToClipboard = (text: string) => { copyWithToast(text) } return (
{/* Navigation - Top Bar (Mobile/Desktop Friendly) */}
{/* Terminal Header */}
NoFx Logo

NEW_USER ONBOARDING

{step === 'register' && 'Initializing Registration Sequence...'} {step === 'setup-otp' && 'Configuring Security Protocols...'} {step === 'verify-otp' && 'Finalizing Authentication...'}

{/* Terminal Output / Form Container */}
{/* Window Bar */}
window.location.href = '/'} title="Close / Return Home" >
setup_account.sh
{/* Status Output */}
System Check: READY
Mode: {betaMode ? 'CLOSED_BETA CA1' : 'PUBLIC'}
{step === 'register' && (
setEmail(e.target.value)} className="w-full bg-black/50 border border-zinc-700 rounded px-4 py-3 text-sm focus:border-nofx-gold focus:ring-1 focus:ring-nofx-gold/50 outline-none transition-all placeholder-zinc-800 text-white font-mono" placeholder="user@nofx.os" required />
setPassword(e.target.value)} className="w-full bg-black/50 border border-zinc-700 rounded px-4 py-3 text-sm focus:border-nofx-gold focus:ring-1 focus:ring-nofx-gold/50 outline-none transition-all placeholder-zinc-800 text-white font-mono pr-10" placeholder="••••••••" required />
setConfirmPassword(e.target.value)} className="w-full bg-black/50 border border-zinc-700 rounded px-4 py-3 text-sm focus:border-nofx-gold focus:ring-1 focus:ring-nofx-gold/50 outline-none transition-all placeholder-zinc-800 text-white font-mono pr-10" placeholder="••••••••" required />
Password Strength Protocol
setPasswordValid(isValid)} iconSize={10} />
{betaMode && (
setBetaCode(e.target.value.replace(/[^a-z0-9]/gi, '').toLowerCase())} className="w-full bg-black/50 border border-zinc-700 rounded px-4 py-3 text-sm focus:border-nofx-gold focus:ring-1 focus:ring-nofx-gold/50 outline-none transition-all placeholder-zinc-800 text-white font-mono tracking-widest" placeholder="XXXXXX" maxLength={6} required={betaMode} />

* CASE SENSITIVE ALPHANUMERIC

)} {error && (
[REGISTRATION_ERROR]: {error}
)}
)} {step === 'setup-otp' && (
SCAN_QR_CODE_SEQUENCE
{qrCodeURL ? (
QR Code
) : (
)}

Backup Secret Key

{otpSecret}
01

Install Authenticator App

We highly recommend Google Authenticator for compatibility.

iOS Android
02

Scan QR Code

Open Google Authenticator, tap the + button, and scan the code above.

Protocol: Time-Based OTP (TOTP)

03

Verify Token

Enter the 6-digit code generated by the app.

⚠️ Stuck? Ensure your phone's time is set to "Automatic". Time drift causes codes to fail.
)} {step === 'verify-otp' && (

ENTER 6-DIGIT SECURITY TOKEN TO FINALIZE ONBOARDING

setOtpCode(e.target.value.replace(/\D/g, '').slice(0, 6)) } className="w-full bg-black border border-zinc-700 rounded px-4 py-4 text-center text-3xl tracking-[0.5em] font-mono text-white focus:border-nofx-gold focus:ring-1 focus:ring-nofx-gold/50 outline-none transition-all placeholder-zinc-800" placeholder="000000" maxLength={6} required autoFocus />
{error && (
[VERIFICATION_FAILED]: {error}
)}
)}
{/* Terminal Footer Info */}
ENCRYPTION: AES-256
SECURE_REGISTRY
{/* Login Link */} {step === 'register' && (

EXISTING_OPERATOR?{' '}

)}
) }