CI / Web-Barrierefreiheitspruefung (axe, Tastatur, Reflow, Textabstaende) (pull_request) Canceled after 0s
CI / Web-Barrierefreiheitspruefung (axe, Tastatur, Reflow, Textabstaende) (push) Canceled after 0s
CI / Core-Modul (Build/Vet/Test) (push) Canceled after 0s
CI / DMS Security-Test-Gate (AC5, Merge-Gate) (push) Canceled after 0s
CI / DMS-Modul Supply-Chain-Scan (govulncheck) (push) Canceled after 0s
CI / Web (dms-browser) (push) Canceled after 0s
CI / Web (pdf-viewer) (push) Canceled after 0s
CI / Web (shl) (push) Canceled after 0s
Supply-Chain-Scan (npm) / npm-audit (push) Canceled after 0s
CI / Core-Modul (Build/Vet/Test) (pull_request) Canceled after 0s
CI / DMS Security-Test-Gate (AC5, Merge-Gate) (pull_request) Canceled after 0s
CI / DMS-Modul Supply-Chain-Scan (govulncheck) (pull_request) Canceled after 0s
CI / Web (dms-browser) (pull_request) Canceled after 0s
CI / Web (pdf-viewer) (pull_request) Canceled after 0s
CI / Web (shl) (pull_request) Canceled after 0s
Core-Schnittstellen-Vertragstests / contract-tests (pull_request) Canceled after 0s
Supply-Chain-Scan (Go) / govulncheck (pull_request) Canceled after 0s
Supply-Chain-Scan (npm) / npm-audit (pull_request) Canceled after 0s
Core-Pflichttest-Gate / pflichttest-gate (pull_request) Canceled after 0s
RBAC-Rollenhierarchie-Pflichtgate / rbac-policy-invariant (pull_request) Canceled after 0s
CI / DMS-Modul (Lint/Build/Test/Coverage/Artefakt) (push) Canceled after 0s
CI / DMS-Modul (Lint/Build/Test/Coverage/Artefakt) (pull_request) Canceled after 0s
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
102 lines
3.0 KiB
TypeScript
102 lines
3.0 KiB
TypeScript
// Duenner Client fuer die eigenen Backend-for-Frontend-Routen unter
|
|
// app/api — kein direkter Zugriff auf die Workflow-API vom Client aus
|
|
// (Rolle: "Alle Daten ausschliesslich ueber die oeffentliche
|
|
// Schnittstelle beziehen"), gleiches Muster wie web/workflow-approvals.
|
|
|
|
export class ApiError extends Error {
|
|
status: number;
|
|
constructor(message: string, status: number) {
|
|
super(message);
|
|
this.status = status;
|
|
}
|
|
}
|
|
|
|
export interface Reference {
|
|
ModuleName: string;
|
|
ObjectType: string;
|
|
ObjectID: string;
|
|
}
|
|
|
|
export interface Case {
|
|
ID: string;
|
|
InstanceID: string;
|
|
CaseNumber: string;
|
|
Responsible: string;
|
|
Status: string;
|
|
CreatedAt: string;
|
|
References: Reference[] | null;
|
|
}
|
|
|
|
export interface Note {
|
|
ID: string;
|
|
CaseID: string;
|
|
Author: string;
|
|
Body: string;
|
|
CreatedAt: string;
|
|
}
|
|
|
|
export interface Reminder {
|
|
ID: string;
|
|
Target: { CaseID: string; ModuleName: string; ObjectType: string; ObjectID: string };
|
|
DueAt: string;
|
|
Note: string;
|
|
TaskID: string;
|
|
Status: string;
|
|
CreatedBy: string;
|
|
CreatedAt: string;
|
|
CompletedAt: string | null;
|
|
}
|
|
|
|
export interface CaseDetail {
|
|
Case: Case;
|
|
Notes: Note[] | null;
|
|
Reminders: Reminder[] | null;
|
|
}
|
|
|
|
export type KanbanColumn = "open" | "this_week" | "overdue" | "done";
|
|
|
|
export interface KanbanItem {
|
|
Reminder: Reminder;
|
|
Column: KanbanColumn;
|
|
}
|
|
|
|
async function parse<T>(res: Response, fallback: string): Promise<T> {
|
|
const body = await res.json().catch(() => null);
|
|
if (!res.ok) {
|
|
throw new ApiError(body?.error ?? `${fallback} (${res.status})`, res.status);
|
|
}
|
|
return body as T;
|
|
}
|
|
|
|
export async function listCases(userId: string, status: string, responsible: string): Promise<Case[]> {
|
|
const params = new URLSearchParams({ userId });
|
|
if (status) params.set("status", status);
|
|
if (responsible) params.set("responsible", responsible);
|
|
const res = await fetch(`/api/cases?${params.toString()}`, { cache: "no-store" });
|
|
return parse<Case[]>(res, "Akten konnten nicht geladen werden");
|
|
}
|
|
|
|
export async function getCaseDetail(userId: string, id: string): Promise<CaseDetail> {
|
|
const res = await fetch(`/api/cases/${encodeURIComponent(id)}/overview?userId=${encodeURIComponent(userId)}`, {
|
|
cache: "no-store",
|
|
});
|
|
return parse<CaseDetail>(res, "Akte konnte nicht geladen werden");
|
|
}
|
|
|
|
export async function listKanban(userId: string): Promise<KanbanItem[]> {
|
|
const res = await fetch(`/api/reminders/kanban?userId=${encodeURIComponent(userId)}`, { cache: "no-store" });
|
|
return parse<KanbanItem[]>(res, "Wiedervorlagen konnten nicht geladen werden");
|
|
}
|
|
|
|
export async function moveReminder(userId: string, id: string, target: KanbanColumn): Promise<void> {
|
|
const res = await fetch(`/api/reminders/${encodeURIComponent(id)}/move?userId=${encodeURIComponent(userId)}`, {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify({ target }),
|
|
});
|
|
if (!res.ok) {
|
|
const body = await res.json().catch(() => null);
|
|
throw new ApiError(body?.error ?? `Verschieben fehlgeschlagen (${res.status})`, res.status);
|
|
}
|
|
}
|