tango-app-api-trax 3.8.25 → 3.8.26

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tango-app-api-trax",
3
- "version": "3.8.25",
3
+ "version": "3.8.26",
4
4
  "description": "Trax",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -4360,7 +4360,6 @@ export async function recurringFlagAlert( req, res ) {
4360
4360
  ],
4361
4361
  },
4362
4362
  }, { _id: 1, checkListName: 1, recurringFlag: 1, notifyFlags: 1, approver: 1, client_id: 1 } );
4363
- console.log( JSON.stringify( checklistDetails ) );
4364
4363
  if ( !checklistDetails.length ) {
4365
4364
  return res.sendSuccess( 'No checklists configured for recurring flag' );
4366
4365
  }
@@ -4470,9 +4469,11 @@ export async function recurringFlagAlert( req, res ) {
4470
4469
  await Promise.all( [ ...byRecipient.entries() ].map( async ( [ recipient, items ] ) => {
4471
4470
  const subjects = new Set( items.map( ( i ) => i.subjectId ) );
4472
4471
  const checklists = new Set( items.map( ( i ) => i.checklistId ) );
4473
- console.log( checklists );
4474
4472
  const isMultiStore = subjects.size > 1; // "isMultiStore" name retained for template back-compat
4475
4473
  const isMultiChecklist = !isMultiStore && checklists.size > 1;
4474
+ // Sub-mode of multi-store when the recipient's flagged subjects all share a single checklist.
4475
+ // Drives a tighter email layout (no Checklist column, no "Total Checklists" line, checklist name in intro).
4476
+ const isMultiStoreSingleChecklist = isMultiStore && checklists.size === 1;
4476
4477
  // Threshold for the message line — when grouping spans multiple checklists/subjects, take min threshold seen.
4477
4478
  const thresholdShown = items.reduce( ( acc, it ) => Math.min( acc, it.days ), items[0].days );
4478
4479
 
@@ -4521,9 +4522,10 @@ export async function recurringFlagAlert( req, res ) {
4521
4522
  checklistName: g.checklistName,
4522
4523
  lastSubmittedBy: g.lastSubmittedBy,
4523
4524
  lastSubmissionDate: g.lastSubmissionDate,
4524
- days: g.questionCount, // template column "Total Recurring Flags" reads `days`
4525
+ days: g.questionCount, // legacy alias kept for back-compat with older template builds
4525
4526
  flagCount: g.questionCount,
4526
4527
  runAICount: g.runAICount,
4528
+ totalFlags: g.questionCount + g.runAICount,
4527
4529
  } ) );
4528
4530
 
4529
4531
  // Excel attachment keeps per-question detail (one row per flagged question).
@@ -4546,6 +4548,7 @@ export async function recurringFlagAlert( req, res ) {
4546
4548
  threshold: thresholdShown,
4547
4549
  isMultiStore,
4548
4550
  isMultiChecklist,
4551
+ isMultiStoreSingleChecklist,
4549
4552
  showTable: isMultiStore || isMultiChecklist,
4550
4553
  hasAttachment,
4551
4554
  domain: flagDomain,
@@ -4563,11 +4566,15 @@ export async function recurringFlagAlert( req, res ) {
4563
4566
  totalChecklists: checklists.size,
4564
4567
  totalFlags: items.length,
4565
4568
  };
4569
+ if ( isMultiStoreSingleChecklist ) {
4570
+ // Show the single checklist name in the intro line for this sub-mode.
4571
+ data.checklistName = items[0].checklistName;
4572
+ }
4566
4573
  } else if ( isMultiChecklist ) {
4567
4574
  data.subjectName = items[0].subjectName;
4568
4575
  data.storeName = items[0].subjectName;
4569
4576
  } else {
4570
- // Single mode: one (subject, checklist) — flagCount is the number of questions that hit threshold.
4577
+ // Single mode: one (subject, checklist) — totalFlags = sop question flags + runAI flags.
4571
4578
  const single = rows[0];
4572
4579
  data.subjectName = single.subjectName;
4573
4580
  data.storeName = single.subjectName;
@@ -4575,9 +4582,8 @@ export async function recurringFlagAlert( req, res ) {
4575
4582
  data.lastSubmittedBy = single.lastSubmittedBy;
4576
4583
  data.lastSubmissionDate = single.lastSubmissionDate;
4577
4584
  data.flagCount = single.flagCount;
4578
- data.flagCountPlural = single.flagCount > 1;
4579
4585
  data.runAICount = single.runAICount;
4580
- data.runAICountPlural = single.runAICount > 1;
4586
+ data.totalFlags = single.totalFlags;
4581
4587
  }
4582
4588
 
4583
4589
  const html = compiled( { data } );
@@ -4602,7 +4608,6 @@ export async function recurringFlagAlert( req, res ) {
4602
4608
  logger.error( { functionName: 'recurringFlagAlert.buildExcel', error: e } );
4603
4609
  }
4604
4610
  }
4605
- console.log( params.toEmail );
4606
4611
  sendEmailWithSES( params.toEmail, params.mailSubject, params.htmlBody, params.attachment, params.sourceEmail );
4607
4612
  sentSummary.push( { recipient, count: items.length, mode: isMultiStore ? 'multi-store' : ( isMultiChecklist ? 'multi-checklist' : 'single' ) } );
4608
4613
  } ) );
@@ -67,7 +67,9 @@
67
67
  <div style="margin-top: 0px;margin-bottom: 0px;font-size: 16px;line-height: 28px;color: #82899a;">
68
68
  <span style="font-weight: 400;color: #121A26;line-height: 140%;">
69
69
  Hi,<br/>
70
- {{#if data.isMultiStore}}
70
+ {{#if data.isMultiStoreSingleChecklist}}
71
+ Recurring flags has been detected across multiple {{data.subjectLabelPluralLower}} in recent <b>{{data.checklistName}}</b> on recent submissions, exceeding the configured threshold of {{data.threshold}} occurrences.
72
+ {{else if data.isMultiStore}}
71
73
  Recurring flags has been detected across multiple {{data.subjectLabelPluralLower}} and across multiple checklists on recent submissions, exceeding the configured threshold of {{data.threshold}} occurrences.
72
74
  {{else if data.isMultiChecklist}}
73
75
  A Recurring flags has been identified for {{data.subjectLabelLower}} <b>{{data.subjectName}}</b> across multiple checklists on recent submissions, exceeding the configured threshold of {{data.threshold}} occurrences.
@@ -87,7 +89,9 @@
87
89
  <b>Key Highlights:</b>
88
90
  <ul style="margin:8px 0 0 0;padding-left:18px;">
89
91
  <li>Total {{data.subjectLabelPlural}} with Recurring Flags: {{data.highlights.totalSubjects}}</li>
92
+ {{#unless data.isMultiStoreSingleChecklist}}
90
93
  <li>Total Checklists with Recurring Flags: {{data.highlights.totalChecklists}}</li>
94
+ {{/unless}}
91
95
  <li>Total Recurring Flags: {{data.highlights.totalFlags}}</li>
92
96
  </ul>
93
97
  </div>
@@ -141,12 +145,7 @@
141
145
  <tr bgcolor="#ffffff">
142
146
  <td class="flagText" style="padding-left:30px;line-height: 24px;">No of Flags :</td>
143
147
  <td></td><td></td>
144
- <td class="flagText">{{data.flagCount}} Question Flag{{#if data.flagCountPlural}}s{{/if}}</td>
145
- </tr>
146
- <tr bgcolor="#ffffff">
147
- <td class="flagText" style="padding-left:30px;line-height: 24px;">Run AI Flags :</td>
148
- <td></td><td></td>
149
- <td class="flagText">{{data.runAICount}} Run AI Flag{{#if data.runAICountPlural}}s{{/if}}</td>
148
+ <td class="flagText">{{data.totalFlags}} (Question Flags: {{data.flagCount}}, Run AI Flags: {{data.runAICount}})</td>
150
149
  </tr>
151
150
  </table>
152
151
  </td>
@@ -164,22 +163,20 @@
164
163
  <thead>
165
164
  <tr>
166
165
  {{#if data.isMultiStore}}<th>{{data.subjectLabel}} Name</th>{{/if}}
167
- <th>Checklist Name</th>
166
+ {{#unless data.isMultiStoreSingleChecklist}}<th>Checklist Name</th>{{/unless}}
168
167
  <th>Last Submitted By</th>
169
168
  <th>Last Submission Date</th>
170
169
  <th>Total Recurring Flags</th>
171
- <th>Run AI Flags</th>
172
170
  </tr>
173
171
  </thead>
174
172
  <tbody>
175
173
  {{#each data.rows}}
176
174
  <tr>
177
175
  {{#if ../data.isMultiStore}}<td>{{this.subjectName}}</td>{{/if}}
178
- <td>{{this.checklistName}}</td>
176
+ {{#unless ../data.isMultiStoreSingleChecklist}}<td>{{this.checklistName}}</td>{{/unless}}
179
177
  <td>{{this.lastSubmittedBy}}</td>
180
178
  <td>{{this.lastSubmissionDate}}</td>
181
- <td>{{this.days}}</td>
182
- <td>{{this.runAICount}}</td>
179
+ <td>{{this.totalFlags}} (Question Flags: {{this.flagCount}}, Run AI Flags: {{this.runAICount}})</td>
183
180
  </tr>
184
181
  {{/each}}
185
182
  </tbody>
@@ -70,6 +70,8 @@
70
70
  .q-answer-text.flagged{color:#a32d2d}
71
71
  .q-answer-media{margin-top:8px}
72
72
  .q-answer-media img,.q-answer-media video,.q-answer-item td img{display:block;width:200px;height:180px;object-fit:cover;border-radius:6px;margin-bottom:6px}
73
+ .img-grid{display:flex;flex-wrap:wrap;gap:8px}
74
+ .img-grid img{margin-bottom:0}
73
75
  .q-answer-link{font-size:12px;color:#0085D2;text-decoration:underline;word-break:break-all}
74
76
  .q-answer-caption{font-size:11px;color:#666;margin-bottom:4px}
75
77
  .q-answer-remarks{font-size:11px;color:#666;margin-top:6px;white-space:pre-line}
@@ -188,9 +190,11 @@
188
190
  {{#if this.multiQuestionReferenceImage.length}}
189
191
  <div class="q-answer-media">
190
192
  <div class="q-answer-caption">Question Reference Images</div>
191
- {{#each this.multiQuestionReferenceImage}}
192
- <img src="{{this}}" alt="Reference Image" />
193
- {{/each}}
193
+ <div class="img-grid">
194
+ {{#each this.multiQuestionReferenceImage}}
195
+ <img src="{{this}}" alt="Reference Image" />
196
+ {{/each}}
197
+ </div>
194
198
  </div>
195
199
  {{/if}}
196
200
  {{!-- <span class="q-ans {{#if this.isYes}}ans-yes{{else}}{{#if this.isNo}}ans-no{{/if}}{{/if}}">{{#if this.isYes}}✓ Yes{{else}}{{#if this.isNo}}✗ No{{else}}{{this.answerDisplay}}{{/if}}{{/if}}</span> --}}
@@ -198,25 +202,6 @@
198
202
  <div class="q-answer-list">
199
203
  {{#each this.userAnswer}}
200
204
  <div class="q-answer-item">
201
- {{#neq ../answerType 'image/video'}}
202
- {{#neq ../answerType 'multipleImage'}}
203
- {{#if this.multiReferenceImage.length}}
204
- <div class="q-answer-media">
205
- <div class="q-answer-caption">Reference Images</div>
206
- {{#each this.multiReferenceImage}}
207
- <img src="{{this}}" alt="Reference Image" />
208
- {{/each}}
209
- </div>
210
- {{else}}
211
- {{#if this.referenceImage}}
212
- <div class="q-answer-media">
213
- <div class="q-answer-caption">Reference Image</div>
214
- <img src="{{this.referenceImage}}" alt="Reference Image" />
215
- </div>
216
- {{/if}}
217
- {{/if}}
218
- {{/neq}}
219
- {{/neq}}
220
205
  {{#eq this.answerType 'text'}}
221
206
  {{#if this.answer}}
222
207
  <div class="q-answer-text {{#if this.sopFlag}}flagged{{/if}}">{{this.answer}}</div>
@@ -231,8 +216,29 @@
231
216
  {{/if}}
232
217
  {{/eq}}
233
218
 
234
- <table style="width:100%;margin-top:8px"><tr>
235
- <td style="vertical-align:top">
219
+ <table style="width:100%;margin-top:8px;table-layout:fixed"><tr>
220
+ <td style="width:50%;vertical-align:top;padding-right:8px">
221
+ {{#neq ../answerType 'image/video'}}
222
+ {{#neq ../answerType 'multipleImage'}}
223
+ {{#if this.multiReferenceImage.length}}
224
+ <div class="q-answer-media">
225
+ <div class="q-answer-caption">Reference Images</div>
226
+ {{#each this.multiReferenceImage}}
227
+ <img src="{{this}}" alt="Reference Image" />
228
+ {{/each}}
229
+ </div>
230
+ {{else}}
231
+ {{#if this.referenceImage}}
232
+ <div class="q-answer-media">
233
+ <div class="q-answer-caption">Reference Image</div>
234
+ <img src="{{this.referenceImage}}" alt="Reference Image" />
235
+ </div>
236
+ {{/if}}
237
+ {{/if}}
238
+ {{/neq}}
239
+ {{/neq}}
240
+ </td>
241
+ <td style="width:50%;vertical-align:top;padding-left:8px">
236
242
  {{#eq this.answerType 'image'}}
237
243
  {{#if this.answer}}
238
244
  <div class="q-answer-caption">Uploaded Image</div>
@@ -169,13 +169,15 @@ function buildQuestionAnswerEntries( question ) {
169
169
 
170
170
  const rawMultiRefSources = [
171
171
  userAnswer?.multiReferenceImage,
172
- matchedAnswer?.multiReferenceImage,
173
- question?.answers?.[0]?.multiReferenceImage,
172
+ // matchedAnswer?.multiReferenceImage,
173
+ // question?.answers?.[0]?.multiReferenceImage,
174
174
  ];
175
175
  let multiReferenceImage = [];
176
176
  for ( const src of rawMultiRefSources ) {
177
177
  const flat = flattenImageRefs( src );
178
- if ( flat.length ) { multiReferenceImage = flat; break; }
178
+ if ( flat.length ) {
179
+ multiReferenceImage = flat; break;
180
+ }
179
181
  }
180
182
  const validationImage = flattenImageRefs( userAnswer?.validationImage );
181
183
 
@@ -920,7 +922,6 @@ export function resolveTemplateUrls( templateData, baseUrl = 'https://d1r0hc2ssk
920
922
  q.multiQuestionReferenceImage = q.multiQuestionReferenceImage.map( ( ele ) => resolveUrl( ele ) );
921
923
  }
922
924
  q.userAnswer?.forEach( ( ua ) => {
923
-
924
925
  if ( ua.multiReferenceImage?.length ) {
925
926
  ua.multiReferenceImage = ua.multiReferenceImage.map( ( ele ) => resolveUrl( ele ) );
926
927
  }