Files
files/nextjs/app/%5Frequest/[id]/page.js
2026-03-28 08:43:04 +01:00

147 lines
4.4 KiB
JavaScript

import { get, runCleanupIfNeeded } from '@/src/lib/db.js';
import { formatTimestamp, readSearchParam } from '@/src/lib/format.js';
import { StatusMessage } from '@/app/manage/_components/status-message.js';
export const dynamic = 'force-dynamic';
function normalizeRequestId(value) {
return String(value || '').trim().toUpperCase();
}
function isValidRequestId(value) {
return /^[A-Z2-7]{6,24}$/.test(value);
}
function requestState(requestEntry, now) {
if (!requestEntry) {
return 'missing';
}
if (Number(requestEntry.completed_at || 0) > 0) {
return 'completed';
}
if (Number(requestEntry.expires_at || 0) <= now) {
return 'expired';
}
return 'open';
}
export default async function UploadRequestPage({ params, searchParams }) {
await runCleanupIfNeeded();
const resolvedParams = await params;
const requestId = normalizeRequestId(resolvedParams.id);
if (!isValidRequestId(requestId)) {
return (
<main className="page-shell narrow">
<section className="panel centered">
<h1>Ungültige Anfrage</h1>
<p className="muted">Die Upload-Anfrage konnte nicht verarbeitet werden.</p>
</section>
</main>
);
}
const requestEntry = await get(
`SELECT id, note, created_at, expires_at, completed_at, uploaded_original_name
FROM upload_requests
WHERE id = ?`,
[requestId]
);
const now = Date.now();
const state = requestState(requestEntry, now);
const resolvedSearchParams = await searchParams;
const error = readSearchParam(resolvedSearchParams, 'error');
const success = readSearchParam(resolvedSearchParams, 'success');
if (state === 'missing') {
return (
<main className="page-shell narrow">
<StatusMessage error={error} success={success} />
<section className="panel centered">
<h1>Anfrage nicht gefunden</h1>
<p className="muted">Diese Upload-Anfrage existiert nicht oder wurde entfernt.</p>
</section>
</main>
);
}
return (
<main className="page-shell narrow">
<header className="page-header">
<div className="header-main">
<h1>Datei-Anfrage</h1>
<p className="muted">Anfrage-ID: {requestEntry.id}</p>
</div>
</header>
<StatusMessage error={error} success={success} />
<section className="panel">
<div className="info-stack">
<div className="info-card">
<strong>Status</strong>
<span className="muted">
{state === 'open' ? 'Offen' : state === 'completed' ? 'Bereits abgeschlossen' : 'Abgelaufen'}
</span>
</div>
<div className="info-card">
<strong>Erstellt</strong>
<span className="muted">{formatTimestamp(requestEntry.created_at)}</span>
</div>
<div className="info-card">
<strong>Gültig bis</strong>
<span className="muted">{formatTimestamp(requestEntry.expires_at)}</span>
</div>
{requestEntry.note ? (
<div className="info-card">
<strong>Notiz</strong>
<span className="muted">{requestEntry.note}</span>
</div>
) : null}
</div>
</section>
{state === 'open' ? (
<section className="panel panel-spotlight">
<h2>Datei hochladen</h2>
<form
className="form-grid"
method="post"
action={`/_request/${encodeURIComponent(requestEntry.id)}/upload`}
encType="multipart/form-data"
>
<label className="field">
Datei
<input className="input" type="file" name="file" required />
</label>
<label className="field">
Dein Name (optional)
<input className="input" name="fulfilledBy" placeholder="z. B. Max Mustermann" />
</label>
<button className="btn" type="submit">
Datei senden
</button>
</form>
</section>
) : null}
{state === 'completed' ? (
<section className="panel centered">
<h2>Vielen Dank</h2>
<p className="muted">
{requestEntry.uploaded_original_name
? `Diese Anfrage wurde bereits mit „${requestEntry.uploaded_original_name}“ abgeschlossen.`
: 'Diese Anfrage wurde bereits abgeschlossen.'}
</p>
</section>
) : null}
</main>
);
}