Turtor Docs
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

AplikaceAdresářPortÚčel
Adminapps/admin/3000Dashboard pro autentizované uživatele
Webapps/web/3002Veř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 /manage

Web -- 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/terms

Vzor 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)
      Toaster

Auth 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
      CookieConsent

SEO 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

ContextSouborÚčel
ManageRegionProvidercontexts/ManageRegionContext.tsxGlobální filtr regionu pro /manage routes
ConfirmDialogProvidercontexts/ConfirmDialogContext.tsxSdílený potvrzovací dialog (useConfirmDialog)

Důležité poznámky

  • Route tree se generuje automaticky -- spuštěním pnpm dev se vygeneruje routeTree.gen.ts
  • Import alias ~ -- import { X } from '~/lib/...' odkazuje na app/ adresář
  • Auth vynucení -- admin app kontroluje auth v root beforeLoad, ne v komponentách
  • Role-based rendering -- dashboard a nastavení kontrolují activeRole z useAuth()
  • Region filtering -- management routes používají region z ManageRegionContext