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>
125 lines
4.1 KiB
TypeScript
125 lines
4.1 KiB
TypeScript
'use client'
|
|
|
|
import { ChevronDown, ChevronRight } from 'lucide-react'
|
|
import {
|
|
DataPoint,
|
|
DataPointCategory,
|
|
SupportedLanguage,
|
|
CATEGORY_METADATA,
|
|
} from '@/lib/sdk/einwilligungen/types'
|
|
import { CategoryIcon } from './DataPointCatalogHelpers'
|
|
import { DataPointRow } from './DataPointRow'
|
|
|
|
interface DataPointCategoryGroupProps {
|
|
category: DataPointCategory
|
|
categoryDataPoints: DataPoint[]
|
|
selectedIds: string[]
|
|
isExpanded: boolean
|
|
readOnly: boolean
|
|
language: SupportedLanguage
|
|
onToggleCategory: (category: DataPointCategory) => void
|
|
onToggleDataPoint: (id: string) => void
|
|
}
|
|
|
|
export function DataPointCategoryGroup({
|
|
category,
|
|
categoryDataPoints,
|
|
selectedIds,
|
|
isExpanded,
|
|
readOnly,
|
|
language,
|
|
onToggleCategory,
|
|
onToggleDataPoint,
|
|
}: DataPointCategoryGroupProps) {
|
|
const meta = CATEGORY_METADATA[category]
|
|
const selectedInCategory = categoryDataPoints.filter((dp) =>
|
|
selectedIds.includes(dp.id)
|
|
).length
|
|
|
|
return (
|
|
<div className="border border-slate-200 rounded-xl overflow-hidden bg-white">
|
|
{/* Category Header */}
|
|
<button
|
|
onClick={() => onToggleCategory(category)}
|
|
className={`w-full flex items-center justify-between px-4 py-3 transition-colors ${
|
|
category === 'HEALTH_DATA'
|
|
? 'bg-rose-50 hover:bg-rose-100 border-l-4 border-rose-400'
|
|
: category === 'EMPLOYEE_DATA'
|
|
? 'bg-orange-50 hover:bg-orange-100 border-l-4 border-orange-400'
|
|
: category === 'AI_DATA'
|
|
? 'bg-fuchsia-50 hover:bg-fuchsia-100 border-l-4 border-fuchsia-400'
|
|
: 'bg-slate-50 hover:bg-slate-100'
|
|
}`}
|
|
>
|
|
<div className="flex items-center gap-3">
|
|
<div className={`p-2 rounded-lg ${
|
|
category === 'HEALTH_DATA' ? 'bg-rose-100' :
|
|
category === 'EMPLOYEE_DATA' ? 'bg-orange-100' :
|
|
category === 'AI_DATA' ? 'bg-fuchsia-100' :
|
|
`bg-${meta.color}-100`
|
|
}`}>
|
|
<CategoryIcon
|
|
category={category}
|
|
className={`w-5 h-5 ${
|
|
category === 'HEALTH_DATA' ? 'text-rose-600' :
|
|
category === 'EMPLOYEE_DATA' ? 'text-orange-600' :
|
|
category === 'AI_DATA' ? 'text-fuchsia-600' :
|
|
`text-${meta.color}-600`
|
|
}`}
|
|
/>
|
|
</div>
|
|
<div className="text-left">
|
|
<div className="flex items-center gap-2">
|
|
<span className="font-semibold text-slate-900">
|
|
{meta.code}. {meta.name[language]}
|
|
</span>
|
|
{category === 'HEALTH_DATA' && (
|
|
<span className="text-xs bg-rose-200 text-rose-700 px-1.5 py-0.5 rounded font-medium">
|
|
Art. 9 DSGVO
|
|
</span>
|
|
)}
|
|
{category === 'EMPLOYEE_DATA' && (
|
|
<span className="text-xs bg-orange-200 text-orange-700 px-1.5 py-0.5 rounded font-medium">
|
|
BDSG § 26
|
|
</span>
|
|
)}
|
|
{category === 'AI_DATA' && (
|
|
<span className="text-xs bg-fuchsia-200 text-fuchsia-700 px-1.5 py-0.5 rounded font-medium">
|
|
AI Act
|
|
</span>
|
|
)}
|
|
</div>
|
|
<div className="text-xs text-slate-500">{meta.description[language]}</div>
|
|
</div>
|
|
</div>
|
|
<div className="flex items-center gap-3">
|
|
<span className="text-sm text-slate-500">
|
|
{selectedInCategory}/{categoryDataPoints.length}
|
|
</span>
|
|
{isExpanded ? (
|
|
<ChevronDown className="w-5 h-5 text-slate-400" />
|
|
) : (
|
|
<ChevronRight className="w-5 h-5 text-slate-400" />
|
|
)}
|
|
</div>
|
|
</button>
|
|
|
|
{/* Data Points List */}
|
|
{isExpanded && (
|
|
<div className="divide-y divide-slate-100">
|
|
{categoryDataPoints.map((dp) => (
|
|
<DataPointRow
|
|
key={dp.id}
|
|
dp={dp}
|
|
isSelected={selectedIds.includes(dp.id)}
|
|
readOnly={readOnly}
|
|
language={language}
|
|
onToggle={onToggleDataPoint}
|
|
/>
|
|
))}
|
|
</div>
|
|
)}
|
|
</div>
|
|
)
|
|
}
|