@squaredr/fieldcraft-pro 1.6.4 → 1.7.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/dist/index.js CHANGED
@@ -11,38 +11,18 @@ var tailwindMerge = require('tailwind-merge');
11
11
  var react$1 = require('@xyflow/react');
12
12
  require('@xyflow/react/dist/style.css');
13
13
 
14
- // ../license/dist/index.mjs
14
+ // package.json
15
+ var version = "1.6.4";
16
+ var PRODUCT_IDS = {
17
+ FIELDCRAFT_PRO: 1
18
+ };
15
19
  var LEGACY_TIER_MAP = {
16
20
  "01": "starter",
17
21
  "02": "pro",
18
22
  "03": "business",
19
23
  "04": "enterprise"
20
24
  };
21
- var TIER_MAP_NUMERIC = {
22
- 1: "starter",
23
- 2: "pro",
24
- 3: "business",
25
- 4: "enterprise"
26
- };
27
- var PRO_FEATURES = [
28
- "SchemaEditor",
29
- "ResponseViewer",
30
- "ThemeEditor",
31
- "FormBuilder",
32
- "ApiManager",
33
- "Analytics"
34
- ];
35
- var ALL_FEATURES = [
36
- ...PRO_FEATURES,
37
- "Telehealth"
38
- ];
39
- var TIER_FEATURES = {
40
- starter: ["SchemaEditor", "ResponseViewer"],
41
- pro: PRO_FEATURES,
42
- business: ALL_FEATURES,
43
- enterprise: ALL_FEATURES
44
- };
45
- var HMAC_SECRET = "e50a657813a5ab9563050728a605b9ab58b911d5c1a9f48c6825f379a533ccd7685d11d01937d9f135776a0db3efeefe29b3e5282b27ede8cee93758f94f2d75";
25
+ var HMAC_SECRET = "15bb3af8d82d01de70ab556c5785fd92461e336b941ed65cf99834d5e99924e742db9a9197056b531bf0f429df621be17cb71d8ba5e892075e1b4283969657dc3bbf4d0287cf15804d5482510b8a405bb33a69249e8007a8a3c2af0d499423623dafecb719d985a4ad8e2edf8623936db90387ea3139f8d0eeb2556e408a0d6de69c034e33e1e6a0633af0eeeb63dd13f4711ba0a0aacc3af6b87bdace13a7886013d3a5410817966f0af7230f277b6207ad5de2916f6c0bfab5c2a18ccfe72d513bb726206d8929e8b01d91f6bf38572c0f238302c4fdf0263c7bd0c48cf0e1678f94de727b61388c672c11e82ecb96591d264731177d7588d92cdf70ea46a2";
46
26
  var B32_CHARS = "0123456789ABCDEFGHIJKLMNOPQRSTUV";
47
27
  function base32hexDecode(str) {
48
28
  const upper = str.toUpperCase();
@@ -76,14 +56,15 @@ function parseOpaqueKey(key) {
76
56
  if (!stripped.startsWith("FCPRO")) return null;
77
57
  const encoded = stripped.slice(5);
78
58
  const decoded = base32hexDecode(encoded);
79
- if (!decoded || decoded.length < 17) return null;
80
- const tier = decoded[0];
81
- if (!(tier in TIER_MAP_NUMERIC)) return null;
82
- const expiryTimestamp = decoded[1] << 24 | decoded[2] << 16 | decoded[3] << 8 | decoded[4];
83
- const expiryUnsigned = expiryTimestamp >>> 0;
84
- const nonce = decoded.slice(5, 9);
85
- const signature = decoded.slice(9, 17);
86
- return { format: "opaque", tier, expiryTimestamp: expiryUnsigned, nonce, signature };
59
+ if (!decoded || decoded.length < 25) return null;
60
+ const productId = decoded[0];
61
+ if (productId !== PRODUCT_IDS.FIELDCRAFT_PRO) return null;
62
+ const purchaseTimestamp = (decoded[1] << 24 | decoded[2] << 16 | decoded[3] << 8 | decoded[4]) >>> 0;
63
+ const expiryTimestamp = (decoded[5] << 24 | decoded[6] << 16 | decoded[7] << 8 | decoded[8]) >>> 0;
64
+ const emailHash = decoded.slice(9, 13);
65
+ const nonce = decoded.slice(13, 17);
66
+ const signature = decoded.slice(17, 25);
67
+ return { format: "opaque", productId, purchaseTimestamp, expiryTimestamp, emailHash, nonce, signature };
87
68
  }
88
69
  function parseKey(key) {
89
70
  if (!key || typeof key !== "string") return null;
@@ -129,54 +110,52 @@ function isExpiredOpaque(expiryTimestamp) {
129
110
  if (expiryTimestamp === 4294967295) return false;
130
111
  return Date.now() / 1e3 > expiryTimestamp;
131
112
  }
113
+ function timingSafeEqual(a, b) {
114
+ if (a.length !== b.length) return false;
115
+ let result = 0;
116
+ for (let i = 0; i < a.length; i++) {
117
+ result |= a[i] ^ b[i];
118
+ }
119
+ return result === 0;
120
+ }
132
121
  async function validateLicense(key) {
133
122
  if (!key || typeof key !== "string") {
134
- return { status: "invalid", tier: null };
123
+ return { status: "invalid" };
135
124
  }
136
125
  const parsed = parseKey(key);
137
126
  if (!parsed) {
138
- return { status: "invalid", tier: null };
127
+ return { status: "invalid" };
139
128
  }
140
129
  if (parsed.format === "opaque") {
141
- const payload = new Uint8Array(9);
142
- payload[0] = parsed.tier;
143
- payload[1] = parsed.expiryTimestamp >>> 24 & 255;
144
- payload[2] = parsed.expiryTimestamp >>> 16 & 255;
145
- payload[3] = parsed.expiryTimestamp >>> 8 & 255;
146
- payload[4] = parsed.expiryTimestamp & 255;
147
- payload.set(parsed.nonce, 5);
130
+ const payload = new Uint8Array(17);
131
+ payload[0] = parsed.productId;
132
+ payload[1] = parsed.purchaseTimestamp >>> 24 & 255;
133
+ payload[2] = parsed.purchaseTimestamp >>> 16 & 255;
134
+ payload[3] = parsed.purchaseTimestamp >>> 8 & 255;
135
+ payload[4] = parsed.purchaseTimestamp & 255;
136
+ payload[5] = parsed.expiryTimestamp >>> 24 & 255;
137
+ payload[6] = parsed.expiryTimestamp >>> 16 & 255;
138
+ payload[7] = parsed.expiryTimestamp >>> 8 & 255;
139
+ payload[8] = parsed.expiryTimestamp & 255;
140
+ payload.set(parsed.emailHash, 9);
141
+ payload.set(parsed.nonce, 13);
148
142
  const expectedSig = await computeHmacOpaque(payload);
149
- let match = true;
150
- for (let i = 0; i < 8; i++) {
151
- if (parsed.signature[i] !== expectedSig[i]) {
152
- match = false;
153
- break;
154
- }
155
- }
156
- if (!match) {
157
- return { status: "invalid", tier: null };
158
- }
159
- const tier2 = TIER_MAP_NUMERIC[parsed.tier];
160
- if (!tier2) {
161
- return { status: "invalid", tier: null };
143
+ if (!timingSafeEqual(parsed.signature, expectedSig)) {
144
+ return { status: "invalid" };
162
145
  }
163
146
  if (isExpiredOpaque(parsed.expiryTimestamp)) {
164
- return { status: "expired", tier: tier2 };
147
+ return { status: "expired" };
165
148
  }
166
- return { status: "valid", tier: tier2 };
149
+ return { status: "valid" };
167
150
  }
168
151
  const expectedHash = await computeHmacLegacy(parsed.tierHex, parsed.expiryHex);
169
152
  if (parsed.hash.toUpperCase() !== expectedHash) {
170
- return { status: "invalid", tier: null };
153
+ return { status: "invalid" };
171
154
  }
172
- const tier = LEGACY_TIER_MAP[parsed.tierHex];
173
155
  if (isExpiredLegacy(parsed.expiryHex)) {
174
- return { status: "expired", tier };
156
+ return { status: "expired" };
175
157
  }
176
- return { status: "valid", tier };
177
- }
178
- function tierHasFeature(tier, featureName) {
179
- return TIER_FEATURES[tier]?.includes(featureName) ?? false;
158
+ return { status: "valid" };
180
159
  }
181
160
  var DEV_HOSTNAMES = /* @__PURE__ */ new Set([
182
161
  "localhost",
@@ -249,7 +228,7 @@ function isProductionEnvironment() {
249
228
  }
250
229
  return false;
251
230
  }
252
- var PING_URL = "https://squaredr.tech/api/license/ping";
231
+ var PING_URL = typeof process !== "undefined" && process.env?.NEXT_PUBLIC_FCPRO_PING_URL || "https://fieldcraft.dev/api/license/ping";
253
232
  var CACHE_KEY = "fcpro_lp";
254
233
  var CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
255
234
  function hashKey(key) {
@@ -277,10 +256,10 @@ function readCache(key) {
277
256
  return null;
278
257
  }
279
258
  }
280
- function writeCache(key, status, tier, reason = null) {
259
+ function writeCache(key, status, reason = null) {
281
260
  if (typeof window === "undefined" || !window.localStorage) return;
282
261
  try {
283
- const entry = { s: status, t: tier, r: reason, ts: Date.now() };
262
+ const entry = { s: status, r: reason, ts: Date.now() };
284
263
  localStorage.setItem(cacheId(key), JSON.stringify(entry));
285
264
  } catch {
286
265
  }
@@ -288,12 +267,12 @@ function writeCache(key, status, tier, reason = null) {
288
267
  function getCachedPingResult(key) {
289
268
  const cached = readCache(key);
290
269
  if (!cached) return null;
291
- return { status: cached.s, tier: cached.t, reason: cached.r || void 0 };
270
+ return { status: cached.s, reason: cached.r || void 0 };
292
271
  }
293
272
  async function performPing(key) {
294
273
  const cached = readCache(key);
295
274
  if (cached) {
296
- return { status: cached.s, tier: cached.t };
275
+ return { status: cached.s };
297
276
  }
298
277
  try {
299
278
  const controller = new AbortController();
@@ -307,29 +286,28 @@ async function performPing(key) {
307
286
  clearTimeout(timeout);
308
287
  if (!res.ok) return null;
309
288
  const data = await res.json();
310
- const tier = data.tier || null;
311
289
  if (data.status === "active") {
312
- writeCache(key, "valid", tier);
313
- return { status: "valid", tier };
290
+ writeCache(key, "valid");
291
+ return { status: "valid" };
314
292
  }
315
293
  if (data.status === "revoked") {
316
- writeCache(key, "revoked", null, data.reason);
317
- return { status: "revoked", tier: null, reason: data.reason };
294
+ writeCache(key, "revoked", data.reason);
295
+ return { status: "revoked", reason: data.reason };
318
296
  }
319
297
  if (data.status === "expired") {
320
- writeCache(key, "expired", tier);
321
- return { status: "expired", tier };
298
+ writeCache(key, "expired");
299
+ return { status: "expired" };
322
300
  }
323
301
  if (data.status === "domain_mismatch") {
324
- writeCache(key, "domain_mismatch", null, data.reason);
325
- return { status: "domain_mismatch", tier: null, reason: data.reason };
302
+ writeCache(key, "domain_mismatch", data.reason);
303
+ return { status: "domain_mismatch", reason: data.reason };
326
304
  }
327
305
  return null;
328
306
  } catch {
329
307
  return null;
330
308
  }
331
309
  }
332
- var defaultContext = { status: "validating", tier: null };
310
+ var defaultContext = { status: "validating" };
333
311
  var LicenseCtx = react.createContext(defaultContext);
334
312
  function FieldCraftProProvider({ licenseKey, children }) {
335
313
  const [license, setLicense] = react.useState(defaultContext);
@@ -343,7 +321,7 @@ function FieldCraftProProvider({ licenseKey, children }) {
343
321
  const cached = getCachedPingResult(licenseKey);
344
322
  if (cached) {
345
323
  if (cached.status === "revoked" || cached.status === "domain_mismatch") {
346
- setLicense({ status: cached.status, tier: null });
324
+ setLicense({ status: cached.status });
347
325
  }
348
326
  return;
349
327
  }
@@ -351,7 +329,7 @@ function FieldCraftProProvider({ licenseKey, children }) {
351
329
  if (cancelled) return;
352
330
  if (!pingResult) return;
353
331
  if (pingResult.status === "revoked" || pingResult.status === "domain_mismatch") {
354
- setLicense({ status: pingResult.status, tier: null });
332
+ setLicense({ status: pingResult.status });
355
333
  }
356
334
  });
357
335
  });
@@ -559,7 +537,7 @@ function UnlicensedOverlay({ featureName, reason, children }) {
559
537
  }
560
538
  function requireLicense(Component3, featureName) {
561
539
  function LicenseGated(props) {
562
- const { status, tier } = useLicense();
540
+ const { status } = useLicense();
563
541
  const isProduction = isProductionEnvironment();
564
542
  if (!isProduction) {
565
543
  return /* @__PURE__ */ jsxRuntime.jsx(Component3, { ...props });
@@ -567,8 +545,7 @@ function requireLicense(Component3, featureName) {
567
545
  if (status === "validating") {
568
546
  return null;
569
547
  }
570
- const isLicensed = status === "valid" && tier != null && tierHasFeature(tier, featureName);
571
- if (isLicensed) {
548
+ if (status === "valid") {
572
549
  return /* @__PURE__ */ jsxRuntime.jsx(Component3, { ...props });
573
550
  }
574
551
  let reason = "A valid license is required for production use.";
@@ -580,8 +557,6 @@ function requireLicense(Component3, featureName) {
580
557
  reason = "This license key has been revoked. Please contact support or purchase a new license.";
581
558
  } else if (status === "domain_mismatch") {
582
559
  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.";
583
- } else if (!tier || !tierHasFeature(tier, featureName)) {
584
- reason = "Your license does not include this feature. Please upgrade your plan.";
585
560
  }
586
561
  return /* @__PURE__ */ jsxRuntime.jsx(UnlicensedOverlay, { featureName, reason, children: /* @__PURE__ */ jsxRuntime.jsx(Component3, { ...props }) });
587
562
  }
@@ -4007,7 +3982,7 @@ var defaultEdgeOptions = {
4007
3982
  height: 12
4008
3983
  }
4009
3984
  };
4010
- function LogicFlowEditor({ schema, onChange, onClose }) {
3985
+ function LogicFlowEditor({ schema, onChange }) {
4011
3986
  const noSections = schema.sections.length === 0;
4012
3987
  const flowGraph = react.useMemo(() => buildReactFlowGraph(schema), [schema]);
4013
3988
  const [nodes, setNodes, onNodesChange] = react$1.useNodesState(flowGraph.nodes);
@@ -4099,33 +4074,89 @@ function LogicFlowEditor({ schema, onChange, onClose }) {
4099
4074
  const jumpCount = flowGraph.edges.filter(
4100
4075
  (e) => e.data?.edgeType === "onExit"
4101
4076
  ).length;
4102
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "fixed inset-0 z-50 flex flex-col bg-background/95 backdrop-blur-sm", children: [
4103
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "h-12 shrink-0 flex items-center justify-between px-4 border-b border-border bg-card", children: [
4104
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
4105
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.GitBranch, { size: 16, className: "text-primary" }),
4106
- /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-sm font-semibold", children: "Logic Flow" }),
4107
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs text-muted-foreground", children: [
4108
- showIfCount,
4109
- " condition",
4110
- showIfCount !== 1 ? "s" : "",
4111
- jumpCount > 0 && ` \xB7 ${jumpCount} jump${jumpCount !== 1 ? "s" : ""}`,
4112
- " \xB7 ",
4113
- sectionIds.length,
4114
- " section",
4115
- sectionIds.length !== 1 ? "s" : ""
4116
- ] })
4117
- ] }),
4077
+ const totalFields = react.useMemo(
4078
+ () => schema.sections.reduce((sum, s) => sum + s.questions.length, 0),
4079
+ [schema]
4080
+ );
4081
+ const conditionalFields = react.useMemo(
4082
+ () => schema.sections.reduce(
4083
+ (sum, s) => sum + s.questions.filter((q) => !!q.showIf).length,
4084
+ 0
4085
+ ),
4086
+ [schema]
4087
+ );
4088
+ return /* @__PURE__ */ jsxRuntime.jsx(react$1.ReactFlowProvider, { children: /* @__PURE__ */ jsxRuntime.jsx(
4089
+ LogicFlowInner,
4090
+ {
4091
+ noSections,
4092
+ nodes,
4093
+ edges,
4094
+ onNodesChange,
4095
+ onEdgesChange,
4096
+ onNodeClick,
4097
+ onConnect,
4098
+ onEdgesDelete,
4099
+ selectedFieldId,
4100
+ selectedQuestion,
4101
+ setSelectedFieldId,
4102
+ handleConditionUpdate,
4103
+ schema,
4104
+ sectionIds,
4105
+ showIfCount,
4106
+ jumpCount,
4107
+ totalFields,
4108
+ conditionalFields
4109
+ }
4110
+ ) });
4111
+ }
4112
+ function LogicFlowInner({
4113
+ noSections,
4114
+ nodes,
4115
+ edges,
4116
+ onNodesChange,
4117
+ onEdgesChange,
4118
+ onNodeClick,
4119
+ onConnect,
4120
+ onEdgesDelete,
4121
+ selectedFieldId,
4122
+ selectedQuestion,
4123
+ setSelectedFieldId,
4124
+ handleConditionUpdate,
4125
+ schema,
4126
+ sectionIds,
4127
+ showIfCount,
4128
+ jumpCount,
4129
+ totalFields,
4130
+ conditionalFields
4131
+ }) {
4132
+ const { zoomIn, zoomOut, fitView } = react$1.useReactFlow();
4133
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 flex flex-col bg-background min-h-0", children: [
4134
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "shrink-0 h-9 flex items-center justify-between px-4 border-b border-border bg-card/50", children: [
4135
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-3", children: /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs text-muted-foreground", children: [
4136
+ sectionIds.length,
4137
+ " section",
4138
+ sectionIds.length !== 1 ? "s" : "",
4139
+ " \xB7 ",
4140
+ totalFields,
4141
+ " field",
4142
+ totalFields !== 1 ? "s" : "",
4143
+ conditionalFields > 0 && ` \xB7 ${conditionalFields} conditional`,
4144
+ showIfCount > 0 && ` \xB7 ${showIfCount} rule${showIfCount !== 1 ? "s" : ""}`,
4145
+ jumpCount > 0 && ` \xB7 ${jumpCount} jump${jumpCount !== 1 ? "s" : ""}`
4146
+ ] }) }),
4118
4147
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1", children: [
4119
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] text-muted-foreground mr-2", children: "Drag between nodes to create conditions \xB7 Select edges and press Delete to remove" }),
4120
- /* @__PURE__ */ jsxRuntime.jsx(fieldcraftReact.Button, { variant: "ghost", size: "icon-sm", onClick: onClose, title: "Close logic flow", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { size: 16, strokeWidth: 1.75 }) })
4148
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] text-muted-foreground mr-2 hidden md:inline", children: "Drag between nodes to create conditions \xB7 Select edges + Delete to remove" }),
4149
+ /* @__PURE__ */ jsxRuntime.jsx(fieldcraftReact.Button, { variant: "ghost", size: "icon-xs", onClick: () => zoomOut(), title: "Zoom out", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ZoomOut, { size: 14, strokeWidth: 1.75 }) }),
4150
+ /* @__PURE__ */ jsxRuntime.jsx(fieldcraftReact.Button, { variant: "ghost", size: "icon-xs", onClick: () => zoomIn(), title: "Zoom in", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ZoomIn, { size: 14, strokeWidth: 1.75 }) }),
4151
+ /* @__PURE__ */ jsxRuntime.jsx(fieldcraftReact.Button, { variant: "ghost", size: "icon-xs", onClick: () => fitView({ padding: 0.2 }), title: "Fit to view", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Maximize, { size: 14, strokeWidth: 1.75 }) })
4121
4152
  ] })
4122
4153
  ] }),
4123
- noSections ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 flex items-center justify-center text-muted-foreground text-sm", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-center space-y-2", children: [
4124
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.GitBranch, { size: 32, className: "mx-auto opacity-40" }),
4125
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "font-medium", children: "No sections found" }),
4126
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs max-w-xs", children: "Add sections and fields to your form to see the logic flow pipeline." })
4127
- ] }) }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 flex", children: [
4128
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1", children: /* @__PURE__ */ jsxRuntime.jsxs(
4154
+ noSections ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 flex items-center justify-center text-muted-foreground text-sm", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-center space-y-3", children: [
4155
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.GitBranch, { size: 40, className: "mx-auto opacity-30" }),
4156
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "font-medium", children: "No logic to display" }),
4157
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs max-w-xs mx-auto", children: "Switch to Design mode and add sections with fields. Then come back here to visualize and edit branching logic." })
4158
+ ] }) }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 flex min-h-0", children: [
4159
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 min-h-0", children: /* @__PURE__ */ jsxRuntime.jsxs(
4129
4160
  react$1.ReactFlow,
4130
4161
  {
4131
4162
  nodes,
@@ -4144,7 +4175,6 @@ function LogicFlowEditor({ schema, onChange, onClose }) {
4144
4175
  proOptions: { hideAttribution: true },
4145
4176
  children: [
4146
4177
  /* @__PURE__ */ jsxRuntime.jsx(react$1.Background, { gap: 20, size: 1 }),
4147
- /* @__PURE__ */ jsxRuntime.jsx(react$1.Controls, { showInteractive: false }),
4148
4178
  /* @__PURE__ */ jsxRuntime.jsx(
4149
4179
  react$1.MiniMap,
4150
4180
  {
@@ -4159,9 +4189,9 @@ function LogicFlowEditor({ schema, onChange, onClose }) {
4159
4189
  ]
4160
4190
  }
4161
4191
  ) }),
4162
- selectedFieldId && selectedQuestion && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "w-72 border-l border-border bg-card overflow-auto", children: [
4192
+ selectedFieldId && selectedQuestion && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "w-72 shrink-0 border-l border-border bg-card overflow-auto", children: [
4163
4193
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-3 py-3 border-b border-border flex items-center justify-between", children: [
4164
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
4194
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0", children: [
4165
4195
  /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs font-semibold truncate", children: selectedQuestion.label || selectedQuestion.id }),
4166
4196
  /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[10px] text-muted-foreground", children: selectedQuestion.type })
4167
4197
  ] }),
@@ -4172,7 +4202,7 @@ function LogicFlowEditor({ schema, onChange, onClose }) {
4172
4202
  size: "icon-xs",
4173
4203
  onClick: () => setSelectedFieldId(null),
4174
4204
  title: "Close panel",
4175
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { size: 14, strokeWidth: 1.75 })
4205
+ children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs", children: "\xD7" })
4176
4206
  }
4177
4207
  )
4178
4208
  ] }),
@@ -4186,7 +4216,7 @@ function LogicFlowEditor({ schema, onChange, onClose }) {
4186
4216
  ) })
4187
4217
  ] })
4188
4218
  ] }),
4189
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "shrink-0 px-4 py-2 border-t border-border bg-card flex items-center gap-4 text-xs text-muted-foreground flex-wrap", children: [
4219
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "shrink-0 px-4 py-1.5 border-t border-border bg-card/50 flex items-center gap-4 text-[11px] text-muted-foreground flex-wrap", children: [
4190
4220
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5", children: [
4191
4221
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-5 h-0.5 rounded", style: { background: "var(--muted-foreground)", opacity: 0.4 } }),
4192
4222
  /* @__PURE__ */ jsxRuntime.jsx("span", { children: "flow" })
@@ -4441,7 +4471,6 @@ function FormBuilderCore(props) {
4441
4471
  const [viewMode, setViewMode] = react.useState("design");
4442
4472
  const [jsonText, setJsonText] = react.useState("");
4443
4473
  const [jsonSwitchError, setJsonSwitchError] = react.useState(null);
4444
- const [showLogicMap, setShowLogicMap] = react.useState(false);
4445
4474
  const [showTemplateGallery, setShowTemplateGallery] = react.useState(false);
4446
4475
  const [saveValidationErrors, setSaveValidationErrors] = react.useState(null);
4447
4476
  const [schemaUrlLoading, setSchemaUrlLoading] = react.useState(!!schemaUrl);
@@ -4598,6 +4627,11 @@ ${details}`);
4598
4627
  handleSave();
4599
4628
  return;
4600
4629
  }
4630
+ if (mod && e.key === "l") {
4631
+ e.preventDefault();
4632
+ handleViewModeChange(viewMode === "logic" ? "design" : "logic");
4633
+ return;
4634
+ }
4601
4635
  if (isEditing) return;
4602
4636
  if (e.key === "Delete" || e.key === "Backspace") {
4603
4637
  const sel = builderState.selectedItem;
@@ -4628,7 +4662,7 @@ ${details}`);
4628
4662
  }
4629
4663
  }
4630
4664
  },
4631
- [builderState, handleSave]
4665
+ [builderState, handleSave, handleViewModeChange, viewMode]
4632
4666
  );
4633
4667
  return /* @__PURE__ */ jsxRuntime.jsx(FormBuilderThemeProvider, { theme, children: /* @__PURE__ */ jsxRuntime.jsxs(
4634
4668
  core.DndContext,
@@ -4719,6 +4753,19 @@ ${details}`);
4719
4753
  "JSON"
4720
4754
  ]
4721
4755
  }
4756
+ ),
4757
+ /* @__PURE__ */ jsxRuntime.jsxs(
4758
+ fieldcraftReact.Button,
4759
+ {
4760
+ variant: viewMode === "logic" ? "secondary" : "ghost",
4761
+ size: "sm",
4762
+ onClick: () => handleViewModeChange("logic"),
4763
+ className: "gap-1.5 h-7 px-2.5 text-xs",
4764
+ children: [
4765
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.GitBranch, { size: 13, strokeWidth: 1.75 }),
4766
+ "Logic"
4767
+ ]
4768
+ }
4722
4769
  )
4723
4770
  ] }),
4724
4771
  toolbarExtra
@@ -4735,17 +4782,6 @@ ${details}`);
4735
4782
  children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.LayoutTemplate, { size: 15, strokeWidth: 1.75 })
4736
4783
  }
4737
4784
  ),
4738
- /* @__PURE__ */ jsxRuntime.jsx(
4739
- fieldcraftReact.Button,
4740
- {
4741
- variant: "ghost",
4742
- size: "icon-sm",
4743
- onClick: () => setShowLogicMap(true),
4744
- title: "View branching logic map",
4745
- "aria-label": "Logic map",
4746
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.GitBranch, { size: 15, strokeWidth: 1.75 })
4747
- }
4748
- ),
4749
4785
  /* @__PURE__ */ jsxRuntime.jsx(fieldcraftReact.Separator, { orientation: "vertical", className: "mx-1 h-5" }),
4750
4786
  /* @__PURE__ */ jsxRuntime.jsx(
4751
4787
  fieldcraftReact.Button,
@@ -4829,6 +4865,19 @@ ${details}`);
4829
4865
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "hidden sm:inline", children: "JSON" })
4830
4866
  ]
4831
4867
  }
4868
+ ),
4869
+ /* @__PURE__ */ jsxRuntime.jsxs(
4870
+ fieldcraftReact.Button,
4871
+ {
4872
+ variant: viewMode === "logic" ? "secondary" : "ghost",
4873
+ size: "sm",
4874
+ onClick: () => handleViewModeChange("logic"),
4875
+ className: "gap-1 h-7 px-2 text-xs",
4876
+ children: [
4877
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.GitBranch, { size: 12, strokeWidth: 1.75 }),
4878
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "hidden sm:inline", children: "Logic" })
4879
+ ]
4880
+ }
4832
4881
  )
4833
4882
  ] }),
4834
4883
  toolbarExtra,
@@ -4962,7 +5011,13 @@ ${details}`);
4962
5011
  errors: jsonErrors,
4963
5012
  onValidate: validateJson
4964
5013
  }
4965
- ) : viewMode === "preview" ? /* @__PURE__ */ jsxRuntime.jsx(FormPreviewPanel, { schema: builderState.schema, preview }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
5014
+ ) : viewMode === "preview" ? /* @__PURE__ */ jsxRuntime.jsx(FormPreviewPanel, { schema: builderState.schema, preview }) : viewMode === "logic" ? /* @__PURE__ */ jsxRuntime.jsx(
5015
+ LogicFlowEditor,
5016
+ {
5017
+ schema: builderState.schema,
5018
+ onChange: (updated) => builderState.resetSchema(updated)
5019
+ }
5020
+ ) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
4966
5021
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "hidden md:flex", children: /* @__PURE__ */ jsxRuntime.jsx(QuestionPalette, { questionTypes: mergedQuestionTypes, palette }) }),
4967
5022
  /* @__PURE__ */ jsxRuntime.jsx(FormCanvas, { builderState }),
4968
5023
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "hidden md:flex", children: /* @__PURE__ */ jsxRuntime.jsx(PropertiesPanel, { builderState }) }),
@@ -4981,14 +5036,6 @@ ${details}`);
4981
5036
  }
4982
5037
  ),
4983
5038
  /* @__PURE__ */ jsxRuntime.jsx(core.DragOverlay, { dropAnimation: null, children: dragDrop.activeDragItem && /* @__PURE__ */ jsxRuntime.jsx(DragOverlayContent, { item: dragDrop.activeDragItem, schema: builderState.schema, questionTypes: mergedQuestionTypes }) }),
4984
- showLogicMap && /* @__PURE__ */ jsxRuntime.jsx(
4985
- LogicFlowEditor,
4986
- {
4987
- schema: builderState.schema,
4988
- onChange: (updated) => builderState.resetSchema(updated),
4989
- onClose: () => setShowLogicMap(false)
4990
- }
4991
- ),
4992
5039
  showTemplateGallery && templates && /* @__PURE__ */ jsxRuntime.jsx(
4993
5040
  TemplateGallery,
4994
5041
  {
@@ -5271,10 +5318,9 @@ function PayKitCheckout({
5271
5318
  react.useEffect(() => {
5272
5319
  let cancelled = false;
5273
5320
  Promise.all([
5274
- // @ts-expect-error — optional peer dep, resolved at runtime
5275
5321
  import('@squaredr/paykit-react'),
5276
- // @ts-expect-error — optional peer dep, resolved at runtime
5277
- import('@squaredr/paykit-stripe/client')
5322
+ // @ts-expect-error — optional peer dep, types not available at build time
5323
+ import('@squaredr/paykit/stripe/client')
5278
5324
  ]).then(([paykit, stripe]) => {
5279
5325
  if (cancelled) return;
5280
5326
  setPayKit({
@@ -5285,7 +5331,7 @@ function PayKitCheckout({
5285
5331
  }).catch((err) => {
5286
5332
  if (cancelled) return;
5287
5333
  setLoadError(
5288
- `Failed to load payment SDK. Ensure @squaredr/paykit-react and @squaredr/paykit-stripe are installed. (${err.message})`
5334
+ `Failed to load payment SDK. Ensure @squaredr/paykit-react and @squaredr/paykit are installed. (${err.message})`
5289
5335
  );
5290
5336
  });
5291
5337
  return () => {
@@ -8863,18 +8909,1128 @@ var themeEditorDarkPreset = {
8863
8909
  accentForeground: "#0F1A1F"
8864
8910
  };
8865
8911
 
8912
+ // src/templates/consultation-booking.ts
8913
+ var consultationBookingSchema = {
8914
+ id: "consultation-booking",
8915
+ version: "1.0.0",
8916
+ title: "Consultation Booking",
8917
+ description: "Book a consultation session. Select your service, answer a few questions, pick a time, and pay \u2014 all in one flow.",
8918
+ settings: {
8919
+ showProgress: true,
8920
+ progressStyle: "steps",
8921
+ navigation: { showBack: true }
8922
+ },
8923
+ submitAction: { type: "callback" },
8924
+ sections: [
8925
+ // ── Section 1: Welcome & Service Selection ────────────────────
8926
+ {
8927
+ id: "service-selection",
8928
+ title: "Choose Your Service",
8929
+ description: "Select the type of consultation you need",
8930
+ questions: [
8931
+ {
8932
+ id: "welcome_info",
8933
+ type: "info_block",
8934
+ label: "Our consultations are 1-on-1 sessions with senior advisors. Sessions are 30 or 60 minutes. Choose your service below to get started."
8935
+ },
8936
+ {
8937
+ id: "service_type",
8938
+ type: "single_select",
8939
+ label: "Service Type",
8940
+ required: true,
8941
+ options: [
8942
+ { label: "Legal Consultation ($150/hr)", value: "legal" },
8943
+ { label: "Business Strategy ($200/hr)", value: "business" },
8944
+ { label: "Technical Audit ($175/hr)", value: "technical" }
8945
+ ]
8946
+ },
8947
+ {
8948
+ id: "session_duration",
8949
+ type: "single_select",
8950
+ label: "Session Duration",
8951
+ required: true,
8952
+ options: [
8953
+ { label: "30 minutes", value: "30" },
8954
+ { label: "60 minutes", value: "60" }
8955
+ ]
8956
+ },
8957
+ {
8958
+ id: "urgency",
8959
+ type: "single_select",
8960
+ label: "How soon do you need the consultation?",
8961
+ required: true,
8962
+ options: [
8963
+ { label: "Within 24 hours (+$50 rush fee)", value: "rush" },
8964
+ { label: "This week", value: "this-week" },
8965
+ { label: "Flexible", value: "flexible" }
8966
+ ]
8967
+ }
8968
+ ],
8969
+ onExit: {
8970
+ rules: [
8971
+ {
8972
+ condition: { field: "service_type", operator: "eq", value: "legal" },
8973
+ jumpTo: "legal-details"
8974
+ },
8975
+ {
8976
+ condition: { field: "service_type", operator: "eq", value: "business" },
8977
+ jumpTo: "business-details"
8978
+ },
8979
+ {
8980
+ condition: { field: "service_type", operator: "eq", value: "technical" },
8981
+ jumpTo: "technical-details"
8982
+ }
8983
+ ],
8984
+ default: "scheduling"
8985
+ }
8986
+ },
8987
+ // ── Section 2A: Legal Consultation Path ───────────────────────
8988
+ {
8989
+ id: "legal-details",
8990
+ title: "Legal Consultation Details",
8991
+ description: "Help us prepare for your legal consultation",
8992
+ showIf: {
8993
+ field: "service_type",
8994
+ operator: "eq",
8995
+ value: "legal"
8996
+ },
8997
+ questions: [
8998
+ {
8999
+ id: "legal_area",
9000
+ type: "single_select",
9001
+ label: "Area of Law",
9002
+ required: true,
9003
+ options: [
9004
+ { label: "Business / Corporate", value: "corporate" },
9005
+ { label: "Employment / Labor", value: "employment" },
9006
+ { label: "Intellectual Property", value: "ip" },
9007
+ { label: "Contracts / Agreements", value: "contracts" },
9008
+ { label: "Regulatory / Compliance", value: "regulatory" },
9009
+ { label: "Other", value: "other" }
9010
+ ]
9011
+ },
9012
+ {
9013
+ id: "legal_area_other",
9014
+ type: "short_text",
9015
+ label: "Please specify the area of law",
9016
+ required: true,
9017
+ placeholder: "Describe the legal area",
9018
+ showIf: { field: "legal_area", operator: "eq", value: "other" },
9019
+ validation: [{ type: "maxLength", value: 200 }]
9020
+ },
9021
+ {
9022
+ id: "legal_existing_counsel",
9023
+ type: "boolean",
9024
+ label: "Do you currently have legal counsel?",
9025
+ required: true
9026
+ },
9027
+ {
9028
+ id: "legal_counsel_reason",
9029
+ type: "single_select",
9030
+ label: "Reason for seeking a second opinion",
9031
+ required: true,
9032
+ showIf: { field: "legal_existing_counsel", operator: "eq", value: true },
9033
+ options: [
9034
+ { label: "Want a second opinion", value: "second-opinion" },
9035
+ { label: "Current counsel lacks specialization", value: "specialization" },
9036
+ { label: "Considering switching counsel", value: "switching" },
9037
+ { label: "Other", value: "other" }
9038
+ ]
9039
+ },
9040
+ {
9041
+ id: "legal_documents",
9042
+ type: "file_upload",
9043
+ label: "Upload relevant documents (optional)",
9044
+ required: false,
9045
+ helpText: "Contracts, letters, filings \u2014 up to 3 files, 10MB each",
9046
+ config: {
9047
+ type: "file_upload",
9048
+ accept: ["application/pdf", "image/png", "image/jpeg"],
9049
+ maxSizeMb: 10,
9050
+ maxFiles: 3
9051
+ }
9052
+ },
9053
+ {
9054
+ id: "legal_summary",
9055
+ type: "long_text",
9056
+ label: "Brief summary of your situation",
9057
+ required: true,
9058
+ placeholder: "Describe the issue, relevant dates, parties involved, and what outcome you're looking for...",
9059
+ validation: [
9060
+ { type: "minLength", value: 50, message: "Please provide enough detail for our team to prepare" },
9061
+ { type: "maxLength", value: 3e3 }
9062
+ ]
9063
+ }
9064
+ ],
9065
+ onExit: {
9066
+ rules: [],
9067
+ default: "scheduling"
9068
+ }
9069
+ },
9070
+ // ── Section 2B: Business Strategy Path ────────────────────────
9071
+ {
9072
+ id: "business-details",
9073
+ title: "Business Strategy Details",
9074
+ description: "Tell us about your business challenge",
9075
+ showIf: {
9076
+ field: "service_type",
9077
+ operator: "eq",
9078
+ value: "business"
9079
+ },
9080
+ questions: [
9081
+ {
9082
+ id: "biz_stage",
9083
+ type: "single_select",
9084
+ label: "Business Stage",
9085
+ required: true,
9086
+ options: [
9087
+ { label: "Pre-revenue / Idea stage", value: "idea" },
9088
+ { label: "Early stage (< $500K ARR)", value: "early" },
9089
+ { label: "Growth ($500K - $5M ARR)", value: "growth" },
9090
+ { label: "Scale ($5M+ ARR)", value: "scale" },
9091
+ { label: "Enterprise / Established", value: "enterprise" }
9092
+ ]
9093
+ },
9094
+ {
9095
+ id: "biz_focus",
9096
+ type: "multi_select",
9097
+ label: "Areas you want to discuss",
9098
+ required: true,
9099
+ options: [
9100
+ { label: "Go-to-market strategy", value: "gtm" },
9101
+ { label: "Pricing & monetization", value: "pricing" },
9102
+ { label: "Fundraising / Investment", value: "fundraising" },
9103
+ { label: "Team building / Hiring", value: "team" },
9104
+ { label: "Operations & scaling", value: "operations" },
9105
+ { label: "Product strategy", value: "product" },
9106
+ { label: "Partnerships & channels", value: "partnerships" }
9107
+ ]
9108
+ },
9109
+ {
9110
+ id: "biz_fundraising_stage",
9111
+ type: "single_select",
9112
+ label: "Current fundraising stage",
9113
+ required: true,
9114
+ showIf: { field: "biz_focus", operator: "contains", value: "fundraising" },
9115
+ options: [
9116
+ { label: "Pre-seed", value: "pre-seed" },
9117
+ { label: "Seed", value: "seed" },
9118
+ { label: "Series A", value: "series-a" },
9119
+ { label: "Series B+", value: "series-b-plus" },
9120
+ { label: "Not raising / Bootstrap", value: "bootstrap" }
9121
+ ]
9122
+ },
9123
+ {
9124
+ id: "biz_team_size",
9125
+ type: "number",
9126
+ label: "Current team size",
9127
+ required: true,
9128
+ validation: [
9129
+ { type: "min", value: 1 },
9130
+ { type: "max", value: 1e5 }
9131
+ ]
9132
+ },
9133
+ {
9134
+ id: "biz_challenge",
9135
+ type: "long_text",
9136
+ label: "Describe your primary challenge",
9137
+ required: true,
9138
+ placeholder: "What's the #1 thing you want to solve in this session? Be specific...",
9139
+ validation: [
9140
+ { type: "minLength", value: 30, message: "Please be more specific" },
9141
+ { type: "maxLength", value: 2e3 }
9142
+ ]
9143
+ },
9144
+ {
9145
+ id: "biz_pitch_deck",
9146
+ type: "file_upload",
9147
+ label: "Upload pitch deck or one-pager (optional)",
9148
+ required: false,
9149
+ config: {
9150
+ type: "file_upload",
9151
+ accept: ["application/pdf"],
9152
+ maxSizeMb: 20,
9153
+ maxFiles: 1
9154
+ }
9155
+ }
9156
+ ],
9157
+ onExit: {
9158
+ rules: [],
9159
+ default: "scheduling"
9160
+ }
9161
+ },
9162
+ // ── Section 2C: Technical Audit Path ──────────────────────────
9163
+ {
9164
+ id: "technical-details",
9165
+ title: "Technical Audit Details",
9166
+ description: "Help us understand your technical landscape",
9167
+ showIf: {
9168
+ field: "service_type",
9169
+ operator: "eq",
9170
+ value: "technical"
9171
+ },
9172
+ questions: [
9173
+ {
9174
+ id: "tech_audit_type",
9175
+ type: "single_select",
9176
+ label: "What type of audit do you need?",
9177
+ required: true,
9178
+ options: [
9179
+ { label: "Architecture review", value: "architecture" },
9180
+ { label: "Security audit", value: "security" },
9181
+ { label: "Performance optimization", value: "performance" },
9182
+ { label: "Code quality review", value: "code-quality" },
9183
+ { label: "Cloud infrastructure", value: "cloud" },
9184
+ { label: "Database optimization", value: "database" }
9185
+ ]
9186
+ },
9187
+ {
9188
+ id: "tech_stack",
9189
+ type: "multi_select",
9190
+ label: "Primary tech stack",
9191
+ required: true,
9192
+ options: [
9193
+ { label: "React / Next.js", value: "react" },
9194
+ { label: "Node.js", value: "node" },
9195
+ { label: "Python / Django / FastAPI", value: "python" },
9196
+ { label: "Go", value: "go" },
9197
+ { label: "Java / Spring", value: "java" },
9198
+ { label: ".NET / C#", value: "dotnet" },
9199
+ { label: "Ruby on Rails", value: "rails" },
9200
+ { label: "Mobile (React Native / Flutter)", value: "mobile" }
9201
+ ]
9202
+ },
9203
+ {
9204
+ id: "tech_cloud",
9205
+ type: "single_select",
9206
+ label: "Cloud provider",
9207
+ required: true,
9208
+ showIf: { field: "tech_audit_type", operator: "eq", value: "cloud" },
9209
+ options: [
9210
+ { label: "AWS", value: "aws" },
9211
+ { label: "Google Cloud", value: "gcp" },
9212
+ { label: "Azure", value: "azure" },
9213
+ { label: "Vercel / Netlify / Other", value: "other" },
9214
+ { label: "Self-hosted / On-prem", value: "on-prem" }
9215
+ ]
9216
+ },
9217
+ {
9218
+ id: "tech_monthly_spend",
9219
+ type: "single_select",
9220
+ label: "Current monthly cloud spend",
9221
+ required: true,
9222
+ showIf: { field: "tech_audit_type", operator: "eq", value: "cloud" },
9223
+ options: [
9224
+ { label: "Under $500", value: "under-500" },
9225
+ { label: "$500 - $2,000", value: "500-2k" },
9226
+ { label: "$2,000 - $10,000", value: "2k-10k" },
9227
+ { label: "$10,000+", value: "10k-plus" }
9228
+ ]
9229
+ },
9230
+ {
9231
+ id: "tech_users",
9232
+ type: "single_select",
9233
+ label: "Scale (monthly active users or requests)",
9234
+ required: true,
9235
+ options: [
9236
+ { label: "< 1,000 MAU", value: "under-1k" },
9237
+ { label: "1K - 10K MAU", value: "1k-10k" },
9238
+ { label: "10K - 100K MAU", value: "10k-100k" },
9239
+ { label: "100K - 1M MAU", value: "100k-1m" },
9240
+ { label: "1M+ MAU", value: "1m-plus" }
9241
+ ]
9242
+ },
9243
+ {
9244
+ id: "tech_repo_access",
9245
+ type: "boolean",
9246
+ label: "Can you grant temporary read access to the codebase?",
9247
+ required: true,
9248
+ helpText: "We'll sign an NDA before accessing any code"
9249
+ },
9250
+ {
9251
+ id: "tech_description",
9252
+ type: "long_text",
9253
+ label: "Describe the specific issues or goals for the audit",
9254
+ required: true,
9255
+ placeholder: "What problems are you seeing? What do you want us to focus on?",
9256
+ validation: [
9257
+ { type: "minLength", value: 30, message: "Please describe the technical issues in detail" },
9258
+ { type: "maxLength", value: 3e3 }
9259
+ ]
9260
+ }
9261
+ ],
9262
+ onExit: {
9263
+ rules: [],
9264
+ default: "scheduling"
9265
+ }
9266
+ },
9267
+ // ── Section 3: Scheduling ─────────────────────────────────────
9268
+ {
9269
+ id: "scheduling",
9270
+ title: "Pick a Time",
9271
+ description: "Choose a convenient time for your consultation",
9272
+ questions: [
9273
+ {
9274
+ id: "timezone",
9275
+ type: "dropdown",
9276
+ label: "Your Timezone",
9277
+ required: true,
9278
+ options: [
9279
+ { label: "US Eastern (ET)", value: "America/New_York" },
9280
+ { label: "US Central (CT)", value: "America/Chicago" },
9281
+ { label: "US Mountain (MT)", value: "America/Denver" },
9282
+ { label: "US Pacific (PT)", value: "America/Los_Angeles" },
9283
+ { label: "UK (GMT/BST)", value: "Europe/London" },
9284
+ { label: "Central Europe (CET)", value: "Europe/Berlin" },
9285
+ { label: "India (IST)", value: "Asia/Kolkata" },
9286
+ { label: "Japan (JST)", value: "Asia/Tokyo" },
9287
+ { label: "Australia Eastern (AEST)", value: "Australia/Sydney" }
9288
+ ]
9289
+ },
9290
+ {
9291
+ id: "appointment_slot",
9292
+ type: "appointment",
9293
+ label: "Select Date & Time",
9294
+ required: true,
9295
+ config: {
9296
+ type: "appointment",
9297
+ slots: [
9298
+ {
9299
+ date: "2026-09-01",
9300
+ times: ["09:00", "10:00", "11:00", "14:00", "15:00", "16:00"]
9301
+ },
9302
+ {
9303
+ date: "2026-09-02",
9304
+ times: ["09:00", "10:30", "13:00", "14:30", "16:00"]
9305
+ },
9306
+ {
9307
+ date: "2026-09-03",
9308
+ times: ["10:00", "11:00", "13:00", "15:00"]
9309
+ },
9310
+ {
9311
+ date: "2026-09-04",
9312
+ times: ["09:00", "10:00", "11:00", "14:00", "15:00"]
9313
+ },
9314
+ {
9315
+ date: "2026-09-05",
9316
+ times: ["09:00", "11:00", "13:00", "14:00", "16:00"]
9317
+ }
9318
+ ],
9319
+ timezone: "America/New_York",
9320
+ duration: 60
9321
+ }
9322
+ },
9323
+ {
9324
+ id: "attendees",
9325
+ type: "repeater",
9326
+ label: "Additional Attendees",
9327
+ required: false,
9328
+ helpText: "Add anyone else who should join the session (you are already included)",
9329
+ config: {
9330
+ type: "repeater",
9331
+ fields: [
9332
+ {
9333
+ id: "attendee_name",
9334
+ type: "short_text",
9335
+ label: "Name",
9336
+ required: true
9337
+ },
9338
+ {
9339
+ id: "attendee_email",
9340
+ type: "email",
9341
+ label: "Email",
9342
+ required: true
9343
+ },
9344
+ {
9345
+ id: "attendee_role",
9346
+ type: "short_text",
9347
+ label: "Role / Title",
9348
+ required: false
9349
+ }
9350
+ ],
9351
+ minEntries: 0,
9352
+ maxEntries: 5,
9353
+ addLabel: "+ Add attendee"
9354
+ }
9355
+ }
9356
+ ]
9357
+ },
9358
+ // ── Section 4: Contact & Payment ──────────────────────────────
9359
+ {
9360
+ id: "payment",
9361
+ title: "Contact & Payment",
9362
+ description: "Complete your booking",
9363
+ questions: [
9364
+ {
9365
+ id: "client_name",
9366
+ type: "legal_name",
9367
+ label: "Your Full Name",
9368
+ required: true
9369
+ },
9370
+ {
9371
+ id: "client_email",
9372
+ type: "email",
9373
+ label: "Email Address",
9374
+ required: true,
9375
+ placeholder: "you@company.com",
9376
+ helpText: "Confirmation and calendar invite will be sent here"
9377
+ },
9378
+ {
9379
+ id: "client_phone",
9380
+ type: "phone",
9381
+ label: "Phone Number",
9382
+ required: true
9383
+ },
9384
+ {
9385
+ id: "company_name",
9386
+ type: "short_text",
9387
+ label: "Company Name",
9388
+ required: false,
9389
+ placeholder: "Your organization",
9390
+ validation: [{ type: "maxLength", value: 150 }]
9391
+ },
9392
+ {
9393
+ id: "section_divider",
9394
+ type: "divider",
9395
+ label: ""
9396
+ },
9397
+ {
9398
+ id: "promo_code",
9399
+ type: "short_text",
9400
+ label: "Promo Code (optional)",
9401
+ required: false,
9402
+ placeholder: "Enter code",
9403
+ validation: [{ type: "maxLength", value: 20 }]
9404
+ },
9405
+ {
9406
+ id: "session_payment",
9407
+ type: "payment",
9408
+ label: "Pay for Consultation",
9409
+ required: true,
9410
+ helpText: "Secure payment via Stripe. You will not be charged until the session is confirmed.",
9411
+ config: {
9412
+ type: "payment",
9413
+ provider: "stripe",
9414
+ publicKey: "",
9415
+ amount: 2e4,
9416
+ currency: "USD",
9417
+ description: "Consultation Session",
9418
+ serverUrl: "/api/payment-intents"
9419
+ }
9420
+ }
9421
+ ]
9422
+ },
9423
+ // ── Section 5: Agreement & Confirmation ───────────────────────
9424
+ {
9425
+ id: "agreement",
9426
+ title: "Agreement",
9427
+ description: "Review and sign",
9428
+ questions: [
9429
+ {
9430
+ id: "terms_info",
9431
+ type: "info_block",
9432
+ label: "By signing below, you agree to our consultation terms: sessions start on time, cancellation within 24 hours receives a full refund, no-shows are non-refundable. All discussions are confidential."
9433
+ },
9434
+ {
9435
+ id: "nda_consent",
9436
+ type: "consent",
9437
+ label: "I agree to the consultation terms and understand the cancellation policy.",
9438
+ required: true
9439
+ },
9440
+ {
9441
+ id: "data_consent",
9442
+ type: "consent",
9443
+ label: "I consent to my information being used to prepare for and conduct the consultation session.",
9444
+ required: true
9445
+ },
9446
+ {
9447
+ id: "client_signature",
9448
+ type: "signature",
9449
+ label: "Signature",
9450
+ required: true,
9451
+ helpText: "Draw your signature to confirm the booking",
9452
+ config: {
9453
+ type: "signature",
9454
+ width: 500,
9455
+ height: 180,
9456
+ penColor: "#1a1a2e"
9457
+ }
9458
+ },
9459
+ {
9460
+ id: "special_requests",
9461
+ type: "long_text",
9462
+ label: "Special Requests or Notes (optional)",
9463
+ required: false,
9464
+ placeholder: "Anything else we should know before the session?",
9465
+ validation: [{ type: "maxLength", value: 500 }]
9466
+ }
9467
+ ]
9468
+ }
9469
+ ]
9470
+ };
9471
+ var consultationBookingMeta = {
9472
+ id: "consultation-booking",
9473
+ name: "Multi-Path Consultation Booking",
9474
+ description: "A branching consultation booking flow with 3 service paths (legal, business, technical), onExit section jumps, appointment scheduling with repeater for attendees, Stripe payment checkout, file uploads, and signature agreement.",
9475
+ category: "advanced",
9476
+ fieldCount: 38,
9477
+ sectionCount: 6,
9478
+ tags: [
9479
+ "advanced",
9480
+ "payment",
9481
+ "appointment",
9482
+ "branching",
9483
+ "onExit",
9484
+ "showIf",
9485
+ "repeater",
9486
+ "signature",
9487
+ "file-upload",
9488
+ "consultation"
9489
+ ]
9490
+ };
9491
+ var consultationBooking = {
9492
+ meta: consultationBookingMeta,
9493
+ schema: consultationBookingSchema
9494
+ };
9495
+
9496
+ // src/templates/ecommerce-checkout.ts
9497
+ var ecommerceCheckoutSchema = {
9498
+ id: "ecommerce-checkout",
9499
+ version: "1.0.0",
9500
+ title: "E-commerce Checkout",
9501
+ description: "Complete your purchase. Review items, enter shipping details, choose delivery, and pay securely.",
9502
+ settings: {
9503
+ showProgress: true,
9504
+ progressStyle: "steps",
9505
+ navigation: { showBack: true }
9506
+ },
9507
+ submitAction: { type: "callback" },
9508
+ sections: [
9509
+ // ── Section 1: Cart Review ──────────────────────────────────
9510
+ {
9511
+ id: "cart-review",
9512
+ title: "Your Cart",
9513
+ description: "Review your items before checkout",
9514
+ questions: [
9515
+ {
9516
+ id: "cart_info",
9517
+ type: "info_block",
9518
+ label: "Review your order below. You can adjust quantities or remove items. Prices are in USD."
9519
+ },
9520
+ {
9521
+ id: "order_items",
9522
+ type: "repeater",
9523
+ label: "Order Items",
9524
+ required: true,
9525
+ helpText: "Add the products you'd like to purchase",
9526
+ config: {
9527
+ type: "repeater",
9528
+ fields: [
9529
+ {
9530
+ id: "product_name",
9531
+ type: "short_text",
9532
+ label: "Product Name",
9533
+ required: true
9534
+ },
9535
+ {
9536
+ id: "product_sku",
9537
+ type: "short_text",
9538
+ label: "SKU",
9539
+ required: false
9540
+ },
9541
+ {
9542
+ id: "quantity",
9543
+ type: "number",
9544
+ label: "Qty",
9545
+ required: true
9546
+ },
9547
+ {
9548
+ id: "unit_price",
9549
+ type: "number",
9550
+ label: "Unit Price ($)",
9551
+ required: true
9552
+ }
9553
+ ],
9554
+ minEntries: 1,
9555
+ maxEntries: 20,
9556
+ addLabel: "+ Add item"
9557
+ }
9558
+ },
9559
+ {
9560
+ id: "discount_code",
9561
+ type: "short_text",
9562
+ label: "Discount Code",
9563
+ required: false,
9564
+ placeholder: "Enter promo code",
9565
+ validation: [{ type: "maxLength", value: 30 }]
9566
+ },
9567
+ {
9568
+ id: "gift_order",
9569
+ type: "boolean",
9570
+ label: "Is this a gift?",
9571
+ required: false
9572
+ },
9573
+ {
9574
+ id: "gift_message",
9575
+ type: "long_text",
9576
+ label: "Gift Message",
9577
+ required: false,
9578
+ showIf: { field: "gift_order", operator: "eq", value: true },
9579
+ placeholder: "Write a personal message for the recipient...",
9580
+ validation: [{ type: "maxLength", value: 300 }]
9581
+ },
9582
+ {
9583
+ id: "gift_wrap",
9584
+ type: "boolean",
9585
+ label: "Add gift wrapping (+$5.99)?",
9586
+ required: false,
9587
+ showIf: { field: "gift_order", operator: "eq", value: true }
9588
+ }
9589
+ ]
9590
+ },
9591
+ // ── Section 2: Customer Info ─────────────────────────────────
9592
+ {
9593
+ id: "customer-info",
9594
+ title: "Your Details",
9595
+ description: "Contact information for order confirmation",
9596
+ questions: [
9597
+ {
9598
+ id: "customer_name",
9599
+ type: "legal_name",
9600
+ label: "Full Name",
9601
+ required: true
9602
+ },
9603
+ {
9604
+ id: "customer_email",
9605
+ type: "email",
9606
+ label: "Email Address",
9607
+ required: true,
9608
+ placeholder: "you@example.com",
9609
+ helpText: "Order confirmation and tracking info will be sent here"
9610
+ },
9611
+ {
9612
+ id: "customer_phone",
9613
+ type: "phone",
9614
+ label: "Phone Number",
9615
+ required: true,
9616
+ helpText: "For delivery notifications"
9617
+ },
9618
+ {
9619
+ id: "account_create",
9620
+ type: "boolean",
9621
+ label: "Create an account for faster checkout next time?",
9622
+ required: false
9623
+ },
9624
+ {
9625
+ id: "account_password",
9626
+ type: "short_text",
9627
+ label: "Choose a Password",
9628
+ required: true,
9629
+ showIf: { field: "account_create", operator: "eq", value: true },
9630
+ placeholder: "Min 8 characters",
9631
+ validation: [
9632
+ { type: "minLength", value: 8, message: "Password must be at least 8 characters" },
9633
+ { type: "maxLength", value: 64 }
9634
+ ]
9635
+ }
9636
+ ]
9637
+ },
9638
+ // ── Section 3: Shipping Address ─────────────────────────────
9639
+ {
9640
+ id: "shipping-address",
9641
+ title: "Shipping Address",
9642
+ description: "Where should we deliver your order?",
9643
+ questions: [
9644
+ {
9645
+ id: "ship_address_line1",
9646
+ type: "short_text",
9647
+ label: "Address Line 1",
9648
+ required: true,
9649
+ placeholder: "Street address, P.O. box",
9650
+ validation: [{ type: "maxLength", value: 200 }]
9651
+ },
9652
+ {
9653
+ id: "ship_address_line2",
9654
+ type: "short_text",
9655
+ label: "Address Line 2",
9656
+ required: false,
9657
+ placeholder: "Apartment, suite, unit, building, floor",
9658
+ validation: [{ type: "maxLength", value: 200 }]
9659
+ },
9660
+ {
9661
+ id: "ship_city",
9662
+ type: "short_text",
9663
+ label: "City",
9664
+ required: true,
9665
+ validation: [{ type: "maxLength", value: 100 }]
9666
+ },
9667
+ {
9668
+ id: "ship_state",
9669
+ type: "dropdown",
9670
+ label: "State / Province",
9671
+ required: true,
9672
+ options: [
9673
+ { label: "Alabama", value: "AL" },
9674
+ { label: "Alaska", value: "AK" },
9675
+ { label: "Arizona", value: "AZ" },
9676
+ { label: "California", value: "CA" },
9677
+ { label: "Colorado", value: "CO" },
9678
+ { label: "Connecticut", value: "CT" },
9679
+ { label: "Florida", value: "FL" },
9680
+ { label: "Georgia", value: "GA" },
9681
+ { label: "Illinois", value: "IL" },
9682
+ { label: "Massachusetts", value: "MA" },
9683
+ { label: "Michigan", value: "MI" },
9684
+ { label: "New York", value: "NY" },
9685
+ { label: "Ohio", value: "OH" },
9686
+ { label: "Pennsylvania", value: "PA" },
9687
+ { label: "Texas", value: "TX" },
9688
+ { label: "Washington", value: "WA" },
9689
+ { label: "Other", value: "other" }
9690
+ ]
9691
+ },
9692
+ {
9693
+ id: "ship_state_other",
9694
+ type: "short_text",
9695
+ label: "State / Province (specify)",
9696
+ required: true,
9697
+ showIf: { field: "ship_state", operator: "eq", value: "other" },
9698
+ validation: [{ type: "maxLength", value: 100 }]
9699
+ },
9700
+ {
9701
+ id: "ship_zip",
9702
+ type: "short_text",
9703
+ label: "ZIP / Postal Code",
9704
+ required: true,
9705
+ validation: [
9706
+ { type: "pattern", regex: "^[0-9A-Za-z\\- ]{3,10}$", message: "Enter a valid postal code" }
9707
+ ]
9708
+ },
9709
+ {
9710
+ id: "ship_country",
9711
+ type: "dropdown",
9712
+ label: "Country",
9713
+ required: true,
9714
+ options: [
9715
+ { label: "United States", value: "US" },
9716
+ { label: "Canada", value: "CA" },
9717
+ { label: "United Kingdom", value: "GB" },
9718
+ { label: "Australia", value: "AU" },
9719
+ { label: "Germany", value: "DE" },
9720
+ { label: "France", value: "FR" },
9721
+ { label: "Japan", value: "JP" },
9722
+ { label: "India", value: "IN" },
9723
+ { label: "Other", value: "other" }
9724
+ ]
9725
+ },
9726
+ {
9727
+ id: "ship_instructions",
9728
+ type: "long_text",
9729
+ label: "Delivery Instructions (optional)",
9730
+ required: false,
9731
+ placeholder: "Gate code, leave at door, etc.",
9732
+ validation: [{ type: "maxLength", value: 300 }]
9733
+ }
9734
+ ]
9735
+ },
9736
+ // ── Section 4: Shipping Method ──────────────────────────────
9737
+ {
9738
+ id: "shipping-method",
9739
+ title: "Shipping Method",
9740
+ description: "Choose how you'd like your order delivered",
9741
+ questions: [
9742
+ {
9743
+ id: "shipping_method",
9744
+ type: "single_select",
9745
+ label: "Delivery Option",
9746
+ required: true,
9747
+ options: [
9748
+ { label: "Standard Shipping (5-7 business days) \u2014 $7.99", value: "standard" },
9749
+ { label: "Express Shipping (2-3 business days) \u2014 $14.99", value: "express" },
9750
+ { label: "Overnight Shipping (next business day) \u2014 $29.99", value: "overnight" },
9751
+ { label: "In-Store Pickup (free) \u2014 Ready in 2 hours", value: "pickup" }
9752
+ ]
9753
+ },
9754
+ {
9755
+ id: "pickup_store",
9756
+ type: "single_select",
9757
+ label: "Select Pickup Location",
9758
+ required: true,
9759
+ showIf: { field: "shipping_method", operator: "eq", value: "pickup" },
9760
+ options: [
9761
+ { label: "Downtown \u2014 123 Main St", value: "downtown" },
9762
+ { label: "Westside \u2014 456 Oak Ave", value: "westside" },
9763
+ { label: "Mall Location \u2014 Riverside Mall, Unit 12", value: "mall" },
9764
+ { label: "Airport \u2014 Terminal 2, Shop 8", value: "airport" }
9765
+ ]
9766
+ },
9767
+ {
9768
+ id: "pickup_person",
9769
+ type: "short_text",
9770
+ label: "Name of person picking up (if different)",
9771
+ required: false,
9772
+ showIf: { field: "shipping_method", operator: "eq", value: "pickup" },
9773
+ validation: [{ type: "maxLength", value: 100 }]
9774
+ },
9775
+ {
9776
+ id: "shipping_insurance",
9777
+ type: "boolean",
9778
+ label: "Add shipping insurance (+$4.99)?",
9779
+ required: false,
9780
+ helpText: "Covers loss or damage during transit up to $500",
9781
+ showIf: { field: "shipping_method", operator: "neq", value: "pickup" }
9782
+ },
9783
+ {
9784
+ id: "signature_required",
9785
+ type: "boolean",
9786
+ label: "Require signature on delivery?",
9787
+ required: false,
9788
+ showIf: { field: "shipping_method", operator: "neq", value: "pickup" }
9789
+ }
9790
+ ],
9791
+ onExit: {
9792
+ rules: [
9793
+ {
9794
+ condition: { field: "shipping_method", operator: "eq", value: "pickup" },
9795
+ jumpTo: "payment"
9796
+ }
9797
+ ],
9798
+ default: "billing-address"
9799
+ }
9800
+ },
9801
+ // ── Section 5: Billing Address (skipped if pickup) ──────────
9802
+ {
9803
+ id: "billing-address",
9804
+ title: "Billing Address",
9805
+ description: "Enter billing details for your payment method",
9806
+ showIf: { field: "shipping_method", operator: "neq", value: "pickup" },
9807
+ questions: [
9808
+ {
9809
+ id: "billing_same_as_shipping",
9810
+ type: "boolean",
9811
+ label: "Billing address is the same as shipping address",
9812
+ required: false
9813
+ },
9814
+ {
9815
+ id: "bill_name",
9816
+ type: "legal_name",
9817
+ label: "Name on Card",
9818
+ required: true,
9819
+ showIf: { field: "billing_same_as_shipping", operator: "eq", value: false }
9820
+ },
9821
+ {
9822
+ id: "bill_address_line1",
9823
+ type: "short_text",
9824
+ label: "Address Line 1",
9825
+ required: true,
9826
+ showIf: { field: "billing_same_as_shipping", operator: "eq", value: false },
9827
+ placeholder: "Street address",
9828
+ validation: [{ type: "maxLength", value: 200 }]
9829
+ },
9830
+ {
9831
+ id: "bill_address_line2",
9832
+ type: "short_text",
9833
+ label: "Address Line 2",
9834
+ required: false,
9835
+ showIf: { field: "billing_same_as_shipping", operator: "eq", value: false },
9836
+ placeholder: "Apartment, suite, unit",
9837
+ validation: [{ type: "maxLength", value: 200 }]
9838
+ },
9839
+ {
9840
+ id: "bill_city",
9841
+ type: "short_text",
9842
+ label: "City",
9843
+ required: true,
9844
+ showIf: { field: "billing_same_as_shipping", operator: "eq", value: false },
9845
+ validation: [{ type: "maxLength", value: 100 }]
9846
+ },
9847
+ {
9848
+ id: "bill_state",
9849
+ type: "short_text",
9850
+ label: "State / Province",
9851
+ required: true,
9852
+ showIf: { field: "billing_same_as_shipping", operator: "eq", value: false },
9853
+ validation: [{ type: "maxLength", value: 100 }]
9854
+ },
9855
+ {
9856
+ id: "bill_zip",
9857
+ type: "short_text",
9858
+ label: "ZIP / Postal Code",
9859
+ required: true,
9860
+ showIf: { field: "billing_same_as_shipping", operator: "eq", value: false },
9861
+ validation: [
9862
+ { type: "pattern", regex: "^[0-9A-Za-z\\- ]{3,10}$", message: "Enter a valid postal code" }
9863
+ ]
9864
+ },
9865
+ {
9866
+ id: "bill_country",
9867
+ type: "dropdown",
9868
+ label: "Country",
9869
+ required: true,
9870
+ showIf: { field: "billing_same_as_shipping", operator: "eq", value: false },
9871
+ options: [
9872
+ { label: "United States", value: "US" },
9873
+ { label: "Canada", value: "CA" },
9874
+ { label: "United Kingdom", value: "GB" },
9875
+ { label: "Australia", value: "AU" },
9876
+ { label: "Germany", value: "DE" },
9877
+ { label: "France", value: "FR" },
9878
+ { label: "Japan", value: "JP" },
9879
+ { label: "India", value: "IN" },
9880
+ { label: "Other", value: "other" }
9881
+ ]
9882
+ }
9883
+ ]
9884
+ },
9885
+ // ── Section 6: Payment ──────────────────────────────────────
9886
+ {
9887
+ id: "payment",
9888
+ title: "Payment",
9889
+ description: "Secure checkout powered by Stripe",
9890
+ questions: [
9891
+ {
9892
+ id: "order_subtotal",
9893
+ type: "calculated",
9894
+ label: "Subtotal",
9895
+ config: {
9896
+ type: "calculated",
9897
+ expression: "SUM({order_items.unit_price} * {order_items.quantity})",
9898
+ format: "currency",
9899
+ decimalPlaces: 2,
9900
+ prefix: "$"
9901
+ }
9902
+ },
9903
+ {
9904
+ id: "order_tax",
9905
+ type: "calculated",
9906
+ label: "Estimated Tax (8.5%)",
9907
+ config: {
9908
+ type: "calculated",
9909
+ expression: "{order_subtotal} * 0.085",
9910
+ format: "currency",
9911
+ decimalPlaces: 2,
9912
+ prefix: "$"
9913
+ }
9914
+ },
9915
+ {
9916
+ id: "order_total",
9917
+ type: "calculated",
9918
+ label: "Order Total",
9919
+ config: {
9920
+ type: "calculated",
9921
+ expression: "{order_subtotal} + {order_tax}",
9922
+ format: "currency",
9923
+ decimalPlaces: 2,
9924
+ prefix: "$"
9925
+ }
9926
+ },
9927
+ {
9928
+ id: "payment_divider",
9929
+ type: "divider",
9930
+ label: ""
9931
+ },
9932
+ {
9933
+ id: "checkout_payment",
9934
+ type: "payment",
9935
+ label: "Pay Now",
9936
+ required: true,
9937
+ helpText: "Your payment is encrypted and processed securely by Stripe.",
9938
+ config: {
9939
+ type: "payment",
9940
+ provider: "stripe",
9941
+ publicKey: "",
9942
+ amount: 1e4,
9943
+ currency: "USD",
9944
+ description: "E-commerce Order",
9945
+ serverUrl: "/api/payment-intents"
9946
+ }
9947
+ }
9948
+ ]
9949
+ },
9950
+ // ── Section 7: Order Confirmation ───────────────────────────
9951
+ {
9952
+ id: "confirmation",
9953
+ title: "Confirm & Place Order",
9954
+ description: "Review your order details and confirm",
9955
+ questions: [
9956
+ {
9957
+ id: "confirm_info",
9958
+ type: "info_block",
9959
+ label: "Please review your order. By placing this order, you agree to our Terms of Service, Return Policy, and Privacy Policy."
9960
+ },
9961
+ {
9962
+ id: "newsletter_optin",
9963
+ type: "boolean",
9964
+ label: "Subscribe to our newsletter for exclusive deals and updates",
9965
+ required: false
9966
+ },
9967
+ {
9968
+ id: "terms_consent",
9969
+ type: "consent",
9970
+ label: "I agree to the Terms of Service, Return Policy, and Privacy Policy.",
9971
+ required: true
9972
+ },
9973
+ {
9974
+ id: "age_consent",
9975
+ type: "consent",
9976
+ label: "I confirm that I am at least 18 years old or have parental consent to make this purchase.",
9977
+ required: true
9978
+ },
9979
+ {
9980
+ id: "order_notes",
9981
+ type: "long_text",
9982
+ label: "Order Notes (optional)",
9983
+ required: false,
9984
+ placeholder: "Special instructions for your order...",
9985
+ validation: [{ type: "maxLength", value: 500 }]
9986
+ }
9987
+ ]
9988
+ }
9989
+ ]
9990
+ };
9991
+ var ecommerceCheckoutMeta = {
9992
+ id: "ecommerce-checkout",
9993
+ name: "E-commerce Checkout",
9994
+ description: "A full shopping checkout flow with cart review (repeater for line items), shipping & billing addresses with conditional toggling, shipping method branching (onExit jumps), calculated subtotal/tax/total, Stripe payment, and order confirmation with consent.",
9995
+ category: "advanced",
9996
+ fieldCount: 42,
9997
+ sectionCount: 7,
9998
+ tags: [
9999
+ "advanced",
10000
+ "payment",
10001
+ "ecommerce",
10002
+ "checkout",
10003
+ "calculated",
10004
+ "repeater",
10005
+ "showIf",
10006
+ "onExit",
10007
+ "address",
10008
+ "shipping"
10009
+ ]
10010
+ };
10011
+ var ecommerceCheckout = {
10012
+ meta: ecommerceCheckoutMeta,
10013
+ schema: ecommerceCheckoutSchema
10014
+ };
10015
+
10016
+ // src/templates/index.ts
10017
+ var proTemplates = [
10018
+ consultationBooking,
10019
+ ecommerceCheckout
10020
+ ];
10021
+
8866
10022
  // src/index.ts
8867
10023
  if (typeof globalThis !== "undefined" && typeof globalThis.process !== "undefined" && globalThis.process.env?.NODE_ENV !== "production") {
8868
10024
  const _fc_banner = `
8869
- %c FieldCraft Pro %c v1.6.3
10025
+ %c FieldCraft Pro %c v${version}
8870
10026
 
8871
10027
  %cForm Builder \xB7 Response Viewer \xB7 Theme Editor
8872
10028
 
8873
- Docs \u2192 https://squaredr.tech/products/fieldcraft/docs/pro
8874
- Pro Tools \u2192 https://squaredr.tech/products/fieldcraft/admin-pro
10029
+ Docs \u2192 https://fieldcraft.squaredr.tech/docs
10030
+ Pro \u2192 https://fieldcraft.squaredr.tech/pro
8875
10031
  Discord \u2192 https://discord.gg/zMxdu5UVW
8876
10032
 
8877
- Need a license? \u2192 https://squaredr.tech/products/fieldcraft/admin-pro#pricing
10033
+ Need a license? \u2192 https://fieldcraft.squaredr.tech/pro#pricing
8878
10034
  `;
8879
10035
  console.log(
8880
10036
  _fc_banner,
@@ -8902,8 +10058,14 @@ exports.addOption = addOption;
8902
10058
  exports.addQuestion = addQuestion;
8903
10059
  exports.addSection = addSection;
8904
10060
  exports.cn = cn;
10061
+ exports.consultationBooking = consultationBooking;
10062
+ exports.consultationBookingMeta = consultationBookingMeta;
10063
+ exports.consultationBookingSchema = consultationBookingSchema;
8905
10064
  exports.duplicateQuestion = duplicateQuestion;
8906
10065
  exports.duplicateSection = duplicateSection;
10066
+ exports.ecommerceCheckout = ecommerceCheckout;
10067
+ exports.ecommerceCheckoutMeta = ecommerceCheckoutMeta;
10068
+ exports.ecommerceCheckoutSchema = ecommerceCheckoutSchema;
8907
10069
  exports.findQuestion = findQuestion;
8908
10070
  exports.findSection = findSection;
8909
10071
  exports.generateId = generateId;
@@ -8914,6 +10076,7 @@ exports.isProductionEnvironment = isProductionEnvironment;
8914
10076
  exports.moveOption = moveOption;
8915
10077
  exports.moveQuestion = moveQuestion;
8916
10078
  exports.moveSection = moveSection;
10079
+ exports.proTemplates = proTemplates;
8917
10080
  exports.removeOption = removeOption;
8918
10081
  exports.removeQuestion = removeQuestion;
8919
10082
  exports.removeSection = removeSection;