'use client'; import Image from 'next/image'; import Link from 'next/link'; import { useSearchParams } from 'next/navigation'; import { useState } from 'react'; import { LanguageSwitcher } from '@/components/LanguageSwitcher'; import { buildFrontendHandoffUrl, configureProviderOnboarding, register, withNext } from '@/lib/auth-client'; import { pickPortalText } from '@/lib/i18n/core'; import { usePortalI18n } from '@/lib/i18n/provider'; import type { TokenResponse } from '@/types/auth'; const PROVIDER_OPTIONS = [ { id: 'openrouter', label: 'OpenRouter', model: 'openrouter/anthropic/claude-sonnet-4.5' }, { id: 'openai', label: 'OpenAI', model: 'openai/gpt-5' }, { id: 'anthropic', label: 'Anthropic', model: 'claude-sonnet-4.5' }, { id: 'dashscope', label: 'DashScope', model: 'qwen-plus' }, { id: 'deepseek', label: 'DeepSeek', model: 'deepseek-chat' }, { id: 'gemini', label: 'Gemini', model: 'gemini/gemini-2.5-pro' }, { id: 'moonshot', label: 'Moonshot', model: 'moonshot/kimi-k2.5' }, { id: 'minimax', label: 'MiniMax', model: 'minimax/minimax-m1' }, { id: 'siliconflow', label: 'SiliconFlow', model: 'Qwen/Qwen3-32B' }, { id: 'volcengine', label: 'VolcEngine', model: 'volcengine/deepseek-v3' }, { id: 'vllm', label: 'vLLM / Local', model: 'hosted_vllm/local-model' }, ]; export default function RegisterPage() { const { locale } = usePortalI18n(); const searchParams = useSearchParams(); const nextPath = searchParams?.get('next') || '/mcp'; const [username, setUsername] = useState(''); const [email, setEmail] = useState(''); const [password, setPassword] = useState(''); const [confirmPassword, setConfirmPassword] = useState(''); const [registrationResponse, setRegistrationResponse] = useState(null); const [provider, setProvider] = useState(PROVIDER_OPTIONS[0].id); const [model, setModel] = useState(PROVIDER_OPTIONS[0].model); const [apiKey, setApiKey] = useState(''); const [apiBase, setApiBase] = useState(''); const [showPassword, setShowPassword] = useState(false); const [showConfirmPassword, setShowConfirmPassword] = useState(false); const [showApiKey, setShowApiKey] = useState(false); const [loading, setLoading] = useState(false); const [onboardingLoading, setOnboardingLoading] = useState(false); const [error, setError] = useState(''); const [onboardingError, setOnboardingError] = useState(''); const handleSubmit = async (event: React.FormEvent) => { event.preventDefault(); setLoading(true); setError(''); try { if (password !== confirmPassword) { throw new Error(pickPortalText(locale, '两次输入的密码不一致', 'Passwords do not match')); } const response = await register(username, email, password); setRegistrationResponse(response); } catch (err) { setError(err instanceof Error ? err.message : pickPortalText(locale, '注册失败,请稍后重试', 'Sign-up failed. Please try again.')); } finally { setLoading(false); } }; const handleProviderChange = (value: string) => { const previousDefault = PROVIDER_OPTIONS.find((item) => item.id === provider)?.model; const selected = PROVIDER_OPTIONS.find((item) => item.id === value); setProvider(value); if (selected && (!model.trim() || model === previousDefault)) { setModel(selected.model); } }; const continueWithoutProvider = () => { if (!registrationResponse) return; window.location.replace(buildFrontendHandoffUrl(registrationResponse, nextPath)); }; const handleProviderSubmit = async (event: React.FormEvent) => { event.preventDefault(); if (!registrationResponse) return; setOnboardingLoading(true); setOnboardingError(''); try { const response = await configureProviderOnboarding({ username, password, provider, model, api_key: apiKey, api_base: apiBase, }); window.location.replace(buildFrontendHandoffUrl(response, nextPath)); } catch (err) { setOnboardingError(err instanceof Error ? err.message : pickPortalText(locale, '模型配置失败,请检查后重试', 'Provider setup failed. Check the values and try again.')); } finally { setOnboardingLoading(false); } }; return (
{registrationResponse ? (
setModel(event.target.value)} placeholder={pickPortalText(locale, '模型', 'Model')} required disabled={onboardingLoading} />
setApiKey(event.target.value)} autoComplete="off" placeholder={provider === 'vllm' ? pickPortalText(locale, 'API Key 可选', 'API key optional') : 'API Key'} required={provider !== 'vllm'} disabled={onboardingLoading} /> setShowApiKey((value) => !value)} label={pickPortalText(locale, showApiKey ? '隐藏 API Key' : '显示 API Key', showApiKey ? 'Hide API key' : 'Show API key')} />
setApiBase(event.target.value)} placeholder="API Base" disabled={onboardingLoading} />
{onboardingError}
) : (
setUsername(event.target.value)} autoComplete="username" placeholder={pickPortalText(locale, '用户名', 'Username')} required />
setEmail(event.target.value)} autoComplete="email" placeholder={pickPortalText(locale, '邮箱', 'Email')} />
setPassword(event.target.value)} autoComplete="new-password" placeholder={pickPortalText(locale, '密码', 'Password')} required /> setShowPassword((value) => !value)} label={pickPortalText(locale, showPassword ? '隐藏密码' : '显示密码', showPassword ? 'Hide password' : 'Show password')} />
setConfirmPassword(event.target.value)} autoComplete="new-password" placeholder={pickPortalText(locale, '确认密码', 'Confirm password')} required /> setShowConfirmPassword((value) => !value)} label={pickPortalText(locale, showConfirmPassword ? '隐藏确认密码' : '显示确认密码', showConfirmPassword ? 'Hide confirm password' : 'Show confirm password')} />
{error}
{pickPortalText(locale, '或', 'or')}
{pickPortalText(locale, '已有账号?', 'Already have an account?')} {pickPortalText(locale, '登录', 'Sign in')}
)}
); } function BrandHeader({ title }: { title: string }) { return ( <> Boardware logo

{title}

); } function VisibilityButton({ active, label, onClick }: { active: boolean; label: string; onClick: () => void }) { return ( ); } function EyeIcon() { return ( ); } function ArrowRightIcon() { return ( ); }