This repository has been archived on 2026-02-15. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
breakpilot-pwa/admin-v2/components/common/PagePurpose.tsx
BreakPilot Dev 660295e218 fix(admin-v2): Restore complete admin-v2 application
The admin-v2 application was incomplete in the repository. This commit
restores all missing components:

- Admin pages (76 pages): dashboard, ai, compliance, dsgvo, education,
  infrastructure, communication, development, onboarding, rbac
- SDK pages (45 pages): tom, dsfa, vvt, loeschfristen, einwilligungen,
  vendor-compliance, tom-generator, dsr, and more
- Developer portal (25 pages): API docs, SDK guides, frameworks
- All components, lib files, hooks, and types
- Updated package.json with all dependencies

The issue was caused by incomplete initial repository state - the full
admin-v2 codebase existed in backend/admin-v2 and docs-src/admin-v2
but was never fully synced to the main admin-v2 directory.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-08 23:40:15 -08:00

170 lines
6.1 KiB
TypeScript
Raw Permalink Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
'use client'
import { useState } from 'react'
import Link from 'next/link'
export interface PagePurposeProps {
title: string
purpose: string
audience: string[]
gdprArticles?: string[]
architecture?: {
services: string[]
databases: string[]
diagram?: string
}
relatedPages?: Array<{
name: string
href: string
description: string
}>
collapsible?: boolean
defaultCollapsed?: boolean
}
export function PagePurpose({
title,
purpose,
audience,
gdprArticles,
architecture,
relatedPages,
collapsible = true,
defaultCollapsed = false,
}: PagePurposeProps) {
const [collapsed, setCollapsed] = useState(defaultCollapsed)
const [showArchitecture, setShowArchitecture] = useState(false)
return (
<div className="bg-gradient-to-r from-slate-50 to-slate-100 rounded-xl border border-slate-200 mb-6 overflow-hidden">
{/* Header */}
<div
className={`flex items-center justify-between px-4 py-3 ${
collapsible ? 'cursor-pointer hover:bg-slate-100' : ''
}`}
onClick={collapsible ? () => setCollapsed(!collapsed) : undefined}
>
<div className="flex items-center gap-2">
<span className="text-lg">🎯</span>
<span className="font-semibold text-slate-700">Warum gibt es diese Seite?</span>
</div>
{collapsible && (
<svg
className={`w-5 h-5 text-slate-400 transition-transform ${collapsed ? '' : 'rotate-180'}`}
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" />
</svg>
)}
</div>
{/* Content */}
{!collapsed && (
<div className="px-4 pb-4 space-y-4">
{/* Purpose */}
<p className="text-slate-600">{purpose}</p>
{/* Metadata */}
<div className="flex flex-wrap gap-4 text-sm">
{/* Audience */}
<div className="flex items-center gap-2">
<span className="text-slate-400">👥</span>
<span className="text-slate-500">Zielgruppe:</span>
<span className="text-slate-700">{audience.join(', ')}</span>
</div>
{/* GDPR Articles */}
{gdprArticles && gdprArticles.length > 0 && (
<div className="flex items-center gap-2">
<span className="text-slate-400">📋</span>
<span className="text-slate-500">DSGVO-Bezug:</span>
<span className="text-slate-700">{gdprArticles.join(', ')}</span>
</div>
)}
</div>
{/* Architecture (expandable) */}
{architecture && (
<div className="border-t border-slate-200 pt-3">
<button
onClick={(e) => {
e.stopPropagation()
setShowArchitecture(!showArchitecture)
}}
className="flex items-center gap-2 text-sm text-slate-500 hover:text-slate-700"
>
<span>🏗</span>
<span>Architektur</span>
<svg
className={`w-4 h-4 transition-transform ${showArchitecture ? 'rotate-180' : ''}`}
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" />
</svg>
</button>
{showArchitecture && (
<div className="mt-2 p-3 bg-white rounded-lg border border-slate-200 text-sm">
<div className="grid grid-cols-2 gap-4">
<div>
<span className="font-medium text-slate-600">Services:</span>
<ul className="mt-1 space-y-1 text-slate-500">
{architecture.services.map((service) => (
<li key={service} className="flex items-center gap-1">
<span className="w-1.5 h-1.5 bg-primary-400 rounded-full" />
{service}
</li>
))}
</ul>
</div>
<div>
<span className="font-medium text-slate-600">Datenbanken:</span>
<ul className="mt-1 space-y-1 text-slate-500">
{architecture.databases.map((db) => (
<li key={db} className="flex items-center gap-1">
<span className="w-1.5 h-1.5 bg-green-400 rounded-full" />
{db}
</li>
))}
</ul>
</div>
</div>
</div>
)}
</div>
)}
{/* Related Pages */}
{relatedPages && relatedPages.length > 0 && (
<div className="border-t border-slate-200 pt-3">
<span className="text-sm text-slate-500 flex items-center gap-2 mb-2">
<span>🔗</span>
<span>Verwandte Seiten</span>
</span>
<div className="flex flex-wrap gap-2">
{relatedPages.map((page) => (
<Link
key={page.href}
href={page.href}
className="inline-flex items-center gap-1 px-3 py-1.5 bg-white border border-slate-200 rounded-lg text-sm text-slate-600 hover:border-primary-300 hover:text-primary-600 transition-colors"
title={page.description}
>
<span>{page.name}</span>
<svg className="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5l7 7-7 7" />
</svg>
</Link>
))}
</div>
</div>
)}
</div>
)}
</div>
)
}