feat(cmp): Phase 3 — admin widerruf, email-linking, vendor display, TCF, E2E tests
Admin Modal:
- vendor_consents as green/red badges
- Consent withdraw button (DELETE /consent/{id}) with confirmation
- Email-linking inline input (POST /consent/link-email)
Cookie Banner Admin:
- TCF toggle reads tcf_enabled from site config (was hardcoded false)
- BannerSite interface extended with tcf_enabled
Document Generator:
- Backend Banner-Config auto-fetch when SDK state has no banner
- Maps vendors to CONSENT (analytics tools, marketing partners)
E2E Tests (cmp-phase3-dsr.spec.ts):
- Vendor-agnostic consent fields (20+ fields, upsert)
- DSR Art. 15 Auskunft (multi-device, email-link, export)
- DSR Art. 17 Löschung (erasure by email)
- Anonymous cookie banner user (export, withdraw)
- Customer lifecycle (consent → login → link → Art.15 → Art.17)
- Admin dashboard integration (list, stats)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -101,7 +101,35 @@ function DocumentGeneratorPageInner() {
|
||||
}
|
||||
}, [state?.complianceScope?.determinedLevel, state?.companyProfile])
|
||||
|
||||
// ── MODULE WIRING: CookieBanner → CONSENT + FEATURES ─────────────────────
|
||||
// ── MODULE WIRING: Backend Banner-Config → CONSENT + FEATURES ────────────
|
||||
useEffect(() => {
|
||||
// Fetch real vendor/category data from backend if SDK state has no banner
|
||||
if (state?.cookieBanner) return // SDK state takes priority
|
||||
fetch('/api/sdk/v1/banner/admin/sites', { headers: { 'x-tenant-id': '9282a473-5c95-4b3a-bf78-0ecc0ec71d3e' } })
|
||||
.then(r => r.json())
|
||||
.then((sites: Array<{ site_id: string }>) => {
|
||||
if (!sites?.length) return
|
||||
return fetch(`/api/sdk/v1/banner/config/${sites[0].site_id}`, { headers: { 'x-tenant-id': '9282a473-5c95-4b3a-bf78-0ecc0ec71d3e' } })
|
||||
})
|
||||
.then(r => r?.json())
|
||||
.then(config => {
|
||||
if (!config?.vendors?.length) return
|
||||
const analytics = config.vendors.filter((v: { category_key: string }) => v.category_key === 'statistics' || v.category_key === 'analytics').map((v: { vendor_name: string }) => v.vendor_name)
|
||||
const marketing = config.vendors.filter((v: { category_key: string }) => v.category_key === 'marketing').map((v: { vendor_name: string }) => v.vendor_name)
|
||||
setContext(prev => ({
|
||||
...prev,
|
||||
CONSENT: {
|
||||
...prev.CONSENT,
|
||||
ANALYTICS_TOOLS: analytics.length > 0 ? analytics.join(', ') : prev.CONSENT.ANALYTICS_TOOLS,
|
||||
MARKETING_PARTNERS: marketing.length > 0 ? marketing.join(', ') : prev.CONSENT.MARKETING_PARTNERS,
|
||||
},
|
||||
FEATURES: { ...prev.FEATURES, CMP_NAME: 'BreakPilot CMP', CMP_LOGS_CONSENTS: true },
|
||||
}))
|
||||
})
|
||||
.catch(() => {})
|
||||
}, [state?.cookieBanner])
|
||||
|
||||
// ── MODULE WIRING: CookieBanner SDK State → CONSENT + FEATURES ──────────
|
||||
useEffect(() => {
|
||||
const banner = state?.cookieBanner
|
||||
if (!banner) return
|
||||
|
||||
Reference in New Issue
Block a user