Files
AfiS-Aktensystem/web/components/export/ExportPanel.tsx
T
Harlekin e0b03ea336
Prüfung / Lint, Typen, Tests (push) Canceled after 0s
Prüfung / Images bauen (pdf) (push) Canceled after 0s
Prüfung / Images bauen (web) (push) Canceled after 0s
Prüfung / Images bauen (worker) (push) Canceled after 0s
Images / bauen (pdf, docker/pdf.Dockerfile) (push) Canceled after 0s
Images / bauen (web, docker/web.Dockerfile) (push) Canceled after 0s
Images / bauen (worker, docker/worker.Dockerfile) (push) Canceled after 0s
Gedankenstriche durch Bindestriche ersetzt
375 Vorkommen in 210 Dateien. Betrifft Kommentare, Oberflaechentexte und die
README; an keiner Stelle Bedeutung, nur Zeichensetzung.
2026-09-04 08:54:52 +02:00

95 lines
3.1 KiB
TypeScript

'use client'
import { useActionState, useEffect, useState } from 'react'
import { exportText } from '@/lib/i18n/export'
import { useStream } from '@/components/realtime/useStream'
import { requestExportAction, type ExportState } from '@/app/(app)/export/actions'
/**
* Export anfordern und auf das Ergebnis warten.
*
* Kein Fortschrittsbalken, der eine Zahl erfindet: der Auftrag hat drei
* Zustände, und die stehen da. Fertig meldet der Ereignisstrom, dann steht
* der Knopf zum Herunterladen bereit - automatisch losladen wäre unhöflich,
* wenn jemand die Seite inzwischen wieder verlassen hat und zurückkommt.
*/
export function ExportPanel({
target,
topic,
}: {
target: { kind: 'CASE'; caseNumber: string } | { kind: 'DOCUMENT'; documentNumber: string }
/** Eigenes Nutzerthema: der Export geht nur den Auftraggeber an. */
topic: string
}) {
const [state, action, pending] = useActionState<ExportState | null, FormData>(
requestExportAction,
null,
)
const [fertig, setFertig] = useState<string | null>(null)
const [gescheitert, setGescheitert] = useState(false)
useStream([topic], {
'export.ready': (data) => {
const ereignis = data as { id: string }
if (state?.jobId && ereignis.id !== state.jobId) return
setFertig(ereignis.id)
},
})
// Nach der Freigabe eines wartenden Auftrags kommt das Ereignis später; bis
// dahin bleibt der Hinweis stehen.
useEffect(() => {
if (state?.status === 'READY' && state.jobId) setFertig(state.jobId)
if (state?.status === 'FAILED') setGescheitert(true)
}, [state])
const wartetAufFreigabe = state?.status === 'PENDING_APPROVAL'
return (
<div className="border border-line p-4">
<form action={action}>
<input type="hidden" name="kind" value={target.kind} />
{target.kind === 'CASE' ? (
<input type="hidden" name="caseNumber" value={target.caseNumber} />
) : (
<input type="hidden" name="documentNumber" value={target.documentNumber} />
)}
<button
type="submit"
disabled={pending || Boolean(state?.jobId)}
className="btn btn-sm btn-primary"
>
{pending ? exportText.preparing : exportText.asPdf}
</button>
</form>
<div className="mt-3 text-2xs">
{state?.error ? <p className="text-stamp-4">{state.error}</p> : null}
{wartetAufFreigabe ? (
<div>
<p className="font-condensed text-stamp-3">{exportText.waitingApproval}</p>
<p className="mt-1 text-text-dim">{exportText.waitingApprovalHint}</p>
</div>
) : null}
{state?.jobId && !fertig && !wartetAufFreigabe && !gescheitert ? (
<p className="text-text-dim">{exportText.preparing}</p>
) : null}
{gescheitert ? <p className="text-stamp-4">{exportText.failed}</p> : null}
{fertig ? (
<a
href={`/api/exports/${fertig}`}
className="border border-line bg-raised px-3 py-1 font-condensed text-accent"
>
{exportText.download}
</a>
) : null}
</div>
</div>
)
}