feat(cmp): unified consent view — Website-Besucher + Login-Nutzer tabs
Merges two separate consent views into one unified page at /sdk/einwilligungen: - Tab "Website-Besucher": device-based banner consents with site selector - Tab "Login-Nutzer": user-based DSGVO consents (existing, unchanged) Backend: - New endpoint GET /admin/consents for paginated banner consent records - Fix: categories JSON string parsing (was iterating chars instead of array) CMP Dashboard: - Dynamic site selector replacing hardcoded "preview-test-site" Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
import { useState, useEffect, useCallback } from 'react'
|
||||
import { BannerConsentRecord, BannerConsentStats, BannerSite, PAGE_SIZE } from '../_types'
|
||||
|
||||
const BANNER_API = '/api/sdk/v1/banner'
|
||||
const TENANT_ID = '9282a473-5c95-4b3a-bf78-0ecc0ec71d3e'
|
||||
const HEADERS = { 'x-tenant-id': TENANT_ID }
|
||||
|
||||
function fb(path: string) {
|
||||
return fetch(`${BANNER_API}/${path}`, { headers: HEADERS })
|
||||
.then(r => r.ok ? r.json() : null)
|
||||
.catch(() => null)
|
||||
}
|
||||
|
||||
export function useBannerConsents() {
|
||||
const [records, setRecords] = useState<BannerConsentRecord[]>([])
|
||||
const [sites, setSites] = useState<BannerSite[]>([])
|
||||
const [selectedSite, setSelectedSite] = useState<string>('')
|
||||
const [stats, setStats] = useState<BannerConsentStats | null>(null)
|
||||
const [currentPage, setCurrentPage] = useState(1)
|
||||
const [totalRecords, setTotalRecords] = useState(0)
|
||||
const [loading, setLoading] = useState(true)
|
||||
|
||||
// Load sites on mount
|
||||
useEffect(() => {
|
||||
fb('admin/sites').then(data => {
|
||||
const list = Array.isArray(data) ? data : []
|
||||
setSites(list)
|
||||
if (list.length > 0) {
|
||||
setSelectedSite(list[0].site_id)
|
||||
}
|
||||
setLoading(false)
|
||||
})
|
||||
}, [])
|
||||
|
||||
// Load consents + stats when site or page changes
|
||||
const loadData = useCallback(async () => {
|
||||
if (!selectedSite) return
|
||||
setLoading(true)
|
||||
const offset = (currentPage - 1) * PAGE_SIZE
|
||||
const [consentsData, statsData] = await Promise.all([
|
||||
fb(`admin/consents?site_id=${selectedSite}&limit=${PAGE_SIZE}&offset=${offset}`),
|
||||
fb(`admin/stats/${selectedSite}`),
|
||||
])
|
||||
if (consentsData) {
|
||||
setRecords(consentsData.consents || [])
|
||||
setTotalRecords(consentsData.total || 0)
|
||||
}
|
||||
setStats(statsData)
|
||||
setLoading(false)
|
||||
}, [selectedSite, currentPage])
|
||||
|
||||
useEffect(() => {
|
||||
loadData()
|
||||
}, [loadData])
|
||||
|
||||
const changeSite = (siteId: string) => {
|
||||
setSelectedSite(siteId)
|
||||
setCurrentPage(1)
|
||||
}
|
||||
|
||||
return {
|
||||
records,
|
||||
sites,
|
||||
selectedSite,
|
||||
changeSite,
|
||||
stats,
|
||||
currentPage,
|
||||
setCurrentPage,
|
||||
totalRecords,
|
||||
loading,
|
||||
reload: loadData,
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user