mirror of
https://github.com/complexcaresolutions/dak.c2s.git
synced 2026-03-17 18:23:42 +00:00
feat: add disclosure request UI and field visibility for dak_mitarbeiter
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
f2219b487b
commit
62a56f3fc9
2 changed files with 98 additions and 20 deletions
|
|
@ -22,6 +22,7 @@ import { Alert, AlertDescription } from '@/components/ui/alert'
|
|||
import { CASE_SECTIONS } from './cases/fieldConfig'
|
||||
import { useInlineEdit } from './cases/useInlineEdit'
|
||||
import { EditableField } from './cases/EditableField'
|
||||
import { requestDisclosure } from '@/services/disclosureService'
|
||||
|
||||
const FALLGRUPPEN_LABELS: Record<string, string> = {
|
||||
onko: 'Onkologie',
|
||||
|
|
@ -396,6 +397,18 @@ function CaseDetail({
|
|||
<StatusBadges c={caseData} />
|
||||
</div>
|
||||
|
||||
{/* Disclosure status / request */}
|
||||
{!isAdmin && caseData.disclosure_granted && caseData.disclosure_expires_at && (
|
||||
<Alert>
|
||||
<AlertDescription>
|
||||
Personendaten sichtbar bis {formatDateTime(caseData.disclosure_expires_at)}
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
)}
|
||||
{!isAdmin && !caseData.disclosure_granted && (
|
||||
<DisclosureRequestButton caseId={caseData.id} />
|
||||
)}
|
||||
|
||||
{/* Static metadata (always read-only) */}
|
||||
<div className="grid grid-cols-2 gap-3 text-sm">
|
||||
<ReadOnlyField label="Fall-ID" value={caseData.fall_id} />
|
||||
|
|
@ -405,23 +418,30 @@ function CaseDetail({
|
|||
</div>
|
||||
|
||||
{/* Editable sections from config */}
|
||||
{CASE_SECTIONS.map((section) => (
|
||||
<div key={section.title} className="border-t pt-3 space-y-3">
|
||||
<h3 className="text-sm font-semibold">{section.title}</h3>
|
||||
<div className="grid grid-cols-2 gap-3 text-sm">
|
||||
{section.fields.map((field) => (
|
||||
<div key={field.key} className={field.colSpan === 2 ? 'col-span-2' : ''}>
|
||||
<EditableField
|
||||
field={field}
|
||||
value={editing ? formValues[field.key] : caseData[field.key]}
|
||||
editable={canEditField(field, isAdmin)}
|
||||
onChange={setFieldValue}
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
{CASE_SECTIONS.map((section) => {
|
||||
const visibleFields = section.fields.filter((field) => {
|
||||
if (field.visibleTo === 'admin' && !isAdmin && !caseData.disclosure_granted) return false
|
||||
return true
|
||||
})
|
||||
if (visibleFields.length === 0) return null
|
||||
return (
|
||||
<div key={section.title} className="border-t pt-3 space-y-3">
|
||||
<h3 className="text-sm font-semibold">{section.title}</h3>
|
||||
<div className="grid grid-cols-2 gap-3 text-sm">
|
||||
{visibleFields.map((field) => (
|
||||
<div key={field.key} className={field.colSpan === 2 ? 'col-span-2' : ''}>
|
||||
<EditableField
|
||||
field={field}
|
||||
value={editing ? formValues[field.key] : caseData[field.key]}
|
||||
editable={canEditField(field, isAdmin)}
|
||||
onChange={setFieldValue}
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
)
|
||||
})}
|
||||
|
||||
{/* ICD section — own endpoint with validation */}
|
||||
<div className="border-t pt-3 space-y-2">
|
||||
|
|
@ -474,6 +494,63 @@ function CaseDetail({
|
|||
)
|
||||
}
|
||||
|
||||
function DisclosureRequestButton({ caseId }: { caseId: number }) {
|
||||
const [open, setOpen] = useState(false)
|
||||
const [reason, setReason] = useState('')
|
||||
const [loading, setLoading] = useState(false)
|
||||
const [error, setError] = useState('')
|
||||
const [success, setSuccess] = useState(false)
|
||||
|
||||
const submit = async () => {
|
||||
if (!reason.trim()) return
|
||||
setLoading(true)
|
||||
setError('')
|
||||
try {
|
||||
await requestDisclosure(caseId, reason.trim())
|
||||
setSuccess(true)
|
||||
setOpen(false)
|
||||
} catch (err: any) {
|
||||
const detail = err.response?.data?.detail
|
||||
setError(typeof detail === 'string' ? detail : 'Fehler beim Senden der Anfrage')
|
||||
} finally {
|
||||
setLoading(false)
|
||||
}
|
||||
}
|
||||
|
||||
if (success) {
|
||||
return <p className="text-sm text-muted-foreground">Freigabe-Anfrage gesendet.</p>
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Button size="sm" variant="outline" onClick={() => setOpen(true)}>
|
||||
Personendaten anfordern
|
||||
</Button>
|
||||
{open && (
|
||||
<div className="space-y-2 border rounded-lg p-3">
|
||||
<p className="text-sm text-muted-foreground">
|
||||
Begründung für die Einsicht in Personendaten:
|
||||
</p>
|
||||
<Input
|
||||
value={reason}
|
||||
onChange={(e) => setReason(e.target.value)}
|
||||
placeholder="z.B. KVNR-Fehler, Identifikation nötig"
|
||||
/>
|
||||
{error && <p className="text-sm text-red-600">{error}</p>}
|
||||
<div className="flex gap-2">
|
||||
<Button size="sm" onClick={submit} disabled={loading || !reason.trim()}>
|
||||
{loading ? 'Senden...' : 'Anfrage senden'}
|
||||
</Button>
|
||||
<Button size="sm" variant="outline" onClick={() => { setOpen(false); setError('') }}>
|
||||
Abbrechen
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
function ReadOnlyField({ label, value }: { label: string; value: string | null | undefined }) {
|
||||
return (
|
||||
<div>
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ export interface FieldConfig {
|
|||
type: FieldType
|
||||
colSpan?: 1 | 2
|
||||
editableBy: 'admin' | 'all'
|
||||
visibleTo?: 'admin' | 'all'
|
||||
placeholder?: string
|
||||
options?: { value: string; label: string }[]
|
||||
}
|
||||
|
|
@ -28,10 +29,10 @@ export const CASE_SECTIONS: SectionConfig[] = [
|
|||
{
|
||||
title: 'Persönliche Daten',
|
||||
fields: [
|
||||
{ key: 'anrede', label: 'Anrede', type: 'select', editableBy: 'admin', options: ANREDE_OPTIONS },
|
||||
{ key: 'vorname', label: 'Vorname', type: 'text', editableBy: 'admin', placeholder: 'Vorname' },
|
||||
{ key: 'nachname', label: 'Nachname', type: 'text', editableBy: 'admin', placeholder: 'Nachname' },
|
||||
{ key: 'geburtsdatum', label: 'Geburtsdatum', type: 'date', editableBy: 'admin' },
|
||||
{ key: 'anrede', label: 'Anrede', type: 'select', editableBy: 'admin', visibleTo: 'admin', options: ANREDE_OPTIONS },
|
||||
{ key: 'vorname', label: 'Vorname', type: 'text', editableBy: 'admin', visibleTo: 'admin', placeholder: 'Vorname' },
|
||||
{ key: 'nachname', label: 'Nachname', type: 'text', editableBy: 'admin', visibleTo: 'admin', placeholder: 'Nachname' },
|
||||
{ key: 'geburtsdatum', label: 'Geburtsdatum', type: 'date', editableBy: 'admin', visibleTo: 'admin' },
|
||||
{ key: 'kvnr', label: 'KVNR', type: 'text', editableBy: 'all', placeholder: 'z.B. A123456789' },
|
||||
{ key: 'versicherung', label: 'Versicherung', type: 'text', editableBy: 'admin', placeholder: 'z.B. DAK' },
|
||||
],
|
||||
|
|
|
|||
Loading…
Reference in a new issue