@infuro/cms-core 1.0.59 → 1.0.61
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/admin.cjs +1020 -83
- package/dist/admin.js +1021 -84
- package/dist/api.cjs +38 -38
- package/dist/api.js +5 -5
- package/dist/auth.cjs +51 -51
- package/dist/auth.js +3 -3
- package/dist/{chunk-3EOM4V2M.cjs → chunk-4U6DATGZ.cjs} +7 -7
- package/dist/{chunk-BNKZNLEX.js → chunk-6DBDJ4VD.js} +2 -2
- package/dist/{chunk-UQWZUZ5X.cjs → chunk-73WVHINE.cjs} +30 -6
- package/dist/{chunk-UCKN4BBY.cjs → chunk-77I3KS7V.cjs} +4 -1
- package/dist/{chunk-MCCA7WLQ.cjs → chunk-CNAHVRRU.cjs} +533 -167
- package/dist/{chunk-77NUXO6A.cjs → chunk-J7FMZK66.cjs} +10 -2
- package/dist/{chunk-BC22I7C7.cjs → chunk-KM2I6AFP.cjs} +9 -9
- package/dist/{chunk-JIWUVQ6B.js → chunk-MVHDC3XF.js} +10 -2
- package/dist/{chunk-RK5ETF2I.js → chunk-NR44CK5E.js} +1 -1
- package/dist/{chunk-MXIWUFBP.js → chunk-O2642WVS.js} +28 -4
- package/dist/{chunk-HCIRL37O.js → chunk-T3HPSF7K.js} +4 -1
- package/dist/{chunk-BTUEUA5H.js → chunk-UHT4INVW.js} +453 -87
- package/dist/{chunk-HYW3MUXT.js → chunk-URN7GS23.js} +30 -16
- package/dist/{chunk-HXLC56ZK.cjs → chunk-YSYX4GUD.cjs} +32 -18
- package/dist/{emit-order-notification-trigger-HZQPPSFB.js → emit-order-notification-trigger-CZU3V2WE.js} +2 -2
- package/dist/{emit-order-notification-trigger-NR3VN6C6.cjs → emit-order-notification-trigger-TNEZOYEE.cjs} +4 -4
- package/dist/index.cjs +614 -333
- package/dist/index.d.cts +31 -0
- package/dist/index.d.ts +31 -0
- package/dist/index.js +329 -48
- package/dist/migrations/1782800000000-AddPaymentSuccessFailedRefundTriggers.ts +32 -0
- package/dist/migrations/1782900000000-AddEnableTurnstileToForms.ts +29 -0
- package/dist/{order-notification-dispatcher-2FCZFZUD.cjs → order-notification-dispatcher-KJVGLK5E.cjs} +5 -5
- package/dist/{order-notification-dispatcher-64WDCHHG.js → order-notification-dispatcher-ZSFKEYMP.js} +2 -2
- package/dist/{rbac-debug-db-6EMIVMGF.js → rbac-debug-db-5R6XFPSV.js} +1 -1
- package/dist/{rbac-debug-db-6PWTLBEL.cjs → rbac-debug-db-JKK2MCWF.cjs} +2 -2
- package/package.json +1 -1
package/dist/admin.cjs
CHANGED
|
@@ -361,7 +361,15 @@ var init_vendor_scope = __esm({
|
|
|
361
361
|
...VENDOR_SCOPED_STORE_ENTITIES,
|
|
362
362
|
"order_discounts",
|
|
363
363
|
"order_addresses",
|
|
364
|
-
"event_products"
|
|
364
|
+
"event_products",
|
|
365
|
+
"attendees",
|
|
366
|
+
"order-attendees",
|
|
367
|
+
"order_attendees",
|
|
368
|
+
"scan",
|
|
369
|
+
"verify-attendee-qr",
|
|
370
|
+
"verify_attendee_qr",
|
|
371
|
+
"forms",
|
|
372
|
+
"cms-forms"
|
|
365
373
|
]);
|
|
366
374
|
__name(isVendorGroupName, "isVendorGroupName");
|
|
367
375
|
__name(isPlatformAdministrator, "isPlatformAdministrator");
|
|
@@ -887,7 +895,7 @@ var init_admin_config_context = __esm({
|
|
|
887
895
|
var CMS_VERSION;
|
|
888
896
|
var init_cms_version = __esm({
|
|
889
897
|
"src/lib/cms-version.ts"() {
|
|
890
|
-
CMS_VERSION = "1.0.
|
|
898
|
+
CMS_VERSION = "1.0.61" ;
|
|
891
899
|
}
|
|
892
900
|
});
|
|
893
901
|
function useCatalogCategories(enabled = true) {
|
|
@@ -1609,6 +1617,15 @@ var init_builtin_plugin_descriptors = __esm({
|
|
|
1609
1617
|
enabled: true,
|
|
1610
1618
|
icon: "auth_providers",
|
|
1611
1619
|
settingsGroup: "auth_providers"
|
|
1620
|
+
},
|
|
1621
|
+
{
|
|
1622
|
+
name: "turnstile",
|
|
1623
|
+
label: "Cloudflare Turnstile",
|
|
1624
|
+
version: "1.0.0",
|
|
1625
|
+
description: "Protect forms, registration, and authentication from spam and bots with Cloudflare Turnstile.",
|
|
1626
|
+
enabled: true,
|
|
1627
|
+
icon: "turnstile",
|
|
1628
|
+
settingsGroup: "turnstile"
|
|
1612
1629
|
}
|
|
1613
1630
|
];
|
|
1614
1631
|
}
|
|
@@ -2209,6 +2226,11 @@ function FileUpload({ onUploadSuccess }) {
|
|
|
2209
2226
|
if (!selectedFile) return;
|
|
2210
2227
|
setUploading(true);
|
|
2211
2228
|
setProgress(10);
|
|
2229
|
+
console.info("[upload] file-upload start", {
|
|
2230
|
+
name: selectedFile.name,
|
|
2231
|
+
type: selectedFile.type,
|
|
2232
|
+
size: selectedFile.size
|
|
2233
|
+
});
|
|
2212
2234
|
const formData = new FormData();
|
|
2213
2235
|
formData.append("file", selectedFile);
|
|
2214
2236
|
try {
|
|
@@ -2217,20 +2239,47 @@ function FileUpload({ onUploadSuccess }) {
|
|
|
2217
2239
|
body: formData
|
|
2218
2240
|
});
|
|
2219
2241
|
setProgress(60);
|
|
2220
|
-
const data = await response.json()
|
|
2242
|
+
const data = await response.json().catch((parseErr) => {
|
|
2243
|
+
console.error("[upload] file-upload JSON parse failed", {
|
|
2244
|
+
status: response.status,
|
|
2245
|
+
parseErr
|
|
2246
|
+
});
|
|
2247
|
+
return {};
|
|
2248
|
+
});
|
|
2249
|
+
console.info("[upload] file-upload response", {
|
|
2250
|
+
status: response.status,
|
|
2251
|
+
ok: response.ok,
|
|
2252
|
+
url: data.url ?? data.filePath ?? null,
|
|
2253
|
+
error: data.error ?? null,
|
|
2254
|
+
details: data.details ?? null
|
|
2255
|
+
});
|
|
2221
2256
|
if (response.ok) {
|
|
2222
|
-
|
|
2257
|
+
const url = data.url ?? data.filePath;
|
|
2258
|
+
setFileUrl(url);
|
|
2223
2259
|
setProgress(100);
|
|
2224
|
-
|
|
2260
|
+
console.info("[upload] file-upload ok", {
|
|
2261
|
+
url,
|
|
2262
|
+
name: selectedFile.name
|
|
2263
|
+
});
|
|
2264
|
+
onUploadSuccess(url);
|
|
2225
2265
|
} else {
|
|
2226
2266
|
console.error("[upload] API error", {
|
|
2227
2267
|
status: response.status,
|
|
2228
2268
|
error: data.error,
|
|
2229
|
-
details: data.details
|
|
2269
|
+
details: data.details,
|
|
2270
|
+
name: selectedFile.name,
|
|
2271
|
+
type: selectedFile.type,
|
|
2272
|
+
size: selectedFile.size
|
|
2230
2273
|
});
|
|
2231
2274
|
}
|
|
2232
2275
|
} catch (error) {
|
|
2233
|
-
console.error("
|
|
2276
|
+
console.error("[upload] file-upload failed", {
|
|
2277
|
+
name: selectedFile.name,
|
|
2278
|
+
type: selectedFile.type,
|
|
2279
|
+
size: selectedFile.size,
|
|
2280
|
+
error: error instanceof Error ? error.message : String(error),
|
|
2281
|
+
stack: error instanceof Error ? error.stack : void 0
|
|
2282
|
+
});
|
|
2234
2283
|
}
|
|
2235
2284
|
setUploading(false);
|
|
2236
2285
|
}, "handleUpload");
|
|
@@ -2362,28 +2411,64 @@ function ImageOrUrlField({ label, value, onChange, placeholder = "https://\u2026
|
|
|
2362
2411
|
return;
|
|
2363
2412
|
}
|
|
2364
2413
|
setIsUploading(true);
|
|
2414
|
+
console.info("[upload] ImageOrUrlField start", {
|
|
2415
|
+
name: file.name,
|
|
2416
|
+
type: file.type,
|
|
2417
|
+
size: file.size,
|
|
2418
|
+
isVideo: isVideo2,
|
|
2419
|
+
maxSizeMb
|
|
2420
|
+
});
|
|
2365
2421
|
try {
|
|
2366
2422
|
const formData = new FormData();
|
|
2367
2423
|
formData.append("file", file);
|
|
2424
|
+
console.info("[upload] ImageOrUrlField POST /api/upload", {
|
|
2425
|
+
name: file.name,
|
|
2426
|
+
type: file.type,
|
|
2427
|
+
size: file.size
|
|
2428
|
+
});
|
|
2368
2429
|
const response = await fetch("/api/upload", {
|
|
2369
2430
|
method: "POST",
|
|
2370
2431
|
body: formData
|
|
2371
2432
|
});
|
|
2372
|
-
const data = await response.json().catch(() =>
|
|
2433
|
+
const data = await response.json().catch((parseErr) => {
|
|
2434
|
+
console.error("[upload] ImageOrUrlField JSON parse failed", {
|
|
2435
|
+
status: response.status,
|
|
2436
|
+
parseErr
|
|
2437
|
+
});
|
|
2438
|
+
return {};
|
|
2439
|
+
});
|
|
2440
|
+
console.info("[upload] ImageOrUrlField response", {
|
|
2441
|
+
status: response.status,
|
|
2442
|
+
ok: response.ok,
|
|
2443
|
+
filePath: data.filePath ?? null,
|
|
2444
|
+
error: data.error ?? null,
|
|
2445
|
+
details: data.details ?? null
|
|
2446
|
+
});
|
|
2373
2447
|
if (!response.ok) {
|
|
2374
2448
|
console.error("[upload] API error", {
|
|
2375
2449
|
status: response.status,
|
|
2376
2450
|
error: data.error,
|
|
2377
|
-
details: data.details
|
|
2451
|
+
details: data.details,
|
|
2452
|
+
fileName: file.name,
|
|
2453
|
+
fileType: file.type,
|
|
2454
|
+
fileSize: file.size
|
|
2378
2455
|
});
|
|
2379
2456
|
throw new Error(data.details || data.error || "Upload failed");
|
|
2380
2457
|
}
|
|
2381
2458
|
console.info("[upload] API ok", {
|
|
2382
|
-
filePath: data.filePath
|
|
2459
|
+
filePath: data.filePath,
|
|
2460
|
+
name: file.name,
|
|
2461
|
+
type: file.type
|
|
2383
2462
|
});
|
|
2384
2463
|
onChange(data.filePath ?? "");
|
|
2385
2464
|
} catch (err) {
|
|
2386
|
-
console.error("[upload] client failed",
|
|
2465
|
+
console.error("[upload] client failed", {
|
|
2466
|
+
name: file.name,
|
|
2467
|
+
type: file.type,
|
|
2468
|
+
size: file.size,
|
|
2469
|
+
error: err instanceof Error ? err.message : String(err),
|
|
2470
|
+
stack: err instanceof Error ? err.stack : void 0
|
|
2471
|
+
});
|
|
2387
2472
|
setError(err instanceof Error ? err.message : "Upload failed");
|
|
2388
2473
|
} finally {
|
|
2389
2474
|
setIsUploading(false);
|
|
@@ -5082,6 +5167,9 @@ function AdminCRUD({ title, apiEndpoint, columns, addEditPageUrl, customViewPage
|
|
|
5082
5167
|
});
|
|
5083
5168
|
if (cancelled) return;
|
|
5084
5169
|
if (!res.ok) {
|
|
5170
|
+
if (res.status === 403) {
|
|
5171
|
+
throw new Error("You don't have access to this section");
|
|
5172
|
+
}
|
|
5085
5173
|
throw new Error(`HTTP error! status: ${res.status}`);
|
|
5086
5174
|
}
|
|
5087
5175
|
const result = await res.json();
|
|
@@ -5498,15 +5586,26 @@ function AdminCRUD({ title, apiEndpoint, columns, addEditPageUrl, customViewPage
|
|
|
5498
5586
|
}, "Loading...")));
|
|
5499
5587
|
}
|
|
5500
5588
|
if (error) {
|
|
5589
|
+
const isForbidden = error.toLowerCase().includes("don't have access") || error.toLowerCase().includes("forbidden") || error.includes("403");
|
|
5501
5590
|
return /* @__PURE__ */ React.createElement("div", {
|
|
5502
5591
|
className: embedded ? "p-4" : "rounded-lg bg-white p-6 shadow-md"
|
|
5503
5592
|
}, /* @__PURE__ */ React.createElement("div", {
|
|
5504
|
-
className: "text-center py-
|
|
5505
|
-
}, /* @__PURE__ */ React.createElement("
|
|
5593
|
+
className: "text-center py-10"
|
|
5594
|
+
}, isForbidden ? /* @__PURE__ */ React.createElement("div", {
|
|
5595
|
+
className: "max-w-md mx-auto"
|
|
5596
|
+
}, /* @__PURE__ */ React.createElement("div", {
|
|
5597
|
+
className: "mx-auto flex h-12 w-12 items-center justify-center rounded-full bg-red-100 mb-3"
|
|
5598
|
+
}, /* @__PURE__ */ React.createElement(LucideIcons.ShieldAlert, {
|
|
5599
|
+
className: "h-6 w-6 text-red-600"
|
|
5600
|
+
})), /* @__PURE__ */ React.createElement("h3", {
|
|
5601
|
+
className: "text-base font-semibold text-gray-900 mb-1"
|
|
5602
|
+
}, "You don't have access"), /* @__PURE__ */ React.createElement("p", {
|
|
5603
|
+
className: "text-sm text-gray-500"
|
|
5604
|
+
}, "You don't have permission to view or manage this tab.")) : /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("p", {
|
|
5506
5605
|
className: "text-red-600 mb-4"
|
|
5507
5606
|
}, "Error loading data: ", error), /* @__PURE__ */ React.createElement(Button, {
|
|
5508
5607
|
onClick: /* @__PURE__ */ __name(() => window.location.reload(), "onClick")
|
|
5509
|
-
}, "Retry")));
|
|
5608
|
+
}, "Retry"))));
|
|
5510
5609
|
}
|
|
5511
5610
|
return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("div", {
|
|
5512
5611
|
className: shellCls
|
|
@@ -6343,6 +6442,7 @@ function FormBuilder({ formId, duplicateFromId }) {
|
|
|
6343
6442
|
campaign: "",
|
|
6344
6443
|
slug: "",
|
|
6345
6444
|
published: false,
|
|
6445
|
+
enableTurnstile: false,
|
|
6346
6446
|
fields: []
|
|
6347
6447
|
});
|
|
6348
6448
|
const [errors, setErrors] = React25.useState([]);
|
|
@@ -6376,6 +6476,7 @@ function FormBuilder({ formId, duplicateFromId }) {
|
|
|
6376
6476
|
campaign: data.campaign || "",
|
|
6377
6477
|
slug: slugNext,
|
|
6378
6478
|
published: isDup ? false : data.published,
|
|
6479
|
+
enableTurnstile: Boolean(data.enableTurnstile ?? data.enable_turnstile),
|
|
6379
6480
|
fields: (data.fields ?? []).map((field, index) => ({
|
|
6380
6481
|
...field,
|
|
6381
6482
|
id: isDup ? `field_dup_${Date.now()}_${index}` : field?.id != null ? String(field.id) : `field_${Date.now()}_${index}`,
|
|
@@ -6684,7 +6785,21 @@ function FormBuilder({ formId, duplicateFromId }) {
|
|
|
6684
6785
|
})), "onCheckedChange")
|
|
6685
6786
|
}), /* @__PURE__ */ React.createElement("label", {
|
|
6686
6787
|
className: "text-sm font-medium text-gray-700"
|
|
6687
|
-
}, "Published"))
|
|
6788
|
+
}, "Published")), /* @__PURE__ */ React.createElement("div", {
|
|
6789
|
+
className: "flex items-center space-x-2 pt-2 border-t border-gray-100"
|
|
6790
|
+
}, /* @__PURE__ */ React.createElement(Switch, {
|
|
6791
|
+
checked: formData.enableTurnstile ?? false,
|
|
6792
|
+
onCheckedChange: /* @__PURE__ */ __name((checked) => setFormData((prev) => ({
|
|
6793
|
+
...prev,
|
|
6794
|
+
enableTurnstile: checked
|
|
6795
|
+
})), "onCheckedChange")
|
|
6796
|
+
}), /* @__PURE__ */ React.createElement("div", {
|
|
6797
|
+
className: "flex flex-col"
|
|
6798
|
+
}, /* @__PURE__ */ React.createElement("label", {
|
|
6799
|
+
className: "text-sm font-medium text-gray-700"
|
|
6800
|
+
}, "Enable Cloudflare Turnstile"), /* @__PURE__ */ React.createElement("span", {
|
|
6801
|
+
className: "text-xs text-gray-500"
|
|
6802
|
+
}, "Requires user verification before submission (when Turnstile plugin is active)")))))), /* @__PURE__ */ React.createElement("div", {
|
|
6688
6803
|
className: "lg:col-span-2"
|
|
6689
6804
|
}, /* @__PURE__ */ React.createElement("div", {
|
|
6690
6805
|
className: "bg-white rounded-lg shadow"
|
|
@@ -6854,26 +6969,63 @@ function ImageUpload({ value, onChange, onRemove, label, required = false, class
|
|
|
6854
6969
|
return;
|
|
6855
6970
|
}
|
|
6856
6971
|
setIsUploading(true);
|
|
6972
|
+
console.info("[upload] client image-upload start", {
|
|
6973
|
+
name: file.name,
|
|
6974
|
+
type: file.type,
|
|
6975
|
+
size: file.size,
|
|
6976
|
+
maxSizeMb: maxSize
|
|
6977
|
+
});
|
|
6857
6978
|
try {
|
|
6858
6979
|
const formData = new FormData();
|
|
6859
6980
|
formData.append("file", file);
|
|
6981
|
+
console.info("[upload] client POST /api/upload", {
|
|
6982
|
+
name: file.name,
|
|
6983
|
+
type: file.type,
|
|
6984
|
+
size: file.size
|
|
6985
|
+
});
|
|
6860
6986
|
const response = await fetch("/api/upload", {
|
|
6861
6987
|
method: "POST",
|
|
6862
6988
|
body: formData
|
|
6863
6989
|
});
|
|
6864
|
-
const data = await response.json()
|
|
6990
|
+
const data = await response.json().catch((parseErr) => {
|
|
6991
|
+
console.error("[upload] client failed to parse JSON response", {
|
|
6992
|
+
status: response.status,
|
|
6993
|
+
parseErr
|
|
6994
|
+
});
|
|
6995
|
+
return {};
|
|
6996
|
+
});
|
|
6997
|
+
console.info("[upload] client response", {
|
|
6998
|
+
status: response.status,
|
|
6999
|
+
ok: response.ok,
|
|
7000
|
+
filePath: data.filePath ?? null,
|
|
7001
|
+
error: data.error ?? null,
|
|
7002
|
+
details: data.details ?? null
|
|
7003
|
+
});
|
|
6865
7004
|
if (!response.ok) {
|
|
6866
7005
|
console.error("[upload] API error", {
|
|
6867
7006
|
status: response.status,
|
|
6868
7007
|
error: data.error,
|
|
6869
|
-
details: data.details
|
|
7008
|
+
details: data.details,
|
|
7009
|
+
fileName: file.name,
|
|
7010
|
+
fileType: file.type,
|
|
7011
|
+
fileSize: file.size
|
|
6870
7012
|
});
|
|
6871
7013
|
throw new Error(data.details || data.error || "Upload failed");
|
|
6872
7014
|
}
|
|
7015
|
+
console.info("[upload] client image-upload ok", {
|
|
7016
|
+
filePath: data.filePath,
|
|
7017
|
+
name: file.name
|
|
7018
|
+
});
|
|
6873
7019
|
onChange(data.filePath);
|
|
6874
7020
|
setUploadProgress(100);
|
|
6875
7021
|
} catch (error2) {
|
|
6876
|
-
console.error("
|
|
7022
|
+
console.error("[upload] client image-upload failed", {
|
|
7023
|
+
name: file.name,
|
|
7024
|
+
type: file.type,
|
|
7025
|
+
size: file.size,
|
|
7026
|
+
error: error2 instanceof Error ? error2.message : String(error2),
|
|
7027
|
+
stack: error2 instanceof Error ? error2.stack : void 0
|
|
7028
|
+
});
|
|
6877
7029
|
setError(error2 instanceof Error ? error2.message : "Failed to upload image");
|
|
6878
7030
|
} finally {
|
|
6879
7031
|
setIsUploading(false);
|
|
@@ -16177,6 +16329,7 @@ var init_order_notification_bindings_shared = __esm({
|
|
|
16177
16329
|
"orderNumber",
|
|
16178
16330
|
"customerName",
|
|
16179
16331
|
"customerPhone",
|
|
16332
|
+
"customerEmail",
|
|
16180
16333
|
"eventName",
|
|
16181
16334
|
"vendorName",
|
|
16182
16335
|
"total",
|
|
@@ -16184,7 +16337,8 @@ var init_order_notification_bindings_shared = __esm({
|
|
|
16184
16337
|
"vendorId",
|
|
16185
16338
|
"refundAmount",
|
|
16186
16339
|
"invoiceNumber",
|
|
16187
|
-
"
|
|
16340
|
+
"invoiceAttachment",
|
|
16341
|
+
"orderDetails"
|
|
16188
16342
|
];
|
|
16189
16343
|
__name(useNotificationVariables, "useNotificationVariables");
|
|
16190
16344
|
EMAIL_TRIGGER_DEFAULTS = {
|
|
@@ -16216,6 +16370,43 @@ If you have any questions, please contact us.
|
|
|
16216
16370
|
|
|
16217
16371
|
Thank you!`,
|
|
16218
16372
|
bodyPlaceholder: "Hi {{customerName}},\n\nYour order {{orderNumber}} has been cancelled.\n\nIf a refund is due, it will be returned to your original payment method."
|
|
16373
|
+
},
|
|
16374
|
+
payment_success: {
|
|
16375
|
+
subject: "Payment Successful for Order {{orderNumber}}",
|
|
16376
|
+
subjectPlaceholder: "e.g. Payment Successful for Order {{orderNumber}}",
|
|
16377
|
+
body: `Hi {{customerName}},
|
|
16378
|
+
|
|
16379
|
+
We have received your payment for order {{orderNumber}} of {{total}} {{currency}}.
|
|
16380
|
+
|
|
16381
|
+
Order Details:
|
|
16382
|
+
{{orderDetails}}
|
|
16383
|
+
|
|
16384
|
+
Thank you!`,
|
|
16385
|
+
bodyPlaceholder: "Hi {{customerName}},\n\nPayment for order {{orderNumber}} was successful.\n\nThank you!"
|
|
16386
|
+
},
|
|
16387
|
+
payment_failed: {
|
|
16388
|
+
subject: "Payment Failed for Order {{orderNumber}}",
|
|
16389
|
+
subjectPlaceholder: "e.g. Payment Failed for Order {{orderNumber}}",
|
|
16390
|
+
body: `Hi {{customerName}},
|
|
16391
|
+
|
|
16392
|
+
Your payment for order {{orderNumber}} of {{total}} {{currency}} could not be completed or remains unpaid.
|
|
16393
|
+
|
|
16394
|
+
If you were charged, please contact us with your order number {{orderNumber}}.
|
|
16395
|
+
|
|
16396
|
+
Thank you!`,
|
|
16397
|
+
bodyPlaceholder: "Hi {{customerName}},\n\nPayment for order {{orderNumber}} failed or remains unpaid.\n\nThank you!"
|
|
16398
|
+
},
|
|
16399
|
+
payment_refund_initiated: {
|
|
16400
|
+
subject: "Refund Initiated for Order {{orderNumber}}",
|
|
16401
|
+
subjectPlaceholder: "e.g. Refund Initiated for Order {{orderNumber}}",
|
|
16402
|
+
body: `Hi {{customerName}},
|
|
16403
|
+
|
|
16404
|
+
Your order {{orderNumber}} has been cancelled and a refund of {{refundAmount}} {{currency}} has been initiated.
|
|
16405
|
+
|
|
16406
|
+
The amount will be credited back to your original payment method.
|
|
16407
|
+
|
|
16408
|
+
Thank you!`,
|
|
16409
|
+
bodyPlaceholder: "Hi {{customerName}},\n\nRefund of {{refundAmount}} {{currency}} for order {{orderNumber}} has been initiated."
|
|
16219
16410
|
}
|
|
16220
16411
|
};
|
|
16221
16412
|
VENDOR_EMAIL_TRIGGER_DEFAULTS = {
|
|
@@ -16240,12 +16431,48 @@ Thank you!`,
|
|
|
16240
16431
|
|
|
16241
16432
|
Order {{orderNumber}} for {{total}} {{currency}} has been cancelled.
|
|
16242
16433
|
|
|
16243
|
-
Customer: {{customerName}
|
|
16434
|
+
Customer: {{customerName}}
|
|
16244
16435
|
Order Items:
|
|
16245
16436
|
{{orderDetails}}
|
|
16246
16437
|
|
|
16247
16438
|
Thank you.`,
|
|
16248
16439
|
bodyPlaceholder: "Hi {{vendorName}},\n\nOrder {{orderNumber}} was cancelled."
|
|
16440
|
+
},
|
|
16441
|
+
payment_success: {
|
|
16442
|
+
subject: "Payment Confirmed for Order {{orderNumber}} - {{customerName}}",
|
|
16443
|
+
subjectPlaceholder: "e.g. Payment Confirmed for Order {{orderNumber}}",
|
|
16444
|
+
body: `Hi {{vendorName}},
|
|
16445
|
+
|
|
16446
|
+
Payment has been confirmed for order {{orderNumber}} ({{total}} {{currency}}).
|
|
16447
|
+
|
|
16448
|
+
Customer: {{customerName}}
|
|
16449
|
+
Order Items:
|
|
16450
|
+
{{orderDetails}}
|
|
16451
|
+
|
|
16452
|
+
Thank you!`,
|
|
16453
|
+
bodyPlaceholder: "Hi {{vendorName}},\n\nPayment for order {{orderNumber}} confirmed."
|
|
16454
|
+
},
|
|
16455
|
+
payment_failed: {
|
|
16456
|
+
subject: "Payment Unpaid / Failed for Order {{orderNumber}}",
|
|
16457
|
+
subjectPlaceholder: "e.g. Payment Unpaid for Order {{orderNumber}}",
|
|
16458
|
+
body: `Hi {{vendorName}},
|
|
16459
|
+
|
|
16460
|
+
Payment for order {{orderNumber}} ({{total}} {{currency}}) is unpaid or failed.
|
|
16461
|
+
|
|
16462
|
+
Customer: {{customerName}}
|
|
16463
|
+
|
|
16464
|
+
Thank you.`,
|
|
16465
|
+
bodyPlaceholder: "Hi {{vendorName}},\n\nPayment for order {{orderNumber}} failed or unpaid."
|
|
16466
|
+
},
|
|
16467
|
+
payment_refund_initiated: {
|
|
16468
|
+
subject: "Refund Initiated for Order {{orderNumber}}",
|
|
16469
|
+
subjectPlaceholder: "e.g. Refund Initiated for Order {{orderNumber}}",
|
|
16470
|
+
body: `Hi {{vendorName}},
|
|
16471
|
+
|
|
16472
|
+
Order {{orderNumber}} has been cancelled and a refund of {{refundAmount}} {{currency}} has been initiated for {{customerName}}.
|
|
16473
|
+
|
|
16474
|
+
Thank you.`,
|
|
16475
|
+
bodyPlaceholder: "Hi {{vendorName}},\n\nRefund initiated for order {{orderNumber}}."
|
|
16249
16476
|
}
|
|
16250
16477
|
};
|
|
16251
16478
|
ADMIN_EMAIL_TRIGGER_DEFAULTS = {
|
|
@@ -16277,6 +16504,42 @@ Customer: {{customerName}}
|
|
|
16277
16504
|
Vendor: {{vendorName}}
|
|
16278
16505
|
Refund Due: {{refundAmount}} {{currency}}`,
|
|
16279
16506
|
bodyPlaceholder: "Hi Admin,\n\nOrder {{orderNumber}} cancelled."
|
|
16507
|
+
},
|
|
16508
|
+
payment_success: {
|
|
16509
|
+
subject: "Payment Success Alert: Order {{orderNumber}} ({{total}} {{currency}})",
|
|
16510
|
+
subjectPlaceholder: "e.g. Payment Success Alert: Order {{orderNumber}}",
|
|
16511
|
+
body: `Hi Admin,
|
|
16512
|
+
|
|
16513
|
+
Payment of {{total}} {{currency}} was successfully captured for order {{orderNumber}}.
|
|
16514
|
+
|
|
16515
|
+
Customer: {{customerName}}
|
|
16516
|
+
Vendor: {{vendorName}}
|
|
16517
|
+
|
|
16518
|
+
Order Summary:
|
|
16519
|
+
{{orderDetails}}`,
|
|
16520
|
+
bodyPlaceholder: "Payment received for order {{orderNumber}}."
|
|
16521
|
+
},
|
|
16522
|
+
payment_failed: {
|
|
16523
|
+
subject: "Payment Failed / Unpaid Alert: Order {{orderNumber}}",
|
|
16524
|
+
subjectPlaceholder: "e.g. Payment Failed Alert: Order {{orderNumber}}",
|
|
16525
|
+
body: `Hi Admin,
|
|
16526
|
+
|
|
16527
|
+
Payment for order {{orderNumber}} ({{total}} {{currency}}) is unpaid or failed.
|
|
16528
|
+
|
|
16529
|
+
Customer: {{customerName}}
|
|
16530
|
+
Vendor: {{vendorName}}`,
|
|
16531
|
+
bodyPlaceholder: "Payment failed/unpaid for order {{orderNumber}}."
|
|
16532
|
+
},
|
|
16533
|
+
payment_refund_initiated: {
|
|
16534
|
+
subject: "Refund Initiated Alert: Order {{orderNumber}}",
|
|
16535
|
+
subjectPlaceholder: "e.g. Refund Initiated Alert: Order {{orderNumber}}",
|
|
16536
|
+
body: `Hi Admin,
|
|
16537
|
+
|
|
16538
|
+
Order {{orderNumber}} was cancelled and refund of {{refundAmount}} {{currency}} was initiated.
|
|
16539
|
+
|
|
16540
|
+
Customer: {{customerName}}
|
|
16541
|
+
Vendor: {{vendorName}}`,
|
|
16542
|
+
bodyPlaceholder: "Refund initiated for order {{orderNumber}}."
|
|
16280
16543
|
}
|
|
16281
16544
|
};
|
|
16282
16545
|
__name(getEmailTriggerDefaults, "getEmailTriggerDefaults");
|
|
@@ -16292,6 +16555,24 @@ Refund Due: {{refundAmount}} {{currency}}`,
|
|
|
16292
16555
|
subjectPlaceholder: "e.g. Order {{orderNumber}} Cancelled",
|
|
16293
16556
|
body: `Hi {{customerName}}, your order {{orderNumber}} for {{total}} {{currency}} has been cancelled.`,
|
|
16294
16557
|
bodyPlaceholder: "Hi {{customerName}}, your order {{orderNumber}} has been cancelled."
|
|
16558
|
+
},
|
|
16559
|
+
payment_success: {
|
|
16560
|
+
subject: "Payment Successful!",
|
|
16561
|
+
subjectPlaceholder: "e.g. Payment Successful!",
|
|
16562
|
+
body: `Hi {{customerName}}, payment for order {{orderNumber}} ({{total}} {{currency}}) was successful.`,
|
|
16563
|
+
bodyPlaceholder: "Payment for order {{orderNumber}} successful."
|
|
16564
|
+
},
|
|
16565
|
+
payment_failed: {
|
|
16566
|
+
subject: "Payment Unpaid / Failed",
|
|
16567
|
+
subjectPlaceholder: "e.g. Payment Unpaid / Failed",
|
|
16568
|
+
body: `Hi {{customerName}}, payment for order {{orderNumber}} failed or remains unpaid.`,
|
|
16569
|
+
bodyPlaceholder: "Payment for order {{orderNumber}} failed."
|
|
16570
|
+
},
|
|
16571
|
+
payment_refund_initiated: {
|
|
16572
|
+
subject: "Refund Initiated",
|
|
16573
|
+
subjectPlaceholder: "e.g. Refund Initiated",
|
|
16574
|
+
body: `Hi {{customerName}}, a refund of {{refundAmount}} {{currency}} for order {{orderNumber}} has been initiated.`,
|
|
16575
|
+
bodyPlaceholder: "Refund for order {{orderNumber}} initiated."
|
|
16295
16576
|
}
|
|
16296
16577
|
};
|
|
16297
16578
|
VENDOR_PUSH_TRIGGER_DEFAULTS = {
|
|
@@ -16306,6 +16587,24 @@ Refund Due: {{refundAmount}} {{currency}}`,
|
|
|
16306
16587
|
subjectPlaceholder: "e.g. Order {{orderNumber}} Cancelled",
|
|
16307
16588
|
body: `Hi {{vendorName}}, order {{orderNumber}} from {{customerName}} has been cancelled.`,
|
|
16308
16589
|
bodyPlaceholder: "Hi {{vendorName}}, order {{orderNumber}} was cancelled."
|
|
16590
|
+
},
|
|
16591
|
+
payment_success: {
|
|
16592
|
+
subject: "Payment Confirmed: {{orderNumber}}",
|
|
16593
|
+
subjectPlaceholder: "e.g. Payment Confirmed: {{orderNumber}}",
|
|
16594
|
+
body: `Hi {{vendorName}}, payment for order {{orderNumber}} from {{customerName}} has been confirmed.`,
|
|
16595
|
+
bodyPlaceholder: "Payment for order {{orderNumber}} confirmed."
|
|
16596
|
+
},
|
|
16597
|
+
payment_failed: {
|
|
16598
|
+
subject: "Payment Unpaid: {{orderNumber}}",
|
|
16599
|
+
subjectPlaceholder: "e.g. Payment Unpaid: {{orderNumber}}",
|
|
16600
|
+
body: `Hi {{vendorName}}, payment for order {{orderNumber}} from {{customerName}} is unpaid or failed.`,
|
|
16601
|
+
bodyPlaceholder: "Payment for order {{orderNumber}} unpaid."
|
|
16602
|
+
},
|
|
16603
|
+
payment_refund_initiated: {
|
|
16604
|
+
subject: "Refund Initiated: {{orderNumber}}",
|
|
16605
|
+
subjectPlaceholder: "e.g. Refund Initiated: {{orderNumber}}",
|
|
16606
|
+
body: `Hi {{vendorName}}, refund initiated for order {{orderNumber}} ({{customerName}}).`,
|
|
16607
|
+
bodyPlaceholder: "Refund initiated for order {{orderNumber}}."
|
|
16309
16608
|
}
|
|
16310
16609
|
};
|
|
16311
16610
|
ADMIN_PUSH_TRIGGER_DEFAULTS = {
|
|
@@ -16337,6 +16636,24 @@ Customer: {{customerName}}
|
|
|
16337
16636
|
Vendor: {{vendorName}}
|
|
16338
16637
|
Refund Due: {{refundAmount}} {{currency}}`,
|
|
16339
16638
|
bodyPlaceholder: "Hi Admin,\n\nOrder {{orderNumber}} cancelled."
|
|
16639
|
+
},
|
|
16640
|
+
payment_success: {
|
|
16641
|
+
subject: "Payment Success: {{orderNumber}}",
|
|
16642
|
+
subjectPlaceholder: "e.g. Payment Success: {{orderNumber}}",
|
|
16643
|
+
body: `Payment of {{total}} {{currency}} captured for order {{orderNumber}} ({{customerName}}).`,
|
|
16644
|
+
bodyPlaceholder: "Payment captured for order {{orderNumber}}."
|
|
16645
|
+
},
|
|
16646
|
+
payment_failed: {
|
|
16647
|
+
subject: "Payment Failed/Unpaid: {{orderNumber}}",
|
|
16648
|
+
subjectPlaceholder: "e.g. Payment Failed: {{orderNumber}}",
|
|
16649
|
+
body: `Payment for order {{orderNumber}} ({{customerName}}) is unpaid or failed.`,
|
|
16650
|
+
bodyPlaceholder: "Payment failed for order {{orderNumber}}."
|
|
16651
|
+
},
|
|
16652
|
+
payment_refund_initiated: {
|
|
16653
|
+
subject: "Refund Initiated: {{orderNumber}}",
|
|
16654
|
+
subjectPlaceholder: "e.g. Refund Initiated: {{orderNumber}}",
|
|
16655
|
+
body: `Refund of {{refundAmount}} {{currency}} initiated for order {{orderNumber}}.`,
|
|
16656
|
+
bodyPlaceholder: "Refund initiated for order {{orderNumber}}."
|
|
16340
16657
|
}
|
|
16341
16658
|
};
|
|
16342
16659
|
__name(getPushTriggerDefaults, "getPushTriggerDefaults");
|
|
@@ -16990,6 +17307,7 @@ var init_emailTriggersBindingsPage = __esm({
|
|
|
16990
17307
|
orderNumber: "Display order number",
|
|
16991
17308
|
customerName: "Customer full name",
|
|
16992
17309
|
customerPhone: "Customer phone",
|
|
17310
|
+
customerEmail: "Customer email address",
|
|
16993
17311
|
eventName: "Event title / product name",
|
|
16994
17312
|
vendorName: "Vendor / store name",
|
|
16995
17313
|
total: "Order total amount",
|
|
@@ -16997,7 +17315,8 @@ var init_emailTriggersBindingsPage = __esm({
|
|
|
16997
17315
|
vendorId: "Vendor / store ID",
|
|
16998
17316
|
refundAmount: "Refund amount (refund triggers)",
|
|
16999
17317
|
invoiceNumber: "Generated invoice number",
|
|
17000
|
-
|
|
17318
|
+
invoiceAttachment: "Include this variable to attach Tax Invoice PDF to email",
|
|
17319
|
+
orderDetails: "Formatted item details summary"
|
|
17001
17320
|
};
|
|
17002
17321
|
__name(EmailTriggerBindings, "EmailTriggerBindings");
|
|
17003
17322
|
__name(TriggerEmailEditor, "TriggerEmailEditor");
|
|
@@ -17295,6 +17614,7 @@ var init_pushTriggersBindingsPage = __esm({
|
|
|
17295
17614
|
orderNumber: "Display order number",
|
|
17296
17615
|
customerName: "Customer full name",
|
|
17297
17616
|
customerPhone: "Customer phone",
|
|
17617
|
+
customerEmail: "Customer email address",
|
|
17298
17618
|
eventName: "Event title / product name",
|
|
17299
17619
|
vendorName: "Vendor / store name",
|
|
17300
17620
|
total: "Order total amount",
|
|
@@ -17302,7 +17622,8 @@ var init_pushTriggersBindingsPage = __esm({
|
|
|
17302
17622
|
vendorId: "Vendor / store ID",
|
|
17303
17623
|
refundAmount: "Refund amount (refund triggers)",
|
|
17304
17624
|
invoiceNumber: "Generated invoice number",
|
|
17305
|
-
|
|
17625
|
+
invoiceAttachment: "Include this variable to attach Tax Invoice PDF to email",
|
|
17626
|
+
orderDetails: "Formatted item details summary"
|
|
17306
17627
|
};
|
|
17307
17628
|
__name(PushTriggerBindings, "PushTriggerBindings");
|
|
17308
17629
|
}
|
|
@@ -18140,6 +18461,177 @@ var init_AuthProvidersPluginSettings = __esm({
|
|
|
18140
18461
|
__name(AuthProvidersPluginSettings, "AuthProvidersPluginSettings");
|
|
18141
18462
|
}
|
|
18142
18463
|
});
|
|
18464
|
+
function TurnstilePluginSettings({ settingsGroup, onEnabledChange }) {
|
|
18465
|
+
const [loading, setLoading] = React25.useState(true);
|
|
18466
|
+
const [saving, setSaving] = React25.useState(false);
|
|
18467
|
+
const [enabled, setEnabled] = React25.useState(false);
|
|
18468
|
+
const [siteKey, setSiteKey] = React25.useState("");
|
|
18469
|
+
const [secretKey, setSecretKey] = React25.useState("");
|
|
18470
|
+
const [hasSavedSecret, setHasSavedSecret] = React25.useState(false);
|
|
18471
|
+
const [showSecret, setShowSecret] = React25.useState(false);
|
|
18472
|
+
const onEnabledChangeRef = React25.useRef(onEnabledChange);
|
|
18473
|
+
onEnabledChangeRef.current = onEnabledChange;
|
|
18474
|
+
React25.useEffect(() => {
|
|
18475
|
+
let cancelled = false;
|
|
18476
|
+
(async () => {
|
|
18477
|
+
setLoading(true);
|
|
18478
|
+
try {
|
|
18479
|
+
const res = await fetch(`/api/settings/${settingsGroup}`, {
|
|
18480
|
+
cache: "no-store"
|
|
18481
|
+
});
|
|
18482
|
+
const data = res.ok ? await res.json() : {};
|
|
18483
|
+
if (cancelled) return;
|
|
18484
|
+
const isEnabled = data.enabled === "true" || data.enabled === "1";
|
|
18485
|
+
setEnabled(isEnabled);
|
|
18486
|
+
setSiteKey(String(data.siteKey ?? data.TURNSTILE_SITE_KEY ?? "").trim());
|
|
18487
|
+
const secret = String(data.secretKey ?? data.TURNSTILE_SECRET_KEY ?? "").trim();
|
|
18488
|
+
setSecretKey("");
|
|
18489
|
+
setHasSavedSecret(Boolean(secret));
|
|
18490
|
+
} catch {
|
|
18491
|
+
} finally {
|
|
18492
|
+
if (!cancelled) setLoading(false);
|
|
18493
|
+
}
|
|
18494
|
+
})();
|
|
18495
|
+
return () => {
|
|
18496
|
+
cancelled = true;
|
|
18497
|
+
};
|
|
18498
|
+
}, [
|
|
18499
|
+
settingsGroup
|
|
18500
|
+
]);
|
|
18501
|
+
const handleSave = /* @__PURE__ */ __name(async () => {
|
|
18502
|
+
setSaving(true);
|
|
18503
|
+
try {
|
|
18504
|
+
const payload = {
|
|
18505
|
+
enabled: {
|
|
18506
|
+
value: enabled ? "true" : "false",
|
|
18507
|
+
type: "public"
|
|
18508
|
+
},
|
|
18509
|
+
siteKey: {
|
|
18510
|
+
value: siteKey.trim(),
|
|
18511
|
+
type: "public"
|
|
18512
|
+
}
|
|
18513
|
+
};
|
|
18514
|
+
if (secretKey.trim()) {
|
|
18515
|
+
payload.secretKey = {
|
|
18516
|
+
value: secretKey.trim(),
|
|
18517
|
+
type: "private",
|
|
18518
|
+
encrypted: true
|
|
18519
|
+
};
|
|
18520
|
+
}
|
|
18521
|
+
const res = await fetch(`/api/settings/${settingsGroup}`, {
|
|
18522
|
+
method: "PUT",
|
|
18523
|
+
headers: {
|
|
18524
|
+
"Content-Type": "application/json"
|
|
18525
|
+
},
|
|
18526
|
+
body: JSON.stringify(payload)
|
|
18527
|
+
});
|
|
18528
|
+
if (res.ok) {
|
|
18529
|
+
sonner.toast.success("Turnstile settings saved");
|
|
18530
|
+
if (secretKey.trim()) {
|
|
18531
|
+
setHasSavedSecret(true);
|
|
18532
|
+
setSecretKey("");
|
|
18533
|
+
}
|
|
18534
|
+
onEnabledChangeRef.current?.(enabled);
|
|
18535
|
+
} else {
|
|
18536
|
+
const err = await res.json().catch(() => ({}));
|
|
18537
|
+
sonner.toast.error(err?.message || "Failed to save settings");
|
|
18538
|
+
}
|
|
18539
|
+
} catch {
|
|
18540
|
+
sonner.toast.error("Failed to save settings");
|
|
18541
|
+
} finally {
|
|
18542
|
+
setSaving(false);
|
|
18543
|
+
}
|
|
18544
|
+
}, "handleSave");
|
|
18545
|
+
if (loading) {
|
|
18546
|
+
return /* @__PURE__ */ React.createElement("div", {
|
|
18547
|
+
className: "flex items-center justify-center p-8 text-muted-foreground text-sm"
|
|
18548
|
+
}, /* @__PURE__ */ React.createElement(LucideIcons.Loader2, {
|
|
18549
|
+
className: "mr-2 h-4 w-4 animate-spin"
|
|
18550
|
+
}), "Loading settings\u2026");
|
|
18551
|
+
}
|
|
18552
|
+
return /* @__PURE__ */ React.createElement("div", {
|
|
18553
|
+
className: "space-y-6"
|
|
18554
|
+
}, /* @__PURE__ */ React.createElement("div", {
|
|
18555
|
+
className: "rounded-lg border border-gray-200 bg-gray-50/80 p-4 dark:border-gray-700 dark:bg-gray-800/40"
|
|
18556
|
+
}, /* @__PURE__ */ React.createElement("div", {
|
|
18557
|
+
className: "flex items-center justify-between"
|
|
18558
|
+
}, /* @__PURE__ */ React.createElement("div", {
|
|
18559
|
+
className: "space-y-0.5"
|
|
18560
|
+
}, /* @__PURE__ */ React.createElement(Label3, {
|
|
18561
|
+
htmlFor: `${settingsGroup}-enabled`,
|
|
18562
|
+
className: "text-sm font-semibold text-gray-900 dark:text-white"
|
|
18563
|
+
}, "Enable Cloudflare Turnstile"), /* @__PURE__ */ React.createElement("p", {
|
|
18564
|
+
className: "text-xs text-muted-foreground"
|
|
18565
|
+
}, "Master switch for bot protection. When enabled, helps protect supported forms from automated bots, while forms can apply their configured bot protection settings.")), /* @__PURE__ */ React.createElement(Switch, {
|
|
18566
|
+
id: `${settingsGroup}-enabled`,
|
|
18567
|
+
checked: enabled,
|
|
18568
|
+
onCheckedChange: setEnabled
|
|
18569
|
+
}))), /* @__PURE__ */ React.createElement("div", {
|
|
18570
|
+
className: "space-y-4"
|
|
18571
|
+
}, /* @__PURE__ */ React.createElement("div", {
|
|
18572
|
+
className: "space-y-1.5"
|
|
18573
|
+
}, /* @__PURE__ */ React.createElement(Label3, {
|
|
18574
|
+
htmlFor: `${settingsGroup}-siteKey`,
|
|
18575
|
+
className: "text-sm font-medium"
|
|
18576
|
+
}, "Turnstile Site Key (Public)"), /* @__PURE__ */ React.createElement(Input, {
|
|
18577
|
+
id: `${settingsGroup}-siteKey`,
|
|
18578
|
+
value: siteKey,
|
|
18579
|
+
onChange: /* @__PURE__ */ __name((e) => setSiteKey(e.target.value), "onChange"),
|
|
18580
|
+
placeholder: "0x4AAAAAA...",
|
|
18581
|
+
className: "h-9 font-mono text-sm"
|
|
18582
|
+
}), /* @__PURE__ */ React.createElement("p", {
|
|
18583
|
+
className: "text-xs text-muted-foreground"
|
|
18584
|
+
}, "Obtained from your Cloudflare dashboard under Turnstile Sites. Safe to expose to the frontend.")), /* @__PURE__ */ React.createElement("div", {
|
|
18585
|
+
className: "space-y-1.5"
|
|
18586
|
+
}, /* @__PURE__ */ React.createElement("div", {
|
|
18587
|
+
className: "flex items-center justify-between"
|
|
18588
|
+
}, /* @__PURE__ */ React.createElement(Label3, {
|
|
18589
|
+
htmlFor: `${settingsGroup}-secretKey`,
|
|
18590
|
+
className: "text-sm font-medium"
|
|
18591
|
+
}, "Turnstile Secret Key (Private)"), hasSavedSecret && /* @__PURE__ */ React.createElement("span", {
|
|
18592
|
+
className: "inline-flex items-center gap-1 text-xs font-medium text-emerald-600 dark:text-emerald-400"
|
|
18593
|
+
}, /* @__PURE__ */ React.createElement(LucideIcons.ShieldCheck, {
|
|
18594
|
+
className: "h-3.5 w-3.5"
|
|
18595
|
+
}), "Secret key configured")), /* @__PURE__ */ React.createElement("div", {
|
|
18596
|
+
className: "relative"
|
|
18597
|
+
}, /* @__PURE__ */ React.createElement(Input, {
|
|
18598
|
+
id: `${settingsGroup}-secretKey`,
|
|
18599
|
+
type: showSecret ? "text" : "password",
|
|
18600
|
+
value: secretKey,
|
|
18601
|
+
onChange: /* @__PURE__ */ __name((e) => setSecretKey(e.target.value), "onChange"),
|
|
18602
|
+
placeholder: hasSavedSecret ? "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022 (leave blank to keep unchanged)" : "0x4AAAAAA...",
|
|
18603
|
+
className: "h-9 font-mono text-sm pr-10"
|
|
18604
|
+
}), /* @__PURE__ */ React.createElement("button", {
|
|
18605
|
+
type: "button",
|
|
18606
|
+
className: "absolute right-2.5 top-1/2 -translate-y-1/2 text-gray-400 hover:text-gray-600 dark:hover:text-gray-200",
|
|
18607
|
+
onClick: /* @__PURE__ */ __name(() => setShowSecret(!showSecret), "onClick")
|
|
18608
|
+
}, showSecret ? /* @__PURE__ */ React.createElement(LucideIcons.EyeOff, {
|
|
18609
|
+
className: "h-4 w-4"
|
|
18610
|
+
}) : /* @__PURE__ */ React.createElement(LucideIcons.Eye, {
|
|
18611
|
+
className: "h-4 w-4"
|
|
18612
|
+
}))), /* @__PURE__ */ React.createElement("p", {
|
|
18613
|
+
className: "text-xs text-muted-foreground"
|
|
18614
|
+
}, "Used only on the server to verify tokens with Cloudflare Siteverify API. Never sent to browsers."))), /* @__PURE__ */ React.createElement(Button, {
|
|
18615
|
+
onClick: handleSave,
|
|
18616
|
+
disabled: saving,
|
|
18617
|
+
size: "sm",
|
|
18618
|
+
className: "gap-2"
|
|
18619
|
+
}, saving ? /* @__PURE__ */ React.createElement(LucideIcons.Loader2, {
|
|
18620
|
+
className: "h-4 w-4 animate-spin"
|
|
18621
|
+
}) : /* @__PURE__ */ React.createElement(LucideIcons.Save, {
|
|
18622
|
+
className: "h-4 w-4"
|
|
18623
|
+
}), "Save Settings"));
|
|
18624
|
+
}
|
|
18625
|
+
var init_TurnstilePluginSettings = __esm({
|
|
18626
|
+
"src/admin/components/TurnstilePluginSettings.tsx"() {
|
|
18627
|
+
"use client";
|
|
18628
|
+
init_button();
|
|
18629
|
+
init_input();
|
|
18630
|
+
init_label();
|
|
18631
|
+
init_switch();
|
|
18632
|
+
__name(TurnstilePluginSettings, "TurnstilePluginSettings");
|
|
18633
|
+
}
|
|
18634
|
+
});
|
|
18143
18635
|
|
|
18144
18636
|
// src/plugins/llm/chat-email-intent.ts
|
|
18145
18637
|
function normalizeIntentKey(raw) {
|
|
@@ -18518,6 +19010,7 @@ function PluginSettingsPanel({ descriptor, onSaved }) {
|
|
|
18518
19010
|
const isSocialMedia = settingsGroup === "social_media";
|
|
18519
19011
|
const isMultiVendor = settingsGroup === "multi_vendor";
|
|
18520
19012
|
const isAuthProviders = settingsGroup === "auth_providers";
|
|
19013
|
+
const isTurnstile = settingsGroup === "turnstile";
|
|
18521
19014
|
const [enabled, setEnabled] = React25.useState(true);
|
|
18522
19015
|
const [botName, setBotName] = React25.useState("");
|
|
18523
19016
|
const [icon, setIcon] = React25.useState("");
|
|
@@ -19861,6 +20354,15 @@ function PluginSettingsPanel({ descriptor, onSaved }) {
|
|
|
19861
20354
|
}, "onEnabledChange")
|
|
19862
20355
|
});
|
|
19863
20356
|
}
|
|
20357
|
+
if (isTurnstile) {
|
|
20358
|
+
return /* @__PURE__ */ React.createElement(TurnstilePluginSettings, {
|
|
20359
|
+
settingsGroup,
|
|
20360
|
+
onEnabledChange: /* @__PURE__ */ __name((value) => {
|
|
20361
|
+
setEnabled(value);
|
|
20362
|
+
onSaved?.();
|
|
20363
|
+
}, "onEnabledChange")
|
|
20364
|
+
});
|
|
20365
|
+
}
|
|
19864
20366
|
if (loading) return /* @__PURE__ */ React.createElement("div", {
|
|
19865
20367
|
className: "text-sm text-gray-500 dark:text-gray-400"
|
|
19866
20368
|
}, "Loading...");
|
|
@@ -21201,6 +21703,10 @@ function PluginsPage() {
|
|
|
21201
21703
|
const ap = pluginDescriptors.find((p) => p.name === "auth_providers");
|
|
21202
21704
|
if (ap) setSelectedName(ap.name);
|
|
21203
21705
|
}
|
|
21706
|
+
if (q === "turnstile" || q === "cloudflare_turnstile" || q === "captcha") {
|
|
21707
|
+
const ts = pluginDescriptors.find((p) => p.name === "turnstile");
|
|
21708
|
+
if (ts) setSelectedName(ts.name);
|
|
21709
|
+
}
|
|
21204
21710
|
}, [
|
|
21205
21711
|
searchParams,
|
|
21206
21712
|
pluginDescriptors
|
|
@@ -21313,6 +21819,7 @@ var init_PluginsPage = __esm({
|
|
|
21313
21819
|
init_select();
|
|
21314
21820
|
init_EventNotificationsPluginSettings();
|
|
21315
21821
|
init_AuthProvidersPluginSettings();
|
|
21822
|
+
init_TurnstilePluginSettings();
|
|
21316
21823
|
init_ImageOrUrlField();
|
|
21317
21824
|
init_chat_email_intent();
|
|
21318
21825
|
init_llm_agent_scope();
|
|
@@ -21332,7 +21839,8 @@ var init_PluginsPage = __esm({
|
|
|
21332
21839
|
share: LucideIcons.Share2,
|
|
21333
21840
|
whatsapp: LucideIcons.MessageCircle,
|
|
21334
21841
|
event_notifications: LucideIcons.Bell,
|
|
21335
|
-
auth_providers: LucideIcons.KeyRound
|
|
21842
|
+
auth_providers: LucideIcons.KeyRound,
|
|
21843
|
+
turnstile: LucideIcons.ShieldCheck
|
|
21336
21844
|
};
|
|
21337
21845
|
__name(normalizeSmsProviderChoice, "normalizeSmsProviderChoice");
|
|
21338
21846
|
__name(normalizeMsg91ApiMode, "normalizeMsg91ApiMode");
|
|
@@ -22294,7 +22802,7 @@ function VendorTeamPage() {
|
|
|
22294
22802
|
}
|
|
22295
22803
|
}, []);
|
|
22296
22804
|
React25.useEffect(() => {
|
|
22297
|
-
if (canManage) load();
|
|
22805
|
+
if (canManage) void load();
|
|
22298
22806
|
else setLoading(false);
|
|
22299
22807
|
}, [
|
|
22300
22808
|
canManage,
|
|
@@ -22352,10 +22860,18 @@ function VendorTeamPage() {
|
|
|
22352
22860
|
}, "closeInviteDialog");
|
|
22353
22861
|
if (!canManage) {
|
|
22354
22862
|
return /* @__PURE__ */ React25__namespace.default.createElement("div", {
|
|
22355
|
-
className: "
|
|
22863
|
+
className: "min-w-0 rounded-lg bg-white shadow-md"
|
|
22864
|
+
}, /* @__PURE__ */ React25__namespace.default.createElement("div", {
|
|
22865
|
+
className: "rounded-t-lg border-b border-gray-700 bg-gray-800 px-4 py-2.5"
|
|
22866
|
+
}, /* @__PURE__ */ React25__namespace.default.createElement("h1", {
|
|
22867
|
+
className: "text-base font-semibold text-white"
|
|
22868
|
+
}, "Vendor Team"), /* @__PURE__ */ React25__namespace.default.createElement("p", {
|
|
22869
|
+
className: "mt-0.5 text-xs text-gray-300"
|
|
22870
|
+
}, "Invite members and assign a store role")), /* @__PURE__ */ React25__namespace.default.createElement("div", {
|
|
22871
|
+
className: "p-6"
|
|
22356
22872
|
}, /* @__PURE__ */ React25__namespace.default.createElement("p", {
|
|
22357
22873
|
className: "text-sm text-red-600"
|
|
22358
|
-
}, "Only the store owner can manage the vendor team."));
|
|
22874
|
+
}, "Only the store owner can manage the vendor team.")));
|
|
22359
22875
|
}
|
|
22360
22876
|
const handleAdd = /* @__PURE__ */ __name(async (e) => {
|
|
22361
22877
|
e.preventDefault();
|
|
@@ -22457,17 +22973,21 @@ function VendorTeamPage() {
|
|
|
22457
22973
|
}
|
|
22458
22974
|
}, "handleRemove");
|
|
22459
22975
|
return /* @__PURE__ */ React25__namespace.default.createElement("div", {
|
|
22460
|
-
className: "
|
|
22976
|
+
className: "min-w-0 rounded-lg bg-white shadow-md"
|
|
22977
|
+
}, /* @__PURE__ */ React25__namespace.default.createElement("div", {
|
|
22978
|
+
className: "rounded-t-lg border-b border-gray-700 bg-gray-800 px-4 py-2.5"
|
|
22461
22979
|
}, /* @__PURE__ */ React25__namespace.default.createElement("h1", {
|
|
22462
|
-
className: "text-
|
|
22980
|
+
className: "text-base font-semibold text-white"
|
|
22463
22981
|
}, "Vendor Team"), /* @__PURE__ */ React25__namespace.default.createElement("p", {
|
|
22464
|
-
className: "mt-
|
|
22465
|
-
}, "Invite member and assign a store role
|
|
22466
|
-
className: "
|
|
22982
|
+
className: "mt-0.5 text-xs text-gray-300"
|
|
22983
|
+
}, "Invite member and assign a store role")), /* @__PURE__ */ React25__namespace.default.createElement("div", {
|
|
22984
|
+
className: "p-6 space-y-6"
|
|
22985
|
+
}, /* @__PURE__ */ React25__namespace.default.createElement("div", {
|
|
22986
|
+
className: "rounded-lg border border-gray-200 overflow-hidden"
|
|
22467
22987
|
}, /* @__PURE__ */ React25__namespace.default.createElement("table", {
|
|
22468
22988
|
className: "min-w-full text-sm"
|
|
22469
22989
|
}, /* @__PURE__ */ React25__namespace.default.createElement("thead", {
|
|
22470
|
-
className: "bg-gray-50 text-left text-gray-600"
|
|
22990
|
+
className: "bg-gray-50 text-left text-gray-600 border-b border-gray-200"
|
|
22471
22991
|
}, /* @__PURE__ */ React25__namespace.default.createElement("tr", null, /* @__PURE__ */ React25__namespace.default.createElement("th", {
|
|
22472
22992
|
className: "px-3 py-2 font-medium"
|
|
22473
22993
|
}, "Name"), /* @__PURE__ */ React25__namespace.default.createElement("th", {
|
|
@@ -22477,8 +22997,10 @@ function VendorTeamPage() {
|
|
|
22477
22997
|
}, "Phone"), /* @__PURE__ */ React25__namespace.default.createElement("th", {
|
|
22478
22998
|
className: "px-3 py-2 font-medium"
|
|
22479
22999
|
}, "Store role"), /* @__PURE__ */ React25__namespace.default.createElement("th", {
|
|
22480
|
-
className: "px-3 py-2 font-medium"
|
|
22481
|
-
}))), /* @__PURE__ */ React25__namespace.default.createElement("tbody",
|
|
23000
|
+
className: "px-3 py-2 font-medium text-right"
|
|
23001
|
+
}))), /* @__PURE__ */ React25__namespace.default.createElement("tbody", {
|
|
23002
|
+
className: "divide-y divide-gray-100"
|
|
23003
|
+
}, loading ? /* @__PURE__ */ React25__namespace.default.createElement("tr", null, /* @__PURE__ */ React25__namespace.default.createElement("td", {
|
|
22482
23004
|
colSpan: 5,
|
|
22483
23005
|
className: "px-3 py-4 text-gray-500"
|
|
22484
23006
|
}, "Loading\u2026")) : members.length === 0 ? /* @__PURE__ */ React25__namespace.default.createElement("tr", null, /* @__PURE__ */ React25__namespace.default.createElement("td", {
|
|
@@ -22488,15 +23010,17 @@ function VendorTeamPage() {
|
|
|
22488
23010
|
key: m.vendorUserId,
|
|
22489
23011
|
className: "border-t border-gray-100"
|
|
22490
23012
|
}, /* @__PURE__ */ React25__namespace.default.createElement("td", {
|
|
22491
|
-
className: "px-3 py-2"
|
|
23013
|
+
className: "px-3 py-2 font-medium text-gray-900"
|
|
22492
23014
|
}, m.name ?? "\u2014"), /* @__PURE__ */ React25__namespace.default.createElement("td", {
|
|
22493
|
-
className: "px-3 py-2"
|
|
23015
|
+
className: "px-3 py-2 text-gray-600"
|
|
22494
23016
|
}, m.email), /* @__PURE__ */ React25__namespace.default.createElement("td", {
|
|
22495
|
-
className: "px-3 py-2"
|
|
23017
|
+
className: "px-3 py-2 text-gray-600"
|
|
22496
23018
|
}, m.phone ?? "\u2014"), /* @__PURE__ */ React25__namespace.default.createElement("td", {
|
|
22497
23019
|
className: "px-3 py-2"
|
|
22498
|
-
}, m.isOwnerRole ? /* @__PURE__ */ React25__namespace.default.createElement("span",
|
|
22499
|
-
className: "
|
|
23020
|
+
}, m.isOwnerRole ? /* @__PURE__ */ React25__namespace.default.createElement("span", {
|
|
23021
|
+
className: "text-gray-900 font-medium"
|
|
23022
|
+
}, m.vendorRoleName ?? "Owner") : /* @__PURE__ */ React25__namespace.default.createElement("select", {
|
|
23023
|
+
className: "rounded border border-gray-200 px-2 py-1 text-sm bg-white",
|
|
22500
23024
|
value: m.vendorRoleId ?? "",
|
|
22501
23025
|
disabled: roleUpdating === m.userId,
|
|
22502
23026
|
onChange: /* @__PURE__ */ __name((e) => handleRoleChange(m.userId, Number(e.target.value)), "onChange")
|
|
@@ -22512,7 +23036,7 @@ function VendorTeamPage() {
|
|
|
22512
23036
|
onClick: /* @__PURE__ */ __name(() => handleRemove(m.userId), "onClick")
|
|
22513
23037
|
}, "Remove"))))))), /* @__PURE__ */ React25__namespace.default.createElement("form", {
|
|
22514
23038
|
onSubmit: handleAdd,
|
|
22515
|
-
className: "
|
|
23039
|
+
className: "space-y-4 rounded-lg border border-gray-200 p-4"
|
|
22516
23040
|
}, /* @__PURE__ */ React25__namespace.default.createElement("h2", {
|
|
22517
23041
|
className: "text-sm font-medium text-gray-900"
|
|
22518
23042
|
}, "Invite team member"), /* @__PURE__ */ React25__namespace.default.createElement("div", {
|
|
@@ -22546,7 +23070,7 @@ function VendorTeamPage() {
|
|
|
22546
23070
|
htmlFor: "teamRole"
|
|
22547
23071
|
}, "Store role"), /* @__PURE__ */ React25__namespace.default.createElement("select", {
|
|
22548
23072
|
id: "teamRole",
|
|
22549
|
-
className: "mt-1 w-full rounded-md border border-gray-200 px-3 py-2 text-sm",
|
|
23073
|
+
className: "mt-1 w-full rounded-md border border-gray-200 px-3 py-2 text-sm bg-white",
|
|
22550
23074
|
value: vendorRoleId,
|
|
22551
23075
|
onChange: /* @__PURE__ */ __name((e) => setVendorRoleId(e.target.value ? Number(e.target.value) : ""), "onChange")
|
|
22552
23076
|
}, assignableRoles.map((r) => /* @__PURE__ */ React25__namespace.default.createElement("option", {
|
|
@@ -22585,7 +23109,7 @@ function VendorTeamPage() {
|
|
|
22585
23109
|
}, message), /* @__PURE__ */ React25__namespace.default.createElement(Button, {
|
|
22586
23110
|
type: "submit",
|
|
22587
23111
|
disabled: submitting
|
|
22588
|
-
}, submitting ? "Inviting\u2026" : "Invite member")), /* @__PURE__ */ React25__namespace.default.createElement(Dialog, {
|
|
23112
|
+
}, submitting ? "Inviting\u2026" : "Invite member"))), /* @__PURE__ */ React25__namespace.default.createElement(Dialog, {
|
|
22589
23113
|
open: inviteDialog != null,
|
|
22590
23114
|
onOpenChange: /* @__PURE__ */ __name((open) => {
|
|
22591
23115
|
if (!open) closeInviteDialog();
|
|
@@ -22605,7 +23129,7 @@ function VendorTeamPage() {
|
|
|
22605
23129
|
variant: "outline",
|
|
22606
23130
|
onClick: /* @__PURE__ */ __name(() => void copyInviteLink(), "onClick")
|
|
22607
23131
|
}, linkCopied ? /* @__PURE__ */ React25__namespace.default.createElement(LucideIcons.Check, {
|
|
22608
|
-
className: "h-4 w-4 mr-2"
|
|
23132
|
+
className: "h-4 w-4 mr-2 text-green-600"
|
|
22609
23133
|
}) : /* @__PURE__ */ React25__namespace.default.createElement(LucideIcons.Copy, {
|
|
22610
23134
|
className: "h-4 w-4 mr-2"
|
|
22611
23135
|
}), linkCopied ? "Copied" : "Copy invite link")), /* @__PURE__ */ React25__namespace.default.createElement(DialogFooter, null, /* @__PURE__ */ React25__namespace.default.createElement(Button, {
|
|
@@ -30620,15 +31144,15 @@ function ProductEditPage({ productId }) {
|
|
|
30620
31144
|
})));
|
|
30621
31145
|
}
|
|
30622
31146
|
}
|
|
30623
|
-
|
|
30624
|
-
|
|
30625
|
-
|
|
30626
|
-
|
|
30627
|
-
|
|
30628
|
-
|
|
30629
|
-
|
|
30630
|
-
|
|
30631
|
-
}
|
|
31147
|
+
const formsResActual = formsRes.ok ? formsRes : await fetch("/api/admin/cms-forms/product-options").catch(() => null);
|
|
31148
|
+
if (!cancelled && formsResActual && formsResActual.ok) {
|
|
31149
|
+
const d = await formsResActual.json();
|
|
31150
|
+
const rows = Array.isArray(d.data) ? d.data : Array.isArray(d) ? d : [];
|
|
31151
|
+
setContactForms(rows.filter((row) => row.id != null || row.value != null).map((row) => ({
|
|
31152
|
+
id: Number(row.id ?? row.value),
|
|
31153
|
+
name: row.name?.trim() || row.label?.trim() || `Form #${row.id ?? row.value}`,
|
|
31154
|
+
slug: row.slug
|
|
31155
|
+
})));
|
|
30632
31156
|
}
|
|
30633
31157
|
if (!cancelled && refundRes.ok) {
|
|
30634
31158
|
const d = await refundRes.json();
|
|
@@ -32880,6 +33404,252 @@ var init_EventProductsSection = __esm({
|
|
|
32880
33404
|
__name(EventProductsSection, "EventProductsSection");
|
|
32881
33405
|
}
|
|
32882
33406
|
});
|
|
33407
|
+
function AttachComboModal({ open, onOpenChange, excludeComboIds = [], onAttach }) {
|
|
33408
|
+
const [attachingId, setAttachingId] = React25.useState(null);
|
|
33409
|
+
const [error, setError] = React25.useState(null);
|
|
33410
|
+
const comboColumns = React25.useMemo(() => exports.STORE_CRUD_CONFIGS.combos.columns.filter((c) => c.field !== "eventId"), []);
|
|
33411
|
+
const comboFilterColumns = React25.useMemo(() => exports.STORE_CRUD_CONFIGS.combos.columns.filter((c) => c.field !== "eventId"), []);
|
|
33412
|
+
const comboFilters = React25.useMemo(() => exports.STORE_CRUD_CONFIGS.combos.filters?.filter((f) => f.param !== "eventId"), []);
|
|
33413
|
+
const extraListParams = React25.useMemo(() => {
|
|
33414
|
+
const params = {};
|
|
33415
|
+
if (excludeComboIds.length > 0) {
|
|
33416
|
+
params.excludeIds = excludeComboIds.join(",");
|
|
33417
|
+
}
|
|
33418
|
+
return params;
|
|
33419
|
+
}, [
|
|
33420
|
+
excludeComboIds
|
|
33421
|
+
]);
|
|
33422
|
+
const handleAttach = /* @__PURE__ */ __name(async (comboId) => {
|
|
33423
|
+
setError(null);
|
|
33424
|
+
setAttachingId(comboId);
|
|
33425
|
+
try {
|
|
33426
|
+
await onAttach(comboId);
|
|
33427
|
+
onOpenChange(false);
|
|
33428
|
+
} catch (err) {
|
|
33429
|
+
setError(err instanceof Error ? err.message : "Failed to attach combo");
|
|
33430
|
+
} finally {
|
|
33431
|
+
setAttachingId(null);
|
|
33432
|
+
}
|
|
33433
|
+
}, "handleAttach");
|
|
33434
|
+
return /* @__PURE__ */ React.createElement(Dialog, {
|
|
33435
|
+
open,
|
|
33436
|
+
onOpenChange
|
|
33437
|
+
}, /* @__PURE__ */ React.createElement(DialogContent, {
|
|
33438
|
+
className: "max-w-4xl max-h-[90vh] overflow-y-auto"
|
|
33439
|
+
}, /* @__PURE__ */ React.createElement(DialogHeader, null, /* @__PURE__ */ React.createElement(DialogTitle, null, "Attach Event Combo"), /* @__PURE__ */ React.createElement(DialogDescription, null, "Choose a combo to link to this event.")), error ? /* @__PURE__ */ React.createElement("p", {
|
|
33440
|
+
className: "text-sm text-red-600 bg-red-50 rounded-md px-3 py-2"
|
|
33441
|
+
}, error) : null, /* @__PURE__ */ React.createElement(AdminCRUD, {
|
|
33442
|
+
key: `attach-combos-${excludeComboIds.join(",")}-${open}`,
|
|
33443
|
+
title: "Combos",
|
|
33444
|
+
apiEndpoint: "/api/combos",
|
|
33445
|
+
columns: comboColumns,
|
|
33446
|
+
filterColumns: comboFilterColumns,
|
|
33447
|
+
addEditPageUrl: "",
|
|
33448
|
+
defaultSortField: exports.STORE_CRUD_CONFIGS.combos.defaultSortField,
|
|
33449
|
+
defaultSortOrder: exports.STORE_CRUD_CONFIGS.combos.defaultSortOrder,
|
|
33450
|
+
filters: comboFilters,
|
|
33451
|
+
extraListParams,
|
|
33452
|
+
embedded: true,
|
|
33453
|
+
disableRowClick: true,
|
|
33454
|
+
emptyState: {
|
|
33455
|
+
title: "No combos available",
|
|
33456
|
+
description: excludeComboIds.length ? "All existing combos are already attached to this event, or none exist yet." : "Create a combo first, then attach it here."
|
|
33457
|
+
},
|
|
33458
|
+
customRowActions: /* @__PURE__ */ __name((item) => {
|
|
33459
|
+
const id = Number(item.id);
|
|
33460
|
+
const busy = attachingId === id;
|
|
33461
|
+
return /* @__PURE__ */ React.createElement(Button, {
|
|
33462
|
+
type: "button",
|
|
33463
|
+
size: "sm",
|
|
33464
|
+
variant: "outline",
|
|
33465
|
+
disabled: !Number.isFinite(id) || busy,
|
|
33466
|
+
className: "h-7 text-xs",
|
|
33467
|
+
onClick: /* @__PURE__ */ __name(() => void handleAttach(id), "onClick")
|
|
33468
|
+
}, /* @__PURE__ */ React.createElement(LucideIcons.Link2, {
|
|
33469
|
+
className: "h-3.5 w-3.5 mr-1"
|
|
33470
|
+
}), busy ? "Attaching\u2026" : "Attach");
|
|
33471
|
+
}, "customRowActions")
|
|
33472
|
+
})));
|
|
33473
|
+
}
|
|
33474
|
+
var init_AttachComboModal = __esm({
|
|
33475
|
+
"src/components/Admin/AttachComboModal.tsx"() {
|
|
33476
|
+
"use client";
|
|
33477
|
+
init_dialog();
|
|
33478
|
+
init_button();
|
|
33479
|
+
init_CRUD();
|
|
33480
|
+
init_store_crud_configs();
|
|
33481
|
+
__name(AttachComboModal, "AttachComboModal");
|
|
33482
|
+
}
|
|
33483
|
+
});
|
|
33484
|
+
function EventCombosSection({ eventId, returnUrl, readOnly = false }) {
|
|
33485
|
+
const [rows, setRows] = React25.useState([]);
|
|
33486
|
+
const [loading, setLoading] = React25.useState(true);
|
|
33487
|
+
const [attachModalOpen, setAttachModalOpen] = React25.useState(false);
|
|
33488
|
+
const [listRefreshKey, setListRefreshKey] = React25.useState(0);
|
|
33489
|
+
const [detachingId, setDetachingId] = React25.useState(null);
|
|
33490
|
+
const comboColumns = React25.useMemo(() => exports.STORE_CRUD_CONFIGS.combos.columns.filter((c) => c.field !== "eventId"), []);
|
|
33491
|
+
const comboFilterColumns = React25.useMemo(() => exports.STORE_CRUD_CONFIGS.combos.columns.filter((c) => c.field !== "eventId"), []);
|
|
33492
|
+
const comboFilters = React25.useMemo(() => exports.STORE_CRUD_CONFIGS.combos.filters?.filter((f) => f.param !== "eventId"), []);
|
|
33493
|
+
const loadRows = React25.useCallback(async () => {
|
|
33494
|
+
setLoading(true);
|
|
33495
|
+
try {
|
|
33496
|
+
const res = await fetch(`/api/combos?eventId=${encodeURIComponent(eventId)}&limit=200`);
|
|
33497
|
+
if (!res.ok) throw new Error("Failed to load");
|
|
33498
|
+
const data = await res.json();
|
|
33499
|
+
const list = Array.isArray(data.data) ? data.data : [];
|
|
33500
|
+
setRows(list);
|
|
33501
|
+
} catch {
|
|
33502
|
+
setRows([]);
|
|
33503
|
+
} finally {
|
|
33504
|
+
setLoading(false);
|
|
33505
|
+
}
|
|
33506
|
+
}, [
|
|
33507
|
+
eventId
|
|
33508
|
+
]);
|
|
33509
|
+
React25.useEffect(() => {
|
|
33510
|
+
void loadRows();
|
|
33511
|
+
}, [
|
|
33512
|
+
loadRows
|
|
33513
|
+
]);
|
|
33514
|
+
const attachedComboIds = React25.useMemo(() => rows.map((r) => Number(r.id)).filter((id) => Number.isFinite(id) && id > 0), [
|
|
33515
|
+
rows
|
|
33516
|
+
]);
|
|
33517
|
+
const attachToEvent = /* @__PURE__ */ __name(async (comboId) => {
|
|
33518
|
+
const res = await fetch(`/api/combos/${comboId}`, {
|
|
33519
|
+
method: "PUT",
|
|
33520
|
+
headers: {
|
|
33521
|
+
"Content-Type": "application/json"
|
|
33522
|
+
},
|
|
33523
|
+
body: JSON.stringify({
|
|
33524
|
+
eventId: Number(eventId)
|
|
33525
|
+
})
|
|
33526
|
+
});
|
|
33527
|
+
if (!res.ok) {
|
|
33528
|
+
const data = await res.json().catch(() => ({}));
|
|
33529
|
+
throw new Error(data.error ?? "Failed to attach combo");
|
|
33530
|
+
}
|
|
33531
|
+
await loadRows();
|
|
33532
|
+
setListRefreshKey((k) => k + 1);
|
|
33533
|
+
}, "attachToEvent");
|
|
33534
|
+
const detachFromEvent = /* @__PURE__ */ __name(async (comboId) => {
|
|
33535
|
+
if (!window.confirm("Remove this combo from the event?")) return;
|
|
33536
|
+
setDetachingId(comboId);
|
|
33537
|
+
try {
|
|
33538
|
+
const res = await fetch(`/api/combos/${comboId}`, {
|
|
33539
|
+
method: "PUT",
|
|
33540
|
+
headers: {
|
|
33541
|
+
"Content-Type": "application/json"
|
|
33542
|
+
},
|
|
33543
|
+
body: JSON.stringify({
|
|
33544
|
+
eventId: null
|
|
33545
|
+
})
|
|
33546
|
+
});
|
|
33547
|
+
if (res.ok) {
|
|
33548
|
+
await loadRows();
|
|
33549
|
+
setListRefreshKey((k) => k + 1);
|
|
33550
|
+
}
|
|
33551
|
+
} finally {
|
|
33552
|
+
setDetachingId(null);
|
|
33553
|
+
}
|
|
33554
|
+
}, "detachFromEvent");
|
|
33555
|
+
const comboCreateHref = !readOnly ? `/admin/combos/create?eventId=${encodeURIComponent(eventId)}${returnUrl ? `&from=${encodeURIComponent(returnUrl)}` : ""}` : null;
|
|
33556
|
+
if (loading) {
|
|
33557
|
+
return /* @__PURE__ */ React.createElement("section", {
|
|
33558
|
+
className: "border border-gray-200 rounded-lg p-8 text-center text-sm text-gray-500"
|
|
33559
|
+
}, "Loading combos\u2026");
|
|
33560
|
+
}
|
|
33561
|
+
if (readOnly && rows.length === 0) {
|
|
33562
|
+
return /* @__PURE__ */ React.createElement("section", {
|
|
33563
|
+
className: "border border-gray-200 rounded-lg p-6"
|
|
33564
|
+
}, /* @__PURE__ */ React.createElement("h2", {
|
|
33565
|
+
className: "text-sm font-semibold text-gray-900"
|
|
33566
|
+
}, "Event Combos"), /* @__PURE__ */ React.createElement("p", {
|
|
33567
|
+
className: "mt-2 text-sm text-gray-600"
|
|
33568
|
+
}, "No combos are linked to this event yet."));
|
|
33569
|
+
}
|
|
33570
|
+
return /* @__PURE__ */ React.createElement("div", {
|
|
33571
|
+
className: "space-y-4"
|
|
33572
|
+
}, /* @__PURE__ */ React.createElement("section", {
|
|
33573
|
+
className: "border border-gray-200 rounded-lg overflow-hidden bg-white"
|
|
33574
|
+
}, /* @__PURE__ */ React.createElement("div", {
|
|
33575
|
+
className: "flex flex-wrap items-center justify-between gap-3 px-4 py-3 border-b border-gray-200"
|
|
33576
|
+
}, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("h2", {
|
|
33577
|
+
className: "text-sm font-semibold text-gray-900"
|
|
33578
|
+
}, "Event Combos"), /* @__PURE__ */ React.createElement("p", {
|
|
33579
|
+
className: "text-xs text-gray-500"
|
|
33580
|
+
}, "Event Combos linked to this event.")), !readOnly ? /* @__PURE__ */ React.createElement("div", {
|
|
33581
|
+
className: "flex flex-wrap items-center gap-2"
|
|
33582
|
+
}, /* @__PURE__ */ React.createElement(Button, {
|
|
33583
|
+
type: "button",
|
|
33584
|
+
variant: "outline",
|
|
33585
|
+
size: "sm",
|
|
33586
|
+
className: "h-8 text-xs",
|
|
33587
|
+
onClick: /* @__PURE__ */ __name(() => setAttachModalOpen(true), "onClick")
|
|
33588
|
+
}, /* @__PURE__ */ React.createElement(LucideIcons.Link2, {
|
|
33589
|
+
className: "h-3.5 w-3.5 mr-1"
|
|
33590
|
+
}), "Attach event combo"), comboCreateHref ? /* @__PURE__ */ React.createElement(Link2__default.default, {
|
|
33591
|
+
href: comboCreateHref,
|
|
33592
|
+
className: "inline-flex items-center gap-1.5 rounded-md border border-gray-300 bg-white px-2.5 py-1.5 text-xs font-medium text-gray-700 hover:bg-gray-50 h-8"
|
|
33593
|
+
}, /* @__PURE__ */ React.createElement(LucideIcons.Plus, {
|
|
33594
|
+
className: "h-3.5 w-3.5"
|
|
33595
|
+
}), "New event combo") : null) : null), /* @__PURE__ */ React.createElement("div", {
|
|
33596
|
+
className: "[&>div]:shadow-none [&>div]:rounded-none"
|
|
33597
|
+
}, rows.length === 0 ? /* @__PURE__ */ React.createElement("div", {
|
|
33598
|
+
className: "px-4 py-8 text-center text-sm text-gray-500"
|
|
33599
|
+
}, "No combos attached to this event yet.") : /* @__PURE__ */ React.createElement(AdminCRUD, {
|
|
33600
|
+
key: `event-combos-${eventId}-${attachedComboIds.join(",")}-${listRefreshKey}`,
|
|
33601
|
+
title: "Event Combos",
|
|
33602
|
+
apiEndpoint: "/api/combos",
|
|
33603
|
+
columns: comboColumns,
|
|
33604
|
+
filterColumns: comboFilterColumns,
|
|
33605
|
+
addEditPageUrl: "/admin/combos",
|
|
33606
|
+
defaultSortField: exports.STORE_CRUD_CONFIGS.combos.defaultSortField,
|
|
33607
|
+
defaultSortOrder: exports.STORE_CRUD_CONFIGS.combos.defaultSortOrder,
|
|
33608
|
+
filters: comboFilters,
|
|
33609
|
+
extraListParams: {
|
|
33610
|
+
eventId: String(eventId)
|
|
33611
|
+
},
|
|
33612
|
+
embedded: true,
|
|
33613
|
+
disableRowClick: readOnly,
|
|
33614
|
+
emptyState: {
|
|
33615
|
+
title: "No combos attached",
|
|
33616
|
+
description: "Attach or create a combo for this event.",
|
|
33617
|
+
action: !readOnly && comboCreateHref ? /* @__PURE__ */ React.createElement(Link2__default.default, {
|
|
33618
|
+
href: comboCreateHref,
|
|
33619
|
+
className: "inline-flex items-center rounded-md bg-gray-900 px-3 py-1.5 text-sm font-medium text-white hover:bg-gray-800"
|
|
33620
|
+
}, "Create combo") : void 0
|
|
33621
|
+
},
|
|
33622
|
+
customRowActions: readOnly ? void 0 : (item) => {
|
|
33623
|
+
const comboId = Number(item.id);
|
|
33624
|
+
const busy = detachingId === comboId;
|
|
33625
|
+
return /* @__PURE__ */ React.createElement(Button, {
|
|
33626
|
+
type: "button",
|
|
33627
|
+
size: "sm",
|
|
33628
|
+
variant: "outline",
|
|
33629
|
+
disabled: !Number.isFinite(comboId) || busy,
|
|
33630
|
+
className: "h-7 text-xs border-red-200 text-red-600 hover:text-red-700",
|
|
33631
|
+
onClick: /* @__PURE__ */ __name(() => void detachFromEvent(comboId), "onClick")
|
|
33632
|
+
}, /* @__PURE__ */ React.createElement(LucideIcons.Unlink, {
|
|
33633
|
+
className: "h-3.5 w-3.5 mr-1"
|
|
33634
|
+
}), busy ? "Removing\u2026" : "Detach");
|
|
33635
|
+
}
|
|
33636
|
+
}))), attachModalOpen ? /* @__PURE__ */ React.createElement(AttachComboModal, {
|
|
33637
|
+
open: attachModalOpen,
|
|
33638
|
+
onOpenChange: setAttachModalOpen,
|
|
33639
|
+
excludeComboIds: attachedComboIds,
|
|
33640
|
+
onAttach: attachToEvent
|
|
33641
|
+
}) : null);
|
|
33642
|
+
}
|
|
33643
|
+
var init_EventCombosSection = __esm({
|
|
33644
|
+
"src/admin/pages/EventCombosSection.tsx"() {
|
|
33645
|
+
"use client";
|
|
33646
|
+
init_button();
|
|
33647
|
+
init_CRUD();
|
|
33648
|
+
init_AttachComboModal();
|
|
33649
|
+
init_store_crud_configs();
|
|
33650
|
+
__name(EventCombosSection, "EventCombosSection");
|
|
33651
|
+
}
|
|
33652
|
+
});
|
|
32883
33653
|
|
|
32884
33654
|
// src/lib/social-media-links.ts
|
|
32885
33655
|
function isValidHttpUrl(value) {
|
|
@@ -34373,10 +35143,13 @@ function EventEditPage({ eventId }) {
|
|
|
34373
35143
|
onClick: goToNextTab,
|
|
34374
35144
|
className: "rounded-md bg-gray-900 px-4 py-2 text-sm font-medium text-white hover:bg-gray-800"
|
|
34375
35145
|
}, "Next") : /* @__PURE__ */ React.createElement("div", null)), showEventProducts ? /* @__PURE__ */ React.createElement("div", {
|
|
34376
|
-
className: "border-t border-gray-200 px-4 py-4 sm:px-6"
|
|
35146
|
+
className: "border-t border-gray-200 px-4 py-4 sm:px-6 space-y-6"
|
|
34377
35147
|
}, /* @__PURE__ */ React.createElement(EventProductsSection, {
|
|
34378
35148
|
eventId: eventRecordId,
|
|
34379
35149
|
returnUrl: eventEditUrl
|
|
35150
|
+
}), /* @__PURE__ */ React.createElement(EventCombosSection, {
|
|
35151
|
+
eventId: eventRecordId,
|
|
35152
|
+
returnUrl: eventEditUrl
|
|
34380
35153
|
})) : null);
|
|
34381
35154
|
}
|
|
34382
35155
|
var ADDITIONAL_VENUE_MAX_CHARS, DEFAULT_EVENT_TIMEZONE, DEFAULT_EVENT_CURRENCY, EVENT_SOCIAL_KEYS, isCreate4, sectionCls4, labelCls6, inputCls6, ENTITY_TYPE_OPTIONS;
|
|
@@ -34391,6 +35164,7 @@ var init_EventEditPage = __esm({
|
|
|
34391
35164
|
init_media_url();
|
|
34392
35165
|
init_JoditRichText();
|
|
34393
35166
|
init_EventProductsSection();
|
|
35167
|
+
init_EventCombosSection();
|
|
34394
35168
|
init_admin_config_context();
|
|
34395
35169
|
init_dialog();
|
|
34396
35170
|
init_button();
|
|
@@ -34428,7 +35202,13 @@ function formatDateTimeLocal(value) {
|
|
|
34428
35202
|
if (value == null) return "";
|
|
34429
35203
|
const date = new Date(String(value));
|
|
34430
35204
|
if (isNaN(date.getTime())) return "";
|
|
34431
|
-
|
|
35205
|
+
const pad = /* @__PURE__ */ __name((n) => String(n).padStart(2, "0"), "pad");
|
|
35206
|
+
const y = date.getFullYear();
|
|
35207
|
+
const m = pad(date.getMonth() + 1);
|
|
35208
|
+
const d = pad(date.getDate());
|
|
35209
|
+
const hh = pad(date.getHours());
|
|
35210
|
+
const mm = pad(date.getMinutes());
|
|
35211
|
+
return `${y}-${m}-${d}T${hh}:${mm}`;
|
|
34432
35212
|
}
|
|
34433
35213
|
async function fetchEventDefaultCurrency(eventId) {
|
|
34434
35214
|
try {
|
|
@@ -34475,13 +35255,14 @@ function ComboEditPage({ comboId }) {
|
|
|
34475
35255
|
const create = isCreate5(comboId);
|
|
34476
35256
|
const duplicateFrom = searchParams.get("duplicateFrom")?.trim();
|
|
34477
35257
|
const duplicateSourceId = create && duplicateFrom && /^\d+$/.test(duplicateFrom) ? duplicateFrom : null;
|
|
35258
|
+
const initialEventId = create ? searchParams.get("eventId")?.trim() || "" : "";
|
|
34478
35259
|
const [loading, setLoading] = React25.useState(!create || !!duplicateSourceId);
|
|
34479
35260
|
const [saving, setSaving] = React25.useState(false);
|
|
34480
35261
|
const [errors, setErrors] = React25.useState([]);
|
|
34481
35262
|
const [name, setName] = React25.useState("");
|
|
34482
35263
|
const [slug, setSlug] = React25.useState("");
|
|
34483
35264
|
const [desc, setDesc] = React25.useState("");
|
|
34484
|
-
const [eventId, setEventId] = React25.useState(
|
|
35265
|
+
const [eventId, setEventId] = React25.useState(initialEventId);
|
|
34485
35266
|
const [priceStr, setPriceStr] = React25.useState("");
|
|
34486
35267
|
const [defaultCurrency, setDefaultCurrency] = React25.useState("INR");
|
|
34487
35268
|
const [minSelectableItems, setMinSelectableItems] = React25.useState(1);
|
|
@@ -34718,15 +35499,9 @@ function ComboEditPage({ comboId }) {
|
|
|
34718
35499
|
]);
|
|
34719
35500
|
return;
|
|
34720
35501
|
}
|
|
34721
|
-
if (
|
|
35502
|
+
if (startsAt && endsAt && new Date(endsAt).getTime() < new Date(startsAt).getTime()) {
|
|
34722
35503
|
setErrors([
|
|
34723
|
-
"
|
|
34724
|
-
]);
|
|
34725
|
-
return;
|
|
34726
|
-
}
|
|
34727
|
-
if (!endsAt) {
|
|
34728
|
-
setErrors([
|
|
34729
|
-
"Ends at is required"
|
|
35504
|
+
"Ends at cannot be earlier than Starts at"
|
|
34730
35505
|
]);
|
|
34731
35506
|
return;
|
|
34732
35507
|
}
|
|
@@ -34794,8 +35569,8 @@ function ComboEditPage({ comboId }) {
|
|
|
34794
35569
|
minSelectableItems,
|
|
34795
35570
|
maxSelectableItems,
|
|
34796
35571
|
status,
|
|
34797
|
-
startsAt: startsAt
|
|
34798
|
-
endsAt: endsAt
|
|
35572
|
+
startsAt: startsAt ? new Date(startsAt).toISOString() : null,
|
|
35573
|
+
endsAt: endsAt ? new Date(endsAt).toISOString() : null,
|
|
34799
35574
|
comboItems: [
|
|
34800
35575
|
...fixedItems.map((i) => ({
|
|
34801
35576
|
productId: Number(i.productId),
|
|
@@ -35019,21 +35794,23 @@ function ComboEditPage({ comboId }) {
|
|
|
35019
35794
|
className: "grid grid-cols-2 gap-4"
|
|
35020
35795
|
}, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("label", {
|
|
35021
35796
|
className: "block text-xs font-medium text-gray-600 mb-1"
|
|
35022
|
-
}, "Starts at
|
|
35797
|
+
}, "Starts at (optional)"), /* @__PURE__ */ React.createElement("input", {
|
|
35023
35798
|
type: "datetime-local",
|
|
35024
35799
|
value: startsAt,
|
|
35025
35800
|
onChange: /* @__PURE__ */ __name((e) => setStartsAt(e.target.value), "onChange"),
|
|
35026
|
-
className: "w-full rounded-md border border-gray-300 px-3 py-2 text-sm"
|
|
35027
|
-
|
|
35028
|
-
|
|
35801
|
+
className: "w-full rounded-md border border-gray-300 px-3 py-2 text-sm"
|
|
35802
|
+
}), /* @__PURE__ */ React.createElement("p", {
|
|
35803
|
+
className: "text-xs text-gray-400 mt-1"
|
|
35804
|
+
}, "Leave empty to be available immediately.")), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("label", {
|
|
35029
35805
|
className: "block text-xs font-medium text-gray-600 mb-1"
|
|
35030
|
-
}, "Ends at
|
|
35806
|
+
}, "Ends at (optional)"), /* @__PURE__ */ React.createElement("input", {
|
|
35031
35807
|
type: "datetime-local",
|
|
35032
35808
|
value: endsAt,
|
|
35033
35809
|
onChange: /* @__PURE__ */ __name((e) => setEndsAt(e.target.value), "onChange"),
|
|
35034
|
-
className: "w-full rounded-md border border-gray-300 px-3 py-2 text-sm"
|
|
35035
|
-
|
|
35036
|
-
|
|
35810
|
+
className: "w-full rounded-md border border-gray-300 px-3 py-2 text-sm"
|
|
35811
|
+
}), /* @__PURE__ */ React.createElement("p", {
|
|
35812
|
+
className: "text-xs text-gray-400 mt-1"
|
|
35813
|
+
}, "Leave empty if no expiration date.")))))),
|
|
35037
35814
|
sidebar: /* @__PURE__ */ React.createElement(React.Fragment, null)
|
|
35038
35815
|
}));
|
|
35039
35816
|
}
|
|
@@ -35149,6 +35926,130 @@ function VendorEditPage({ vendorId }) {
|
|
|
35149
35926
|
const [inviteDialog, setInviteDialog] = React25.useState(null);
|
|
35150
35927
|
const [sendingInviteEmail, setSendingInviteEmail] = React25.useState(false);
|
|
35151
35928
|
const [linkCopied, setLinkCopied] = React25.useState(false);
|
|
35929
|
+
const VENDOR_CREATE_DRAFT_KEY = "cms_vendor_create_draft";
|
|
35930
|
+
React25.useEffect(() => {
|
|
35931
|
+
if (!create || typeof window === "undefined") return;
|
|
35932
|
+
try {
|
|
35933
|
+
const saved = sessionStorage.getItem(VENDOR_CREATE_DRAFT_KEY);
|
|
35934
|
+
if (saved) {
|
|
35935
|
+
const draft = JSON.parse(saved);
|
|
35936
|
+
if (draft && typeof draft === "object") {
|
|
35937
|
+
if (draft.name) setName(draft.name);
|
|
35938
|
+
if (draft.legalName) setLegalName(draft.legalName);
|
|
35939
|
+
if (draft.slug) setSlug(draft.slug);
|
|
35940
|
+
if (draft.businessType) setBusinessType(draft.businessType);
|
|
35941
|
+
if (draft.description) setDescription(draft.description);
|
|
35942
|
+
if (draft.website) setWebsite(draft.website);
|
|
35943
|
+
if (draft.logo) setLogo(draft.logo);
|
|
35944
|
+
if (draft.email) setEmail(draft.email);
|
|
35945
|
+
if (draft.storePhoneCode) setStorePhoneCode(draft.storePhoneCode);
|
|
35946
|
+
if (draft.storePhoneNum) setStorePhoneNum(draft.storePhoneNum);
|
|
35947
|
+
if (draft.addressLine1) setAddressLine1(draft.addressLine1);
|
|
35948
|
+
if (draft.addressLine2) setAddressLine2(draft.addressLine2);
|
|
35949
|
+
if (draft.city) setCity(draft.city);
|
|
35950
|
+
if (draft.state) setState(draft.state);
|
|
35951
|
+
if (draft.country) setCountry(draft.country);
|
|
35952
|
+
if (draft.postalCode) setPostalCode(draft.postalCode);
|
|
35953
|
+
if (draft.gstin) setGstin(draft.gstin);
|
|
35954
|
+
if (typeof draft.active === "boolean") setActive(draft.active);
|
|
35955
|
+
if (draft.registrationStatus) setRegistrationStatus(draft.registrationStatus);
|
|
35956
|
+
if (draft.ownerName) setOwnerName(draft.ownerName);
|
|
35957
|
+
if (draft.ownerEmail) setOwnerEmail(draft.ownerEmail);
|
|
35958
|
+
if (draft.ownerPhoneCode) setOwnerPhoneCode(draft.ownerPhoneCode);
|
|
35959
|
+
if (draft.ownerPhoneNum) setOwnerPhoneNum(draft.ownerPhoneNum);
|
|
35960
|
+
if (draft.ownerDesignation) setOwnerDesignation(draft.ownerDesignation);
|
|
35961
|
+
if (draft.ownerAadhaarNo) setOwnerAadhaarNo(draft.ownerAadhaarNo);
|
|
35962
|
+
if (draft.ownerPanNo) setOwnerPanNo(draft.ownerPanNo);
|
|
35963
|
+
if (draft.ownerAddressLine1) setOwnerAddressLine1(draft.ownerAddressLine1);
|
|
35964
|
+
if (draft.ownerAddressLine2) setOwnerAddressLine2(draft.ownerAddressLine2);
|
|
35965
|
+
if (draft.ownerCity) setOwnerCity(draft.ownerCity);
|
|
35966
|
+
if (draft.ownerState) setOwnerState(draft.ownerState);
|
|
35967
|
+
if (draft.ownerPostalCode) setOwnerPostalCode(draft.ownerPostalCode);
|
|
35968
|
+
if (typeof draft.termsAccepted === "boolean") setTermsAccepted(draft.termsAccepted);
|
|
35969
|
+
}
|
|
35970
|
+
}
|
|
35971
|
+
} catch {
|
|
35972
|
+
}
|
|
35973
|
+
}, [
|
|
35974
|
+
create
|
|
35975
|
+
]);
|
|
35976
|
+
React25.useEffect(() => {
|
|
35977
|
+
if (!create || typeof window === "undefined") return;
|
|
35978
|
+
const hasAnyData = Boolean(name || legalName || gstin || ownerName || ownerEmail || ownerPhoneNum || ownerAadhaarNo || ownerPanNo || ownerAddressLine1);
|
|
35979
|
+
if (!hasAnyData) return;
|
|
35980
|
+
try {
|
|
35981
|
+
const draft = {
|
|
35982
|
+
name,
|
|
35983
|
+
legalName,
|
|
35984
|
+
slug,
|
|
35985
|
+
businessType,
|
|
35986
|
+
description,
|
|
35987
|
+
website,
|
|
35988
|
+
logo,
|
|
35989
|
+
email,
|
|
35990
|
+
storePhoneCode,
|
|
35991
|
+
storePhoneNum,
|
|
35992
|
+
addressLine1,
|
|
35993
|
+
addressLine2,
|
|
35994
|
+
city,
|
|
35995
|
+
state,
|
|
35996
|
+
country,
|
|
35997
|
+
postalCode,
|
|
35998
|
+
gstin,
|
|
35999
|
+
active,
|
|
36000
|
+
registrationStatus,
|
|
36001
|
+
ownerName,
|
|
36002
|
+
ownerEmail,
|
|
36003
|
+
ownerPhoneCode,
|
|
36004
|
+
ownerPhoneNum,
|
|
36005
|
+
ownerDesignation,
|
|
36006
|
+
ownerAadhaarNo,
|
|
36007
|
+
ownerPanNo,
|
|
36008
|
+
ownerAddressLine1,
|
|
36009
|
+
ownerAddressLine2,
|
|
36010
|
+
ownerCity,
|
|
36011
|
+
ownerState,
|
|
36012
|
+
ownerPostalCode,
|
|
36013
|
+
termsAccepted
|
|
36014
|
+
};
|
|
36015
|
+
sessionStorage.setItem(VENDOR_CREATE_DRAFT_KEY, JSON.stringify(draft));
|
|
36016
|
+
} catch {
|
|
36017
|
+
}
|
|
36018
|
+
}, [
|
|
36019
|
+
create,
|
|
36020
|
+
name,
|
|
36021
|
+
legalName,
|
|
36022
|
+
slug,
|
|
36023
|
+
businessType,
|
|
36024
|
+
description,
|
|
36025
|
+
website,
|
|
36026
|
+
logo,
|
|
36027
|
+
email,
|
|
36028
|
+
storePhoneCode,
|
|
36029
|
+
storePhoneNum,
|
|
36030
|
+
addressLine1,
|
|
36031
|
+
addressLine2,
|
|
36032
|
+
city,
|
|
36033
|
+
state,
|
|
36034
|
+
country,
|
|
36035
|
+
postalCode,
|
|
36036
|
+
gstin,
|
|
36037
|
+
active,
|
|
36038
|
+
registrationStatus,
|
|
36039
|
+
ownerName,
|
|
36040
|
+
ownerEmail,
|
|
36041
|
+
ownerPhoneCode,
|
|
36042
|
+
ownerPhoneNum,
|
|
36043
|
+
ownerDesignation,
|
|
36044
|
+
ownerAadhaarNo,
|
|
36045
|
+
ownerPanNo,
|
|
36046
|
+
ownerAddressLine1,
|
|
36047
|
+
ownerAddressLine2,
|
|
36048
|
+
ownerCity,
|
|
36049
|
+
ownerState,
|
|
36050
|
+
ownerPostalCode,
|
|
36051
|
+
termsAccepted
|
|
36052
|
+
]);
|
|
35152
36053
|
const vendorPayload = /* @__PURE__ */ __name(() => ({
|
|
35153
36054
|
name: name.trim(),
|
|
35154
36055
|
legalName: legalName.trim() || null,
|
|
@@ -35392,12 +36293,15 @@ function VendorEditPage({ vendorId }) {
|
|
|
35392
36293
|
setSaving(false);
|
|
35393
36294
|
return;
|
|
35394
36295
|
}
|
|
36296
|
+
const abortController = new AbortController();
|
|
36297
|
+
const timeoutId = setTimeout(() => abortController.abort(), 15e3);
|
|
35395
36298
|
try {
|
|
35396
36299
|
const res = await fetch("/api/admin/vendors/onboard", {
|
|
35397
36300
|
method: "POST",
|
|
35398
36301
|
headers: {
|
|
35399
36302
|
"Content-Type": "application/json"
|
|
35400
36303
|
},
|
|
36304
|
+
signal: abortController.signal,
|
|
35401
36305
|
body: JSON.stringify({
|
|
35402
36306
|
activation: "invite",
|
|
35403
36307
|
sendOwnerEmail: false,
|
|
@@ -35418,15 +36322,20 @@ function VendorEditPage({ vendorId }) {
|
|
|
35418
36322
|
}
|
|
35419
36323
|
})
|
|
35420
36324
|
});
|
|
35421
|
-
|
|
36325
|
+
clearTimeout(timeoutId);
|
|
36326
|
+
const data = await res.json().catch(() => ({}));
|
|
35422
36327
|
if (!res.ok) {
|
|
35423
36328
|
setErrors([
|
|
35424
36329
|
data.error || "Onboarding failed"
|
|
35425
36330
|
]);
|
|
35426
36331
|
return;
|
|
35427
36332
|
}
|
|
36333
|
+
try {
|
|
36334
|
+
sessionStorage.removeItem(VENDOR_CREATE_DRAFT_KEY);
|
|
36335
|
+
} catch {
|
|
36336
|
+
}
|
|
35428
36337
|
const vendorIdNum = Number(data.vendor?.id);
|
|
35429
|
-
const inviteLink = typeof data.inviteLink === "string" && data.inviteLink
|
|
36338
|
+
const inviteLink = typeof data.inviteLink === "string" && data.inviteLink?.trim() ? data.inviteLink.trim() : "";
|
|
35430
36339
|
if (!Number.isFinite(vendorIdNum) || vendorIdNum <= 0 || !inviteLink) {
|
|
35431
36340
|
sonner.toast.success(data.message || "Vendor created");
|
|
35432
36341
|
router.push(listReturnUrl);
|
|
@@ -35438,11 +36347,18 @@ function VendorEditPage({ vendorId }) {
|
|
|
35438
36347
|
vendorId: vendorIdNum,
|
|
35439
36348
|
inviteLink
|
|
35440
36349
|
});
|
|
35441
|
-
} catch {
|
|
35442
|
-
|
|
35443
|
-
|
|
35444
|
-
|
|
36350
|
+
} catch (err) {
|
|
36351
|
+
if (err instanceof DOMException && err.name === "AbortError") {
|
|
36352
|
+
setErrors([
|
|
36353
|
+
"Request timed out. Your entered data is preserved. Please click submit again."
|
|
36354
|
+
]);
|
|
36355
|
+
} else {
|
|
36356
|
+
setErrors([
|
|
36357
|
+
err instanceof Error && err.message || "Request failed"
|
|
36358
|
+
]);
|
|
36359
|
+
}
|
|
35445
36360
|
} finally {
|
|
36361
|
+
clearTimeout(timeoutId);
|
|
35446
36362
|
setSaving(false);
|
|
35447
36363
|
}
|
|
35448
36364
|
}, "handleCreate");
|
|
@@ -35481,12 +36397,15 @@ function VendorEditPage({ vendorId }) {
|
|
|
35481
36397
|
setSaving(false);
|
|
35482
36398
|
return;
|
|
35483
36399
|
}
|
|
36400
|
+
const abortController = new AbortController();
|
|
36401
|
+
const timeoutId = setTimeout(() => abortController.abort(), 15e3);
|
|
35484
36402
|
try {
|
|
35485
36403
|
const res = await fetch(`/api/vendors/${vendorId}`, {
|
|
35486
36404
|
method: "PUT",
|
|
35487
36405
|
headers: {
|
|
35488
36406
|
"Content-Type": "application/json"
|
|
35489
36407
|
},
|
|
36408
|
+
signal: abortController.signal,
|
|
35490
36409
|
body: JSON.stringify({
|
|
35491
36410
|
...vendorPayload(),
|
|
35492
36411
|
slug: slug.trim(),
|
|
@@ -35502,6 +36421,7 @@ function VendorEditPage({ vendorId }) {
|
|
|
35502
36421
|
})
|
|
35503
36422
|
});
|
|
35504
36423
|
if (!res.ok) {
|
|
36424
|
+
clearTimeout(timeoutId);
|
|
35505
36425
|
const data = await res.json().catch(() => ({}));
|
|
35506
36426
|
setErrors([
|
|
35507
36427
|
data.error || "Failed to save"
|
|
@@ -35515,6 +36435,7 @@ function VendorEditPage({ vendorId }) {
|
|
|
35515
36435
|
headers: {
|
|
35516
36436
|
"Content-Type": "application/json"
|
|
35517
36437
|
},
|
|
36438
|
+
signal: abortController.signal,
|
|
35518
36439
|
body: JSON.stringify({
|
|
35519
36440
|
name: ownerName.trim(),
|
|
35520
36441
|
email: ownerEmail.trim(),
|
|
@@ -35522,6 +36443,7 @@ function VendorEditPage({ vendorId }) {
|
|
|
35522
36443
|
})
|
|
35523
36444
|
});
|
|
35524
36445
|
if (!userRes.ok) {
|
|
36446
|
+
clearTimeout(timeoutId);
|
|
35525
36447
|
const data = await userRes.json().catch(() => ({}));
|
|
35526
36448
|
setErrors([
|
|
35527
36449
|
data.error || "Vendor saved, but updating owner details failed"
|
|
@@ -35529,13 +36451,21 @@ function VendorEditPage({ vendorId }) {
|
|
|
35529
36451
|
return;
|
|
35530
36452
|
}
|
|
35531
36453
|
}
|
|
36454
|
+
clearTimeout(timeoutId);
|
|
35532
36455
|
sonner.toast.success("Vendor saved");
|
|
35533
36456
|
router.push(listReturnUrl);
|
|
35534
|
-
} catch {
|
|
35535
|
-
|
|
35536
|
-
|
|
35537
|
-
|
|
36457
|
+
} catch (err) {
|
|
36458
|
+
if (err instanceof DOMException && err.name === "AbortError") {
|
|
36459
|
+
setErrors([
|
|
36460
|
+
"Request timed out. Please try saving again."
|
|
36461
|
+
]);
|
|
36462
|
+
} else {
|
|
36463
|
+
setErrors([
|
|
36464
|
+
err instanceof Error && err.message || "Failed to save"
|
|
36465
|
+
]);
|
|
36466
|
+
}
|
|
35538
36467
|
} finally {
|
|
36468
|
+
clearTimeout(timeoutId);
|
|
35539
36469
|
setSaving(false);
|
|
35540
36470
|
}
|
|
35541
36471
|
}, "handleSave");
|
|
@@ -40941,6 +41871,8 @@ var init_AdminPageResolver = __esm({
|
|
|
40941
41871
|
submissions: {
|
|
40942
41872
|
title: "Submissions",
|
|
40943
41873
|
apiEndpoint: "/api/form-submissions",
|
|
41874
|
+
defaultSortField: "createdAt",
|
|
41875
|
+
defaultSortOrder: "desc",
|
|
40944
41876
|
columns: [
|
|
40945
41877
|
{
|
|
40946
41878
|
field: "form.name",
|
|
@@ -41486,6 +42418,10 @@ function EventDetailPage({ eventId }) {
|
|
|
41486
42418
|
eventId: String(event.id),
|
|
41487
42419
|
returnUrl: detailUrl,
|
|
41488
42420
|
readOnly: true
|
|
42421
|
+
}), /* @__PURE__ */ React.createElement(EventCombosSection, {
|
|
42422
|
+
eventId: String(event.id),
|
|
42423
|
+
returnUrl: detailUrl,
|
|
42424
|
+
readOnly: true
|
|
41489
42425
|
}))
|
|
41490
42426
|
}));
|
|
41491
42427
|
}
|
|
@@ -41501,6 +42437,7 @@ var init_EventDetailPage = __esm({
|
|
|
41501
42437
|
init_DetailPageLayout();
|
|
41502
42438
|
init_DetailPageHeader();
|
|
41503
42439
|
init_EventProductsSection();
|
|
42440
|
+
init_EventCombosSection();
|
|
41504
42441
|
sectionCls6 = "border border-gray-200 rounded-lg p-4 bg-gray-50/50";
|
|
41505
42442
|
labelCls7 = "text-xs font-medium text-gray-500";
|
|
41506
42443
|
valueCls = "text-sm text-gray-900 mt-0.5";
|