From 8261fa4420c8c8094381b9b482c0261cbe572c81 Mon Sep 17 00:00:00 2001 From: Lars Date: Sun, 10 May 2026 10:51:20 +0200 Subject: [PATCH] feat(compliance): P-01b Mobile/PWA-Zugriff auf Rechtstexte via Einstellungen MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - SettingsLegalPage.jsx: neue Hub-Seite /settings/legal mit allen 4 Rechtstext-Links - App.jsx: Route /settings/legal in ProtectedLayout registriert - AccountSettingsPage.jsx: Link zu /settings/legal unterhalb System-Info - 3 Playwright-Tests für P-01b (Einstellungen → Rechtliches → Links → Routen) - Version: 0.8.69 → 0.8.70 (backend + frontend) Co-Authored-By: Claude Sonnet 4.6 --- backend/version.py | 9 ++- frontend/src/App.jsx | 2 + frontend/src/pages/AccountSettingsPage.jsx | 4 ++ frontend/src/pages/SettingsLegalPage.jsx | 66 ++++++++++++++++++++++ frontend/src/version.js | 3 +- tests/dev-smoke-test.spec.js | 53 +++++++++++++++++ 6 files changed, 135 insertions(+), 2 deletions(-) create mode 100644 frontend/src/pages/SettingsLegalPage.jsx diff --git a/backend/version.py b/backend/version.py index ac2ca16..168a3ce 100644 --- a/backend/version.py +++ b/backend/version.py @@ -1,6 +1,6 @@ # Shinkan Jinkendo Version Information -APP_VERSION = "0.8.69" +APP_VERSION = "0.8.70" BUILD_DATE = "2026-05-10" DB_SCHEMA_VERSION = "20260508049" @@ -29,6 +29,13 @@ MODULE_VERSIONS = { } CHANGELOG = [ + { + "version": "0.8.70", + "date": "2026-05-10", + "changes": [ + "Compliance P-01b: Einstellungen/Rechtliches (/settings/legal) fuer mobile/PWA-Darstellung; Hub mit Links zu Impressum, Datenschutz, Nutzungsbedingungen, Medienrichtlinie", + ], + }, { "version": "0.8.69", "date": "2026-05-10", diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index 6067359..348833d 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -38,6 +38,7 @@ import AdminHomeRedirect from './components/AdminHomeRedirect' import PlatformAdminRoute from './components/PlatformAdminRoute' import MediaLibraryPage from './pages/MediaLibraryPage' import LegalPage from './pages/LegalPage' +import SettingsLegalPage from './pages/SettingsLegalPage' import ActiveClubSwitcher from './components/ActiveClubSwitcher' import InactiveMembershipBanner from './components/InactiveMembershipBanner' import './app.css' @@ -183,6 +184,7 @@ function AppRoutes() { } /> } /> } /> + } /> } /> } /> diff --git a/frontend/src/pages/AccountSettingsPage.jsx b/frontend/src/pages/AccountSettingsPage.jsx index 67375ae..047e515 100644 --- a/frontend/src/pages/AccountSettingsPage.jsx +++ b/frontend/src/pages/AccountSettingsPage.jsx @@ -426,6 +426,10 @@ function AccountSettingsPage() { Technische Systeminformationen {' — App-Version, Build, Umgebung, Datenbankschema'}

+

+ Rechtliches + {' — Impressum, Datenschutz, Nutzungsbedingungen, Medienrichtlinie'} +

) } diff --git a/frontend/src/pages/SettingsLegalPage.jsx b/frontend/src/pages/SettingsLegalPage.jsx new file mode 100644 index 0000000..d1dc039 --- /dev/null +++ b/frontend/src/pages/SettingsLegalPage.jsx @@ -0,0 +1,66 @@ +import { Link } from 'react-router-dom' +import { Scale } from 'lucide-react' + +const LEGAL_LINKS = [ + { to: '/impressum', label: 'Impressum', description: 'Angaben zum Betreiber und Verantwortlichen' }, + { to: '/datenschutz', label: 'Datenschutzerklärung', description: 'Verarbeitung personenbezogener Daten' }, + { to: '/nutzungsbedingungen', label: 'Nutzungsbedingungen', description: 'Regeln für die Nutzung der Plattform' }, + { to: '/medienrichtlinie', label: 'Medienrichtlinie', description: 'Urheberrecht, Rechte am eigenen Bild, Sichtbarkeit' }, +] + +function SettingsLegalPage() { + return ( +
+

+ + ← Zurück zu Einstellungen + +

+ +

Rechtliches

+

+ Rechtstexte und Richtlinien der Plattform. + Die Inhalte befinden sich noch in redaktioneller Prüfung. +

+ +
+ {LEGAL_LINKS.map((item, idx) => ( + + +
+
+ {item.label} +
+
+ {item.description} +
+
+ + + ))} +
+
+ ) +} + +export default SettingsLegalPage diff --git a/frontend/src/version.js b/frontend/src/version.js index 31ceb7d..9ccbd2f 100644 --- a/frontend/src/version.js +++ b/frontend/src/version.js @@ -1,11 +1,12 @@ // Shinkan Jinkendo Frontend Version -export const APP_VERSION = "0.8.69" +export const APP_VERSION = "0.8.70" export const BUILD_DATE = "2026-05-10" export const PAGE_VERSIONS = { LoginPage: "1.0.2", LegalPage: "1.0.0", + SettingsLegalPage: "1.0.0", Dashboard: "1.0.0", AccountSettingsPage: "1.0.1", ExercisesPage: "1.5.0", // Fokus +/- Regeln, nur ohne Fokusbereich; Filterprefs diff --git a/tests/dev-smoke-test.spec.js b/tests/dev-smoke-test.spec.js index 8a61fb7..c1fe24a 100644 --- a/tests/dev-smoke-test.spec.js +++ b/tests/dev-smoke-test.spec.js @@ -230,6 +230,59 @@ test('P-01: Login-Seite enthält Links zu allen vier Rechtstextseiten', async ({ console.log('✓ P-01: Login-Seite – alle vier Rechtstext-Links vorhanden'); }); +// P-01b: Rechtliches über Einstellungen (Mobile/PWA-Erreichbarkeit) + +test('P-01b: Einstellungen enthält Link zu Rechtliches', async ({ page }) => { + await page.setViewportSize({ width: 390, height: 844 }); + await login(page); + await page.waitForLoadState('networkidle'); + + await page.goto('/settings'); + await page.waitForLoadState('networkidle'); + + const link = page.locator('a[href="/settings/legal"]'); + await expect(link).toBeVisible(); + + console.log('✓ P-01b: Einstellungen enthält Link zu /settings/legal'); +}); + +test('P-01b: /settings/legal enthält Links zu allen vier Rechtstextseiten', async ({ page }) => { + await page.setViewportSize({ width: 390, height: 844 }); + await login(page); + await page.waitForLoadState('networkidle'); + + await page.goto('/settings/legal'); + await page.waitForLoadState('networkidle'); + + await expect(page.getByRole('heading', { level: 1 })).toContainText('Rechtliches'); + + for (const route of LEGAL_ROUTES) { + const link = page.locator(`a[href="${route.path}"]`); + await expect(link).toBeVisible(); + } + + console.log('✓ P-01b: /settings/legal – Überschrift + alle vier Rechtstext-Links vorhanden'); +}); + +test('P-01b: Jeder Rechtstext-Link aus /settings/legal führt zur korrekten Route', async ({ page }) => { + await page.setViewportSize({ width: 390, height: 844 }); + await login(page); + await page.waitForLoadState('networkidle'); + + for (const route of LEGAL_ROUTES) { + await page.goto('/settings/legal'); + await page.waitForLoadState('networkidle'); + + await page.locator(`a[href="${route.path}"]`).click(); + await page.waitForLoadState('networkidle'); + + expect(page.url()).toContain(route.path); + await expect(page.getByRole('heading', { level: 1 })).toContainText(route.label); + + console.log(`✓ P-01b: ${route.label} – Link aus /settings/legal korrekt`); + } +}); + test('8. Keine kritischen Console-Fehler', async ({ page }) => { const errors = []; page.on('console', msg => {