refactor(admin): split AIUseCaseModuleEditor, DataPointCatalog, ProjectSelector components
AIUseCaseModuleEditor (698 LOC) → thin orchestrator (187) + constants (29) + barrel tabs (4) + tabs implementation split into SystemData (261), PurposeAct (149), RisksReview (219). DataPointCatalog (658 LOC) → main (291) + helpers (190) + CategoryGroup (124) + Row (108). ProjectSelector (656 LOC) → main (211) + CreateProjectDialog (169) + ProjectActionDialog (140) + ProjectCard (128). All files now under 300 LOC soft target and 500 LOC hard cap. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
108
admin-compliance/components/sdk/einwilligungen/DataPointRow.tsx
Normal file
108
admin-compliance/components/sdk/einwilligungen/DataPointRow.tsx
Normal file
@@ -0,0 +1,108 @@
|
||||
'use client'
|
||||
|
||||
import { CheckCircle, Circle, AlertTriangle } from 'lucide-react'
|
||||
import {
|
||||
DataPoint,
|
||||
SupportedLanguage,
|
||||
RETENTION_PERIOD_INFO,
|
||||
} from '@/lib/sdk/einwilligungen/types'
|
||||
import { RiskBadge, LegalBasisBadge, Article9Badge } from './DataPointCatalogHelpers'
|
||||
|
||||
interface DataPointRowProps {
|
||||
dp: DataPoint
|
||||
isSelected: boolean
|
||||
readOnly: boolean
|
||||
language: SupportedLanguage
|
||||
onToggle: (id: string) => void
|
||||
}
|
||||
|
||||
export function DataPointRow({ dp, isSelected, readOnly, language, onToggle }: DataPointRowProps) {
|
||||
return (
|
||||
<div
|
||||
className={`flex items-start gap-4 p-4 ${
|
||||
readOnly ? '' : 'cursor-pointer hover:bg-slate-50'
|
||||
} transition-colors ${isSelected ? 'bg-indigo-50/50' : ''}`}
|
||||
onClick={() => !readOnly && onToggle(dp.id)}
|
||||
>
|
||||
{!readOnly && (
|
||||
<div className="flex-shrink-0 pt-0.5">
|
||||
{isSelected ? (
|
||||
<CheckCircle className="w-5 h-5 text-indigo-600" />
|
||||
) : (
|
||||
<Circle className="w-5 h-5 text-slate-300" />
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
<div className="flex-1 min-w-0">
|
||||
<div className="flex items-start justify-between gap-4">
|
||||
<div>
|
||||
<div className="flex items-center gap-2 flex-wrap">
|
||||
<span className="text-xs font-mono text-slate-400 bg-slate-100 px-1.5 py-0.5 rounded">
|
||||
{dp.code}
|
||||
</span>
|
||||
<span className="font-medium text-slate-900">
|
||||
{dp.name[language]}
|
||||
</span>
|
||||
{dp.isSpecialCategory && (
|
||||
<Article9Badge language={language} />
|
||||
)}
|
||||
{dp.isCustom && (
|
||||
<span className="text-xs bg-purple-100 text-purple-700 px-1.5 py-0.5 rounded">
|
||||
{language === 'de' ? 'Benutzerdefiniert' : 'Custom'}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
<p className="text-sm text-slate-600 mt-1">
|
||||
{dp.description[language]}
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex-shrink-0 flex flex-col items-end gap-1">
|
||||
<RiskBadge level={dp.riskLevel} language={language} />
|
||||
<LegalBasisBadge basis={dp.legalBasis} language={language} />
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-3 flex flex-wrap gap-x-4 gap-y-1 text-xs text-slate-500">
|
||||
<span>
|
||||
<strong>{language === 'de' ? 'Zweck' : 'Purpose'}:</strong> {dp.purpose[language]}
|
||||
</span>
|
||||
<span>
|
||||
<strong>{language === 'de' ? 'Loeschfrist' : 'Retention'}:</strong>{' '}
|
||||
{RETENTION_PERIOD_INFO[dp.retentionPeriod]?.label[language] || dp.retentionPeriod}
|
||||
</span>
|
||||
{dp.cookieCategory && (
|
||||
<span>
|
||||
<strong>Cookie:</strong> {dp.cookieCategory}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
{(dp.requiresExplicitConsent || dp.isSpecialCategory) && (
|
||||
<div className="mt-2 p-2 rounded-md bg-rose-50 border border-rose-200">
|
||||
<div className="flex items-start gap-2 text-xs text-rose-700">
|
||||
<AlertTriangle className="w-4 h-4 flex-shrink-0 mt-0.5" />
|
||||
<div>
|
||||
<strong>
|
||||
{language === 'de'
|
||||
? 'Ausdrueckliche Einwilligung erforderlich'
|
||||
: 'Explicit consent required'}
|
||||
</strong>
|
||||
{dp.legalBasis === 'EXPLICIT_CONSENT' && (
|
||||
<span className="block mt-1 text-rose-600">
|
||||
{language === 'de'
|
||||
? 'Art. 9 Abs. 2 lit. a DSGVO - Separate Einwilligungserklaerung notwendig'
|
||||
: 'Art. 9(2)(a) GDPR - Separate consent declaration required'}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{dp.thirdPartyRecipients.length > 0 && (
|
||||
<div className="mt-2 text-xs text-slate-500">
|
||||
<strong>Drittanbieter:</strong>{' '}
|
||||
{dp.thirdPartyRecipients.join(', ')}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user