@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.
- package/LICENSE.txt +48 -10
- package/README.md +37 -6
- package/dist/{chunk-MQGR25NG.mjs → chunk-7LQW5QYT.mjs} +1 -3
- package/dist/{chunk-APHGEYG4.mjs → chunk-CJBC3KWB.mjs} +156 -130
- package/dist/chunk-QQ4JZGTD.mjs +9 -0
- package/dist/chunk-RSU3X25P.mjs +976 -0
- package/dist/chunk-VECQKSWS.mjs +582 -0
- package/dist/form-builder/index.d.mts +2 -2
- package/dist/form-builder/index.d.ts +2 -2
- package/dist/form-builder/index.js +474 -123
- package/dist/form-builder/index.mjs +3 -1
- package/dist/index.d.mts +52 -3
- package/dist/index.d.ts +52 -3
- package/dist/index.js +1571 -474
- package/dist/index.mjs +7 -5
- package/dist/response-viewer/index.d.mts +4 -1
- package/dist/response-viewer/index.d.ts +4 -1
- package/dist/response-viewer/index.js +1155 -320
- package/dist/response-viewer/index.mjs +3 -1
- package/dist/styles.css +1 -1
- package/dist/theme-editor/index.js +324 -4
- package/dist/theme-editor/index.mjs +2 -1
- package/package.json +15 -14
- package/dist/chunk-NIKQEWPG.mjs +0 -467
- /package/{dist/theme-editor-styles.css → theme-editor/styles.css} +0 -0
package/dist/index.js
CHANGED
|
@@ -1,15 +1,591 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var fieldcraftProLicense = require('@squaredr/fieldcraft-pro-license');
|
|
4
3
|
var react = require('react');
|
|
4
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
5
5
|
var core = require('@dnd-kit/core');
|
|
6
6
|
var lucideReact = require('lucide-react');
|
|
7
7
|
var fieldcraftReact = require('@squaredr/fieldcraft-react');
|
|
8
|
+
var fieldcraftCore = require('@squaredr/fieldcraft-core');
|
|
8
9
|
var clsx = require('clsx');
|
|
9
10
|
var tailwindMerge = require('tailwind-merge');
|
|
10
|
-
var jsxRuntime = require('react/jsx-runtime');
|
|
11
11
|
|
|
12
|
-
//
|
|
12
|
+
// ../license/dist/index.mjs
|
|
13
|
+
var LEGACY_TIER_MAP = {
|
|
14
|
+
"01": "starter",
|
|
15
|
+
"02": "pro",
|
|
16
|
+
"03": "business",
|
|
17
|
+
"04": "enterprise"
|
|
18
|
+
};
|
|
19
|
+
var TIER_MAP_NUMERIC = {
|
|
20
|
+
1: "starter",
|
|
21
|
+
2: "pro",
|
|
22
|
+
3: "business",
|
|
23
|
+
4: "enterprise"
|
|
24
|
+
};
|
|
25
|
+
var PRO_FEATURES = [
|
|
26
|
+
"SchemaEditor",
|
|
27
|
+
"ResponseViewer",
|
|
28
|
+
"ThemeEditor",
|
|
29
|
+
"FormBuilder",
|
|
30
|
+
"ApiManager",
|
|
31
|
+
"Analytics"
|
|
32
|
+
];
|
|
33
|
+
var ALL_FEATURES = [
|
|
34
|
+
...PRO_FEATURES,
|
|
35
|
+
"Telehealth"
|
|
36
|
+
];
|
|
37
|
+
var TIER_FEATURES = {
|
|
38
|
+
starter: ["SchemaEditor", "ResponseViewer"],
|
|
39
|
+
pro: PRO_FEATURES,
|
|
40
|
+
business: ALL_FEATURES,
|
|
41
|
+
enterprise: ALL_FEATURES
|
|
42
|
+
};
|
|
43
|
+
var HMAC_SECRET = "e50a657813a5ab9563050728a605b9ab58b911d5c1a9f48c6825f379a533ccd7685d11d01937d9f135776a0db3efeefe29b3e5282b27ede8cee93758f94f2d75";
|
|
44
|
+
var B32_CHARS = "0123456789ABCDEFGHIJKLMNOPQRSTUV";
|
|
45
|
+
function base32hexDecode(str) {
|
|
46
|
+
const upper = str.toUpperCase();
|
|
47
|
+
let bits = 0;
|
|
48
|
+
let value = 0;
|
|
49
|
+
const bytes = [];
|
|
50
|
+
for (let i = 0; i < upper.length; i++) {
|
|
51
|
+
const idx = B32_CHARS.indexOf(upper[i]);
|
|
52
|
+
if (idx === -1) return null;
|
|
53
|
+
value = value << 5 | idx;
|
|
54
|
+
bits += 5;
|
|
55
|
+
if (bits >= 8) {
|
|
56
|
+
bits -= 8;
|
|
57
|
+
bytes.push(value >>> bits & 255);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return new Uint8Array(bytes);
|
|
61
|
+
}
|
|
62
|
+
function parseLegacyKey(key) {
|
|
63
|
+
const parts = key.split("-");
|
|
64
|
+
if (parts.length !== 5) return null;
|
|
65
|
+
const [p1, p2, tierHex, expiryHex, hash] = parts;
|
|
66
|
+
if (p1 !== "FC" || p2 !== "PRO") return null;
|
|
67
|
+
if (!(tierHex in LEGACY_TIER_MAP)) return null;
|
|
68
|
+
if (!/^[0-9A-Fa-f]{8}$/.test(expiryHex)) return null;
|
|
69
|
+
if (!/^[0-9A-Fa-f]{8}$/.test(hash)) return null;
|
|
70
|
+
return { format: "legacy", tierHex, expiryHex, hash };
|
|
71
|
+
}
|
|
72
|
+
function parseOpaqueKey(key) {
|
|
73
|
+
const stripped = key.replace(/-/g, "");
|
|
74
|
+
if (!stripped.startsWith("FCPRO")) return null;
|
|
75
|
+
const encoded = stripped.slice(5);
|
|
76
|
+
const decoded = base32hexDecode(encoded);
|
|
77
|
+
if (!decoded || decoded.length < 17) return null;
|
|
78
|
+
const tier = decoded[0];
|
|
79
|
+
if (!(tier in TIER_MAP_NUMERIC)) return null;
|
|
80
|
+
const expiryTimestamp = decoded[1] << 24 | decoded[2] << 16 | decoded[3] << 8 | decoded[4];
|
|
81
|
+
const expiryUnsigned = expiryTimestamp >>> 0;
|
|
82
|
+
const nonce = decoded.slice(5, 9);
|
|
83
|
+
const signature = decoded.slice(9, 17);
|
|
84
|
+
return { format: "opaque", tier, expiryTimestamp: expiryUnsigned, nonce, signature };
|
|
85
|
+
}
|
|
86
|
+
function parseKey(key) {
|
|
87
|
+
if (!key || typeof key !== "string") return null;
|
|
88
|
+
if (key.startsWith("FCPRO-")) {
|
|
89
|
+
return parseOpaqueKey(key);
|
|
90
|
+
}
|
|
91
|
+
return parseLegacyKey(key);
|
|
92
|
+
}
|
|
93
|
+
async function computeHmacLegacy(tierHex, expiryHex) {
|
|
94
|
+
const encoder = new TextEncoder();
|
|
95
|
+
const keyData = encoder.encode(HMAC_SECRET);
|
|
96
|
+
const message = encoder.encode(`FC-PRO-${tierHex}-${expiryHex}`);
|
|
97
|
+
const cryptoKey = await crypto.subtle.importKey(
|
|
98
|
+
"raw",
|
|
99
|
+
keyData,
|
|
100
|
+
{ name: "HMAC", hash: "SHA-256" },
|
|
101
|
+
false,
|
|
102
|
+
["sign"]
|
|
103
|
+
);
|
|
104
|
+
const signature = await crypto.subtle.sign("HMAC", cryptoKey, message);
|
|
105
|
+
const hashBytes = new Uint8Array(signature).slice(0, 4);
|
|
106
|
+
return Array.from(hashBytes).map((b) => b.toString(16).padStart(2, "0")).join("").toUpperCase();
|
|
107
|
+
}
|
|
108
|
+
async function computeHmacOpaque(payload) {
|
|
109
|
+
const encoder = new TextEncoder();
|
|
110
|
+
const keyData = encoder.encode(HMAC_SECRET);
|
|
111
|
+
const cryptoKey = await crypto.subtle.importKey(
|
|
112
|
+
"raw",
|
|
113
|
+
keyData,
|
|
114
|
+
{ name: "HMAC", hash: "SHA-256" },
|
|
115
|
+
false,
|
|
116
|
+
["sign"]
|
|
117
|
+
);
|
|
118
|
+
const signature = await crypto.subtle.sign("HMAC", cryptoKey, payload);
|
|
119
|
+
return new Uint8Array(signature).slice(0, 8);
|
|
120
|
+
}
|
|
121
|
+
function isExpiredLegacy(expiryHex) {
|
|
122
|
+
const expiryTimestamp = parseInt(expiryHex, 16);
|
|
123
|
+
if (expiryTimestamp === 4294967295) return false;
|
|
124
|
+
return Date.now() / 1e3 > expiryTimestamp;
|
|
125
|
+
}
|
|
126
|
+
function isExpiredOpaque(expiryTimestamp) {
|
|
127
|
+
if (expiryTimestamp === 4294967295) return false;
|
|
128
|
+
return Date.now() / 1e3 > expiryTimestamp;
|
|
129
|
+
}
|
|
130
|
+
async function validateLicense(key) {
|
|
131
|
+
if (!key || typeof key !== "string") {
|
|
132
|
+
return { status: "invalid", tier: null };
|
|
133
|
+
}
|
|
134
|
+
const parsed = parseKey(key);
|
|
135
|
+
if (!parsed) {
|
|
136
|
+
return { status: "invalid", tier: null };
|
|
137
|
+
}
|
|
138
|
+
if (parsed.format === "opaque") {
|
|
139
|
+
const payload = new Uint8Array(9);
|
|
140
|
+
payload[0] = parsed.tier;
|
|
141
|
+
payload[1] = parsed.expiryTimestamp >>> 24 & 255;
|
|
142
|
+
payload[2] = parsed.expiryTimestamp >>> 16 & 255;
|
|
143
|
+
payload[3] = parsed.expiryTimestamp >>> 8 & 255;
|
|
144
|
+
payload[4] = parsed.expiryTimestamp & 255;
|
|
145
|
+
payload.set(parsed.nonce, 5);
|
|
146
|
+
const expectedSig = await computeHmacOpaque(payload);
|
|
147
|
+
let match = true;
|
|
148
|
+
for (let i = 0; i < 8; i++) {
|
|
149
|
+
if (parsed.signature[i] !== expectedSig[i]) {
|
|
150
|
+
match = false;
|
|
151
|
+
break;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
if (!match) {
|
|
155
|
+
return { status: "invalid", tier: null };
|
|
156
|
+
}
|
|
157
|
+
const tier2 = TIER_MAP_NUMERIC[parsed.tier];
|
|
158
|
+
if (!tier2) {
|
|
159
|
+
return { status: "invalid", tier: null };
|
|
160
|
+
}
|
|
161
|
+
if (isExpiredOpaque(parsed.expiryTimestamp)) {
|
|
162
|
+
return { status: "expired", tier: tier2 };
|
|
163
|
+
}
|
|
164
|
+
return { status: "valid", tier: tier2 };
|
|
165
|
+
}
|
|
166
|
+
const expectedHash = await computeHmacLegacy(parsed.tierHex, parsed.expiryHex);
|
|
167
|
+
if (parsed.hash.toUpperCase() !== expectedHash) {
|
|
168
|
+
return { status: "invalid", tier: null };
|
|
169
|
+
}
|
|
170
|
+
const tier = LEGACY_TIER_MAP[parsed.tierHex];
|
|
171
|
+
if (isExpiredLegacy(parsed.expiryHex)) {
|
|
172
|
+
return { status: "expired", tier };
|
|
173
|
+
}
|
|
174
|
+
return { status: "valid", tier };
|
|
175
|
+
}
|
|
176
|
+
function tierHasFeature(tier, featureName) {
|
|
177
|
+
return TIER_FEATURES[tier]?.includes(featureName) ?? false;
|
|
178
|
+
}
|
|
179
|
+
var DEV_HOSTNAMES = /* @__PURE__ */ new Set([
|
|
180
|
+
"localhost",
|
|
181
|
+
"127.0.0.1",
|
|
182
|
+
"0.0.0.0",
|
|
183
|
+
"[::1]",
|
|
184
|
+
"::1"
|
|
185
|
+
]);
|
|
186
|
+
var DEV_HOSTNAME_PATTERNS = [
|
|
187
|
+
/^192\.168\.\d+\.\d+$/,
|
|
188
|
+
// local network
|
|
189
|
+
/^10\.\d+\.\d+\.\d+$/,
|
|
190
|
+
// local network
|
|
191
|
+
/^172\.(1[6-9]|2\d|3[01])\.\d+\.\d+$/
|
|
192
|
+
// local network
|
|
193
|
+
];
|
|
194
|
+
var PRODUCTION_HOST_SUFFIXES = [
|
|
195
|
+
".vercel.app",
|
|
196
|
+
".netlify.app",
|
|
197
|
+
".netlify.com",
|
|
198
|
+
".herokuapp.com",
|
|
199
|
+
".fly.dev",
|
|
200
|
+
".railway.app",
|
|
201
|
+
".render.com",
|
|
202
|
+
".onrender.com",
|
|
203
|
+
".pages.dev",
|
|
204
|
+
// Cloudflare Pages
|
|
205
|
+
".workers.dev",
|
|
206
|
+
// Cloudflare Workers
|
|
207
|
+
".azurewebsites.net",
|
|
208
|
+
".web.app",
|
|
209
|
+
// Firebase
|
|
210
|
+
".firebaseapp.com",
|
|
211
|
+
".amplifyapp.com",
|
|
212
|
+
".surge.sh",
|
|
213
|
+
".github.io",
|
|
214
|
+
".gitlab.io"
|
|
215
|
+
];
|
|
216
|
+
function isDevHostname(hostname) {
|
|
217
|
+
if (DEV_HOSTNAMES.has(hostname)) return true;
|
|
218
|
+
for (const pattern of DEV_HOSTNAME_PATTERNS) {
|
|
219
|
+
if (pattern.test(hostname)) return true;
|
|
220
|
+
}
|
|
221
|
+
return false;
|
|
222
|
+
}
|
|
223
|
+
function isKnownProductionHost(hostname) {
|
|
224
|
+
for (const suffix of PRODUCTION_HOST_SUFFIXES) {
|
|
225
|
+
if (hostname.endsWith(suffix)) return true;
|
|
226
|
+
}
|
|
227
|
+
return false;
|
|
228
|
+
}
|
|
229
|
+
function hasRealTLD(hostname) {
|
|
230
|
+
return /\.[a-z]{2,}$/i.test(hostname) && !isDevHostname(hostname);
|
|
231
|
+
}
|
|
232
|
+
function isProductionEnvironment() {
|
|
233
|
+
const _proc = typeof globalThis !== "undefined" ? globalThis.process : void 0;
|
|
234
|
+
if (_proc?.env) {
|
|
235
|
+
const nodeEnv = _proc.env.NODE_ENV;
|
|
236
|
+
if (nodeEnv === "production") return true;
|
|
237
|
+
if (nodeEnv === "development" || nodeEnv === "test") return false;
|
|
238
|
+
}
|
|
239
|
+
if (typeof window !== "undefined" && window.location) {
|
|
240
|
+
const { hostname, protocol, port } = window.location;
|
|
241
|
+
if (protocol === "file:") return false;
|
|
242
|
+
if (isDevHostname(hostname)) return false;
|
|
243
|
+
if (port && port !== "443" && port !== "80") return false;
|
|
244
|
+
if (isKnownProductionHost(hostname)) return true;
|
|
245
|
+
if (protocol === "https:" && hasRealTLD(hostname)) return true;
|
|
246
|
+
if (hasRealTLD(hostname)) return true;
|
|
247
|
+
}
|
|
248
|
+
return false;
|
|
249
|
+
}
|
|
250
|
+
var PING_URL = "https://squaredr.tech/api/license/ping";
|
|
251
|
+
var CACHE_KEY = "fcpro_lp";
|
|
252
|
+
var CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
253
|
+
function hashKey(key) {
|
|
254
|
+
let hash = 0;
|
|
255
|
+
for (let i = 0; i < key.length; i++) {
|
|
256
|
+
hash = (hash << 5) - hash + key.charCodeAt(i) | 0;
|
|
257
|
+
}
|
|
258
|
+
return Math.abs(hash).toString(36);
|
|
259
|
+
}
|
|
260
|
+
function cacheId(key) {
|
|
261
|
+
return `${CACHE_KEY}_${hashKey(key)}`;
|
|
262
|
+
}
|
|
263
|
+
function readCache(key) {
|
|
264
|
+
if (typeof window === "undefined" || !window.localStorage) return null;
|
|
265
|
+
try {
|
|
266
|
+
const raw = localStorage.getItem(cacheId(key));
|
|
267
|
+
if (!raw) return null;
|
|
268
|
+
const entry = JSON.parse(raw);
|
|
269
|
+
if (Date.now() - entry.ts > CACHE_TTL_MS) {
|
|
270
|
+
localStorage.removeItem(cacheId(key));
|
|
271
|
+
return null;
|
|
272
|
+
}
|
|
273
|
+
return entry;
|
|
274
|
+
} catch {
|
|
275
|
+
return null;
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
function writeCache(key, status, tier, reason = null) {
|
|
279
|
+
if (typeof window === "undefined" || !window.localStorage) return;
|
|
280
|
+
try {
|
|
281
|
+
const entry = { s: status, t: tier, r: reason, ts: Date.now() };
|
|
282
|
+
localStorage.setItem(cacheId(key), JSON.stringify(entry));
|
|
283
|
+
} catch {
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
function getCachedPingResult(key) {
|
|
287
|
+
const cached = readCache(key);
|
|
288
|
+
if (!cached) return null;
|
|
289
|
+
return { status: cached.s, tier: cached.t, reason: cached.r || void 0 };
|
|
290
|
+
}
|
|
291
|
+
async function performPing(key) {
|
|
292
|
+
const cached = readCache(key);
|
|
293
|
+
if (cached) {
|
|
294
|
+
return { status: cached.s, tier: cached.t };
|
|
295
|
+
}
|
|
296
|
+
try {
|
|
297
|
+
const controller = new AbortController();
|
|
298
|
+
const timeout = setTimeout(() => controller.abort(), 1e4);
|
|
299
|
+
const res = await fetch(PING_URL, {
|
|
300
|
+
method: "POST",
|
|
301
|
+
headers: { "Content-Type": "application/json" },
|
|
302
|
+
body: JSON.stringify({ key }),
|
|
303
|
+
signal: controller.signal
|
|
304
|
+
});
|
|
305
|
+
clearTimeout(timeout);
|
|
306
|
+
if (!res.ok) return null;
|
|
307
|
+
const data = await res.json();
|
|
308
|
+
const tier = data.tier || null;
|
|
309
|
+
if (data.status === "active") {
|
|
310
|
+
writeCache(key, "valid", tier);
|
|
311
|
+
return { status: "valid", tier };
|
|
312
|
+
}
|
|
313
|
+
if (data.status === "revoked") {
|
|
314
|
+
writeCache(key, "revoked", null, data.reason);
|
|
315
|
+
return { status: "revoked", tier: null, reason: data.reason };
|
|
316
|
+
}
|
|
317
|
+
if (data.status === "expired") {
|
|
318
|
+
writeCache(key, "expired", tier);
|
|
319
|
+
return { status: "expired", tier };
|
|
320
|
+
}
|
|
321
|
+
if (data.status === "domain_mismatch") {
|
|
322
|
+
writeCache(key, "domain_mismatch", null, data.reason);
|
|
323
|
+
return { status: "domain_mismatch", tier: null, reason: data.reason };
|
|
324
|
+
}
|
|
325
|
+
return null;
|
|
326
|
+
} catch {
|
|
327
|
+
return null;
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
var defaultContext = { status: "validating", tier: null };
|
|
331
|
+
var LicenseCtx = react.createContext(defaultContext);
|
|
332
|
+
function FieldCraftProProvider({ licenseKey, children }) {
|
|
333
|
+
const [license, setLicense] = react.useState(defaultContext);
|
|
334
|
+
react.useEffect(() => {
|
|
335
|
+
let cancelled = false;
|
|
336
|
+
setLicense(defaultContext);
|
|
337
|
+
validateLicense(licenseKey).then((clientResult) => {
|
|
338
|
+
if (cancelled) return;
|
|
339
|
+
setLicense(clientResult);
|
|
340
|
+
if (clientResult.status !== "valid" || !isProductionEnvironment()) return;
|
|
341
|
+
const cached = getCachedPingResult(licenseKey);
|
|
342
|
+
if (cached) {
|
|
343
|
+
if (cached.status === "revoked" || cached.status === "domain_mismatch") {
|
|
344
|
+
setLicense({ status: cached.status, tier: null });
|
|
345
|
+
}
|
|
346
|
+
return;
|
|
347
|
+
}
|
|
348
|
+
performPing(licenseKey).then((pingResult) => {
|
|
349
|
+
if (cancelled) return;
|
|
350
|
+
if (!pingResult) return;
|
|
351
|
+
if (pingResult.status === "revoked" || pingResult.status === "domain_mismatch") {
|
|
352
|
+
setLicense({ status: pingResult.status, tier: null });
|
|
353
|
+
}
|
|
354
|
+
});
|
|
355
|
+
});
|
|
356
|
+
return () => {
|
|
357
|
+
cancelled = true;
|
|
358
|
+
};
|
|
359
|
+
}, [licenseKey]);
|
|
360
|
+
return /* @__PURE__ */ jsxRuntime.jsx(LicenseCtx.Provider, { value: license, children });
|
|
361
|
+
}
|
|
362
|
+
function useLicense() {
|
|
363
|
+
return react.useContext(LicenseCtx);
|
|
364
|
+
}
|
|
365
|
+
function UnlicensedOverlay({ featureName, reason, children }) {
|
|
366
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { position: "relative", minHeight: "200px" }, children: [
|
|
367
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: { pointerEvents: "none", userSelect: "none", filter: "blur(2px)" }, children }),
|
|
368
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
369
|
+
"div",
|
|
370
|
+
{
|
|
371
|
+
style: {
|
|
372
|
+
position: "absolute",
|
|
373
|
+
inset: 0,
|
|
374
|
+
zIndex: 2147483647,
|
|
375
|
+
display: "flex",
|
|
376
|
+
flexDirection: "column",
|
|
377
|
+
alignItems: "center",
|
|
378
|
+
justifyContent: "center",
|
|
379
|
+
backgroundColor: "rgba(0, 0, 0, 0.75)",
|
|
380
|
+
backdropFilter: "blur(4px)",
|
|
381
|
+
fontFamily: "system-ui, -apple-system, sans-serif",
|
|
382
|
+
padding: "32px"
|
|
383
|
+
},
|
|
384
|
+
children: [
|
|
385
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
386
|
+
"div",
|
|
387
|
+
{
|
|
388
|
+
style: {
|
|
389
|
+
position: "absolute",
|
|
390
|
+
inset: 0,
|
|
391
|
+
overflow: "hidden",
|
|
392
|
+
pointerEvents: "none",
|
|
393
|
+
zIndex: 0
|
|
394
|
+
},
|
|
395
|
+
children: Array.from({ length: 12 }).map((_, i) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
396
|
+
"div",
|
|
397
|
+
{
|
|
398
|
+
style: {
|
|
399
|
+
position: "absolute",
|
|
400
|
+
top: `${i * 80}px`,
|
|
401
|
+
left: "-50%",
|
|
402
|
+
right: "-50%",
|
|
403
|
+
textAlign: "center",
|
|
404
|
+
transform: "rotate(-30deg)",
|
|
405
|
+
fontSize: "18px",
|
|
406
|
+
fontWeight: 700,
|
|
407
|
+
color: "rgba(255, 255, 255, 0.06)",
|
|
408
|
+
letterSpacing: "8px",
|
|
409
|
+
textTransform: "uppercase",
|
|
410
|
+
whiteSpace: "nowrap",
|
|
411
|
+
userSelect: "none"
|
|
412
|
+
},
|
|
413
|
+
children: "UNLICENSED \u2022 FIELDCRAFT PRO \u2022 UNLICENSED \u2022 FIELDCRAFT PRO \u2022 UNLICENSED \u2022 FIELDCRAFT PRO"
|
|
414
|
+
},
|
|
415
|
+
i
|
|
416
|
+
))
|
|
417
|
+
}
|
|
418
|
+
),
|
|
419
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
420
|
+
"div",
|
|
421
|
+
{
|
|
422
|
+
style: {
|
|
423
|
+
position: "relative",
|
|
424
|
+
zIndex: 1,
|
|
425
|
+
textAlign: "center",
|
|
426
|
+
maxWidth: "420px"
|
|
427
|
+
},
|
|
428
|
+
children: [
|
|
429
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
430
|
+
"div",
|
|
431
|
+
{
|
|
432
|
+
style: {
|
|
433
|
+
width: "64px",
|
|
434
|
+
height: "64px",
|
|
435
|
+
margin: "0 auto 16px",
|
|
436
|
+
borderRadius: "50%",
|
|
437
|
+
backgroundColor: "rgba(239, 68, 68, 0.2)",
|
|
438
|
+
border: "2px solid rgba(239, 68, 68, 0.5)",
|
|
439
|
+
display: "flex",
|
|
440
|
+
alignItems: "center",
|
|
441
|
+
justifyContent: "center",
|
|
442
|
+
fontSize: "28px"
|
|
443
|
+
},
|
|
444
|
+
children: "\u{1F6E1}"
|
|
445
|
+
}
|
|
446
|
+
),
|
|
447
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
448
|
+
"div",
|
|
449
|
+
{
|
|
450
|
+
style: {
|
|
451
|
+
fontSize: "22px",
|
|
452
|
+
fontWeight: 700,
|
|
453
|
+
color: "#ffffff",
|
|
454
|
+
marginBottom: "8px",
|
|
455
|
+
letterSpacing: "-0.02em"
|
|
456
|
+
},
|
|
457
|
+
children: "License Required"
|
|
458
|
+
}
|
|
459
|
+
),
|
|
460
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
461
|
+
"div",
|
|
462
|
+
{
|
|
463
|
+
style: {
|
|
464
|
+
fontSize: "15px",
|
|
465
|
+
fontWeight: 600,
|
|
466
|
+
color: "#f87171",
|
|
467
|
+
marginBottom: "6px"
|
|
468
|
+
},
|
|
469
|
+
children: featureName
|
|
470
|
+
}
|
|
471
|
+
),
|
|
472
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
473
|
+
"div",
|
|
474
|
+
{
|
|
475
|
+
style: {
|
|
476
|
+
fontSize: "14px",
|
|
477
|
+
color: "#d1d5db",
|
|
478
|
+
marginBottom: "24px",
|
|
479
|
+
lineHeight: "1.5"
|
|
480
|
+
},
|
|
481
|
+
children: reason
|
|
482
|
+
}
|
|
483
|
+
),
|
|
484
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", gap: "10px", justifyContent: "center", flexWrap: "wrap" }, children: [
|
|
485
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
486
|
+
"a",
|
|
487
|
+
{
|
|
488
|
+
href: "https://squaredr.tech/products/fieldcraft/admin-pro#pricing",
|
|
489
|
+
target: "_blank",
|
|
490
|
+
rel: "noopener noreferrer",
|
|
491
|
+
style: {
|
|
492
|
+
display: "inline-block",
|
|
493
|
+
padding: "12px 24px",
|
|
494
|
+
fontSize: "14px",
|
|
495
|
+
fontWeight: 600,
|
|
496
|
+
color: "#ffffff",
|
|
497
|
+
backgroundColor: "#2563eb",
|
|
498
|
+
borderRadius: "8px",
|
|
499
|
+
textDecoration: "none",
|
|
500
|
+
boxShadow: "0 4px 14px rgba(37, 99, 235, 0.4)"
|
|
501
|
+
},
|
|
502
|
+
children: "Get a License"
|
|
503
|
+
}
|
|
504
|
+
),
|
|
505
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
506
|
+
"a",
|
|
507
|
+
{
|
|
508
|
+
href: "https://discord.gg/zMxdu5UVW",
|
|
509
|
+
target: "_blank",
|
|
510
|
+
rel: "noopener noreferrer",
|
|
511
|
+
style: {
|
|
512
|
+
display: "inline-block",
|
|
513
|
+
padding: "12px 24px",
|
|
514
|
+
fontSize: "14px",
|
|
515
|
+
fontWeight: 600,
|
|
516
|
+
color: "#93c5fd",
|
|
517
|
+
backgroundColor: "rgba(37, 99, 235, 0.15)",
|
|
518
|
+
border: "1px solid rgba(37, 99, 235, 0.4)",
|
|
519
|
+
borderRadius: "8px",
|
|
520
|
+
textDecoration: "none"
|
|
521
|
+
},
|
|
522
|
+
children: "Join Discord"
|
|
523
|
+
}
|
|
524
|
+
)
|
|
525
|
+
] }),
|
|
526
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
527
|
+
"div",
|
|
528
|
+
{
|
|
529
|
+
style: {
|
|
530
|
+
fontSize: "12px",
|
|
531
|
+
color: "#6b7280",
|
|
532
|
+
marginTop: "16px"
|
|
533
|
+
},
|
|
534
|
+
children: [
|
|
535
|
+
"This component works freely in development.",
|
|
536
|
+
" ",
|
|
537
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
538
|
+
"a",
|
|
539
|
+
{
|
|
540
|
+
href: "https://squaredr.tech/products/fieldcraft/docs/pro/license",
|
|
541
|
+
target: "_blank",
|
|
542
|
+
rel: "noopener noreferrer",
|
|
543
|
+
style: { color: "#9ca3af", textDecoration: "underline" },
|
|
544
|
+
children: "Learn more"
|
|
545
|
+
}
|
|
546
|
+
)
|
|
547
|
+
]
|
|
548
|
+
}
|
|
549
|
+
)
|
|
550
|
+
]
|
|
551
|
+
}
|
|
552
|
+
)
|
|
553
|
+
]
|
|
554
|
+
}
|
|
555
|
+
)
|
|
556
|
+
] });
|
|
557
|
+
}
|
|
558
|
+
function requireLicense(Component2, featureName) {
|
|
559
|
+
function LicenseGated(props) {
|
|
560
|
+
const { status, tier } = useLicense();
|
|
561
|
+
const isProduction = isProductionEnvironment();
|
|
562
|
+
if (!isProduction) {
|
|
563
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Component2, { ...props });
|
|
564
|
+
}
|
|
565
|
+
if (status === "validating") {
|
|
566
|
+
return null;
|
|
567
|
+
}
|
|
568
|
+
const isLicensed = status === "valid" && tier != null && tierHasFeature(tier, featureName);
|
|
569
|
+
if (isLicensed) {
|
|
570
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Component2, { ...props });
|
|
571
|
+
}
|
|
572
|
+
let reason = "A valid license is required for production use.";
|
|
573
|
+
if (status === "invalid") {
|
|
574
|
+
reason = "Invalid license key. Please check your license key and try again.";
|
|
575
|
+
} else if (status === "expired") {
|
|
576
|
+
reason = "Your license has expired. Please renew to continue using this component in production.";
|
|
577
|
+
} else if (status === "revoked") {
|
|
578
|
+
reason = "This license key has been revoked. Please contact support or purchase a new license.";
|
|
579
|
+
} else if (status === "domain_mismatch") {
|
|
580
|
+
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.";
|
|
581
|
+
} else if (!tier || !tierHasFeature(tier, featureName)) {
|
|
582
|
+
reason = "Your license does not include this feature. Please upgrade your plan.";
|
|
583
|
+
}
|
|
584
|
+
return /* @__PURE__ */ jsxRuntime.jsx(UnlicensedOverlay, { featureName, reason, children: /* @__PURE__ */ jsxRuntime.jsx(Component2, { ...props }) });
|
|
585
|
+
}
|
|
586
|
+
LicenseGated.displayName = `requireLicense(${Component2.displayName || Component2.name || "Component"})`;
|
|
587
|
+
return LicenseGated;
|
|
588
|
+
}
|
|
13
589
|
var MAX_HISTORY = 50;
|
|
14
590
|
function useUndoRedo(currentSchema, setSchema) {
|
|
15
591
|
const historyRef = react.useRef([currentSchema]);
|
|
@@ -80,6 +656,39 @@ function generateOptionId() {
|
|
|
80
656
|
function deepClone(obj) {
|
|
81
657
|
return structuredClone(obj);
|
|
82
658
|
}
|
|
659
|
+
function cleanCondition(expr, deletedFieldId) {
|
|
660
|
+
if (expr.field === deletedFieldId) return void 0;
|
|
661
|
+
if (expr.field && expr.field !== deletedFieldId) return expr;
|
|
662
|
+
if (expr.conditions) {
|
|
663
|
+
const cleaned = expr.conditions.map((c) => cleanCondition(c, deletedFieldId)).filter((c) => c !== void 0);
|
|
664
|
+
if (cleaned.length === 0) return void 0;
|
|
665
|
+
if (cleaned.length === 1) return cleaned[0];
|
|
666
|
+
return { ...expr, conditions: cleaned };
|
|
667
|
+
}
|
|
668
|
+
return expr;
|
|
669
|
+
}
|
|
670
|
+
function cleanupOrphanConditions(schema, deletedFieldId) {
|
|
671
|
+
for (const section of schema.sections) {
|
|
672
|
+
if (section.showIf) {
|
|
673
|
+
const cleaned = cleanCondition(section.showIf, deletedFieldId);
|
|
674
|
+
if (cleaned) {
|
|
675
|
+
section.showIf = cleaned;
|
|
676
|
+
} else {
|
|
677
|
+
delete section.showIf;
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
for (const question of section.questions) {
|
|
681
|
+
if (question.showIf) {
|
|
682
|
+
const cleaned = cleanCondition(question.showIf, deletedFieldId);
|
|
683
|
+
if (cleaned) {
|
|
684
|
+
question.showIf = cleaned;
|
|
685
|
+
} else {
|
|
686
|
+
delete question.showIf;
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
}
|
|
83
692
|
function addSection(schema, section, index) {
|
|
84
693
|
const newSchema = deepClone(schema);
|
|
85
694
|
newSchema.sections.splice(index, 0, section);
|
|
@@ -87,7 +696,12 @@ function addSection(schema, section, index) {
|
|
|
87
696
|
}
|
|
88
697
|
function removeSection(schema, sectionId) {
|
|
89
698
|
const newSchema = deepClone(schema);
|
|
699
|
+
const removedSection = newSchema.sections.find((s) => s.id === sectionId);
|
|
700
|
+
const removedFieldIds = removedSection ? removedSection.questions.map((q) => q.id) : [];
|
|
90
701
|
newSchema.sections = newSchema.sections.filter((s) => s.id !== sectionId);
|
|
702
|
+
for (const fieldId of removedFieldIds) {
|
|
703
|
+
cleanupOrphanConditions(newSchema, fieldId);
|
|
704
|
+
}
|
|
91
705
|
return newSchema;
|
|
92
706
|
}
|
|
93
707
|
function updateSection(schema, sectionId, updates) {
|
|
@@ -137,6 +751,7 @@ function removeQuestion(schema, sectionId, questionId) {
|
|
|
137
751
|
const section = newSchema.sections.find((s) => s.id === sectionId);
|
|
138
752
|
if (!section) return schema;
|
|
139
753
|
section.questions = section.questions.filter((q) => q.id !== questionId);
|
|
754
|
+
cleanupOrphanConditions(newSchema, questionId);
|
|
140
755
|
return newSchema;
|
|
141
756
|
}
|
|
142
757
|
function updateQuestion(schema, sectionId, questionId, updates) {
|
|
@@ -975,11 +1590,13 @@ function QuestionPalette({ questionTypes, palette }) {
|
|
|
975
1590
|
const isCollapsed = collapsed[category.category] && !search;
|
|
976
1591
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-3", children: [
|
|
977
1592
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
978
|
-
|
|
1593
|
+
fieldcraftReact.Button,
|
|
979
1594
|
{
|
|
980
1595
|
type: "button",
|
|
1596
|
+
variant: "ghost",
|
|
1597
|
+
size: "xs",
|
|
981
1598
|
onClick: () => toggleCategory(category.category),
|
|
982
|
-
className: "
|
|
1599
|
+
className: "w-full justify-start px-1 text-[11px] font-semibold uppercase tracking-widest text-muted-foreground",
|
|
983
1600
|
"aria-expanded": !isCollapsed,
|
|
984
1601
|
children: [
|
|
985
1602
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -1343,11 +1960,12 @@ function FormCanvas({ builderState }) {
|
|
|
1343
1960
|
section.id
|
|
1344
1961
|
)),
|
|
1345
1962
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1346
|
-
|
|
1963
|
+
fieldcraftReact.Button,
|
|
1347
1964
|
{
|
|
1348
1965
|
type: "button",
|
|
1966
|
+
variant: "outline",
|
|
1349
1967
|
onClick: handleAddSection,
|
|
1350
|
-
className: "w-full py-4 text-sm font-medium
|
|
1968
|
+
className: "w-full py-4 h-auto text-sm font-medium border-dashed border-fcb-border-strong text-muted-foreground hover:border-primary hover:text-primary hover:bg-primary/5",
|
|
1351
1969
|
children: [
|
|
1352
1970
|
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Plus, { size: 14, strokeWidth: 2 }),
|
|
1353
1971
|
"Add Section"
|
|
@@ -1357,6 +1975,26 @@ function FormCanvas({ builderState }) {
|
|
|
1357
1975
|
] })
|
|
1358
1976
|
] }) });
|
|
1359
1977
|
}
|
|
1978
|
+
var NativeSelect = react.forwardRef(
|
|
1979
|
+
({ className, wrapperClassName, children, ...props }, ref) => {
|
|
1980
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("relative", wrapperClassName), children: [
|
|
1981
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1982
|
+
"select",
|
|
1983
|
+
{
|
|
1984
|
+
ref,
|
|
1985
|
+
className: cn(
|
|
1986
|
+
"flex h-9 w-full appearance-none rounded-md border border-input bg-card px-3 py-1 pr-8 text-sm shadow-xs transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring text-foreground cursor-pointer",
|
|
1987
|
+
className
|
|
1988
|
+
),
|
|
1989
|
+
...props,
|
|
1990
|
+
children
|
|
1991
|
+
}
|
|
1992
|
+
),
|
|
1993
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { className: "pointer-events-none absolute right-2.5 top-1/2 -translate-y-1/2 size-4 text-muted-foreground" })
|
|
1994
|
+
] });
|
|
1995
|
+
}
|
|
1996
|
+
);
|
|
1997
|
+
NativeSelect.displayName = "NativeSelect";
|
|
1360
1998
|
function useConfigUpdater(question, onUpdate) {
|
|
1361
1999
|
return (field, value) => {
|
|
1362
2000
|
const current = question.config ?? {};
|
|
@@ -1751,18 +2389,7 @@ function SelectField({
|
|
|
1751
2389
|
}) {
|
|
1752
2390
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
1753
2391
|
/* @__PURE__ */ jsxRuntime.jsx(fieldcraftReact.Label, { className: "text-xs text-muted-foreground mb-1", children: label }),
|
|
1754
|
-
/* @__PURE__ */ jsxRuntime.
|
|
1755
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1756
|
-
"select",
|
|
1757
|
-
{
|
|
1758
|
-
value,
|
|
1759
|
-
onChange: (e) => onChange(e.target.value),
|
|
1760
|
-
className: "flex h-9 w-full appearance-none rounded-md border border-input bg-card px-3 py-1 pr-8 text-sm shadow-xs transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring text-foreground cursor-pointer",
|
|
1761
|
-
children: options.map((opt) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: opt.value, children: opt.label }, opt.value))
|
|
1762
|
-
}
|
|
1763
|
-
),
|
|
1764
|
-
/* @__PURE__ */ jsxRuntime.jsx("svg", { className: "pointer-events-none absolute right-2.5 top-1/2 -translate-y-1/2 size-4 text-muted-foreground", xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m6 9 6 6 6-6" }) })
|
|
1765
|
-
] })
|
|
2392
|
+
/* @__PURE__ */ jsxRuntime.jsx(NativeSelect, { value, onChange: (e) => onChange(e.target.value), children: options.map((opt) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: opt.value, children: opt.label }, opt.value)) })
|
|
1766
2393
|
] });
|
|
1767
2394
|
}
|
|
1768
2395
|
function LikertLabelsEditor({
|
|
@@ -1783,15 +2410,7 @@ function LikertLabelsEditor({
|
|
|
1783
2410
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
1784
2411
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between mb-2", children: [
|
|
1785
2412
|
/* @__PURE__ */ jsxRuntime.jsx(fieldcraftReact.Label, { className: "text-xs text-muted-foreground", children: "Scale Labels" }),
|
|
1786
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1787
|
-
"button",
|
|
1788
|
-
{
|
|
1789
|
-
type: "button",
|
|
1790
|
-
onClick: handleAdd,
|
|
1791
|
-
className: "text-xs text-primary hover:underline",
|
|
1792
|
-
children: "+ Add"
|
|
1793
|
-
}
|
|
1794
|
-
)
|
|
2413
|
+
/* @__PURE__ */ jsxRuntime.jsx(fieldcraftReact.Button, { type: "button", variant: "link", size: "xs", onClick: handleAdd, className: "px-0", children: "+ Add" })
|
|
1795
2414
|
] }),
|
|
1796
2415
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-1.5", children: labels.map((label, index) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5 group", children: [
|
|
1797
2416
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] text-muted-foreground w-4 text-right shrink-0", children: index + 1 }),
|
|
@@ -1804,11 +2423,13 @@ function LikertLabelsEditor({
|
|
|
1804
2423
|
}
|
|
1805
2424
|
),
|
|
1806
2425
|
labels.length > 2 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1807
|
-
|
|
2426
|
+
fieldcraftReact.Button,
|
|
1808
2427
|
{
|
|
1809
2428
|
type: "button",
|
|
2429
|
+
variant: "ghost",
|
|
2430
|
+
size: "icon-xs",
|
|
1810
2431
|
onClick: () => handleRemove(index),
|
|
1811
|
-
className: "text-
|
|
2432
|
+
className: "text-destructive opacity-0 group-hover:opacity-100 transition-opacity",
|
|
1812
2433
|
children: "x"
|
|
1813
2434
|
}
|
|
1814
2435
|
)
|
|
@@ -1837,15 +2458,7 @@ function MatrixItemsEditor({
|
|
|
1837
2458
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
1838
2459
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between mb-2", children: [
|
|
1839
2460
|
/* @__PURE__ */ jsxRuntime.jsx(fieldcraftReact.Label, { className: "text-xs text-muted-foreground", children: label }),
|
|
1840
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1841
|
-
"button",
|
|
1842
|
-
{
|
|
1843
|
-
type: "button",
|
|
1844
|
-
onClick: handleAdd,
|
|
1845
|
-
className: "text-xs text-primary hover:underline",
|
|
1846
|
-
children: "+ Add"
|
|
1847
|
-
}
|
|
1848
|
-
)
|
|
2461
|
+
/* @__PURE__ */ jsxRuntime.jsx(fieldcraftReact.Button, { type: "button", variant: "link", size: "xs", onClick: handleAdd, className: "px-0", children: "+ Add" })
|
|
1849
2462
|
] }),
|
|
1850
2463
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-1.5", children: items.map((item, index) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5 group", children: [
|
|
1851
2464
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -1857,11 +2470,13 @@ function MatrixItemsEditor({
|
|
|
1857
2470
|
}
|
|
1858
2471
|
),
|
|
1859
2472
|
items.length > 1 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1860
|
-
|
|
2473
|
+
fieldcraftReact.Button,
|
|
1861
2474
|
{
|
|
1862
2475
|
type: "button",
|
|
2476
|
+
variant: "ghost",
|
|
2477
|
+
size: "icon-xs",
|
|
1863
2478
|
onClick: () => handleRemove(index),
|
|
1864
|
-
className: "text-
|
|
2479
|
+
className: "text-destructive opacity-0 group-hover:opacity-100 transition-opacity",
|
|
1865
2480
|
children: "x"
|
|
1866
2481
|
}
|
|
1867
2482
|
)
|
|
@@ -1894,7 +2509,7 @@ function ScoringOptionsEditor({
|
|
|
1894
2509
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
1895
2510
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between mb-2", children: [
|
|
1896
2511
|
/* @__PURE__ */ jsxRuntime.jsx(fieldcraftReact.Label, { className: "text-xs text-muted-foreground", children: "Score Options" }),
|
|
1897
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2512
|
+
/* @__PURE__ */ jsxRuntime.jsx(fieldcraftReact.Button, { type: "button", variant: "link", size: "xs", onClick: handleAdd, className: "px-0", children: "+ Add" })
|
|
1898
2513
|
] }),
|
|
1899
2514
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-1.5", children: options.map((opt, index) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5 group", children: [
|
|
1900
2515
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -1916,7 +2531,7 @@ function ScoringOptionsEditor({
|
|
|
1916
2531
|
placeholder: "Score"
|
|
1917
2532
|
}
|
|
1918
2533
|
),
|
|
1919
|
-
options.length > 1 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2534
|
+
options.length > 1 && /* @__PURE__ */ jsxRuntime.jsx(fieldcraftReact.Button, { type: "button", variant: "ghost", size: "icon-xs", onClick: () => handleRemove(index), className: "text-destructive opacity-0 group-hover:opacity-100 transition-opacity", children: "x" })
|
|
1920
2535
|
] }, index)) })
|
|
1921
2536
|
] });
|
|
1922
2537
|
}
|
|
@@ -1938,7 +2553,7 @@ function ScoreRangesEditor({
|
|
|
1938
2553
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
1939
2554
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between mb-2", children: [
|
|
1940
2555
|
/* @__PURE__ */ jsxRuntime.jsx(fieldcraftReact.Label, { className: "text-xs text-muted-foreground", children: "Score Ranges" }),
|
|
1941
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2556
|
+
/* @__PURE__ */ jsxRuntime.jsx(fieldcraftReact.Button, { type: "button", variant: "link", size: "xs", onClick: handleAdd, className: "px-0", children: "+ Add" })
|
|
1942
2557
|
] }),
|
|
1943
2558
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-2", children: ranges.map((range, index) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-2 rounded-md border border-border space-y-1.5 group", children: [
|
|
1944
2559
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5", children: [
|
|
@@ -1946,7 +2561,7 @@ function ScoreRangesEditor({
|
|
|
1946
2561
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-muted-foreground", children: "to" }),
|
|
1947
2562
|
/* @__PURE__ */ jsxRuntime.jsx(fieldcraftReact.Input, { type: "number", value: range.max, onChange: (e) => handleUpdate(index, { max: Number(e.target.value) }), className: "h-7 text-xs w-16", placeholder: "Max" }),
|
|
1948
2563
|
/* @__PURE__ */ jsxRuntime.jsx(fieldcraftReact.Input, { value: range.label, onChange: (e) => handleUpdate(index, { label: e.target.value }), className: "h-7 text-xs flex-1", placeholder: "Label" }),
|
|
1949
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2564
|
+
/* @__PURE__ */ jsxRuntime.jsx(fieldcraftReact.Button, { type: "button", variant: "ghost", size: "icon-xs", onClick: () => handleRemove(index), className: "text-destructive opacity-0 group-hover:opacity-100 transition-opacity", children: "x" })
|
|
1950
2565
|
] }),
|
|
1951
2566
|
/* @__PURE__ */ jsxRuntime.jsx(fieldcraftReact.Input, { value: range.description ?? "", onChange: (e) => handleUpdate(index, { description: e.target.value || void 0 }), className: "h-7 text-xs", placeholder: "Description (optional)" })
|
|
1952
2567
|
] }, index)) })
|
|
@@ -1996,26 +2611,20 @@ function ValidationRulesEditor({ question, onUpdate }) {
|
|
|
1996
2611
|
},
|
|
1997
2612
|
`${rule.type}-${index}`
|
|
1998
2613
|
)) }),
|
|
1999
|
-
availableTypes.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-3", children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
children:
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
availableTypes.map((t) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: t.value, children: t.label }, t.value))
|
|
2014
|
-
]
|
|
2015
|
-
}
|
|
2016
|
-
),
|
|
2017
|
-
/* @__PURE__ */ jsxRuntime.jsx("svg", { className: "pointer-events-none absolute right-2.5 top-1/2 -translate-y-1/2 size-3.5 text-muted-foreground", xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m6 9 6 6 6-6" }) })
|
|
2018
|
-
] }) })
|
|
2614
|
+
availableTypes.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-3", children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2615
|
+
NativeSelect,
|
|
2616
|
+
{
|
|
2617
|
+
value: "",
|
|
2618
|
+
onChange: (e) => {
|
|
2619
|
+
if (e.target.value) addRule(e.target.value);
|
|
2620
|
+
},
|
|
2621
|
+
className: "h-8 text-xs text-muted-foreground",
|
|
2622
|
+
children: [
|
|
2623
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "", children: "Add validation rule..." }),
|
|
2624
|
+
availableTypes.map((t) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: t.value, children: t.label }, t.value))
|
|
2625
|
+
]
|
|
2626
|
+
}
|
|
2627
|
+
) })
|
|
2019
2628
|
] });
|
|
2020
2629
|
}
|
|
2021
2630
|
function RuleRow({
|
|
@@ -2029,13 +2638,15 @@ function RuleRow({
|
|
|
2029
2638
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
|
|
2030
2639
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-foreground", children: label }),
|
|
2031
2640
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2032
|
-
|
|
2641
|
+
fieldcraftReact.Button,
|
|
2033
2642
|
{
|
|
2034
2643
|
type: "button",
|
|
2644
|
+
variant: "ghost",
|
|
2645
|
+
size: "icon-xs",
|
|
2035
2646
|
onClick: onRemove,
|
|
2036
|
-
className: "opacity-0 group-hover:opacity-100 transition-opacity",
|
|
2647
|
+
className: "opacity-0 group-hover:opacity-100 transition-opacity hover:bg-destructive/10 hover:text-destructive",
|
|
2037
2648
|
title: "Remove rule",
|
|
2038
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2, { size: 12,
|
|
2649
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2, { size: 12, strokeWidth: 1.75 })
|
|
2039
2650
|
}
|
|
2040
2651
|
)
|
|
2041
2652
|
] }),
|
|
@@ -2270,11 +2881,13 @@ function ConditionEditor({ question, schema, onUpdate }) {
|
|
|
2270
2881
|
!hasConditions && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground mb-3", children: "Always visible. Add a rule to show this field conditionally." }),
|
|
2271
2882
|
hasConditions && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-2 mb-3", children: showIf.conditions.map((cond, index) => /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
2272
2883
|
index > 0 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2273
|
-
|
|
2884
|
+
fieldcraftReact.Button,
|
|
2274
2885
|
{
|
|
2275
2886
|
type: "button",
|
|
2887
|
+
variant: "link",
|
|
2888
|
+
size: "xs",
|
|
2276
2889
|
onClick: toggleCombine,
|
|
2277
|
-
className: "text-[10px] font-semibold uppercase tracking-wider
|
|
2890
|
+
className: "text-[10px] font-semibold uppercase tracking-wider px-0 mb-1.5",
|
|
2278
2891
|
children: showIf.combine ?? "AND"
|
|
2279
2892
|
}
|
|
2280
2893
|
),
|
|
@@ -2282,43 +2895,39 @@ function ConditionEditor({ question, schema, onUpdate }) {
|
|
|
2282
2895
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
|
|
2283
2896
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] text-muted-foreground uppercase tracking-wider", children: "When" }),
|
|
2284
2897
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2285
|
-
|
|
2898
|
+
fieldcraftReact.Button,
|
|
2286
2899
|
{
|
|
2287
2900
|
type: "button",
|
|
2901
|
+
variant: "ghost",
|
|
2902
|
+
size: "icon-xs",
|
|
2288
2903
|
onClick: () => removeCondition(index),
|
|
2289
|
-
className: "opacity-0 group-hover:opacity-100 transition-opacity",
|
|
2904
|
+
className: "opacity-0 group-hover:opacity-100 transition-opacity hover:bg-destructive/10 hover:text-destructive",
|
|
2290
2905
|
title: "Remove condition",
|
|
2291
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2, { size: 12,
|
|
2906
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2, { size: 12, strokeWidth: 1.75 })
|
|
2292
2907
|
}
|
|
2293
2908
|
)
|
|
2294
2909
|
] }),
|
|
2295
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
children:
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
"
|
|
2313
|
-
{
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
className: "flex h-7 w-full appearance-none rounded-md border border-input bg-card px-2 py-1 pr-7 text-xs shadow-xs transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring text-foreground cursor-pointer",
|
|
2317
|
-
children: OPERATORS.map((op) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: op.value, children: op.label }, op.value))
|
|
2318
|
-
}
|
|
2319
|
-
),
|
|
2320
|
-
/* @__PURE__ */ jsxRuntime.jsx("svg", { className: "pointer-events-none absolute right-2 top-1/2 -translate-y-1/2 size-3 text-muted-foreground", xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m6 9 6 6 6-6" }) })
|
|
2321
|
-
] }),
|
|
2910
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
2911
|
+
NativeSelect,
|
|
2912
|
+
{
|
|
2913
|
+
value: cond.field ?? "",
|
|
2914
|
+
onChange: (e) => updateCondition(index, { field: e.target.value }),
|
|
2915
|
+
className: "h-7 text-xs",
|
|
2916
|
+
children: [
|
|
2917
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "", children: "Select field..." }),
|
|
2918
|
+
fieldOptions.map((f) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: f.id, children: f.label }, f.id))
|
|
2919
|
+
]
|
|
2920
|
+
}
|
|
2921
|
+
),
|
|
2922
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2923
|
+
NativeSelect,
|
|
2924
|
+
{
|
|
2925
|
+
value: cond.operator ?? "eq",
|
|
2926
|
+
onChange: (e) => updateCondition(index, { operator: e.target.value }),
|
|
2927
|
+
className: "h-7 text-xs",
|
|
2928
|
+
children: OPERATORS.map((op) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: op.value, children: op.label }, op.value))
|
|
2929
|
+
}
|
|
2930
|
+
),
|
|
2322
2931
|
cond.operator !== "exists" && cond.operator !== "notExists" && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2323
2932
|
fieldcraftReact.Input,
|
|
2324
2933
|
{
|
|
@@ -2331,11 +2940,13 @@ function ConditionEditor({ question, schema, onUpdate }) {
|
|
|
2331
2940
|
] })
|
|
2332
2941
|
] }, index)) }),
|
|
2333
2942
|
fieldOptions.length > 0 ? /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2334
|
-
|
|
2943
|
+
fieldcraftReact.Button,
|
|
2335
2944
|
{
|
|
2336
2945
|
type: "button",
|
|
2946
|
+
variant: "link",
|
|
2947
|
+
size: "xs",
|
|
2337
2948
|
onClick: addCondition,
|
|
2338
|
-
className: "
|
|
2949
|
+
className: "px-0 gap-1.5",
|
|
2339
2950
|
children: [
|
|
2340
2951
|
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Plus, { size: 12, strokeWidth: 2 }),
|
|
2341
2952
|
"Add condition"
|
|
@@ -2497,18 +3108,7 @@ function SettingsSelect({
|
|
|
2497
3108
|
}) {
|
|
2498
3109
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
2499
3110
|
/* @__PURE__ */ jsxRuntime.jsx(fieldcraftReact.Label, { className: "text-xs text-muted-foreground mb-1", children: label }),
|
|
2500
|
-
/* @__PURE__ */ jsxRuntime.
|
|
2501
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2502
|
-
"select",
|
|
2503
|
-
{
|
|
2504
|
-
value,
|
|
2505
|
-
onChange: (e) => onChange(e.target.value),
|
|
2506
|
-
className: "flex h-9 w-full appearance-none rounded-md border border-input bg-card px-3 py-1 pr-8 text-sm shadow-xs transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring text-foreground cursor-pointer",
|
|
2507
|
-
children: options.map((opt) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: opt.value, children: opt.label }, opt.value))
|
|
2508
|
-
}
|
|
2509
|
-
),
|
|
2510
|
-
/* @__PURE__ */ jsxRuntime.jsx("svg", { className: "pointer-events-none absolute right-2.5 top-1/2 -translate-y-1/2 size-4 text-muted-foreground", xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m6 9 6 6 6-6" }) })
|
|
2511
|
-
] })
|
|
3111
|
+
/* @__PURE__ */ jsxRuntime.jsx(NativeSelect, { value, onChange: (e) => onChange(e.target.value), children: options.map((opt) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: opt.value, children: opt.label }, opt.value)) })
|
|
2512
3112
|
] });
|
|
2513
3113
|
}
|
|
2514
3114
|
function PropertiesPanel({ builderState }) {
|
|
@@ -2610,13 +3210,14 @@ function QuestionProperties({ question, sectionId, builderState, onClose, onOpen
|
|
|
2610
3210
|
typeInfo?.label
|
|
2611
3211
|
] }) }),
|
|
2612
3212
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "shrink-0 px-4 pt-3 flex gap-0.5", children: tabs.map((tab) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
2613
|
-
|
|
3213
|
+
fieldcraftReact.Button,
|
|
2614
3214
|
{
|
|
2615
3215
|
type: "button",
|
|
3216
|
+
variant: activeTab === tab.key ? "default" : "ghost",
|
|
3217
|
+
size: "xs",
|
|
2616
3218
|
onClick: () => setActiveTab(tab.key),
|
|
2617
3219
|
className: cn(
|
|
2618
|
-
|
|
2619
|
-
activeTab === tab.key ? "bg-primary text-primary-foreground" : "bg-transparent text-muted-foreground hover:bg-accent hover:text-foreground"
|
|
3220
|
+
activeTab !== tab.key && "text-muted-foreground"
|
|
2620
3221
|
),
|
|
2621
3222
|
children: tab.label
|
|
2622
3223
|
},
|
|
@@ -2875,13 +3476,18 @@ function FormBuilderCore(props) {
|
|
|
2875
3476
|
reader.onload = (event) => {
|
|
2876
3477
|
try {
|
|
2877
3478
|
const parsed = JSON.parse(event.target?.result);
|
|
2878
|
-
|
|
2879
|
-
|
|
3479
|
+
const validated = fieldcraftCore.validateSchema(parsed);
|
|
3480
|
+
builderState.resetSchema(validated);
|
|
3481
|
+
} catch (err) {
|
|
3482
|
+
if (err instanceof fieldcraftCore.FormEngineSchemaError) {
|
|
3483
|
+
const details = err.issues.slice(0, 3).map((i) => `\u2022 ${i.path.join(".")}: ${i.message}`).join("\n");
|
|
3484
|
+
alert(`Invalid schema:
|
|
3485
|
+
${details}`);
|
|
3486
|
+
} else if (err instanceof SyntaxError) {
|
|
3487
|
+
alert("Failed to parse JSON file.");
|
|
2880
3488
|
} else {
|
|
2881
|
-
alert("Invalid schema
|
|
3489
|
+
alert("Invalid schema file.");
|
|
2882
3490
|
}
|
|
2883
|
-
} catch {
|
|
2884
|
-
alert("Failed to parse JSON file.");
|
|
2885
3491
|
}
|
|
2886
3492
|
};
|
|
2887
3493
|
reader.readAsText(file);
|
|
@@ -3091,7 +3697,7 @@ function FormBuilderInner(props) {
|
|
|
3091
3697
|
}
|
|
3092
3698
|
|
|
3093
3699
|
// src/form-builder/components/FormBuilderGated.tsx
|
|
3094
|
-
var FormBuilder =
|
|
3700
|
+
var FormBuilder = requireLicense(FormBuilderInner, "FormBuilder");
|
|
3095
3701
|
|
|
3096
3702
|
// src/form-builder/theme/presets.ts
|
|
3097
3703
|
var squaredrDarkPreset = {
|
|
@@ -3166,74 +3772,190 @@ var cleanPreset = {
|
|
|
3166
3772
|
borderStrong: "#d1d5db",
|
|
3167
3773
|
textDim: "#9ca3af"
|
|
3168
3774
|
};
|
|
3169
|
-
|
|
3170
|
-
|
|
3171
|
-
|
|
3172
|
-
|
|
3173
|
-
|
|
3174
|
-
|
|
3175
|
-
|
|
3176
|
-
|
|
3177
|
-
|
|
3178
|
-
|
|
3179
|
-
|
|
3180
|
-
|
|
3181
|
-
|
|
3182
|
-
|
|
3183
|
-
|
|
3184
|
-
|
|
3185
|
-
|
|
3186
|
-
|
|
3187
|
-
|
|
3188
|
-
|
|
3189
|
-
|
|
3190
|
-
|
|
3191
|
-
|
|
3192
|
-
|
|
3193
|
-
|
|
3194
|
-
|
|
3195
|
-
|
|
3196
|
-
|
|
3197
|
-
|
|
3198
|
-
|
|
3199
|
-
|
|
3200
|
-
|
|
3201
|
-
|
|
3202
|
-
|
|
3203
|
-
|
|
3204
|
-
|
|
3205
|
-
|
|
3206
|
-
|
|
3207
|
-
|
|
3208
|
-
|
|
3209
|
-
|
|
3210
|
-
|
|
3211
|
-
|
|
3212
|
-
|
|
3213
|
-
|
|
3214
|
-
|
|
3215
|
-
|
|
3216
|
-
|
|
3217
|
-
|
|
3218
|
-
|
|
3219
|
-
|
|
3775
|
+
|
|
3776
|
+
// src/response-viewer/clinical-display-data.ts
|
|
3777
|
+
var BODY_REGION_LABELS = {
|
|
3778
|
+
head: "Head",
|
|
3779
|
+
neck: "Neck",
|
|
3780
|
+
"left-shoulder": "Left Shoulder",
|
|
3781
|
+
"right-shoulder": "Right Shoulder",
|
|
3782
|
+
chest: "Chest",
|
|
3783
|
+
abdomen: "Abdomen",
|
|
3784
|
+
"left-upper-arm": "Left Upper Arm",
|
|
3785
|
+
"right-upper-arm": "Right Upper Arm",
|
|
3786
|
+
"left-forearm": "Left Forearm",
|
|
3787
|
+
"right-forearm": "Right Forearm",
|
|
3788
|
+
"left-hand": "Left Hand",
|
|
3789
|
+
"right-hand": "Right Hand",
|
|
3790
|
+
pelvis: "Pelvis",
|
|
3791
|
+
"left-thigh": "Left Thigh",
|
|
3792
|
+
"right-thigh": "Right Thigh",
|
|
3793
|
+
"left-knee": "Left Knee",
|
|
3794
|
+
"right-knee": "Right Knee",
|
|
3795
|
+
"left-shin": "Left Shin",
|
|
3796
|
+
"right-shin": "Right Shin",
|
|
3797
|
+
"left-foot": "Left Foot",
|
|
3798
|
+
"right-foot": "Right Foot"
|
|
3799
|
+
};
|
|
3800
|
+
var PAIN_FACE_LABELS = [
|
|
3801
|
+
{ score: 0, label: "No Hurt", color: "#22c55e" },
|
|
3802
|
+
{ score: 2, label: "Hurts Little Bit", color: "#84cc16" },
|
|
3803
|
+
{ score: 4, label: "Hurts Little More", color: "#eab308" },
|
|
3804
|
+
{ score: 6, label: "Hurts Even More", color: "#f97316" },
|
|
3805
|
+
{ score: 8, label: "Hurts Whole Lot", color: "#ef4444" },
|
|
3806
|
+
{ score: 10, label: "Hurts Worst", color: "#dc2626" }
|
|
3807
|
+
];
|
|
3808
|
+
function getPainLabel(score) {
|
|
3809
|
+
const face = PAIN_FACE_LABELS.reduce(
|
|
3810
|
+
(closest, f) => closest == null || Math.abs(f.score - score) < Math.abs(closest.score - score) ? f : closest,
|
|
3811
|
+
void 0
|
|
3812
|
+
);
|
|
3813
|
+
return face;
|
|
3814
|
+
}
|
|
3815
|
+
var SEVERITY_COLORS = {
|
|
3816
|
+
mild: "#eab308",
|
|
3817
|
+
moderate: "#f97316",
|
|
3818
|
+
severe: "#ef4444",
|
|
3819
|
+
"life-threatening": "#991b1b"
|
|
3820
|
+
};
|
|
3821
|
+
var BMI_CATEGORIES = [
|
|
3822
|
+
{ label: "Underweight", max: 18.5, color: "#3b82f6" },
|
|
3823
|
+
{ label: "Normal", max: 25, color: "#22c55e" },
|
|
3824
|
+
{ label: "Overweight", max: 30, color: "#eab308" },
|
|
3825
|
+
{ label: "Obese", max: Infinity, color: "#ef4444" }
|
|
3826
|
+
];
|
|
3827
|
+
function getBmiCategory(bmi) {
|
|
3828
|
+
return BMI_CATEGORIES.find((c) => bmi < c.max) ?? BMI_CATEGORIES[BMI_CATEGORIES.length - 1];
|
|
3220
3829
|
}
|
|
3221
|
-
var
|
|
3222
|
-
|
|
3223
|
-
|
|
3224
|
-
|
|
3225
|
-
|
|
3226
|
-
|
|
3227
|
-
|
|
3830
|
+
var INSTRUMENT_DISPLAY_NAMES = {
|
|
3831
|
+
phq9: "PHQ-9",
|
|
3832
|
+
phq2: "PHQ-2",
|
|
3833
|
+
gad7: "GAD-7",
|
|
3834
|
+
gad2: "GAD-2",
|
|
3835
|
+
"audit-c": "AUDIT-C",
|
|
3836
|
+
dast10: "DAST-10",
|
|
3837
|
+
cssrs: "C-SSRS",
|
|
3838
|
+
epds: "EPDS",
|
|
3839
|
+
isi: "ISI",
|
|
3840
|
+
pcl5: "PCL-5",
|
|
3841
|
+
psc17: "PSC-17"
|
|
3228
3842
|
};
|
|
3229
|
-
var
|
|
3230
|
-
|
|
3231
|
-
|
|
3232
|
-
|
|
3233
|
-
|
|
3234
|
-
|
|
3235
|
-
|
|
3843
|
+
var SCORE_THRESHOLDS = {
|
|
3844
|
+
phq9: [
|
|
3845
|
+
{ min: 0, max: 4, label: "Minimal", color: "#22c55e" },
|
|
3846
|
+
{ min: 5, max: 9, label: "Mild", color: "#eab308" },
|
|
3847
|
+
{ min: 10, max: 14, label: "Moderate", color: "#f97316" },
|
|
3848
|
+
{ min: 15, max: 19, label: "Moderately Severe", color: "#ef4444" },
|
|
3849
|
+
{ min: 20, max: 27, label: "Severe", color: "#dc2626" }
|
|
3850
|
+
],
|
|
3851
|
+
phq2: [
|
|
3852
|
+
{ min: 0, max: 2, label: "Negative Screen", color: "#22c55e" },
|
|
3853
|
+
{ min: 3, max: 6, label: "Positive Screen", color: "#ef4444" }
|
|
3854
|
+
],
|
|
3855
|
+
gad7: [
|
|
3856
|
+
{ min: 0, max: 4, label: "Minimal", color: "#22c55e" },
|
|
3857
|
+
{ min: 5, max: 9, label: "Mild", color: "#eab308" },
|
|
3858
|
+
{ min: 10, max: 14, label: "Moderate", color: "#f97316" },
|
|
3859
|
+
{ min: 15, max: 21, label: "Severe", color: "#ef4444" }
|
|
3860
|
+
],
|
|
3861
|
+
gad2: [
|
|
3862
|
+
{ min: 0, max: 2, label: "Negative Screen", color: "#22c55e" },
|
|
3863
|
+
{ min: 3, max: 6, label: "Positive Screen", color: "#ef4444" }
|
|
3864
|
+
],
|
|
3865
|
+
"audit-c": [
|
|
3866
|
+
{ min: 0, max: 3, label: "Low Risk", color: "#22c55e" },
|
|
3867
|
+
{ min: 4, max: 7, label: "At Risk", color: "#eab308" },
|
|
3868
|
+
{ min: 8, max: 12, label: "High Risk", color: "#ef4444" }
|
|
3869
|
+
],
|
|
3870
|
+
dast10: [
|
|
3871
|
+
{ min: 0, max: 0, label: "No Problems", color: "#22c55e" },
|
|
3872
|
+
{ min: 1, max: 2, label: "Low Level", color: "#eab308" },
|
|
3873
|
+
{ min: 3, max: 5, label: "Moderate Level", color: "#f97316" },
|
|
3874
|
+
{ min: 6, max: 8, label: "Substantial Level", color: "#ef4444" },
|
|
3875
|
+
{ min: 9, max: 10, label: "Severe Level", color: "#dc2626" }
|
|
3876
|
+
],
|
|
3877
|
+
cssrs: [
|
|
3878
|
+
{ min: 0, max: 0, label: "No Risk Identified", color: "#22c55e" },
|
|
3879
|
+
{ min: 1, max: 1, label: "Wish to be Dead", color: "#eab308" },
|
|
3880
|
+
{ min: 2, max: 2, label: "Non-specific Active Suicidal Thoughts", color: "#f97316" },
|
|
3881
|
+
{ min: 3, max: 3, label: "Active Suicidal Ideation", color: "#ef4444" },
|
|
3882
|
+
{ min: 4, max: 4, label: "Active Ideation with Intent", color: "#dc2626" },
|
|
3883
|
+
{ min: 5, max: 5, label: "Active Ideation with Plan", color: "#991b1b" },
|
|
3884
|
+
{ min: 6, max: 6, label: "Imminent Risk", color: "#7f1d1d" }
|
|
3885
|
+
],
|
|
3886
|
+
epds: [
|
|
3887
|
+
{ min: 0, max: 8, label: "Low Likelihood", color: "#22c55e" },
|
|
3888
|
+
{ min: 9, max: 11, label: "Possible Depression", color: "#eab308" },
|
|
3889
|
+
{ min: 12, max: 13, label: "Fairly High Possibility", color: "#f97316" },
|
|
3890
|
+
{ min: 14, max: 30, label: "Probable Depression", color: "#ef4444" }
|
|
3891
|
+
],
|
|
3892
|
+
isi: [
|
|
3893
|
+
{ min: 0, max: 7, label: "No Clinically Significant Insomnia", color: "#22c55e" },
|
|
3894
|
+
{ min: 8, max: 14, label: "Subthreshold Insomnia", color: "#eab308" },
|
|
3895
|
+
{ min: 15, max: 21, label: "Clinical Insomnia (Moderate)", color: "#f97316" },
|
|
3896
|
+
{ min: 22, max: 28, label: "Clinical Insomnia (Severe)", color: "#ef4444" }
|
|
3897
|
+
],
|
|
3898
|
+
pcl5: [
|
|
3899
|
+
{ min: 0, max: 30, label: "Below Threshold", color: "#22c55e" },
|
|
3900
|
+
{ min: 31, max: 80, label: "Probable PTSD", color: "#ef4444" }
|
|
3901
|
+
],
|
|
3902
|
+
psc17: [
|
|
3903
|
+
{ min: 0, max: 14, label: "No Significant Concerns", color: "#22c55e" },
|
|
3904
|
+
{ min: 15, max: 34, label: "Significant Concerns", color: "#ef4444" }
|
|
3905
|
+
]
|
|
3236
3906
|
};
|
|
3907
|
+
function getScoreSeverity(instrumentKey, score) {
|
|
3908
|
+
const thresholds = SCORE_THRESHOLDS[instrumentKey];
|
|
3909
|
+
if (!thresholds) return void 0;
|
|
3910
|
+
return thresholds.find((t) => score >= t.min && score <= t.max);
|
|
3911
|
+
}
|
|
3912
|
+
function ResponseTable({ schema, responses, onRowClick }) {
|
|
3913
|
+
const questions = getAllQuestions(schema);
|
|
3914
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "overflow-auto", children: /* @__PURE__ */ jsxRuntime.jsxs("table", { className: "w-full border-collapse text-[13px]", children: [
|
|
3915
|
+
/* @__PURE__ */ jsxRuntime.jsx("thead", { children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { className: "bg-muted", children: [
|
|
3916
|
+
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-3 py-2 text-left font-semibold text-foreground border-b-2 border-border whitespace-nowrap", children: "Submitted" }),
|
|
3917
|
+
questions.map((q) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
3918
|
+
"th",
|
|
3919
|
+
{
|
|
3920
|
+
className: "px-3 py-2 text-left font-semibold text-foreground border-b-2 border-border whitespace-nowrap",
|
|
3921
|
+
children: q.label
|
|
3922
|
+
},
|
|
3923
|
+
q.id
|
|
3924
|
+
)),
|
|
3925
|
+
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-3 py-2 text-left font-semibold text-foreground border-b-2 border-border whitespace-nowrap", children: "Score" })
|
|
3926
|
+
] }) }),
|
|
3927
|
+
/* @__PURE__ */ jsxRuntime.jsxs("tbody", { children: [
|
|
3928
|
+
responses.map((response, idx) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3929
|
+
"tr",
|
|
3930
|
+
{
|
|
3931
|
+
onClick: () => onRowClick?.(response),
|
|
3932
|
+
className: onRowClick ? "cursor-pointer border-b border-border hover:bg-accent transition-colors" : "border-b border-border",
|
|
3933
|
+
children: [
|
|
3934
|
+
/* @__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() }),
|
|
3935
|
+
questions.map((q) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
3936
|
+
"td",
|
|
3937
|
+
{
|
|
3938
|
+
className: "px-3 py-2 text-foreground max-w-50 overflow-hidden text-ellipsis whitespace-nowrap",
|
|
3939
|
+
children: formatCellValue(response.values[q.id], q.type)
|
|
3940
|
+
},
|
|
3941
|
+
q.id
|
|
3942
|
+
)),
|
|
3943
|
+
/* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-3 py-2 text-foreground max-w-50 overflow-hidden text-ellipsis whitespace-nowrap", children: response.totalScore ?? "\u2014" })
|
|
3944
|
+
]
|
|
3945
|
+
},
|
|
3946
|
+
response.sessionToken || idx
|
|
3947
|
+
)),
|
|
3948
|
+
responses.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("tr", { children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
3949
|
+
"td",
|
|
3950
|
+
{
|
|
3951
|
+
colSpan: questions.length + 2,
|
|
3952
|
+
className: "px-3 py-8 text-center text-muted-foreground",
|
|
3953
|
+
children: "No responses yet"
|
|
3954
|
+
}
|
|
3955
|
+
) })
|
|
3956
|
+
] })
|
|
3957
|
+
] }) });
|
|
3958
|
+
}
|
|
3237
3959
|
function getAllQuestions(schema) {
|
|
3238
3960
|
const questions = [];
|
|
3239
3961
|
for (const section of schema.sections) {
|
|
@@ -3246,8 +3968,69 @@ function getAllQuestions(schema) {
|
|
|
3246
3968
|
}
|
|
3247
3969
|
return questions;
|
|
3248
3970
|
}
|
|
3249
|
-
function formatCellValue(value) {
|
|
3971
|
+
function formatCellValue(value, type) {
|
|
3250
3972
|
if (value == null) return "\u2014";
|
|
3973
|
+
if (type) {
|
|
3974
|
+
switch (type) {
|
|
3975
|
+
case "vitals_entry": {
|
|
3976
|
+
if (typeof value !== "object" || value === null) break;
|
|
3977
|
+
const v = value;
|
|
3978
|
+
const parts = [];
|
|
3979
|
+
if (v.systolicBp && v.diastolicBp) parts.push(`BP ${v.systolicBp}/${v.diastolicBp}`);
|
|
3980
|
+
if (v.heartRate) parts.push(`HR ${v.heartRate}`);
|
|
3981
|
+
if (v.temperature) parts.push(`${v.temperature}\xB0F`);
|
|
3982
|
+
if (v.oxygenSaturation) parts.push(`SpO\u2082 ${v.oxygenSaturation}%`);
|
|
3983
|
+
return parts.length > 0 ? parts.join(", ") : "\u2014";
|
|
3984
|
+
}
|
|
3985
|
+
case "medication_list":
|
|
3986
|
+
if (Array.isArray(value)) return `${value.length} medication${value.length !== 1 ? "s" : ""}`;
|
|
3987
|
+
break;
|
|
3988
|
+
case "allergy_list":
|
|
3989
|
+
if (Array.isArray(value)) return `${value.length} allerg${value.length !== 1 ? "ies" : "y"}`;
|
|
3990
|
+
break;
|
|
3991
|
+
case "body_diagram":
|
|
3992
|
+
if (Array.isArray(value)) {
|
|
3993
|
+
const labels = value.map((id) => BODY_REGION_LABELS[id] ?? id);
|
|
3994
|
+
return labels.join(", ");
|
|
3995
|
+
}
|
|
3996
|
+
break;
|
|
3997
|
+
case "pain_scale":
|
|
3998
|
+
if (typeof value === "number") return `${value}/10`;
|
|
3999
|
+
break;
|
|
4000
|
+
case "bmi_calculator": {
|
|
4001
|
+
if (typeof value !== "object" || value === null) break;
|
|
4002
|
+
const d = value;
|
|
4003
|
+
if (d.bmi != null) return `BMI ${d.bmi}`;
|
|
4004
|
+
break;
|
|
4005
|
+
}
|
|
4006
|
+
case "payment": {
|
|
4007
|
+
if (typeof value !== "object" || value === null) break;
|
|
4008
|
+
const p = value;
|
|
4009
|
+
const status = p.status;
|
|
4010
|
+
return status ? status.charAt(0).toUpperCase() + status.slice(1) : "\u2014";
|
|
4011
|
+
}
|
|
4012
|
+
case "insurance_card": {
|
|
4013
|
+
if (typeof value !== "object" || value === null) break;
|
|
4014
|
+
const ins = value;
|
|
4015
|
+
const parts = [ins.carrierId, ins.planName].filter(Boolean);
|
|
4016
|
+
return parts.length > 0 ? parts.join(" \u2014 ") : "Card uploaded";
|
|
4017
|
+
}
|
|
4018
|
+
case "legal_name": {
|
|
4019
|
+
if (typeof value !== "object" || value === null) break;
|
|
4020
|
+
const n = value;
|
|
4021
|
+
return [n.first, n.last].filter(Boolean).join(" ") || "\u2014";
|
|
4022
|
+
}
|
|
4023
|
+
case "address": {
|
|
4024
|
+
if (typeof value !== "object" || value === null) break;
|
|
4025
|
+
const a = value;
|
|
4026
|
+
return [a.city, a.state].filter(Boolean).join(", ") || "\u2014";
|
|
4027
|
+
}
|
|
4028
|
+
case "consent":
|
|
4029
|
+
return value === true || value === "true" || value === "agreed" ? "Agreed" : "Not agreed";
|
|
4030
|
+
case "signature":
|
|
4031
|
+
return typeof value === "string" && value.startsWith("data:image") ? "Signed" : "\u2014";
|
|
4032
|
+
}
|
|
4033
|
+
}
|
|
3251
4034
|
if (typeof value === "boolean") return value ? "Yes" : "No";
|
|
3252
4035
|
if (Array.isArray(value)) return value.join(", ");
|
|
3253
4036
|
if (typeof value === "object") return JSON.stringify(value);
|
|
@@ -3258,238 +4041,570 @@ function ResponseCard({ response, fields, onClick }) {
|
|
|
3258
4041
|
"div",
|
|
3259
4042
|
{
|
|
3260
4043
|
onClick,
|
|
3261
|
-
|
|
3262
|
-
border: "1px solid var(--border, #1c1c20)",
|
|
3263
|
-
borderRadius: "8px",
|
|
3264
|
-
padding: "16px",
|
|
3265
|
-
backgroundColor: "var(--card, #111113)",
|
|
3266
|
-
cursor: onClick ? "pointer" : "default",
|
|
3267
|
-
fontFamily: "inherit",
|
|
3268
|
-
transition: "box-shadow 0.15s"
|
|
3269
|
-
},
|
|
3270
|
-
onMouseEnter: (e) => {
|
|
3271
|
-
if (onClick) e.currentTarget.style.boxShadow = "0 2px 8px rgba(0,0,0,0.3)";
|
|
3272
|
-
},
|
|
3273
|
-
onMouseLeave: (e) => {
|
|
3274
|
-
e.currentTarget.style.boxShadow = "none";
|
|
3275
|
-
},
|
|
4044
|
+
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",
|
|
3276
4045
|
children: [
|
|
3277
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
3278
|
-
"
|
|
3279
|
-
{
|
|
3280
|
-
|
|
3281
|
-
|
|
3282
|
-
|
|
3283
|
-
|
|
3284
|
-
|
|
3285
|
-
|
|
3286
|
-
|
|
3287
|
-
children: [
|
|
3288
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { children: new Date(response.submittedAt).toLocaleString() }),
|
|
3289
|
-
response.completionTimeMs != null && /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
|
|
3290
|
-
Math.round(response.completionTimeMs / 1e3),
|
|
3291
|
-
"s"
|
|
3292
|
-
] })
|
|
3293
|
-
]
|
|
3294
|
-
}
|
|
3295
|
-
),
|
|
3296
|
-
fields.slice(0, 4).map((field) => /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { marginBottom: "8px" }, children: [
|
|
3297
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontSize: "11px", color: "var(--muted-foreground, #8a8a95)", marginBottom: "2px" }, children: field.label }),
|
|
3298
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontSize: "13px", color: "var(--foreground, #e8e8ea)" }, children: formatValue(field.value) })
|
|
4046
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-between mb-3 text-xs text-muted-foreground", children: [
|
|
4047
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: new Date(response.submittedAt).toLocaleString() }),
|
|
4048
|
+
response.completionTimeMs != null && /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
|
|
4049
|
+
Math.round(response.completionTimeMs / 1e3),
|
|
4050
|
+
"s"
|
|
4051
|
+
] })
|
|
4052
|
+
] }),
|
|
4053
|
+
fields.slice(0, 4).map((field) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-2", children: [
|
|
4054
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-[11px] text-muted-foreground mb-0.5", children: field.label }),
|
|
4055
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-[13px] text-foreground", children: formatCardValue(field.value, field.type) })
|
|
3299
4056
|
] }, field.questionId)),
|
|
3300
|
-
fields.length > 4 && /* @__PURE__ */ jsxRuntime.jsxs("div", {
|
|
4057
|
+
fields.length > 4 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-xs text-muted-foreground mt-2", children: [
|
|
3301
4058
|
"+",
|
|
3302
4059
|
fields.length - 4,
|
|
3303
4060
|
" more fields"
|
|
3304
4061
|
] }),
|
|
3305
|
-
response.totalScore != null && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3306
|
-
"
|
|
3307
|
-
|
|
3308
|
-
|
|
3309
|
-
marginTop: "12px",
|
|
3310
|
-
paddingTop: "8px",
|
|
3311
|
-
borderTop: "1px solid var(--border, #1c1c20)",
|
|
3312
|
-
fontSize: "13px",
|
|
3313
|
-
fontWeight: 600,
|
|
3314
|
-
color: "var(--foreground, #e8e8ea)"
|
|
3315
|
-
},
|
|
3316
|
-
children: [
|
|
3317
|
-
"Score: ",
|
|
3318
|
-
response.totalScore
|
|
3319
|
-
]
|
|
3320
|
-
}
|
|
3321
|
-
)
|
|
4062
|
+
response.totalScore != null && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-3 pt-2 border-t border-border text-[13px] font-semibold text-foreground", children: [
|
|
4063
|
+
"Score: ",
|
|
4064
|
+
response.totalScore
|
|
4065
|
+
] })
|
|
3322
4066
|
]
|
|
3323
4067
|
}
|
|
3324
4068
|
);
|
|
3325
4069
|
}
|
|
3326
|
-
function
|
|
4070
|
+
function formatCardValue(value, type) {
|
|
3327
4071
|
if (value == null) return "\u2014";
|
|
4072
|
+
if (type) {
|
|
4073
|
+
switch (type) {
|
|
4074
|
+
case "vitals_entry": {
|
|
4075
|
+
if (typeof value !== "object" || value === null) break;
|
|
4076
|
+
const v = value;
|
|
4077
|
+
const parts = [];
|
|
4078
|
+
if (v.systolicBp && v.diastolicBp) parts.push(`BP ${v.systolicBp}/${v.diastolicBp}`);
|
|
4079
|
+
if (v.heartRate) parts.push(`HR ${v.heartRate}`);
|
|
4080
|
+
if (v.temperature) parts.push(`${v.temperature}\xB0F`);
|
|
4081
|
+
if (v.oxygenSaturation) parts.push(`SpO\u2082 ${v.oxygenSaturation}%`);
|
|
4082
|
+
return parts.length > 0 ? parts.join(", ") : "\u2014";
|
|
4083
|
+
}
|
|
4084
|
+
case "medication_list":
|
|
4085
|
+
if (Array.isArray(value)) return `${value.length} medication${value.length !== 1 ? "s" : ""}`;
|
|
4086
|
+
break;
|
|
4087
|
+
case "allergy_list":
|
|
4088
|
+
if (Array.isArray(value)) return `${value.length} allerg${value.length !== 1 ? "ies" : "y"}`;
|
|
4089
|
+
break;
|
|
4090
|
+
case "body_diagram":
|
|
4091
|
+
if (Array.isArray(value)) {
|
|
4092
|
+
const labels = value.map((id) => BODY_REGION_LABELS[id] ?? id);
|
|
4093
|
+
return labels.join(", ");
|
|
4094
|
+
}
|
|
4095
|
+
break;
|
|
4096
|
+
case "pain_scale":
|
|
4097
|
+
if (typeof value === "number") return `${value}/10`;
|
|
4098
|
+
break;
|
|
4099
|
+
case "bmi_calculator": {
|
|
4100
|
+
if (typeof value !== "object" || value === null) break;
|
|
4101
|
+
const d = value;
|
|
4102
|
+
if (d.bmi != null) return `BMI ${d.bmi}`;
|
|
4103
|
+
break;
|
|
4104
|
+
}
|
|
4105
|
+
case "payment": {
|
|
4106
|
+
if (typeof value !== "object" || value === null) break;
|
|
4107
|
+
const p = value;
|
|
4108
|
+
const status = p.status;
|
|
4109
|
+
return status ? status.charAt(0).toUpperCase() + status.slice(1) : "\u2014";
|
|
4110
|
+
}
|
|
4111
|
+
case "insurance_card": {
|
|
4112
|
+
if (typeof value !== "object" || value === null) break;
|
|
4113
|
+
const ins = value;
|
|
4114
|
+
const parts = [ins.carrierId, ins.planName].filter(Boolean);
|
|
4115
|
+
return parts.length > 0 ? parts.join(" \u2014 ") : "Card uploaded";
|
|
4116
|
+
}
|
|
4117
|
+
case "legal_name": {
|
|
4118
|
+
if (typeof value !== "object" || value === null) break;
|
|
4119
|
+
const n = value;
|
|
4120
|
+
return [n.first, n.last].filter(Boolean).join(" ") || "\u2014";
|
|
4121
|
+
}
|
|
4122
|
+
case "address": {
|
|
4123
|
+
if (typeof value !== "object" || value === null) break;
|
|
4124
|
+
const a = value;
|
|
4125
|
+
return [a.city, a.state].filter(Boolean).join(", ") || "\u2014";
|
|
4126
|
+
}
|
|
4127
|
+
case "consent":
|
|
4128
|
+
return value === true || value === "true" || value === "agreed" ? "Agreed" : "Not agreed";
|
|
4129
|
+
case "signature":
|
|
4130
|
+
return typeof value === "string" && value.startsWith("data:image") ? "Signed" : "\u2014";
|
|
4131
|
+
}
|
|
4132
|
+
}
|
|
3328
4133
|
if (typeof value === "boolean") return value ? "Yes" : "No";
|
|
3329
|
-
if (Array.isArray(value)) return value.map(
|
|
4134
|
+
if (Array.isArray(value)) return value.map(String).join(", ");
|
|
3330
4135
|
if (typeof value === "object") return JSON.stringify(value);
|
|
3331
4136
|
return String(value);
|
|
3332
4137
|
}
|
|
3333
4138
|
function ResponseDetail({ response, fields, onBack }) {
|
|
3334
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", {
|
|
3335
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
3336
|
-
"
|
|
3337
|
-
{
|
|
3338
|
-
|
|
3339
|
-
|
|
3340
|
-
|
|
3341
|
-
|
|
3342
|
-
|
|
3343
|
-
|
|
3344
|
-
|
|
3345
|
-
|
|
3346
|
-
|
|
3347
|
-
onBack && /* @__PURE__ */ jsxRuntime.jsx(
|
|
3348
|
-
"button",
|
|
3349
|
-
{
|
|
3350
|
-
type: "button",
|
|
3351
|
-
onClick: onBack,
|
|
3352
|
-
style: {
|
|
3353
|
-
padding: "4px 10px",
|
|
3354
|
-
fontSize: "13px",
|
|
3355
|
-
color: "var(--secondary-foreground, #e8e8ea)",
|
|
3356
|
-
backgroundColor: "var(--secondary, #17171a)",
|
|
3357
|
-
border: "1px solid var(--border, #1c1c20)",
|
|
3358
|
-
borderRadius: "6px",
|
|
3359
|
-
cursor: "pointer"
|
|
3360
|
-
},
|
|
3361
|
-
children: "Back"
|
|
3362
|
-
}
|
|
3363
|
-
),
|
|
3364
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
3365
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontSize: "14px", fontWeight: 600, color: "var(--foreground, #e8e8ea)" }, children: "Response Detail" }),
|
|
3366
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: { fontSize: "12px", color: "var(--muted-foreground, #8a8a95)" }, children: [
|
|
3367
|
-
"Submitted ",
|
|
3368
|
-
new Date(response.submittedAt).toLocaleString(),
|
|
3369
|
-
response.completionTimeMs != null && ` \u2014 ${Math.round(response.completionTimeMs / 1e3)}s`
|
|
3370
|
-
] })
|
|
3371
|
-
] })
|
|
3372
|
-
]
|
|
3373
|
-
}
|
|
3374
|
-
),
|
|
3375
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { style: { display: "flex", flexDirection: "column", gap: "16px" }, children: fields.map((field) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
4139
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
4140
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3 mb-5 pb-3 border-b border-border", children: [
|
|
4141
|
+
onBack && /* @__PURE__ */ jsxRuntime.jsx(fieldcraftReact.Button, { variant: "outline", size: "sm", onClick: onBack, children: "Back" }),
|
|
4142
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
4143
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm font-semibold text-foreground", children: "Response Detail" }),
|
|
4144
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-xs text-muted-foreground", children: [
|
|
4145
|
+
"Submitted ",
|
|
4146
|
+
new Date(response.submittedAt).toLocaleString(),
|
|
4147
|
+
response.completionTimeMs != null && ` \u2014 ${Math.round(response.completionTimeMs / 1e3)}s`
|
|
4148
|
+
] })
|
|
4149
|
+
] })
|
|
4150
|
+
] }),
|
|
4151
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col gap-4", children: fields.map((field) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3376
4152
|
"div",
|
|
3377
4153
|
{
|
|
3378
|
-
|
|
3379
|
-
padding: "12px",
|
|
3380
|
-
backgroundColor: "var(--muted, #111113)",
|
|
3381
|
-
borderRadius: "6px"
|
|
3382
|
-
},
|
|
4154
|
+
className: "p-3 bg-muted rounded-md",
|
|
3383
4155
|
children: [
|
|
3384
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", {
|
|
4156
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-xs text-muted-foreground mb-1", children: [
|
|
3385
4157
|
field.label,
|
|
3386
|
-
/* @__PURE__ */ jsxRuntime.jsxs("span", {
|
|
4158
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "ml-2 text-[11px] text-muted-foreground", children: [
|
|
3387
4159
|
"(",
|
|
3388
4160
|
field.type,
|
|
3389
4161
|
")"
|
|
3390
4162
|
] })
|
|
3391
4163
|
] }),
|
|
3392
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", {
|
|
4164
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm text-foreground", children: renderFieldValue(field) })
|
|
3393
4165
|
]
|
|
3394
4166
|
},
|
|
3395
4167
|
field.questionId
|
|
3396
4168
|
)) }),
|
|
3397
|
-
response.scores && Object.keys(response.scores).length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", {
|
|
3398
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3399
|
-
|
|
3400
|
-
{
|
|
3401
|
-
|
|
3402
|
-
|
|
3403
|
-
|
|
3404
|
-
|
|
3405
|
-
|
|
3406
|
-
|
|
3407
|
-
|
|
3408
|
-
|
|
3409
|
-
|
|
3410
|
-
|
|
3411
|
-
|
|
3412
|
-
|
|
3413
|
-
|
|
3414
|
-
|
|
3415
|
-
|
|
3416
|
-
|
|
3417
|
-
|
|
3418
|
-
|
|
3419
|
-
|
|
3420
|
-
|
|
3421
|
-
|
|
3422
|
-
key,
|
|
3423
|
-
": "
|
|
3424
|
-
] }),
|
|
3425
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontWeight: 600, color: "var(--primary, oklch(0.82 0.14 210))" }, children: value })
|
|
3426
|
-
]
|
|
3427
|
-
},
|
|
3428
|
-
key
|
|
3429
|
-
)),
|
|
3430
|
-
response.totalScore != null && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3431
|
-
"div",
|
|
3432
|
-
{
|
|
3433
|
-
style: {
|
|
3434
|
-
padding: "8px 16px",
|
|
3435
|
-
backgroundColor: "var(--accent, #17171a)",
|
|
3436
|
-
borderRadius: "6px",
|
|
3437
|
-
fontSize: "13px"
|
|
4169
|
+
response.scores && Object.keys(response.scores).length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-5", children: [
|
|
4170
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm font-semibold text-foreground mb-3", children: "Scores" }),
|
|
4171
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-3 flex-wrap", children: [
|
|
4172
|
+
Object.entries(response.scores).map(([key, value]) => {
|
|
4173
|
+
const displayName = INSTRUMENT_DISPLAY_NAMES[key] ?? key;
|
|
4174
|
+
const severity = typeof value === "number" ? getScoreSeverity(key, value) : void 0;
|
|
4175
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
4176
|
+
"div",
|
|
4177
|
+
{
|
|
4178
|
+
className: "px-4 py-2 bg-accent rounded-md text-[13px] flex items-center gap-2",
|
|
4179
|
+
children: [
|
|
4180
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-muted-foreground", children: [
|
|
4181
|
+
displayName,
|
|
4182
|
+
": "
|
|
4183
|
+
] }),
|
|
4184
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-semibold text-primary", children: value }),
|
|
4185
|
+
severity && /* @__PURE__ */ jsxRuntime.jsx(
|
|
4186
|
+
"span",
|
|
4187
|
+
{
|
|
4188
|
+
className: "text-[11px] font-semibold px-2 py-0.5 rounded-full text-white",
|
|
4189
|
+
style: { backgroundColor: severity.color },
|
|
4190
|
+
children: severity.label
|
|
4191
|
+
}
|
|
4192
|
+
)
|
|
4193
|
+
]
|
|
3438
4194
|
},
|
|
3439
|
-
|
|
3440
|
-
|
|
3441
|
-
|
|
3442
|
-
|
|
3443
|
-
}
|
|
3444
|
-
|
|
4195
|
+
key
|
|
4196
|
+
);
|
|
4197
|
+
}),
|
|
4198
|
+
response.totalScore != null && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-4 py-2 bg-accent rounded-md text-[13px]", children: [
|
|
4199
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: "Total: " }),
|
|
4200
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-semibold text-primary", children: response.totalScore })
|
|
4201
|
+
] })
|
|
3445
4202
|
] })
|
|
3446
4203
|
] }),
|
|
3447
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
4204
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-5 pt-3 border-t border-border text-xs text-muted-foreground", children: [
|
|
4205
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
4206
|
+
"Schema: ",
|
|
4207
|
+
response.schemaId,
|
|
4208
|
+
" (v",
|
|
4209
|
+
response.schemaVersion,
|
|
4210
|
+
")"
|
|
4211
|
+
] }),
|
|
4212
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
4213
|
+
"Session: ",
|
|
4214
|
+
response.sessionToken
|
|
4215
|
+
] })
|
|
4216
|
+
] })
|
|
4217
|
+
] });
|
|
4218
|
+
}
|
|
4219
|
+
function renderFieldValue(field) {
|
|
4220
|
+
const { type, value } = field;
|
|
4221
|
+
if (value == null) return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: "\u2014" });
|
|
4222
|
+
switch (type) {
|
|
4223
|
+
case "vitals_entry":
|
|
4224
|
+
return renderVitals(value);
|
|
4225
|
+
case "medication_list":
|
|
4226
|
+
return renderMedications(value);
|
|
4227
|
+
case "allergy_list":
|
|
4228
|
+
return renderAllergies(value);
|
|
4229
|
+
case "bmi_calculator":
|
|
4230
|
+
return renderBmi(value);
|
|
4231
|
+
case "body_diagram":
|
|
4232
|
+
return renderBodyDiagram(value);
|
|
4233
|
+
case "pain_scale":
|
|
4234
|
+
return renderPainScale(value);
|
|
4235
|
+
case "insurance_card":
|
|
4236
|
+
return renderInsurance(value);
|
|
4237
|
+
case "payment":
|
|
4238
|
+
return renderPayment(value);
|
|
4239
|
+
case "legal_name":
|
|
4240
|
+
return renderLegalName(value);
|
|
4241
|
+
case "address":
|
|
4242
|
+
return renderAddress(value);
|
|
4243
|
+
case "consent":
|
|
4244
|
+
return renderConsent(value);
|
|
4245
|
+
case "signature":
|
|
4246
|
+
return renderSignature(value);
|
|
4247
|
+
default:
|
|
4248
|
+
return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "whitespace-pre-wrap", children: formatFallbackValue(value) });
|
|
4249
|
+
}
|
|
4250
|
+
}
|
|
4251
|
+
var VITALS_LABELS = {
|
|
4252
|
+
systolicBp: { label: "Systolic BP", unit: "mmHg", normalRange: "90-140" },
|
|
4253
|
+
diastolicBp: { label: "Diastolic BP", unit: "mmHg", normalRange: "60-90" },
|
|
4254
|
+
heartRate: { label: "Heart Rate", unit: "bpm", normalRange: "60-100" },
|
|
4255
|
+
temperature: { label: "Temperature", unit: "\xB0F", normalRange: "97.0-99.5" },
|
|
4256
|
+
respiratoryRate: { label: "Respiratory Rate", unit: "/min", normalRange: "12-20" },
|
|
4257
|
+
oxygenSaturation: { label: "SpO\u2082", unit: "%", normalRange: "95-100" }
|
|
4258
|
+
};
|
|
4259
|
+
function renderVitals(value) {
|
|
4260
|
+
if (typeof value !== "object" || value === null) return formatFallbackValue(value);
|
|
4261
|
+
const vitals = value;
|
|
4262
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-2 gap-2", children: Object.entries(VITALS_LABELS).map(([key, meta]) => {
|
|
4263
|
+
const val = vitals[key];
|
|
4264
|
+
if (val == null || val === 0) return null;
|
|
4265
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-[13px]", children: [
|
|
4266
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-muted-foreground", children: [
|
|
4267
|
+
meta.label,
|
|
4268
|
+
": "
|
|
4269
|
+
] }),
|
|
4270
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-medium", children: [
|
|
4271
|
+
String(val),
|
|
4272
|
+
" ",
|
|
4273
|
+
meta.unit
|
|
4274
|
+
] }),
|
|
4275
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-[11px] text-muted-foreground ml-1", children: [
|
|
4276
|
+
"(",
|
|
4277
|
+
meta.normalRange,
|
|
4278
|
+
")"
|
|
4279
|
+
] })
|
|
4280
|
+
] }, key);
|
|
4281
|
+
}) });
|
|
4282
|
+
}
|
|
4283
|
+
function renderMedications(value) {
|
|
4284
|
+
if (!Array.isArray(value) || value.length === 0) return "No medications";
|
|
4285
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col gap-2", children: value.map((med, idx) => {
|
|
4286
|
+
const m = med;
|
|
4287
|
+
const parts = [m.dosage, m.frequency, m.route].filter(Boolean);
|
|
4288
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3448
4289
|
"div",
|
|
3449
4290
|
{
|
|
3450
|
-
|
|
3451
|
-
marginTop: "20px",
|
|
3452
|
-
paddingTop: "12px",
|
|
3453
|
-
borderTop: "1px solid var(--border, #1c1c20)",
|
|
3454
|
-
fontSize: "12px",
|
|
3455
|
-
color: "var(--muted-foreground, #8a8a95)"
|
|
3456
|
-
},
|
|
4291
|
+
className: "px-3 py-2 border border-border rounded-md text-[13px]",
|
|
3457
4292
|
children: [
|
|
3458
|
-
/* @__PURE__ */ jsxRuntime.
|
|
3459
|
-
|
|
3460
|
-
|
|
3461
|
-
"
|
|
3462
|
-
|
|
4293
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-semibold", children: m.name || "Unnamed" }),
|
|
4294
|
+
parts.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-muted-foreground", children: [
|
|
4295
|
+
" \u2014 ",
|
|
4296
|
+
parts.join(" \xB7 ")
|
|
4297
|
+
] }),
|
|
4298
|
+
m.notes && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs text-muted-foreground mt-0.5", children: m.notes })
|
|
4299
|
+
]
|
|
4300
|
+
},
|
|
4301
|
+
idx
|
|
4302
|
+
);
|
|
4303
|
+
}) });
|
|
4304
|
+
}
|
|
4305
|
+
function renderAllergies(value) {
|
|
4306
|
+
if (!Array.isArray(value) || value.length === 0) return "No allergies";
|
|
4307
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col gap-2", children: value.map((allergy, idx) => {
|
|
4308
|
+
const a = allergy;
|
|
4309
|
+
const sevColor = SEVERITY_COLORS[a.severity];
|
|
4310
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
4311
|
+
"div",
|
|
4312
|
+
{
|
|
4313
|
+
className: "px-3 py-2 border border-border rounded-md text-[13px] flex items-center gap-2 flex-wrap",
|
|
4314
|
+
children: [
|
|
4315
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-semibold", children: a.allergen || "Unknown" }),
|
|
4316
|
+
a.type && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-[11px] text-muted-foreground", children: [
|
|
4317
|
+
"(",
|
|
4318
|
+
a.type,
|
|
3463
4319
|
")"
|
|
3464
4320
|
] }),
|
|
3465
|
-
/* @__PURE__ */ jsxRuntime.
|
|
3466
|
-
"
|
|
3467
|
-
|
|
4321
|
+
a.severity && /* @__PURE__ */ jsxRuntime.jsx(
|
|
4322
|
+
"span",
|
|
4323
|
+
{
|
|
4324
|
+
className: "text-[11px] font-semibold px-2 py-0.5 rounded-full",
|
|
4325
|
+
style: {
|
|
4326
|
+
backgroundColor: sevColor ?? "var(--accent)",
|
|
4327
|
+
color: sevColor ? "#fff" : "var(--foreground)"
|
|
4328
|
+
},
|
|
4329
|
+
children: a.severity
|
|
4330
|
+
}
|
|
4331
|
+
),
|
|
4332
|
+
a.reaction && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs text-muted-foreground", children: [
|
|
4333
|
+
"\u2014 ",
|
|
4334
|
+
a.reaction
|
|
3468
4335
|
] })
|
|
3469
4336
|
]
|
|
4337
|
+
},
|
|
4338
|
+
idx
|
|
4339
|
+
);
|
|
4340
|
+
}) });
|
|
4341
|
+
}
|
|
4342
|
+
function renderBmi(value) {
|
|
4343
|
+
if (typeof value !== "object" || value === null) return formatFallbackValue(value);
|
|
4344
|
+
const data = value;
|
|
4345
|
+
const bmi = data.bmi;
|
|
4346
|
+
const unit = data.unit ?? "imperial";
|
|
4347
|
+
const height = data.height;
|
|
4348
|
+
const weight = data.weight;
|
|
4349
|
+
const heightUnit = unit === "metric" ? "cm" : "in";
|
|
4350
|
+
const weightUnit = unit === "metric" ? "kg" : "lbs";
|
|
4351
|
+
const category = bmi != null ? getBmiCategory(bmi) : void 0;
|
|
4352
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-[13px] flex items-center gap-2 flex-wrap", children: [
|
|
4353
|
+
height != null && /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
|
|
4354
|
+
"Height: ",
|
|
4355
|
+
height,
|
|
4356
|
+
" ",
|
|
4357
|
+
heightUnit
|
|
4358
|
+
] }),
|
|
4359
|
+
height != null && weight != null && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: "|" }),
|
|
4360
|
+
weight != null && /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
|
|
4361
|
+
"Weight: ",
|
|
4362
|
+
weight,
|
|
4363
|
+
" ",
|
|
4364
|
+
weightUnit
|
|
4365
|
+
] }),
|
|
4366
|
+
bmi != null && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
4367
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: "\u2014" }),
|
|
4368
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-semibold", children: [
|
|
4369
|
+
"BMI: ",
|
|
4370
|
+
bmi
|
|
4371
|
+
] }),
|
|
4372
|
+
category && /* @__PURE__ */ jsxRuntime.jsx(
|
|
4373
|
+
"span",
|
|
4374
|
+
{
|
|
4375
|
+
className: "text-[11px] font-semibold px-2 py-0.5 rounded-full text-white",
|
|
4376
|
+
style: { backgroundColor: category.color },
|
|
4377
|
+
children: category.label
|
|
4378
|
+
}
|
|
4379
|
+
)
|
|
4380
|
+
] })
|
|
4381
|
+
] });
|
|
4382
|
+
}
|
|
4383
|
+
function renderBodyDiagram(value) {
|
|
4384
|
+
if (!Array.isArray(value) || value.length === 0) return "No regions selected";
|
|
4385
|
+
const labels = value.map((id) => BODY_REGION_LABELS[id] ?? id);
|
|
4386
|
+
return /* @__PURE__ */ jsxRuntime.jsx("span", { children: labels.join(", ") });
|
|
4387
|
+
}
|
|
4388
|
+
function renderPainScale(value) {
|
|
4389
|
+
if (typeof value !== "number") return formatFallbackValue(value);
|
|
4390
|
+
const face = getPainLabel(value);
|
|
4391
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-semibold", style: { color: face?.color }, children: [
|
|
4392
|
+
value,
|
|
4393
|
+
"/10",
|
|
4394
|
+
face ? ` \u2014 ${face.label}` : ""
|
|
4395
|
+
] });
|
|
4396
|
+
}
|
|
4397
|
+
function renderInsurance(value) {
|
|
4398
|
+
if (typeof value !== "object" || value === null) return formatFallbackValue(value);
|
|
4399
|
+
const ins = value;
|
|
4400
|
+
const textFields = [
|
|
4401
|
+
{ key: "carrierId", label: "Carrier" },
|
|
4402
|
+
{ key: "planName", label: "Plan" },
|
|
4403
|
+
{ key: "memberId", label: "Member ID" },
|
|
4404
|
+
{ key: "groupNumber", label: "Group #" },
|
|
4405
|
+
{ key: "subscriberName", label: "Subscriber" },
|
|
4406
|
+
{ key: "relationship", label: "Relationship" }
|
|
4407
|
+
];
|
|
4408
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-2", children: [
|
|
4409
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-2 gap-x-3 gap-y-1 text-[13px]", children: textFields.map(({ key, label }) => {
|
|
4410
|
+
const val = ins[key];
|
|
4411
|
+
if (!val) return null;
|
|
4412
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
4413
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-muted-foreground", children: [
|
|
4414
|
+
label,
|
|
4415
|
+
": "
|
|
4416
|
+
] }),
|
|
4417
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: String(val) })
|
|
4418
|
+
] }, key);
|
|
4419
|
+
}) }),
|
|
4420
|
+
!!(ins.frontImage || ins.backImage) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-2 mt-1", children: [
|
|
4421
|
+
typeof ins.frontImage === "string" && /* @__PURE__ */ jsxRuntime.jsx(
|
|
4422
|
+
"img",
|
|
4423
|
+
{
|
|
4424
|
+
src: ins.frontImage,
|
|
4425
|
+
alt: "Front of card",
|
|
4426
|
+
className: "h-12 rounded border border-border"
|
|
4427
|
+
}
|
|
4428
|
+
),
|
|
4429
|
+
typeof ins.backImage === "string" && /* @__PURE__ */ jsxRuntime.jsx(
|
|
4430
|
+
"img",
|
|
4431
|
+
{
|
|
4432
|
+
src: ins.backImage,
|
|
4433
|
+
alt: "Back of card",
|
|
4434
|
+
className: "h-12 rounded border border-border"
|
|
4435
|
+
}
|
|
4436
|
+
)
|
|
4437
|
+
] })
|
|
4438
|
+
] });
|
|
4439
|
+
}
|
|
4440
|
+
function renderPayment(value) {
|
|
4441
|
+
if (typeof value !== "object" || value === null) return formatFallbackValue(value);
|
|
4442
|
+
const payment = value;
|
|
4443
|
+
const status = payment.status;
|
|
4444
|
+
const statusConfig = {
|
|
4445
|
+
succeeded: { bg: "#22c55e", label: "Succeeded" },
|
|
4446
|
+
failed: { bg: "#ef4444", label: "Failed" },
|
|
4447
|
+
processing: { bg: "#eab308", label: "Processing" }
|
|
4448
|
+
};
|
|
4449
|
+
const cfg = statusConfig[status];
|
|
4450
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 text-[13px]", children: [
|
|
4451
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4452
|
+
"span",
|
|
4453
|
+
{
|
|
4454
|
+
className: "text-[11px] font-semibold px-2.5 py-0.5 rounded-full text-white",
|
|
4455
|
+
style: { backgroundColor: cfg?.bg ?? "var(--accent)" },
|
|
4456
|
+
children: cfg?.label ?? status
|
|
3470
4457
|
}
|
|
3471
|
-
)
|
|
4458
|
+
),
|
|
4459
|
+
!!payment.chargeId && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-muted-foreground", children: String(payment.chargeId) }),
|
|
4460
|
+
!!payment.error && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-destructive", children: String(payment.error) })
|
|
3472
4461
|
] });
|
|
3473
4462
|
}
|
|
3474
|
-
function
|
|
4463
|
+
function renderLegalName(value) {
|
|
4464
|
+
if (typeof value !== "object" || value === null) return formatFallbackValue(value);
|
|
4465
|
+
const name = value;
|
|
4466
|
+
const parts = [name.first, name.middle, name.last].filter(Boolean);
|
|
4467
|
+
return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: parts.join(" ") || "\u2014" });
|
|
4468
|
+
}
|
|
4469
|
+
function renderAddress(value) {
|
|
4470
|
+
if (typeof value !== "object" || value === null) return formatFallbackValue(value);
|
|
4471
|
+
const addr = value;
|
|
4472
|
+
const line1 = [addr.street, addr.street2].filter(Boolean).join(", ");
|
|
4473
|
+
const line2 = [addr.city, addr.state, addr.zip].filter(Boolean).join(", ");
|
|
4474
|
+
const full = [line1, line2].filter(Boolean).join(", ");
|
|
4475
|
+
return /* @__PURE__ */ jsxRuntime.jsx("span", { children: full || "\u2014" });
|
|
4476
|
+
}
|
|
4477
|
+
function renderConsent(value) {
|
|
4478
|
+
const agreed = value === true || value === "true" || value === "agreed";
|
|
4479
|
+
return /* @__PURE__ */ jsxRuntime.jsx("span", { className: agreed ? "font-semibold text-green-500" : "font-semibold text-muted-foreground", children: agreed ? "Agreed" : "Not agreed" });
|
|
4480
|
+
}
|
|
4481
|
+
function renderSignature(value) {
|
|
4482
|
+
if (typeof value !== "string") return formatFallbackValue(value);
|
|
4483
|
+
if (value.startsWith("data:image")) {
|
|
4484
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
4485
|
+
"img",
|
|
4486
|
+
{
|
|
4487
|
+
src: value,
|
|
4488
|
+
alt: "Signature",
|
|
4489
|
+
className: "h-15 border border-border rounded"
|
|
4490
|
+
}
|
|
4491
|
+
);
|
|
4492
|
+
}
|
|
4493
|
+
return /* @__PURE__ */ jsxRuntime.jsx("span", { children: value });
|
|
4494
|
+
}
|
|
4495
|
+
function formatFallbackValue(value) {
|
|
3475
4496
|
if (value == null) return "\u2014";
|
|
3476
4497
|
if (typeof value === "boolean") return value ? "Yes" : "No";
|
|
3477
|
-
if (Array.isArray(value)) return value.map(
|
|
4498
|
+
if (Array.isArray(value)) return value.map(formatFallbackValue).join(", ");
|
|
3478
4499
|
if (typeof value === "object") return JSON.stringify(value, null, 2);
|
|
3479
4500
|
return String(value);
|
|
3480
4501
|
}
|
|
3481
|
-
|
|
3482
|
-
|
|
3483
|
-
|
|
3484
|
-
|
|
3485
|
-
|
|
3486
|
-
|
|
3487
|
-
|
|
3488
|
-
|
|
3489
|
-
|
|
3490
|
-
|
|
3491
|
-
|
|
3492
|
-
|
|
4502
|
+
|
|
4503
|
+
// src/response-viewer/export-utils.ts
|
|
4504
|
+
function exportToCsv(schema, responses, filename = "responses.csv") {
|
|
4505
|
+
const questions = getExportableQuestions(schema);
|
|
4506
|
+
const headers = ["Submitted", ...questions.map((q) => q.label), "Score"];
|
|
4507
|
+
const rows = responses.map((r) => {
|
|
4508
|
+
const submitted = new Date(r.submittedAt).toLocaleString();
|
|
4509
|
+
const values = questions.map((q) => formatExportValue(r.values[q.id], q.type));
|
|
4510
|
+
const score = r.totalScore != null ? String(r.totalScore) : "";
|
|
4511
|
+
return [submitted, ...values, score];
|
|
4512
|
+
});
|
|
4513
|
+
const csvContent = [headers, ...rows].map((row) => row.map(escapeCsvField).join(",")).join("\n");
|
|
4514
|
+
downloadBlob(csvContent, filename, "text/csv;charset=utf-8;");
|
|
4515
|
+
}
|
|
4516
|
+
function exportToJson(responses, filename = "responses.json") {
|
|
4517
|
+
const content = JSON.stringify(responses, null, 2);
|
|
4518
|
+
downloadBlob(content, filename, "application/json;charset=utf-8;");
|
|
4519
|
+
}
|
|
4520
|
+
function getExportableQuestions(schema) {
|
|
4521
|
+
const questions = [];
|
|
4522
|
+
for (const section of schema.sections) {
|
|
4523
|
+
for (const q of section.questions) {
|
|
4524
|
+
if (q.type === "info-block" || q.type === "section-header" || q.type === "page-break") {
|
|
4525
|
+
continue;
|
|
4526
|
+
}
|
|
4527
|
+
questions.push(q);
|
|
4528
|
+
}
|
|
4529
|
+
}
|
|
4530
|
+
return questions;
|
|
4531
|
+
}
|
|
4532
|
+
function formatExportValue(value, type) {
|
|
4533
|
+
if (value == null) return "";
|
|
4534
|
+
switch (type) {
|
|
4535
|
+
case "vitals_entry": {
|
|
4536
|
+
if (typeof value !== "object" || value === null) break;
|
|
4537
|
+
const v = value;
|
|
4538
|
+
const parts = [];
|
|
4539
|
+
if (v.systolicBp && v.diastolicBp) parts.push(`BP ${v.systolicBp}/${v.diastolicBp}`);
|
|
4540
|
+
if (v.heartRate) parts.push(`HR ${v.heartRate}`);
|
|
4541
|
+
if (v.temperature) parts.push(`${v.temperature}\xB0F`);
|
|
4542
|
+
if (v.oxygenSaturation) parts.push(`SpO2 ${v.oxygenSaturation}%`);
|
|
4543
|
+
return parts.join("; ");
|
|
4544
|
+
}
|
|
4545
|
+
case "medication_list":
|
|
4546
|
+
if (Array.isArray(value)) {
|
|
4547
|
+
return value.map((m) => [m.name, m.dosage, m.frequency].filter(Boolean).join(" ")).join("; ");
|
|
4548
|
+
}
|
|
4549
|
+
break;
|
|
4550
|
+
case "allergy_list":
|
|
4551
|
+
if (Array.isArray(value)) {
|
|
4552
|
+
return value.map((a) => [a.allergen, a.severity].filter(Boolean).join(" - ")).join("; ");
|
|
4553
|
+
}
|
|
4554
|
+
break;
|
|
4555
|
+
case "body_diagram":
|
|
4556
|
+
if (Array.isArray(value)) {
|
|
4557
|
+
return value.map((id) => BODY_REGION_LABELS[id] ?? id).join("; ");
|
|
4558
|
+
}
|
|
4559
|
+
break;
|
|
4560
|
+
case "pain_scale":
|
|
4561
|
+
return typeof value === "number" ? `${value}/10` : String(value);
|
|
4562
|
+
case "bmi_calculator": {
|
|
4563
|
+
if (typeof value !== "object" || value === null) break;
|
|
4564
|
+
const d = value;
|
|
4565
|
+
return d.bmi != null ? `BMI ${d.bmi}` : "";
|
|
4566
|
+
}
|
|
4567
|
+
case "payment": {
|
|
4568
|
+
if (typeof value !== "object" || value === null) break;
|
|
4569
|
+
return value.status ?? "";
|
|
4570
|
+
}
|
|
4571
|
+
case "legal_name": {
|
|
4572
|
+
if (typeof value !== "object" || value === null) break;
|
|
4573
|
+
const n = value;
|
|
4574
|
+
return [n.first, n.middle, n.last].filter(Boolean).join(" ");
|
|
4575
|
+
}
|
|
4576
|
+
case "address": {
|
|
4577
|
+
if (typeof value !== "object" || value === null) break;
|
|
4578
|
+
const a = value;
|
|
4579
|
+
return [a.street, a.city, a.state, a.zip].filter(Boolean).join(", ");
|
|
4580
|
+
}
|
|
4581
|
+
case "consent":
|
|
4582
|
+
return value === true || value === "true" || value === "agreed" ? "Agreed" : "Not agreed";
|
|
4583
|
+
case "signature":
|
|
4584
|
+
return typeof value === "string" && value.startsWith("data:image") ? "Signed" : "";
|
|
4585
|
+
}
|
|
4586
|
+
if (typeof value === "boolean") return value ? "Yes" : "No";
|
|
4587
|
+
if (Array.isArray(value)) return value.join("; ");
|
|
4588
|
+
if (typeof value === "object") return JSON.stringify(value);
|
|
4589
|
+
return String(value);
|
|
4590
|
+
}
|
|
4591
|
+
function escapeCsvField(field) {
|
|
4592
|
+
if (field.includes(",") || field.includes('"') || field.includes("\n")) {
|
|
4593
|
+
return `"${field.replace(/"/g, '""')}"`;
|
|
4594
|
+
}
|
|
4595
|
+
return field;
|
|
4596
|
+
}
|
|
4597
|
+
function downloadBlob(content, filename, mimeType) {
|
|
4598
|
+
const blob = new Blob([content], { type: mimeType });
|
|
4599
|
+
const url = URL.createObjectURL(blob);
|
|
4600
|
+
const link = document.createElement("a");
|
|
4601
|
+
link.href = url;
|
|
4602
|
+
link.download = filename;
|
|
4603
|
+
document.body.appendChild(link);
|
|
4604
|
+
link.click();
|
|
4605
|
+
document.body.removeChild(link);
|
|
4606
|
+
URL.revokeObjectURL(url);
|
|
4607
|
+
}
|
|
3493
4608
|
function ResponseViewerInner({
|
|
3494
4609
|
schema,
|
|
3495
4610
|
responses,
|
|
@@ -3515,62 +4630,73 @@ function ResponseViewerInner({
|
|
|
3515
4630
|
value: response.values[q.id]
|
|
3516
4631
|
}));
|
|
3517
4632
|
}
|
|
4633
|
+
const heightValue = typeof height === "number" ? `${height}px` : height;
|
|
4634
|
+
const widthValue = typeof width === "number" ? `${width}px` : width;
|
|
3518
4635
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3519
4636
|
"div",
|
|
3520
4637
|
{
|
|
3521
|
-
|
|
3522
|
-
|
|
3523
|
-
flexDirection: "column",
|
|
3524
|
-
height: typeof height === "number" ? `${height}px` : height,
|
|
3525
|
-
width: typeof width === "number" ? `${width}px` : width,
|
|
3526
|
-
border: "1px solid var(--border, #1c1c20)",
|
|
3527
|
-
borderRadius: "8px",
|
|
3528
|
-
overflow: "hidden",
|
|
3529
|
-
fontFamily: "inherit",
|
|
3530
|
-
backgroundColor: "var(--background, #0a0a0b)",
|
|
3531
|
-
color: "var(--foreground, #e8e8ea)"
|
|
3532
|
-
},
|
|
4638
|
+
className: "flex flex-col border border-border rounded-lg overflow-hidden bg-background text-foreground",
|
|
4639
|
+
style: { height: heightValue, width: widthValue },
|
|
3533
4640
|
children: [
|
|
3534
|
-
!selectedResponse && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3535
|
-
"div",
|
|
3536
|
-
|
|
3537
|
-
|
|
3538
|
-
|
|
3539
|
-
|
|
3540
|
-
|
|
3541
|
-
|
|
3542
|
-
|
|
3543
|
-
|
|
3544
|
-
|
|
3545
|
-
|
|
3546
|
-
|
|
3547
|
-
|
|
3548
|
-
|
|
3549
|
-
] }),
|
|
3550
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", gap: "4px" }, children: [
|
|
3551
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3552
|
-
"button",
|
|
3553
|
-
{
|
|
3554
|
-
type: "button",
|
|
3555
|
-
style: viewButtonStyle(viewMode === "table"),
|
|
3556
|
-
onClick: () => setViewMode("table"),
|
|
3557
|
-
children: "Table"
|
|
3558
|
-
}
|
|
4641
|
+
!selectedResponse && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-between items-center px-3 py-2 border-b border-border", children: [
|
|
4642
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-xs text-muted-foreground", children: [
|
|
4643
|
+
responses.length,
|
|
4644
|
+
" response",
|
|
4645
|
+
responses.length !== 1 ? "s" : ""
|
|
4646
|
+
] }),
|
|
4647
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1", children: [
|
|
4648
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4649
|
+
fieldcraftReact.Button,
|
|
4650
|
+
{
|
|
4651
|
+
variant: viewMode === "table" ? "secondary" : "ghost",
|
|
4652
|
+
size: "sm",
|
|
4653
|
+
className: cn(
|
|
4654
|
+
"h-7 text-xs",
|
|
4655
|
+
viewMode === "table" && "font-semibold border border-ring"
|
|
3559
4656
|
),
|
|
3560
|
-
|
|
3561
|
-
|
|
3562
|
-
|
|
3563
|
-
|
|
3564
|
-
|
|
3565
|
-
|
|
3566
|
-
|
|
3567
|
-
|
|
3568
|
-
|
|
3569
|
-
|
|
3570
|
-
|
|
3571
|
-
|
|
3572
|
-
|
|
3573
|
-
|
|
4657
|
+
onClick: () => setViewMode("table"),
|
|
4658
|
+
children: "Table"
|
|
4659
|
+
}
|
|
4660
|
+
),
|
|
4661
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4662
|
+
fieldcraftReact.Button,
|
|
4663
|
+
{
|
|
4664
|
+
variant: viewMode === "card" ? "secondary" : "ghost",
|
|
4665
|
+
size: "sm",
|
|
4666
|
+
className: cn(
|
|
4667
|
+
"h-7 text-xs",
|
|
4668
|
+
viewMode === "card" && "font-semibold border border-ring"
|
|
4669
|
+
),
|
|
4670
|
+
onClick: () => setViewMode("card"),
|
|
4671
|
+
children: "Cards"
|
|
4672
|
+
}
|
|
4673
|
+
),
|
|
4674
|
+
/* @__PURE__ */ jsxRuntime.jsx(fieldcraftReact.Separator, { orientation: "vertical", className: "h-5 mx-1" }),
|
|
4675
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4676
|
+
fieldcraftReact.Button,
|
|
4677
|
+
{
|
|
4678
|
+
variant: "outline",
|
|
4679
|
+
size: "sm",
|
|
4680
|
+
className: "h-7 text-xs",
|
|
4681
|
+
onClick: () => exportToCsv(schema, responses),
|
|
4682
|
+
disabled: responses.length === 0,
|
|
4683
|
+
children: "Export CSV"
|
|
4684
|
+
}
|
|
4685
|
+
),
|
|
4686
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4687
|
+
fieldcraftReact.Button,
|
|
4688
|
+
{
|
|
4689
|
+
variant: "outline",
|
|
4690
|
+
size: "sm",
|
|
4691
|
+
className: "h-7 text-xs",
|
|
4692
|
+
onClick: () => exportToJson(responses),
|
|
4693
|
+
disabled: responses.length === 0,
|
|
4694
|
+
children: "Export JSON"
|
|
4695
|
+
}
|
|
4696
|
+
)
|
|
4697
|
+
] })
|
|
4698
|
+
] }),
|
|
4699
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("flex-1 overflow-auto", selectedResponse && "p-4"), children: selectedResponse ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
3574
4700
|
ResponseDetail,
|
|
3575
4701
|
{
|
|
3576
4702
|
response: selectedResponse,
|
|
@@ -3584,29 +4710,18 @@ function ResponseViewerInner({
|
|
|
3584
4710
|
responses,
|
|
3585
4711
|
onRowClick: handleSelect
|
|
3586
4712
|
}
|
|
3587
|
-
) : /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3588
|
-
|
|
3589
|
-
|
|
3590
|
-
|
|
3591
|
-
|
|
3592
|
-
|
|
3593
|
-
|
|
3594
|
-
padding: "12px"
|
|
4713
|
+
) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid gap-3 p-3 grid-cols-[repeat(auto-fill,minmax(280px,1fr))]", children: [
|
|
4714
|
+
responses.map((response, idx) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
4715
|
+
ResponseCard,
|
|
4716
|
+
{
|
|
4717
|
+
response,
|
|
4718
|
+
fields: getFields(response),
|
|
4719
|
+
onClick: () => handleSelect(response)
|
|
3595
4720
|
},
|
|
3596
|
-
|
|
3597
|
-
|
|
3598
|
-
|
|
3599
|
-
|
|
3600
|
-
response,
|
|
3601
|
-
fields: getFields(response),
|
|
3602
|
-
onClick: () => handleSelect(response)
|
|
3603
|
-
},
|
|
3604
|
-
response.sessionToken || idx
|
|
3605
|
-
)),
|
|
3606
|
-
responses.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { style: { padding: "32px", textAlign: "center", color: "var(--muted-foreground, #8a8a95)" }, children: "No responses yet" })
|
|
3607
|
-
]
|
|
3608
|
-
}
|
|
3609
|
-
) })
|
|
4721
|
+
response.sessionToken || idx
|
|
4722
|
+
)),
|
|
4723
|
+
responses.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-8 text-center text-muted-foreground", children: "No responses yet" })
|
|
4724
|
+
] }) })
|
|
3610
4725
|
]
|
|
3611
4726
|
}
|
|
3612
4727
|
);
|
|
@@ -3625,7 +4740,7 @@ function getAllQuestions2(schema) {
|
|
|
3625
4740
|
}
|
|
3626
4741
|
|
|
3627
4742
|
// src/response-viewer/ResponseViewer.tsx
|
|
3628
|
-
var ResponseViewer =
|
|
4743
|
+
var ResponseViewer = requireLicense(ResponseViewerInner, "ResponseViewer");
|
|
3629
4744
|
|
|
3630
4745
|
// src/theme-editor/preview-schema.ts
|
|
3631
4746
|
var PREVIEW_SCHEMA = {
|
|
@@ -4026,12 +5141,12 @@ function ThemeEditorInner({
|
|
|
4026
5141
|
}
|
|
4027
5142
|
|
|
4028
5143
|
// src/theme-editor/ThemeEditor.tsx
|
|
4029
|
-
var ThemeEditor =
|
|
5144
|
+
var ThemeEditor = requireLicense(ThemeEditorInner, "ThemeEditor");
|
|
4030
5145
|
|
|
4031
5146
|
// src/index.ts
|
|
4032
5147
|
if (typeof globalThis !== "undefined" && typeof globalThis.process !== "undefined" && globalThis.process.env?.NODE_ENV !== "production") {
|
|
4033
5148
|
const _fc_banner = `
|
|
4034
|
-
%c FieldCraft Pro %c
|
|
5149
|
+
%c FieldCraft Pro %c v1.0.1
|
|
4035
5150
|
|
|
4036
5151
|
%cForm Builder \xB7 Response Viewer \xB7 Theme Editor
|
|
4037
5152
|
|
|
@@ -4049,32 +5164,9 @@ Need a license? \u2192 https://squaredr.tech/products/fieldcraft/admin-pro#prici
|
|
|
4049
5164
|
);
|
|
4050
5165
|
}
|
|
4051
5166
|
|
|
4052
|
-
Object.defineProperty(exports, "FieldCraftProProvider", {
|
|
4053
|
-
enumerable: true,
|
|
4054
|
-
get: function () { return fieldcraftProLicense.FieldCraftProProvider; }
|
|
4055
|
-
});
|
|
4056
|
-
Object.defineProperty(exports, "UnlicensedOverlay", {
|
|
4057
|
-
enumerable: true,
|
|
4058
|
-
get: function () { return fieldcraftProLicense.UnlicensedOverlay; }
|
|
4059
|
-
});
|
|
4060
|
-
Object.defineProperty(exports, "isProductionEnvironment", {
|
|
4061
|
-
enumerable: true,
|
|
4062
|
-
get: function () { return fieldcraftProLicense.isProductionEnvironment; }
|
|
4063
|
-
});
|
|
4064
|
-
Object.defineProperty(exports, "requireLicense", {
|
|
4065
|
-
enumerable: true,
|
|
4066
|
-
get: function () { return fieldcraftProLicense.requireLicense; }
|
|
4067
|
-
});
|
|
4068
|
-
Object.defineProperty(exports, "useLicense", {
|
|
4069
|
-
enumerable: true,
|
|
4070
|
-
get: function () { return fieldcraftProLicense.useLicense; }
|
|
4071
|
-
});
|
|
4072
|
-
Object.defineProperty(exports, "validateLicense", {
|
|
4073
|
-
enumerable: true,
|
|
4074
|
-
get: function () { return fieldcraftProLicense.validateLicense; }
|
|
4075
|
-
});
|
|
4076
5167
|
exports.DEFAULT_PALETTE = DEFAULT_PALETTE;
|
|
4077
5168
|
exports.DEFAULT_SCHEMA = DEFAULT_SCHEMA;
|
|
5169
|
+
exports.FieldCraftProProvider = FieldCraftProProvider;
|
|
4078
5170
|
exports.FormBuilder = FormBuilder;
|
|
4079
5171
|
exports.FormBuilderThemeProvider = FormBuilderThemeProvider;
|
|
4080
5172
|
exports.PREVIEW_SCHEMA = PREVIEW_SCHEMA;
|
|
@@ -4082,6 +5174,7 @@ exports.QUESTION_TYPE_INFO = QUESTION_TYPE_INFO;
|
|
|
4082
5174
|
exports.ResponseViewer = ResponseViewer;
|
|
4083
5175
|
exports.ThemeEditor = ThemeEditor;
|
|
4084
5176
|
exports.ThemeEditorInner = ThemeEditorInner;
|
|
5177
|
+
exports.UnlicensedOverlay = UnlicensedOverlay;
|
|
4085
5178
|
exports.addOption = addOption;
|
|
4086
5179
|
exports.addQuestion = addQuestion;
|
|
4087
5180
|
exports.addSection = addSection;
|
|
@@ -4095,12 +5188,14 @@ exports.generateId = generateId;
|
|
|
4095
5188
|
exports.generateOptionId = generateOptionId;
|
|
4096
5189
|
exports.generateQuestionId = generateQuestionId;
|
|
4097
5190
|
exports.generateSectionId = generateSectionId;
|
|
5191
|
+
exports.isProductionEnvironment = isProductionEnvironment;
|
|
4098
5192
|
exports.moveOption = moveOption;
|
|
4099
5193
|
exports.moveQuestion = moveQuestion;
|
|
4100
5194
|
exports.moveSection = moveSection;
|
|
4101
5195
|
exports.removeOption = removeOption;
|
|
4102
5196
|
exports.removeQuestion = removeQuestion;
|
|
4103
5197
|
exports.removeSection = removeSection;
|
|
5198
|
+
exports.requireLicense = requireLicense;
|
|
4104
5199
|
exports.squaredrDarkPreset = squaredrDarkPreset;
|
|
4105
5200
|
exports.updateOption = updateOption;
|
|
4106
5201
|
exports.updateQuestion = updateQuestion;
|
|
@@ -4108,4 +5203,6 @@ exports.updateSection = updateSection;
|
|
|
4108
5203
|
exports.useBuilderState = useBuilderState;
|
|
4109
5204
|
exports.useBuilderTheme = useBuilderTheme;
|
|
4110
5205
|
exports.useDragDrop = useDragDrop;
|
|
5206
|
+
exports.useLicense = useLicense;
|
|
4111
5207
|
exports.useUndoRedo = useUndoRedo;
|
|
5208
|
+
exports.validateLicense = validateLicense;
|