XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

XFEServerManager

【Java】我的世界XFE服务器管理器

公开
关注 0 Fork 0 Star 0
UTF-8
import { useState, type FormEvent } from 'react';
import { KeyRound, Languages, LockKeyhole, ShieldCheck } from 'lucide-react';
import { useServer } from '../context/server-context';
import { useI18n } from '../lib/i18n';
import { Button, Field, Input } from '../components/ui';

export function LoginPage() {
  const { t, locale, setLocale } = useI18n();
  const { login, setup, session } = useServer();
  const setupRequired = session?.bootstrapRequired === true;
  const [bootstrapToken, setBootstrapToken] = useState('');
  const [username, setUsername] = useState('');
  const [password, setPassword] = useState('');
  const [passwordConfirmation, setPasswordConfirmation] = useState('');
  const [totp, setTotp] = useState('');
  const [useRecoveryCode, setUseRecoveryCode] = useState(false);
  const [busy, setBusy] = useState(false);
  const [error, setError] = useState<string>();
  const submit = async (event: FormEvent) => {
    event.preventDefault();
    setBusy(true);
    try {
      if (setupRequired) {
        if (password.length < 12) throw new Error(t('auth.passwordHint'));
        if (password !== passwordConfirmation) throw new Error(t('auth.passwordMismatch'));
        await setup(bootstrapToken.trim(), username.trim(), password);
      } else {
        await login(username.trim(), password, totp.trim() || undefined, useRecoveryCode);
      }
      setError(undefined);
    }
    catch (cause) { setError(cause instanceof Error ? cause.message : String(cause)); }
    finally { setBusy(false); }
  };
  return <main className="login-page"><button className="language-button login-language" onClick={() => setLocale(locale === 'zh-CN' ? 'en-US' : 'zh-CN')}><Languages size={16} />{locale === 'zh-CN' ? 'English' : '简体中文'}</button><section className="login-card"><div className="login-brand"><div className="brand__mark"><span /><span /><span /></div><span>{t('app.name')}</span></div><div className="login-icon"><LockKeyhole /></div><h1>{setupRequired ? t('auth.setupTitle') : t('auth.title')}</h1><p>{setupRequired ? t('auth.setupDescription') : t('auth.description')}</p>{setupRequired && <div className="bootstrap-note"><KeyRound />{t('auth.bootstrap')}</div>}<form className="form-stack" onSubmit={submit}>{setupRequired && <Field label={t('auth.bootstrapToken')}><Input autoComplete="off" value={bootstrapToken} onChange={(event) => setBootstrapToken(event.target.value)} required /></Field>}<Field label={t('auth.username')}><Input autoComplete="username" minLength={3} value={username} onChange={(event) => setUsername(event.target.value)} required /></Field><Field label={t('auth.password')} hint={setupRequired ? t('auth.passwordHint') : undefined}><Input type="password" autoComplete={setupRequired ? 'new-password' : 'current-password'} minLength={setupRequired ? 12 : undefined} value={password} onChange={(event) => setPassword(event.target.value)} required /></Field>{setupRequired && <Field label={t('auth.passwordConfirm')}><Input type="password" autoComplete="new-password" minLength={12} value={passwordConfirmation} onChange={(event) => setPasswordConfirmation(event.target.value)} required /></Field>}{!setupRequired && <><Field label={useRecoveryCode ? t('auth.recoveryCode') : t('auth.totp')}><Input inputMode={useRecoveryCode ? 'text' : 'numeric'} autoComplete="one-time-code" pattern={useRecoveryCode ? undefined : '[0-9]{6}'} value={totp} onChange={(event) => setTotp(useRecoveryCode ? event.target.value : event.target.value.replace(/\D/g, '').slice(0, 6))} /></Field><button type="button" className="auth-mode-toggle" onClick={() => { setUseRecoveryCode((current) => !current); setTotp(''); }}>{useRecoveryCode ? t('auth.useTotp') : t('auth.useRecovery')}</button></>}{error && <div className="form-error" role="alert">{error}</div>}<Button type="submit" disabled={busy || !username || !password || (setupRequired && (!bootstrapToken.trim() || !passwordConfirmation))}><ShieldCheck />{setupRequired ? t('auth.createOwner') : t('auth.signIn')}</Button></form></section></main>;
}