@squaredr/fieldcraft-pro 1.7.0 → 1.9.0
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/LICENSE.txt +51 -51
- package/README.md +139 -139
- package/dist/{chunk-VEP3DOCQ.mjs → chunk-5QXKDYWY.mjs} +103 -19
- package/dist/{chunk-GZIV2XAD.mjs → chunk-7GPX3YIB.mjs} +146 -183
- package/dist/{chunk-J5V6OVZO.mjs → chunk-DWRLPGX5.mjs} +690 -211
- package/dist/{chunk-4TN6YJDF.mjs → chunk-KTIU7VCP.mjs} +971 -214
- package/dist/default-schema-BGxf9Jrg.d.ts +174 -0
- package/dist/default-schema-Bwq8FATF.d.mts +174 -0
- package/dist/form-builder/index.d.mts +14 -170
- package/dist/form-builder/index.d.ts +14 -170
- package/dist/form-builder/index.js +827 -326
- package/dist/form-builder/index.mjs +1 -1
- package/dist/index.d.mts +111 -10
- package/dist/index.d.ts +111 -10
- package/dist/index.js +3525 -971
- package/dist/index.mjs +1424 -124
- package/dist/response-viewer/index.d.mts +1 -1
- package/dist/response-viewer/index.d.ts +1 -1
- package/dist/response-viewer/index.js +146 -183
- package/dist/response-viewer/index.mjs +1 -1
- package/dist/styles.css +2 -2
- package/dist/templates/index.d.mts +1 -1
- package/dist/templates/index.d.ts +1 -1
- package/dist/templates/index.js +103 -19
- package/dist/templates/index.mjs +1 -1
- package/dist/theme-editor/index.d.mts +12 -7
- package/dist/theme-editor/index.d.ts +12 -7
- package/dist/theme-editor/index.js +971 -214
- package/dist/theme-editor/index.mjs +1 -1
- package/dist/{types-bFHsZT1n.d.mts → types-BQOeI3LX.d.mts} +1 -1
- package/dist/{types-bFHsZT1n.d.ts → types-BQOeI3LX.d.ts} +1 -1
- package/package.json +29 -18
- package/theme-editor/styles.css +497 -466
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { FormResponse, FormEngineSchema } from '@squaredr/fieldcraft-core';
|
|
3
3
|
|
|
4
4
|
type FieldRenderer = (field: ResponseField, response: FormResponse) => React.ReactNode;
|
|
5
5
|
type ResponseViewerProps = {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { FormResponse, FormEngineSchema } from '@squaredr/fieldcraft-core';
|
|
3
3
|
|
|
4
4
|
type FieldRenderer = (field: ResponseField, response: FormResponse) => React.ReactNode;
|
|
5
5
|
type ResponseViewerProps = {
|
|
@@ -306,6 +306,119 @@ function requireLicense(Component, featureName) {
|
|
|
306
306
|
return LicenseGated;
|
|
307
307
|
}
|
|
308
308
|
|
|
309
|
+
// src/response-viewer/constants.ts
|
|
310
|
+
var DISPLAY_ONLY_TYPES = /* @__PURE__ */ new Set([
|
|
311
|
+
"info-block",
|
|
312
|
+
"info_block",
|
|
313
|
+
"section-header",
|
|
314
|
+
"page-break",
|
|
315
|
+
"image",
|
|
316
|
+
"divider",
|
|
317
|
+
"spacer",
|
|
318
|
+
"video",
|
|
319
|
+
"rich-text",
|
|
320
|
+
"welcome-screen",
|
|
321
|
+
"thank-you-screen",
|
|
322
|
+
"hidden",
|
|
323
|
+
"calculated"
|
|
324
|
+
]);
|
|
325
|
+
function formatDuration(ms) {
|
|
326
|
+
if (ms == null || ms < 0) return "\u2014";
|
|
327
|
+
const totalSeconds = Math.round(ms / 1e3);
|
|
328
|
+
if (totalSeconds < 60) return `${totalSeconds}s`;
|
|
329
|
+
const minutes = Math.floor(totalSeconds / 60);
|
|
330
|
+
const seconds = totalSeconds % 60;
|
|
331
|
+
return `${minutes}m ${seconds}s`;
|
|
332
|
+
}
|
|
333
|
+
function countAnswered(values) {
|
|
334
|
+
let count = 0;
|
|
335
|
+
for (const v of Object.values(values)) {
|
|
336
|
+
if (v !== void 0 && v !== null && v !== "") count++;
|
|
337
|
+
}
|
|
338
|
+
return count;
|
|
339
|
+
}
|
|
340
|
+
function getTotalFieldCount(schema) {
|
|
341
|
+
let count = 0;
|
|
342
|
+
for (const section of schema.sections) {
|
|
343
|
+
for (const q of section.questions) {
|
|
344
|
+
if (!DISPLAY_ONLY_TYPES.has(q.type)) count++;
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
return count;
|
|
348
|
+
}
|
|
349
|
+
function ResponseTable({
|
|
350
|
+
schema,
|
|
351
|
+
responses,
|
|
352
|
+
onRowClick,
|
|
353
|
+
selectable,
|
|
354
|
+
selectedIds,
|
|
355
|
+
onToggleSelect,
|
|
356
|
+
onSelectAll
|
|
357
|
+
}) {
|
|
358
|
+
const totalFields = getTotalFieldCount(schema);
|
|
359
|
+
const allPageSelected = selectable && responses.length > 0 && responses.every(
|
|
360
|
+
(r) => r.sessionToken && selectedIds?.has(r.sessionToken)
|
|
361
|
+
);
|
|
362
|
+
const colCount = 4 + (selectable ? 1 : 0);
|
|
363
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "overflow-auto", children: /* @__PURE__ */ jsxRuntime.jsxs("table", { className: "w-full border-collapse text-[13px]", children: [
|
|
364
|
+
/* @__PURE__ */ jsxRuntime.jsx("thead", { children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { className: "bg-muted", children: [
|
|
365
|
+
selectable && /* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-3 py-2 w-8 border-b-2 border-border", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
366
|
+
"input",
|
|
367
|
+
{
|
|
368
|
+
type: "checkbox",
|
|
369
|
+
checked: allPageSelected,
|
|
370
|
+
onChange: () => onSelectAll?.(),
|
|
371
|
+
className: "accent-primary"
|
|
372
|
+
}
|
|
373
|
+
) }),
|
|
374
|
+
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-3 py-2 text-left font-semibold text-foreground border-b-2 border-border whitespace-nowrap", children: "Submitted" }),
|
|
375
|
+
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-3 py-2 text-left font-semibold text-foreground border-b-2 border-border whitespace-nowrap", children: "Completion Time" }),
|
|
376
|
+
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-3 py-2 text-left font-semibold text-foreground border-b-2 border-border whitespace-nowrap", children: "Fields Answered" }),
|
|
377
|
+
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-3 py-2 text-left font-semibold text-foreground border-b-2 border-border whitespace-nowrap", children: "Score" })
|
|
378
|
+
] }) }),
|
|
379
|
+
/* @__PURE__ */ jsxRuntime.jsxs("tbody", { children: [
|
|
380
|
+
responses.map((response, idx) => {
|
|
381
|
+
const answered = countAnswered(response.values);
|
|
382
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
383
|
+
"tr",
|
|
384
|
+
{
|
|
385
|
+
onClick: () => onRowClick?.(response),
|
|
386
|
+
className: onRowClick ? "cursor-pointer border-b border-border hover:bg-accent transition-colors" : "border-b border-border",
|
|
387
|
+
children: [
|
|
388
|
+
selectable && /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-3 py-2 w-8", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
389
|
+
"input",
|
|
390
|
+
{
|
|
391
|
+
type: "checkbox",
|
|
392
|
+
checked: !!(response.sessionToken && selectedIds?.has(response.sessionToken)),
|
|
393
|
+
onChange: (e) => {
|
|
394
|
+
e.stopPropagation();
|
|
395
|
+
if (response.sessionToken) onToggleSelect?.(response.sessionToken);
|
|
396
|
+
},
|
|
397
|
+
onClick: (e) => e.stopPropagation(),
|
|
398
|
+
className: "accent-primary"
|
|
399
|
+
}
|
|
400
|
+
) }),
|
|
401
|
+
/* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-3 py-2 text-foreground whitespace-nowrap", children: new Date(response.submittedAt).toLocaleString() }),
|
|
402
|
+
/* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-3 py-2 text-foreground whitespace-nowrap", children: formatDuration(response.completionTimeMs) }),
|
|
403
|
+
/* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-3 py-2 text-foreground whitespace-nowrap", children: totalFields > 0 ? `${answered}/${totalFields}` : "\u2014" }),
|
|
404
|
+
/* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-3 py-2 text-foreground whitespace-nowrap", children: response.totalScore ?? "\u2014" })
|
|
405
|
+
]
|
|
406
|
+
},
|
|
407
|
+
response.sessionToken || idx
|
|
408
|
+
);
|
|
409
|
+
}),
|
|
410
|
+
responses.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("tr", { children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
411
|
+
"td",
|
|
412
|
+
{
|
|
413
|
+
colSpan: colCount,
|
|
414
|
+
className: "px-3 py-8 text-center text-muted-foreground",
|
|
415
|
+
children: "No responses yet"
|
|
416
|
+
}
|
|
417
|
+
) })
|
|
418
|
+
] })
|
|
419
|
+
] }) });
|
|
420
|
+
}
|
|
421
|
+
|
|
309
422
|
// src/response-viewer/clinical-display-data.ts
|
|
310
423
|
var BODY_REGION_LABELS = {
|
|
311
424
|
head: "Head",
|
|
@@ -442,166 +555,6 @@ function getScoreSeverity(instrumentKey, score) {
|
|
|
442
555
|
if (!thresholds) return void 0;
|
|
443
556
|
return thresholds.find((t) => score >= t.min && score <= t.max);
|
|
444
557
|
}
|
|
445
|
-
function ResponseTable({
|
|
446
|
-
schema,
|
|
447
|
-
responses,
|
|
448
|
-
onRowClick,
|
|
449
|
-
selectable,
|
|
450
|
-
selectedIds,
|
|
451
|
-
onToggleSelect,
|
|
452
|
-
onSelectAll
|
|
453
|
-
}) {
|
|
454
|
-
const questions = getAllQuestions(schema);
|
|
455
|
-
const allPageSelected = selectable && responses.length > 0 && responses.every(
|
|
456
|
-
(r) => r.sessionToken && selectedIds?.has(r.sessionToken)
|
|
457
|
-
);
|
|
458
|
-
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "overflow-auto", children: /* @__PURE__ */ jsxRuntime.jsxs("table", { className: "w-full border-collapse text-[13px]", children: [
|
|
459
|
-
/* @__PURE__ */ jsxRuntime.jsx("thead", { children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { className: "bg-muted", children: [
|
|
460
|
-
selectable && /* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-3 py-2 w-8 border-b-2 border-border", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
461
|
-
"input",
|
|
462
|
-
{
|
|
463
|
-
type: "checkbox",
|
|
464
|
-
checked: allPageSelected,
|
|
465
|
-
onChange: () => onSelectAll?.(),
|
|
466
|
-
className: "accent-primary"
|
|
467
|
-
}
|
|
468
|
-
) }),
|
|
469
|
-
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-3 py-2 text-left font-semibold text-foreground border-b-2 border-border whitespace-nowrap", children: "Submitted" }),
|
|
470
|
-
questions.map((q) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
471
|
-
"th",
|
|
472
|
-
{
|
|
473
|
-
className: "px-3 py-2 text-left font-semibold text-foreground border-b-2 border-border whitespace-nowrap",
|
|
474
|
-
children: q.label
|
|
475
|
-
},
|
|
476
|
-
q.id
|
|
477
|
-
)),
|
|
478
|
-
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-3 py-2 text-left font-semibold text-foreground border-b-2 border-border whitespace-nowrap", children: "Score" })
|
|
479
|
-
] }) }),
|
|
480
|
-
/* @__PURE__ */ jsxRuntime.jsxs("tbody", { children: [
|
|
481
|
-
responses.map((response, idx) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
482
|
-
"tr",
|
|
483
|
-
{
|
|
484
|
-
onClick: () => onRowClick?.(response),
|
|
485
|
-
className: onRowClick ? "cursor-pointer border-b border-border hover:bg-accent transition-colors" : "border-b border-border",
|
|
486
|
-
children: [
|
|
487
|
-
selectable && /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-3 py-2 w-8", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
488
|
-
"input",
|
|
489
|
-
{
|
|
490
|
-
type: "checkbox",
|
|
491
|
-
checked: !!(response.sessionToken && selectedIds?.has(response.sessionToken)),
|
|
492
|
-
onChange: (e) => {
|
|
493
|
-
e.stopPropagation();
|
|
494
|
-
if (response.sessionToken) onToggleSelect?.(response.sessionToken);
|
|
495
|
-
},
|
|
496
|
-
onClick: (e) => e.stopPropagation(),
|
|
497
|
-
className: "accent-primary"
|
|
498
|
-
}
|
|
499
|
-
) }),
|
|
500
|
-
/* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-3 py-2 text-foreground max-w-50 overflow-hidden text-ellipsis whitespace-nowrap", children: new Date(response.submittedAt).toLocaleString() }),
|
|
501
|
-
questions.map((q) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
502
|
-
"td",
|
|
503
|
-
{
|
|
504
|
-
className: "px-3 py-2 text-foreground max-w-50 overflow-hidden text-ellipsis whitespace-nowrap",
|
|
505
|
-
children: formatCellValue(response.values[q.id], q.type)
|
|
506
|
-
},
|
|
507
|
-
q.id
|
|
508
|
-
)),
|
|
509
|
-
/* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-3 py-2 text-foreground max-w-50 overflow-hidden text-ellipsis whitespace-nowrap", children: response.totalScore ?? "\u2014" })
|
|
510
|
-
]
|
|
511
|
-
},
|
|
512
|
-
response.sessionToken || idx
|
|
513
|
-
)),
|
|
514
|
-
responses.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("tr", { children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
515
|
-
"td",
|
|
516
|
-
{
|
|
517
|
-
colSpan: questions.length + 2 + (selectable ? 1 : 0),
|
|
518
|
-
className: "px-3 py-8 text-center text-muted-foreground",
|
|
519
|
-
children: "No responses yet"
|
|
520
|
-
}
|
|
521
|
-
) })
|
|
522
|
-
] })
|
|
523
|
-
] }) });
|
|
524
|
-
}
|
|
525
|
-
function getAllQuestions(schema) {
|
|
526
|
-
const questions = [];
|
|
527
|
-
for (const section of schema.sections) {
|
|
528
|
-
for (const q of section.questions) {
|
|
529
|
-
if (q.type === "info-block" || q.type === "section-header" || q.type === "page-break") {
|
|
530
|
-
continue;
|
|
531
|
-
}
|
|
532
|
-
questions.push(q);
|
|
533
|
-
}
|
|
534
|
-
}
|
|
535
|
-
return questions;
|
|
536
|
-
}
|
|
537
|
-
function formatCellValue(value, type) {
|
|
538
|
-
if (value == null) return "\u2014";
|
|
539
|
-
if (type) {
|
|
540
|
-
switch (type) {
|
|
541
|
-
case "vitals_entry": {
|
|
542
|
-
if (typeof value !== "object" || value === null) break;
|
|
543
|
-
const v = value;
|
|
544
|
-
const parts = [];
|
|
545
|
-
if (v.systolicBp && v.diastolicBp) parts.push(`BP ${v.systolicBp}/${v.diastolicBp}`);
|
|
546
|
-
if (v.heartRate) parts.push(`HR ${v.heartRate}`);
|
|
547
|
-
if (v.temperature) parts.push(`${v.temperature}\xB0F`);
|
|
548
|
-
if (v.oxygenSaturation) parts.push(`SpO\u2082 ${v.oxygenSaturation}%`);
|
|
549
|
-
return parts.length > 0 ? parts.join(", ") : "\u2014";
|
|
550
|
-
}
|
|
551
|
-
case "medication_list":
|
|
552
|
-
if (Array.isArray(value)) return `${value.length} medication${value.length !== 1 ? "s" : ""}`;
|
|
553
|
-
break;
|
|
554
|
-
case "allergy_list":
|
|
555
|
-
if (Array.isArray(value)) return `${value.length} allerg${value.length !== 1 ? "ies" : "y"}`;
|
|
556
|
-
break;
|
|
557
|
-
case "body_diagram":
|
|
558
|
-
if (Array.isArray(value)) {
|
|
559
|
-
const labels = value.map((id) => BODY_REGION_LABELS[id] ?? id);
|
|
560
|
-
return labels.join(", ");
|
|
561
|
-
}
|
|
562
|
-
break;
|
|
563
|
-
case "pain_scale":
|
|
564
|
-
if (typeof value === "number") return `${value}/10`;
|
|
565
|
-
break;
|
|
566
|
-
case "bmi_calculator": {
|
|
567
|
-
if (typeof value !== "object" || value === null) break;
|
|
568
|
-
const d = value;
|
|
569
|
-
if (d.bmi != null) return `BMI ${d.bmi}`;
|
|
570
|
-
break;
|
|
571
|
-
}
|
|
572
|
-
case "payment": {
|
|
573
|
-
if (typeof value !== "object" || value === null) break;
|
|
574
|
-
const p = value;
|
|
575
|
-
const status = p.status;
|
|
576
|
-
return status ? status.charAt(0).toUpperCase() + status.slice(1) : "\u2014";
|
|
577
|
-
}
|
|
578
|
-
case "insurance_card": {
|
|
579
|
-
if (typeof value !== "object" || value === null) break;
|
|
580
|
-
const ins = value;
|
|
581
|
-
const parts = [ins.carrierId, ins.planName].filter(Boolean);
|
|
582
|
-
return parts.length > 0 ? parts.join(" \u2014 ") : "Card uploaded";
|
|
583
|
-
}
|
|
584
|
-
case "legal_name": {
|
|
585
|
-
if (typeof value !== "object" || value === null) break;
|
|
586
|
-
const n = value;
|
|
587
|
-
return [n.first, n.last].filter(Boolean).join(" ") || "\u2014";
|
|
588
|
-
}
|
|
589
|
-
case "address": {
|
|
590
|
-
if (typeof value !== "object" || value === null) break;
|
|
591
|
-
const a = value;
|
|
592
|
-
return [a.city, a.state].filter(Boolean).join(", ") || "\u2014";
|
|
593
|
-
}
|
|
594
|
-
case "consent":
|
|
595
|
-
return value === true || value === "true" || value === "agreed" ? "Agreed" : "Not agreed";
|
|
596
|
-
case "signature":
|
|
597
|
-
return typeof value === "string" && value.startsWith("data:image") ? "Signed" : "\u2014";
|
|
598
|
-
}
|
|
599
|
-
}
|
|
600
|
-
if (typeof value === "boolean") return value ? "Yes" : "No";
|
|
601
|
-
if (Array.isArray(value)) return value.join(", ");
|
|
602
|
-
if (typeof value === "object") return JSON.stringify(value);
|
|
603
|
-
return String(value);
|
|
604
|
-
}
|
|
605
558
|
function ResponseCard({
|
|
606
559
|
response,
|
|
607
560
|
fields,
|
|
@@ -1085,7 +1038,13 @@ function formatFallbackValue(value) {
|
|
|
1085
1038
|
if (value == null) return "\u2014";
|
|
1086
1039
|
if (typeof value === "boolean") return value ? "Yes" : "No";
|
|
1087
1040
|
if (Array.isArray(value)) return value.map(formatFallbackValue).join(", ");
|
|
1088
|
-
if (typeof value === "object")
|
|
1041
|
+
if (typeof value === "object") {
|
|
1042
|
+
try {
|
|
1043
|
+
return JSON.stringify(value, null, 2);
|
|
1044
|
+
} catch {
|
|
1045
|
+
return "[Object]";
|
|
1046
|
+
}
|
|
1047
|
+
}
|
|
1089
1048
|
return String(value);
|
|
1090
1049
|
}
|
|
1091
1050
|
function TimelineView({ responses, questions, onSelect }) {
|
|
@@ -1603,9 +1562,7 @@ function getExportableQuestions(schema) {
|
|
|
1603
1562
|
const questions = [];
|
|
1604
1563
|
for (const section of schema.sections) {
|
|
1605
1564
|
for (const q of section.questions) {
|
|
1606
|
-
if (
|
|
1607
|
-
continue;
|
|
1608
|
-
}
|
|
1565
|
+
if (DISPLAY_ONLY_TYPES.has(q.type)) continue;
|
|
1609
1566
|
questions.push(q);
|
|
1610
1567
|
}
|
|
1611
1568
|
}
|
|
@@ -1671,6 +1628,10 @@ function formatExportValue(value, type) {
|
|
|
1671
1628
|
return String(value);
|
|
1672
1629
|
}
|
|
1673
1630
|
function escapeCsvField(field) {
|
|
1631
|
+
const first = field.charAt(0);
|
|
1632
|
+
if (first === "=" || first === "+" || first === "-" || first === "@" || first === " " || first === "\r") {
|
|
1633
|
+
field = `'${field}`;
|
|
1634
|
+
}
|
|
1674
1635
|
if (field.includes(",") || field.includes('"') || field.includes("\n")) {
|
|
1675
1636
|
return `"${field.replace(/"/g, '""')}"`;
|
|
1676
1637
|
}
|
|
@@ -1685,7 +1646,7 @@ function downloadBlob(content, filename, mimeType) {
|
|
|
1685
1646
|
document.body.appendChild(link);
|
|
1686
1647
|
link.click();
|
|
1687
1648
|
document.body.removeChild(link);
|
|
1688
|
-
URL.revokeObjectURL(url);
|
|
1649
|
+
setTimeout(() => URL.revokeObjectURL(url), 100);
|
|
1689
1650
|
}
|
|
1690
1651
|
|
|
1691
1652
|
// src/response-viewer/pagination-utils.ts
|
|
@@ -1805,14 +1766,15 @@ function applyFilters(responses, state) {
|
|
|
1805
1766
|
function matchesDateRange(submittedAt, range) {
|
|
1806
1767
|
if (!range.from && !range.to) return true;
|
|
1807
1768
|
const submitted = new Date(submittedAt);
|
|
1769
|
+
if (isNaN(submitted.getTime())) return false;
|
|
1808
1770
|
if (range.from) {
|
|
1809
|
-
const from = new Date(range.from);
|
|
1810
|
-
from.
|
|
1771
|
+
const from = /* @__PURE__ */ new Date(range.from + "T00:00:00");
|
|
1772
|
+
if (isNaN(from.getTime())) return false;
|
|
1811
1773
|
if (submitted < from) return false;
|
|
1812
1774
|
}
|
|
1813
1775
|
if (range.to) {
|
|
1814
|
-
const to = new Date(range.to);
|
|
1815
|
-
to.
|
|
1776
|
+
const to = /* @__PURE__ */ new Date(range.to + "T23:59:59.999");
|
|
1777
|
+
if (isNaN(to.getTime())) return false;
|
|
1816
1778
|
if (submitted > to) return false;
|
|
1817
1779
|
}
|
|
1818
1780
|
return true;
|
|
@@ -1921,9 +1883,12 @@ function ResponseViewerInner({
|
|
|
1921
1883
|
[responses, searchQuery, schema]
|
|
1922
1884
|
);
|
|
1923
1885
|
const isFiltered = hasActiveFilters(filterState);
|
|
1924
|
-
const filteredResponses =
|
|
1886
|
+
const filteredResponses = react.useMemo(
|
|
1887
|
+
() => applyFilters(searchedResponses, filterState),
|
|
1888
|
+
[searchedResponses, filterState]
|
|
1889
|
+
);
|
|
1925
1890
|
const pag = paginate(filteredResponses, currentPage, effectivePageSize);
|
|
1926
|
-
const questions =
|
|
1891
|
+
const questions = react.useMemo(() => getAllQuestions(schema), [schema]);
|
|
1927
1892
|
const isSelectable = selectable && (!!onBulkDelete || !!onBulkExport);
|
|
1928
1893
|
function handleSelect(response) {
|
|
1929
1894
|
setSelectedResponse(response);
|
|
@@ -2025,7 +1990,7 @@ function ResponseViewerInner({
|
|
|
2025
1990
|
});
|
|
2026
1991
|
}
|
|
2027
1992
|
function getFields(response) {
|
|
2028
|
-
return questions.map((q) => ({
|
|
1993
|
+
return questions.filter((q) => response.values[q.id] !== void 0).map((q) => ({
|
|
2029
1994
|
questionId: q.id,
|
|
2030
1995
|
label: q.label,
|
|
2031
1996
|
type: q.type,
|
|
@@ -2178,10 +2143,10 @@ function ResponseViewerInner({
|
|
|
2178
2143
|
className: "h-7 text-xs",
|
|
2179
2144
|
onClick: () => {
|
|
2180
2145
|
const csvFilename = filename ? filename.replace(/\.\w+$/, ".csv") : "responses.csv";
|
|
2181
|
-
exportToCsv(schema,
|
|
2182
|
-
onExport?.("csv",
|
|
2146
|
+
exportToCsv(schema, filteredResponses, csvFilename, { dateFormat, columnLabels });
|
|
2147
|
+
onExport?.("csv", filteredResponses.length);
|
|
2183
2148
|
},
|
|
2184
|
-
disabled:
|
|
2149
|
+
disabled: filteredResponses.length === 0,
|
|
2185
2150
|
children: "Export CSV"
|
|
2186
2151
|
}
|
|
2187
2152
|
),
|
|
@@ -2193,10 +2158,10 @@ function ResponseViewerInner({
|
|
|
2193
2158
|
className: "h-7 text-xs",
|
|
2194
2159
|
onClick: () => {
|
|
2195
2160
|
const jsonFilename = filename ? filename.replace(/\.\w+$/, ".json") : "responses.json";
|
|
2196
|
-
exportToJson(
|
|
2197
|
-
onExport?.("json",
|
|
2161
|
+
exportToJson(filteredResponses, jsonFilename);
|
|
2162
|
+
onExport?.("json", filteredResponses.length);
|
|
2198
2163
|
},
|
|
2199
|
-
disabled:
|
|
2164
|
+
disabled: filteredResponses.length === 0,
|
|
2200
2165
|
children: "Export JSON"
|
|
2201
2166
|
}
|
|
2202
2167
|
)
|
|
@@ -2372,7 +2337,7 @@ function ResponseViewerInner({
|
|
|
2372
2337
|
response: selectedResponse,
|
|
2373
2338
|
fields: getFields(selectedResponse),
|
|
2374
2339
|
onBack: handleBack,
|
|
2375
|
-
onDelete: onDelete && selectedResponse.sessionToken ? () => handleDeleteSingle(selectedResponse.sessionToken) : void 0
|
|
2340
|
+
onDelete: onDelete && selectedResponse.sessionToken != null ? () => handleDeleteSingle(selectedResponse.sessionToken) : void 0
|
|
2376
2341
|
}
|
|
2377
2342
|
) }) : viewMode === "timeline" ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
2378
2343
|
TimelineView,
|
|
@@ -2477,13 +2442,11 @@ function ResponseViewerInner({
|
|
|
2477
2442
|
}
|
|
2478
2443
|
);
|
|
2479
2444
|
}
|
|
2480
|
-
function
|
|
2445
|
+
function getAllQuestions(schema) {
|
|
2481
2446
|
const questions = [];
|
|
2482
2447
|
for (const section of schema.sections) {
|
|
2483
2448
|
for (const q of section.questions) {
|
|
2484
|
-
if (
|
|
2485
|
-
continue;
|
|
2486
|
-
}
|
|
2449
|
+
if (DISPLAY_ONLY_TYPES.has(q.type)) continue;
|
|
2487
2450
|
questions.push(q);
|
|
2488
2451
|
}
|
|
2489
2452
|
}
|