Pack FPP selection by column height

This commit is contained in:
sas.fajri
2026-04-13 17:11:42 +07:00
parent 9a28421108
commit 0030cfb11a
2 changed files with 119 additions and 74 deletions

186
server.js
View File

@@ -631,6 +631,7 @@ function renderOrderDetail(order) {
function renderOrderForm(step, stepKey = "demografi", fppTests = [], mouId = "") { function renderOrderForm(step, stepKey = "demografi", fppTests = [], mouId = "") {
const fppGroups = groupFppTestsForSelection(fppTests); const fppGroups = groupFppTestsForSelection(fppTests);
const packedGroups = packFppGroupsIntoColumns(fppGroups, 5);
const steps = [ const steps = [
["demografi", "Demografi", "Patient identity and contact details."], ["demografi", "Demografi", "Patient identity and contact details."],
["diagnosa", "Diagnosa", "Clinical indication and diagnosis."], ["diagnosa", "Diagnosa", "Clinical indication and diagnosis."],
@@ -689,50 +690,58 @@ function renderOrderForm(step, stepKey = "demografi", fppTests = [], mouId = "")
<p id="order-selected-count">0 selected</p> <p id="order-selected-count">0 selected</p>
</div> </div>
${ ${
fppGroups.length packedGroups.length
? `<div class="fpp-select-board">${fppGroups ? `<div class="fpp-select-board">${packedGroups
.map( .map(
(group) => ` (column) => `
<article class="fpp-select-column"> <div class="fpp-select-stack">
<div class="fpp-select-head"> ${column
<div class="fpp-select-title">${escapeHtml(group.heading)}</div> .map(
<div class="fpp-select-count">${group.sections.reduce((sum, section) => sum + section.tests.length, 0)} tests</div> (group) => `
</div> <article class="fpp-select-column">
<div class="fpp-select-body"> <div class="fpp-select-head">
${group.sections <div class="fpp-select-title">${escapeHtml(group.heading)}</div>
.map( <div class="fpp-select-count">${group.sections.reduce((sum, section) => sum + section.tests.length, 0)} tests</div>
(section) => ` </div>
<section class="fpp-select-section"> <div class="fpp-select-body">
${section.title ? `<div class="fpp-select-section-head">${escapeHtml(section.title)}</div>` : ""} ${group.sections
<ul class="fpp-select-list"> .map(
${section.tests (section) => `
.map( <section class="fpp-select-section">
(test) => ` ${section.title ? `<div class="fpp-select-section-head">${escapeHtml(section.title)}</div>` : ""}
<li class="fpp-select-row ${test.doctortest ? "" : "is-disabled"}"> <ul class="fpp-select-list">
<label class="fpp-select-label"> ${section.tests
<input .map(
class="fpp-select-toggle" (test) => `
type="checkbox" <li class="fpp-select-row ${test.doctortest ? "" : "is-disabled"}">
${test.doctortest ? "" : "disabled"} <label class="fpp-select-label">
data-test-id="${escapeHtml(test.testId)}" <input
data-test-name="${escapeHtml(test.name)}" class="fpp-select-toggle"
data-test-price="${escapeHtml(test.price)}" type="checkbox"
data-test-heading="${escapeHtml(group.heading)}" ${test.doctortest ? "" : "disabled"}
data-test-subcategory="${escapeHtml(section.title || "")}" data-test-id="${escapeHtml(test.testId)}"
/> data-test-name="${escapeHtml(test.name)}"
<span class="fpp-select-name">${escapeHtml(test.name)}</span> data-test-price="${escapeHtml(test.price)}"
</label> data-test-heading="${escapeHtml(group.heading)}"
</li> data-test-subcategory="${escapeHtml(section.title || "")}"
`, />
) <span class="fpp-select-name">${escapeHtml(test.name)}</span>
.join("")} </label>
</ul> </li>
</section> `,
`, )
) .join("")}
.join("")} </ul>
</div> </section>
</article> `,
)
.join("")}
</div>
</article>
`,
)
.join("")}
</div>
`, `,
) )
.join("")}</div>` .join("")}</div>`
@@ -954,9 +963,30 @@ function groupFppTestsForSelection(tests = []) {
})); }));
} }
function packFppGroupsIntoColumns(groups = [], maxColumns = 5) {
const columnCount = Math.min(Math.max(groups.length, 1), maxColumns);
const columns = Array.from({ length: columnCount }, () => ({ items: [], score: 0 }));
const estimateScore = (group) =>
1 +
group.sections.length +
group.sections.reduce((sum, section) => sum + section.tests.length * 0.12, 0);
for (const group of groups) {
let target = columns[0];
for (const column of columns) {
if (column.score < target.score) target = column;
}
target.items.push(group);
target.score += estimateScore(group);
}
return columns.map((column) => column.items);
}
function renderFpp(groups, activeGroup = "All") { function renderFpp(groups, activeGroup = "All") {
const availableGroups = groups.map((item) => item.heading); const availableGroups = groups.map((item) => item.heading);
const visibleGroups = activeGroup === "All" ? groups : groups.filter((item) => item.heading === activeGroup); const visibleGroups = activeGroup === "All" ? groups : groups.filter((item) => item.heading === activeGroup);
const packedGroups = packFppGroupsIntoColumns(visibleGroups, 5);
return ` return `
<div class="stack swap-zone fpp-shell"> <div class="stack swap-zone fpp-shell">
<section class="panel fpp-toolbar"> <section class="panel fpp-toolbar">
@@ -971,38 +1001,46 @@ function renderFpp(groups, activeGroup = "All") {
<div class="fpp-sheet-meta">Hitam putih, padat, dan mengikuti pembagian grup seperti form manual.</div> <div class="fpp-sheet-meta">Hitam putih, padat, dan mengikuti pembagian grup seperti form manual.</div>
</div> </div>
<div class="fpp-board"> <div class="fpp-board">
${visibleGroups ${packedGroups
.map( .map(
(group) => ` (column) => `
<article class="fpp-column"> <div class="fpp-select-stack">
<div class="fpp-column-head"> ${column
<div class="fpp-column-title">${escapeHtml(group.heading)}</div> .map(
<div class="fpp-column-count">${group.sections.reduce((sum, section) => sum + section.tests.length, 0)} tests</div> (group) => `
</div> <article class="fpp-column">
<div class="fpp-column-body"> <div class="fpp-column-head">
${group.sections <div class="fpp-column-title">${escapeHtml(group.heading)}</div>
.map( <div class="fpp-column-count">${group.sections.reduce((sum, section) => sum + section.tests.length, 0)} tests</div>
(section) => ` </div>
<section class="fpp-section"> <div class="fpp-column-body">
${section.title ? `<div class="fpp-section-head">${escapeHtml(section.title)}</div>` : ""} ${group.sections
<ul class="fpp-test-list"> .map(
${section.tests (section) => `
.map( <section class="fpp-section">
(test) => ` ${section.title ? `<div class="fpp-section-head">${escapeHtml(section.title)}</div>` : ""}
<li class="fpp-test ${test.doctortest ? "" : "is-disabled"}" title="${test.doctortest ? "" : "Tidak dapat dicentang"}"> <ul class="fpp-test-list">
<span class="fpp-dot" aria-hidden="true"></span> ${section.tests
<span class="fpp-test-name">${escapeHtml(test.name)}</span> .map(
</li> (test) => `
`, <li class="fpp-test ${test.doctortest ? "" : "is-disabled"}" title="${test.doctortest ? "" : "Tidak dapat dicentang"}">
) <span class="fpp-dot" aria-hidden="true"></span>
.join("")} <span class="fpp-test-name">${escapeHtml(test.name)}</span>
</ul> </li>
</section> `,
`, )
) .join("")}
.join("")} </ul>
</div> </section>
</article> `,
)
.join("")}
</div>
</article>
`,
)
.join("")}
</div>
`, `,
) )
.join("")} .join("")}

View File

@@ -745,6 +745,13 @@ tr:last-child td {
align-items: start; align-items: start;
} }
.fpp-select-stack {
display: flex;
flex-direction: column;
gap: 6px;
min-width: 0;
}
.fpp-select-column { .fpp-select-column {
overflow: hidden; overflow: hidden;
border-radius: 8px; border-radius: 8px;