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)}
${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", "Landing page for registration, lookup, and entry flow.")}
Lookup
Search an existing patient and reuse their visit data.
Search patient
${panelHeader("Recent patients", "A compact list that becomes cards on mobile.")}
Name MRN Gender Last visit Note
${mockPatients
.map(
(person) => `
${escapeHtml(person.name)}
${escapeHtml(person.mrn)}
${escapeHtml(person.gender)}
${escapeHtml(person.lastVisit)}
${escapeHtml(person.note)}
`,
)
.join("")}
`;
}
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",
`
DocLink rebuild · responsive shell
Clinical workflow that works on desktop and mobile.
The old app behavior is preserved in a cleaner layout with dashboard, orders, results, FPP, and settings routes.
Route structure Login, dashboard, order flow, result flow, and account pages.
Responsive shell Persistent sidebar on desktop, bottom nav on mobile.
Clean interaction model HTMX fragments plus server-rendered templates.
`,
{ authenticated: false, shell: false, activePath: "/login" },
);
}
function splashPage() {
return layout(
"DocLink Splash",
`
Starting DocLink
Loading workspace...
Checking session and routing into the right entry point.
`,
{ authenticated: false, shell: false, activePath: "/splash" },
);
}
function problemLoginPage() {
return layout(
"Problem Login",
`
Login problem
Access needs attention.
Use this page when auth state is broken or a session expires.
`,
{ 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}`);
});