@squaredr/fieldcraft-pro 0.0.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.
@@ -0,0 +1,467 @@
1
+ import { requireLicense } from '@squaredr/fieldcraft-pro-license';
2
+ import { useState } from 'react';
3
+ import { jsxs, jsx } from 'react/jsx-runtime';
4
+
5
+ // src/response-viewer/ResponseViewer.tsx
6
+ function ResponseTable({ schema, responses, onRowClick }) {
7
+ const questions = getAllQuestions(schema);
8
+ return /* @__PURE__ */ jsx("div", { style: { overflow: "auto", fontFamily: "inherit" }, children: /* @__PURE__ */ jsxs(
9
+ "table",
10
+ {
11
+ style: {
12
+ width: "100%",
13
+ borderCollapse: "collapse",
14
+ fontSize: "13px"
15
+ },
16
+ children: [
17
+ /* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { style: { backgroundColor: "var(--muted, #111113)" }, children: [
18
+ /* @__PURE__ */ jsx("th", { style: thStyle, children: "Submitted" }),
19
+ questions.map((q) => /* @__PURE__ */ jsx("th", { style: thStyle, children: q.label }, q.id)),
20
+ /* @__PURE__ */ jsx("th", { style: thStyle, children: "Score" })
21
+ ] }) }),
22
+ /* @__PURE__ */ jsxs("tbody", { children: [
23
+ responses.map((response, idx) => /* @__PURE__ */ jsxs(
24
+ "tr",
25
+ {
26
+ onClick: () => onRowClick?.(response),
27
+ style: {
28
+ cursor: onRowClick ? "pointer" : "default",
29
+ borderBottom: "1px solid var(--border, #1c1c20)"
30
+ },
31
+ onMouseEnter: (e) => {
32
+ if (onRowClick) e.currentTarget.style.backgroundColor = "var(--accent, #17171a)";
33
+ },
34
+ onMouseLeave: (e) => {
35
+ e.currentTarget.style.backgroundColor = "transparent";
36
+ },
37
+ children: [
38
+ /* @__PURE__ */ jsx("td", { style: tdStyle, children: new Date(response.submittedAt).toLocaleString() }),
39
+ questions.map((q) => /* @__PURE__ */ jsx("td", { style: tdStyle, children: formatCellValue(response.values[q.id]) }, q.id)),
40
+ /* @__PURE__ */ jsx("td", { style: tdStyle, children: response.totalScore ?? "\u2014" })
41
+ ]
42
+ },
43
+ response.sessionToken || idx
44
+ )),
45
+ responses.length === 0 && /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsx(
46
+ "td",
47
+ {
48
+ colSpan: questions.length + 2,
49
+ style: { ...tdStyle, textAlign: "center", color: "var(--muted-foreground, #8a8a95)", padding: "32px" },
50
+ children: "No responses yet"
51
+ }
52
+ ) })
53
+ ] })
54
+ ]
55
+ }
56
+ ) });
57
+ }
58
+ var thStyle = {
59
+ padding: "8px 12px",
60
+ textAlign: "left",
61
+ fontWeight: 600,
62
+ color: "var(--foreground, #e8e8ea)",
63
+ borderBottom: "2px solid var(--border, #1c1c20)",
64
+ whiteSpace: "nowrap"
65
+ };
66
+ var tdStyle = {
67
+ padding: "8px 12px",
68
+ color: "var(--foreground, #e8e8ea)",
69
+ maxWidth: "200px",
70
+ overflow: "hidden",
71
+ textOverflow: "ellipsis",
72
+ whiteSpace: "nowrap"
73
+ };
74
+ function getAllQuestions(schema) {
75
+ const questions = [];
76
+ for (const section of schema.sections) {
77
+ for (const q of section.questions) {
78
+ if (q.type === "info-block" || q.type === "section-header" || q.type === "page-break") {
79
+ continue;
80
+ }
81
+ questions.push(q);
82
+ }
83
+ }
84
+ return questions;
85
+ }
86
+ function formatCellValue(value) {
87
+ if (value == null) return "\u2014";
88
+ if (typeof value === "boolean") return value ? "Yes" : "No";
89
+ if (Array.isArray(value)) return value.join(", ");
90
+ if (typeof value === "object") return JSON.stringify(value);
91
+ return String(value);
92
+ }
93
+ function ResponseCard({ response, fields, onClick }) {
94
+ return /* @__PURE__ */ jsxs(
95
+ "div",
96
+ {
97
+ onClick,
98
+ style: {
99
+ border: "1px solid var(--border, #1c1c20)",
100
+ borderRadius: "8px",
101
+ padding: "16px",
102
+ backgroundColor: "var(--card, #111113)",
103
+ cursor: onClick ? "pointer" : "default",
104
+ fontFamily: "inherit",
105
+ transition: "box-shadow 0.15s"
106
+ },
107
+ onMouseEnter: (e) => {
108
+ if (onClick) e.currentTarget.style.boxShadow = "0 2px 8px rgba(0,0,0,0.3)";
109
+ },
110
+ onMouseLeave: (e) => {
111
+ e.currentTarget.style.boxShadow = "none";
112
+ },
113
+ children: [
114
+ /* @__PURE__ */ jsxs(
115
+ "div",
116
+ {
117
+ style: {
118
+ display: "flex",
119
+ justifyContent: "space-between",
120
+ marginBottom: "12px",
121
+ fontSize: "12px",
122
+ color: "var(--muted-foreground, #8a8a95)"
123
+ },
124
+ children: [
125
+ /* @__PURE__ */ jsx("span", { children: new Date(response.submittedAt).toLocaleString() }),
126
+ response.completionTimeMs != null && /* @__PURE__ */ jsxs("span", { children: [
127
+ Math.round(response.completionTimeMs / 1e3),
128
+ "s"
129
+ ] })
130
+ ]
131
+ }
132
+ ),
133
+ fields.slice(0, 4).map((field) => /* @__PURE__ */ jsxs("div", { style: { marginBottom: "8px" }, children: [
134
+ /* @__PURE__ */ jsx("div", { style: { fontSize: "11px", color: "var(--muted-foreground, #8a8a95)", marginBottom: "2px" }, children: field.label }),
135
+ /* @__PURE__ */ jsx("div", { style: { fontSize: "13px", color: "var(--foreground, #e8e8ea)" }, children: formatValue(field.value) })
136
+ ] }, field.questionId)),
137
+ fields.length > 4 && /* @__PURE__ */ jsxs("div", { style: { fontSize: "12px", color: "var(--muted-foreground, #8a8a95)", marginTop: "8px" }, children: [
138
+ "+",
139
+ fields.length - 4,
140
+ " more fields"
141
+ ] }),
142
+ response.totalScore != null && /* @__PURE__ */ jsxs(
143
+ "div",
144
+ {
145
+ style: {
146
+ marginTop: "12px",
147
+ paddingTop: "8px",
148
+ borderTop: "1px solid var(--border, #1c1c20)",
149
+ fontSize: "13px",
150
+ fontWeight: 600,
151
+ color: "var(--foreground, #e8e8ea)"
152
+ },
153
+ children: [
154
+ "Score: ",
155
+ response.totalScore
156
+ ]
157
+ }
158
+ )
159
+ ]
160
+ }
161
+ );
162
+ }
163
+ function formatValue(value) {
164
+ if (value == null) return "\u2014";
165
+ if (typeof value === "boolean") return value ? "Yes" : "No";
166
+ if (Array.isArray(value)) return value.map(formatValue).join(", ");
167
+ if (typeof value === "object") return JSON.stringify(value);
168
+ return String(value);
169
+ }
170
+ function ResponseDetail({ response, fields, onBack }) {
171
+ return /* @__PURE__ */ jsxs("div", { style: { fontFamily: "inherit" }, children: [
172
+ /* @__PURE__ */ jsxs(
173
+ "div",
174
+ {
175
+ style: {
176
+ display: "flex",
177
+ alignItems: "center",
178
+ gap: "12px",
179
+ marginBottom: "20px",
180
+ paddingBottom: "12px",
181
+ borderBottom: "1px solid var(--border, #1c1c20)"
182
+ },
183
+ children: [
184
+ onBack && /* @__PURE__ */ jsx(
185
+ "button",
186
+ {
187
+ type: "button",
188
+ onClick: onBack,
189
+ style: {
190
+ padding: "4px 10px",
191
+ fontSize: "13px",
192
+ color: "var(--secondary-foreground, #e8e8ea)",
193
+ backgroundColor: "var(--secondary, #17171a)",
194
+ border: "1px solid var(--border, #1c1c20)",
195
+ borderRadius: "6px",
196
+ cursor: "pointer"
197
+ },
198
+ children: "Back"
199
+ }
200
+ ),
201
+ /* @__PURE__ */ jsxs("div", { children: [
202
+ /* @__PURE__ */ jsx("div", { style: { fontSize: "14px", fontWeight: 600, color: "var(--foreground, #e8e8ea)" }, children: "Response Detail" }),
203
+ /* @__PURE__ */ jsxs("div", { style: { fontSize: "12px", color: "var(--muted-foreground, #8a8a95)" }, children: [
204
+ "Submitted ",
205
+ new Date(response.submittedAt).toLocaleString(),
206
+ response.completionTimeMs != null && ` \u2014 ${Math.round(response.completionTimeMs / 1e3)}s`
207
+ ] })
208
+ ] })
209
+ ]
210
+ }
211
+ ),
212
+ /* @__PURE__ */ jsx("div", { style: { display: "flex", flexDirection: "column", gap: "16px" }, children: fields.map((field) => /* @__PURE__ */ jsxs(
213
+ "div",
214
+ {
215
+ style: {
216
+ padding: "12px",
217
+ backgroundColor: "var(--muted, #111113)",
218
+ borderRadius: "6px"
219
+ },
220
+ children: [
221
+ /* @__PURE__ */ jsxs("div", { style: { fontSize: "12px", color: "var(--muted-foreground, #8a8a95)", marginBottom: "4px" }, children: [
222
+ field.label,
223
+ /* @__PURE__ */ jsxs("span", { style: { marginLeft: "8px", fontSize: "11px", color: "var(--muted-foreground, #8a8a95)" }, children: [
224
+ "(",
225
+ field.type,
226
+ ")"
227
+ ] })
228
+ ] }),
229
+ /* @__PURE__ */ jsx("div", { style: { fontSize: "14px", color: "var(--foreground, #e8e8ea)", whiteSpace: "pre-wrap" }, children: formatDetailValue(field.value) })
230
+ ]
231
+ },
232
+ field.questionId
233
+ )) }),
234
+ response.scores && Object.keys(response.scores).length > 0 && /* @__PURE__ */ jsxs("div", { style: { marginTop: "20px" }, children: [
235
+ /* @__PURE__ */ jsx(
236
+ "div",
237
+ {
238
+ style: {
239
+ fontSize: "14px",
240
+ fontWeight: 600,
241
+ color: "var(--foreground, #e8e8ea)",
242
+ marginBottom: "12px"
243
+ },
244
+ children: "Scores"
245
+ }
246
+ ),
247
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: "12px", flexWrap: "wrap" }, children: [
248
+ Object.entries(response.scores).map(([key, value]) => /* @__PURE__ */ jsxs(
249
+ "div",
250
+ {
251
+ style: {
252
+ padding: "8px 16px",
253
+ backgroundColor: "var(--accent, #17171a)",
254
+ borderRadius: "6px",
255
+ fontSize: "13px"
256
+ },
257
+ children: [
258
+ /* @__PURE__ */ jsxs("span", { style: { color: "var(--muted-foreground, #8a8a95)" }, children: [
259
+ key,
260
+ ": "
261
+ ] }),
262
+ /* @__PURE__ */ jsx("span", { style: { fontWeight: 600, color: "var(--primary, oklch(0.82 0.14 210))" }, children: value })
263
+ ]
264
+ },
265
+ key
266
+ )),
267
+ response.totalScore != null && /* @__PURE__ */ jsxs(
268
+ "div",
269
+ {
270
+ style: {
271
+ padding: "8px 16px",
272
+ backgroundColor: "var(--accent, #17171a)",
273
+ borderRadius: "6px",
274
+ fontSize: "13px"
275
+ },
276
+ children: [
277
+ /* @__PURE__ */ jsx("span", { style: { color: "var(--muted-foreground, #8a8a95)" }, children: "Total: " }),
278
+ /* @__PURE__ */ jsx("span", { style: { fontWeight: 600, color: "var(--primary, oklch(0.82 0.14 210))" }, children: response.totalScore })
279
+ ]
280
+ }
281
+ )
282
+ ] })
283
+ ] }),
284
+ /* @__PURE__ */ jsxs(
285
+ "div",
286
+ {
287
+ style: {
288
+ marginTop: "20px",
289
+ paddingTop: "12px",
290
+ borderTop: "1px solid var(--border, #1c1c20)",
291
+ fontSize: "12px",
292
+ color: "var(--muted-foreground, #8a8a95)"
293
+ },
294
+ children: [
295
+ /* @__PURE__ */ jsxs("div", { children: [
296
+ "Schema: ",
297
+ response.schemaId,
298
+ " (v",
299
+ response.schemaVersion,
300
+ ")"
301
+ ] }),
302
+ /* @__PURE__ */ jsxs("div", { children: [
303
+ "Session: ",
304
+ response.sessionToken
305
+ ] })
306
+ ]
307
+ }
308
+ )
309
+ ] });
310
+ }
311
+ function formatDetailValue(value) {
312
+ if (value == null) return "\u2014";
313
+ if (typeof value === "boolean") return value ? "Yes" : "No";
314
+ if (Array.isArray(value)) return value.map(formatDetailValue).join("\n");
315
+ if (typeof value === "object") return JSON.stringify(value, null, 2);
316
+ return String(value);
317
+ }
318
+ var viewButtonStyle = (active) => ({
319
+ padding: "4px 10px",
320
+ fontSize: "12px",
321
+ fontWeight: active ? 600 : 400,
322
+ color: active ? "var(--primary, oklch(0.82 0.14 210))" : "var(--muted-foreground, #8a8a95)",
323
+ backgroundColor: active ? "var(--accent, #17171a)" : "transparent",
324
+ border: "1px solid",
325
+ borderColor: active ? "var(--ring, oklch(0.82 0.14 210))" : "var(--border, #1c1c20)",
326
+ borderRadius: "6px",
327
+ cursor: "pointer",
328
+ fontFamily: "inherit"
329
+ });
330
+ function ResponseViewerInner({
331
+ schema,
332
+ responses,
333
+ onResponseSelect,
334
+ height = "500px",
335
+ width = "100%"
336
+ }) {
337
+ const [viewMode, setViewMode] = useState("table");
338
+ const [selectedResponse, setSelectedResponse] = useState(null);
339
+ function handleSelect(response) {
340
+ setSelectedResponse(response);
341
+ onResponseSelect?.(response);
342
+ }
343
+ function handleBack() {
344
+ setSelectedResponse(null);
345
+ }
346
+ const questions = getAllQuestions2(schema);
347
+ function getFields(response) {
348
+ return questions.map((q) => ({
349
+ questionId: q.id,
350
+ label: q.label,
351
+ type: q.type,
352
+ value: response.values[q.id]
353
+ }));
354
+ }
355
+ return /* @__PURE__ */ jsxs(
356
+ "div",
357
+ {
358
+ style: {
359
+ display: "flex",
360
+ flexDirection: "column",
361
+ height: typeof height === "number" ? `${height}px` : height,
362
+ width: typeof width === "number" ? `${width}px` : width,
363
+ border: "1px solid var(--border, #1c1c20)",
364
+ borderRadius: "8px",
365
+ overflow: "hidden",
366
+ fontFamily: "inherit",
367
+ backgroundColor: "var(--background, #0a0a0b)",
368
+ color: "var(--foreground, #e8e8ea)"
369
+ },
370
+ children: [
371
+ !selectedResponse && /* @__PURE__ */ jsxs(
372
+ "div",
373
+ {
374
+ style: {
375
+ display: "flex",
376
+ justifyContent: "space-between",
377
+ alignItems: "center",
378
+ padding: "8px 12px",
379
+ borderBottom: "1px solid var(--border, #1c1c20)"
380
+ },
381
+ children: [
382
+ /* @__PURE__ */ jsxs("div", { style: { fontSize: "13px", color: "var(--muted-foreground, #8a8a95)" }, children: [
383
+ responses.length,
384
+ " response",
385
+ responses.length !== 1 ? "s" : ""
386
+ ] }),
387
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: "4px" }, children: [
388
+ /* @__PURE__ */ jsx(
389
+ "button",
390
+ {
391
+ type: "button",
392
+ style: viewButtonStyle(viewMode === "table"),
393
+ onClick: () => setViewMode("table"),
394
+ children: "Table"
395
+ }
396
+ ),
397
+ /* @__PURE__ */ jsx(
398
+ "button",
399
+ {
400
+ type: "button",
401
+ style: viewButtonStyle(viewMode === "card"),
402
+ onClick: () => setViewMode("card"),
403
+ children: "Cards"
404
+ }
405
+ )
406
+ ] })
407
+ ]
408
+ }
409
+ ),
410
+ /* @__PURE__ */ jsx("div", { style: { flex: 1, overflow: "auto", padding: selectedResponse ? "16px" : void 0 }, children: selectedResponse ? /* @__PURE__ */ jsx(
411
+ ResponseDetail,
412
+ {
413
+ response: selectedResponse,
414
+ fields: getFields(selectedResponse),
415
+ onBack: handleBack
416
+ }
417
+ ) : viewMode === "table" ? /* @__PURE__ */ jsx(
418
+ ResponseTable,
419
+ {
420
+ schema,
421
+ responses,
422
+ onRowClick: handleSelect
423
+ }
424
+ ) : /* @__PURE__ */ jsxs(
425
+ "div",
426
+ {
427
+ style: {
428
+ display: "grid",
429
+ gridTemplateColumns: "repeat(auto-fill, minmax(280px, 1fr))",
430
+ gap: "12px",
431
+ padding: "12px"
432
+ },
433
+ children: [
434
+ responses.map((response, idx) => /* @__PURE__ */ jsx(
435
+ ResponseCard,
436
+ {
437
+ response,
438
+ fields: getFields(response),
439
+ onClick: () => handleSelect(response)
440
+ },
441
+ response.sessionToken || idx
442
+ )),
443
+ responses.length === 0 && /* @__PURE__ */ jsx("div", { style: { padding: "32px", textAlign: "center", color: "var(--muted-foreground, #8a8a95)" }, children: "No responses yet" })
444
+ ]
445
+ }
446
+ ) })
447
+ ]
448
+ }
449
+ );
450
+ }
451
+ function getAllQuestions2(schema) {
452
+ const questions = [];
453
+ for (const section of schema.sections) {
454
+ for (const q of section.questions) {
455
+ if (q.type === "info-block" || q.type === "section-header" || q.type === "page-break") {
456
+ continue;
457
+ }
458
+ questions.push(q);
459
+ }
460
+ }
461
+ return questions;
462
+ }
463
+
464
+ // src/response-viewer/ResponseViewer.tsx
465
+ var ResponseViewer = requireLicense(ResponseViewerInner, "ResponseViewer");
466
+
467
+ export { ResponseViewer };