Files
breakpilot-compliance/admin-compliance/app/sdk/einwilligungen/page.tsx
Sharang Parnerkar 92a730626d refactor(admin): split einwilligungen page.tsx into colocated components
Extract nav tabs, detail modal, table row, stats grid, search/filter,
records table, pagination, and data-loading hook into _components/ and
_hooks/. page.tsx reduced from 833 to 114 LOC.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 08:20:50 +02:00

115 lines
3.8 KiB
TypeScript

'use client'
import { useState } from 'react'
import { StepHeader, STEP_EXPLANATIONS } from '@/components/sdk/StepHeader'
import { History } from 'lucide-react'
import { ConsentRecord } from './_types'
import { useConsents } from './_hooks/useConsents'
import { EinwilligungenNavTabs } from './_components/EinwilligungenNavTabs'
import { StatsGrid } from './_components/StatsGrid'
import { SearchAndFilter } from './_components/SearchAndFilter'
import { RecordsTable } from './_components/RecordsTable'
import { Pagination } from './_components/Pagination'
import { ConsentDetailModal } from './_components/ConsentDetailModal'
export default function EinwilligungenPage() {
const {
records,
currentPage,
setCurrentPage,
totalRecords,
globalStats,
handleRevoke,
} = useConsents()
const [filter, setFilter] = useState<string>('all')
const [searchQuery, setSearchQuery] = useState('')
const [selectedRecord, setSelectedRecord] = useState<ConsentRecord | null>(null)
const filteredRecords = records.filter(record => {
const matchesFilter = filter === 'all' || record.consentType === filter || record.status === filter
const matchesSearch = searchQuery === '' ||
record.email.toLowerCase().includes(searchQuery.toLowerCase()) ||
record.identifier.toLowerCase().includes(searchQuery.toLowerCase())
return matchesFilter && matchesSearch
})
const versionUpdates = records.reduce(
(acc, r) => acc + r.history.filter(h => h.action === 'version_update').length,
0,
)
const stepInfo = STEP_EXPLANATIONS['einwilligungen']
return (
<div className="space-y-6">
{/* Step Header */}
<StepHeader
stepId="einwilligungen"
title={stepInfo.title}
description={stepInfo.description}
explanation={stepInfo.explanation}
tips={stepInfo.tips}
>
<button className="flex items-center gap-2 px-4 py-2 bg-purple-600 text-white rounded-lg hover:bg-purple-700 transition-colors">
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4" />
</svg>
Export
</button>
</StepHeader>
{/* Navigation Tabs */}
<EinwilligungenNavTabs />
{/* Stats */}
<StatsGrid
total={globalStats.total}
active={globalStats.active}
revoked={globalStats.revoked}
versionUpdates={versionUpdates}
/>
{/* Info Banner */}
<div className="bg-gradient-to-r from-purple-50 to-indigo-50 rounded-xl border border-purple-200 p-4 flex items-start gap-3">
<History className="w-5 h-5 text-purple-600 mt-0.5" />
<div>
<div className="font-medium text-purple-900">Consent-Historie aktiviert</div>
<div className="text-sm text-purple-700">
Alle Änderungen an Einwilligungen werden protokolliert, inkl. Zustimmungen zu neuen Versionen von AGB, DSI und anderen Dokumenten.
Klicken Sie auf "Details" um die vollständige Historie eines Nutzers einzusehen.
</div>
</div>
</div>
{/* Search and Filter */}
<SearchAndFilter
searchQuery={searchQuery}
onSearchChange={setSearchQuery}
filter={filter}
onFilterChange={setFilter}
/>
{/* Records Table */}
<RecordsTable records={filteredRecords} onShowDetails={setSelectedRecord} />
{/* Pagination */}
<Pagination
currentPage={currentPage}
totalRecords={totalRecords}
onPageChange={setCurrentPage}
/>
{/* Detail Modal */}
{selectedRecord && (
<ConsentDetailModal
record={selectedRecord}
onClose={() => setSelectedRecord(null)}
onRevoke={handleRevoke}
/>
)}
</div>
)
}