import http from "node:http";
import { readFile } from "node:fs/promises";
import { extname } from "node:path";
const PORT = Number(process.env.PORT || 5173);
const API_BASE =
process.env.DOCLINK_API_BASE ||
"https://devbandungraya.aplikasi.web.id/one-api-doctor/doctor_mitra";
const sessionKey = "doclink_session";
const mockUser = {
name: "dr. Fajri",
role: "Dokter Mitra",
hospital: "Pramita Bandungraya",
doctorId: "DR-10024",
};
const mockOrders = [
{
id: "ORD-24001",
patient: "Siti Amelia",
doctor: "dr. Fajri",
updated: "2m ago",
status: "Processing",
tone: "warning",
mode: "Inpatient",
age: "34",
gender: "F",
tests: ["Hematology", "Glucose", "Urine"],
diagnosis: "Check-up rutin",
message: "Prioritize fasting sample and note dizziness symptom.",
},
{
id: "ORD-24002",
patient: "Budi Santoso",
doctor: "dr. Fajri",
updated: "14m ago",
status: "Ready",
tone: "success",
mode: "Outpatient",
age: "52",
gender: "M",
tests: ["Lipid Profile", "Liver Function"],
diagnosis: "Kontrol hipertensi",
message: "Call if LDL exceeds threshold.",
},
{
id: "ORD-24003",
patient: "Nia Putri",
doctor: "dr. Fajri",
updated: "40m ago",
status: "Needs review",
tone: "danger",
mode: "Emergency",
age: "27",
gender: "F",
tests: ["Electrolytes", "CBC", "CRP"],
diagnosis: "Dehydration",
message: "Urgent release once CRP is complete.",
},
];
const mockResults = [
{
id: "RES-8821",
patient: "Siti Amelia",
test: "CBC",
status: "Released",
tone: "success",
date: "13 Apr 2026",
summary: "Hemoglobin slightly below baseline.",
value: "11.2 g/dL",
},
{
id: "RES-8822",
patient: "Budi Santoso",
test: "Lipid Profile",
status: "Pending",
tone: "warning",
date: "13 Apr 2026",
summary: "Awaiting final approval.",
value: "LDL 145 mg/dL",
},
{
id: "RES-8823",
patient: "Nia Putri",
test: "CRP",
status: "Review",
tone: "danger",
date: "12 Apr 2026",
summary: "Result flagged for clinical review.",
value: "18.4 mg/L",
},
];
const mockFppGroups = [
{ group: "HEMATOLOGI", count: 6, desc: "Complete blood count and related panels." },
{ group: "KLINIK RUTIN", count: 5, desc: "Daily screening and basic chemistry." },
{ group: "IMUNOLOGI", count: 3, desc: "Inflammation and antibody markers." },
{ group: "URINALISA", count: 4, desc: "Urine screening and microscopic checks." },
];
const mockPatients = [
{ name: "Siti Amelia", mrn: "MRN-10011", gender: "Female", lastVisit: "Today", note: "Active order" },
{ name: "Budi Santoso", mrn: "MRN-10012", gender: "Male", lastVisit: "Yesterday", note: "Repeat visit" },
{ name: "Nia Putri", mrn: "MRN-10013", gender: "Female", lastVisit: "12 Apr", note: "New registration" },
];
function escapeHtml(value) {
return String(value)
.replaceAll("&", "&")
.replaceAll("<", "<")
.replaceAll(">", ">")
.replaceAll('"', """);
}
function statusClass(status) {
const mapping = {
Processing: "warning",
Ready: "success",
"Needs review": "danger",
Released: "success",
Pending: "warning",
Review: "danger",
};
return mapping[status] || "neutral";
}
function statusBadge(text) {
return `${escapeHtml(text)} `;
}
function icon(name) {
const map = {
search:
' ',
plus:
' ',
bell:
' ',
arrow:
' ',
login:
' ',
};
return map[name] || "";
}
function layout(title, body, { authenticated = false, activePath = "/", subtitle = "", shell = true } = {}) {
const nav = authenticated ? desktopNav(activePath) : "";
const mobile = authenticated ? mobileNav(activePath) : "";
const header = authenticated ? topbar(activePath, subtitle) : "";
return `
${escapeHtml(title)}
${shell && authenticated ? `
${nav}
${header}
${body}
${mobile}
` : body}
`;
}
function topbar(activePath, subtitle) {
const titleMap = {
"/": ["Dashboard", "Overview of orders, results, and work queues."],
"/orders": ["Orders", "Search, review, and create patient orders."],
"/results": ["Results", "Monitor released and pending laboratory results."],
"/fpp": ["FPP", "Browse grouped reference packages and filters."],
"/patients": ["Patients", "Landing for patient registration and lookup."],
"/settings": ["Settings", "Account profile and password management."],
};
const [title, fallbackSubtitle] = titleMap[activePath] || ["DocLink Web", "Responsive clinical workflow shell."];
const searchForm = activePath === "/orders"
? `
`
: activePath === "/results"
? `
`
: `
Search orders
`;
return `
`;
}
function desktopNav(activePath) {
const items = [
["/", "Home", "Dashboard"],
["/orders", "Order", "Create & list"],
["/results", "Result", "History"],
["/fpp", "FPP", "Catalog"],
["/settings", "Akun", "Profile"],
];
const active = (href) => activePath === href || activePath.startsWith(`${href}/`);
return `
`;
}
function mobileNav(activePath) {
const items = [
["/", "Home", "Dashboard"],
["/orders", "Order", "Create"],
["/results", "Result", "History"],
["/fpp", "FPP", "Catalog"],
["/settings", "Akun", "Profile"],
];
const active = (href) => activePath === href || activePath.startsWith(`${href}/`);
return `
`;
}
function panelHeader(title, text, action = "") {
return `
`;
}
function dashboardPage() {
const stats = [
{ label: "Orders today", value: "28", trend: "+12%", hint: "Vs yesterday" },
{ label: "Results pending", value: "7", trend: "-3%", hint: "Still waiting release" },
{ label: "FPP items", value: "14", trend: "+2", hint: "Active reference set" },
{ label: "Special messages", value: "5", trend: "+1", hint: "Need follow-up" },
];
const shortcuts = [
{ title: "New order", desc: "Start registration flow", href: "/orders/new" },
{ title: "Pending results", desc: "Review unreleased items", href: "/results/pending" },
{ title: "FPP catalog", desc: "Inspect lab groups", href: "/fpp" },
{ title: "Change password", desc: "Update account security", href: "/settings/change-password" },
];
return `
${stats
.map(
(item) => `
${escapeHtml(item.label)}
${escapeHtml(item.trend)}
${escapeHtml(item.value)}
${escapeHtml(item.hint)}
`,
)
.join("")}
${panelHeader("Quick actions", "Jump into the common flows without digging through nested screens.")}
${panelHeader("Recent orders", "A compact snapshot of the latest patient orders and their state.", '
View all ')}
Patient Order Status Updated
${mockOrders
.map(
(order) => `
${escapeHtml(order.patient)} ${escapeHtml(order.mode)}
${escapeHtml(order.id)} ${escapeHtml(order.diagnosis)}
${statusBadge(order.status)}
${escapeHtml(order.updated)}
`,
)
.join("")}
${panelHeader("Today’s notes", "Items that need attention now, not later.")}
${[
["FPP ready for release", "Review Hematology group before rounding."],
["Pending sample", "One fasting sample still waiting in the queue."],
["Password rotation", "Prompt user to refresh credentials after 90 days."],
]
.map(
([title, text]) => `
${escapeHtml(title)}
${escapeHtml(text)}
${icon("arrow")}
`,
)
.join("")}
`;
}
function renderOrdersTable(orders, selectedOrderId, filter = "All") {
const selected = orders.find((item) => item.id === selectedOrderId) || orders[0] || mockOrders[0];
return `
${panelHeader("Search orders", "Use the filter to match the old app flow without giving up desktop readability.", 'Create order ')}
Patient Order ID Doctor Status Updated
${orders
.map(
(order) => `
${escapeHtml(order.patient)} ${escapeHtml(order.mode)}
${escapeHtml(order.id)}
${escapeHtml(order.doctor)}
${statusBadge(order.status)}
${escapeHtml(order.updated)}
`,
)
.join("")}
${orders
.map(
(order) => `
${escapeHtml(order.patient)}
${escapeHtml(order.id)} · ${escapeHtml(order.mode)}
${statusBadge(order.status)}
${escapeHtml(order.doctor)}
${escapeHtml(order.updated)}
`,
)
.join("")}
${panelHeader("Selected order", "Master-detail layout keeps context visible while reviewing the list.", `Open detail `)}
${escapeHtml(selected.patient)}
${escapeHtml(selected.id)} · ${escapeHtml(selected.mode)}
${statusBadge(selected.status)}
${escapeHtml(selected.age)} years
${escapeHtml(selected.gender)}
Diagnosis ${escapeHtml(selected.diagnosis)}
Requested tests ${escapeHtml(selected.tests.join(", "))}
Special note ${escapeHtml(selected.message)}
`;
}
function renderOrderDetail(order) {
return `
${panelHeader(
`${order.patient} · ${order.id}`,
"Order detail with the same structure as the proposed master-detail workflow.",
`Pesan khusus `,
)}
Status ${statusBadge(order.status)}
Patient ${escapeHtml(order.patient)} ${escapeHtml(order.mode)} · ${escapeHtml(order.age)} years
Doctor ${escapeHtml(order.doctor)} ${escapeHtml(mockUser.hospital)}
${panelHeader("Requested tests", "List/table treatment on desktop, cards on smaller screens.")}
${order.tests
.map(
(test) => `
${escapeHtml(test)} Included in the current order bundle.
`,
)
.join("")}
${panelHeader("Clinical note", "A compact summary for quick review.")}
${escapeHtml(order.message)}
${order.apiSaran ? `
${escapeHtml(typeof order.apiSaran === "string" ? order.apiSaran : JSON.stringify(order.apiSaran))}
` : ""}
Diagnosis ${escapeHtml(order.diagnosis)}
Updated ${escapeHtml(order.updated)}
`;
}
function renderOrderForm(step, stepKey = "demografi") {
const steps = [
["demografi", "Demografi", "Patient identity and contact details."],
["diagnosa", "Diagnosa", "Clinical indication and diagnosis."],
["pemeriksaan", "Pemeriksaan", "Choose examination groups."],
["qrcode", "QR Code", "Fast entry for existing records."],
["review", "Review", "Check before submit."],
];
const activeIndex = Math.max(0, steps.findIndex((item) => item[0] === stepKey));
const stepBody = {
demografi: `
Patient name
Medical record no.
Gender Female Male
Date of birth
Address
`,
diagnosa: `
Diagnosis
Patient note
Clinical complaint
`,
pemeriksaan: `
${["Hematology", "Clinical Chemistry", "Urinalysis", "Immunology", "Microbiology"].map((item) => `${escapeHtml(item)} `).join("")}
${["CBC", "Glucose", "Lipid Profile", "CRP"].map((item) => `
${escapeHtml(item)}
Selectable test item
`).join("")}
`,
qrcode: `
Scan existing patient QR
Use a QR code to pull patient and visit context instantly.
QR preview area
`,
review: `
Summary All steps are merged into a final review before submit.
Message Prioritize fasting sample
`,
}[stepKey];
const prev = steps[activeIndex - 1];
const next = steps[activeIndex + 1];
return `
${panelHeader("Create new order", "The new project collapses the old step-heavy flow into a cleaner shell while keeping the same workflow.", 'Cancel ')}
`;
}
function renderResultsTable(results, selectedResultId) {
const selected = results.find((item) => item.id === selectedResultId) || results[0] || mockResults[0];
return `
${panelHeader("Result history", "Desktop shows table detail. Mobile collapses into stacked cards.")}
Patient Result ID Test Status Date
${results
.map(
(result) => `
${escapeHtml(result.patient)} ${escapeHtml(result.summary)}
${escapeHtml(result.id)}
${escapeHtml(result.test)}
${statusBadge(result.status)}
${escapeHtml(result.date)}
`,
)
.join("")}
${results
.map(
(result) => `
${escapeHtml(result.patient)}
${escapeHtml(result.test)} · ${escapeHtml(result.date)}
${statusBadge(result.status)}
Open detail
${escapeHtml(result.summary)}
`,
)
.join("")}
`;
}
function renderResultDetail(result) {
return `
${panelHeader(`${result.patient} · ${result.id}`, "Result detail with summary, status, and interpretation fields.", 'Back to results ')}
Status ${statusBadge(result.status)}
Test ${escapeHtml(result.test)}
Value ${escapeHtml(result.value)}
${escapeHtml(result.summary)}
Date ${escapeHtml(result.date)}
Interpretation Borderline value requires doctor review.
Action Keep in pending state until confirmed.
`;
}
function renderFpp(groups) {
return `
${panelHeader("FPP catalog", "Filter blocks and list cards on mobile, richer panel on desktop.")}
${["All", ...mockFppGroups.map((item) => item.group)]
.map(
(item) => `
${escapeHtml(item)}
`,
)
.join("")}
${groups.items
.map(
(item) => `
${["Filter", "Inspect", "Select", "Export"]
.map(
(action) => `
${escapeHtml(action)}
Workflow action for ${escapeHtml(item.group)}.
`,
)
.join("")}
`,
)
.join("")}
`;
}
function renderPatients() {
return `
${panelHeader("Patient registration", "A landing zone for registration, lookup, and intake shortcuts.", 'Start registration ')}
${[
["Today's intake", "11", "New or updated patients"],
["Active visits", "7", "Cases linked to lab orders"],
["QR scans", "4", "Fast entry from QR code"],
["Needs review", "2", "Patients waiting verification"],
]
.map(
([label, value, hint]) => `
${escapeHtml(label)}
Live
${escapeHtml(value)}
${escapeHtml(hint)}
`,
)
.join("")}
${panelHeader("Quick intake", "Route into the proper entry flow without forcing the user through extra screens.")}
New patient
Jump straight into demographic capture.
Use the registration stepper when the patient is not yet in the system.
`;
}
function renderSettings() {
return `
${panelHeader("Account", "Profile data and security entry points.")}
Name ${escapeHtml(mockUser.name)}
Doctor ID ${escapeHtml(mockUser.doctorId)}
Role ${escapeHtml(mockUser.role)}
Hospital ${escapeHtml(mockUser.hospital)}
${panelHeader("Settings actions", "Keep the common account actions obvious.")}
`;
}
function renderChangePassword() {
return `
${panelHeader("Change password", "Inline validation and a straightforward submit path.")}
`;
}
function loginPage({ error = "" } = {}) {
return layout(
"DocLink Login",
`
`,
{ authenticated: false, shell: false, activePath: "/login" },
);
}
function splashPage() {
return layout(
"DocLink Splash",
`
`,
{ authenticated: false, shell: false, activePath: "/splash" },
);
}
function problemLoginPage() {
return layout(
"Problem Login",
`
`,
{ authenticated: false, shell: false, activePath: "/problem-login" },
);
}
function orderNewPage(path) {
const step = path.split("/").filter(Boolean)[2] || "demografi";
return layout("Create Order", `${renderOrderForm({}, step)}
`, {
authenticated: true,
activePath: "/orders",
subtitle: "The new project collapses the old step-heavy flow into a cleaner shell while keeping the same workflow.",
});
}
function ordersPage({ query = {}, orders = mockOrders, selectedOrderId = mockOrders[0].id } = {}) {
return layout("Orders", `${renderOrdersTable(orders, selectedOrderId, query.status || "All")}
`, {
authenticated: true,
activePath: "/orders",
});
}
function resultsPage({ query = {}, results = mockResults, selectedResultId = mockResults[0].id } = {}) {
return layout("Results", `${renderResultsTable(results, selectedResultId)}
`, {
authenticated: true,
activePath: "/results",
});
}
function fppPage({ group = "All", groups = mockFppGroups } = {}) {
return layout("FPP", `${renderFpp({ items: groups, filter: group })}
`, {
authenticated: true,
activePath: "/fpp",
});
}
function patientsPage() {
return layout("Patients", renderPatients(), { authenticated: true, activePath: "/patients" });
}
function settingsPage() {
return layout("Settings", renderSettings(), { authenticated: true, activePath: "/settings" });
}
function changePasswordPage() {
return layout("Change Password", renderChangePassword(), {
authenticated: true,
activePath: "/settings/change-password",
});
}
function orderDetailPage(order) {
return layout("Order Detail", renderOrderDetail(order), {
authenticated: true,
activePath: "/orders",
});
}
function resultDetailPage(result) {
return layout("Result Detail", renderResultDetail(result), {
authenticated: true,
activePath: "/results",
});
}
function specialMessagePage(order) {
return layout(
"Pesan Khusus",
`
${panelHeader("Pesan khusus", "Desktop can treat this as a modal-style panel; mobile reads it as a dedicated page.", `Back `)}
${escapeHtml(order.patient)}
${escapeHtml(order.id)}
${statusBadge(order.status)}
${escapeHtml(order.message)}
${order.apiSaran ? `
${escapeHtml(typeof order.apiSaran === "string" ? order.apiSaran : JSON.stringify(order.apiSaran))}
` : ""}
`,
{ authenticated: true, activePath: "/orders" },
);
}
function emptyRoute(path) {
return layout("Not Found", `Route not found ${escapeHtml(path)} is not part of the current rebuild scope.
Go to dashboard `, {
authenticated: true,
activePath: "/",
});
}
function cookieHeader(req) {
return req.headers.cookie || "";
}
function getCookie(req, name) {
const cookies = cookieHeader(req)
.split(";")
.map((part) => part.trim())
.filter(Boolean);
for (const item of cookies) {
const [key, ...rest] = item.split("=");
if (key === name) return decodeURIComponent(rest.join("="));
}
return "";
}
function setCookie(name, value, opts = {}) {
const parts = [`${name}=${encodeURIComponent(value)}`, "Path=/", "HttpOnly", "SameSite=Lax"];
if (opts.maxAge != null) parts.push(`Max-Age=${opts.maxAge}`);
if (opts.secure) parts.push("Secure");
return parts.join("; ");
}
function deleteCookie(name) {
return `${name}=; Path=/; HttpOnly; SameSite=Lax; Max-Age=0`;
}
function readSession(req) {
const raw = getCookie(req, sessionKey);
if (!raw) return null;
try {
return JSON.parse(raw);
} catch {
return null;
}
}
function requireAuth(req, res) {
const session = readSession(req);
if (session) return session;
redirect(res, "/login");
return null;
}
async function fetchJson(url, options = {}) {
const response = await fetch(url, options);
const contentType = response.headers.get("content-type") || "";
const body = contentType.includes("application/json") ? await response.json() : await response.text();
if (!response.ok) {
const error = new Error(`Upstream error ${response.status}`);
error.status = response.status;
error.body = body;
throw error;
}
return body;
}
async function apiPost(path, payload, token = "") {
const headers = { "Content-Type": "application/json" };
if (token) {
headers.Authorization = `Bearer ${token}`;
payload.token = payload.token || token;
}
const url = `${API_BASE}${path}`;
return fetchJson(url, {
method: "POST",
headers,
body: JSON.stringify(payload),
});
}
function normalizeSession(payload) {
const data = payload?.data || payload?.result || payload;
const token = data?.token || data?.access_token || data?.accessToken || payload?.token || "";
const username = data?.username || data?.M_UserUsername || data?.name || "";
const doctorId = data?.doctor_id || data?.M_UserID || data?.doctorId || "";
return {
token,
username,
doctorId,
raw: payload,
};
}
function extractArray(payload) {
if (Array.isArray(payload)) return payload;
if (!payload || typeof payload !== "object") return null;
for (const key of ["data", "result", "results", "items", "list"]) {
const value = payload[key];
const found = extractArray(value);
if (found) return found;
}
return null;
}
function normalizeOrder(raw, index = 0) {
const testsSource = raw?.details || raw?.tests || raw?.items || raw?.order_details || [];
const tests = Array.isArray(testsSource)
? testsSource
.map((item) => {
if (typeof item === "string") return item;
return item?.name || item?.test_name || item?.detail_name || item?.exam || item?.label || "";
})
.filter(Boolean)
: [];
const status = raw?.status || raw?.order_status || raw?.state || "Processing";
return {
id:
raw?.order_patient_id ||
raw?.order_id ||
raw?.id ||
raw?.OrderPatientID ||
raw?.OrderID ||
`ORD-${String(index + 1).padStart(5, "0")}`,
patient: raw?.patient_name || raw?.name || raw?.patient || raw?.patient_fullname || "Patient",
doctor: raw?.doctor_name || raw?.doctor || raw?.M_UserUsername || mockUser.name,
updated: raw?.updated_at || raw?.updated || raw?.created_at || "Today",
status,
tone: statusClass(status),
mode: raw?.mode || raw?.visit_type || raw?.patient_type || "Outpatient",
age: String(raw?.age || raw?.patient_age || ""),
gender: raw?.gender || raw?.patient_gender || "",
tests,
diagnosis: raw?.patient_diagnosa || raw?.diagnosis || raw?.note || "",
message: raw?.message || raw?.patient_note || "",
};
}
function normalizeResult(raw, index = 0) {
const status = raw?.status || raw?.result_status || "Released";
return {
id:
raw?.result_id ||
raw?.order_id ||
raw?.id ||
raw?.hasil_id ||
`RES-${String(index + 1).padStart(4, "0")}`,
patient: raw?.patient_name || raw?.name || raw?.patient || "Patient",
test: raw?.test_name || raw?.item_name || raw?.test || "Result",
status,
tone: statusClass(status),
date: raw?.date || raw?.created_at || raw?.updated_at || "Today",
summary: raw?.summary || raw?.note || raw?.result_summary || "",
value: raw?.value || raw?.result_value || raw?.result || "",
};
}
async function loadOrders(session, search = "", status = "All") {
const term = String(search || "").trim();
try {
const payload = await apiPost(
"/order/search_order_pasien_by_doktorid",
{
token: session.token,
OrderPatientM_DoctorID: session.doctorId || mockUser.doctorId,
search: term,
},
session.token,
);
const rows = extractArray(payload) || [];
const orders = rows.map((row, index) => normalizeOrder(row, index)).filter((item) => {
const matchesSearch =
!term ||
[item.id, item.patient, item.status, item.diagnosis, item.message].some((value) =>
String(value).toLowerCase().includes(term.toLowerCase()),
);
const matchesStatus = !status || status === "All" || item.status === status;
return matchesSearch && matchesStatus;
});
if (orders.length) return orders;
} catch {
// Fall through to mock data.
}
return filterOrders(term, status);
}
async function loadResults(session, search = "") {
const term = String(search || "").trim();
try {
const payload = await apiPost(
"/order/hasil_belum_keluar_by_id",
{ token: session.token, order_id: session.orderId || "" },
session.token,
);
const rows = extractArray(payload) || [];
const results = rows.map((row, index) => normalizeResult(row, index)).filter((item) => {
if (!term) return true;
return [item.id, item.patient, item.test, item.status, item.summary].some((value) =>
String(value).toLowerCase().includes(term.toLowerCase()),
);
});
if (results.length) return results;
} catch {
// Fall through to mock data.
}
return filterResults(term);
}
async function loadResultDetail(session, resultId) {
const fallback = mockResults.find((item) => item.id === resultId) || mockResults[0];
try {
// Inferred from project-specs note about an additional result base path.
const payload = await apiPost(
"/result/getResult",
{
token: session.token,
result_id: resultId,
order_id: resultId,
},
session.token,
);
const rows = extractArray(payload);
if (rows?.length) return normalizeResult(rows[0], 0);
if (payload && typeof payload === "object") {
return {
...fallback,
...normalizeResult(payload, 0),
id: resultId || fallback.id,
};
}
} catch {
// Fall through to local seed data when the upstream result API is unavailable.
}
return fallback;
}
async function loadFpp(session, group = "All") {
try {
const payload = await apiPost("/Fpp/load/1/1", { token: session.token }, session.token);
const rows = extractArray(payload) || [];
const items = rows.map((row, index) => ({
group: row?.group || row?.kategori || row?.name || `GROUP-${index + 1}`,
count: Number(row?.count || row?.total || row?.qty || 1),
desc: row?.description || row?.desc || "Laboratory reference item.",
}));
if (items.length) {
const filtered = group === "All" ? items : items.filter((item) => item.group === group);
return { items: filtered, filter: group };
}
} catch {
// Fall through to mock data.
}
const items = group === "All" ? mockFppGroups : mockFppGroups.filter((item) => item.group === group);
return { items, filter: group };
}
async function loadOrderDetail(session, orderId) {
const order = mockOrders.find((item) => item.id === orderId) || mockOrders[0];
const detail = { ...order };
try {
const saran = await apiPost(
"/order/get_order_saran_by_order_patient_id",
{ token: session.token, order_patient_id: orderId },
session.token,
);
detail.apiSaran = extractArray(saran) || saran?.message || saran?.note || saran?.result || "";
} catch {
detail.apiSaran = "";
}
try {
const hasil = await apiPost(
"/order/hasil_belum_keluar_by_id",
{ token: session.token, order_id: orderId },
session.token,
);
detail.apiHasil = extractArray(hasil) || hasil?.message || hasil?.note || hasil?.result || "";
} catch {
detail.apiHasil = "";
}
return detail;
}
function json(res, status, payload) {
res.writeHead(status, { "Content-Type": "application/json; charset=utf-8" });
res.end(JSON.stringify(payload));
}
function redirect(res, location, headers = {}) {
res.writeHead(302, { Location: location, ...headers });
res.end();
}
function html(res, status, body, headers = {}) {
res.writeHead(status, { "Content-Type": "text/html; charset=utf-8", ...headers });
res.end(body);
}
function isHtmx(req) {
return req.headers["hx-request"] === "true";
}
async function readBody(req) {
const chunks = [];
for await (const chunk of req) chunks.push(chunk);
const raw = Buffer.concat(chunks).toString("utf8");
const contentType = req.headers["content-type"] || "";
if (contentType.includes("application/json")) return raw ? JSON.parse(raw) : {};
return Object.fromEntries(new URLSearchParams(raw));
}
function filterOrders(search, status) {
const term = String(search || "").trim().toLowerCase();
return mockOrders.filter((order) => {
const matchesSearch =
!term ||
[order.id, order.patient, order.status, order.diagnosis, order.message].some((value) =>
String(value).toLowerCase().includes(term),
);
const matchesStatus = !status || status === "All" || order.status === status;
return matchesSearch && matchesStatus;
});
}
function filterResults(search) {
const term = String(search || "").trim().toLowerCase();
return mockResults.filter((result) => {
if (!term) return true;
return [result.id, result.patient, result.test, result.status, result.summary].some((value) =>
String(value).toLowerCase().includes(term),
);
});
}
function fragmentOrdersTable(search = "", status = "All", ordersData = null) {
const orders = ordersData || filterOrders(search, status);
const selected = orders[0] || mockOrders[0];
return `
${panelHeader("Search orders", "Filter the list without full page refresh.")}
${["All", "Processing", "Ready", "Needs review"]
.map(
(item) => `
${escapeHtml(item)}
`,
)
.join("")}
Patient Order ID Doctor Status Updated
${orders
.map(
(order) => `
${escapeHtml(order.patient)} ${escapeHtml(order.mode)}
${escapeHtml(order.id)}
${escapeHtml(order.doctor)}
${statusBadge(order.status)}
${escapeHtml(order.updated)}
`,
)
.join("")}
${panelHeader("Selected order", "Context stays visible while you review the table.", `Open detail `)}
${escapeHtml(selected.patient)}
${escapeHtml(selected.id)} · ${escapeHtml(selected.mode)}
${statusBadge(selected.status)}${escapeHtml(selected.age)} years ${escapeHtml(selected.gender)}
Diagnosis ${escapeHtml(selected.diagnosis)}
Requested tests ${escapeHtml(selected.tests.join(", "))}
Special note ${escapeHtml(selected.message)}
`;
}
function fragmentResultsTable(search = "", resultsData = null) {
const results = resultsData || filterResults(search);
const selected = results[0] || mockResults[0];
return `
${panelHeader("Result history", "Desktop shows table detail. Mobile collapses into stacked cards.")}
Patient Result ID Test Status Date
${results
.map(
(result) => `
${escapeHtml(result.patient)} ${escapeHtml(result.summary)}
${escapeHtml(result.id)}
${escapeHtml(result.test)}
${statusBadge(result.status)}
${escapeHtml(result.date)}
`,
)
.join("")}
`;
}
function fragmentFpp(group = "All", itemsData = null) {
const items = itemsData || (group === "All" ? mockFppGroups : mockFppGroups.filter((item) => item.group === group));
return `
${panelHeader("FPP catalog", "Filter blocks and list cards on mobile, richer panel on desktop.")}
${["All", ...mockFppGroups.map((item) => item.group)]
.map(
(item) => `
${escapeHtml(item)}
`,
)
.join("")}
${items
.map(
(item) => `
${["Filter", "Inspect", "Select", "Export"]
.map(
(action) => `
${escapeHtml(action)}
Workflow action for ${escapeHtml(item.group)}.
`,
)
.join("")}
`,
)
.join("")}
`;
}
function fragmentOrderStep(step) {
return renderOrderForm({}, step);
}
function fragmentPesanKhusus(orderId) {
const order = mockOrders.find((item) => item.id === orderId) || mockOrders[0];
return `
${panelHeader("Pesan khusus", "Desktop opens this as a modal, mobile can still use it as a full sheet.", `Close `)}
${escapeHtml(order.patient)}
${escapeHtml(order.id)}
${statusBadge(order.status)}
${escapeHtml(order.message)}
Special message
${escapeHtml(order.message)}
Save message
Cancel
`;
}
async function fragmentResultDetail(session, resultId) {
const result = await loadResultDetail(session, resultId);
return `
${renderResultDetail(result)}
`;
}
async function renderRoute(req, res, url) {
const path = url.pathname;
const query = Object.fromEntries(url.searchParams.entries());
const session = readSession(req);
const authed = Boolean(session);
const isGet = req.method === "GET" || req.method === "HEAD";
if (path === "/styles.css") {
const css = await readFile(new URL("./styles.css", import.meta.url), "utf8");
res.writeHead(200, { "Content-Type": "text/css; charset=utf-8" });
res.end(css);
return;
}
if (path === "/login" && isGet) {
html(res, 200, loginPage(), { "Cache-Control": "no-store" });
return;
}
if (path === "/splash" && isGet) {
html(res, 200, splashPage(), { "Cache-Control": "no-store" });
return;
}
if (path === "/problem-login" && isGet) {
html(res, 200, problemLoginPage(), { "Cache-Control": "no-store" });
return;
}
if (path === "/login" && req.method === "POST") {
const body = await readBody(req);
try {
const payload = await apiPost("/auth/login", body);
const normalized = normalizeSession(payload);
const upstreamFailed = String(payload?.status || payload?.result_status || "").toUpperCase() === "ERR" || !normalized.token;
if (upstreamFailed) {
throw new Error(payload?.message || "Invalid login response");
}
const sessionValue = JSON.stringify({
token: normalized.token,
username: normalized.username || body.username || "",
doctorId: normalized.doctorId || body.doctor_id || "",
raw: payload,
});
redirect(res, "/", {
"Set-Cookie": setCookie(sessionKey, sessionValue, { maxAge: 60 * 60 * 12 }),
});
} catch (error) {
if (process.env.DOCLINK_DEMO_MODE !== "0") {
const sessionValue = JSON.stringify({
token: "demo-token",
username: body.username || mockUser.name,
doctorId: body.doctor_id || mockUser.doctorId,
raw: { demo: true },
});
redirect(res, "/", {
"Set-Cookie": setCookie(sessionKey, sessionValue, { maxAge: 60 * 60 * 12 }),
});
} else {
html(res, 200, loginPage({ error: "Login failed or upstream API unavailable. Check credentials and network." }));
}
}
return;
}
if (path === "/logout" && req.method === "POST") {
const sessionData = readSession(req);
if (sessionData?.token) {
try {
await apiPost(
"/auth/logout",
{
M_UserID: sessionData.doctorId || mockUser.doctorId,
M_UserUsername: sessionData.username || mockUser.name,
},
sessionData.token,
);
} catch {
// Ignore upstream logout failures and still clear local session.
}
}
redirect(res, "/login", { "Set-Cookie": deleteCookie(sessionKey) });
return;
}
if (path === "/settings/change-password" && req.method === "POST") {
const sessionData = requireAuth(req, res);
if (!sessionData) return;
const body = await readBody(req);
try {
await apiPost(
"/auth/change_password",
{
token: sessionData.token,
M_UserID: sessionData.doctorId || mockUser.doctorId,
username: sessionData.username || mockUser.name,
doctor_id: sessionData.doctorId || mockUser.doctorId,
new_password: body.new_password,
confirm_password: body.confirm_password,
},
sessionData.token,
);
redirect(res, "/settings");
} catch (error) {
html(
res,
200,
layout(
"Change Password",
`${panelHeader("Change password", "Inline validation and a straightforward submit path.")}Upstream change password call failed. Check API availability.
`,
{ authenticated: true, activePath: "/settings/change-password" },
),
);
}
return;
}
if (path === "/orders/new" && isGet) {
if (!requireAuth(req, res)) return;
html(res, 200, orderNewPage(path));
return;
}
if (path.startsWith("/orders/new/") && isGet) {
if (!requireAuth(req, res)) return;
html(res, 200, orderNewPage(path));
return;
}
if (path === "/orders" && isGet) {
if (!requireAuth(req, res)) return;
const orders = await loadOrders(session, query.search || "", query.status || "All");
html(res, 200, ordersPage({ query, orders, selectedOrderId: orders[0]?.id || mockOrders[0].id }));
return;
}
if (path === "/results" && isGet) {
if (!requireAuth(req, res)) return;
const results = await loadResults(session, query.search || "");
html(res, 200, resultsPage({ query, results, selectedResultId: results[0]?.id || mockResults[0].id }));
return;
}
if (path === "/results/historical" && isGet) {
if (!requireAuth(req, res)) return;
html(
res,
200,
layout(
"Historical results",
`${panelHeader("Historical results", "A compact historic view that still fits the responsive shell.")} `,
{ authenticated: true, activePath: "/results" },
),
);
return;
}
if (path === "/results/pending" && isGet) {
if (!requireAuth(req, res)) return;
html(
res,
200,
layout(
"Pending results",
`${panelHeader("Pending results", "Items that need attention before release.")}${mockResults.filter((item) => item.status !== "Released").map((item) => `
${escapeHtml(item.patient)} ${statusBadge(item.status)}
${escapeHtml(item.test)} · ${escapeHtml(item.summary)}
Open detail `).join("")}
`,
{ authenticated: true, activePath: "/results" },
),
);
return;
}
if (path === "/fpp" && isGet) {
if (!requireAuth(req, res)) return;
const groups = await loadFpp(session, query.group || "All");
html(res, 200, fppPage({ group: groups.filter, groups: groups.items }));
return;
}
if (path === "/patients" && isGet) {
if (!requireAuth(req, res)) return;
html(res, 200, patientsPage());
return;
}
if ((path === "/settings" || path === "/settings/account") && isGet) {
if (!requireAuth(req, res)) return;
html(res, 200, settingsPage());
return;
}
if (path === "/settings/change-password" && isGet) {
if (!requireAuth(req, res)) return;
html(res, 200, changePasswordPage());
return;
}
if (path === "/" && isGet) {
if (!requireAuth(req, res)) return;
html(res, 200, layout("Dashboard", dashboardPage(), { authenticated: true, activePath: "/" }));
return;
}
if (path.startsWith("/orders/") && path.endsWith("/pesan-khusus") && isGet) {
if (!requireAuth(req, res)) return;
const orderId = path.split("/")[2];
const order = await loadOrderDetail(session, orderId);
html(res, 200, specialMessagePage(order));
return;
}
if (path.startsWith("/orders/") && isGet) {
if (!requireAuth(req, res)) return;
const orderId = path.split("/")[2];
const order = await loadOrderDetail(session, orderId);
html(res, 200, orderDetailPage(order));
return;
}
if (path.startsWith("/results/") && isGet) {
if (!requireAuth(req, res)) return;
const resultId = path.split("/")[2];
const result = await loadResultDetail(session, resultId);
html(res, 200, resultDetailPage(result));
return;
}
if (path === "/fragments/orders/table" && isGet) {
if (!requireAuth(req, res)) return;
const orders = await loadOrders(session, query.search || "", query.status || "All");
html(res, 200, fragmentOrdersTable(query.search || "", query.status || "All", orders), { "HX-Trigger": JSON.stringify({ "doclink:orders-updated": true }) });
return;
}
if (path === "/fragments/results/table" && isGet) {
if (!requireAuth(req, res)) return;
const results = await loadResults(session, query.search || "");
html(res, 200, fragmentResultsTable(query.search || "", results));
return;
}
if (path === "/fragments/fpp/list" && isGet) {
if (!requireAuth(req, res)) return;
const groups = await loadFpp(session, query.group || "All");
html(res, 200, fragmentFpp(groups.filter || "All", groups.items));
return;
}
if (path.startsWith("/fragments/forms/order-step/") && isGet) {
if (!requireAuth(req, res)) return;
const step = path.split("/")[4] || "demografi";
html(res, 200, fragmentOrderStep(step));
return;
}
if (path === "/fragments/modals/pesan-khusus" && isGet) {
if (!requireAuth(req, res)) return;
html(res, 200, fragmentPesanKhusus(query.order_id || mockOrders[0].id));
return;
}
if (path.startsWith("/fragments/results/detail/") && isGet) {
if (!requireAuth(req, res)) return;
const resultId = path.split("/")[4] || mockResults[0].id;
html(res, 200, await fragmentResultDetail(session, resultId));
return;
}
if (path.startsWith("/api/") && isGet) {
json(res, 200, { ok: true });
return;
}
if (path === "/orders" && req.method === "POST") {
const sessionData = requireAuth(req, res);
if (!sessionData) return;
const body = await readBody(req);
try {
await apiPost(
"/order/order_patient",
{
token: sessionData.token,
M_MouID: body.M_MouID || mockUser.doctorId,
patient_name: body.patient_name || "",
patient_diagnosa: body.patient_diagnosa || "",
patient_address: body.patient_address || "",
patient_nik: body.patient_nik || "",
patient_hp: body.patient_hp || "",
patient_dob: body.patient_dob || "",
patient_note: body.patient_note || "",
details: body.details || [],
},
sessionData.token,
);
redirect(res, "/orders");
} catch {
html(
res,
200,
layout(
"Create Order",
`${panelHeader("Create new order", "The new project collapses the old step-heavy flow into a cleaner shell while keeping the same workflow.")}Upstream order create call failed. Check API availability.
`,
{ authenticated: true, activePath: "/orders" },
),
);
}
return;
}
if (path.startsWith("/orders/") && path.endsWith("/pesan-khusus") && req.method === "POST") {
const sessionData = requireAuth(req, res);
if (!sessionData) return;
const orderId = path.split("/")[2];
const body = await readBody(req);
try {
await apiPost(
"/Pesankhusus/add_pesan_khusus",
{
token: sessionData.token,
order_id: orderId,
pesan_khusus: body.pesan_khusus,
},
sessionData.token,
);
redirect(res, `/orders/${orderId}`);
} catch {
html(
res,
200,
layout(
"Pesan Khusus",
`${panelHeader("Pesan khusus", "Desktop can treat this as a modal-style panel; mobile reads it as a dedicated page.")}Upstream save failed. Check API availability.
`,
{ authenticated: true, activePath: "/orders" },
),
);
}
return;
}
html(res, 404, emptyRoute(path));
}
const server = http.createServer(async (req, res) => {
try {
const url = new URL(req.url, `http://${req.headers.host}`);
await renderRoute(req, res, url);
} catch (error) {
res.writeHead(500, { "Content-Type": "text/plain; charset=utf-8" });
res.end(`Internal error: ${error.message}`);
}
});
server.listen(PORT, () => {
console.log(`DocLink Web running on http://localhost:${PORT}`);
});