Use desktop order search with row selection
This commit is contained in:
350
server.js
350
server.js
@@ -31,6 +31,8 @@ function statusClass(status) {
|
||||
Released: "success",
|
||||
Pending: "warning",
|
||||
Review: "danger",
|
||||
Confirmed: "success",
|
||||
Unconfirmed: "danger",
|
||||
};
|
||||
return mapping[status] || "neutral";
|
||||
}
|
||||
@@ -448,17 +450,20 @@ function accountLayoutOptions(session = {}) {
|
||||
}
|
||||
|
||||
async function dashboardPage(session) {
|
||||
const [orders, results] = await Promise.all([
|
||||
loadOrders(session, "", "All"),
|
||||
const [homeOrders, results] = await Promise.all([
|
||||
loadHomeOrders(session),
|
||||
loadResults(session, ""),
|
||||
]);
|
||||
const orders = homeOrders.items;
|
||||
const stats = [
|
||||
{ label: "Orders today", value: String(orders.length), trend: "Live", hint: "" },
|
||||
{ label: "Orders this month", value: String(homeOrders.totals.total), trend: `${homeOrders.month}/${homeOrders.year}`, hint: "" },
|
||||
{ label: "Confirmed", value: String(homeOrders.totals.confirmed), trend: "Home", hint: "" },
|
||||
{ label: "Results pending", value: String(results.filter((item) => item.status !== "Released").length), trend: "Live", hint: "" },
|
||||
{ label: "Unconfirmed", value: String(homeOrders.totals.unconfirmed), trend: "Home", hint: "" },
|
||||
];
|
||||
return `
|
||||
<div class="stack">
|
||||
<section class="grid grid-2">
|
||||
<section class="grid grid-4">
|
||||
${stats
|
||||
.map(
|
||||
(item) => `
|
||||
@@ -476,7 +481,7 @@ async function dashboardPage(session) {
|
||||
</section>
|
||||
<section class="detail-grid">
|
||||
<div class="panel">
|
||||
${panelHeader("Recent orders", "A compact snapshot of the latest patient orders and their state.", '<a class="btn btn-secondary" href="/orders">View all</a>')}
|
||||
${panelHeader("Recent orders", `Monthly snapshot from /order/home for ${homeOrders.month}/${homeOrders.year}.`, '<a class="btn btn-secondary" href="/orders">View all</a>')}
|
||||
<div class="table-wrap">
|
||||
<table>
|
||||
<thead>
|
||||
@@ -497,7 +502,7 @@ async function dashboardPage(session) {
|
||||
`,
|
||||
)
|
||||
.join("")
|
||||
: `<tr><td colspan="4">${emptyState("No orders returned", "The order endpoint did not return any rows for this session.")}</td></tr>`}
|
||||
: `<tr><td colspan="4">${emptyState("No orders returned", "The home endpoint did not return any rows for this month.")}</td></tr>`}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
@@ -507,39 +512,70 @@ async function dashboardPage(session) {
|
||||
`;
|
||||
}
|
||||
|
||||
function renderOrdersTable(orders, selectedOrderId, filter = "All") {
|
||||
const selected = orders.find((item) => item.id === selectedOrderId) || orders[0] || null;
|
||||
function renderOrdersTable({
|
||||
items = [],
|
||||
search = "",
|
||||
month = "",
|
||||
year = "",
|
||||
currentPage = 1,
|
||||
hasNext = false,
|
||||
hasPrev = false,
|
||||
selectedOrderId = "",
|
||||
} = {}) {
|
||||
const now = new Date();
|
||||
const resolvedMonth = String(month || now.getMonth() + 1).padStart(2, "0");
|
||||
const resolvedYear = String(year || now.getFullYear());
|
||||
const monthOptions = Array.from({ length: 12 }, (_, index) => {
|
||||
const value = String(index + 1).padStart(2, "0");
|
||||
return `<option value="${value}" ${value === resolvedMonth ? "selected" : ""}>${value}</option>`;
|
||||
}).join("");
|
||||
const yearStart = Number(resolvedYear) - 1;
|
||||
const yearOptions = Array.from({ length: 3 }, (_, index) => {
|
||||
const value = String(yearStart + index);
|
||||
return `<option value="${value}" ${value === resolvedYear ? "selected" : ""}>${value}</option>`;
|
||||
}).join("");
|
||||
const prevPage = Math.max(1, Number(currentPage) - 1);
|
||||
const nextPage = Math.max(1, Number(currentPage) + 1);
|
||||
const selected = items.find((item) => item.id === selectedOrderId) || items[0] || null;
|
||||
const selectedId = selected?.id || "";
|
||||
return `
|
||||
<div class="detail-grid">
|
||||
<section class="panel">
|
||||
${panelHeader("Search orders", "Use the filter to match the old app flow without giving up desktop readability.", '<a class="btn btn-primary" href="/orders/new">Create order</a>')}
|
||||
<form class="pill-row" hx-get="/fragments/orders/table" hx-target="#orders-fragment" hx-push-url="true">
|
||||
<input type="hidden" name="status" value="${escapeHtml(filter)}" />
|
||||
${["All", "Processing", "Ready", "Needs review"]
|
||||
.map(
|
||||
(item) => `
|
||||
<button class="pill ${filter === item ? "active" : ""}" name="status" value="${escapeHtml(item)}" type="submit">${escapeHtml(item)}</button>
|
||||
`,
|
||||
)
|
||||
.join("")}
|
||||
${panelHeader("Orders", "Monthly order list from the desktop endpoint with name, month, and year filters.", '<a class="btn btn-primary" href="/orders/new">Create order</a>')}
|
||||
<form class="card" hx-get="/fragments/orders/table" hx-target="#orders-fragment" hx-push-url="true">
|
||||
<div class="grid grid-3">
|
||||
<label class="field"><span>Search patient</span><input name="search" type="search" value="${escapeHtml(search)}" placeholder="ANDI SETADI" /></label>
|
||||
<label class="field"><span>Month</span><select name="month">${monthOptions}</select></label>
|
||||
<label class="field"><span>Year</span><select name="year">${yearOptions}</select></label>
|
||||
</div>
|
||||
<input type="hidden" name="current_page" value="1" />
|
||||
<input type="hidden" name="selected" value="${escapeHtml(selectedId)}" />
|
||||
<div class="topbar-actions" style="justify-content:flex-end; margin-top:14px">
|
||||
<button class="btn btn-primary" type="submit">Apply filter</button>
|
||||
</div>
|
||||
</form>
|
||||
${
|
||||
orders.length
|
||||
items.length
|
||||
? `
|
||||
<div id="orders-table" class="desktop-only table-wrap" style="margin-top:16px">
|
||||
<div class="table-wrap" style="margin-top:16px">
|
||||
<table>
|
||||
<thead>
|
||||
<tr><th>Patient</th><th>Order ID</th><th>Doctor</th><th>Status</th><th>Updated</th></tr>
|
||||
<tr><th>Patient</th><th>Order ID</th><th>Order QR</th><th>Date</th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
${orders
|
||||
${items
|
||||
.map(
|
||||
(order) => `
|
||||
<tr>
|
||||
<td><strong>${escapeHtml(order.patient || "Unknown patient")}</strong><br /><span class="muted">${escapeHtml(order.mode || "-")}</span></td>
|
||||
<td><a href="/orders/${order.id}">${escapeHtml(order.id)}</a></td>
|
||||
<td>${escapeHtml(order.doctor || "-")}</td>
|
||||
<td>${statusBadge(order.status)}</td>
|
||||
<tr
|
||||
class="order-row ${selectedId === order.id ? "active" : ""}"
|
||||
hx-get="/fragments/orders/table?search=${encodeURIComponent(search)}&month=${encodeURIComponent(resolvedMonth)}&year=${encodeURIComponent(resolvedYear)}¤t_page=${encodeURIComponent(String(currentPage || 1))}&selected=${encodeURIComponent(order.id)}"
|
||||
hx-target="#orders-fragment"
|
||||
hx-push-url="true"
|
||||
hx-trigger="click"
|
||||
>
|
||||
<td><strong>${escapeHtml(order.patient || "Unknown patient")}</strong><br /><span class="muted">${escapeHtml(order.diagnosis || "-")}</span></td>
|
||||
<td>${escapeHtml(order.id || "-")}</td>
|
||||
<td>${escapeHtml(order.qrcode || "-")}</td>
|
||||
<td>${escapeHtml(order.updated || "-")}</td>
|
||||
</tr>
|
||||
`,
|
||||
@@ -548,33 +584,31 @@ function renderOrdersTable(orders, selectedOrderId, filter = "All") {
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="mobile-only list" style="margin-top:16px">
|
||||
${orders
|
||||
.map(
|
||||
(order) => `
|
||||
<article class="card">
|
||||
<div class="topbar-actions" style="justify-content:space-between">
|
||||
<div>
|
||||
<strong>${escapeHtml(order.patient || "Unknown patient")}</strong>
|
||||
<p class="muted">${escapeHtml(order.id || "-")} · ${escapeHtml(order.mode || "-")}</p>
|
||||
</div>
|
||||
${statusBadge(order.status)}
|
||||
</div>
|
||||
<div class="pill-row" style="margin-top:12px">
|
||||
<span class="pill">${escapeHtml(order.doctor || "-")}</span>
|
||||
<span class="pill">${escapeHtml(order.updated || "-")}</span>
|
||||
</div>
|
||||
</article>
|
||||
`,
|
||||
)
|
||||
.join("")}
|
||||
</div>
|
||||
`
|
||||
: emptyState("No orders returned", "The order endpoint did not return any rows for this filter.")
|
||||
: emptyState("No orders returned", "The desktop order endpoint did not return any rows for this filter.")
|
||||
}
|
||||
<div class="topbar-actions" style="justify-content:space-between; margin-top:16px">
|
||||
<button
|
||||
class="btn btn-secondary"
|
||||
type="button"
|
||||
hx-get="/fragments/orders/table?search=${encodeURIComponent(search)}&month=${encodeURIComponent(resolvedMonth)}&year=${encodeURIComponent(resolvedYear)}¤t_page=${encodeURIComponent(String(prevPage))}&selected=${encodeURIComponent(selectedId)}"
|
||||
hx-target="#orders-fragment"
|
||||
hx-push-url="true"
|
||||
${hasPrev ? "" : "disabled"}
|
||||
>Previous</button>
|
||||
<span class="pill">Page ${escapeHtml(String(currentPage || 1))}</span>
|
||||
<button
|
||||
class="btn btn-secondary"
|
||||
type="button"
|
||||
hx-get="/fragments/orders/table?search=${encodeURIComponent(search)}&month=${encodeURIComponent(resolvedMonth)}&year=${encodeURIComponent(resolvedYear)}¤t_page=${encodeURIComponent(String(nextPage))}&selected=${encodeURIComponent(selectedId)}"
|
||||
hx-target="#orders-fragment"
|
||||
hx-push-url="true"
|
||||
${hasNext ? "" : "disabled"}
|
||||
>Next</button>
|
||||
</div>
|
||||
</section>
|
||||
<aside class="panel">
|
||||
${panelHeader("Selected order", "Master-detail layout keeps context visible while reviewing the list.", selected ? `<a class="btn btn-secondary" href="/orders/${selected.id}">Open detail</a>` : "")}
|
||||
${panelHeader("Selected order", "Click a row to update the detail pane. The row you pick is highlighted.", selected ? `<span class="pill">Selected</span>` : "")}
|
||||
${
|
||||
selected
|
||||
? `
|
||||
@@ -583,19 +617,20 @@ function renderOrdersTable(orders, selectedOrderId, filter = "All") {
|
||||
<strong>${escapeHtml(selected.patient || "Unknown patient")}</strong>
|
||||
<p class="muted">${escapeHtml(selected.id || "-")} · ${escapeHtml(selected.updated || "-")}</p>
|
||||
<div class="pill-row" style="margin-top:12px">
|
||||
${statusBadge(selected.status)}
|
||||
<span class="pill">Doctor ${escapeHtml(selected.doctor || "-")}</span>
|
||||
<span class="pill">${escapeHtml(selected.orderDate || selected.updated || "-")}</span>
|
||||
${selected.status ? statusBadge(selected.status) : ""}
|
||||
<span class="pill">${escapeHtml(selected.qrcode || "-")}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mini-list">
|
||||
<div class="mini-item"><div><strong>NIK</strong><p>${escapeHtml(selected.orderNik || selected.diagnosis || "-")}</p></div></div>
|
||||
<div class="mini-item"><div><strong>NIK</strong><p>${escapeHtml(selected.orderNik || "-")}</p></div></div>
|
||||
<div class="mini-item"><div><strong>Phone</strong><p>${escapeHtml(selected.orderHp || "-")}</p></div></div>
|
||||
<div class="mini-item"><div><strong>Address</strong><p>${escapeHtml(selected.orderAddress || selected.message || "-")}</p></div></div>
|
||||
<div class="mini-item"><div><strong>Address</strong><p>${escapeHtml(selected.orderAddress || "-")}</p></div></div>
|
||||
<div class="mini-item"><div><strong>Diagnosis</strong><p>${escapeHtml(selected.diagnosis || "-")}</p></div></div>
|
||||
<div class="mini-item"><div><strong>Note</strong><p>${escapeHtml(selected.message || "-")}</p></div></div>
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
: emptyState("No selected order", "The API returned no rows for this search.")
|
||||
: emptyState("No selected order", "Click one row on the left to see its detail here.")
|
||||
}
|
||||
</aside>
|
||||
</div>
|
||||
@@ -1355,8 +1390,8 @@ async function orderNewPage(session, path) {
|
||||
});
|
||||
}
|
||||
|
||||
function ordersPage({ query = {}, orders = [], selectedOrderId = "" } = {}, session = {}) {
|
||||
return layout("Orders", `<div id="orders-fragment">${renderOrdersTable(orders, selectedOrderId, query.status || "All")}</div>`, {
|
||||
function ordersPage(data = {}, session = {}) {
|
||||
return layout("Orders", `<div id="orders-fragment">${renderOrdersTable(data)}</div>`, {
|
||||
authenticated: true,
|
||||
activePath: "/orders",
|
||||
...accountLayoutOptions(session),
|
||||
@@ -1582,6 +1617,46 @@ function normalizeOrder(raw, index = 0) {
|
||||
};
|
||||
}
|
||||
|
||||
function normalizeHomeOrder(raw, index = 0) {
|
||||
const status = String(raw?.is_confirm || raw?.status || "").toUpperCase() === "Y" ? "Confirmed" : "Unconfirmed";
|
||||
return {
|
||||
id: raw?.order_id || raw?.id || raw?.order_patient_id || "",
|
||||
patient: raw?.order_name || raw?.patient_name || raw?.name || "",
|
||||
doctor: raw?.doctor_id || raw?.doctor_name || raw?.doctor || "",
|
||||
updated: raw?.order_date || raw?.updated_at || raw?.updated || "",
|
||||
status,
|
||||
tone: statusClass(status),
|
||||
mode: raw?.LabNumber && raw?.LabNumber !== "-" ? raw.LabNumber : raw?.order_qrcode || "",
|
||||
age: String(raw?.age || raw?.patient_age || ""),
|
||||
gender: raw?.gender || raw?.patient_gender || "",
|
||||
tests: Array.isArray(raw?.details) ? raw.details.map((item) => item?.test_name || item?.name || "").filter(Boolean) : [],
|
||||
diagnosis: raw?.order_diagnosa || raw?.diagnosis || "",
|
||||
message: raw?.order_note || raw?.note || "",
|
||||
orderDate: raw?.order_date || "",
|
||||
orderNik: raw?.order_nik || "",
|
||||
orderHp: raw?.order_hp || "",
|
||||
orderAddress: raw?.order_address || "",
|
||||
orderDob: raw?.order_dob || "",
|
||||
};
|
||||
}
|
||||
|
||||
function normalizeDesktopOrder(raw, index = 0) {
|
||||
return {
|
||||
id: raw?.order_id || raw?.id || raw?.order_patient_id || "",
|
||||
patient: raw?.order_name || raw?.patient_name || raw?.name || "",
|
||||
doctor: raw?.doctor_id || raw?.doctor_name || raw?.doctor || "",
|
||||
updated: raw?.order_date || raw?.updated_at || raw?.updated || "",
|
||||
qrcode: raw?.order_qrcode || raw?.qrcode || "",
|
||||
orderNik: raw?.order_nik || "",
|
||||
orderHp: raw?.order_hp || "",
|
||||
orderAddress: raw?.order_address || "",
|
||||
orderDob: raw?.order_dob || "",
|
||||
diagnosis: raw?.order_diagnosa || raw?.diagnosis || "",
|
||||
message: raw?.order_note || raw?.note || "",
|
||||
status: String(raw?.is_confirm || raw?.status || "").toUpperCase() === "Y" ? "Confirmed" : "",
|
||||
};
|
||||
}
|
||||
|
||||
function normalizeResult(raw, index = 0) {
|
||||
const status = raw?.status || raw?.result_status || raw?.order_status || "Pending";
|
||||
const detailsSource = raw?.details || raw?.items || raw?.order_details || [];
|
||||
@@ -1640,6 +1715,74 @@ async function loadOrders(session, search = "", status = "All") {
|
||||
return [];
|
||||
}
|
||||
|
||||
async function loadHomeOrders(session) {
|
||||
try {
|
||||
const now = new Date();
|
||||
const payload = await apiPost(
|
||||
"/order/home",
|
||||
{
|
||||
token: session.token,
|
||||
month: String(now.getMonth() + 1),
|
||||
year: String(now.getFullYear()),
|
||||
},
|
||||
session.token,
|
||||
);
|
||||
const rows = extractArray(payload) || payload?.data || [];
|
||||
const items = Array.isArray(rows) ? rows.map((row, index) => normalizeHomeOrder(row, index)).filter((item) => item.id) : [];
|
||||
const totals = {
|
||||
total: Number(payload?.total_order || payload?.total || items.length || 0),
|
||||
confirmed: Number(payload?.total_confirmed || items.filter((item) => item.status === "Confirmed").length || 0),
|
||||
unconfirmed: Number(payload?.total_unconfirmed || items.filter((item) => item.status === "Unconfirmed").length || 0),
|
||||
};
|
||||
return { items, totals, month: String(now.getMonth() + 1), year: String(now.getFullYear()) };
|
||||
} catch {
|
||||
return { items: [], totals: { total: 0, confirmed: 0, unconfirmed: 0 }, month: "", year: "" };
|
||||
}
|
||||
}
|
||||
|
||||
async function loadDesktopOrders(session, { search = "", month = "", year = "", currentPage = 1 } = {}) {
|
||||
try {
|
||||
const now = new Date();
|
||||
const resolvedMonth = String(month || now.getMonth() + 1);
|
||||
const resolvedYear = String(year || now.getFullYear());
|
||||
const resolvedPage = String(Math.max(1, Number(currentPage) || 1));
|
||||
const payload = await apiPost(
|
||||
"/order/search_order_pasien_by_doktorid_desktop",
|
||||
{
|
||||
token: session.token,
|
||||
month: resolvedMonth,
|
||||
year: resolvedYear,
|
||||
search: String(search || ""),
|
||||
current_page: resolvedPage,
|
||||
OrderPatientM_DoctorID: session.doctorId || sampleLogin.doctorId,
|
||||
},
|
||||
session.token,
|
||||
);
|
||||
const rows = extractArray(payload) || payload?.data || [];
|
||||
const items = Array.isArray(rows) ? rows.map((row, index) => normalizeDesktopOrder(row, index)).filter((item) => item.id) : [];
|
||||
return {
|
||||
items,
|
||||
month: resolvedMonth,
|
||||
year: resolvedYear,
|
||||
currentPage: Number(resolvedPage),
|
||||
search: String(search || ""),
|
||||
hasNext: items.length > 0,
|
||||
hasPrev: Number(resolvedPage) > 1,
|
||||
};
|
||||
} catch {
|
||||
const now = new Date();
|
||||
return {
|
||||
items: [],
|
||||
month: String(month || now.getMonth() + 1),
|
||||
year: String(year || now.getFullYear()),
|
||||
currentPage: Number(currentPage) || 1,
|
||||
search: String(search || ""),
|
||||
hasNext: false,
|
||||
hasPrev: false,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
async function loadResults(session, search = "") {
|
||||
const term = String(search || "").trim();
|
||||
try {
|
||||
@@ -1827,75 +1970,15 @@ async function readBody(req) {
|
||||
return flat;
|
||||
}
|
||||
|
||||
function fragmentOrdersTable(search = "", status = "All", ordersData = null) {
|
||||
const orders = ordersData || [];
|
||||
const selected = orders[0] || null;
|
||||
return `
|
||||
<div class="detail-grid">
|
||||
<section class="panel">
|
||||
${panelHeader("Search orders", "Filter the list without full page refresh.")}
|
||||
<form class="pill-row" hx-get="/fragments/orders/table" hx-target="#orders-fragment" hx-push-url="true">
|
||||
<input type="hidden" name="search" value="${escapeHtml(search)}" />
|
||||
${["All", "Processing", "Ready", "Needs review"]
|
||||
.map(
|
||||
(item) => `
|
||||
<button class="pill ${status === item ? "active" : ""}" name="status" value="${escapeHtml(item)}" type="submit">${escapeHtml(item)}</button>
|
||||
`,
|
||||
)
|
||||
.join("")}
|
||||
</form>
|
||||
${
|
||||
orders.length
|
||||
? `
|
||||
<div id="orders-table" class="table-wrap" style="margin-top:16px">
|
||||
<table>
|
||||
<thead>
|
||||
<tr><th>Patient</th><th>Order ID</th><th>Doctor</th><th>Status</th><th>Updated</th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
${orders
|
||||
.map(
|
||||
(order) => `
|
||||
<tr>
|
||||
<td><strong>${escapeHtml(order.patient || "Unknown patient")}</strong><br /><span class="muted">${escapeHtml(order.mode || "-")}</span></td>
|
||||
<td><a href="/orders/${order.id}">${escapeHtml(order.id)}</a></td>
|
||||
<td>${escapeHtml(order.doctor || "-")}</td>
|
||||
<td>${statusBadge(order.status)}</td>
|
||||
<td>${escapeHtml(order.updated || "-")}</td>
|
||||
</tr>
|
||||
`,
|
||||
)
|
||||
.join("")}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
`
|
||||
: emptyState("No orders returned", "The order endpoint did not return any rows for this filter.")
|
||||
}
|
||||
</section>
|
||||
<aside class="panel">
|
||||
${panelHeader("Selected order", "Context stays visible while you review the table.", selected ? `<a class="btn btn-secondary" href="/orders/${selected.id}">Open detail</a>` : "")}
|
||||
${
|
||||
selected
|
||||
? `
|
||||
<div class="stack">
|
||||
<div class="card">
|
||||
<strong>${escapeHtml(selected.patient || "Unknown patient")}</strong>
|
||||
<p class="muted">${escapeHtml(selected.id || "-")} · ${escapeHtml(selected.mode || "-")}</p>
|
||||
<div class="pill-row" style="margin-top:12px">${statusBadge(selected.status)}<span class="pill">${escapeHtml(selected.age || "-")} years</span><span class="pill">${escapeHtml(selected.gender || "-")}</span></div>
|
||||
</div>
|
||||
<div class="mini-list">
|
||||
<div class="mini-item"><div><strong>Diagnosis</strong><p>${escapeHtml(selected.diagnosis || "-")}</p></div></div>
|
||||
<div class="mini-item"><div><strong>Requested tests</strong><p>${escapeHtml((selected.tests || []).join(", ") || "-")}</p></div></div>
|
||||
<div class="mini-item"><div><strong>Special note</strong><p>${escapeHtml(selected.message || "-")}</p></div></div>
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
: emptyState("No selected order", "The API returned no rows for this search.")
|
||||
}
|
||||
</aside>
|
||||
</div>
|
||||
`;
|
||||
function fragmentOrdersTable(search = "", month = "", year = "", currentPage = 1, selected = "", data = null) {
|
||||
return renderOrdersTable({
|
||||
...(data || {}),
|
||||
search,
|
||||
month,
|
||||
year,
|
||||
currentPage,
|
||||
selectedOrderId: selected,
|
||||
});
|
||||
}
|
||||
|
||||
function fragmentResultsTable(search = "", resultsData = null) {
|
||||
@@ -2140,8 +2223,8 @@ async function renderRoute(req, res, url) {
|
||||
|
||||
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 || "" }, session));
|
||||
const orders = await loadDesktopOrders(session, query);
|
||||
html(res, 200, ordersPage({ ...orders, selectedOrderId: query.selected || orders.items[0]?.id || "" }, session));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2235,8 +2318,13 @@ async function renderRoute(req, res, url) {
|
||||
|
||||
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 }) });
|
||||
const orders = await loadDesktopOrders(session, query);
|
||||
html(
|
||||
res,
|
||||
200,
|
||||
fragmentOrdersTable(query.search || "", query.month || "", query.year || "", query.current_page || 1, query.selected || orders.items[0]?.id || "", orders),
|
||||
{ "HX-Trigger": JSON.stringify({ "doclink:orders-updated": true }) },
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
12
styles.css
12
styles.css
@@ -561,6 +561,18 @@ table {
|
||||
background: rgba(255, 255, 255, 0.88);
|
||||
}
|
||||
|
||||
.order-row {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.order-row.active td {
|
||||
background: rgba(185, 28, 28, 0.08);
|
||||
}
|
||||
|
||||
.order-row:hover td {
|
||||
background: rgba(185, 28, 28, 0.05);
|
||||
}
|
||||
|
||||
th,
|
||||
td {
|
||||
padding: 14px 16px;
|
||||
|
||||
Reference in New Issue
Block a user