Validation_Suite/validation-suite/frontend/atlas/lib/api.ts
2026-07-11 15:50:15 +02:00

184 lines
5.1 KiB
TypeScript

export const API_BASE = "/api/v1";
export type Entity = {
id: string;
created_at: string;
updated_at: string;
};
export type Customer = Entity & {
customer_type: "practice" | "clinic";
name: string;
city?: string | null;
phone?: string | null;
email?: string | null;
hygiene_officer?: string | null;
quality_manager?: string | null;
notes?: string | null;
};
export type Location = Entity & {
customer_id: string;
name: string;
street?: string | null;
postal_code?: string | null;
city?: string | null;
room?: string | null;
};
export type Contact = Entity & {
customer_id: string;
full_name: string;
function?: string | null;
email?: string | null;
phone?: string | null;
};
export type Device = Entity & {
customer_id: string;
location_id?: string | null;
manufacturer: string;
model: string;
serial_number: string;
device_type?: string | null;
year_built?: number | null;
commissioned_on?: string | null;
chamber_volume_liters?: number | null;
steam_generation?: string | null;
water_treatment?: string | null;
documentation?: string | null;
supplier?: string | null;
};
export type Equipment = Entity & {
kind: string;
manufacturer?: string | null;
model?: string | null;
serial_number: string;
calibrated_on?: string | null;
calibration_due_on?: string | null;
certificate_document_id?: string | null;
status: "green" | "yellow" | "red";
};
export type User = Entity & {
email: string;
first_name: string;
last_name: string;
role: "admin" | "pruefer" | "mitarbeiter" | "leser";
is_active: boolean;
must_change_password: boolean;
last_login_at?: string | null;
password_changed_at?: string | null;
};
export type ValidationItem = Entity & {
report_number: string;
customer_id: string;
location_id?: string | null;
contact_id?: string | null;
device_id?: string | null;
validation_type: string;
project?: string | null;
test_location?: string | null;
examiner_name?: string | null;
participants?: string | null;
operator_name?: string | null;
status: string;
result?: string | null;
scheduled_on?: string | null;
performed_on?: string | null;
next_validation_on?: string | null;
revalidation_interval_months: number;
next_validation_manually_overridden: boolean;
version: number;
previous_validation_id?: string | null;
equipment_ids: string[];
environment_conditions: Record<string, unknown>;
documentation_checklist: Record<string, unknown>[];
performance_checklist: Record<string, unknown>[];
programs: Record<string, unknown>[];
loading_patterns: Record<string, unknown>[];
measurement_data: Record<string, unknown>[];
drying: Record<string, unknown>;
recommendations: Record<string, unknown>[];
attachments: Record<string, unknown>[];
};
export function normalizeValidationPayload<T extends Record<string, unknown>>(values: T): T {
const optionalForeignKeys = ["contact_id", "examiner_id"];
return {
...values,
...Object.fromEntries(optionalForeignKeys.map((key) => [key, values[key] || null]))
};
}
export type Paginated<T> = {
items: T[];
total: number;
page: number;
page_size: number;
};
export async function login(email: string, password: string) {
const response = await fetch(`/api/login`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ email, password }),
credentials: "include"
});
if (!response.ok) {
const detail = await response.text();
const error = new Error(detail || `HTTP ${response.status}`) as Error & { status?: number };
error.status = response.status;
throw error;
}
return response.json() as Promise<{ user: User; expires_in: number }>;
}
export async function apiGet<T>(path: string, token: string): Promise<T> {
const response = await fetch(`${API_BASE}${path}`, {
cache: "no-store",
credentials: "include"
});
if (!response.ok) {
throw new Error(`API request failed: ${response.status}`);
}
return response.json() as Promise<T>;
}
export async function apiSend<T>(path: string, token: string, method: "POST" | "PUT", body: unknown): Promise<T> {
const response = await fetch(`${API_BASE}${path}`, {
method,
headers: { "Content-Type": "application/json" },
body: JSON.stringify(body),
credentials: "include"
});
if (!response.ok) {
const detail = await response.text();
throw new Error(detail || `API request failed: ${response.status}`);
}
return response.json() as Promise<T>;
}
export async function apiDelete(path: string, token: string): Promise<void> {
const response = await fetch(`${API_BASE}${path}`, {
method: "DELETE",
credentials: "include"
});
if (!response.ok) {
throw new Error(`API request failed: ${response.status}`);
}
}
export async function apiFetch<T>(path: string, token: string, init?: RequestInit): Promise<T> {
const response = await fetch(`${API_BASE}${path}`, {
...init,
headers: { "Content-Type": "application/json", ...(init?.headers ?? {}) },
credentials: "include"
});
if (!response.ok) {
throw new Error(await response.text());
}
return response.json() as Promise<T>;
}