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>
This commit is contained in:
@@ -0,0 +1,482 @@
|
||||
'use client'
|
||||
|
||||
import React, { useState } from 'react'
|
||||
import { SDKDocsSidebar } from '@/components/developers/SDKDocsSidebar'
|
||||
import { Copy, Check } from 'lucide-react'
|
||||
|
||||
function CopyButton({ text }: { text: string }) {
|
||||
const [copied, setCopied] = useState(false)
|
||||
|
||||
const handleCopy = async () => {
|
||||
await navigator.clipboard.writeText(text)
|
||||
setCopied(true)
|
||||
setTimeout(() => setCopied(false), 2000)
|
||||
}
|
||||
|
||||
return (
|
||||
<button
|
||||
onClick={handleCopy}
|
||||
className="p-2 hover:bg-gray-700 rounded transition-colors"
|
||||
title="Kopieren"
|
||||
>
|
||||
{copied ? (
|
||||
<Check className="w-4 h-4 text-green-400" />
|
||||
) : (
|
||||
<Copy className="w-4 h-4 text-gray-400" />
|
||||
)}
|
||||
</button>
|
||||
)
|
||||
}
|
||||
|
||||
function CodeBlock({ code }: { code: string }) {
|
||||
return (
|
||||
<div className="relative bg-gray-900 rounded-lg overflow-hidden">
|
||||
<div className="absolute top-2 right-2">
|
||||
<CopyButton text={code} />
|
||||
</div>
|
||||
<pre className="p-4 text-sm text-gray-300 font-mono overflow-x-auto">
|
||||
<code>{code}</code>
|
||||
</pre>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
function MethodCard({
|
||||
name,
|
||||
signature,
|
||||
description,
|
||||
params,
|
||||
returns,
|
||||
example,
|
||||
}: {
|
||||
name: string
|
||||
signature: string
|
||||
description: string
|
||||
params?: { name: string; type: string; description: string }[]
|
||||
returns?: string
|
||||
example?: string
|
||||
}) {
|
||||
return (
|
||||
<div className="bg-white rounded-xl border border-gray-200 overflow-hidden">
|
||||
<div className="px-6 py-4 border-b border-gray-200 bg-gray-50">
|
||||
<code className="text-violet-600 font-mono font-semibold">{name}</code>
|
||||
</div>
|
||||
<div className="p-6">
|
||||
<div className="bg-gray-100 rounded-lg p-3 mb-4">
|
||||
<code className="text-sm font-mono text-gray-800">{signature}</code>
|
||||
</div>
|
||||
<p className="text-gray-600 mb-4">{description}</p>
|
||||
|
||||
{params && params.length > 0 && (
|
||||
<div className="mb-4">
|
||||
<h4 className="font-medium text-gray-900 mb-2">Parameter</h4>
|
||||
<table className="min-w-full">
|
||||
<tbody className="divide-y divide-gray-200">
|
||||
{params.map((param) => (
|
||||
<tr key={param.name}>
|
||||
<td className="py-2 pr-4">
|
||||
<code className="text-sm text-violet-600">{param.name}</code>
|
||||
</td>
|
||||
<td className="py-2 pr-4">
|
||||
<code className="text-sm text-gray-500">{param.type}</code>
|
||||
</td>
|
||||
<td className="py-2 text-sm text-gray-600">{param.description}</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{returns && (
|
||||
<div className="mb-4">
|
||||
<h4 className="font-medium text-gray-900 mb-2">Rueckgabe</h4>
|
||||
<code className="text-sm text-gray-600">{returns}</code>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{example && (
|
||||
<div>
|
||||
<h4 className="font-medium text-gray-900 mb-2">Beispiel</h4>
|
||||
<CodeBlock code={example} />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default function APIReferencePage() {
|
||||
return (
|
||||
<div className="min-h-screen bg-gray-50 flex">
|
||||
<SDKDocsSidebar />
|
||||
|
||||
<main className="flex-1 ml-64">
|
||||
<div className="max-w-4xl mx-auto px-8 py-12">
|
||||
<h1 className="text-3xl font-bold text-gray-900 mb-2">API Referenz</h1>
|
||||
<p className="text-lg text-gray-600 mb-8">
|
||||
Vollstaendige Dokumentation aller Methoden und Konfigurationsoptionen des Consent SDK.
|
||||
</p>
|
||||
|
||||
{/* ConsentManager */}
|
||||
<section className="mb-12">
|
||||
<h2 className="text-2xl font-semibold text-gray-900 mb-6">ConsentManager</h2>
|
||||
<p className="text-gray-600 mb-6">
|
||||
Die zentrale Klasse fuer das Consent Management. Verwaltet Einwilligungen, Script-Blocking und Events.
|
||||
</p>
|
||||
|
||||
{/* Constructor */}
|
||||
<div className="space-y-6">
|
||||
<MethodCard
|
||||
name="constructor"
|
||||
signature="new ConsentManager(config: ConsentConfig)"
|
||||
description="Erstellt eine neue Instanz des ConsentManagers mit der angegebenen Konfiguration."
|
||||
params={[
|
||||
{
|
||||
name: 'config',
|
||||
type: 'ConsentConfig',
|
||||
description: 'Konfigurationsobjekt fuer den Manager',
|
||||
},
|
||||
]}
|
||||
example={`const consent = new ConsentManager({
|
||||
apiEndpoint: 'https://api.example.com/consent',
|
||||
siteId: 'my-site',
|
||||
debug: true,
|
||||
});`}
|
||||
/>
|
||||
|
||||
<MethodCard
|
||||
name="init"
|
||||
signature="async init(): Promise<void>"
|
||||
description="Initialisiert das SDK, laedt bestehenden Consent und startet das Script-Blocking. Zeigt den Banner an falls noetig."
|
||||
example={`await consent.init();`}
|
||||
/>
|
||||
|
||||
<MethodCard
|
||||
name="hasConsent"
|
||||
signature="hasConsent(category: ConsentCategory): boolean"
|
||||
description="Prueft ob Einwilligung fuer eine Kategorie vorliegt."
|
||||
params={[
|
||||
{
|
||||
name: 'category',
|
||||
type: 'ConsentCategory',
|
||||
description: 'essential | functional | analytics | marketing | social',
|
||||
},
|
||||
]}
|
||||
returns="boolean - true wenn Einwilligung vorliegt"
|
||||
example={`if (consent.hasConsent('analytics')) {
|
||||
// Analytics laden
|
||||
loadGoogleAnalytics();
|
||||
}`}
|
||||
/>
|
||||
|
||||
<MethodCard
|
||||
name="setConsent"
|
||||
signature="async setConsent(input: ConsentInput): Promise<void>"
|
||||
description="Setzt die Einwilligungen und speichert sie lokal sowie auf dem Server."
|
||||
params={[
|
||||
{
|
||||
name: 'input',
|
||||
type: 'ConsentInput',
|
||||
description: 'Objekt mit Kategorien und optionalen Vendors',
|
||||
},
|
||||
]}
|
||||
example={`await consent.setConsent({
|
||||
essential: true,
|
||||
functional: true,
|
||||
analytics: true,
|
||||
marketing: false,
|
||||
social: false,
|
||||
});`}
|
||||
/>
|
||||
|
||||
<MethodCard
|
||||
name="acceptAll"
|
||||
signature="async acceptAll(): Promise<void>"
|
||||
description="Akzeptiert alle Consent-Kategorien und schliesst den Banner."
|
||||
example={`document.getElementById('accept-all').addEventListener('click', async () => {
|
||||
await consent.acceptAll();
|
||||
});`}
|
||||
/>
|
||||
|
||||
<MethodCard
|
||||
name="rejectAll"
|
||||
signature="async rejectAll(): Promise<void>"
|
||||
description="Lehnt alle nicht-essentiellen Kategorien ab und schliesst den Banner."
|
||||
example={`document.getElementById('reject-all').addEventListener('click', async () => {
|
||||
await consent.rejectAll();
|
||||
});`}
|
||||
/>
|
||||
|
||||
<MethodCard
|
||||
name="revokeAll"
|
||||
signature="async revokeAll(): Promise<void>"
|
||||
description="Widerruft alle Einwilligungen und loescht den gespeicherten Consent."
|
||||
example={`document.getElementById('revoke').addEventListener('click', async () => {
|
||||
await consent.revokeAll();
|
||||
location.reload();
|
||||
});`}
|
||||
/>
|
||||
|
||||
<MethodCard
|
||||
name="on"
|
||||
signature="on<T>(event: ConsentEventType, callback: (data: T) => void): () => void"
|
||||
description="Registriert einen Event-Listener. Gibt eine Unsubscribe-Funktion zurueck."
|
||||
params={[
|
||||
{
|
||||
name: 'event',
|
||||
type: 'ConsentEventType',
|
||||
description: 'init | change | accept_all | reject_all | banner_show | banner_hide | etc.',
|
||||
},
|
||||
{
|
||||
name: 'callback',
|
||||
type: 'function',
|
||||
description: 'Callback-Funktion die bei Event aufgerufen wird',
|
||||
},
|
||||
]}
|
||||
returns="() => void - Funktion zum Entfernen des Listeners"
|
||||
example={`const unsubscribe = consent.on('change', (state) => {
|
||||
console.log('Consent geaendert:', state);
|
||||
});
|
||||
|
||||
// Spaeter: Listener entfernen
|
||||
unsubscribe();`}
|
||||
/>
|
||||
|
||||
<MethodCard
|
||||
name="getConsent"
|
||||
signature="getConsent(): ConsentState | null"
|
||||
description="Gibt den aktuellen Consent-Status zurueck oder null falls kein Consent vorliegt."
|
||||
returns="ConsentState | null"
|
||||
example={`const state = consent.getConsent();
|
||||
if (state) {
|
||||
console.log('Consent ID:', state.consentId);
|
||||
console.log('Kategorien:', state.categories);
|
||||
}`}
|
||||
/>
|
||||
|
||||
<MethodCard
|
||||
name="exportConsent"
|
||||
signature="async exportConsent(): Promise<string>"
|
||||
description="Exportiert alle Consent-Daten als JSON-String (DSGVO Art. 20 Datenportabilitaet)."
|
||||
returns="Promise<string> - JSON-formatierter Export"
|
||||
example={`const exportData = await consent.exportConsent();
|
||||
downloadAsFile(exportData, 'consent-export.json');`}
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Configuration */}
|
||||
<section className="mb-12">
|
||||
<h2 className="text-2xl font-semibold text-gray-900 mb-6">Konfiguration</h2>
|
||||
|
||||
<div className="bg-white rounded-xl border border-gray-200 overflow-hidden">
|
||||
<table className="min-w-full divide-y divide-gray-200">
|
||||
<thead className="bg-gray-50">
|
||||
<tr>
|
||||
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">
|
||||
Option
|
||||
</th>
|
||||
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">
|
||||
Typ
|
||||
</th>
|
||||
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">
|
||||
Default
|
||||
</th>
|
||||
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">
|
||||
Beschreibung
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="divide-y divide-gray-200">
|
||||
<tr>
|
||||
<td className="px-6 py-4">
|
||||
<code className="text-sm text-violet-600">apiEndpoint</code>
|
||||
</td>
|
||||
<td className="px-6 py-4">
|
||||
<code className="text-sm text-gray-500">string</code>
|
||||
</td>
|
||||
<td className="px-6 py-4 text-sm text-gray-500">erforderlich</td>
|
||||
<td className="px-6 py-4 text-sm text-gray-600">URL des Consent-Backends</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className="px-6 py-4">
|
||||
<code className="text-sm text-violet-600">siteId</code>
|
||||
</td>
|
||||
<td className="px-6 py-4">
|
||||
<code className="text-sm text-gray-500">string</code>
|
||||
</td>
|
||||
<td className="px-6 py-4 text-sm text-gray-500">erforderlich</td>
|
||||
<td className="px-6 py-4 text-sm text-gray-600">Eindeutige Site-ID</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className="px-6 py-4">
|
||||
<code className="text-sm text-violet-600">debug</code>
|
||||
</td>
|
||||
<td className="px-6 py-4">
|
||||
<code className="text-sm text-gray-500">boolean</code>
|
||||
</td>
|
||||
<td className="px-6 py-4 text-sm text-gray-500">false</td>
|
||||
<td className="px-6 py-4 text-sm text-gray-600">Aktiviert Debug-Logging</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className="px-6 py-4">
|
||||
<code className="text-sm text-violet-600">language</code>
|
||||
</td>
|
||||
<td className="px-6 py-4">
|
||||
<code className="text-sm text-gray-500">string</code>
|
||||
</td>
|
||||
<td className="px-6 py-4 text-sm text-gray-500">'de'</td>
|
||||
<td className="px-6 py-4 text-sm text-gray-600">Sprache fuer UI-Texte</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className="px-6 py-4">
|
||||
<code className="text-sm text-violet-600">consent.rememberDays</code>
|
||||
</td>
|
||||
<td className="px-6 py-4">
|
||||
<code className="text-sm text-gray-500">number</code>
|
||||
</td>
|
||||
<td className="px-6 py-4 text-sm text-gray-500">365</td>
|
||||
<td className="px-6 py-4 text-sm text-gray-600">Gueltigkeitsdauer in Tagen</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className="px-6 py-4">
|
||||
<code className="text-sm text-violet-600">consent.recheckAfterDays</code>
|
||||
</td>
|
||||
<td className="px-6 py-4">
|
||||
<code className="text-sm text-gray-500">number</code>
|
||||
</td>
|
||||
<td className="px-6 py-4 text-sm text-gray-500">180</td>
|
||||
<td className="px-6 py-4 text-sm text-gray-600">Erneute Abfrage nach X Tagen</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Events */}
|
||||
<section className="mb-12">
|
||||
<h2 className="text-2xl font-semibold text-gray-900 mb-6">Events</h2>
|
||||
|
||||
<div className="bg-white rounded-xl border border-gray-200 overflow-hidden">
|
||||
<table className="min-w-full divide-y divide-gray-200">
|
||||
<thead className="bg-gray-50">
|
||||
<tr>
|
||||
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">
|
||||
Event
|
||||
</th>
|
||||
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">
|
||||
Daten
|
||||
</th>
|
||||
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">
|
||||
Beschreibung
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="divide-y divide-gray-200">
|
||||
<tr>
|
||||
<td className="px-6 py-4">
|
||||
<code className="text-sm text-violet-600">init</code>
|
||||
</td>
|
||||
<td className="px-6 py-4">
|
||||
<code className="text-sm text-gray-500">ConsentState | null</code>
|
||||
</td>
|
||||
<td className="px-6 py-4 text-sm text-gray-600">SDK initialisiert</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className="px-6 py-4">
|
||||
<code className="text-sm text-violet-600">change</code>
|
||||
</td>
|
||||
<td className="px-6 py-4">
|
||||
<code className="text-sm text-gray-500">ConsentState</code>
|
||||
</td>
|
||||
<td className="px-6 py-4 text-sm text-gray-600">Consent geaendert</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className="px-6 py-4">
|
||||
<code className="text-sm text-violet-600">accept_all</code>
|
||||
</td>
|
||||
<td className="px-6 py-4">
|
||||
<code className="text-sm text-gray-500">ConsentState</code>
|
||||
</td>
|
||||
<td className="px-6 py-4 text-sm text-gray-600">Alle akzeptiert</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className="px-6 py-4">
|
||||
<code className="text-sm text-violet-600">reject_all</code>
|
||||
</td>
|
||||
<td className="px-6 py-4">
|
||||
<code className="text-sm text-gray-500">ConsentState</code>
|
||||
</td>
|
||||
<td className="px-6 py-4 text-sm text-gray-600">Alle abgelehnt</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className="px-6 py-4">
|
||||
<code className="text-sm text-violet-600">banner_show</code>
|
||||
</td>
|
||||
<td className="px-6 py-4">
|
||||
<code className="text-sm text-gray-500">undefined</code>
|
||||
</td>
|
||||
<td className="px-6 py-4 text-sm text-gray-600">Banner angezeigt</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className="px-6 py-4">
|
||||
<code className="text-sm text-violet-600">banner_hide</code>
|
||||
</td>
|
||||
<td className="px-6 py-4">
|
||||
<code className="text-sm text-gray-500">undefined</code>
|
||||
</td>
|
||||
<td className="px-6 py-4 text-sm text-gray-600">Banner versteckt</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className="px-6 py-4">
|
||||
<code className="text-sm text-violet-600">error</code>
|
||||
</td>
|
||||
<td className="px-6 py-4">
|
||||
<code className="text-sm text-gray-500">Error</code>
|
||||
</td>
|
||||
<td className="px-6 py-4 text-sm text-gray-600">Fehler aufgetreten</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Types */}
|
||||
<section>
|
||||
<h2 className="text-2xl font-semibold text-gray-900 mb-6">TypeScript Types</h2>
|
||||
<CodeBlock
|
||||
code={`// Consent-Kategorien
|
||||
type ConsentCategory = 'essential' | 'functional' | 'analytics' | 'marketing' | 'social';
|
||||
|
||||
// Consent-Status
|
||||
interface ConsentState {
|
||||
categories: Record<ConsentCategory, boolean>;
|
||||
vendors: Record<string, boolean>;
|
||||
timestamp: string;
|
||||
version: string;
|
||||
consentId?: string;
|
||||
expiresAt?: string;
|
||||
}
|
||||
|
||||
// Konfiguration
|
||||
interface ConsentConfig {
|
||||
apiEndpoint: string;
|
||||
siteId: string;
|
||||
debug?: boolean;
|
||||
language?: string;
|
||||
fallbackLanguage?: string;
|
||||
ui?: ConsentUIConfig;
|
||||
consent?: ConsentBehaviorConfig;
|
||||
onConsentChange?: (state: ConsentState) => void;
|
||||
onBannerShow?: () => void;
|
||||
onBannerHide?: () => void;
|
||||
onError?: (error: Error) => void;
|
||||
}`}
|
||||
/>
|
||||
</section>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user