@medicus.ai/medicus-report-pdf-generator 1.3.16 → 1.3.18

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.
@@ -524,7 +524,8 @@ const renderExtendedFirstSection = (template, calculationData, metrics, client)
524
524
  .replace(/{{rotatePhysicalAmount}}/gi, metrics.physical.rotateAmount)
525
525
  .replace(/{{physicalColor}}/gi, metrics.physical.color)
526
526
  .replace("{{ScoreText}}", localeService.t('scoreText'))
527
- .replace("{{lowScoreText}}", localeService.t('lowScoreText'))
527
+ .replace("{{lowScoreText}}", localeService.t(
528
+ String(client).toLowerCase() === 'maisonsante' ? 'scoreText' : 'lowScoreText'))
528
529
  .replace("{{PhysicalWellbeingText}}", localeService.t('PhysicalWellbeingText'))
529
530
  .replace("{{PsychologicalWellbeingText}}", localeService.t('PsychologicalWellbeingText'))
530
531
  .replace("{{psychologicalScore}}", metrics.psychological.scoreInteger)
@@ -928,9 +929,13 @@ const renderPatientTable = (profileInfo, startIndex = 4) => {
928
929
  /**
929
930
  * Render doctor quiz details
930
931
  * @param {array} doctorData - Doctor data array
932
+ * @param {boolean} startQuizAnswersOnNewPage - when true, force the "Quiz Answers"
933
+ * title onto a fresh page instead of letting it orphan at the bottom of the
934
+ * previous one. Only set for the Maison Sante quiz-only doctor PDF (no smart
935
+ * report); the report-backed doctor PDF passes false so its layout is untouched.
931
936
  * @returns {string} Rendered doctor details HTML
932
937
  */
933
- const renderDoctorDetails = (doctorData) => {
938
+ const renderDoctorDetails = (doctorData, startQuizAnswersOnNewPage = false) => {
934
939
  if (empty(doctorData)) {
935
940
  return '';
936
941
  }
@@ -961,27 +966,42 @@ const renderDoctorDetails = (doctorData) => {
961
966
  `;
962
967
  }
963
968
 
964
- return `
965
- <p class="resume-title">Quiz Answers</p>
966
- <!-- display:flow-root overrides the class's flex-direction:column. Chrome 73
967
- (puppeteer 1.15) does not fragment inside flex containers, so
968
- break-inside:avoid on a row is ignored while the rows are flex items
969
- and a row can be sliced across a page boundary. As block boxes they
970
- honour it. flow-root rather than block: block lets the first row's
971
- margin-top:1% collapse out through the column, shifting the whole section
972
- up ~9px, which changes where the natural page break lands and spills rows
973
- onto the previous page. flow-root establishes a block formatting context so
974
- the margin is contained and the geometry matches the original exactly.
975
- width:100% on the rows is required too: a row is a
976
- block-level flex container and Chrome computes its width as 0 here
977
- once it is no longer stretched by the flex parent, which collapses the
978
- whole section. Measured: baseline row 907px, block-only 0px,
979
- block+width:100% 907px. Inline so only these two columns change --
980
- .details-column and .details-row are shared with renderPatientTable
981
- and the patient-table.html blocks of maisonsante, Mediclinic and Pha. -->
969
+ // display:flow-root overrides the class's flex-direction:column. Chrome 73
970
+ // (puppeteer 1.15) does not fragment inside flex containers, so
971
+ // break-inside:avoid on a row is ignored while the rows are flex items
972
+ // and a row can be sliced across a page boundary. As block boxes they
973
+ // honour it. flow-root rather than block: block lets the first row's
974
+ // margin-top:1% collapse out through the column, shifting the whole section
975
+ // up ~9px, which changes where the natural page break lands and spills rows
976
+ // onto the previous page. flow-root establishes a block formatting context so
977
+ // the margin is contained and the geometry matches the original exactly.
978
+ // width:100% on the rows is required too: a row is a
979
+ // block-level flex container and Chrome computes its width as 0 here
980
+ // once it is no longer stretched by the flex parent, which collapses the
981
+ // whole section. Measured: baseline row 907px, block-only 0px,
982
+ // block+width:100% 907px. Inline so only these two columns change --
983
+ // .details-column and .details-row are shared with renderPatientTable
984
+ // and the patient-table.html blocks of maisonsante, Mediclinic and Pha.
985
+ const columnsHTML = `
982
986
  <div class="details-column" style="display:flow-root">${details1HTML}</div>
983
987
  <div class="details-column" style="display:flow-root;margin-left: 1%">${details2HTML}</div>
984
988
  `;
989
+
990
+ // Quiz-only: the caller turns .doctor-details into a page-break-inside:avoid block so
991
+ // the whole Quiz Answers section is pushed onto a fresh page (see the caller for why
992
+ // that mechanism is used instead of page-break-before). Once .doctor-details is a
993
+ // block rather than the shared flex container, the two columns need their own flex
994
+ // row to stay side by side, mirroring the gap/flex-wrap the .doctor-details flex rule
995
+ // normally supplies. The report-backed doctor PDF keeps the shared flex layout
996
+ // untouched.
997
+ const bodyHTML = startQuizAnswersOnNewPage
998
+ ? `<div style="display:flex; flex-wrap:wrap; gap:25px; width:100%;">${columnsHTML}</div>`
999
+ : columnsHTML;
1000
+
1001
+ return `
1002
+ <p class="resume-title">Quiz Answers</p>
1003
+ ${bodyHTML}
1004
+ `;
985
1005
  };
986
1006
 
987
1007
  /**
@@ -1254,7 +1274,12 @@ let generateHTMLWellbeingReportWithSmartReport = async (data, isDebugging, clien
1254
1274
  // Calculate all metrics
1255
1275
  const metrics = {
1256
1276
  physical: calculatePhysicalScoreMetrics(wellbeingData.calculation.physicalScore, client),
1257
- psychological: calculateScoreMetrics(wellbeingData.calculation.psychologicalScore, client),
1277
+ // Maison Sante draws the psychological dial with the same three bands as the
1278
+ // physical one, so it needs the physical needle geometry too. Every other
1279
+ // client keeps the five-band dial and its own rotation math.
1280
+ psychological: client.toLowerCase() === 'maisonsante'
1281
+ ? calculatePhysicalScoreMetrics(wellbeingData.calculation.psychologicalScore, client)
1282
+ : calculateScoreMetrics(wellbeingData.calculation.psychologicalScore, client),
1258
1283
  depression: calculateExtendedScoreMetrics(wellbeingData.calculation.depressionRiskScore, 'depression', client),
1259
1284
  anxiety: calculateExtendedScoreMetrics(wellbeingData.calculation.anxietyRiskScore, 'anxiety', client)
1260
1285
  };
@@ -1349,8 +1374,32 @@ let generateHTMLWellbeingReportWithSmartReport = async (data, isDebugging, clien
1349
1374
 
1350
1375
  // Render doctor details
1351
1376
  if (!empty(doctorData)) {
1352
- const doctorDetailsHtml = renderDoctorDetails(doctorData);
1377
+ // Quiz-only Maison Sante doctor PDF has no smart report above the Quiz Answers
1378
+ // block, so its title would orphan at the bottom of page 1; start it on a fresh
1379
+ // page there. The report-backed doctor PDF keeps its existing pagination.
1380
+ const startQuizAnswersOnNewPage = empty(smartReport)
1381
+ && client.toLowerCase() === 'maisonsante'
1382
+ && !!data.IsDoctor;
1383
+ const doctorDetailsHtml = renderDoctorDetails(doctorData, startQuizAnswersOnNewPage);
1353
1384
  $('.doctor-details').html(doctorDetailsHtml);
1385
+ // Quiz-only: start the whole Quiz Answers block on a fresh page so its title
1386
+ // does not orphan at the bottom of page 1. Chrome 73 (puppeteer 1.15) ignores
1387
+ // page-break-before here (both on the flex container and its items), so this
1388
+ // reuses the mechanism the .new-page sections rely on: a block that establishes
1389
+ // its own formatting context (display:block + overflow:hidden) and refuses to be
1390
+ // split (page-break-inside:avoid) is pushed to the next page when it cannot fit
1391
+ // in the space left on the current one. display:block also restores the columns'
1392
+ // side-by-side layout (they carry their own flex row now). Inline so only this
1393
+ // render changes; the shared .doctor-details flex rule is untouched for the
1394
+ // report-backed doctor PDF and every other client.
1395
+ if (startQuizAnswersOnNewPage) {
1396
+ $('.doctor-details').css({
1397
+ 'display': 'block',
1398
+ 'overflow': 'hidden',
1399
+ 'page-break-inside': 'avoid',
1400
+ 'break-inside': 'avoid'
1401
+ });
1402
+ }
1354
1403
  }
1355
1404
 
1356
1405
  // Render Big Integral Questionnaire section (Maison Sante doctor PDF only)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@medicus.ai/medicus-report-pdf-generator",
3
- "version": "1.3.16",
3
+ "version": "1.3.18",
4
4
  "description": "Nasco corporate report - latest update in 12/10/2023 - Fix HRC for bionext",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -65,12 +65,12 @@
65
65
 
66
66
  </div>
67
67
  </div>
68
- <div style="width: calc(50% - 11px); margin-left: 22px;">
68
+ <div style="width: calc(50% - 11px); margin-left: 22px; position: relative;">
69
69
  <div style="color: {{sectionTitleBorderColor}}; font-size: 16px; font-weight: 700; word-wrap: break-word;padding-bottom: 5px;text-align: center;margin-left: 10px;">{{PsychologicalWellbeingText}}</div>
70
70
 
71
- <div class="row score-section" style="width: calc(100% - 38px) !important; margin-left: 0;">
71
+ <div class="row score-section" style="width: calc(100% - 38px) !important; margin-left: 0; position: static;">
72
72
  <div style="display: flex;width: 100%;justify-content: center;">
73
- <div class="center aligned eight wide psychological-score-section">
73
+ <div class="center aligned eight wide psychological-score-section" style="position: static;">
74
74
  <div class="meter-component">
75
75
  <style>
76
76
 
@@ -83,31 +83,22 @@
83
83
  </style>
84
84
  <div id="screenshot">
85
85
  <div class="speedometer-container">
86
- <svg width="150" height="120" viewBox="0 -1 90 90" fill="none" >
87
- <path d="M68.9641 8.0985C69.2649 7.63531 69.885 7.50276 70.3414 7.81377C75.5335 11.352 79.9304 15.9407 83.2452 21.287C86.56 26.6332 88.7151 32.6119 89.5758 38.8358C89.6515 39.3828 89.257 39.8793 88.7084 39.9428L86.672 40.1784C86.1234 40.2419 85.6284 39.8483 85.5516 39.3014C84.7602 33.6697 82.8038 28.2607 79.8031 23.4212C76.8024 18.5816 72.8274 14.4242 68.1349 11.2113C67.6792 10.8993 67.5468 10.281 67.8476 9.81777L68.9641 8.0985Z"
88
- fill="{{secondLevelColor}}" stroke="{{secondLevelColor}}" stroke-width="2"/>
89
-
90
- <path d="M26.4048 5.12246C26.1714 4.62192 26.3876 4.02584 26.8932 3.80361C32.6452 1.27543 38.8666 -0.0216826 45.1571 0.000274124C51.4475 0.0222308 57.6597 1.36275 63.394 3.93101C63.898 4.15676 64.11 4.75434 63.8731 5.25324L62.9938 7.10507C62.7569 7.60397 62.1609 7.81517 61.6564 7.59053C56.461 5.27733 50.8372 4.07012 45.1429 4.05025C39.4486 4.03037 33.8165 5.19829 28.6052 7.47516C28.0991 7.69628 27.5046 7.48093 27.2712 6.98039L26.4048 5.12246Z" fill="{{thirdLevelColor}}" stroke="{{thirdLevelColor}}" stroke-width="2"/>
91
-
92
- <path
93
- d="M26.4048 5.12246C26.1714 4.62192 26.3876 4.02584 26.8932 3.80361C32.6452 1.27543 38.8666 -0.0216826 45.1571 0.000274124C51.4475 0.0222308 57.6597 1.36275 63.394 3.93101C63.898 4.15676 64.11 4.75434 63.8731 5.25324L62.9938 7.10507C62.7569 7.60397 62.1609 7.81517 61.6564 7.59053C56.461 5.27733 50.8372 4.07012 45.1429 4.05025C39.4486 4.03037 33.8165 5.19829 28.6052 7.47516C28.0991 7.69628 27.5046 7.48093 27.2712 6.98039L26.4048 5.12246Z"
94
- fill="{{thirdLevelColor}}" stroke="{{thirdLevelColor}}" stroke-width="2"/>
95
-
96
- <path d="M1.32797 39.6377C0.779802 39.5704 0.388848 39.0712 0.468318 38.5247C1.37242 32.307 3.56925 26.3435 6.92131 21.0206C10.2734 15.6976 14.7022 11.1397 19.9189 7.63776C20.3774 7.32994 20.9965 7.46682 21.2941 7.93209L22.3986 9.65912C22.6961 10.1244 22.5594 10.7418 22.1015 11.0506C17.3867 14.2307 13.3828 18.3602 10.3484 23.1787C7.31402 27.9972 5.31991 33.3924 4.48922 39.0184C4.40854 39.5648 3.91086 39.9549 3.36269 39.8876L1.32797 39.6377Z"
97
- fill="{{forthLevelColor}}" stroke="{{forthLevelColor}}" stroke-width="2"/>
98
-
99
- <path d="M15.5583 77.6984C15.1887 78.1088 14.5555 78.1427 14.1534 77.7641C9.57873 73.4572 5.95383 68.2372 3.51616 62.4382C1.07849 56.6392 -0.114859 50.3971 0.00869898 44.1152C0.0195597 43.563 0.486795 43.1343 1.0386 43.1575L3.0868 43.2433C3.6386 43.2664 4.06589 43.7326 4.05624 44.2848C3.9569 49.9709 5.04306 55.6194 7.2497 60.8688C9.45634 66.1182 12.7321 70.8462 16.8642 74.7536C17.2654 75.1331 17.2995 75.7645 16.93 76.1749L15.5583 77.6984Z"
100
- fill="{{fifthLevelColor}}" stroke="{{fifthLevelColor}}" stroke-width="2"/>
101
-
102
- <path d="M87.9738 43.4993C89.0777 43.4608 90.0085 44.3247 89.998 45.4293C89.9413 51.3724 88.7076 57.2525 86.3611 62.7274C84.0145 68.2023 80.6071 73.1507 76.3423 77.2902C75.5497 78.0596 74.2822 77.9813 73.5488 77.1553L72.0218 75.4354C71.2884 74.6094 71.3676 73.3489 72.1546 72.5739C75.7288 69.054 78.5893 64.868 80.5705 60.2456C82.5517 55.6231 83.6104 50.6649 83.6946 45.6491C83.7131 44.5447 84.5713 43.6182 85.6752 43.5796L87.9738 43.4993Z"
103
- fill="{{firstLevelColor}}" stroke="{{firstLevelColor}}" stroke-width="0"/>
104
- </svg>
86
+ <svg width="150" height="102" viewBox="0 0 92 80" fill="none" >
87
+ <path
88
+ d="M47.7561 0.0346775C47.1753 0.00827408 46.5856 -0.000526428 45.9959 -0.000526428C45.4062 -0.000526428 44.8165 0.00827408 44.2356 0.0346775C32.7245 0.454498 22.2369 4.96779 14.1978 12.1602C13.8255 12.4929 13.8141 13.0764 14.1661 13.4311L14.7602 14.0287L17.251 16.5106L17.9119 17.1716C18.2376 17.4973 18.756 17.5087 19.1019 17.2033C25.87 11.2448 34.6343 7.48583 44.2356 7.08449C44.8165 7.04928 45.4062 7.04048 45.9959 7.04048C46.5856 7.04048 47.1753 7.04928 47.7561 7.08449C57.3574 7.48583 66.1217 11.2448 72.889 17.2112C73.2358 17.5166 73.7542 17.5061 74.0807 17.1795L74.7496 16.5106L77.2404 14.0287L77.8345 13.4311C78.1865 13.0764 78.1751 12.4929 77.8028 12.1602C69.7628 4.96779 59.2752 0.454498 47.7561 0.0346775Z"
89
+ fill="{{thirdLevelColor}}" stroke="{{thirdLevelColor}}" stroke-width="0"/>
90
+ <path
91
+ d="M91.9648 45.9963C91.5547 34.9727 87.2359 24.9278 80.3551 17.2074C80.0197 16.8307 79.4309 16.8201 79.0736 17.1757L77.8256 18.4202C77.4973 18.7476 77.4867 19.2686 77.7939 19.6154C84.0745 26.7004 88.0342 35.8951 88.4443 45.9963C88.4707 46.5772 88.4795 47.1669 88.4795 47.7566C88.4795 48.3462 88.4707 48.9359 88.4443 49.5168C88.0342 59.6171 84.0745 68.8118 77.7939 75.8977C77.4867 76.2445 77.4973 76.7655 77.8256 77.0929L79.0789 78.3418C79.4336 78.6957 80.0171 78.6851 80.3507 78.311C87.2341 70.5897 91.5547 60.543 91.9648 49.5168C91.9912 48.9271 92 48.3462 92 47.7566C92 47.1669 91.9912 46.586 91.9648 45.9963Z"
92
+ fill="{{fifthLevelColor}}" stroke="{{fifthLevelColor}}" stroke-width="3"/>
93
+ <path
94
+ d="M3.52051 47.7566C3.52051 47.1669 3.52931 46.5772 3.55571 45.9963C3.96673 35.8951 7.92554 26.7004 14.2061 19.6154C14.5133 19.2686 14.5036 18.7476 14.1744 18.4202L12.9211 17.1713C12.5664 16.8175 11.9829 16.828 11.6494 17.2021C4.76588 24.9234 0.445344 34.9701 0.035205 45.9963C0.00880123 46.586 0 47.1669 0 47.7566C0 48.3463 0.00880123 48.9271 0.035205 49.5168C0.445344 60.543 4.76588 70.5897 11.6494 78.311C11.9829 78.6851 12.5664 78.6957 12.9211 78.3418L14.1744 77.0929C14.5036 76.7655 14.5133 76.2445 14.2061 75.8977C7.92554 68.8118 3.96673 59.6171 3.55571 49.5168C3.52931 48.9359 3.52051 48.3463 3.52051 47.7566Z"
95
+ fill="{{secondLevelColor}}" stroke="{{secondLevelColor}}" stroke-width="3"/>
96
+ </svg>
105
97
 
106
98
 
107
99
  </div>
108
100
 
109
- <div class=" loading_Meter1
110
- needle-container2">
101
+ <div class="needle-container loading_Meter1" style="margin-right: auto;">
111
102
  <svg class="ui image meter-needle " version="1.2" baseProfile="tiny-ps" viewBox="0 0 65 57" width="65" height="57">
112
103
  <g id="Layer">
113
104
  <path id="Layer" class="shp0" fill="none" d="M-4.05 94.8L-30.63 57.17L386.92 -218.49L413.51 -180.86L-4.05 94.8Z" />
@@ -115,7 +106,7 @@
115
106
  </g>
116
107
  </svg>
117
108
  </div>
118
- <div class="speedometer-value2">
109
+ <div style="margin-top: 22px; left: 0;" class="speedometer-value">
119
110
  <span class="speedometer-value-up needle-value" >
120
111
  <div><strong>{{psychologicalScore}}</strong>{{psychologicalScoreDecimalPart}}</div>
121
112
  </span>