Frontend
Routování
TanStack Router file-based routing v admin a web aplikaci
Obě frontend aplikace používají TanStack Router s file-based routingem. Routy jsou definovány jako soubory v adresáři app/routes/ a router automaticky generuje route tree.
Dvě aplikace
| Aplikace | Adresář | Port | Účel |
|---|---|---|---|
| Admin | apps/admin/ | 3000 | Dashboard pro autentizované uživatele |
| Web | apps/web/ | 3002 | Veřejný web, výpis kurzů, checkout |
Admin -- struktura routes
apps/admin/app/routes/
├── __root.tsx # Root layout (auth check, sidebar, providery)
├── index.tsx # Dashboard redirect
├── dashboard.tsx # Hlavní dashboard
├── profile.tsx # Nastavení profilu
├── notifications.tsx # Seznam notifikací
├── auth/
│ ├── login.tsx # /auth/login
│ └── callback.tsx # /auth/callback (OAuth)
├── instructor/
│ ├── dashboard.tsx # /instructor/dashboard
│ ├── courses.tsx # /instructor/courses
│ ├── courses.$id.tsx # /instructor/courses/:id
│ ├── availability.tsx # /instructor/availability
│ └── earnings.tsx # /instructor/earnings
├── manage/ # Správa (admin/garant)
│ ├── dashboard.tsx # /manage/dashboard
│ ├── courses.tsx # /manage/courses
│ ├── courses.$id.tsx # /manage/courses/:id
│ ├── instructors.tsx # /manage/instructors
│ ├── instructors.$id.tsx # /manage/instructors/:id
│ ├── companies.tsx # /manage/companies
│ ├── companies.$id.tsx # /manage/companies/:id
│ ├── withdrawals.tsx # /manage/withdrawals
│ ├── calendar.tsx # /manage/calendar
│ ├── settings.tsx # /manage/settings
│ └── planning/ # Plánování kurzů
│ ├── kanban.tsx # /manage/planning/kanban
│ ├── generation-logs.tsx
│ ├── replacements.tsx
│ └── coverage.tsx # H3 mapa pokrytí
├── sales/
│ ├── dashboard.tsx # /sales/dashboard
│ ├── leads.tsx # /sales/leads
│ ├── leads.$id.tsx # /sales/leads/:id
│ └── pipeline.tsx # /sales/pipeline
├── admin/
│ └── index.tsx # Redirect na /manage
└── garant/
└── index.tsx # Redirect na /manageWeb -- struktura routes
apps/web/app/routes/
├── __root.tsx # Root layout (Header, Footer, SEO)
├── index.tsx # Domovská stránka
├── about.tsx # O nás
├── courses.tsx # Seznam kurzů
├── course.$courseId.tsx # Detail kurzu
├── checkout.$courseId.tsx # Checkout flow
├── checkout.success.tsx # Úspěšná objednávka
├── auth/
│ ├── login.tsx # /auth/login
│ ├── register.tsx # /auth/register
│ └── callback.tsx # /auth/callback
├── profile/
│ ├── bookings.tsx # /profile/bookings
│ └── settings.tsx # /profile/settings
└── legal/
├── privacy.tsx # /legal/privacy
└── terms.tsx # /legal/termsVzor route komponenty
import { createFileRoute } from '@tanstack/react-router';
import { PageShell } from '~/components/layout';
export const Route = createFileRoute('/manage/courses')({
component: CoursesPage,
});
function CoursesPage() {
const { data, isLoading } = useCourseList();
if (isLoading) return <PageSkeleton variant="list" />;
return (
<PageShell title="Kurzy" actions={<Button>Nový kurz</Button>}>
{/* obsah stránky */}
</PageShell>
);
}PageShell -- layout wrapper
Všechny admin stránky by měly používat PageShell pro konzistentní layout:
import { PageShell } from '~/components/layout';
<PageShell
title="Název stránky"
description="Volitelný podnázev"
actions={<Button>Akce</Button>}
fullWidth={false} // Výchozí max-w-7xl (1280px)
fullHeight={false} // Pro kanban/split-view layouty
>
{/* obsah */}
</PageShell>Root layout -- Admin
Admin root layout vynucuje autentizaci a poskytuje provider stack:
ThemeProvider
AuthProvider
ConfirmDialogProvider
ManageRegionProvider
SidebarProvider
AppSidebar
SidebarInset
header (SidebarTrigger + CommandPalette + RegionSelector + NotificationBell + UserMenu)
main (Outlet)
ToasterAuth routes (/auth/*) se vykreslují bez sidebaru.
Root layout -- Web
Veřejný web má jednodušší strukturu bez požadavku na autentizaci:
ThemeProvider
AuthProvider
ErrorBoundary
SEOHead (dynamické meta tagy z route staticData)
Header
main (Outlet)
Footer
Toaster
CookieConsentSEO podpora
Web routes mohou definovat staticData.meta pro SEO tagy:
export const Route = createFileRoute('/courses')({
staticData: {
meta: {
title: 'Kurzy první pomoci',
description: 'Najděte a zarezervujte kurz první pomoci',
keywords: ['první pomoc', 'kurzy', 'školení'],
},
},
component: CoursesPage,
});Validace search parametrů
TanStack Router vyžaduje validateSearch pro typově bezpečné search parametry:
export const Route = createFileRoute('/manage/planning/kanban')({
validateSearch: (search) => ({
course: search.course as string | undefined,
}),
component: KanbanPage,
});
// V komponentě
const { course } = Route.useSearch();
// Navigace s parametry
navigate({ search: { course: courseId } });Kontextové providery
| Context | Soubor | Účel |
|---|---|---|
ManageRegionProvider | contexts/ManageRegionContext.tsx | Globální filtr regionu pro /manage routes |
ConfirmDialogProvider | contexts/ConfirmDialogContext.tsx | Sdílený potvrzovací dialog (useConfirmDialog) |
Důležité poznámky
- Route tree se generuje automaticky -- spuštěním
pnpm devse vygenerujerouteTree.gen.ts - Import alias
~--import { X } from '~/lib/...'odkazuje naapp/adresář - Auth vynucení -- admin app kontroluje auth v root
beforeLoad, ne v komponentách - Role-based rendering -- dashboard a nastavení kontrolují
activeRolezuseAuth() - Region filtering -- management routes používají region z
ManageRegionContext