From 4921d1c0528d14b4b1d48bbb3fc806fa55eb883b Mon Sep 17 00:00:00 2001 From: Sharang Parnerkar <30073382+mighty840@users.noreply.github.com> Date: Tue, 14 Apr 2026 22:55:12 +0200 Subject: [PATCH] refactor(admin): split dsr page.tsx into colocated components Extract TabNavigation, StatCard, RequestCard, FilterBar, DSRCreateModal, DSRDetailPanel, DSRHeaderActions, and banner components (LoadingSpinner, SettingsTab, OverdueAlert, DeadlineInfoBox, EmptyState) into _components/ so page.tsx drops from 1019 to 247 LOC (under the 300 soft target). Co-Authored-By: Claude Opus 4.6 (1M context) --- .../app/sdk/dsr/_components/DSRBanners.tsx | 136 +++ .../sdk/dsr/_components/DSRCreateModal.tsx | 187 ++++ .../sdk/dsr/_components/DSRDetailPanel.tsx | 211 +++++ .../sdk/dsr/_components/DSRHeaderActions.tsx | 35 + .../app/sdk/dsr/_components/FilterBar.tsx | 81 ++ .../app/sdk/dsr/_components/RequestCard.tsx | 121 +++ .../app/sdk/dsr/_components/StatCard.tsx | 51 ++ .../app/sdk/dsr/_components/TabNavigation.tsx | 45 + admin-compliance/app/sdk/dsr/_types.ts | 8 + admin-compliance/app/sdk/dsr/page.tsx | 844 +----------------- 10 files changed, 911 insertions(+), 808 deletions(-) create mode 100644 admin-compliance/app/sdk/dsr/_components/DSRBanners.tsx create mode 100644 admin-compliance/app/sdk/dsr/_components/DSRCreateModal.tsx create mode 100644 admin-compliance/app/sdk/dsr/_components/DSRDetailPanel.tsx create mode 100644 admin-compliance/app/sdk/dsr/_components/DSRHeaderActions.tsx create mode 100644 admin-compliance/app/sdk/dsr/_components/FilterBar.tsx create mode 100644 admin-compliance/app/sdk/dsr/_components/RequestCard.tsx create mode 100644 admin-compliance/app/sdk/dsr/_components/StatCard.tsx create mode 100644 admin-compliance/app/sdk/dsr/_components/TabNavigation.tsx create mode 100644 admin-compliance/app/sdk/dsr/_types.ts diff --git a/admin-compliance/app/sdk/dsr/_components/DSRBanners.tsx b/admin-compliance/app/sdk/dsr/_components/DSRBanners.tsx new file mode 100644 index 0000000..df734c0 --- /dev/null +++ b/admin-compliance/app/sdk/dsr/_components/DSRBanners.tsx @@ -0,0 +1,136 @@ +'use client' + +import type { DSRType, DSRStatus } from '@/lib/sdk/dsr/types' + +export function LoadingSpinner() { + return ( +
+ + + + +
+ ) +} + +export function SettingsTab() { + return ( +
+
+ + + + +
+

Einstellungen

+

+ DSR-Portal-Einstellungen, E-Mail-Vorlagen und Workflow-Konfiguration + werden in einer spaeteren Version verfuegbar sein. +

+
+ ) +} + +export function OverdueAlert({ + overdueCount, + onShowOverdue, +}: { + overdueCount: number + onShowOverdue: () => void +}) { + return ( +
+
+ + + +
+
+

+ Achtung: {overdueCount} ueberfaellige Anfrage(n) +

+

+ Die gesetzliche Frist ist abgelaufen. Handeln Sie umgehend, um Bussgelder zu vermeiden. +

+
+ +
+ ) +} + +export function DeadlineInfoBox() { + return ( +
+
+ + + +
+

Fristen beachten

+

+ Nach Art. 12 DSGVO muessen Anfragen innerhalb von einem Monat beantwortet werden. + Eine Verlaengerung um zwei weitere Monate ist bei komplexen Anfragen moeglich, + sofern der Betroffene innerhalb eines Monats darueber informiert wird. +

+
+
+
+ ) +} + +export function EmptyState({ + selectedType, + selectedStatus, + selectedPriority, + onClearFilters, + onOpenCreate, +}: { + selectedType: DSRType | 'all' + selectedStatus: DSRStatus | 'all' + selectedPriority: string + onClearFilters: () => void + onOpenCreate: () => void +}) { + const hasFilters = + selectedType !== 'all' || selectedStatus !== 'all' || selectedPriority !== 'all' + + return ( +
+
+ + + +
+

Keine Anfragen gefunden

+

+ {hasFilters + ? 'Passen Sie die Filter an oder' + : 'Es sind noch keine Anfragen vorhanden.' + } +

+ {hasFilters ? ( + + ) : ( + + )} +
+ ) +} diff --git a/admin-compliance/app/sdk/dsr/_components/DSRCreateModal.tsx b/admin-compliance/app/sdk/dsr/_components/DSRCreateModal.tsx new file mode 100644 index 0000000..07a08a8 --- /dev/null +++ b/admin-compliance/app/sdk/dsr/_components/DSRCreateModal.tsx @@ -0,0 +1,187 @@ +'use client' + +import React, { useState } from 'react' +import { createSDKDSR } from '@/lib/sdk/dsr/api' + +export function DSRCreateModal({ + onClose, + onSuccess +}: { + onClose: () => void + onSuccess: () => void +}) { + const [type, setType] = useState('access') + const [subjectName, setSubjectName] = useState('') + const [subjectEmail, setSubjectEmail] = useState('') + const [description, setDescription] = useState('') + const [source, setSource] = useState('web_form') + const [isSaving, setIsSaving] = useState(false) + const [error, setError] = useState(null) + + const deadline = new Date() + deadline.setDate(deadline.getDate() + 30) + const deadlineStr = deadline.toLocaleDateString('de-DE') + + const handleSubmit = async (e: React.FormEvent) => { + e.preventDefault() + if (!subjectName.trim() || !subjectEmail.trim()) return + + setIsSaving(true) + setError(null) + try { + await createSDKDSR({ + type, + requester: { name: subjectName.trim(), email: subjectEmail.trim() }, + requestText: description.trim(), + source + }) + onSuccess() + } catch (err: unknown) { + setError(err instanceof Error ? err.message : 'Unbekannter Fehler') + } finally { + setIsSaving(false) + } + } + + return ( +
+ {/* Backdrop */} +
+ + {/* Modal */} +
+
+
+

Neue Anfrage anlegen

+ +
+ + {error && ( +
+ {error} +
+ )} + +
+ {/* Type */} +
+ + +
+ + {/* Subject Name */} +
+ + setSubjectName(e.target.value)} + required + className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-purple-500 focus:border-purple-500 text-sm" + placeholder="Vor- und Nachname" + /> +
+ + {/* Subject Email */} +
+ + setSubjectEmail(e.target.value)} + required + className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-purple-500 focus:border-purple-500 text-sm" + placeholder="email@beispiel.de" + /> +
+ + {/* Description */} +
+ +