feat(invites): страница приглашения со splash и переопределением
- миграция 00015: переопределение splash у приглашения (AGENT.md 7.9)
- GET /invites/{code} доступен без сессии: гость по ссылке видит карточку
сервера, описание, число участников и пригласившего
- POST/DELETE /invites/{code}/background: своя картинка страницы под правом
создателя или MANAGE_GUILD, файл удаляется при замене и снятии
- клиент: маршрут /invite/:code с фоном (переопределение → splash → баннер),
карточкой сервера, кнопками «Присоединиться»/«Открыть сервер» и входом с
возвратом на страницу (?next=)
- тесты: Go (карточка, загрузка, права, снятие) и Vitest (splash, гость,
присоединение, недействительная ссылка)
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import { useState, type FormEvent } from 'react';
|
||||
import { useMutation } from '@tanstack/react-query';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Link, useLocation, useNavigate } from 'react-router';
|
||||
import { Link, useLocation, useNavigate, useSearchParams } from 'react-router';
|
||||
|
||||
import { login } from '@/api/auth';
|
||||
import { ErrorNotice } from '@/components/ui/ErrorNotice';
|
||||
@@ -30,8 +30,13 @@ export default function LoginPage() {
|
||||
const [password, setPassword] = useState('');
|
||||
const [totpCode, setTotpCode] = useState('');
|
||||
const [needsTotp, setNeedsTotp] = useState(false);
|
||||
const [searchParams] = useSearchParams();
|
||||
|
||||
const from = (location.state as LocationState | null)?.from ?? '/app';
|
||||
// Возврат после входа: `?next=` (страница приглашения) важнее состояния
|
||||
// перехода из AuthGuard, но только для внутренних путей.
|
||||
const next = searchParams.get('next');
|
||||
const stateFrom = (location.state as LocationState | null)?.from ?? null;
|
||||
const from = next !== null && next.startsWith('/') ? next : (stateFrom ?? '/app');
|
||||
|
||||
const submit = useMutation({
|
||||
mutationFn: () => {
|
||||
|
||||
Reference in New Issue
Block a user