|
@@ -8,7 +8,7 @@
|
|
|
|
|
|
|
|
<!-- --------------------------------------------------------------------------- -->
|
|
<!-- --------------------------------------------------------------------------- -->
|
|
|
|
|
|
|
|
-# Frontend UI: App Shell, Routing, Auth/RBAC, and Explorer (RHL-019 / RHL-020 / RHL-021 / RHL-022)
|
|
|
|
|
|
|
+# Frontend UI: App Shell, Routing, Auth/RBAC, and Explorer (RHL-019 / RHL-020 / RHL-021 / RHL-022 / RHL-023)
|
|
|
|
|
|
|
|
This document describes the **frontend routing scaffold**, the **application shell layout**, and the **core navigation UI (Explorer)** for the RHL Lieferscheine app.
|
|
This document describes the **frontend routing scaffold**, the **application shell layout**, and the **core navigation UI (Explorer)** for the RHL Lieferscheine app.
|
|
|
|
|
|
|
@@ -18,6 +18,7 @@ Timeline:
|
|
|
- **RHL-020**: Real login flow + session handling and redirects.
|
|
- **RHL-020**: Real login flow + session handling and redirects.
|
|
|
- **RHL-021**: UI-side RBAC guard + consistent Forbidden / NotFound UX.
|
|
- **RHL-021**: UI-side RBAC guard + consistent Forbidden / NotFound UX.
|
|
|
- **RHL-022**: Explorer v2 (Year → Month → Day → Files) + shadcn Breadcrumbs with dropdowns.
|
|
- **RHL-022**: Explorer v2 (Year → Month → Day → Files) + shadcn Breadcrumbs with dropdowns.
|
|
|
|
|
+- **RHL-023**: Explorer file action “Open PDF” using the binary PDF endpoint (opens in a new tab).
|
|
|
|
|
|
|
|
> **Language policy**
|
|
> **Language policy**
|
|
|
>
|
|
>
|
|
@@ -29,7 +30,7 @@ Timeline:
|
|
|
|
|
|
|
|
## 1. Scope
|
|
## 1. Scope
|
|
|
|
|
|
|
|
-### 1.1 Implemented (as of RHL-022)
|
|
|
|
|
|
|
+### 1.1 Implemented (as of RHL-023)
|
|
|
|
|
|
|
|
- **Public** `/login` route with a functional login form (shadcn/ui primitives).
|
|
- **Public** `/login` route with a functional login form (shadcn/ui primitives).
|
|
|
|
|
|
|
@@ -86,14 +87,34 @@ Timeline:
|
|
|
- Error states with retry
|
|
- Error states with retry
|
|
|
- FS_NOT_FOUND mapped to an Explorer “path no longer exists” card
|
|
- FS_NOT_FOUND mapped to an Explorer “path no longer exists” card
|
|
|
|
|
|
|
|
|
|
+- **Explorer leaf action: Open PDF (RHL-023)**
|
|
|
|
|
+
|
|
|
|
|
+ - The file list on `/:branch/:year/:month/:day` provides an **“Öffnen”** action.
|
|
|
|
|
+
|
|
|
|
|
+ - Clicking “Öffnen” opens the selected PDF **in a new browser tab**.
|
|
|
|
|
+
|
|
|
|
|
+ - URL construction is centralized in a pure helper:
|
|
|
|
|
+
|
|
|
|
|
+ - `lib/frontend/explorer/pdfUrl.js` (`buildPdfUrl`, optional `buildPdfDownloadUrl`)
|
|
|
|
|
+
|
|
|
|
|
+ - The PDF endpoint is **binary** (`application/pdf`) and is opened via navigation (`<a target="_blank">`).
|
|
|
|
|
+
|
|
|
|
|
+ - The frontend does **not** use `apiClient.apiFetch()` for PDF opening (JSON-centric).
|
|
|
|
|
+
|
|
|
### 1.2 Still out of scope / planned
|
|
### 1.2 Still out of scope / planned
|
|
|
|
|
|
|
|
- Search UI (route exists as placeholder: `/:branch/search`).
|
|
- Search UI (route exists as placeholder: `/:branch/search`).
|
|
|
-- PDF viewer / streaming endpoint integration (planned as RHL-023). File “Open” stays disabled for now.
|
|
|
|
|
|
|
+
|
|
|
- Admin/dev branch selector in the sidebar.
|
|
- Admin/dev branch selector in the sidebar.
|
|
|
-- Performance polish:
|
|
|
|
|
|
|
|
|
|
- - smoother navigation via client-side caching / prefetching
|
|
|
|
|
|
|
+- Optional Explorer improvements:
|
|
|
|
|
+
|
|
|
|
|
+ - “Herunterladen” action (download variant) next to “Öffnen”
|
|
|
|
|
+ - a dedicated in-app PDF viewer UI (instead of a new tab)
|
|
|
|
|
+
|
|
|
|
|
+- Perceived performance polish:
|
|
|
|
|
+
|
|
|
|
|
+ - client-side caching/prefetch
|
|
|
- skeleton/layout shift reduction
|
|
- skeleton/layout shift reduction
|
|
|
|
|
|
|
|
---
|
|
---
|
|
@@ -185,6 +206,7 @@ File: `components/auth/AuthProvider.jsx`
|
|
|
Behavior:
|
|
Behavior:
|
|
|
|
|
|
|
|
1. On mount, call `apiClient.getMe()`.
|
|
1. On mount, call `apiClient.getMe()`.
|
|
|
|
|
+
|
|
|
2. If `{ user: { ... } }`:
|
|
2. If `{ user: { ... } }`:
|
|
|
|
|
|
|
|
- set auth state to `authenticated`
|
|
- set auth state to `authenticated`
|
|
@@ -219,12 +241,14 @@ Files:
|
|
|
Flow:
|
|
Flow:
|
|
|
|
|
|
|
|
1. Login page parses query params using `parseLoginParams(...)`.
|
|
1. Login page parses query params using `parseLoginParams(...)`.
|
|
|
|
|
+
|
|
|
2. If `reason` is present:
|
|
2. If `reason` is present:
|
|
|
|
|
|
|
|
- `expired` → show “session expired” banner (German)
|
|
- `expired` → show “session expired” banner (German)
|
|
|
- `logged-out` → show “logged out” banner (German)
|
|
- `logged-out` → show “logged out” banner (German)
|
|
|
|
|
|
|
|
3. On submit, the form calls `apiClient.login({ username, password })`.
|
|
3. On submit, the form calls `apiClient.login({ username, password })`.
|
|
|
|
|
+
|
|
|
4. On success:
|
|
4. On success:
|
|
|
|
|
|
|
|
- redirect to `next` if present
|
|
- redirect to `next` if present
|
|
@@ -348,7 +372,7 @@ Where NotFound is shown:
|
|
|
|
|
|
|
|
---
|
|
---
|
|
|
|
|
|
|
|
-## 6. Explorer v2 (RHL-022)
|
|
|
|
|
|
|
+## 6. Explorer v2 (RHL-022) + PDF Open (RHL-023)
|
|
|
|
|
|
|
|
### 6.1 UI goal
|
|
### 6.1 UI goal
|
|
|
|
|
|
|
@@ -368,7 +392,7 @@ Routes and components:
|
|
|
### 6.3 Data fetching strategy
|
|
### 6.3 Data fetching strategy
|
|
|
|
|
|
|
|
- All Explorer pages are **Client Components**.
|
|
- All Explorer pages are **Client Components**.
|
|
|
-- All API calls go through `lib/frontend/apiClient.js`.
|
|
|
|
|
|
|
+- All JSON API calls go through `lib/frontend/apiClient.js`.
|
|
|
- A small hook provides consistent query state:
|
|
- A small hook provides consistent query state:
|
|
|
|
|
|
|
|
- `lib/frontend/hooks/useExplorerQuery.js`
|
|
- `lib/frontend/hooks/useExplorerQuery.js`
|
|
@@ -424,7 +448,13 @@ Error mapping:
|
|
|
- `FS_NOT_FOUND` → ExplorerNotFound
|
|
- `FS_NOT_FOUND` → ExplorerNotFound
|
|
|
- other errors → ExplorerError + retry
|
|
- other errors → ExplorerError + retry
|
|
|
|
|
|
|
|
-### 6.6 Files list
|
|
|
|
|
|
|
+### 6.6 Files list (leaf route) and “Open PDF”
|
|
|
|
|
+
|
|
|
|
|
+Leaf route:
|
|
|
|
|
+
|
|
|
|
|
+- `/:branch/:year/:month/:day`
|
|
|
|
|
+
|
|
|
|
|
+Files list behavior:
|
|
|
|
|
|
|
|
- Uses shadcn/ui `Table`.
|
|
- Uses shadcn/ui `Table`.
|
|
|
- Shows:
|
|
- Shows:
|
|
@@ -432,9 +462,25 @@ Error mapping:
|
|
|
- file name
|
|
- file name
|
|
|
- relative path (desktop column + mobile secondary line)
|
|
- relative path (desktop column + mobile secondary line)
|
|
|
|
|
|
|
|
-- Primary action:
|
|
|
|
|
|
|
+Primary file action:
|
|
|
|
|
+
|
|
|
|
|
+- “Öffnen” opens the PDF in a **new browser tab** via the binary PDF endpoint:
|
|
|
|
|
+
|
|
|
|
|
+ - `GET /api/files/:branch/:year/:month/:day/:filename`
|
|
|
|
|
|
|
|
- - “Öffnen” button remains disabled until the PDF endpoint/viewer ticket (RHL-023).
|
|
|
|
|
|
|
+Implementation notes:
|
|
|
|
|
+
|
|
|
|
|
+- URL construction is centralized in:
|
|
|
|
|
+
|
|
|
|
|
+ - `lib/frontend/explorer/pdfUrl.js`
|
|
|
|
|
+
|
|
|
|
|
+- The PDF endpoint is binary (`application/pdf`). The UI uses navigation (`<a target="_blank">`) instead of `apiClient`.
|
|
|
|
|
+
|
|
|
|
|
+- The filename segment must be URL-encoded (handled by `buildPdfUrl(...)`).
|
|
|
|
|
+
|
|
|
|
|
+Accessibility:
|
|
|
|
|
+
|
|
|
|
|
+- The “Öffnen” action uses an `aria-label` like `PDF öffnen: <filename>`.
|
|
|
|
|
|
|
|
---
|
|
---
|
|
|
|
|
|
|
@@ -496,6 +542,7 @@ Explorer helper tests:
|
|
|
- `lib/frontend/explorer/errorMapping.test.js`
|
|
- `lib/frontend/explorer/errorMapping.test.js`
|
|
|
- `lib/frontend/explorer/formatters.test.js`
|
|
- `lib/frontend/explorer/formatters.test.js`
|
|
|
- `lib/frontend/explorer/sorters.test.js`
|
|
- `lib/frontend/explorer/sorters.test.js`
|
|
|
|
|
+- `lib/frontend/explorer/pdfUrl.test.js` (RHL-023)
|
|
|
|
|
|
|
|
Component SSR smoke test:
|
|
Component SSR smoke test:
|
|
|
|
|
|
|
@@ -559,24 +606,17 @@ Explorer checks:
|
|
|
- `/:branch/:year` shows months
|
|
- `/:branch/:year` shows months
|
|
|
- `/:branch/:year/:month` shows days
|
|
- `/:branch/:year/:month` shows days
|
|
|
- `/:branch/:year/:month/:day` shows files
|
|
- `/:branch/:year/:month/:day` shows files
|
|
|
-- Breadcrumb dropdowns:
|
|
|
|
|
-
|
|
|
|
|
- - year dropdown exists on month/day/files levels
|
|
|
|
|
- - month dropdown exists on day/files levels
|
|
|
|
|
- - day dropdown exists on files level
|
|
|
|
|
|
|
|
|
|
-### 10.2 Server
|
|
|
|
|
|
|
+PDF open (RHL-023):
|
|
|
|
|
|
|
|
-Deploy and verify on the server URL.
|
|
|
|
|
|
|
+- On `/:branch/:year/:month/:day`, click **“Öffnen”** on multiple files
|
|
|
|
|
|
|
|
-Important cookie note:
|
|
|
|
|
|
|
+ - Expected: opens the PDF in a new tab
|
|
|
|
|
+ - Expected: works for filenames with spaces and special characters (URL-encoding)
|
|
|
|
|
|
|
|
-- Browsers reject `Secure` cookies over HTTP.
|
|
|
|
|
-- Therefore the server `.env.server` must set:
|
|
|
|
|
|
|
+### 10.2 Server
|
|
|
|
|
|
|
|
-```env
|
|
|
|
|
-SESSION_COOKIE_SECURE=false
|
|
|
|
|
-```
|
|
|
|
|
|
|
+Deploy and verify on the server URL.
|
|
|
|
|
|
|
|
Verify flows:
|
|
Verify flows:
|
|
|
|
|
|
|
@@ -589,13 +629,23 @@ Admin/dev checks:
|
|
|
- existing branches render
|
|
- existing branches render
|
|
|
- non-existing branch (e.g. `/NL9999`) shows NotFound (existence validation)
|
|
- non-existing branch (e.g. `/NL9999`) shows NotFound (existence validation)
|
|
|
|
|
|
|
|
|
|
+PDF open (RHL-023):
|
|
|
|
|
+
|
|
|
|
|
+- Repeat the local PDF open checks against real NAS data
|
|
|
|
|
+
|
|
|
---
|
|
---
|
|
|
|
|
|
|
|
## 11. Planned follow-ups
|
|
## 11. Planned follow-ups
|
|
|
|
|
|
|
|
- Search UI and filters (`/:branch/search`).
|
|
- Search UI and filters (`/:branch/search`).
|
|
|
-- PDF open/view experience (RHL-023).
|
|
|
|
|
|
|
+
|
|
|
|
|
+- Optional Explorer UI enhancements:
|
|
|
|
|
+
|
|
|
|
|
+ - add a secondary action “Herunterladen” (download variant)
|
|
|
|
|
+ - optional in-app PDF viewer experience (instead of a new tab)
|
|
|
|
|
+
|
|
|
- Admin/dev branch selector in the sidebar.
|
|
- Admin/dev branch selector in the sidebar.
|
|
|
|
|
+
|
|
|
- Smooth navigation / perceived performance improvements:
|
|
- Smooth navigation / perceived performance improvements:
|
|
|
|
|
|
|
|
- reduce skeleton/layout shift
|
|
- reduce skeleton/layout shift
|