Files
pipu-music/apps/web/src/App.tsx
T
mrleo1nidandClaude Opus 5.5 ab092def54
ci / contract / contract (сгенерированный код совпадает с openapi.yaml) (push) Successful in 50s
ci / ts / ts (packages + web) (push) Successful in 43s
ci / docker / docker (образы собираются — их сервер собирает сам при обновлении) (push) Successful in 27s
ci / mobile / mobile (Metro-бандл Android) (push) Successful in 1m22s
feat(web): sign-in, first-run setup, app shell and user admin (M1)
- core: AuthSession keeps the access token in memory, refreshes it
  once for all parallel requests (single-flight) and retries them;
  refresh races between tabs are retried, reuse signs out; ApiError
  carries problem+json codes and field errors
- web: TanStack Router with guards — guests go to /login, the bootstrap
  admin to /setup/admin, temporary passwords to /setup/password, admin
  pages by role
- login, setup screens, Classic shell (top bar, role-based sidebar,
  empty player), settings: name, theme, language, password, devices
- users admin: search, role filter, create with a one-time temporary
  password, reset, block, role change, delete as the policy allows;
  audit log for admins
- ru/en strings for auth, admin and error codes; language and theme
  are saved in the profile

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 06:33:46 +03:00

31 lines
894 B
TypeScript

import type { AuthSession } from '@pipu/core';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { RouterProvider } from '@tanstack/react-router';
import { useState } from 'react';
import type { createAppRouter } from './app/router';
import { SessionProvider } from './app/session';
export function createQueryClient() {
return new QueryClient({ defaultOptions: { queries: { retry: 1, refetchOnWindowFocus: false } } });
}
export function App({
session,
router,
queryClient,
}: {
session: AuthSession;
router: ReturnType<typeof createAppRouter>;
queryClient?: QueryClient;
}) {
const [client] = useState(() => queryClient ?? createQueryClient());
return (
<SessionProvider session={session}>
<QueryClientProvider client={client}>
<RouterProvider router={router} />
</QueryClientProvider>
</SessionProvider>
);
}