ci / api / api (push) Successful in 43s
ci / contract / contract (сгенерированный код совпадает с openapi.yaml) (push) Successful in 1m19s
ci / desktop / rust (desktop proxy) (push) Failing after 3m34s
ci / ts / ts (packages + web) (push) Failing after 2m49s
release / release (версия и заметки) (push) Successful in 5s
ci / db / db (push) Successful in 40s
ci / mobile / mobile (Metro-бандл Android) (push) Successful in 1m12s
ci / docker / docker (образы собираются — их сервер собирает сам при обновлении) (push) Successful in 1m28s
release / android (APK в релиз) (push) Failing after 2m0s
EOF Co-authored-by: Cursor <cursoragent@cursor.com>
56 lines
1.7 KiB
TypeScript
56 lines
1.7 KiB
TypeScript
import { useState, type FormEvent } from 'react';
|
|
import { useTranslation } from 'react-i18next';
|
|
import { useRouter } from '@tanstack/react-router';
|
|
|
|
import { useDesktop } from '../desktop';
|
|
import { Button, Field, FormError } from '../shared/ui/ui';
|
|
import { AuthLayout } from './AuthLayout';
|
|
import s from './auth.module.css';
|
|
|
|
export function ConnectPage() {
|
|
const { t } = useTranslation();
|
|
const desktop = useDesktop();
|
|
const router = useRouter();
|
|
const [address, setAddress] = useState(desktop?.server ?? '');
|
|
const [busy, setBusy] = useState(false);
|
|
const [error, setError] = useState<string | null>(null);
|
|
|
|
const submit = async (e: FormEvent) => {
|
|
e.preventDefault();
|
|
if (!desktop) return;
|
|
setBusy(true);
|
|
setError(null);
|
|
try {
|
|
await desktop.setServer(address);
|
|
await router.invalidate();
|
|
await router.navigate({ to: '/login' });
|
|
} catch (err) {
|
|
const text = err instanceof Error ? err.message : '';
|
|
setError(/Invalid|query|fragment|credentials/i.test(text) ? t('server.invalid_address') : t('server.offline'));
|
|
setBusy(false);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<AuthLayout>
|
|
<h1>{t('server.title')}</h1>
|
|
<p className={s.lead}>{t('app.tagline')}</p>
|
|
<form onSubmit={(e) => void submit(e)} noValidate>
|
|
<Field
|
|
label={t('server.address')}
|
|
value={address}
|
|
onChange={setAddress}
|
|
autoComplete="url"
|
|
autoCapitalize="none"
|
|
spellCheck={false}
|
|
required
|
|
/>
|
|
<FormError>{error}</FormError>
|
|
<Button type="submit" variant="primary" className={s.submit} busy={busy} disabled={!address.trim()}>
|
|
{t('mobile.connect')}
|
|
</Button>
|
|
</form>
|
|
</AuthLayout>
|
|
);
|
|
}
|