@squaredr/fieldcraft-pro 0.0.5 → 1.1.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.
@@ -1,78 +1,517 @@
1
1
  'use strict';
2
2
 
3
- var fieldcraftProLicense = require('@squaredr/fieldcraft-pro-license');
4
3
  var react = require('react');
5
4
  var jsxRuntime = require('react/jsx-runtime');
5
+ var fieldcraftReact = require('@squaredr/fieldcraft-react');
6
+ var clsx = require('clsx');
7
+ var tailwindMerge = require('tailwind-merge');
6
8
 
7
- // src/response-viewer/ResponseViewer.tsx
8
- function ResponseTable({ schema, responses, onRowClick }) {
9
- const questions = getAllQuestions(schema);
10
- return /* @__PURE__ */ jsxRuntime.jsx("div", { style: { overflow: "auto", fontFamily: "inherit" }, children: /* @__PURE__ */ jsxRuntime.jsxs(
11
- "table",
12
- {
13
- style: {
14
- width: "100%",
15
- borderCollapse: "collapse",
16
- fontSize: "13px"
17
- },
18
- children: [
19
- /* @__PURE__ */ jsxRuntime.jsx("thead", { children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { style: { backgroundColor: "var(--muted, #111113)" }, children: [
20
- /* @__PURE__ */ jsxRuntime.jsx("th", { style: thStyle, children: "Submitted" }),
21
- questions.map((q) => /* @__PURE__ */ jsxRuntime.jsx("th", { style: thStyle, children: q.label }, q.id)),
22
- /* @__PURE__ */ jsxRuntime.jsx("th", { style: thStyle, children: "Score" })
23
- ] }) }),
24
- /* @__PURE__ */ jsxRuntime.jsxs("tbody", { children: [
25
- responses.map((response, idx) => /* @__PURE__ */ jsxRuntime.jsxs(
26
- "tr",
9
+ // ../license/dist/index.mjs
10
+ var PRO_FEATURES = [
11
+ "SchemaEditor",
12
+ "ResponseViewer",
13
+ "ThemeEditor",
14
+ "FormBuilder",
15
+ "ApiManager",
16
+ "Analytics"
17
+ ];
18
+ var ALL_FEATURES = [
19
+ ...PRO_FEATURES,
20
+ "Telehealth"
21
+ ];
22
+ var TIER_FEATURES = {
23
+ starter: ["SchemaEditor", "ResponseViewer"],
24
+ pro: PRO_FEATURES,
25
+ business: ALL_FEATURES,
26
+ enterprise: ALL_FEATURES
27
+ };
28
+ function tierHasFeature(tier, featureName) {
29
+ return TIER_FEATURES[tier]?.includes(featureName) ?? false;
30
+ }
31
+ var DEV_HOSTNAMES = /* @__PURE__ */ new Set([
32
+ "localhost",
33
+ "127.0.0.1",
34
+ "0.0.0.0",
35
+ "[::1]",
36
+ "::1"
37
+ ]);
38
+ var DEV_HOSTNAME_PATTERNS = [
39
+ /^192\.168\.\d+\.\d+$/,
40
+ // local network
41
+ /^10\.\d+\.\d+\.\d+$/,
42
+ // local network
43
+ /^172\.(1[6-9]|2\d|3[01])\.\d+\.\d+$/
44
+ // local network
45
+ ];
46
+ var PRODUCTION_HOST_SUFFIXES = [
47
+ ".vercel.app",
48
+ ".netlify.app",
49
+ ".netlify.com",
50
+ ".herokuapp.com",
51
+ ".fly.dev",
52
+ ".railway.app",
53
+ ".render.com",
54
+ ".onrender.com",
55
+ ".pages.dev",
56
+ // Cloudflare Pages
57
+ ".workers.dev",
58
+ // Cloudflare Workers
59
+ ".azurewebsites.net",
60
+ ".web.app",
61
+ // Firebase
62
+ ".firebaseapp.com",
63
+ ".amplifyapp.com",
64
+ ".surge.sh",
65
+ ".github.io",
66
+ ".gitlab.io"
67
+ ];
68
+ function isDevHostname(hostname) {
69
+ if (DEV_HOSTNAMES.has(hostname)) return true;
70
+ for (const pattern of DEV_HOSTNAME_PATTERNS) {
71
+ if (pattern.test(hostname)) return true;
72
+ }
73
+ return false;
74
+ }
75
+ function isKnownProductionHost(hostname) {
76
+ for (const suffix of PRODUCTION_HOST_SUFFIXES) {
77
+ if (hostname.endsWith(suffix)) return true;
78
+ }
79
+ return false;
80
+ }
81
+ function hasRealTLD(hostname) {
82
+ return /\.[a-z]{2,}$/i.test(hostname) && !isDevHostname(hostname);
83
+ }
84
+ function isProductionEnvironment() {
85
+ const _proc = typeof globalThis !== "undefined" ? globalThis.process : void 0;
86
+ if (_proc?.env) {
87
+ const nodeEnv = _proc.env.NODE_ENV;
88
+ if (nodeEnv === "production") return true;
89
+ if (nodeEnv === "development" || nodeEnv === "test") return false;
90
+ }
91
+ if (typeof window !== "undefined" && window.location) {
92
+ const { hostname, protocol, port } = window.location;
93
+ if (protocol === "file:") return false;
94
+ if (isDevHostname(hostname)) return false;
95
+ if (port && port !== "443" && port !== "80") return false;
96
+ if (isKnownProductionHost(hostname)) return true;
97
+ if (protocol === "https:" && hasRealTLD(hostname)) return true;
98
+ if (hasRealTLD(hostname)) return true;
99
+ }
100
+ return false;
101
+ }
102
+ var defaultContext = { status: "validating", tier: null };
103
+ var LicenseCtx = react.createContext(defaultContext);
104
+ function useLicense() {
105
+ return react.useContext(LicenseCtx);
106
+ }
107
+ function UnlicensedOverlay({ featureName, reason, children }) {
108
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { position: "relative", minHeight: "200px" }, children: [
109
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { pointerEvents: "none", userSelect: "none", filter: "blur(2px)" }, children }),
110
+ /* @__PURE__ */ jsxRuntime.jsxs(
111
+ "div",
112
+ {
113
+ style: {
114
+ position: "absolute",
115
+ inset: 0,
116
+ zIndex: 2147483647,
117
+ display: "flex",
118
+ flexDirection: "column",
119
+ alignItems: "center",
120
+ justifyContent: "center",
121
+ backgroundColor: "rgba(0, 0, 0, 0.75)",
122
+ backdropFilter: "blur(4px)",
123
+ fontFamily: "system-ui, -apple-system, sans-serif",
124
+ padding: "32px"
125
+ },
126
+ children: [
127
+ /* @__PURE__ */ jsxRuntime.jsx(
128
+ "div",
27
129
  {
28
- onClick: () => onRowClick?.(response),
29
130
  style: {
30
- cursor: onRowClick ? "pointer" : "default",
31
- borderBottom: "1px solid var(--border, #1c1c20)"
32
- },
33
- onMouseEnter: (e) => {
34
- if (onRowClick) e.currentTarget.style.backgroundColor = "var(--accent, #17171a)";
131
+ position: "absolute",
132
+ inset: 0,
133
+ overflow: "hidden",
134
+ pointerEvents: "none",
135
+ zIndex: 0
35
136
  },
36
- onMouseLeave: (e) => {
37
- e.currentTarget.style.backgroundColor = "transparent";
137
+ children: Array.from({ length: 12 }).map((_, i) => /* @__PURE__ */ jsxRuntime.jsx(
138
+ "div",
139
+ {
140
+ style: {
141
+ position: "absolute",
142
+ top: `${i * 80}px`,
143
+ left: "-50%",
144
+ right: "-50%",
145
+ textAlign: "center",
146
+ transform: "rotate(-30deg)",
147
+ fontSize: "18px",
148
+ fontWeight: 700,
149
+ color: "rgba(255, 255, 255, 0.06)",
150
+ letterSpacing: "8px",
151
+ textTransform: "uppercase",
152
+ whiteSpace: "nowrap",
153
+ userSelect: "none"
154
+ },
155
+ children: "UNLICENSED \u2022 FIELDCRAFT PRO \u2022 UNLICENSED \u2022 FIELDCRAFT PRO \u2022 UNLICENSED \u2022 FIELDCRAFT PRO"
156
+ },
157
+ i
158
+ ))
159
+ }
160
+ ),
161
+ /* @__PURE__ */ jsxRuntime.jsxs(
162
+ "div",
163
+ {
164
+ style: {
165
+ position: "relative",
166
+ zIndex: 1,
167
+ textAlign: "center",
168
+ maxWidth: "420px"
38
169
  },
39
170
  children: [
40
- /* @__PURE__ */ jsxRuntime.jsx("td", { style: tdStyle, children: new Date(response.submittedAt).toLocaleString() }),
41
- questions.map((q) => /* @__PURE__ */ jsxRuntime.jsx("td", { style: tdStyle, children: formatCellValue(response.values[q.id]) }, q.id)),
42
- /* @__PURE__ */ jsxRuntime.jsx("td", { style: tdStyle, children: response.totalScore ?? "\u2014" })
171
+ /* @__PURE__ */ jsxRuntime.jsx(
172
+ "div",
173
+ {
174
+ style: {
175
+ width: "64px",
176
+ height: "64px",
177
+ margin: "0 auto 16px",
178
+ borderRadius: "50%",
179
+ backgroundColor: "rgba(239, 68, 68, 0.2)",
180
+ border: "2px solid rgba(239, 68, 68, 0.5)",
181
+ display: "flex",
182
+ alignItems: "center",
183
+ justifyContent: "center",
184
+ fontSize: "28px"
185
+ },
186
+ children: "\u{1F6E1}"
187
+ }
188
+ ),
189
+ /* @__PURE__ */ jsxRuntime.jsx(
190
+ "div",
191
+ {
192
+ style: {
193
+ fontSize: "22px",
194
+ fontWeight: 700,
195
+ color: "#ffffff",
196
+ marginBottom: "8px",
197
+ letterSpacing: "-0.02em"
198
+ },
199
+ children: "License Required"
200
+ }
201
+ ),
202
+ /* @__PURE__ */ jsxRuntime.jsx(
203
+ "div",
204
+ {
205
+ style: {
206
+ fontSize: "15px",
207
+ fontWeight: 600,
208
+ color: "#f87171",
209
+ marginBottom: "6px"
210
+ },
211
+ children: featureName
212
+ }
213
+ ),
214
+ /* @__PURE__ */ jsxRuntime.jsx(
215
+ "div",
216
+ {
217
+ style: {
218
+ fontSize: "14px",
219
+ color: "#d1d5db",
220
+ marginBottom: "24px",
221
+ lineHeight: "1.5"
222
+ },
223
+ children: reason
224
+ }
225
+ ),
226
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", gap: "10px", justifyContent: "center", flexWrap: "wrap" }, children: [
227
+ /* @__PURE__ */ jsxRuntime.jsx(
228
+ "a",
229
+ {
230
+ href: "https://squaredr.tech/products/fieldcraft/admin-pro#pricing",
231
+ target: "_blank",
232
+ rel: "noopener noreferrer",
233
+ style: {
234
+ display: "inline-block",
235
+ padding: "12px 24px",
236
+ fontSize: "14px",
237
+ fontWeight: 600,
238
+ color: "#ffffff",
239
+ backgroundColor: "#2563eb",
240
+ borderRadius: "8px",
241
+ textDecoration: "none",
242
+ boxShadow: "0 4px 14px rgba(37, 99, 235, 0.4)"
243
+ },
244
+ children: "Get a License"
245
+ }
246
+ ),
247
+ /* @__PURE__ */ jsxRuntime.jsx(
248
+ "a",
249
+ {
250
+ href: "https://discord.gg/zMxdu5UVW",
251
+ target: "_blank",
252
+ rel: "noopener noreferrer",
253
+ style: {
254
+ display: "inline-block",
255
+ padding: "12px 24px",
256
+ fontSize: "14px",
257
+ fontWeight: 600,
258
+ color: "#93c5fd",
259
+ backgroundColor: "rgba(37, 99, 235, 0.15)",
260
+ border: "1px solid rgba(37, 99, 235, 0.4)",
261
+ borderRadius: "8px",
262
+ textDecoration: "none"
263
+ },
264
+ children: "Join Discord"
265
+ }
266
+ )
267
+ ] }),
268
+ /* @__PURE__ */ jsxRuntime.jsxs(
269
+ "div",
270
+ {
271
+ style: {
272
+ fontSize: "12px",
273
+ color: "#6b7280",
274
+ marginTop: "16px"
275
+ },
276
+ children: [
277
+ "This component works freely in development.",
278
+ " ",
279
+ /* @__PURE__ */ jsxRuntime.jsx(
280
+ "a",
281
+ {
282
+ href: "https://squaredr.tech/products/fieldcraft/docs/pro/license",
283
+ target: "_blank",
284
+ rel: "noopener noreferrer",
285
+ style: { color: "#9ca3af", textDecoration: "underline" },
286
+ children: "Learn more"
287
+ }
288
+ )
289
+ ]
290
+ }
291
+ )
43
292
  ]
44
- },
45
- response.sessionToken || idx
46
- )),
47
- responses.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("tr", { children: /* @__PURE__ */ jsxRuntime.jsx(
48
- "td",
49
- {
50
- colSpan: questions.length + 2,
51
- style: { ...tdStyle, textAlign: "center", color: "var(--muted-foreground, #8a8a95)", padding: "32px" },
52
- children: "No responses yet"
53
293
  }
54
- ) })
55
- ] })
56
- ]
294
+ )
295
+ ]
296
+ }
297
+ )
298
+ ] });
299
+ }
300
+ function requireLicense(Component, featureName) {
301
+ function LicenseGated(props) {
302
+ const { status, tier } = useLicense();
303
+ const isProduction = isProductionEnvironment();
304
+ if (!isProduction) {
305
+ return /* @__PURE__ */ jsxRuntime.jsx(Component, { ...props });
306
+ }
307
+ if (status === "validating") {
308
+ return null;
309
+ }
310
+ const isLicensed = status === "valid" && tier != null && tierHasFeature(tier, featureName);
311
+ if (isLicensed) {
312
+ return /* @__PURE__ */ jsxRuntime.jsx(Component, { ...props });
57
313
  }
58
- ) });
59
- }
60
- var thStyle = {
61
- padding: "8px 12px",
62
- textAlign: "left",
63
- fontWeight: 600,
64
- color: "var(--foreground, #e8e8ea)",
65
- borderBottom: "2px solid var(--border, #1c1c20)",
66
- whiteSpace: "nowrap"
314
+ let reason = "A valid license is required for production use.";
315
+ if (status === "invalid") {
316
+ reason = "Invalid license key. Please check your license key and try again.";
317
+ } else if (status === "expired") {
318
+ reason = "Your license has expired. Please renew to continue using this component in production.";
319
+ } else if (status === "revoked") {
320
+ reason = "This license key has been revoked. Please contact support or purchase a new license.";
321
+ } else if (status === "domain_mismatch") {
322
+ reason = "This license key is registered to a different domain. Each key can only be used on one production domain. Please purchase a new license for this domain.";
323
+ } else if (!tier || !tierHasFeature(tier, featureName)) {
324
+ reason = "Your license does not include this feature. Please upgrade your plan.";
325
+ }
326
+ return /* @__PURE__ */ jsxRuntime.jsx(UnlicensedOverlay, { featureName, reason, children: /* @__PURE__ */ jsxRuntime.jsx(Component, { ...props }) });
327
+ }
328
+ LicenseGated.displayName = `requireLicense(${Component.displayName || Component.name || "Component"})`;
329
+ return LicenseGated;
330
+ }
331
+
332
+ // src/response-viewer/clinical-display-data.ts
333
+ var BODY_REGION_LABELS = {
334
+ head: "Head",
335
+ neck: "Neck",
336
+ "left-shoulder": "Left Shoulder",
337
+ "right-shoulder": "Right Shoulder",
338
+ chest: "Chest",
339
+ abdomen: "Abdomen",
340
+ "left-upper-arm": "Left Upper Arm",
341
+ "right-upper-arm": "Right Upper Arm",
342
+ "left-forearm": "Left Forearm",
343
+ "right-forearm": "Right Forearm",
344
+ "left-hand": "Left Hand",
345
+ "right-hand": "Right Hand",
346
+ pelvis: "Pelvis",
347
+ "left-thigh": "Left Thigh",
348
+ "right-thigh": "Right Thigh",
349
+ "left-knee": "Left Knee",
350
+ "right-knee": "Right Knee",
351
+ "left-shin": "Left Shin",
352
+ "right-shin": "Right Shin",
353
+ "left-foot": "Left Foot",
354
+ "right-foot": "Right Foot"
355
+ };
356
+ var PAIN_FACE_LABELS = [
357
+ { score: 0, label: "No Hurt", color: "#22c55e" },
358
+ { score: 2, label: "Hurts Little Bit", color: "#84cc16" },
359
+ { score: 4, label: "Hurts Little More", color: "#eab308" },
360
+ { score: 6, label: "Hurts Even More", color: "#f97316" },
361
+ { score: 8, label: "Hurts Whole Lot", color: "#ef4444" },
362
+ { score: 10, label: "Hurts Worst", color: "#dc2626" }
363
+ ];
364
+ function getPainLabel(score) {
365
+ const face = PAIN_FACE_LABELS.reduce(
366
+ (closest, f) => closest == null || Math.abs(f.score - score) < Math.abs(closest.score - score) ? f : closest,
367
+ void 0
368
+ );
369
+ return face;
370
+ }
371
+ var SEVERITY_COLORS = {
372
+ mild: "#eab308",
373
+ moderate: "#f97316",
374
+ severe: "#ef4444",
375
+ "life-threatening": "#991b1b"
376
+ };
377
+ var BMI_CATEGORIES = [
378
+ { label: "Underweight", max: 18.5, color: "#3b82f6" },
379
+ { label: "Normal", max: 25, color: "#22c55e" },
380
+ { label: "Overweight", max: 30, color: "#eab308" },
381
+ { label: "Obese", max: Infinity, color: "#ef4444" }
382
+ ];
383
+ function getBmiCategory(bmi) {
384
+ return BMI_CATEGORIES.find((c) => bmi < c.max) ?? BMI_CATEGORIES[BMI_CATEGORIES.length - 1];
385
+ }
386
+ var INSTRUMENT_DISPLAY_NAMES = {
387
+ phq9: "PHQ-9",
388
+ phq2: "PHQ-2",
389
+ gad7: "GAD-7",
390
+ gad2: "GAD-2",
391
+ "audit-c": "AUDIT-C",
392
+ dast10: "DAST-10",
393
+ cssrs: "C-SSRS",
394
+ epds: "EPDS",
395
+ isi: "ISI",
396
+ pcl5: "PCL-5",
397
+ psc17: "PSC-17"
67
398
  };
68
- var tdStyle = {
69
- padding: "8px 12px",
70
- color: "var(--foreground, #e8e8ea)",
71
- maxWidth: "200px",
72
- overflow: "hidden",
73
- textOverflow: "ellipsis",
74
- whiteSpace: "nowrap"
399
+ var SCORE_THRESHOLDS = {
400
+ phq9: [
401
+ { min: 0, max: 4, label: "Minimal", color: "#22c55e" },
402
+ { min: 5, max: 9, label: "Mild", color: "#eab308" },
403
+ { min: 10, max: 14, label: "Moderate", color: "#f97316" },
404
+ { min: 15, max: 19, label: "Moderately Severe", color: "#ef4444" },
405
+ { min: 20, max: 27, label: "Severe", color: "#dc2626" }
406
+ ],
407
+ phq2: [
408
+ { min: 0, max: 2, label: "Negative Screen", color: "#22c55e" },
409
+ { min: 3, max: 6, label: "Positive Screen", color: "#ef4444" }
410
+ ],
411
+ gad7: [
412
+ { min: 0, max: 4, label: "Minimal", color: "#22c55e" },
413
+ { min: 5, max: 9, label: "Mild", color: "#eab308" },
414
+ { min: 10, max: 14, label: "Moderate", color: "#f97316" },
415
+ { min: 15, max: 21, label: "Severe", color: "#ef4444" }
416
+ ],
417
+ gad2: [
418
+ { min: 0, max: 2, label: "Negative Screen", color: "#22c55e" },
419
+ { min: 3, max: 6, label: "Positive Screen", color: "#ef4444" }
420
+ ],
421
+ "audit-c": [
422
+ { min: 0, max: 3, label: "Low Risk", color: "#22c55e" },
423
+ { min: 4, max: 7, label: "At Risk", color: "#eab308" },
424
+ { min: 8, max: 12, label: "High Risk", color: "#ef4444" }
425
+ ],
426
+ dast10: [
427
+ { min: 0, max: 0, label: "No Problems", color: "#22c55e" },
428
+ { min: 1, max: 2, label: "Low Level", color: "#eab308" },
429
+ { min: 3, max: 5, label: "Moderate Level", color: "#f97316" },
430
+ { min: 6, max: 8, label: "Substantial Level", color: "#ef4444" },
431
+ { min: 9, max: 10, label: "Severe Level", color: "#dc2626" }
432
+ ],
433
+ cssrs: [
434
+ { min: 0, max: 0, label: "No Risk Identified", color: "#22c55e" },
435
+ { min: 1, max: 1, label: "Wish to be Dead", color: "#eab308" },
436
+ { min: 2, max: 2, label: "Non-specific Active Suicidal Thoughts", color: "#f97316" },
437
+ { min: 3, max: 3, label: "Active Suicidal Ideation", color: "#ef4444" },
438
+ { min: 4, max: 4, label: "Active Ideation with Intent", color: "#dc2626" },
439
+ { min: 5, max: 5, label: "Active Ideation with Plan", color: "#991b1b" },
440
+ { min: 6, max: 6, label: "Imminent Risk", color: "#7f1d1d" }
441
+ ],
442
+ epds: [
443
+ { min: 0, max: 8, label: "Low Likelihood", color: "#22c55e" },
444
+ { min: 9, max: 11, label: "Possible Depression", color: "#eab308" },
445
+ { min: 12, max: 13, label: "Fairly High Possibility", color: "#f97316" },
446
+ { min: 14, max: 30, label: "Probable Depression", color: "#ef4444" }
447
+ ],
448
+ isi: [
449
+ { min: 0, max: 7, label: "No Clinically Significant Insomnia", color: "#22c55e" },
450
+ { min: 8, max: 14, label: "Subthreshold Insomnia", color: "#eab308" },
451
+ { min: 15, max: 21, label: "Clinical Insomnia (Moderate)", color: "#f97316" },
452
+ { min: 22, max: 28, label: "Clinical Insomnia (Severe)", color: "#ef4444" }
453
+ ],
454
+ pcl5: [
455
+ { min: 0, max: 30, label: "Below Threshold", color: "#22c55e" },
456
+ { min: 31, max: 80, label: "Probable PTSD", color: "#ef4444" }
457
+ ],
458
+ psc17: [
459
+ { min: 0, max: 14, label: "No Significant Concerns", color: "#22c55e" },
460
+ { min: 15, max: 34, label: "Significant Concerns", color: "#ef4444" }
461
+ ]
75
462
  };
463
+ function getScoreSeverity(instrumentKey, score) {
464
+ const thresholds = SCORE_THRESHOLDS[instrumentKey];
465
+ if (!thresholds) return void 0;
466
+ return thresholds.find((t) => score >= t.min && score <= t.max);
467
+ }
468
+ function ResponseTable({ schema, responses, onRowClick }) {
469
+ const questions = getAllQuestions(schema);
470
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "overflow-auto", children: /* @__PURE__ */ jsxRuntime.jsxs("table", { className: "w-full border-collapse text-[13px]", children: [
471
+ /* @__PURE__ */ jsxRuntime.jsx("thead", { children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { className: "bg-muted", children: [
472
+ /* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-3 py-2 text-left font-semibold text-foreground border-b-2 border-border whitespace-nowrap", children: "Submitted" }),
473
+ questions.map((q) => /* @__PURE__ */ jsxRuntime.jsx(
474
+ "th",
475
+ {
476
+ className: "px-3 py-2 text-left font-semibold text-foreground border-b-2 border-border whitespace-nowrap",
477
+ children: q.label
478
+ },
479
+ q.id
480
+ )),
481
+ /* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-3 py-2 text-left font-semibold text-foreground border-b-2 border-border whitespace-nowrap", children: "Score" })
482
+ ] }) }),
483
+ /* @__PURE__ */ jsxRuntime.jsxs("tbody", { children: [
484
+ responses.map((response, idx) => /* @__PURE__ */ jsxRuntime.jsxs(
485
+ "tr",
486
+ {
487
+ onClick: () => onRowClick?.(response),
488
+ className: onRowClick ? "cursor-pointer border-b border-border hover:bg-accent transition-colors" : "border-b border-border",
489
+ children: [
490
+ /* @__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() }),
491
+ questions.map((q) => /* @__PURE__ */ jsxRuntime.jsx(
492
+ "td",
493
+ {
494
+ className: "px-3 py-2 text-foreground max-w-50 overflow-hidden text-ellipsis whitespace-nowrap",
495
+ children: formatCellValue(response.values[q.id], q.type)
496
+ },
497
+ q.id
498
+ )),
499
+ /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-3 py-2 text-foreground max-w-50 overflow-hidden text-ellipsis whitespace-nowrap", children: response.totalScore ?? "\u2014" })
500
+ ]
501
+ },
502
+ response.sessionToken || idx
503
+ )),
504
+ responses.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("tr", { children: /* @__PURE__ */ jsxRuntime.jsx(
505
+ "td",
506
+ {
507
+ colSpan: questions.length + 2,
508
+ className: "px-3 py-8 text-center text-muted-foreground",
509
+ children: "No responses yet"
510
+ }
511
+ ) })
512
+ ] })
513
+ ] }) });
514
+ }
76
515
  function getAllQuestions(schema) {
77
516
  const questions = [];
78
517
  for (const section of schema.sections) {
@@ -85,8 +524,69 @@ function getAllQuestions(schema) {
85
524
  }
86
525
  return questions;
87
526
  }
88
- function formatCellValue(value) {
527
+ function formatCellValue(value, type) {
89
528
  if (value == null) return "\u2014";
529
+ if (type) {
530
+ switch (type) {
531
+ case "vitals_entry": {
532
+ if (typeof value !== "object" || value === null) break;
533
+ const v = value;
534
+ const parts = [];
535
+ if (v.systolicBp && v.diastolicBp) parts.push(`BP ${v.systolicBp}/${v.diastolicBp}`);
536
+ if (v.heartRate) parts.push(`HR ${v.heartRate}`);
537
+ if (v.temperature) parts.push(`${v.temperature}\xB0F`);
538
+ if (v.oxygenSaturation) parts.push(`SpO\u2082 ${v.oxygenSaturation}%`);
539
+ return parts.length > 0 ? parts.join(", ") : "\u2014";
540
+ }
541
+ case "medication_list":
542
+ if (Array.isArray(value)) return `${value.length} medication${value.length !== 1 ? "s" : ""}`;
543
+ break;
544
+ case "allergy_list":
545
+ if (Array.isArray(value)) return `${value.length} allerg${value.length !== 1 ? "ies" : "y"}`;
546
+ break;
547
+ case "body_diagram":
548
+ if (Array.isArray(value)) {
549
+ const labels = value.map((id) => BODY_REGION_LABELS[id] ?? id);
550
+ return labels.join(", ");
551
+ }
552
+ break;
553
+ case "pain_scale":
554
+ if (typeof value === "number") return `${value}/10`;
555
+ break;
556
+ case "bmi_calculator": {
557
+ if (typeof value !== "object" || value === null) break;
558
+ const d = value;
559
+ if (d.bmi != null) return `BMI ${d.bmi}`;
560
+ break;
561
+ }
562
+ case "payment": {
563
+ if (typeof value !== "object" || value === null) break;
564
+ const p = value;
565
+ const status = p.status;
566
+ return status ? status.charAt(0).toUpperCase() + status.slice(1) : "\u2014";
567
+ }
568
+ case "insurance_card": {
569
+ if (typeof value !== "object" || value === null) break;
570
+ const ins = value;
571
+ const parts = [ins.carrierId, ins.planName].filter(Boolean);
572
+ return parts.length > 0 ? parts.join(" \u2014 ") : "Card uploaded";
573
+ }
574
+ case "legal_name": {
575
+ if (typeof value !== "object" || value === null) break;
576
+ const n = value;
577
+ return [n.first, n.last].filter(Boolean).join(" ") || "\u2014";
578
+ }
579
+ case "address": {
580
+ if (typeof value !== "object" || value === null) break;
581
+ const a = value;
582
+ return [a.city, a.state].filter(Boolean).join(", ") || "\u2014";
583
+ }
584
+ case "consent":
585
+ return value === true || value === "true" || value === "agreed" ? "Agreed" : "Not agreed";
586
+ case "signature":
587
+ return typeof value === "string" && value.startsWith("data:image") ? "Signed" : "\u2014";
588
+ }
589
+ }
90
590
  if (typeof value === "boolean") return value ? "Yes" : "No";
91
591
  if (Array.isArray(value)) return value.join(", ");
92
592
  if (typeof value === "object") return JSON.stringify(value);
@@ -97,238 +597,573 @@ function ResponseCard({ response, fields, onClick }) {
97
597
  "div",
98
598
  {
99
599
  onClick,
100
- style: {
101
- border: "1px solid var(--border, #1c1c20)",
102
- borderRadius: "8px",
103
- padding: "16px",
104
- backgroundColor: "var(--card, #111113)",
105
- cursor: onClick ? "pointer" : "default",
106
- fontFamily: "inherit",
107
- transition: "box-shadow 0.15s"
108
- },
109
- onMouseEnter: (e) => {
110
- if (onClick) e.currentTarget.style.boxShadow = "0 2px 8px rgba(0,0,0,0.3)";
111
- },
112
- onMouseLeave: (e) => {
113
- e.currentTarget.style.boxShadow = "none";
114
- },
600
+ className: onClick ? "border border-border rounded-lg p-4 bg-card cursor-pointer transition-shadow hover:shadow-md" : "border border-border rounded-lg p-4 bg-card",
115
601
  children: [
116
- /* @__PURE__ */ jsxRuntime.jsxs(
117
- "div",
118
- {
119
- style: {
120
- display: "flex",
121
- justifyContent: "space-between",
122
- marginBottom: "12px",
123
- fontSize: "12px",
124
- color: "var(--muted-foreground, #8a8a95)"
125
- },
126
- children: [
127
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: new Date(response.submittedAt).toLocaleString() }),
128
- response.completionTimeMs != null && /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
129
- Math.round(response.completionTimeMs / 1e3),
130
- "s"
131
- ] })
132
- ]
133
- }
134
- ),
135
- fields.slice(0, 4).map((field) => /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { marginBottom: "8px" }, children: [
136
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontSize: "11px", color: "var(--muted-foreground, #8a8a95)", marginBottom: "2px" }, children: field.label }),
137
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontSize: "13px", color: "var(--foreground, #e8e8ea)" }, children: formatValue(field.value) })
602
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-between mb-3 text-xs text-muted-foreground", children: [
603
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: new Date(response.submittedAt).toLocaleString() }),
604
+ response.completionTimeMs != null && /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
605
+ Math.round(response.completionTimeMs / 1e3),
606
+ "s"
607
+ ] })
608
+ ] }),
609
+ fields.slice(0, 4).map((field) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-2", children: [
610
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-[11px] text-muted-foreground mb-0.5", children: field.label }),
611
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-[13px] text-foreground", children: formatCardValue(field.value, field.type) })
138
612
  ] }, field.questionId)),
139
- fields.length > 4 && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { fontSize: "12px", color: "var(--muted-foreground, #8a8a95)", marginTop: "8px" }, children: [
613
+ fields.length > 4 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-xs text-muted-foreground mt-2", children: [
140
614
  "+",
141
615
  fields.length - 4,
142
616
  " more fields"
143
617
  ] }),
144
- response.totalScore != null && /* @__PURE__ */ jsxRuntime.jsxs(
145
- "div",
146
- {
147
- style: {
148
- marginTop: "12px",
149
- paddingTop: "8px",
150
- borderTop: "1px solid var(--border, #1c1c20)",
151
- fontSize: "13px",
152
- fontWeight: 600,
153
- color: "var(--foreground, #e8e8ea)"
154
- },
155
- children: [
156
- "Score: ",
157
- response.totalScore
158
- ]
159
- }
160
- )
618
+ response.totalScore != null && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-3 pt-2 border-t border-border text-[13px] font-semibold text-foreground", children: [
619
+ "Score: ",
620
+ response.totalScore
621
+ ] })
161
622
  ]
162
623
  }
163
624
  );
164
625
  }
165
- function formatValue(value) {
626
+ function formatCardValue(value, type) {
166
627
  if (value == null) return "\u2014";
628
+ if (type) {
629
+ switch (type) {
630
+ case "vitals_entry": {
631
+ if (typeof value !== "object" || value === null) break;
632
+ const v = value;
633
+ const parts = [];
634
+ if (v.systolicBp && v.diastolicBp) parts.push(`BP ${v.systolicBp}/${v.diastolicBp}`);
635
+ if (v.heartRate) parts.push(`HR ${v.heartRate}`);
636
+ if (v.temperature) parts.push(`${v.temperature}\xB0F`);
637
+ if (v.oxygenSaturation) parts.push(`SpO\u2082 ${v.oxygenSaturation}%`);
638
+ return parts.length > 0 ? parts.join(", ") : "\u2014";
639
+ }
640
+ case "medication_list":
641
+ if (Array.isArray(value)) return `${value.length} medication${value.length !== 1 ? "s" : ""}`;
642
+ break;
643
+ case "allergy_list":
644
+ if (Array.isArray(value)) return `${value.length} allerg${value.length !== 1 ? "ies" : "y"}`;
645
+ break;
646
+ case "body_diagram":
647
+ if (Array.isArray(value)) {
648
+ const labels = value.map((id) => BODY_REGION_LABELS[id] ?? id);
649
+ return labels.join(", ");
650
+ }
651
+ break;
652
+ case "pain_scale":
653
+ if (typeof value === "number") return `${value}/10`;
654
+ break;
655
+ case "bmi_calculator": {
656
+ if (typeof value !== "object" || value === null) break;
657
+ const d = value;
658
+ if (d.bmi != null) return `BMI ${d.bmi}`;
659
+ break;
660
+ }
661
+ case "payment": {
662
+ if (typeof value !== "object" || value === null) break;
663
+ const p = value;
664
+ const status = p.status;
665
+ return status ? status.charAt(0).toUpperCase() + status.slice(1) : "\u2014";
666
+ }
667
+ case "insurance_card": {
668
+ if (typeof value !== "object" || value === null) break;
669
+ const ins = value;
670
+ const parts = [ins.carrierId, ins.planName].filter(Boolean);
671
+ return parts.length > 0 ? parts.join(" \u2014 ") : "Card uploaded";
672
+ }
673
+ case "legal_name": {
674
+ if (typeof value !== "object" || value === null) break;
675
+ const n = value;
676
+ return [n.first, n.last].filter(Boolean).join(" ") || "\u2014";
677
+ }
678
+ case "address": {
679
+ if (typeof value !== "object" || value === null) break;
680
+ const a = value;
681
+ return [a.city, a.state].filter(Boolean).join(", ") || "\u2014";
682
+ }
683
+ case "consent":
684
+ return value === true || value === "true" || value === "agreed" ? "Agreed" : "Not agreed";
685
+ case "signature":
686
+ return typeof value === "string" && value.startsWith("data:image") ? "Signed" : "\u2014";
687
+ }
688
+ }
167
689
  if (typeof value === "boolean") return value ? "Yes" : "No";
168
- if (Array.isArray(value)) return value.map(formatValue).join(", ");
690
+ if (Array.isArray(value)) return value.map(String).join(", ");
169
691
  if (typeof value === "object") return JSON.stringify(value);
170
692
  return String(value);
171
693
  }
172
694
  function ResponseDetail({ response, fields, onBack }) {
173
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { fontFamily: "inherit" }, children: [
174
- /* @__PURE__ */ jsxRuntime.jsxs(
175
- "div",
176
- {
177
- style: {
178
- display: "flex",
179
- alignItems: "center",
180
- gap: "12px",
181
- marginBottom: "20px",
182
- paddingBottom: "12px",
183
- borderBottom: "1px solid var(--border, #1c1c20)"
184
- },
185
- children: [
186
- onBack && /* @__PURE__ */ jsxRuntime.jsx(
187
- "button",
188
- {
189
- type: "button",
190
- onClick: onBack,
191
- style: {
192
- padding: "4px 10px",
193
- fontSize: "13px",
194
- color: "var(--secondary-foreground, #e8e8ea)",
195
- backgroundColor: "var(--secondary, #17171a)",
196
- border: "1px solid var(--border, #1c1c20)",
197
- borderRadius: "6px",
198
- cursor: "pointer"
199
- },
200
- children: "Back"
201
- }
202
- ),
203
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
204
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontSize: "14px", fontWeight: 600, color: "var(--foreground, #e8e8ea)" }, children: "Response Detail" }),
205
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { fontSize: "12px", color: "var(--muted-foreground, #8a8a95)" }, children: [
206
- "Submitted ",
207
- new Date(response.submittedAt).toLocaleString(),
208
- response.completionTimeMs != null && ` \u2014 ${Math.round(response.completionTimeMs / 1e3)}s`
209
- ] })
210
- ] })
211
- ]
212
- }
213
- ),
214
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: { display: "flex", flexDirection: "column", gap: "16px" }, children: fields.map((field) => /* @__PURE__ */ jsxRuntime.jsxs(
695
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
696
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3 mb-5 pb-3 border-b border-border", children: [
697
+ onBack && /* @__PURE__ */ jsxRuntime.jsx(fieldcraftReact.Button, { variant: "outline", size: "sm", onClick: onBack, children: "Back" }),
698
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
699
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm font-semibold text-foreground", children: "Response Detail" }),
700
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-xs text-muted-foreground", children: [
701
+ "Submitted ",
702
+ new Date(response.submittedAt).toLocaleString(),
703
+ response.completionTimeMs != null && ` \u2014 ${Math.round(response.completionTimeMs / 1e3)}s`
704
+ ] })
705
+ ] })
706
+ ] }),
707
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col gap-4", children: fields.map((field) => /* @__PURE__ */ jsxRuntime.jsxs(
215
708
  "div",
216
709
  {
217
- style: {
218
- padding: "12px",
219
- backgroundColor: "var(--muted, #111113)",
220
- borderRadius: "6px"
221
- },
710
+ className: "p-3 bg-muted rounded-md",
222
711
  children: [
223
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { fontSize: "12px", color: "var(--muted-foreground, #8a8a95)", marginBottom: "4px" }, children: [
712
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-xs text-muted-foreground mb-1", children: [
224
713
  field.label,
225
- /* @__PURE__ */ jsxRuntime.jsxs("span", { style: { marginLeft: "8px", fontSize: "11px", color: "var(--muted-foreground, #8a8a95)" }, children: [
714
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "ml-2 text-[11px] text-muted-foreground", children: [
226
715
  "(",
227
716
  field.type,
228
717
  ")"
229
718
  ] })
230
719
  ] }),
231
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontSize: "14px", color: "var(--foreground, #e8e8ea)", whiteSpace: "pre-wrap" }, children: formatDetailValue(field.value) })
720
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm text-foreground", children: renderFieldValue(field) })
232
721
  ]
233
722
  },
234
723
  field.questionId
235
724
  )) }),
236
- response.scores && Object.keys(response.scores).length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { marginTop: "20px" }, children: [
237
- /* @__PURE__ */ jsxRuntime.jsx(
238
- "div",
239
- {
240
- style: {
241
- fontSize: "14px",
242
- fontWeight: 600,
243
- color: "var(--foreground, #e8e8ea)",
244
- marginBottom: "12px"
245
- },
246
- children: "Scores"
247
- }
248
- ),
249
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", gap: "12px", flexWrap: "wrap" }, children: [
250
- Object.entries(response.scores).map(([key, value]) => /* @__PURE__ */ jsxRuntime.jsxs(
251
- "div",
252
- {
253
- style: {
254
- padding: "8px 16px",
255
- backgroundColor: "var(--accent, #17171a)",
256
- borderRadius: "6px",
257
- fontSize: "13px"
258
- },
259
- children: [
260
- /* @__PURE__ */ jsxRuntime.jsxs("span", { style: { color: "var(--muted-foreground, #8a8a95)" }, children: [
261
- key,
262
- ": "
263
- ] }),
264
- /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontWeight: 600, color: "var(--primary, oklch(0.82 0.14 210))" }, children: value })
265
- ]
266
- },
267
- key
268
- )),
269
- response.totalScore != null && /* @__PURE__ */ jsxRuntime.jsxs(
270
- "div",
271
- {
272
- style: {
273
- padding: "8px 16px",
274
- backgroundColor: "var(--accent, #17171a)",
275
- borderRadius: "6px",
276
- fontSize: "13px"
725
+ response.scores && Object.keys(response.scores).length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-5", children: [
726
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm font-semibold text-foreground mb-3", children: "Scores" }),
727
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-3 flex-wrap", children: [
728
+ Object.entries(response.scores).map(([key, value]) => {
729
+ const displayName = INSTRUMENT_DISPLAY_NAMES[key] ?? key;
730
+ const severity = typeof value === "number" ? getScoreSeverity(key, value) : void 0;
731
+ return /* @__PURE__ */ jsxRuntime.jsxs(
732
+ "div",
733
+ {
734
+ className: "px-4 py-2 bg-accent rounded-md text-[13px] flex items-center gap-2",
735
+ children: [
736
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-muted-foreground", children: [
737
+ displayName,
738
+ ": "
739
+ ] }),
740
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-semibold text-primary", children: value }),
741
+ severity && /* @__PURE__ */ jsxRuntime.jsx(
742
+ "span",
743
+ {
744
+ className: "text-[11px] font-semibold px-2 py-0.5 rounded-full text-white",
745
+ style: { backgroundColor: severity.color },
746
+ children: severity.label
747
+ }
748
+ )
749
+ ]
277
750
  },
278
- children: [
279
- /* @__PURE__ */ jsxRuntime.jsx("span", { style: { color: "var(--muted-foreground, #8a8a95)" }, children: "Total: " }),
280
- /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontWeight: 600, color: "var(--primary, oklch(0.82 0.14 210))" }, children: response.totalScore })
281
- ]
282
- }
283
- )
751
+ key
752
+ );
753
+ }),
754
+ response.totalScore != null && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-4 py-2 bg-accent rounded-md text-[13px]", children: [
755
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: "Total: " }),
756
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-semibold text-primary", children: response.totalScore })
757
+ ] })
284
758
  ] })
285
759
  ] }),
286
- /* @__PURE__ */ jsxRuntime.jsxs(
760
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-5 pt-3 border-t border-border text-xs text-muted-foreground", children: [
761
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
762
+ "Schema: ",
763
+ response.schemaId,
764
+ " (v",
765
+ response.schemaVersion,
766
+ ")"
767
+ ] }),
768
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
769
+ "Session: ",
770
+ response.sessionToken
771
+ ] })
772
+ ] })
773
+ ] });
774
+ }
775
+ function renderFieldValue(field) {
776
+ const { type, value } = field;
777
+ if (value == null) return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: "\u2014" });
778
+ switch (type) {
779
+ case "vitals_entry":
780
+ return renderVitals(value);
781
+ case "medication_list":
782
+ return renderMedications(value);
783
+ case "allergy_list":
784
+ return renderAllergies(value);
785
+ case "bmi_calculator":
786
+ return renderBmi(value);
787
+ case "body_diagram":
788
+ return renderBodyDiagram(value);
789
+ case "pain_scale":
790
+ return renderPainScale(value);
791
+ case "insurance_card":
792
+ return renderInsurance(value);
793
+ case "payment":
794
+ return renderPayment(value);
795
+ case "legal_name":
796
+ return renderLegalName(value);
797
+ case "address":
798
+ return renderAddress(value);
799
+ case "consent":
800
+ return renderConsent(value);
801
+ case "signature":
802
+ return renderSignature(value);
803
+ default:
804
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "whitespace-pre-wrap", children: formatFallbackValue(value) });
805
+ }
806
+ }
807
+ var VITALS_LABELS = {
808
+ systolicBp: { label: "Systolic BP", unit: "mmHg", normalRange: "90-140" },
809
+ diastolicBp: { label: "Diastolic BP", unit: "mmHg", normalRange: "60-90" },
810
+ heartRate: { label: "Heart Rate", unit: "bpm", normalRange: "60-100" },
811
+ temperature: { label: "Temperature", unit: "\xB0F", normalRange: "97.0-99.5" },
812
+ respiratoryRate: { label: "Respiratory Rate", unit: "/min", normalRange: "12-20" },
813
+ oxygenSaturation: { label: "SpO\u2082", unit: "%", normalRange: "95-100" }
814
+ };
815
+ function renderVitals(value) {
816
+ if (typeof value !== "object" || value === null) return formatFallbackValue(value);
817
+ const vitals = value;
818
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-2 gap-2", children: Object.entries(VITALS_LABELS).map(([key, meta]) => {
819
+ const val = vitals[key];
820
+ if (val == null || val === 0) return null;
821
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-[13px]", children: [
822
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-muted-foreground", children: [
823
+ meta.label,
824
+ ": "
825
+ ] }),
826
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-medium", children: [
827
+ String(val),
828
+ " ",
829
+ meta.unit
830
+ ] }),
831
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-[11px] text-muted-foreground ml-1", children: [
832
+ "(",
833
+ meta.normalRange,
834
+ ")"
835
+ ] })
836
+ ] }, key);
837
+ }) });
838
+ }
839
+ function renderMedications(value) {
840
+ if (!Array.isArray(value) || value.length === 0) return "No medications";
841
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col gap-2", children: value.map((med, idx) => {
842
+ const m = med;
843
+ const parts = [m.dosage, m.frequency, m.route].filter(Boolean);
844
+ return /* @__PURE__ */ jsxRuntime.jsxs(
287
845
  "div",
288
846
  {
289
- style: {
290
- marginTop: "20px",
291
- paddingTop: "12px",
292
- borderTop: "1px solid var(--border, #1c1c20)",
293
- fontSize: "12px",
294
- color: "var(--muted-foreground, #8a8a95)"
295
- },
847
+ className: "px-3 py-2 border border-border rounded-md text-[13px]",
848
+ children: [
849
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-semibold", children: m.name || "Unnamed" }),
850
+ parts.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-muted-foreground", children: [
851
+ " \u2014 ",
852
+ parts.join(" \xB7 ")
853
+ ] }),
854
+ m.notes && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs text-muted-foreground mt-0.5", children: m.notes })
855
+ ]
856
+ },
857
+ idx
858
+ );
859
+ }) });
860
+ }
861
+ function renderAllergies(value) {
862
+ if (!Array.isArray(value) || value.length === 0) return "No allergies";
863
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col gap-2", children: value.map((allergy, idx) => {
864
+ const a = allergy;
865
+ const sevColor = SEVERITY_COLORS[a.severity];
866
+ return /* @__PURE__ */ jsxRuntime.jsxs(
867
+ "div",
868
+ {
869
+ className: "px-3 py-2 border border-border rounded-md text-[13px] flex items-center gap-2 flex-wrap",
296
870
  children: [
297
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
298
- "Schema: ",
299
- response.schemaId,
300
- " (v",
301
- response.schemaVersion,
871
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-semibold", children: a.allergen || "Unknown" }),
872
+ a.type && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-[11px] text-muted-foreground", children: [
873
+ "(",
874
+ a.type,
302
875
  ")"
303
876
  ] }),
304
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
305
- "Session: ",
306
- response.sessionToken
877
+ a.severity && /* @__PURE__ */ jsxRuntime.jsx(
878
+ "span",
879
+ {
880
+ className: "text-[11px] font-semibold px-2 py-0.5 rounded-full",
881
+ style: {
882
+ backgroundColor: sevColor ?? "var(--accent)",
883
+ color: sevColor ? "#fff" : "var(--foreground)"
884
+ },
885
+ children: a.severity
886
+ }
887
+ ),
888
+ a.reaction && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs text-muted-foreground", children: [
889
+ "\u2014 ",
890
+ a.reaction
307
891
  ] })
308
892
  ]
893
+ },
894
+ idx
895
+ );
896
+ }) });
897
+ }
898
+ function renderBmi(value) {
899
+ if (typeof value !== "object" || value === null) return formatFallbackValue(value);
900
+ const data = value;
901
+ const bmi = data.bmi;
902
+ const unit = data.unit ?? "imperial";
903
+ const height = data.height;
904
+ const weight = data.weight;
905
+ const heightUnit = unit === "metric" ? "cm" : "in";
906
+ const weightUnit = unit === "metric" ? "kg" : "lbs";
907
+ const category = bmi != null ? getBmiCategory(bmi) : void 0;
908
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-[13px] flex items-center gap-2 flex-wrap", children: [
909
+ height != null && /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
910
+ "Height: ",
911
+ height,
912
+ " ",
913
+ heightUnit
914
+ ] }),
915
+ height != null && weight != null && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: "|" }),
916
+ weight != null && /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
917
+ "Weight: ",
918
+ weight,
919
+ " ",
920
+ weightUnit
921
+ ] }),
922
+ bmi != null && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
923
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: "\u2014" }),
924
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-semibold", children: [
925
+ "BMI: ",
926
+ bmi
927
+ ] }),
928
+ category && /* @__PURE__ */ jsxRuntime.jsx(
929
+ "span",
930
+ {
931
+ className: "text-[11px] font-semibold px-2 py-0.5 rounded-full text-white",
932
+ style: { backgroundColor: category.color },
933
+ children: category.label
934
+ }
935
+ )
936
+ ] })
937
+ ] });
938
+ }
939
+ function renderBodyDiagram(value) {
940
+ if (!Array.isArray(value) || value.length === 0) return "No regions selected";
941
+ const labels = value.map((id) => BODY_REGION_LABELS[id] ?? id);
942
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { children: labels.join(", ") });
943
+ }
944
+ function renderPainScale(value) {
945
+ if (typeof value !== "number") return formatFallbackValue(value);
946
+ const face = getPainLabel(value);
947
+ return /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-semibold", style: { color: face?.color }, children: [
948
+ value,
949
+ "/10",
950
+ face ? ` \u2014 ${face.label}` : ""
951
+ ] });
952
+ }
953
+ function renderInsurance(value) {
954
+ if (typeof value !== "object" || value === null) return formatFallbackValue(value);
955
+ const ins = value;
956
+ const textFields = [
957
+ { key: "carrierId", label: "Carrier" },
958
+ { key: "planName", label: "Plan" },
959
+ { key: "memberId", label: "Member ID" },
960
+ { key: "groupNumber", label: "Group #" },
961
+ { key: "subscriberName", label: "Subscriber" },
962
+ { key: "relationship", label: "Relationship" }
963
+ ];
964
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-2", children: [
965
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-2 gap-x-3 gap-y-1 text-[13px]", children: textFields.map(({ key, label }) => {
966
+ const val = ins[key];
967
+ if (!val) return null;
968
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
969
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-muted-foreground", children: [
970
+ label,
971
+ ": "
972
+ ] }),
973
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: String(val) })
974
+ ] }, key);
975
+ }) }),
976
+ !!(ins.frontImage || ins.backImage) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-2 mt-1", children: [
977
+ typeof ins.frontImage === "string" && /* @__PURE__ */ jsxRuntime.jsx(
978
+ "img",
979
+ {
980
+ src: ins.frontImage,
981
+ alt: "Front of card",
982
+ className: "h-12 rounded border border-border"
983
+ }
984
+ ),
985
+ typeof ins.backImage === "string" && /* @__PURE__ */ jsxRuntime.jsx(
986
+ "img",
987
+ {
988
+ src: ins.backImage,
989
+ alt: "Back of card",
990
+ className: "h-12 rounded border border-border"
991
+ }
992
+ )
993
+ ] })
994
+ ] });
995
+ }
996
+ function renderPayment(value) {
997
+ if (typeof value !== "object" || value === null) return formatFallbackValue(value);
998
+ const payment = value;
999
+ const status = payment.status;
1000
+ const statusConfig = {
1001
+ succeeded: { bg: "#22c55e", label: "Succeeded" },
1002
+ failed: { bg: "#ef4444", label: "Failed" },
1003
+ processing: { bg: "#eab308", label: "Processing" }
1004
+ };
1005
+ const cfg = statusConfig[status];
1006
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 text-[13px]", children: [
1007
+ /* @__PURE__ */ jsxRuntime.jsx(
1008
+ "span",
1009
+ {
1010
+ className: "text-[11px] font-semibold px-2.5 py-0.5 rounded-full text-white",
1011
+ style: { backgroundColor: cfg?.bg ?? "var(--accent)" },
1012
+ children: cfg?.label ?? status
309
1013
  }
310
- )
1014
+ ),
1015
+ !!payment.chargeId && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-muted-foreground", children: String(payment.chargeId) }),
1016
+ !!payment.error && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-destructive", children: String(payment.error) })
311
1017
  ] });
312
1018
  }
313
- function formatDetailValue(value) {
1019
+ function renderLegalName(value) {
1020
+ if (typeof value !== "object" || value === null) return formatFallbackValue(value);
1021
+ const name = value;
1022
+ const parts = [name.first, name.middle, name.last].filter(Boolean);
1023
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: parts.join(" ") || "\u2014" });
1024
+ }
1025
+ function renderAddress(value) {
1026
+ if (typeof value !== "object" || value === null) return formatFallbackValue(value);
1027
+ const addr = value;
1028
+ const line1 = [addr.street, addr.street2].filter(Boolean).join(", ");
1029
+ const line2 = [addr.city, addr.state, addr.zip].filter(Boolean).join(", ");
1030
+ const full = [line1, line2].filter(Boolean).join(", ");
1031
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { children: full || "\u2014" });
1032
+ }
1033
+ function renderConsent(value) {
1034
+ const agreed = value === true || value === "true" || value === "agreed";
1035
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { className: agreed ? "font-semibold text-green-500" : "font-semibold text-muted-foreground", children: agreed ? "Agreed" : "Not agreed" });
1036
+ }
1037
+ function renderSignature(value) {
1038
+ if (typeof value !== "string") return formatFallbackValue(value);
1039
+ if (value.startsWith("data:image")) {
1040
+ return /* @__PURE__ */ jsxRuntime.jsx(
1041
+ "img",
1042
+ {
1043
+ src: value,
1044
+ alt: "Signature",
1045
+ className: "h-15 border border-border rounded"
1046
+ }
1047
+ );
1048
+ }
1049
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { children: value });
1050
+ }
1051
+ function formatFallbackValue(value) {
314
1052
  if (value == null) return "\u2014";
315
1053
  if (typeof value === "boolean") return value ? "Yes" : "No";
316
- if (Array.isArray(value)) return value.map(formatDetailValue).join("\n");
1054
+ if (Array.isArray(value)) return value.map(formatFallbackValue).join(", ");
317
1055
  if (typeof value === "object") return JSON.stringify(value, null, 2);
318
1056
  return String(value);
319
1057
  }
320
- var viewButtonStyle = (active) => ({
321
- padding: "4px 10px",
322
- fontSize: "12px",
323
- fontWeight: active ? 600 : 400,
324
- color: active ? "var(--primary, oklch(0.82 0.14 210))" : "var(--muted-foreground, #8a8a95)",
325
- backgroundColor: active ? "var(--accent, #17171a)" : "transparent",
326
- border: "1px solid",
327
- borderColor: active ? "var(--ring, oklch(0.82 0.14 210))" : "var(--border, #1c1c20)",
328
- borderRadius: "6px",
329
- cursor: "pointer",
330
- fontFamily: "inherit"
331
- });
1058
+
1059
+ // src/response-viewer/export-utils.ts
1060
+ function exportToCsv(schema, responses, filename = "responses.csv") {
1061
+ const questions = getExportableQuestions(schema);
1062
+ const headers = ["Submitted", ...questions.map((q) => q.label), "Score"];
1063
+ const rows = responses.map((r) => {
1064
+ const submitted = new Date(r.submittedAt).toLocaleString();
1065
+ const values = questions.map((q) => formatExportValue(r.values[q.id], q.type));
1066
+ const score = r.totalScore != null ? String(r.totalScore) : "";
1067
+ return [submitted, ...values, score];
1068
+ });
1069
+ const csvContent = [headers, ...rows].map((row) => row.map(escapeCsvField).join(",")).join("\n");
1070
+ downloadBlob(csvContent, filename, "text/csv;charset=utf-8;");
1071
+ }
1072
+ function exportToJson(responses, filename = "responses.json") {
1073
+ const content = JSON.stringify(responses, null, 2);
1074
+ downloadBlob(content, filename, "application/json;charset=utf-8;");
1075
+ }
1076
+ function getExportableQuestions(schema) {
1077
+ const questions = [];
1078
+ for (const section of schema.sections) {
1079
+ for (const q of section.questions) {
1080
+ if (q.type === "info-block" || q.type === "section-header" || q.type === "page-break") {
1081
+ continue;
1082
+ }
1083
+ questions.push(q);
1084
+ }
1085
+ }
1086
+ return questions;
1087
+ }
1088
+ function formatExportValue(value, type) {
1089
+ if (value == null) return "";
1090
+ switch (type) {
1091
+ case "vitals_entry": {
1092
+ if (typeof value !== "object" || value === null) break;
1093
+ const v = value;
1094
+ const parts = [];
1095
+ if (v.systolicBp && v.diastolicBp) parts.push(`BP ${v.systolicBp}/${v.diastolicBp}`);
1096
+ if (v.heartRate) parts.push(`HR ${v.heartRate}`);
1097
+ if (v.temperature) parts.push(`${v.temperature}\xB0F`);
1098
+ if (v.oxygenSaturation) parts.push(`SpO2 ${v.oxygenSaturation}%`);
1099
+ return parts.join("; ");
1100
+ }
1101
+ case "medication_list":
1102
+ if (Array.isArray(value)) {
1103
+ return value.map((m) => [m.name, m.dosage, m.frequency].filter(Boolean).join(" ")).join("; ");
1104
+ }
1105
+ break;
1106
+ case "allergy_list":
1107
+ if (Array.isArray(value)) {
1108
+ return value.map((a) => [a.allergen, a.severity].filter(Boolean).join(" - ")).join("; ");
1109
+ }
1110
+ break;
1111
+ case "body_diagram":
1112
+ if (Array.isArray(value)) {
1113
+ return value.map((id) => BODY_REGION_LABELS[id] ?? id).join("; ");
1114
+ }
1115
+ break;
1116
+ case "pain_scale":
1117
+ return typeof value === "number" ? `${value}/10` : String(value);
1118
+ case "bmi_calculator": {
1119
+ if (typeof value !== "object" || value === null) break;
1120
+ const d = value;
1121
+ return d.bmi != null ? `BMI ${d.bmi}` : "";
1122
+ }
1123
+ case "payment": {
1124
+ if (typeof value !== "object" || value === null) break;
1125
+ return value.status ?? "";
1126
+ }
1127
+ case "legal_name": {
1128
+ if (typeof value !== "object" || value === null) break;
1129
+ const n = value;
1130
+ return [n.first, n.middle, n.last].filter(Boolean).join(" ");
1131
+ }
1132
+ case "address": {
1133
+ if (typeof value !== "object" || value === null) break;
1134
+ const a = value;
1135
+ return [a.street, a.city, a.state, a.zip].filter(Boolean).join(", ");
1136
+ }
1137
+ case "consent":
1138
+ return value === true || value === "true" || value === "agreed" ? "Agreed" : "Not agreed";
1139
+ case "signature":
1140
+ return typeof value === "string" && value.startsWith("data:image") ? "Signed" : "";
1141
+ }
1142
+ if (typeof value === "boolean") return value ? "Yes" : "No";
1143
+ if (Array.isArray(value)) return value.join("; ");
1144
+ if (typeof value === "object") return JSON.stringify(value);
1145
+ return String(value);
1146
+ }
1147
+ function escapeCsvField(field) {
1148
+ if (field.includes(",") || field.includes('"') || field.includes("\n")) {
1149
+ return `"${field.replace(/"/g, '""')}"`;
1150
+ }
1151
+ return field;
1152
+ }
1153
+ function downloadBlob(content, filename, mimeType) {
1154
+ const blob = new Blob([content], { type: mimeType });
1155
+ const url = URL.createObjectURL(blob);
1156
+ const link = document.createElement("a");
1157
+ link.href = url;
1158
+ link.download = filename;
1159
+ document.body.appendChild(link);
1160
+ link.click();
1161
+ document.body.removeChild(link);
1162
+ URL.revokeObjectURL(url);
1163
+ }
1164
+ function cn(...inputs) {
1165
+ return tailwindMerge.twMerge(clsx.clsx(inputs));
1166
+ }
332
1167
  function ResponseViewerInner({
333
1168
  schema,
334
1169
  responses,
@@ -354,62 +1189,73 @@ function ResponseViewerInner({
354
1189
  value: response.values[q.id]
355
1190
  }));
356
1191
  }
1192
+ const heightValue = typeof height === "number" ? `${height}px` : height;
1193
+ const widthValue = typeof width === "number" ? `${width}px` : width;
357
1194
  return /* @__PURE__ */ jsxRuntime.jsxs(
358
1195
  "div",
359
1196
  {
360
- style: {
361
- display: "flex",
362
- flexDirection: "column",
363
- height: typeof height === "number" ? `${height}px` : height,
364
- width: typeof width === "number" ? `${width}px` : width,
365
- border: "1px solid var(--border, #1c1c20)",
366
- borderRadius: "8px",
367
- overflow: "hidden",
368
- fontFamily: "inherit",
369
- backgroundColor: "var(--background, #0a0a0b)",
370
- color: "var(--foreground, #e8e8ea)"
371
- },
1197
+ className: "flex flex-col border border-border rounded-lg overflow-hidden bg-background text-foreground",
1198
+ style: { height: heightValue, width: widthValue },
372
1199
  children: [
373
- !selectedResponse && /* @__PURE__ */ jsxRuntime.jsxs(
374
- "div",
375
- {
376
- style: {
377
- display: "flex",
378
- justifyContent: "space-between",
379
- alignItems: "center",
380
- padding: "8px 12px",
381
- borderBottom: "1px solid var(--border, #1c1c20)"
382
- },
383
- children: [
384
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { fontSize: "13px", color: "var(--muted-foreground, #8a8a95)" }, children: [
385
- responses.length,
386
- " response",
387
- responses.length !== 1 ? "s" : ""
388
- ] }),
389
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", gap: "4px" }, children: [
390
- /* @__PURE__ */ jsxRuntime.jsx(
391
- "button",
392
- {
393
- type: "button",
394
- style: viewButtonStyle(viewMode === "table"),
395
- onClick: () => setViewMode("table"),
396
- children: "Table"
397
- }
1200
+ !selectedResponse && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-between items-center px-3 py-2 border-b border-border", children: [
1201
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-xs text-muted-foreground", children: [
1202
+ responses.length,
1203
+ " response",
1204
+ responses.length !== 1 ? "s" : ""
1205
+ ] }),
1206
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1", children: [
1207
+ /* @__PURE__ */ jsxRuntime.jsx(
1208
+ fieldcraftReact.Button,
1209
+ {
1210
+ variant: viewMode === "table" ? "secondary" : "ghost",
1211
+ size: "sm",
1212
+ className: cn(
1213
+ "h-7 text-xs",
1214
+ viewMode === "table" && "font-semibold border border-ring"
398
1215
  ),
399
- /* @__PURE__ */ jsxRuntime.jsx(
400
- "button",
401
- {
402
- type: "button",
403
- style: viewButtonStyle(viewMode === "card"),
404
- onClick: () => setViewMode("card"),
405
- children: "Cards"
406
- }
407
- )
408
- ] })
409
- ]
410
- }
411
- ),
412
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: { flex: 1, overflow: "auto", padding: selectedResponse ? "16px" : void 0 }, children: selectedResponse ? /* @__PURE__ */ jsxRuntime.jsx(
1216
+ onClick: () => setViewMode("table"),
1217
+ children: "Table"
1218
+ }
1219
+ ),
1220
+ /* @__PURE__ */ jsxRuntime.jsx(
1221
+ fieldcraftReact.Button,
1222
+ {
1223
+ variant: viewMode === "card" ? "secondary" : "ghost",
1224
+ size: "sm",
1225
+ className: cn(
1226
+ "h-7 text-xs",
1227
+ viewMode === "card" && "font-semibold border border-ring"
1228
+ ),
1229
+ onClick: () => setViewMode("card"),
1230
+ children: "Cards"
1231
+ }
1232
+ ),
1233
+ /* @__PURE__ */ jsxRuntime.jsx(fieldcraftReact.Separator, { orientation: "vertical", className: "h-5 mx-1" }),
1234
+ /* @__PURE__ */ jsxRuntime.jsx(
1235
+ fieldcraftReact.Button,
1236
+ {
1237
+ variant: "outline",
1238
+ size: "sm",
1239
+ className: "h-7 text-xs",
1240
+ onClick: () => exportToCsv(schema, responses),
1241
+ disabled: responses.length === 0,
1242
+ children: "Export CSV"
1243
+ }
1244
+ ),
1245
+ /* @__PURE__ */ jsxRuntime.jsx(
1246
+ fieldcraftReact.Button,
1247
+ {
1248
+ variant: "outline",
1249
+ size: "sm",
1250
+ className: "h-7 text-xs",
1251
+ onClick: () => exportToJson(responses),
1252
+ disabled: responses.length === 0,
1253
+ children: "Export JSON"
1254
+ }
1255
+ )
1256
+ ] })
1257
+ ] }),
1258
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("flex-1 overflow-auto", selectedResponse && "p-4"), children: selectedResponse ? /* @__PURE__ */ jsxRuntime.jsx(
413
1259
  ResponseDetail,
414
1260
  {
415
1261
  response: selectedResponse,
@@ -423,29 +1269,18 @@ function ResponseViewerInner({
423
1269
  responses,
424
1270
  onRowClick: handleSelect
425
1271
  }
426
- ) : /* @__PURE__ */ jsxRuntime.jsxs(
427
- "div",
428
- {
429
- style: {
430
- display: "grid",
431
- gridTemplateColumns: "repeat(auto-fill, minmax(280px, 1fr))",
432
- gap: "12px",
433
- padding: "12px"
1272
+ ) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid gap-3 p-3 grid-cols-[repeat(auto-fill,minmax(280px,1fr))]", children: [
1273
+ responses.map((response, idx) => /* @__PURE__ */ jsxRuntime.jsx(
1274
+ ResponseCard,
1275
+ {
1276
+ response,
1277
+ fields: getFields(response),
1278
+ onClick: () => handleSelect(response)
434
1279
  },
435
- children: [
436
- responses.map((response, idx) => /* @__PURE__ */ jsxRuntime.jsx(
437
- ResponseCard,
438
- {
439
- response,
440
- fields: getFields(response),
441
- onClick: () => handleSelect(response)
442
- },
443
- response.sessionToken || idx
444
- )),
445
- responses.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { style: { padding: "32px", textAlign: "center", color: "var(--muted-foreground, #8a8a95)" }, children: "No responses yet" })
446
- ]
447
- }
448
- ) })
1280
+ response.sessionToken || idx
1281
+ )),
1282
+ responses.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-8 text-center text-muted-foreground", children: "No responses yet" })
1283
+ ] }) })
449
1284
  ]
450
1285
  }
451
1286
  );
@@ -464,6 +1299,6 @@ function getAllQuestions2(schema) {
464
1299
  }
465
1300
 
466
1301
  // src/response-viewer/ResponseViewer.tsx
467
- var ResponseViewer = fieldcraftProLicense.requireLicense(ResponseViewerInner, "ResponseViewer");
1302
+ var ResponseViewer = requireLicense(ResponseViewerInner, "ResponseViewer");
468
1303
 
469
1304
  exports.ResponseViewer = ResponseViewer;