@infuro/cms-core 1.0.60 → 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 +579 -47
- package/dist/admin.js +580 -48
- package/dist/api.cjs +33 -33
- package/dist/api.js +1 -1
- package/dist/{chunk-BSLNXKV2.cjs → chunk-CNAHVRRU.cjs} +251 -39
- package/dist/{chunk-JAEUYYGA.js → chunk-UHT4INVW.js} +251 -39
- package/dist/index.cjs +489 -246
- package/dist/index.js +277 -34
- package/package.json +1 -1
package/dist/admin.cjs
CHANGED
|
@@ -895,7 +895,7 @@ var init_admin_config_context = __esm({
|
|
|
895
895
|
var CMS_VERSION;
|
|
896
896
|
var init_cms_version = __esm({
|
|
897
897
|
"src/lib/cms-version.ts"() {
|
|
898
|
-
CMS_VERSION = "1.0.
|
|
898
|
+
CMS_VERSION = "1.0.61" ;
|
|
899
899
|
}
|
|
900
900
|
});
|
|
901
901
|
function useCatalogCategories(enabled = true) {
|
|
@@ -2226,6 +2226,11 @@ function FileUpload({ onUploadSuccess }) {
|
|
|
2226
2226
|
if (!selectedFile) return;
|
|
2227
2227
|
setUploading(true);
|
|
2228
2228
|
setProgress(10);
|
|
2229
|
+
console.info("[upload] file-upload start", {
|
|
2230
|
+
name: selectedFile.name,
|
|
2231
|
+
type: selectedFile.type,
|
|
2232
|
+
size: selectedFile.size
|
|
2233
|
+
});
|
|
2229
2234
|
const formData = new FormData();
|
|
2230
2235
|
formData.append("file", selectedFile);
|
|
2231
2236
|
try {
|
|
@@ -2234,20 +2239,47 @@ function FileUpload({ onUploadSuccess }) {
|
|
|
2234
2239
|
body: formData
|
|
2235
2240
|
});
|
|
2236
2241
|
setProgress(60);
|
|
2237
|
-
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
|
+
});
|
|
2238
2256
|
if (response.ok) {
|
|
2239
|
-
|
|
2257
|
+
const url = data.url ?? data.filePath;
|
|
2258
|
+
setFileUrl(url);
|
|
2240
2259
|
setProgress(100);
|
|
2241
|
-
|
|
2260
|
+
console.info("[upload] file-upload ok", {
|
|
2261
|
+
url,
|
|
2262
|
+
name: selectedFile.name
|
|
2263
|
+
});
|
|
2264
|
+
onUploadSuccess(url);
|
|
2242
2265
|
} else {
|
|
2243
2266
|
console.error("[upload] API error", {
|
|
2244
2267
|
status: response.status,
|
|
2245
2268
|
error: data.error,
|
|
2246
|
-
details: data.details
|
|
2269
|
+
details: data.details,
|
|
2270
|
+
name: selectedFile.name,
|
|
2271
|
+
type: selectedFile.type,
|
|
2272
|
+
size: selectedFile.size
|
|
2247
2273
|
});
|
|
2248
2274
|
}
|
|
2249
2275
|
} catch (error) {
|
|
2250
|
-
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
|
+
});
|
|
2251
2283
|
}
|
|
2252
2284
|
setUploading(false);
|
|
2253
2285
|
}, "handleUpload");
|
|
@@ -2379,28 +2411,64 @@ function ImageOrUrlField({ label, value, onChange, placeholder = "https://\u2026
|
|
|
2379
2411
|
return;
|
|
2380
2412
|
}
|
|
2381
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
|
+
});
|
|
2382
2421
|
try {
|
|
2383
2422
|
const formData = new FormData();
|
|
2384
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
|
+
});
|
|
2385
2429
|
const response = await fetch("/api/upload", {
|
|
2386
2430
|
method: "POST",
|
|
2387
2431
|
body: formData
|
|
2388
2432
|
});
|
|
2389
|
-
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
|
+
});
|
|
2390
2447
|
if (!response.ok) {
|
|
2391
2448
|
console.error("[upload] API error", {
|
|
2392
2449
|
status: response.status,
|
|
2393
2450
|
error: data.error,
|
|
2394
|
-
details: data.details
|
|
2451
|
+
details: data.details,
|
|
2452
|
+
fileName: file.name,
|
|
2453
|
+
fileType: file.type,
|
|
2454
|
+
fileSize: file.size
|
|
2395
2455
|
});
|
|
2396
2456
|
throw new Error(data.details || data.error || "Upload failed");
|
|
2397
2457
|
}
|
|
2398
2458
|
console.info("[upload] API ok", {
|
|
2399
|
-
filePath: data.filePath
|
|
2459
|
+
filePath: data.filePath,
|
|
2460
|
+
name: file.name,
|
|
2461
|
+
type: file.type
|
|
2400
2462
|
});
|
|
2401
2463
|
onChange(data.filePath ?? "");
|
|
2402
2464
|
} catch (err) {
|
|
2403
|
-
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
|
+
});
|
|
2404
2472
|
setError(err instanceof Error ? err.message : "Upload failed");
|
|
2405
2473
|
} finally {
|
|
2406
2474
|
setIsUploading(false);
|
|
@@ -5099,6 +5167,9 @@ function AdminCRUD({ title, apiEndpoint, columns, addEditPageUrl, customViewPage
|
|
|
5099
5167
|
});
|
|
5100
5168
|
if (cancelled) return;
|
|
5101
5169
|
if (!res.ok) {
|
|
5170
|
+
if (res.status === 403) {
|
|
5171
|
+
throw new Error("You don't have access to this section");
|
|
5172
|
+
}
|
|
5102
5173
|
throw new Error(`HTTP error! status: ${res.status}`);
|
|
5103
5174
|
}
|
|
5104
5175
|
const result = await res.json();
|
|
@@ -5515,15 +5586,26 @@ function AdminCRUD({ title, apiEndpoint, columns, addEditPageUrl, customViewPage
|
|
|
5515
5586
|
}, "Loading...")));
|
|
5516
5587
|
}
|
|
5517
5588
|
if (error) {
|
|
5589
|
+
const isForbidden = error.toLowerCase().includes("don't have access") || error.toLowerCase().includes("forbidden") || error.includes("403");
|
|
5518
5590
|
return /* @__PURE__ */ React.createElement("div", {
|
|
5519
5591
|
className: embedded ? "p-4" : "rounded-lg bg-white p-6 shadow-md"
|
|
5520
5592
|
}, /* @__PURE__ */ React.createElement("div", {
|
|
5521
|
-
className: "text-center py-
|
|
5522
|
-
}, /* @__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", {
|
|
5523
5605
|
className: "text-red-600 mb-4"
|
|
5524
5606
|
}, "Error loading data: ", error), /* @__PURE__ */ React.createElement(Button, {
|
|
5525
5607
|
onClick: /* @__PURE__ */ __name(() => window.location.reload(), "onClick")
|
|
5526
|
-
}, "Retry")));
|
|
5608
|
+
}, "Retry"))));
|
|
5527
5609
|
}
|
|
5528
5610
|
return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("div", {
|
|
5529
5611
|
className: shellCls
|
|
@@ -6887,26 +6969,63 @@ function ImageUpload({ value, onChange, onRemove, label, required = false, class
|
|
|
6887
6969
|
return;
|
|
6888
6970
|
}
|
|
6889
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
|
+
});
|
|
6890
6978
|
try {
|
|
6891
6979
|
const formData = new FormData();
|
|
6892
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
|
+
});
|
|
6893
6986
|
const response = await fetch("/api/upload", {
|
|
6894
6987
|
method: "POST",
|
|
6895
6988
|
body: formData
|
|
6896
6989
|
});
|
|
6897
|
-
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
|
+
});
|
|
6898
7004
|
if (!response.ok) {
|
|
6899
7005
|
console.error("[upload] API error", {
|
|
6900
7006
|
status: response.status,
|
|
6901
7007
|
error: data.error,
|
|
6902
|
-
details: data.details
|
|
7008
|
+
details: data.details,
|
|
7009
|
+
fileName: file.name,
|
|
7010
|
+
fileType: file.type,
|
|
7011
|
+
fileSize: file.size
|
|
6903
7012
|
});
|
|
6904
7013
|
throw new Error(data.details || data.error || "Upload failed");
|
|
6905
7014
|
}
|
|
7015
|
+
console.info("[upload] client image-upload ok", {
|
|
7016
|
+
filePath: data.filePath,
|
|
7017
|
+
name: file.name
|
|
7018
|
+
});
|
|
6906
7019
|
onChange(data.filePath);
|
|
6907
7020
|
setUploadProgress(100);
|
|
6908
7021
|
} catch (error2) {
|
|
6909
|
-
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
|
+
});
|
|
6910
7029
|
setError(error2 instanceof Error ? error2.message : "Failed to upload image");
|
|
6911
7030
|
} finally {
|
|
6912
7031
|
setIsUploading(false);
|
|
@@ -33285,6 +33404,252 @@ var init_EventProductsSection = __esm({
|
|
|
33285
33404
|
__name(EventProductsSection, "EventProductsSection");
|
|
33286
33405
|
}
|
|
33287
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
|
+
});
|
|
33288
33653
|
|
|
33289
33654
|
// src/lib/social-media-links.ts
|
|
33290
33655
|
function isValidHttpUrl(value) {
|
|
@@ -34778,10 +35143,13 @@ function EventEditPage({ eventId }) {
|
|
|
34778
35143
|
onClick: goToNextTab,
|
|
34779
35144
|
className: "rounded-md bg-gray-900 px-4 py-2 text-sm font-medium text-white hover:bg-gray-800"
|
|
34780
35145
|
}, "Next") : /* @__PURE__ */ React.createElement("div", null)), showEventProducts ? /* @__PURE__ */ React.createElement("div", {
|
|
34781
|
-
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"
|
|
34782
35147
|
}, /* @__PURE__ */ React.createElement(EventProductsSection, {
|
|
34783
35148
|
eventId: eventRecordId,
|
|
34784
35149
|
returnUrl: eventEditUrl
|
|
35150
|
+
}), /* @__PURE__ */ React.createElement(EventCombosSection, {
|
|
35151
|
+
eventId: eventRecordId,
|
|
35152
|
+
returnUrl: eventEditUrl
|
|
34785
35153
|
})) : null);
|
|
34786
35154
|
}
|
|
34787
35155
|
var ADDITIONAL_VENUE_MAX_CHARS, DEFAULT_EVENT_TIMEZONE, DEFAULT_EVENT_CURRENCY, EVENT_SOCIAL_KEYS, isCreate4, sectionCls4, labelCls6, inputCls6, ENTITY_TYPE_OPTIONS;
|
|
@@ -34796,6 +35164,7 @@ var init_EventEditPage = __esm({
|
|
|
34796
35164
|
init_media_url();
|
|
34797
35165
|
init_JoditRichText();
|
|
34798
35166
|
init_EventProductsSection();
|
|
35167
|
+
init_EventCombosSection();
|
|
34799
35168
|
init_admin_config_context();
|
|
34800
35169
|
init_dialog();
|
|
34801
35170
|
init_button();
|
|
@@ -34833,7 +35202,13 @@ function formatDateTimeLocal(value) {
|
|
|
34833
35202
|
if (value == null) return "";
|
|
34834
35203
|
const date = new Date(String(value));
|
|
34835
35204
|
if (isNaN(date.getTime())) return "";
|
|
34836
|
-
|
|
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}`;
|
|
34837
35212
|
}
|
|
34838
35213
|
async function fetchEventDefaultCurrency(eventId) {
|
|
34839
35214
|
try {
|
|
@@ -34880,13 +35255,14 @@ function ComboEditPage({ comboId }) {
|
|
|
34880
35255
|
const create = isCreate5(comboId);
|
|
34881
35256
|
const duplicateFrom = searchParams.get("duplicateFrom")?.trim();
|
|
34882
35257
|
const duplicateSourceId = create && duplicateFrom && /^\d+$/.test(duplicateFrom) ? duplicateFrom : null;
|
|
35258
|
+
const initialEventId = create ? searchParams.get("eventId")?.trim() || "" : "";
|
|
34883
35259
|
const [loading, setLoading] = React25.useState(!create || !!duplicateSourceId);
|
|
34884
35260
|
const [saving, setSaving] = React25.useState(false);
|
|
34885
35261
|
const [errors, setErrors] = React25.useState([]);
|
|
34886
35262
|
const [name, setName] = React25.useState("");
|
|
34887
35263
|
const [slug, setSlug] = React25.useState("");
|
|
34888
35264
|
const [desc, setDesc] = React25.useState("");
|
|
34889
|
-
const [eventId, setEventId] = React25.useState(
|
|
35265
|
+
const [eventId, setEventId] = React25.useState(initialEventId);
|
|
34890
35266
|
const [priceStr, setPriceStr] = React25.useState("");
|
|
34891
35267
|
const [defaultCurrency, setDefaultCurrency] = React25.useState("INR");
|
|
34892
35268
|
const [minSelectableItems, setMinSelectableItems] = React25.useState(1);
|
|
@@ -35123,15 +35499,9 @@ function ComboEditPage({ comboId }) {
|
|
|
35123
35499
|
]);
|
|
35124
35500
|
return;
|
|
35125
35501
|
}
|
|
35126
|
-
if (
|
|
35502
|
+
if (startsAt && endsAt && new Date(endsAt).getTime() < new Date(startsAt).getTime()) {
|
|
35127
35503
|
setErrors([
|
|
35128
|
-
"
|
|
35129
|
-
]);
|
|
35130
|
-
return;
|
|
35131
|
-
}
|
|
35132
|
-
if (!endsAt) {
|
|
35133
|
-
setErrors([
|
|
35134
|
-
"Ends at is required"
|
|
35504
|
+
"Ends at cannot be earlier than Starts at"
|
|
35135
35505
|
]);
|
|
35136
35506
|
return;
|
|
35137
35507
|
}
|
|
@@ -35199,8 +35569,8 @@ function ComboEditPage({ comboId }) {
|
|
|
35199
35569
|
minSelectableItems,
|
|
35200
35570
|
maxSelectableItems,
|
|
35201
35571
|
status,
|
|
35202
|
-
startsAt: startsAt
|
|
35203
|
-
endsAt: endsAt
|
|
35572
|
+
startsAt: startsAt ? new Date(startsAt).toISOString() : null,
|
|
35573
|
+
endsAt: endsAt ? new Date(endsAt).toISOString() : null,
|
|
35204
35574
|
comboItems: [
|
|
35205
35575
|
...fixedItems.map((i) => ({
|
|
35206
35576
|
productId: Number(i.productId),
|
|
@@ -35424,21 +35794,23 @@ function ComboEditPage({ comboId }) {
|
|
|
35424
35794
|
className: "grid grid-cols-2 gap-4"
|
|
35425
35795
|
}, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("label", {
|
|
35426
35796
|
className: "block text-xs font-medium text-gray-600 mb-1"
|
|
35427
|
-
}, "Starts at
|
|
35797
|
+
}, "Starts at (optional)"), /* @__PURE__ */ React.createElement("input", {
|
|
35428
35798
|
type: "datetime-local",
|
|
35429
35799
|
value: startsAt,
|
|
35430
35800
|
onChange: /* @__PURE__ */ __name((e) => setStartsAt(e.target.value), "onChange"),
|
|
35431
|
-
className: "w-full rounded-md border border-gray-300 px-3 py-2 text-sm"
|
|
35432
|
-
|
|
35433
|
-
|
|
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", {
|
|
35434
35805
|
className: "block text-xs font-medium text-gray-600 mb-1"
|
|
35435
|
-
}, "Ends at
|
|
35806
|
+
}, "Ends at (optional)"), /* @__PURE__ */ React.createElement("input", {
|
|
35436
35807
|
type: "datetime-local",
|
|
35437
35808
|
value: endsAt,
|
|
35438
35809
|
onChange: /* @__PURE__ */ __name((e) => setEndsAt(e.target.value), "onChange"),
|
|
35439
|
-
className: "w-full rounded-md border border-gray-300 px-3 py-2 text-sm"
|
|
35440
|
-
|
|
35441
|
-
|
|
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.")))))),
|
|
35442
35814
|
sidebar: /* @__PURE__ */ React.createElement(React.Fragment, null)
|
|
35443
35815
|
}));
|
|
35444
35816
|
}
|
|
@@ -35554,6 +35926,130 @@ function VendorEditPage({ vendorId }) {
|
|
|
35554
35926
|
const [inviteDialog, setInviteDialog] = React25.useState(null);
|
|
35555
35927
|
const [sendingInviteEmail, setSendingInviteEmail] = React25.useState(false);
|
|
35556
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
|
+
]);
|
|
35557
36053
|
const vendorPayload = /* @__PURE__ */ __name(() => ({
|
|
35558
36054
|
name: name.trim(),
|
|
35559
36055
|
legalName: legalName.trim() || null,
|
|
@@ -35797,12 +36293,15 @@ function VendorEditPage({ vendorId }) {
|
|
|
35797
36293
|
setSaving(false);
|
|
35798
36294
|
return;
|
|
35799
36295
|
}
|
|
36296
|
+
const abortController = new AbortController();
|
|
36297
|
+
const timeoutId = setTimeout(() => abortController.abort(), 15e3);
|
|
35800
36298
|
try {
|
|
35801
36299
|
const res = await fetch("/api/admin/vendors/onboard", {
|
|
35802
36300
|
method: "POST",
|
|
35803
36301
|
headers: {
|
|
35804
36302
|
"Content-Type": "application/json"
|
|
35805
36303
|
},
|
|
36304
|
+
signal: abortController.signal,
|
|
35806
36305
|
body: JSON.stringify({
|
|
35807
36306
|
activation: "invite",
|
|
35808
36307
|
sendOwnerEmail: false,
|
|
@@ -35823,15 +36322,20 @@ function VendorEditPage({ vendorId }) {
|
|
|
35823
36322
|
}
|
|
35824
36323
|
})
|
|
35825
36324
|
});
|
|
35826
|
-
|
|
36325
|
+
clearTimeout(timeoutId);
|
|
36326
|
+
const data = await res.json().catch(() => ({}));
|
|
35827
36327
|
if (!res.ok) {
|
|
35828
36328
|
setErrors([
|
|
35829
36329
|
data.error || "Onboarding failed"
|
|
35830
36330
|
]);
|
|
35831
36331
|
return;
|
|
35832
36332
|
}
|
|
36333
|
+
try {
|
|
36334
|
+
sessionStorage.removeItem(VENDOR_CREATE_DRAFT_KEY);
|
|
36335
|
+
} catch {
|
|
36336
|
+
}
|
|
35833
36337
|
const vendorIdNum = Number(data.vendor?.id);
|
|
35834
|
-
const inviteLink = typeof data.inviteLink === "string" && data.inviteLink
|
|
36338
|
+
const inviteLink = typeof data.inviteLink === "string" && data.inviteLink?.trim() ? data.inviteLink.trim() : "";
|
|
35835
36339
|
if (!Number.isFinite(vendorIdNum) || vendorIdNum <= 0 || !inviteLink) {
|
|
35836
36340
|
sonner.toast.success(data.message || "Vendor created");
|
|
35837
36341
|
router.push(listReturnUrl);
|
|
@@ -35843,11 +36347,18 @@ function VendorEditPage({ vendorId }) {
|
|
|
35843
36347
|
vendorId: vendorIdNum,
|
|
35844
36348
|
inviteLink
|
|
35845
36349
|
});
|
|
35846
|
-
} catch {
|
|
35847
|
-
|
|
35848
|
-
|
|
35849
|
-
|
|
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
|
+
}
|
|
35850
36360
|
} finally {
|
|
36361
|
+
clearTimeout(timeoutId);
|
|
35851
36362
|
setSaving(false);
|
|
35852
36363
|
}
|
|
35853
36364
|
}, "handleCreate");
|
|
@@ -35886,12 +36397,15 @@ function VendorEditPage({ vendorId }) {
|
|
|
35886
36397
|
setSaving(false);
|
|
35887
36398
|
return;
|
|
35888
36399
|
}
|
|
36400
|
+
const abortController = new AbortController();
|
|
36401
|
+
const timeoutId = setTimeout(() => abortController.abort(), 15e3);
|
|
35889
36402
|
try {
|
|
35890
36403
|
const res = await fetch(`/api/vendors/${vendorId}`, {
|
|
35891
36404
|
method: "PUT",
|
|
35892
36405
|
headers: {
|
|
35893
36406
|
"Content-Type": "application/json"
|
|
35894
36407
|
},
|
|
36408
|
+
signal: abortController.signal,
|
|
35895
36409
|
body: JSON.stringify({
|
|
35896
36410
|
...vendorPayload(),
|
|
35897
36411
|
slug: slug.trim(),
|
|
@@ -35907,6 +36421,7 @@ function VendorEditPage({ vendorId }) {
|
|
|
35907
36421
|
})
|
|
35908
36422
|
});
|
|
35909
36423
|
if (!res.ok) {
|
|
36424
|
+
clearTimeout(timeoutId);
|
|
35910
36425
|
const data = await res.json().catch(() => ({}));
|
|
35911
36426
|
setErrors([
|
|
35912
36427
|
data.error || "Failed to save"
|
|
@@ -35920,6 +36435,7 @@ function VendorEditPage({ vendorId }) {
|
|
|
35920
36435
|
headers: {
|
|
35921
36436
|
"Content-Type": "application/json"
|
|
35922
36437
|
},
|
|
36438
|
+
signal: abortController.signal,
|
|
35923
36439
|
body: JSON.stringify({
|
|
35924
36440
|
name: ownerName.trim(),
|
|
35925
36441
|
email: ownerEmail.trim(),
|
|
@@ -35927,6 +36443,7 @@ function VendorEditPage({ vendorId }) {
|
|
|
35927
36443
|
})
|
|
35928
36444
|
});
|
|
35929
36445
|
if (!userRes.ok) {
|
|
36446
|
+
clearTimeout(timeoutId);
|
|
35930
36447
|
const data = await userRes.json().catch(() => ({}));
|
|
35931
36448
|
setErrors([
|
|
35932
36449
|
data.error || "Vendor saved, but updating owner details failed"
|
|
@@ -35934,13 +36451,21 @@ function VendorEditPage({ vendorId }) {
|
|
|
35934
36451
|
return;
|
|
35935
36452
|
}
|
|
35936
36453
|
}
|
|
36454
|
+
clearTimeout(timeoutId);
|
|
35937
36455
|
sonner.toast.success("Vendor saved");
|
|
35938
36456
|
router.push(listReturnUrl);
|
|
35939
|
-
} catch {
|
|
35940
|
-
|
|
35941
|
-
|
|
35942
|
-
|
|
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
|
+
}
|
|
35943
36467
|
} finally {
|
|
36468
|
+
clearTimeout(timeoutId);
|
|
35944
36469
|
setSaving(false);
|
|
35945
36470
|
}
|
|
35946
36471
|
}, "handleSave");
|
|
@@ -41346,6 +41871,8 @@ var init_AdminPageResolver = __esm({
|
|
|
41346
41871
|
submissions: {
|
|
41347
41872
|
title: "Submissions",
|
|
41348
41873
|
apiEndpoint: "/api/form-submissions",
|
|
41874
|
+
defaultSortField: "createdAt",
|
|
41875
|
+
defaultSortOrder: "desc",
|
|
41349
41876
|
columns: [
|
|
41350
41877
|
{
|
|
41351
41878
|
field: "form.name",
|
|
@@ -41891,6 +42418,10 @@ function EventDetailPage({ eventId }) {
|
|
|
41891
42418
|
eventId: String(event.id),
|
|
41892
42419
|
returnUrl: detailUrl,
|
|
41893
42420
|
readOnly: true
|
|
42421
|
+
}), /* @__PURE__ */ React.createElement(EventCombosSection, {
|
|
42422
|
+
eventId: String(event.id),
|
|
42423
|
+
returnUrl: detailUrl,
|
|
42424
|
+
readOnly: true
|
|
41894
42425
|
}))
|
|
41895
42426
|
}));
|
|
41896
42427
|
}
|
|
@@ -41906,6 +42437,7 @@ var init_EventDetailPage = __esm({
|
|
|
41906
42437
|
init_DetailPageLayout();
|
|
41907
42438
|
init_DetailPageHeader();
|
|
41908
42439
|
init_EventProductsSection();
|
|
42440
|
+
init_EventCombosSection();
|
|
41909
42441
|
sectionCls6 = "border border-gray-200 rounded-lg p-4 bg-gray-50/50";
|
|
41910
42442
|
labelCls7 = "text-xs font-medium text-gray-500";
|
|
41911
42443
|
valueCls = "text-sm text-gray-900 mt-0.5";
|