further rework to the documentation
This commit is contained in:
158
docs/archive/prp/07-guest-pwa-routes-components.md
Normal file
158
docs/archive/prp/07-guest-pwa-routes-components.md
Normal file
@@ -0,0 +1,158 @@
|
||||
# 07a — Guest PWA Routes & Components
|
||||
|
||||
This scaffold describes recommended routes, guards, directories, and components for the Guest PWA. It is framework-leaning (React Router v6 + Vite), but adaptable.
|
||||
|
||||
Routing Principles
|
||||
- Event routes require an event token (from QR/PIN). Guard redirects to Landing when missing/invalid.
|
||||
- Use route-level code splitting for camera/lightbox/slideshow.
|
||||
- Prefer modal routes (photo detail) layered over the gallery.
|
||||
|
||||
Route Map (proposed)
|
||||
- `/` — Landing (QR/PIN input; deep-link handler)
|
||||
- `/setup` — Profile Setup (name/avatar; skippable)
|
||||
- `/e/:slug` — Home/Feed (default gallery view + info bar)
|
||||
- `/e/:slug/tasks` — Task Picker (random/emotion)
|
||||
- `/e/:slug/tasks/:taskId` — Task Detail (card)
|
||||
- `/e/:slug/upload` — Upload Picker (camera/library + tagging)
|
||||
- `/e/:slug/queue` — Upload Queue (progress/retry)
|
||||
- `/e/:slug/gallery` — Gallery index (alias of Home or dedicated page)
|
||||
- `/e/:slug/photo/:photoId` — Photo Lightbox (modal over gallery)
|
||||
- `/e/:slug/achievements` — Achievements (optional)
|
||||
- `/e/:slug/slideshow` — Slideshow (optional, read-only)
|
||||
- `/legal/:page` — Legal pages (imprint/privacy/terms)
|
||||
- `*` — NotFound
|
||||
|
||||
Note: The settings experience is handled via the header sheet (no dedicated route; legal pages stay routable under /legal/:page).
|
||||
|
||||
Guards & Loaders
|
||||
- `EventGuard` — verifies event token in storage; attempts refresh; otherwise redirects to `/`.
|
||||
- `PrefetchEvent` — loads event metadata/theme on `:slug` routes.
|
||||
- `OfflineFallback` — surfaces offline banner and queues mutations.
|
||||
|
||||
Suggested Directory Structure
|
||||
```
|
||||
apps/guest-pwa/
|
||||
src/
|
||||
routes/
|
||||
index.tsx // router config + guards
|
||||
pages/
|
||||
LandingPage.tsx
|
||||
ProfileSetupPage.tsx
|
||||
HomePage.tsx
|
||||
TaskPickerPage.tsx
|
||||
TaskDetailPage.tsx
|
||||
UploadPage.tsx
|
||||
UploadQueuePage.tsx
|
||||
GalleryPage.tsx
|
||||
PhotoLightbox.tsx // modal route
|
||||
AchievementsPage.tsx
|
||||
SlideshowPage.tsx
|
||||
SettingsSheet.tsx
|
||||
LegalPage.tsx
|
||||
NotFoundPage.tsx
|
||||
components/
|
||||
Header.tsx
|
||||
InfoBar.tsx
|
||||
BottomNav.tsx
|
||||
QRPinForm.tsx
|
||||
CTAButtons.tsx
|
||||
EmotionPickerGrid.tsx
|
||||
TaskCard.tsx
|
||||
CameraPicker.tsx // photos only; no video capture
|
||||
UploadPreviewList.tsx
|
||||
UploadQueueList.tsx
|
||||
GalleryMasonry.tsx
|
||||
PhotoCard.tsx
|
||||
FiltersBar.tsx
|
||||
Toast.tsx
|
||||
stores/
|
||||
useEventStore.ts // tenant/event token, theme
|
||||
useProfileStore.ts // name/avatar (local)
|
||||
useUploadQueue.ts // IndexedDB-backed queue
|
||||
services/
|
||||
apiClient.ts // fetch wrapper + trace id
|
||||
eventsApi.ts // GET event meta
|
||||
photosApi.ts // list/finalize/like
|
||||
uploadService.ts // request signed URL, do PUT, finalize; photo only
|
||||
sw.ts // service worker register helpers
|
||||
hooks/
|
||||
useOnline.ts
|
||||
useA2HS.ts
|
||||
usePollStats.ts // polls /events/:slug/stats every 10s
|
||||
usePollGalleryDelta.ts // polls /events/:slug/photos?since=...
|
||||
i18n/
|
||||
config.ts // i18next init with react-i18next, backend loadPath '/lang/\{\{lng\}\}/guest.json'
|
||||
de.json // Namespace: guest (e.g., { "gallery": { "title": "Galerie" } })
|
||||
en.json
|
||||
main.tsx
|
||||
App.tsx
|
||||
```
|
||||
|
||||
Router Sketch (React Router v6)
|
||||
```tsx
|
||||
import { createBrowserRouter } from 'react-router-dom';
|
||||
import EventGuard from './routes/EventGuard';
|
||||
import PrefetchEvent from './routes/PrefetchEvent';
|
||||
|
||||
export const router = createBrowserRouter([
|
||||
{ path: '/', element: <LandingPage /> },
|
||||
{ path: '/setup', element: <ProfileSetupPage /> },
|
||||
{
|
||||
path: '/e/:slug',
|
||||
element: (
|
||||
<EventGuard>
|
||||
<PrefetchEvent>
|
||||
<HomeLayout />
|
||||
</PrefetchEvent>
|
||||
</EventGuard>
|
||||
),
|
||||
children: [
|
||||
{ index: true, element: <HomePage /> },
|
||||
{ path: 'tasks', element: <TaskPickerPage /> },
|
||||
{ path: 'tasks/:taskId', element: <TaskDetailPage /> },
|
||||
{ path: 'upload', element: <UploadPage /> },
|
||||
{ path: 'queue', element: <UploadQueuePage /> },
|
||||
{ path: 'gallery', element: <GalleryPage /> },
|
||||
{ path: 'photo/:photoId', element: <PhotoLightbox /> },
|
||||
{ path: 'achievements', element: <AchievementsPage /> },
|
||||
{ path: 'slideshow', element: <SlideshowPage /> },
|
||||
],
|
||||
},
|
||||
// Settings sheet is rendered inside Header; no standalone route.
|
||||
{ path: '/legal/:page', element: <LegalPage /> },
|
||||
{ path: '*', element: <NotFoundPage /> },
|
||||
]);
|
||||
```
|
||||
|
||||
Component Checklist
|
||||
- Layout
|
||||
- `Header`, `InfoBar` (X Gäste online • Y Aufgaben gelöst), `BottomNav`, `Toast`.
|
||||
- Entry
|
||||
- `QRPinForm` (QR deep link or PIN fallback), `ProfileForm` (name/avatar).
|
||||
- Home/Feed
|
||||
- `HeroCard` (Willkommensgruess + Eventtitel) und `StatTiles` (online Gaeste, geloeste Aufgaben, letztes Upload).
|
||||
- `CTAButtons` (Aufgabe ziehen, Direkt-Upload, Galerie) + `UploadQueueLink` fuer Warteschlange.
|
||||
- `EmotionPickerGrid` und `GalleryPreview` als inhaltlicher Einstieg.
|
||||
- Tasks
|
||||
- `EmotionPickerGrid`, `TaskCard` (shows duration, group size, actions).
|
||||
- Capture/Upload (photos only)
|
||||
- `CameraPicker`, `UploadPreviewList`, `UploadQueueList`.
|
||||
- Photo View
|
||||
- `PhotoLightbox` (modal), like/share controls, emotion tags.
|
||||
- Settings & Legal
|
||||
- `SettingsSheet` (Header-Overlay mit Namenseditor, eingebetteten Rechtsdokumenten, Cache-Leeren), `LegalPage` Renderer.
|
||||
|
||||
State & Data
|
||||
- TanStack Query for server data (events, photos); optimistic updates for likes.
|
||||
- Zustand store for local-only state (profile, queue, banners).
|
||||
- IndexedDB for upload queue; CacheStorage for shell/assets.
|
||||
- i18n: react-i18next; load 'guest' namespace JSON from /lang/\{locale\}/guest.json; path-based detection for /de/e/:slug, /en/e/:slug; useTranslation('guest') in components.
|
||||
- Polling: focus-aware intervals (10s stats, 30s gallery); use document visibility to pause; backoff on failures.
|
||||
|
||||
Accessibility & Performance
|
||||
- Focus management on modal open/close; trap focus.
|
||||
- Color contrast and minimum tap target sizes (44px).
|
||||
- Code-split camera/lightbox/slideshow; prefetch next gallery page.
|
||||
|
||||
Out of Scope
|
||||
- Video capture/upload is not supported.
|
||||
Reference in New Issue
Block a user