refactor(admin): split dsr/[requestId] page.tsx into colocated components
Split the 854-line DSR detail page into colocated components under _components/ and a data-loading hook under _hooks/. No behavior changes. page.tsx is now 172 LOC, all extracted files under 300 LOC. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
204
admin-compliance/app/sdk/dsr/[requestId]/_hooks/useDSRDetail.ts
Normal file
204
admin-compliance/app/sdk/dsr/[requestId]/_hooks/useDSRDetail.ts
Normal file
@@ -0,0 +1,204 @@
|
||||
'use client'
|
||||
|
||||
import { useState, useEffect } from 'react'
|
||||
import {
|
||||
DSRRequest,
|
||||
DSRCommunication,
|
||||
DSRVerifyIdentityRequest,
|
||||
} from '@/lib/sdk/dsr/types'
|
||||
import {
|
||||
fetchSDKDSR,
|
||||
verifyDSRIdentity,
|
||||
assignDSR,
|
||||
extendDSRDeadline,
|
||||
completeDSR,
|
||||
rejectDSR,
|
||||
fetchDSRCommunications,
|
||||
sendDSRCommunication,
|
||||
fetchDSRExceptionChecks,
|
||||
initDSRExceptionChecks,
|
||||
updateDSRExceptionCheck,
|
||||
fetchDSRHistory,
|
||||
} from '@/lib/sdk/dsr/api'
|
||||
|
||||
export function useDSRDetail(requestId: string) {
|
||||
const [request, setRequest] = useState<DSRRequest | null>(null)
|
||||
const [communications, setCommunications] = useState<DSRCommunication[]>([])
|
||||
const [history, setHistory] = useState<any[]>([])
|
||||
const [exceptionChecks, setExceptionChecks] = useState<any[]>([])
|
||||
const [isLoading, setIsLoading] = useState(true)
|
||||
|
||||
// Load data from SDK backend
|
||||
useEffect(() => {
|
||||
const loadData = async () => {
|
||||
setIsLoading(true)
|
||||
try {
|
||||
const found = await fetchSDKDSR(requestId)
|
||||
if (found) {
|
||||
setRequest(found)
|
||||
// Load communications, history, and exception checks in parallel
|
||||
const [comms, hist] = await Promise.all([
|
||||
fetchDSRCommunications(requestId).catch(() => []),
|
||||
fetchDSRHistory(requestId).catch(() => []),
|
||||
])
|
||||
setCommunications(comms.map((c: any) => ({
|
||||
id: c.id,
|
||||
dsrId: c.dsr_id,
|
||||
type: c.communication_type,
|
||||
channel: c.channel,
|
||||
subject: c.subject,
|
||||
content: c.content,
|
||||
createdAt: c.created_at,
|
||||
createdBy: c.created_by,
|
||||
sentAt: c.sent_at,
|
||||
sentBy: c.sent_by,
|
||||
})))
|
||||
setHistory(hist)
|
||||
|
||||
// Load exception checks for erasure requests
|
||||
if (found.type === 'erasure') {
|
||||
try {
|
||||
const checks = await fetchDSRExceptionChecks(requestId)
|
||||
if (checks.length === 0) {
|
||||
// Auto-initialize if none exist
|
||||
const initialized = await initDSRExceptionChecks(requestId)
|
||||
setExceptionChecks(initialized)
|
||||
} else {
|
||||
setExceptionChecks(checks)
|
||||
}
|
||||
} catch {
|
||||
setExceptionChecks([])
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to load DSR:', error)
|
||||
} finally {
|
||||
setIsLoading(false)
|
||||
}
|
||||
}
|
||||
loadData()
|
||||
}, [requestId])
|
||||
|
||||
const handleVerifyIdentity = async (verification: DSRVerifyIdentityRequest) => {
|
||||
if (!request) return
|
||||
try {
|
||||
const updated = await verifyDSRIdentity(request.id, {
|
||||
method: verification.method,
|
||||
notes: verification.notes,
|
||||
document_ref: verification.documentRef,
|
||||
})
|
||||
setRequest(updated)
|
||||
fetchDSRHistory(requestId).then(setHistory).catch(() => {})
|
||||
} catch (err) {
|
||||
console.error('Failed to verify identity:', err)
|
||||
}
|
||||
}
|
||||
|
||||
const handleAssign = async () => {
|
||||
if (!request) return
|
||||
const assignee = prompt('Zuweisen an (Name/ID):')
|
||||
if (!assignee) return
|
||||
try {
|
||||
const updated = await assignDSR(request.id, assignee)
|
||||
setRequest(updated)
|
||||
fetchDSRHistory(requestId).then(setHistory).catch(() => {})
|
||||
} catch (err) {
|
||||
console.error('Failed to assign:', err)
|
||||
}
|
||||
}
|
||||
|
||||
const handleExtendDeadline = async () => {
|
||||
if (!request) return
|
||||
const reason = prompt('Grund fuer die Fristverlaengerung:')
|
||||
if (!reason) return
|
||||
const daysStr = prompt('Um wie viele Tage verlaengern? (Standard: 60)', '60')
|
||||
const days = parseInt(daysStr || '60', 10) || 60
|
||||
try {
|
||||
const updated = await extendDSRDeadline(request.id, reason, days)
|
||||
setRequest(updated)
|
||||
fetchDSRHistory(requestId).then(setHistory).catch(() => {})
|
||||
} catch (err) {
|
||||
console.error('Failed to extend deadline:', err)
|
||||
}
|
||||
}
|
||||
|
||||
const handleComplete = async () => {
|
||||
if (!request) return
|
||||
const summary = prompt('Zusammenfassung der Bearbeitung:')
|
||||
if (summary === null) return
|
||||
try {
|
||||
const updated = await completeDSR(request.id, summary || undefined)
|
||||
setRequest(updated)
|
||||
fetchDSRHistory(requestId).then(setHistory).catch(() => {})
|
||||
} catch (err) {
|
||||
console.error('Failed to complete:', err)
|
||||
}
|
||||
}
|
||||
|
||||
const handleReject = async () => {
|
||||
if (!request) return
|
||||
const reason = prompt('Ablehnungsgrund:')
|
||||
if (!reason) return
|
||||
const legalBasis = prompt('Rechtsgrundlage (optional):')
|
||||
try {
|
||||
const updated = await rejectDSR(request.id, reason, legalBasis || undefined)
|
||||
setRequest(updated)
|
||||
fetchDSRHistory(requestId).then(setHistory).catch(() => {})
|
||||
} catch (err) {
|
||||
console.error('Failed to reject:', err)
|
||||
}
|
||||
}
|
||||
|
||||
const handleSendCommunication = async (message: any) => {
|
||||
if (!request) return
|
||||
try {
|
||||
const result = await sendDSRCommunication(requestId, {
|
||||
communication_type: message.type || 'outgoing',
|
||||
channel: message.channel || 'email',
|
||||
subject: message.subject,
|
||||
content: message.content,
|
||||
})
|
||||
const newComm: DSRCommunication = {
|
||||
id: result.id,
|
||||
dsrId: result.dsr_id,
|
||||
type: result.communication_type,
|
||||
channel: result.channel,
|
||||
subject: result.subject,
|
||||
content: result.content,
|
||||
createdAt: result.created_at,
|
||||
createdBy: result.created_by || 'Current User',
|
||||
sentAt: result.sent_at,
|
||||
sentBy: result.sent_by,
|
||||
}
|
||||
setCommunications(prev => [newComm, ...prev])
|
||||
} catch (err) {
|
||||
console.error('Failed to send communication:', err)
|
||||
}
|
||||
}
|
||||
|
||||
const handleExceptionCheckChange = async (checkId: string, applies: boolean, notes?: string) => {
|
||||
try {
|
||||
const updated = await updateDSRExceptionCheck(requestId, checkId, { applies, notes })
|
||||
setExceptionChecks(prev => prev.map(c => c.id === checkId ? updated : c))
|
||||
} catch (err) {
|
||||
console.error('Failed to update exception check:', err)
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
request,
|
||||
setRequest,
|
||||
communications,
|
||||
history,
|
||||
exceptionChecks,
|
||||
isLoading,
|
||||
handleVerifyIdentity,
|
||||
handleAssign,
|
||||
handleExtendDeadline,
|
||||
handleComplete,
|
||||
handleReject,
|
||||
handleSendCommunication,
|
||||
handleExceptionCheckChange,
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user