funktechnik-schubert-website/lib/olympus/status.ts
2026-07-05 02:17:19 +02:00

145 lines
3.5 KiB
TypeScript

import "server-only";
export type OlympusRepairStatusHistoryItem = {
status: string;
status_label: string;
created_at: string;
};
export type OlympusEstimateItem = {
item_type: string;
title: string;
description: string | null;
quantity: string | number;
unit: string;
unit_price_cents: number;
total_cents: number;
};
export type OlympusEstimate = {
estimate_number: string;
status: "draft" | "sent" | "approved" | "declined" | "expired" | "cancelled" | string;
title: string;
customer_message: string | null;
subtotal_cents: number;
tax_cents: number;
total_cents: number;
currency: string;
valid_until: string | null;
items: OlympusEstimateItem[];
};
export type OlympusRepairStatus = {
repair_number: string;
public_status_label: string;
device_manufacturer: string;
device_model: string;
status_history_public: OlympusRepairStatusHistoryItem[];
updated_at: string;
estimate?: OlympusEstimate | null;
};
export type RepairStatusResult =
| { ok: true; status: OlympusRepairStatus }
| { ok: false; reason: "invalid" | "unavailable" };
export type EstimateAction = "approve" | "decline" | "question";
export type EstimateActionResult =
| { ok: true }
| { ok: false; reason: "invalid" | "unavailable" | "failed" };
function getStatusApiBaseUrl() {
return process.env.OLYMPUS_PUBLIC_STATUS_API_URL?.replace(/\/$/, "") ?? "";
}
function getStatusApiToken() {
return process.env.OLYMPUS_PUBLIC_STATUS_API_TOKEN ?? "";
}
export async function fetchOlympusRepairStatus(token: string): Promise<RepairStatusResult> {
const baseUrl = getStatusApiBaseUrl();
if (!baseUrl || !token.trim()) {
return { ok: false, reason: "unavailable" };
}
const headers: HeadersInit = {
Accept: "application/json",
};
const apiToken = getStatusApiToken();
if (apiToken) {
headers.Authorization = `Bearer ${apiToken}`;
}
let response: Response;
try {
response = await fetch(`${baseUrl}/public/repairs/status/${encodeURIComponent(token)}`, {
headers,
cache: "no-store",
});
} catch {
return { ok: false, reason: "unavailable" };
}
if (response.status === 401 || response.status === 403 || response.status === 404) {
return { ok: false, reason: "invalid" };
}
if (!response.ok) {
return { ok: false, reason: "unavailable" };
}
try {
return { ok: true, status: await response.json() as OlympusRepairStatus };
} catch {
return { ok: false, reason: "unavailable" };
}
}
export async function submitOlympusEstimateAction(
token: string,
action: EstimateAction,
message?: string,
): Promise<EstimateActionResult> {
const baseUrl = getStatusApiBaseUrl();
if (!baseUrl || !token.trim()) {
return { ok: false, reason: "unavailable" };
}
const headers: HeadersInit = {
Accept: "application/json",
"Content-Type": "application/json",
};
const apiToken = getStatusApiToken();
if (apiToken) {
headers.Authorization = `Bearer ${apiToken}`;
}
let response: Response;
try {
response = await fetch(`${baseUrl}/public/repairs/status/${encodeURIComponent(token)}/estimate/${action}`, {
method: "POST",
headers,
body: JSON.stringify({ message: message?.trim() || null }),
cache: "no-store",
});
} catch {
return { ok: false, reason: "unavailable" };
}
if (response.status === 401 || response.status === 403 || response.status === 404) {
return { ok: false, reason: "invalid" };
}
if (!response.ok) {
return { ok: false, reason: "failed" };
}
return { ok: true };
}