@medicus.ai/medicus-report-pdf-generator 1.3.11 → 1.3.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/config/maisonsante.json +13 -1
- package/lib/big_integral_questionnaire.js +298 -0
- package/lib/template.js +26 -17
- package/lib/wellbeing_report_generator.js +18 -1
- package/locales/en.json +64 -0
- package/locales/wellbeing/en.json +422 -408
- package/package.json +1 -1
- package/preview-big-integral.js +75 -0
- package/templates/maisonsante/ltr_no_pages.html +1 -0
- package/templates/maisonsante/rtl_no_pages.html +1 -0
- package/test.js +7 -10
- package/testing-reports/mediclinic/arabic-data.js +402 -506
- package/testing-reports/mediclinic/doctor-data.js +483 -620
- package/testing-reports/mediclinic/with-wellbeing.js +382 -8110
- package/testing-reports/pha/notes-example.js +397 -0
- package/testing-reports/pha/ex1.js +0 -485
- package/testing-reports/pha/ex2.js +0 -116
- package/testing-reports/pha/prod-patient.js +0 -510
- package/testing-reports/pha/with-wellbeing-full-data.js +0 -813
- package/testing-reports/pha/with-wellbeing.js +0 -529
- package/testing-reports/pha/without-wellbeing.js +0 -448
package/config/maisonsante.json
CHANGED
|
@@ -24,5 +24,17 @@
|
|
|
24
24
|
"body_font_color": "#0F2062",
|
|
25
25
|
"list_icons_font_color": "#0F2062",
|
|
26
26
|
"insights_font_color": "#1A3A7A",
|
|
27
|
-
"signature": "Team Medicus"
|
|
27
|
+
"signature": "Team Medicus",
|
|
28
|
+
"big_integral_questionnaire": {
|
|
29
|
+
"title": "Key to the Big Integral Questionnaire",
|
|
30
|
+
"showHormonalFemale": true,
|
|
31
|
+
"showHormonalMale": true,
|
|
32
|
+
"colors": {
|
|
33
|
+
"headerBg": "#0F2062",
|
|
34
|
+
"subheaderBg": "#1B4080",
|
|
35
|
+
"headerText": "#FFFFFF",
|
|
36
|
+
"rowBorder": "rgba(15, 32, 98, 0.12)",
|
|
37
|
+
"elevatedText": "#A43B2F"
|
|
38
|
+
}
|
|
39
|
+
}
|
|
28
40
|
}
|
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
// ---------------------------------------------------------------------------
|
|
4
|
+
// Dummy data — structure mirrors the Excel RESULTS KEY sheet.
|
|
5
|
+
// result = 0 for all rows (questionnaire not yet filled in).
|
|
6
|
+
// Hormonal Health rows have no High/Questions/Maximum — rendered as "—".
|
|
7
|
+
// ---------------------------------------------------------------------------
|
|
8
|
+
function getDummyData() {
|
|
9
|
+
return {
|
|
10
|
+
rows: [
|
|
11
|
+
{
|
|
12
|
+
system: "STOMACH and GI (Gastrointestinal) Tract",
|
|
13
|
+
high: ">8",
|
|
14
|
+
questions: 9,
|
|
15
|
+
result: 0,
|
|
16
|
+
maximum: 27,
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
system: "Small Intestine",
|
|
20
|
+
high: ">7",
|
|
21
|
+
questions: 8,
|
|
22
|
+
result: 0,
|
|
23
|
+
maximum: 24,
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
system: "Infections/Invasions of the GI (Gastrointestinal Tract)",
|
|
27
|
+
high: ">3",
|
|
28
|
+
questions: 4,
|
|
29
|
+
result: 0,
|
|
30
|
+
maximum: 12,
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
system: "Large Intestine",
|
|
34
|
+
high: ">2",
|
|
35
|
+
questions: 3,
|
|
36
|
+
result: 0,
|
|
37
|
+
maximum: 9,
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
system: "Liver and Gallbladder",
|
|
41
|
+
high: ">7",
|
|
42
|
+
questions: 8,
|
|
43
|
+
result: 0,
|
|
44
|
+
maximum: 22,
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
system: "Essential Nutrients",
|
|
48
|
+
high: ">25",
|
|
49
|
+
questions: 26,
|
|
50
|
+
result: 0,
|
|
51
|
+
maximum: 68,
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
system: "Carbohydrate Metabolism",
|
|
55
|
+
high: ">4",
|
|
56
|
+
questions: 4,
|
|
57
|
+
result: 0,
|
|
58
|
+
maximum: 12,
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
system: "Immune System",
|
|
62
|
+
high: ">3",
|
|
63
|
+
questions: 4,
|
|
64
|
+
result: 0,
|
|
65
|
+
maximum: 10,
|
|
66
|
+
},
|
|
67
|
+
{ system: "Lifestyle", high: ">7", questions: 7, result: 0, maximum: 7 },
|
|
68
|
+
{
|
|
69
|
+
system: "Hormonal Health Female",
|
|
70
|
+
high: null,
|
|
71
|
+
questions: null,
|
|
72
|
+
result: 0,
|
|
73
|
+
maximum: null,
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
system: "Hormonal Health Male",
|
|
77
|
+
high: null,
|
|
78
|
+
questions: null,
|
|
79
|
+
result: 0,
|
|
80
|
+
maximum: null,
|
|
81
|
+
},
|
|
82
|
+
],
|
|
83
|
+
meta: {
|
|
84
|
+
patientName: "Final Test 3",
|
|
85
|
+
age: "37",
|
|
86
|
+
bmi: "23.67",
|
|
87
|
+
},
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// ---------------------------------------------------------------------------
|
|
92
|
+
// Helpers
|
|
93
|
+
// ---------------------------------------------------------------------------
|
|
94
|
+
function fmt(val, decimals) {
|
|
95
|
+
if (val === null || val === undefined) return "\u2014"; // em dash
|
|
96
|
+
if (typeof val === "number") {
|
|
97
|
+
const rounded =
|
|
98
|
+
Math.round(val * Math.pow(10, decimals)) / Math.pow(10, decimals);
|
|
99
|
+
return String(rounded);
|
|
100
|
+
}
|
|
101
|
+
return String(val);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// ---------------------------------------------------------------------------
|
|
105
|
+
// Single render — faithful to the reference image, Maison Sante colours.
|
|
106
|
+
//
|
|
107
|
+
// Structure:
|
|
108
|
+
// ┌──────────────────────────────────────────────────────┐
|
|
109
|
+
// │ Key to the Big Integral Questionnaire [title bar] │
|
|
110
|
+
// ├──────────────────────────────────────────────────────┤
|
|
111
|
+
// │ Client/Patient Full Name … Age … BMI … │
|
|
112
|
+
// ├──────────────────────────────────────────────────────┤
|
|
113
|
+
// │ SYSTEM SCORES [subheader band] │
|
|
114
|
+
// ├────────────┬──────┬─────────┬────────┬───────┬──┬───┤
|
|
115
|
+
// │ SYSTEM │ High │Questions│ Result │Maximum│/3 │Cmt│
|
|
116
|
+
// ├────────────┼──────┼─────────┼────────┼───────┼──┼───┤
|
|
117
|
+
// │ ...rows... │
|
|
118
|
+
// └──────────────────────────────────────────────────────┘
|
|
119
|
+
// ---------------------------------------------------------------------------
|
|
120
|
+
function renderTable(rows, meta, cfg) {
|
|
121
|
+
const c = cfg.colors;
|
|
122
|
+
const title = cfg.title || "Key to the Big Integral Questionnaire";
|
|
123
|
+
|
|
124
|
+
// ── patient info bar ──────────────────────────────────────────────────
|
|
125
|
+
const infoBar = `
|
|
126
|
+
<div style="background:#ffffff;border-bottom:1px solid ${c.rowBorder};">
|
|
127
|
+
<table style="border-collapse:collapse;">
|
|
128
|
+
<tr>
|
|
129
|
+
<td style="padding:7px 40px 7px 14px;font-size:9px;color:#1a1a1a;white-space:nowrap;vertical-align:middle;">
|
|
130
|
+
<span style="color:${c.headerBg};font-weight:700;">Client/Patient Full Name</span>
|
|
131
|
+
${meta.patientName}
|
|
132
|
+
</td>
|
|
133
|
+
<td style="padding:7px 40px 7px 0;font-size:9px;color:#1a1a1a;white-space:nowrap;vertical-align:middle;">
|
|
134
|
+
<span style="color:${c.headerBg};font-weight:700;">Age</span>
|
|
135
|
+
${meta.age}
|
|
136
|
+
</td>
|
|
137
|
+
<td style="padding:7px 0 7px 0;font-size:9px;color:#1a1a1a;white-space:nowrap;vertical-align:middle;">
|
|
138
|
+
<span style="color:${c.headerBg};font-weight:700;">BMI</span>
|
|
139
|
+
${meta.bmi}
|
|
140
|
+
</td>
|
|
141
|
+
</tr>
|
|
142
|
+
</table>
|
|
143
|
+
</div>`;
|
|
144
|
+
|
|
145
|
+
// ── "SYSTEM SCORES" subheader band ───────────────────────────────────
|
|
146
|
+
const subheaderBg = c.subheaderBg || "#1B4080";
|
|
147
|
+
const subheaderBand = `
|
|
148
|
+
<div style="
|
|
149
|
+
padding: 5px 14px;
|
|
150
|
+
background: ${subheaderBg};
|
|
151
|
+
color: #ffffff;
|
|
152
|
+
font-size: 8.5px;
|
|
153
|
+
font-weight: 700;
|
|
154
|
+
letter-spacing: 0.8px;
|
|
155
|
+
text-transform: uppercase;
|
|
156
|
+
">SYSTEM SCORES</div>`;
|
|
157
|
+
|
|
158
|
+
// ── column widths ──────────────────────────────────────────────────────
|
|
159
|
+
const COL = {
|
|
160
|
+
system: "width:34%;text-align:left;",
|
|
161
|
+
high: "width:8%; text-align:center;",
|
|
162
|
+
questions: "width:9%; text-align:center;",
|
|
163
|
+
result: "width:8%; text-align:center;",
|
|
164
|
+
maximum: "width:9%; text-align:center;",
|
|
165
|
+
perThree: "width:8%; text-align:center;",
|
|
166
|
+
comments: "width:24%;text-align:left;",
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
const TH_BASE = `padding:6px 14px;font-size:8px;font-weight:700;color:#ffffff;
|
|
170
|
+
background:${c.headerBg};border-bottom:2px solid rgba(255,255,255,0.2);`;
|
|
171
|
+
|
|
172
|
+
const th = (label, colKey) =>
|
|
173
|
+
`<th style="${TH_BASE}${COL[colKey]}">${label}</th>`;
|
|
174
|
+
|
|
175
|
+
const tableHeader = `
|
|
176
|
+
<tr>
|
|
177
|
+
${th("SYSTEM", "system")}
|
|
178
|
+
${th("High", "high")}
|
|
179
|
+
${th("Questions", "questions")}
|
|
180
|
+
${th("Result", "result")}
|
|
181
|
+
${th("Maximum", "maximum")}
|
|
182
|
+
${th("/3", "perThree")}
|
|
183
|
+
${th("Comments", "comments")}
|
|
184
|
+
</tr>`;
|
|
185
|
+
|
|
186
|
+
// ── data rows ─────────────────────────────────────────────────────────
|
|
187
|
+
const TD = (content, colKey, extra = "") =>
|
|
188
|
+
`<td style="padding:5px 14px;font-size:8.5px;${COL[colKey]}border-bottom:1px solid ${c.rowBorder};${extra}">${content}</td>`;
|
|
189
|
+
|
|
190
|
+
const dataRows = rows
|
|
191
|
+
.map((row, i) => {
|
|
192
|
+
const hasThreshold = row.high !== null && row.high !== undefined;
|
|
193
|
+
const hasQuantity = row.questions !== null && row.questions !== undefined;
|
|
194
|
+
const hasMaximum = row.maximum !== null && row.maximum !== undefined;
|
|
195
|
+
|
|
196
|
+
const highDisplay = hasThreshold
|
|
197
|
+
? `<span style="color:${c.elevatedText};font-weight:600;">${row.high}</span>`
|
|
198
|
+
: "\u2014";
|
|
199
|
+
|
|
200
|
+
const questionsDisplay = hasQuantity ? String(row.questions) : "\u2014";
|
|
201
|
+
const resultDisplay = String(row.result);
|
|
202
|
+
const maximumDisplay = hasMaximum ? fmt(row.maximum, 0) : "\u2014";
|
|
203
|
+
const perThreeDisplay = hasMaximum ? fmt(row.maximum / 3, 2) : "\u2014";
|
|
204
|
+
|
|
205
|
+
const rowBg = i % 2 === 0 ? "#ffffff" : "rgba(15, 32, 98, 0.03)";
|
|
206
|
+
|
|
207
|
+
return `
|
|
208
|
+
<tr style="background:${rowBg};">
|
|
209
|
+
${TD(`<span style="color:#1a1a1a;">${row.system}</span>`, "system")}
|
|
210
|
+
${TD(highDisplay, "high")}
|
|
211
|
+
${TD(questionsDisplay, "questions")}
|
|
212
|
+
${TD(resultDisplay, "result", `font-weight:600;color:#444;`)}
|
|
213
|
+
${TD(maximumDisplay, "maximum")}
|
|
214
|
+
${TD(perThreeDisplay, "perThree")}
|
|
215
|
+
${TD("", "comments")}
|
|
216
|
+
</tr>`;
|
|
217
|
+
})
|
|
218
|
+
.join("");
|
|
219
|
+
|
|
220
|
+
// ── assemble ──────────────────────────────────────────────────────────
|
|
221
|
+
// Outer wrapper uses padding-top instead of an empty spacer div, because
|
|
222
|
+
// empty divs with only `height` get collapsed by wkhtmltopdf. Padding
|
|
223
|
+
// always renders.
|
|
224
|
+
return `
|
|
225
|
+
<div style="padding-top:25px;font-family:'Open Sans',sans-serif;">
|
|
226
|
+
<div class="biq-wrapper" style="
|
|
227
|
+
font-family: 'Open Sans', sans-serif;
|
|
228
|
+
page-break-inside: avoid;
|
|
229
|
+
border-radius: 4px;
|
|
230
|
+
overflow: hidden;
|
|
231
|
+
border: 1px solid ${c.rowBorder};
|
|
232
|
+
">
|
|
233
|
+
<!-- title bar -->
|
|
234
|
+
<div style="
|
|
235
|
+
background: ${c.headerBg};
|
|
236
|
+
border-radius: 4px 4px 0 0;
|
|
237
|
+
color: #ffffff;
|
|
238
|
+
padding: 9px 14px;
|
|
239
|
+
font-size: 11px;
|
|
240
|
+
font-weight: 700;
|
|
241
|
+
letter-spacing: 0.3px;
|
|
242
|
+
">${title}</div>
|
|
243
|
+
|
|
244
|
+
${infoBar}
|
|
245
|
+
${subheaderBand}
|
|
246
|
+
|
|
247
|
+
<table style="width:100%;border-collapse:collapse;table-layout:fixed;">
|
|
248
|
+
<thead>${tableHeader}</thead>
|
|
249
|
+
<tbody>${dataRows}</tbody>
|
|
250
|
+
</table>
|
|
251
|
+
</div>
|
|
252
|
+
</div>`;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// ---------------------------------------------------------------------------
|
|
256
|
+
// Public entry
|
|
257
|
+
// ---------------------------------------------------------------------------
|
|
258
|
+
/**
|
|
259
|
+
* Render the Big Integral Questionnaire section for Maison Sante doctor PDFs.
|
|
260
|
+
*
|
|
261
|
+
* @param {object} opts
|
|
262
|
+
* @param {object} opts.clientConfig - The full maisonsante.json config object
|
|
263
|
+
* @param {object} opts.localeService - localeService with .t(key) method (unused for now; strings are hardcoded to match the reference design)
|
|
264
|
+
* @returns {string} HTML string to inject into #big-integral-section
|
|
265
|
+
*/
|
|
266
|
+
function renderBigIntegralQuestionnaire({ clientConfig }) {
|
|
267
|
+
const cfg = (clientConfig && clientConfig.big_integral_questionnaire) || {};
|
|
268
|
+
|
|
269
|
+
const colors = Object.assign(
|
|
270
|
+
{
|
|
271
|
+
headerBg: "#0F2062",
|
|
272
|
+
subheaderBg: "#1B4080",
|
|
273
|
+
headerText: "#FFFFFF",
|
|
274
|
+
rowBorder: "rgba(15, 32, 98, 0.12)",
|
|
275
|
+
elevatedText: "#A43B2F",
|
|
276
|
+
},
|
|
277
|
+
cfg.colors || {},
|
|
278
|
+
);
|
|
279
|
+
|
|
280
|
+
const resolvedCfg = Object.assign({}, cfg, { colors });
|
|
281
|
+
|
|
282
|
+
const { rows: allRows, meta } = getDummyData();
|
|
283
|
+
|
|
284
|
+
const rows = allRows.filter((row) => {
|
|
285
|
+
if (
|
|
286
|
+
row.system === "Hormonal Health Female" &&
|
|
287
|
+
cfg.showHormonalFemale === false
|
|
288
|
+
)
|
|
289
|
+
return false;
|
|
290
|
+
if (row.system === "Hormonal Health Male" && cfg.showHormonalMale === false)
|
|
291
|
+
return false;
|
|
292
|
+
return true;
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
return renderTable(rows, meta, resolvedCfg);
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
module.exports = { renderBigIntegralQuestionnaire };
|
package/lib/template.js
CHANGED
|
@@ -3,6 +3,9 @@ const i18n = require('../app/i18n_wellbeing.config.js');
|
|
|
3
3
|
fetchFileContents
|
|
4
4
|
const fs = require("fs");
|
|
5
5
|
const path = require('path');
|
|
6
|
+
|
|
7
|
+
let useMonospace = false;
|
|
8
|
+
function setUseMonospace(val) { useMonospace = val; }
|
|
6
9
|
const INDENTATION = {
|
|
7
10
|
PANEL_TITLE: 12,
|
|
8
11
|
BIOMARKER_DETAILS: 12,
|
|
@@ -1165,7 +1168,12 @@ function renderBiomarkerV3(biomarker, nestingLevel, isChildBiomarker, isCompactV
|
|
|
1165
1168
|
}
|
|
1166
1169
|
let notesPadding = isRtl ? 'padding: 0px 16px 10px 0px;' : 'padding: 0px 0px 10px 16px;';
|
|
1167
1170
|
let classNote = !isCompactView ? 'note-margin-bottom' : '';
|
|
1168
|
-
|
|
1171
|
+
if (useMonospace) {
|
|
1172
|
+
const monoStyle = `font-style: normal; font-size: 13px; color: #333; font-family: 'Roboto Mono', monospace; white-space: pre-wrap; overflow-x: auto;`;
|
|
1173
|
+
newBiomarkerHtml += `<div class="biomarker-notes 2 ${classNote}" style="${notesPadding} ${BioNoteStyle}"><span style="${monoStyle}">${biomarker.notes.join('<br/>')}</span></div>`;
|
|
1174
|
+
} else {
|
|
1175
|
+
newBiomarkerHtml += `<div class="biomarker-notes 2 ${classNote}" style="color: #8F8F92; ${notesPadding} ${BioNoteStyle}">${biomarker.notes.join('<br/>')}</div>`;
|
|
1176
|
+
}
|
|
1169
1177
|
}
|
|
1170
1178
|
}
|
|
1171
1179
|
|
|
@@ -1323,17 +1331,10 @@ function renderDetailsListV3(detailsList, nestingLevel, isCompactView) {
|
|
|
1323
1331
|
}
|
|
1324
1332
|
|
|
1325
1333
|
function renderNoteV3(note, nestingLevel, isCompactView, showInCompactView, showInDetailsView) {
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
plusPadding = isCompactView ? 18 : 29;
|
|
1331
|
-
let levelNesting = extraPadding + nestingLevel * INDENTATION.BIOMARKER_DETAILS + plusPadding;
|
|
1332
|
-
blockStyle = `padding-left: ${levelNesting}px`;
|
|
1333
|
-
}
|
|
1334
|
-
// if (note) {
|
|
1335
|
-
// return `<div style="padding: 2px ${plusPadding}px; ${blockStyle}" class="note-block">${note}</div>`;
|
|
1336
|
-
// }
|
|
1334
|
+
// Standalone biomarkerNote items duplicate the note already rendered inside
|
|
1335
|
+
// renderBiomarkerV3 (biomarker.notes), so they are intentionally suppressed
|
|
1336
|
+
// here to avoid every note appearing twice. Monospace styling for PHA is
|
|
1337
|
+
// handled where biomarker.notes is rendered.
|
|
1337
1338
|
return '';
|
|
1338
1339
|
}
|
|
1339
1340
|
|
|
@@ -1585,9 +1586,16 @@ function renderOneAllergyBiomarker(biomarker, isRtl, nestingLevel, isChildBiomar
|
|
|
1585
1586
|
}
|
|
1586
1587
|
bioIndentStyle = isRtl ? 'padding-right: 16px;' : 'padding-left: 16px;';
|
|
1587
1588
|
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1589
|
+
if (useMonospace) {
|
|
1590
|
+
const monoStyle = `font-style: normal; font-size: 13px; color: #333; font-family: 'Roboto Mono', monospace; white-space: pre-wrap; overflow-x: auto;`;
|
|
1591
|
+
biomarkerDetailsHtml += '<div class="biomarker-notes 1" style="padding-top: 10px;' + bioIndentStyle + '">';
|
|
1592
|
+
biomarkerDetailsHtml += `<span style="${monoStyle}">` + biomarker.notes.join('<br/>') + '</span>';
|
|
1593
|
+
biomarkerDetailsHtml += '</div>';
|
|
1594
|
+
} else {
|
|
1595
|
+
biomarkerDetailsHtml += '<div class="biomarker-notes 1" style="color: #8F8F92;padding-top: 10px;' + bioIndentStyle + '">';
|
|
1596
|
+
biomarkerDetailsHtml += biomarker.notes.join('<br/>');
|
|
1597
|
+
biomarkerDetailsHtml += '</div>';
|
|
1598
|
+
}
|
|
1591
1599
|
}
|
|
1592
1600
|
biomarkerDetailsHtml += '</div> <!-- end first col -->';
|
|
1593
1601
|
|
|
@@ -2196,8 +2204,9 @@ module.exports = {
|
|
|
2196
2204
|
find,
|
|
2197
2205
|
renderSummary,
|
|
2198
2206
|
renderReportSummary,
|
|
2199
|
-
renderHTMLTemplate
|
|
2200
|
-
|
|
2207
|
+
renderHTMLTemplate,
|
|
2208
|
+
renderAllergyClasses,
|
|
2209
|
+
setUseMonospace,
|
|
2201
2210
|
}
|
|
2202
2211
|
|
|
2203
2212
|
|
|
@@ -7,7 +7,7 @@ const path = require("path");
|
|
|
7
7
|
const LocaleService = require('../app/services/localeService.js');
|
|
8
8
|
const i18n = require('../app/i18n_wellbeing.config.js');
|
|
9
9
|
const puppeteer = require("puppeteer");
|
|
10
|
-
const { renderReportItems, find, renderSummary, renderReportSummary, renderHTMLTemplate, renderAllergyClasses } = require("./template.js");
|
|
10
|
+
const { renderReportItems, find, renderSummary, renderReportSummary, renderHTMLTemplate, renderAllergyClasses, setUseMonospace } = require("./template.js");
|
|
11
11
|
const { cli } = require("webpack");
|
|
12
12
|
|
|
13
13
|
|
|
@@ -1337,12 +1337,29 @@ let generateHTMLWellbeingReportWithSmartReport = async (data, isDebugging, clien
|
|
|
1337
1337
|
$('.doctor-details').html(doctorDetailsHtml);
|
|
1338
1338
|
}
|
|
1339
1339
|
|
|
1340
|
+
// Render Big Integral Questionnaire section (Maison Sante doctor PDF only)
|
|
1341
|
+
if (client.toLowerCase() === 'maisonsante' && data.IsDoctor) {
|
|
1342
|
+
const { renderBigIntegralQuestionnaire } = require('./big_integral_questionnaire');
|
|
1343
|
+
const rawClientConfig = (() => {
|
|
1344
|
+
try {
|
|
1345
|
+
const cfgPath = path.resolve(__dirname + '/../config/maisonsante.json');
|
|
1346
|
+
return JSON.parse(require('fs').readFileSync(cfgPath, 'utf8'));
|
|
1347
|
+
} catch (e) { return {}; }
|
|
1348
|
+
})();
|
|
1349
|
+
const integralHtml = renderBigIntegralQuestionnaire({
|
|
1350
|
+
clientConfig: rawClientConfig,
|
|
1351
|
+
});
|
|
1352
|
+
$('#big-integral-section').html(integralHtml);
|
|
1353
|
+
}
|
|
1354
|
+
|
|
1340
1355
|
// Update report info
|
|
1341
1356
|
$('.report-info').html(headerInfoHtml);
|
|
1342
1357
|
|
|
1343
1358
|
// Add smart report if available
|
|
1344
1359
|
if (!empty(smartReport)) {
|
|
1360
|
+
setUseMonospace(client.toLowerCase() === 'pha');
|
|
1345
1361
|
let smartReportHtml = generateReportHtml(smartReport, isRtl, false, false, language).html;
|
|
1362
|
+
setUseMonospace(false);
|
|
1346
1363
|
|
|
1347
1364
|
if (shouldHideWellbeingUI) {
|
|
1348
1365
|
// Parse and clean smart report HTML to remove page breaks when wellbeing is missing
|
package/locales/en.json
CHANGED
|
@@ -162,5 +162,69 @@
|
|
|
162
162
|
"signedBy": {
|
|
163
163
|
"message": "Signed by",
|
|
164
164
|
"description": "Label showing above the doctors who signed on this report"
|
|
165
|
+
},
|
|
166
|
+
"bigIntegralTitle": {
|
|
167
|
+
"message": "Key to the Big Integral Questionnaire",
|
|
168
|
+
"description": "Title of the Big Integral Questionnaire section in the Maison Sante doctor PDF"
|
|
169
|
+
},
|
|
170
|
+
"bigIntegralSystem": {
|
|
171
|
+
"message": "System",
|
|
172
|
+
"description": "Column header: body system name"
|
|
173
|
+
},
|
|
174
|
+
"bigIntegralHigh": {
|
|
175
|
+
"message": "High",
|
|
176
|
+
"description": "Column header: threshold above which result is considered elevated"
|
|
177
|
+
},
|
|
178
|
+
"bigIntegralQuestions": {
|
|
179
|
+
"message": "Questions",
|
|
180
|
+
"description": "Column header: number of questions for this system"
|
|
181
|
+
},
|
|
182
|
+
"bigIntegralResult": {
|
|
183
|
+
"message": "Result",
|
|
184
|
+
"description": "Column header: patient's result score"
|
|
185
|
+
},
|
|
186
|
+
"bigIntegralComments": {
|
|
187
|
+
"message": "Comments",
|
|
188
|
+
"description": "Column header: free-text comments area"
|
|
189
|
+
},
|
|
190
|
+
"bigIntegralMaximum": {
|
|
191
|
+
"message": "Maximum",
|
|
192
|
+
"description": "Column header: maximum possible score for this system"
|
|
193
|
+
},
|
|
194
|
+
"bigIntegralPerThree": {
|
|
195
|
+
"message": "/3",
|
|
196
|
+
"description": "Column header: score divided by 3"
|
|
197
|
+
},
|
|
198
|
+
"bigIntegralDateOfCompletion": {
|
|
199
|
+
"message": "Date of completion",
|
|
200
|
+
"description": "Footer meta label"
|
|
201
|
+
},
|
|
202
|
+
"bigIntegralPatientName": {
|
|
203
|
+
"message": "Client / Patient Full Name",
|
|
204
|
+
"description": "Footer meta label"
|
|
205
|
+
},
|
|
206
|
+
"bigIntegralAge": {
|
|
207
|
+
"message": "Age",
|
|
208
|
+
"description": "Footer meta label"
|
|
209
|
+
},
|
|
210
|
+
"bigIntegralBmi": {
|
|
211
|
+
"message": "BMI",
|
|
212
|
+
"description": "Footer meta label"
|
|
213
|
+
},
|
|
214
|
+
"bigIntegralElevated": {
|
|
215
|
+
"message": "ELEVATED",
|
|
216
|
+
"description": "Badge text shown when a system result exceeds its threshold"
|
|
217
|
+
},
|
|
218
|
+
"bigIntegralVariantClinical": {
|
|
219
|
+
"message": "Clinical View",
|
|
220
|
+
"description": "Variant label shown in the section header for the clinical table design"
|
|
221
|
+
},
|
|
222
|
+
"bigIntegralVariantScorecard": {
|
|
223
|
+
"message": "Scorecard View",
|
|
224
|
+
"description": "Variant label shown in the section header for the scorecard bar design"
|
|
225
|
+
},
|
|
226
|
+
"bigIntegralVariantHybrid": {
|
|
227
|
+
"message": "Hybrid View",
|
|
228
|
+
"description": "Variant label shown in the section header for the hybrid (table + bar) design"
|
|
165
229
|
}
|
|
166
230
|
}
|