feat(compliance): P-01b Mobile/PWA-Zugriff auf Rechtstexte via Einstellungen
Some checks failed
Deploy Development / deploy (push) Successful in 34s
Test Suite / pytest-backend (push) Successful in 32s
Test Suite / lint-backend (push) Successful in 0s
Test Suite / build-frontend (push) Successful in 8s
Test Suite / playwright-tests (push) Failing after 49s
Some checks failed
Deploy Development / deploy (push) Successful in 34s
Test Suite / pytest-backend (push) Successful in 32s
Test Suite / lint-backend (push) Successful in 0s
Test Suite / build-frontend (push) Successful in 8s
Test Suite / playwright-tests (push) Failing after 49s
- 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 <noreply@anthropic.com>
This commit is contained in:
parent
75d6a40817
commit
8261fa4420
|
|
@ -1,6 +1,6 @@
|
||||||
# Shinkan Jinkendo Version Information
|
# Shinkan Jinkendo Version Information
|
||||||
|
|
||||||
APP_VERSION = "0.8.69"
|
APP_VERSION = "0.8.70"
|
||||||
BUILD_DATE = "2026-05-10"
|
BUILD_DATE = "2026-05-10"
|
||||||
DB_SCHEMA_VERSION = "20260508049"
|
DB_SCHEMA_VERSION = "20260508049"
|
||||||
|
|
||||||
|
|
@ -29,6 +29,13 @@ MODULE_VERSIONS = {
|
||||||
}
|
}
|
||||||
|
|
||||||
CHANGELOG = [
|
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",
|
"version": "0.8.69",
|
||||||
"date": "2026-05-10",
|
"date": "2026-05-10",
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,7 @@ import AdminHomeRedirect from './components/AdminHomeRedirect'
|
||||||
import PlatformAdminRoute from './components/PlatformAdminRoute'
|
import PlatformAdminRoute from './components/PlatformAdminRoute'
|
||||||
import MediaLibraryPage from './pages/MediaLibraryPage'
|
import MediaLibraryPage from './pages/MediaLibraryPage'
|
||||||
import LegalPage from './pages/LegalPage'
|
import LegalPage from './pages/LegalPage'
|
||||||
|
import SettingsLegalPage from './pages/SettingsLegalPage'
|
||||||
import ActiveClubSwitcher from './components/ActiveClubSwitcher'
|
import ActiveClubSwitcher from './components/ActiveClubSwitcher'
|
||||||
import InactiveMembershipBanner from './components/InactiveMembershipBanner'
|
import InactiveMembershipBanner from './components/InactiveMembershipBanner'
|
||||||
import './app.css'
|
import './app.css'
|
||||||
|
|
@ -183,6 +184,7 @@ function AppRoutes() {
|
||||||
<Route path="profile" element={<Navigate to="/settings" replace />} />
|
<Route path="profile" element={<Navigate to="/settings" replace />} />
|
||||||
<Route path="settings" element={<AccountSettingsPage />} />
|
<Route path="settings" element={<AccountSettingsPage />} />
|
||||||
<Route path="settings/system" element={<SettingsSystemInfoPage />} />
|
<Route path="settings/system" element={<SettingsSystemInfoPage />} />
|
||||||
|
<Route path="settings/legal" element={<SettingsLegalPage />} />
|
||||||
<Route path="media" element={<MediaLibraryPage />} />
|
<Route path="media" element={<MediaLibraryPage />} />
|
||||||
<Route path="exercises">
|
<Route path="exercises">
|
||||||
<Route index element={<ExercisesListPage />} />
|
<Route index element={<ExercisesListPage />} />
|
||||||
|
|
|
||||||
|
|
@ -426,6 +426,10 @@ function AccountSettingsPage() {
|
||||||
<Link to="/settings/system">Technische Systeminformationen</Link>
|
<Link to="/settings/system">Technische Systeminformationen</Link>
|
||||||
{' — App-Version, Build, Umgebung, Datenbankschema'}
|
{' — App-Version, Build, Umgebung, Datenbankschema'}
|
||||||
</p>
|
</p>
|
||||||
|
<p className="muted" style={{ marginTop: '0.6rem', fontSize: '0.875rem', lineHeight: 1.5 }}>
|
||||||
|
<Link to="/settings/legal">Rechtliches</Link>
|
||||||
|
{' — Impressum, Datenschutz, Nutzungsbedingungen, Medienrichtlinie'}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
66
frontend/src/pages/SettingsLegalPage.jsx
Normal file
66
frontend/src/pages/SettingsLegalPage.jsx
Normal file
|
|
@ -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 (
|
||||||
|
<div className="page-padding app-page" style={{ padding: '1rem' }}>
|
||||||
|
<p style={{ marginBottom: '0.75rem' }}>
|
||||||
|
<Link to="/settings" style={{ fontSize: '0.9rem' }}>
|
||||||
|
← Zurück zu Einstellungen
|
||||||
|
</Link>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h1 style={{ marginBottom: '0.35rem', fontSize: '1.5rem' }}>Rechtliches</h1>
|
||||||
|
<p
|
||||||
|
style={{
|
||||||
|
color: 'var(--text2)',
|
||||||
|
marginBottom: '1.25rem',
|
||||||
|
fontSize: '0.95rem',
|
||||||
|
lineHeight: 1.5,
|
||||||
|
maxWidth: '40rem',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Rechtstexte und Richtlinien der Plattform.
|
||||||
|
Die Inhalte befinden sich noch in redaktioneller Prüfung.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div className="card" style={{ padding: 0, overflow: 'hidden' }}>
|
||||||
|
{LEGAL_LINKS.map((item, idx) => (
|
||||||
|
<Link
|
||||||
|
key={item.to}
|
||||||
|
to={item.to}
|
||||||
|
style={{
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
gap: '0.85rem',
|
||||||
|
padding: '1rem 1.1rem',
|
||||||
|
borderBottom: idx < LEGAL_LINKS.length - 1 ? '1px solid var(--border)' : 'none',
|
||||||
|
textDecoration: 'none',
|
||||||
|
color: 'inherit',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Scale size={18} style={{ color: 'var(--text3)', flexShrink: 0 }} />
|
||||||
|
<div>
|
||||||
|
<div style={{ fontWeight: 500, color: 'var(--text1)', fontSize: '0.95rem' }}>
|
||||||
|
{item.label}
|
||||||
|
</div>
|
||||||
|
<div style={{ fontSize: '0.8rem', color: 'var(--text3)', marginTop: '0.15rem' }}>
|
||||||
|
{item.description}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<span style={{ marginLeft: 'auto', color: 'var(--text3)', fontSize: '1.1rem' }}>›</span>
|
||||||
|
</Link>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SettingsLegalPage
|
||||||
|
|
@ -1,11 +1,12 @@
|
||||||
// Shinkan Jinkendo Frontend Version
|
// 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 BUILD_DATE = "2026-05-10"
|
||||||
|
|
||||||
export const PAGE_VERSIONS = {
|
export const PAGE_VERSIONS = {
|
||||||
LoginPage: "1.0.2",
|
LoginPage: "1.0.2",
|
||||||
LegalPage: "1.0.0",
|
LegalPage: "1.0.0",
|
||||||
|
SettingsLegalPage: "1.0.0",
|
||||||
Dashboard: "1.0.0",
|
Dashboard: "1.0.0",
|
||||||
AccountSettingsPage: "1.0.1",
|
AccountSettingsPage: "1.0.1",
|
||||||
ExercisesPage: "1.5.0", // Fokus +/- Regeln, nur ohne Fokusbereich; Filterprefs
|
ExercisesPage: "1.5.0", // Fokus +/- Regeln, nur ohne Fokusbereich; Filterprefs
|
||||||
|
|
|
||||||
|
|
@ -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');
|
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 }) => {
|
test('8. Keine kritischen Console-Fehler', async ({ page }) => {
|
||||||
const errors = [];
|
const errors = [];
|
||||||
page.on('console', msg => {
|
page.on('console', msg => {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user