Files
glchat/web/src/App.tsx
T
grendervill 61a84bfeae feat(invites): приглашения, каталог публичных серверов и публичность сервера
- POST /guilds/{id}/invites (CREATE_INVITES): код из 10 символов, лимит
  использований и срок жизни; GET /guilds/{id}/invites (MANAGE_GUILD);
  DELETE /invites/{code} — создатель или MANAGE_GUILD;
- GET /invites/{code} — предпросмотр с карточкой сервера, 410 для истёкших и
  исчерпанных; POST /invites/{code} — принятие с проверкой лимита участников,
  повторное принятие не расходует использование;
- PATCH /guilds/{id} принимает `public`: сервер попадает в каталог и открыт для
  входа без приглашения (главный сервер публиковать нельзя);
- GET /guilds/public — каталог (имя, описание, иконка, число участников);
- аудит invite.create/invite.revoke/invite.accept, события INVITE_CREATE и
  INVITE_DELETE владельцу сессии;
- тесты: полный жизненный цикл приглашения, исчерпание, отзыв, права,
  публичный каталог и вход в публичный сервер.
2026-09-19 23:33:34 +03:00

27 lines
745 B
TypeScript

import { Suspense } from 'react';
import { RouterProvider } from 'react-router';
import { Card } from '@/components/ui/primitives';
import { SkeletonLines } from '@/components/ui/Skeleton';
import { router } from '@/router';
import '@/i18n';
/** Заглушка на время загрузки ленивых страниц: скелетон вместо пустоты. */
export function RouteFallback() {
return (
<div className="flex min-h-full items-center justify-center p-6">
<Card className="w-full max-w-md">
<SkeletonLines rows={4} />
</Card>
</div>
);
}
export function App() {
return (
<Suspense fallback={<RouteFallback />}>
<RouterProvider router={router} />
</Suspense>
);
}