@universe-platform/ui 0.1.0-beta.6 → 0.1.0-beta.8
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/globals.css +244 -0
- package/dist/index.d.mts +33 -1
- package/dist/index.d.ts +33 -1
- package/dist/index.js +1748 -232
- package/dist/index.mjs +1741 -227
- package/dist/phone.d.mts +38 -0
- package/dist/phone.d.ts +38 -0
- package/dist/phone.js +90 -0
- package/dist/phone.mjs +59 -0
- package/package.json +6 -1
package/dist/index.js
CHANGED
|
@@ -58,16 +58,18 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
58
58
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
59
59
|
|
|
60
60
|
// src/index.ts
|
|
61
|
-
var
|
|
62
|
-
__export(
|
|
61
|
+
var src_exports = {};
|
|
62
|
+
__export(src_exports, {
|
|
63
63
|
TableBlock: () => TableBlock,
|
|
64
64
|
ToastContext: () => ToastContext,
|
|
65
65
|
ToastProvider: () => ToastProvider,
|
|
66
66
|
UNIVERSE_COMPONENTS: () => UNIVERSE_COMPONENTS,
|
|
67
67
|
cn: () => cn,
|
|
68
|
+
formatPhoneDisplay: () => formatPhoneDisplay,
|
|
69
|
+
openWhatsAppChat: () => openWhatsAppChat,
|
|
68
70
|
useToast: () => useToast
|
|
69
71
|
});
|
|
70
|
-
module.exports = __toCommonJS(
|
|
72
|
+
module.exports = __toCommonJS(src_exports);
|
|
71
73
|
|
|
72
74
|
// src/utils/cn.ts
|
|
73
75
|
var import_clsx = require("clsx");
|
|
@@ -76,8 +78,38 @@ function cn(...inputs) {
|
|
|
76
78
|
return (0, import_tailwind_merge.twMerge)((0, import_clsx.clsx)(inputs));
|
|
77
79
|
}
|
|
78
80
|
|
|
81
|
+
// src/utils/whatsapp.ts
|
|
82
|
+
function openWhatsAppChat(phone, defaultCountryCode = "972") {
|
|
83
|
+
if (!phone || typeof window === "undefined") return;
|
|
84
|
+
let cleaned = phone.replace(/\D/g, "");
|
|
85
|
+
if (cleaned.startsWith("0")) {
|
|
86
|
+
cleaned = defaultCountryCode + cleaned.substring(1);
|
|
87
|
+
}
|
|
88
|
+
const appUrl = `whatsapp://send?phone=${cleaned}`;
|
|
89
|
+
const webUrl = `https://web.whatsapp.com/send?phone=${cleaned}`;
|
|
90
|
+
const start = Date.now();
|
|
91
|
+
window.location.href = appUrl;
|
|
92
|
+
setTimeout(() => {
|
|
93
|
+
if (typeof document !== "undefined" && document.hasFocus() && Date.now() - start < 2e3) {
|
|
94
|
+
window.open(webUrl, "_blank", "noopener,noreferrer");
|
|
95
|
+
}
|
|
96
|
+
}, 1200);
|
|
97
|
+
}
|
|
98
|
+
function formatPhoneDisplay(phone) {
|
|
99
|
+
if (!phone) return "";
|
|
100
|
+
const digits = phone.replace(/\D/g, "");
|
|
101
|
+
if (digits.length === 10 && digits.startsWith("05")) {
|
|
102
|
+
return `${digits.slice(0, 3)}-${digits.slice(3, 6)}-${digits.slice(6)}`;
|
|
103
|
+
}
|
|
104
|
+
if (digits.length === 12 && digits.startsWith("9725")) {
|
|
105
|
+
const local = "0" + digits.slice(3);
|
|
106
|
+
return `${local.slice(0, 3)}-${local.slice(3, 6)}-${local.slice(6)}`;
|
|
107
|
+
}
|
|
108
|
+
return phone;
|
|
109
|
+
}
|
|
110
|
+
|
|
79
111
|
// src/components/TableBlock/TableBlockClient.tsx
|
|
80
|
-
var
|
|
112
|
+
var import_react7 = __toESM(require("react"));
|
|
81
113
|
|
|
82
114
|
// src/hooks/useToast.ts
|
|
83
115
|
var import_react2 = require("react");
|
|
@@ -280,12 +312,36 @@ function useToast() {
|
|
|
280
312
|
var import_react5 = __toESM(require("react"));
|
|
281
313
|
|
|
282
314
|
// src/components/TableBlock/fields/DrivePickerCell.tsx
|
|
283
|
-
var import_react3 = require("react");
|
|
315
|
+
var import_react3 = __toESM(require("react"));
|
|
284
316
|
var import_lucide_react2 = require("lucide-react");
|
|
285
317
|
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
286
|
-
function DrivePickerCell({ value, onChange, tableName, onMarkForDeletion, context }) {
|
|
318
|
+
function DrivePickerCell({ value, onChange, tableName, column, rowId, onMarkForDeletion, context }) {
|
|
287
319
|
const [isOpening, setIsOpening] = (0, import_react3.useState)(false);
|
|
288
320
|
const { showError } = useToast();
|
|
321
|
+
const cellContextId = import_react3.default.useMemo(() => {
|
|
322
|
+
const colName = (column == null ? void 0 : column.name) || "col";
|
|
323
|
+
const rId = rowId || "row";
|
|
324
|
+
return `${rId}-${colName}`;
|
|
325
|
+
}, [rowId, column == null ? void 0 : column.name]);
|
|
326
|
+
const fileList = import_react3.default.useMemo(() => {
|
|
327
|
+
if (!value) return [];
|
|
328
|
+
if (Array.isArray(value)) return value;
|
|
329
|
+
if (typeof value === "object" && (value.fileId || value.fileUrl || value.url)) {
|
|
330
|
+
return [value];
|
|
331
|
+
}
|
|
332
|
+
return [];
|
|
333
|
+
}, [value]);
|
|
334
|
+
(0, import_react3.useEffect)(() => {
|
|
335
|
+
const handleMessage = (event) => {
|
|
336
|
+
var _a, _b, _c;
|
|
337
|
+
if (((_a = event.data) == null ? void 0 : _a.type) === "DRIVE_UPLOAD_SUCCESS" && ((_b = event.data) == null ? void 0 : _b.payload) && ((_c = event.data) == null ? void 0 : _c.cellContextId) === cellContextId) {
|
|
338
|
+
const incoming = Array.isArray(event.data.payload) ? event.data.payload : [event.data.payload];
|
|
339
|
+
onChange([...fileList, ...incoming]);
|
|
340
|
+
}
|
|
341
|
+
};
|
|
342
|
+
window.addEventListener("message", handleMessage);
|
|
343
|
+
return () => window.removeEventListener("message", handleMessage);
|
|
344
|
+
}, [fileList, onChange, cellContextId]);
|
|
289
345
|
const openUploadPopup = async () => {
|
|
290
346
|
if (isOpening) return;
|
|
291
347
|
setIsOpening(true);
|
|
@@ -314,34 +370,35 @@ function DrivePickerCell({ value, onChange, tableName, onMarkForDeletion, contex
|
|
|
314
370
|
} catch (e) {
|
|
315
371
|
}
|
|
316
372
|
}
|
|
317
|
-
const actionResult = await context.executeAction("UPLOAD_DRIVE_FILE", { tableName });
|
|
373
|
+
const actionResult = await context.executeAction("UPLOAD_DRIVE_FILE", { tableName, cellContextId });
|
|
318
374
|
const folderId = actionResult == null ? void 0 : actionResult.folderId;
|
|
319
|
-
|
|
375
|
+
let pickerUrl = (actionResult == null ? void 0 : actionResult.pickerUrl) || (folderId ? `/embed/picker?folderId=${encodeURIComponent(folderId)}` : `/embed/picker`);
|
|
376
|
+
if (!pickerUrl.includes("cellContextId=")) {
|
|
377
|
+
const separator = pickerUrl.includes("?") ? "&" : "?";
|
|
378
|
+
pickerUrl = `${pickerUrl}${separator}cellContextId=${encodeURIComponent(cellContextId)}`;
|
|
379
|
+
}
|
|
320
380
|
if (popup) {
|
|
321
381
|
popup.location.href = pickerUrl;
|
|
322
382
|
}
|
|
323
|
-
|
|
383
|
+
await new Promise((resolve) => {
|
|
324
384
|
let timer = null;
|
|
325
|
-
const
|
|
385
|
+
const handlePopupMessage = (event) => {
|
|
326
386
|
var _a, _b;
|
|
327
|
-
if (((_a = event.data) == null ? void 0 : _a.type) === "DRIVE_UPLOAD_SUCCESS" && ((_b = event.data) == null ? void 0 : _b.
|
|
328
|
-
window.removeEventListener("message",
|
|
387
|
+
if (((_a = event.data) == null ? void 0 : _a.type) === "DRIVE_UPLOAD_SUCCESS" && ((_b = event.data) == null ? void 0 : _b.cellContextId) === cellContextId) {
|
|
388
|
+
window.removeEventListener("message", handlePopupMessage);
|
|
329
389
|
if (timer) clearInterval(timer);
|
|
330
|
-
resolve(
|
|
390
|
+
resolve();
|
|
331
391
|
}
|
|
332
392
|
};
|
|
333
393
|
timer = setInterval(() => {
|
|
334
394
|
if (!popup || popup.closed) {
|
|
335
395
|
if (timer) clearInterval(timer);
|
|
336
|
-
window.removeEventListener("message",
|
|
337
|
-
resolve(
|
|
396
|
+
window.removeEventListener("message", handlePopupMessage);
|
|
397
|
+
resolve();
|
|
338
398
|
}
|
|
339
399
|
}, 800);
|
|
340
|
-
window.addEventListener("message",
|
|
400
|
+
window.addEventListener("message", handlePopupMessage);
|
|
341
401
|
});
|
|
342
|
-
if (newFile) {
|
|
343
|
-
onChange(newFile);
|
|
344
|
-
}
|
|
345
402
|
}
|
|
346
403
|
} catch (error) {
|
|
347
404
|
console.error("[DrivePickerCell] Error uploading file:", error);
|
|
@@ -351,40 +408,15 @@ function DrivePickerCell({ value, onChange, tableName, onMarkForDeletion, contex
|
|
|
351
408
|
setIsOpening(false);
|
|
352
409
|
}
|
|
353
410
|
};
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
title: value.fileName || "Open file",
|
|
364
|
-
children: [
|
|
365
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_lucide_react2.FileText, { className: "w-3.5 h-3.5 shrink-0" }),
|
|
366
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "truncate", children: value.fileName || "Unnamed file" })
|
|
367
|
-
]
|
|
368
|
-
}
|
|
369
|
-
),
|
|
370
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
371
|
-
"button",
|
|
372
|
-
{
|
|
373
|
-
type: "button",
|
|
374
|
-
onClick: () => {
|
|
375
|
-
if ((value == null ? void 0 : value.fileId) && onMarkForDeletion) {
|
|
376
|
-
onMarkForDeletion(value.fileId);
|
|
377
|
-
}
|
|
378
|
-
onChange(null);
|
|
379
|
-
},
|
|
380
|
-
className: "shrink-0 p-0.5 rounded hover:bg-rose-100 text-slate-400 hover:text-rose-500 transition-colors",
|
|
381
|
-
title: "Remove file",
|
|
382
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_lucide_react2.X, { className: "w-3.5 h-3.5" })
|
|
383
|
-
}
|
|
384
|
-
)
|
|
385
|
-
] });
|
|
386
|
-
}
|
|
387
|
-
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "flex items-center w-full h-8 px-2", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
411
|
+
const handleRemoveFile = (indexToRemove) => {
|
|
412
|
+
const fileToRemove = fileList[indexToRemove];
|
|
413
|
+
if ((fileToRemove == null ? void 0 : fileToRemove.fileId) && onMarkForDeletion) {
|
|
414
|
+
onMarkForDeletion(fileToRemove.fileId);
|
|
415
|
+
}
|
|
416
|
+
const updated = fileList.filter((_, idx) => idx !== indexToRemove);
|
|
417
|
+
onChange(updated);
|
|
418
|
+
};
|
|
419
|
+
const renderUploadButton = () => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "flex items-center w-full h-8 px-2", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
388
420
|
"button",
|
|
389
421
|
{
|
|
390
422
|
type: "button",
|
|
@@ -397,6 +429,38 @@ function DrivePickerCell({ value, onChange, tableName, onMarkForDeletion, contex
|
|
|
397
429
|
]
|
|
398
430
|
}
|
|
399
431
|
) });
|
|
432
|
+
if (fileList.length > 0) {
|
|
433
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex flex-col w-full py-1 gap-1", children: [
|
|
434
|
+
fileList.map((file, idx) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex items-center w-full h-8 px-2 gap-1", children: [
|
|
435
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
436
|
+
"a",
|
|
437
|
+
{
|
|
438
|
+
href: file.fileUrl || file.url,
|
|
439
|
+
target: "_blank",
|
|
440
|
+
rel: "noopener noreferrer",
|
|
441
|
+
className: "inline-flex items-center gap-1.5 max-w-[calc(100%-24px)] px-2 py-1 rounded-md text-xs font-medium text-blue-700 bg-blue-50 hover:bg-blue-100 transition-colors truncate",
|
|
442
|
+
title: file.fileName || "Open file",
|
|
443
|
+
children: [
|
|
444
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_lucide_react2.FileText, { className: "w-3.5 h-3.5 shrink-0" }),
|
|
445
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "truncate", children: file.fileName || "Unnamed file" })
|
|
446
|
+
]
|
|
447
|
+
}
|
|
448
|
+
),
|
|
449
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
450
|
+
"button",
|
|
451
|
+
{
|
|
452
|
+
type: "button",
|
|
453
|
+
onClick: () => handleRemoveFile(idx),
|
|
454
|
+
className: "shrink-0 p-0.5 rounded hover:bg-rose-100 text-slate-400 hover:text-rose-500 transition-colors",
|
|
455
|
+
title: "Remove file",
|
|
456
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_lucide_react2.X, { className: "w-3.5 h-3.5" })
|
|
457
|
+
}
|
|
458
|
+
)
|
|
459
|
+
] }, file.fileId || idx)),
|
|
460
|
+
renderUploadButton()
|
|
461
|
+
] });
|
|
462
|
+
}
|
|
463
|
+
return renderUploadButton();
|
|
400
464
|
}
|
|
401
465
|
|
|
402
466
|
// src/components/TableBlock/fields/DatePickerCell.tsx
|
|
@@ -831,11 +895,13 @@ var FORM_INPUTS = {
|
|
|
831
895
|
className: "w-4 h-4 rounded border-slate-300 text-brand"
|
|
832
896
|
}
|
|
833
897
|
) }),
|
|
834
|
-
GOOGLE_DRIVE_FILE: ({ value, onChange, context }) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
898
|
+
GOOGLE_DRIVE_FILE: ({ value, onChange, column, rowId, context }) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
835
899
|
DrivePickerCell,
|
|
836
900
|
{
|
|
837
|
-
value: value ||
|
|
901
|
+
value: value || [],
|
|
838
902
|
onChange,
|
|
903
|
+
column,
|
|
904
|
+
rowId,
|
|
839
905
|
tableName: context == null ? void 0 : context.tableName,
|
|
840
906
|
onMarkForDeletion: context == null ? void 0 : context.onMarkForDeletion,
|
|
841
907
|
context
|
|
@@ -893,6 +959,249 @@ var FORM_INPUTS = {
|
|
|
893
959
|
}
|
|
894
960
|
}
|
|
895
961
|
),
|
|
962
|
+
PHONE: ({ value, onChange, column }) => {
|
|
963
|
+
var _a;
|
|
964
|
+
const enableWhatsApp = (_a = column == null ? void 0 : column.config) == null ? void 0 : _a.enableWhatsApp;
|
|
965
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "flex items-center w-full h-full px-2 gap-1.5", children: [
|
|
966
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
967
|
+
"input",
|
|
968
|
+
{
|
|
969
|
+
type: "tel",
|
|
970
|
+
className: "w-full h-8 bg-transparent focus:bg-white focus:outline-none focus:ring-1 focus:ring-blue-400 text-sm flex-1",
|
|
971
|
+
value: value !== void 0 && value !== null ? String(value) : "",
|
|
972
|
+
onChange: (e) => onChange(e.target.value),
|
|
973
|
+
dir: "ltr"
|
|
974
|
+
}
|
|
975
|
+
),
|
|
976
|
+
enableWhatsApp && value && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
977
|
+
"button",
|
|
978
|
+
{
|
|
979
|
+
type: "button",
|
|
980
|
+
className: "text-emerald-500 cursor-pointer hover:opacity-80 transition-opacity shrink-0 p-1 rounded hover:bg-emerald-50",
|
|
981
|
+
title: "\u05E4\u05EA\u05D9\u05D7\u05EA \u05D5\u05D5\u05D0\u05D8\u05E1\u05D0\u05E4",
|
|
982
|
+
onClick: (e) => {
|
|
983
|
+
e.stopPropagation();
|
|
984
|
+
openWhatsAppChat(String(value));
|
|
985
|
+
},
|
|
986
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { className: "w-4 h-4", fill: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M17.472 14.382c-.297-.149-1.758-.867-2.03-.967-.273-.099-.471-.148-.67.15-.197.297-.767.966-.94 1.164-.173.199-.347.223-.644.075-.297-.15-1.255-.463-2.39-1.475-.883-.788-1.48-1.761-1.653-2.059-.173-.297-.018-.458.13-.606.134-.133.298-.347.446-.52.149-.174.198-.298.298-.497.099-.198.05-.371-.025-.52-.075-.149-.669-1.612-.916-2.207-.242-.579-.487-.5-.669-.51a5.816 5.816 0 00-.571-.01c-.198 0-.52.074-.792.372-.272.297-1.04 1.016-1.04 2.479 0 1.462 1.065 2.875 1.213 3.074.149.198 2.096 3.2 5.077 4.487.709.306 1.262.489 1.694.625.712.227 1.36.195 1.871.118.571-.085 1.758-.719 2.006-1.413.248-.694.248-1.289.173-1.413-.074-.124-.272-.198-.57-.347m-5.421 7.403h-.004a9.87 9.87 0 01-5.031-1.378l-.361-.214-3.741.982.998-3.648-.235-.374a9.86 9.86 0 01-1.51-5.26c.001-5.45 4.436-9.884 9.888-9.884 2.64 0 5.122 1.03 6.988 2.898a9.825 9.825 0 012.893 6.994c-.003 5.45-4.437 9.884-9.885 9.884m8.413-18.297A11.815 11.815 0 0012.05 0C5.495 0 .16 5.335.157 11.892c0 2.096.547 4.142 1.588 5.945L.057 24l6.305-1.654a11.882 11.882 0 005.683 1.448h.005c6.554 0 11.89-5.335 11.893-11.893a11.821 11.821 0 00-3.48-8.413z" }) })
|
|
987
|
+
}
|
|
988
|
+
)
|
|
989
|
+
] });
|
|
990
|
+
},
|
|
991
|
+
GOOGLE_CONTACT: ({ value, column, rowId, onChange, context }) => {
|
|
992
|
+
const [isSyncing, setIsSyncing] = import_react5.default.useState(false);
|
|
993
|
+
const { addToast } = useToast();
|
|
994
|
+
const googleClientIdRef = import_react5.default.useRef(null);
|
|
995
|
+
const ensureGisScript = import_react5.default.useCallback(() => {
|
|
996
|
+
return new Promise((resolve, reject) => {
|
|
997
|
+
var _a, _b, _c;
|
|
998
|
+
if ((_c = (_b = (_a = window.google) == null ? void 0 : _a.accounts) == null ? void 0 : _b.oauth2) == null ? void 0 : _c.initTokenClient) {
|
|
999
|
+
resolve();
|
|
1000
|
+
return;
|
|
1001
|
+
}
|
|
1002
|
+
if (document.querySelector('script[src*="accounts.google.com/gsi/client"]')) {
|
|
1003
|
+
const waitForLoad = setInterval(() => {
|
|
1004
|
+
var _a2, _b2, _c2;
|
|
1005
|
+
if ((_c2 = (_b2 = (_a2 = window.google) == null ? void 0 : _a2.accounts) == null ? void 0 : _b2.oauth2) == null ? void 0 : _c2.initTokenClient) {
|
|
1006
|
+
clearInterval(waitForLoad);
|
|
1007
|
+
resolve();
|
|
1008
|
+
}
|
|
1009
|
+
}, 100);
|
|
1010
|
+
setTimeout(() => {
|
|
1011
|
+
clearInterval(waitForLoad);
|
|
1012
|
+
reject(new Error("GIS script load timeout"));
|
|
1013
|
+
}, 1e4);
|
|
1014
|
+
return;
|
|
1015
|
+
}
|
|
1016
|
+
const script = document.createElement("script");
|
|
1017
|
+
script.src = "https://accounts.google.com/gsi/client";
|
|
1018
|
+
script.async = true;
|
|
1019
|
+
script.onload = () => resolve();
|
|
1020
|
+
script.onerror = () => reject(new Error("Failed to load Google Identity Services"));
|
|
1021
|
+
document.head.appendChild(script);
|
|
1022
|
+
});
|
|
1023
|
+
}, []);
|
|
1024
|
+
const requestGisToken = import_react5.default.useCallback(async (hint) => {
|
|
1025
|
+
await ensureGisScript();
|
|
1026
|
+
if (!googleClientIdRef.current && (context == null ? void 0 : context.executeAction)) {
|
|
1027
|
+
try {
|
|
1028
|
+
const config = await context.executeAction("GET_GOOGLE_CONFIG", {});
|
|
1029
|
+
googleClientIdRef.current = (config == null ? void 0 : config.clientId) || "";
|
|
1030
|
+
} catch (e) {
|
|
1031
|
+
throw new Error("Failed to fetch Google configuration");
|
|
1032
|
+
}
|
|
1033
|
+
}
|
|
1034
|
+
const clientId = googleClientIdRef.current;
|
|
1035
|
+
if (!clientId) {
|
|
1036
|
+
throw new Error("Google Client ID is not configured");
|
|
1037
|
+
}
|
|
1038
|
+
const accessToken = await new Promise((resolve, reject) => {
|
|
1039
|
+
const tokenClient = window.google.accounts.oauth2.initTokenClient({
|
|
1040
|
+
client_id: clientId,
|
|
1041
|
+
scope: "https://www.googleapis.com/auth/contacts https://www.googleapis.com/auth/userinfo.email",
|
|
1042
|
+
prompt: hint ? "" : "select_account",
|
|
1043
|
+
hint: hint || void 0,
|
|
1044
|
+
callback: (tokenResponse) => {
|
|
1045
|
+
if (tokenResponse == null ? void 0 : tokenResponse.access_token) {
|
|
1046
|
+
resolve(tokenResponse.access_token);
|
|
1047
|
+
} else {
|
|
1048
|
+
reject(new Error("Google authorization was cancelled or failed"));
|
|
1049
|
+
}
|
|
1050
|
+
},
|
|
1051
|
+
error_callback: (err) => {
|
|
1052
|
+
reject(new Error((err == null ? void 0 : err.message) || "Google authorization error"));
|
|
1053
|
+
}
|
|
1054
|
+
});
|
|
1055
|
+
tokenClient.requestAccessToken({ hint: hint || void 0 });
|
|
1056
|
+
});
|
|
1057
|
+
let email = "";
|
|
1058
|
+
try {
|
|
1059
|
+
const res = await fetch("https://www.googleapis.com/oauth2/v3/userinfo", {
|
|
1060
|
+
headers: { Authorization: `Bearer ${accessToken}` }
|
|
1061
|
+
});
|
|
1062
|
+
if (res.ok) {
|
|
1063
|
+
const info = await res.json();
|
|
1064
|
+
email = info.email || "";
|
|
1065
|
+
}
|
|
1066
|
+
} catch (e) {
|
|
1067
|
+
}
|
|
1068
|
+
return { accessToken, email };
|
|
1069
|
+
}, [ensureGisScript, context]);
|
|
1070
|
+
const handleSync = async () => {
|
|
1071
|
+
var _a, _b, _c;
|
|
1072
|
+
if (!(context == null ? void 0 : context.executeAction)) return;
|
|
1073
|
+
setIsSyncing(true);
|
|
1074
|
+
try {
|
|
1075
|
+
const mapping = column.contactMapping || {};
|
|
1076
|
+
const rowData = context.rowData || {};
|
|
1077
|
+
let hasPhone = false;
|
|
1078
|
+
if (mapping.phoneCol && rowData[mapping.phoneCol]) hasPhone = true;
|
|
1079
|
+
let hasName = false;
|
|
1080
|
+
if (mapping.nameParts && Array.isArray(mapping.nameParts)) {
|
|
1081
|
+
for (const part of mapping.nameParts) {
|
|
1082
|
+
if (part.type === "LOCAL" && rowData[part.columnId]) hasName = true;
|
|
1083
|
+
if (part.type === "PARENT" && ((_a = context.parentRecord) == null ? void 0 : _a.tableId) === part.parentTableId && ((_c = (_b = context.parentRecord) == null ? void 0 : _b.data) == null ? void 0 : _c[part.columnId])) hasName = true;
|
|
1084
|
+
}
|
|
1085
|
+
}
|
|
1086
|
+
if (!hasPhone) {
|
|
1087
|
+
addToast({ type: "warning", message: "\u05E0\u05D0 \u05DC\u05DE\u05DC\u05D0 \u05DE\u05E1\u05E4\u05E8 \u05D8\u05DC\u05E4\u05D5\u05DF \u05DB\u05D3\u05D9 \u05DC\u05E1\u05E0\u05DB\u05E8\u05DF \u05D0\u05D9\u05E9 \u05E7\u05E9\u05E8 \u05DC\u05D2\u05D5\u05D2\u05DC" });
|
|
1088
|
+
setIsSyncing(false);
|
|
1089
|
+
return;
|
|
1090
|
+
}
|
|
1091
|
+
if (!hasName) {
|
|
1092
|
+
addToast({ type: "warning", message: "\u05E0\u05D0 \u05DC\u05DE\u05DC\u05D0 \u05E9\u05DD \u05DB\u05D3\u05D9 \u05DC\u05E1\u05E0\u05DB\u05E8\u05DF \u05D0\u05D9\u05E9 \u05E7\u05E9\u05E8 \u05DC\u05D2\u05D5\u05D2\u05DC" });
|
|
1093
|
+
setIsSyncing(false);
|
|
1094
|
+
return;
|
|
1095
|
+
}
|
|
1096
|
+
let accessToken;
|
|
1097
|
+
let userEmail = "";
|
|
1098
|
+
try {
|
|
1099
|
+
const gisResult = await requestGisToken();
|
|
1100
|
+
accessToken = gisResult.accessToken;
|
|
1101
|
+
userEmail = gisResult.email;
|
|
1102
|
+
} catch (gisError) {
|
|
1103
|
+
addToast({ type: "warning", message: gisError.message || "\u05D4\u05D4\u05E8\u05E9\u05D0\u05D4 \u05DC\u05D2\u05D5\u05D2\u05DC \u05E0\u05DB\u05E9\u05DC\u05D4" });
|
|
1104
|
+
setIsSyncing(false);
|
|
1105
|
+
return;
|
|
1106
|
+
}
|
|
1107
|
+
const payload = {
|
|
1108
|
+
nameParts: mapping.nameParts || [],
|
|
1109
|
+
phoneCol: mapping.phoneCol,
|
|
1110
|
+
emailCol: mapping.emailCol,
|
|
1111
|
+
localRowData: rowData,
|
|
1112
|
+
parentRecord: context.parentRecord,
|
|
1113
|
+
accessToken,
|
|
1114
|
+
userEmail
|
|
1115
|
+
};
|
|
1116
|
+
const res = await context.executeAction("SYNC_GOOGLE_CONTACT", payload);
|
|
1117
|
+
if (res && res.synced) {
|
|
1118
|
+
if (context.updateQuietly) {
|
|
1119
|
+
context.updateQuietly(rowId, column.name, res);
|
|
1120
|
+
} else {
|
|
1121
|
+
onChange(res);
|
|
1122
|
+
}
|
|
1123
|
+
if (context.tableId && !rowId.startsWith("temp_")) {
|
|
1124
|
+
await context.executeAction("UPDATE_RECORD", {
|
|
1125
|
+
tableId: context.tableId,
|
|
1126
|
+
recordId: rowId,
|
|
1127
|
+
data: { [column.name]: res }
|
|
1128
|
+
});
|
|
1129
|
+
}
|
|
1130
|
+
}
|
|
1131
|
+
} catch (error) {
|
|
1132
|
+
console.error("Failed to sync contact:", error);
|
|
1133
|
+
addToast({ type: "warning", message: "\u05E9\u05D2\u05D9\u05D0\u05D4 \u05D1\u05E1\u05E0\u05DB\u05E8\u05D5\u05DF \u05D0\u05D9\u05E9 \u05E7\u05E9\u05E8: " + error.message });
|
|
1134
|
+
} finally {
|
|
1135
|
+
setIsSyncing(false);
|
|
1136
|
+
}
|
|
1137
|
+
};
|
|
1138
|
+
const handleUnlink = async () => {
|
|
1139
|
+
let accessToken;
|
|
1140
|
+
try {
|
|
1141
|
+
let emailHint = value == null ? void 0 : value.userEmail;
|
|
1142
|
+
if (!emailHint && (value == null ? void 0 : value.url)) {
|
|
1143
|
+
try {
|
|
1144
|
+
const parsed = new URL(value.url);
|
|
1145
|
+
emailHint = parsed.searchParams.get("authuser") || void 0;
|
|
1146
|
+
} catch (e) {
|
|
1147
|
+
}
|
|
1148
|
+
}
|
|
1149
|
+
const auth = await requestGisToken(emailHint);
|
|
1150
|
+
accessToken = auth.accessToken;
|
|
1151
|
+
} catch (err) {
|
|
1152
|
+
console.warn("[handleUnlink] Could not obtain token via GIS, falling back to server default token:", err);
|
|
1153
|
+
}
|
|
1154
|
+
if ((value == null ? void 0 : value.resourceName) && (context == null ? void 0 : context.executeAction)) {
|
|
1155
|
+
await context.executeAction("DELETE_GOOGLE_CONTACT", {
|
|
1156
|
+
resourceName: value.resourceName,
|
|
1157
|
+
accessToken
|
|
1158
|
+
});
|
|
1159
|
+
}
|
|
1160
|
+
if (context == null ? void 0 : context.updateQuietly) {
|
|
1161
|
+
context.updateQuietly(rowId, column.name, null);
|
|
1162
|
+
} else {
|
|
1163
|
+
onChange(null);
|
|
1164
|
+
}
|
|
1165
|
+
if ((context == null ? void 0 : context.tableId) && (context == null ? void 0 : context.executeAction) && !rowId.startsWith("temp_")) {
|
|
1166
|
+
await context.executeAction("UPDATE_RECORD", {
|
|
1167
|
+
tableId: context.tableId,
|
|
1168
|
+
recordId: rowId,
|
|
1169
|
+
data: { [column.name]: null }
|
|
1170
|
+
});
|
|
1171
|
+
}
|
|
1172
|
+
};
|
|
1173
|
+
if (value && value.synced && value.url) {
|
|
1174
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "flex items-center gap-1.5 h-8 px-2 group whitespace-nowrap", children: [
|
|
1175
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("a", { href: value.url, target: "_blank", rel: "noopener noreferrer", className: "text-blue-600 hover:underline flex-1 truncate text-xs whitespace-nowrap", children: "\u05D0\u05D9\u05E9 \u05E7\u05E9\u05E8 \u05D2\u05D5\u05D2\u05DC" }),
|
|
1176
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1177
|
+
"button",
|
|
1178
|
+
{
|
|
1179
|
+
type: "button",
|
|
1180
|
+
onClick: handleUnlink,
|
|
1181
|
+
className: "text-slate-400 hover:text-rose-500 opacity-0 group-hover:opacity-100 transition-opacity p-1 shrink-0",
|
|
1182
|
+
title: "\u05D1\u05D8\u05DC \u05E1\u05E0\u05DB\u05E8\u05D5\u05DF",
|
|
1183
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { className: "w-3.5 h-3.5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M6 18L18 6M6 6l12 12" }) })
|
|
1184
|
+
}
|
|
1185
|
+
)
|
|
1186
|
+
] });
|
|
1187
|
+
}
|
|
1188
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "flex items-center h-8 px-2 whitespace-nowrap", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
1189
|
+
"button",
|
|
1190
|
+
{
|
|
1191
|
+
type: "button",
|
|
1192
|
+
onClick: handleSync,
|
|
1193
|
+
disabled: isSyncing,
|
|
1194
|
+
className: "inline-flex items-center gap-1.5 px-2.5 py-1 bg-blue-50 text-blue-600 hover:bg-blue-100 border border-blue-200 rounded-md text-xs font-medium transition-colors whitespace-nowrap shrink-0 disabled:opacity-50 cursor-pointer",
|
|
1195
|
+
children: [
|
|
1196
|
+
isSyncing ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("svg", { className: "w-3.5 h-3.5 animate-spin shrink-0", viewBox: "0 0 24 24", fill: "none", children: [
|
|
1197
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("circle", { className: "opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4" }),
|
|
1198
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { className: "opacity-75", fill: "currentColor", d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z" })
|
|
1199
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { className: "w-3.5 h-3.5 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M12 4v16m8-8H4" }) }),
|
|
1200
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "whitespace-nowrap", children: "\u05E1\u05E0\u05DB\u05E8\u05DF \u05DC\u05D2\u05D5\u05D2\u05DC" })
|
|
1201
|
+
]
|
|
1202
|
+
}
|
|
1203
|
+
) });
|
|
1204
|
+
},
|
|
896
1205
|
DEFAULT: ({ value, onChange }) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
897
1206
|
"input",
|
|
898
1207
|
{
|
|
@@ -901,12 +1210,1045 @@ var FORM_INPUTS = {
|
|
|
901
1210
|
value: value !== void 0 && value !== null ? String(value) : "",
|
|
902
1211
|
onChange: (e) => onChange(e.target.value)
|
|
903
1212
|
}
|
|
904
|
-
)
|
|
1213
|
+
),
|
|
1214
|
+
SUB_TABLE: ({ value, column }) => {
|
|
1215
|
+
var _a, _b;
|
|
1216
|
+
if (!Array.isArray(value)) return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "px-2 py-1 flex items-center h-full text-slate-300 text-xs italic", children: "\u05E8\u05D9\u05E7" });
|
|
1217
|
+
const selected = value.filter((e) => e == null ? void 0 : e.isSelected);
|
|
1218
|
+
if (selected.length === 0) return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "px-2 py-1 flex items-center h-full text-slate-300 text-xs italic", children: "\u05E8\u05D9\u05E7" });
|
|
1219
|
+
const displayFields = column.subTableDisplayFields || [];
|
|
1220
|
+
const isWhatsApp = ((_a = column.config) == null ? void 0 : _a.actionType) === "WHATSAPP";
|
|
1221
|
+
const actionPhoneCol = (_b = column.config) == null ? void 0 : _b.actionPhoneColumn;
|
|
1222
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "px-1.5 py-1 flex flex-wrap items-center gap-1 h-full", children: selected.map((entry, idx) => {
|
|
1223
|
+
var _a2, _b2;
|
|
1224
|
+
let label = "";
|
|
1225
|
+
if (entry._resolvedData) {
|
|
1226
|
+
if (displayFields.length > 0) {
|
|
1227
|
+
label = displayFields.map((f) => String(entry._resolvedData[f] || "")).filter(Boolean).join(" ");
|
|
1228
|
+
} else {
|
|
1229
|
+
const firstField = Object.keys(entry._resolvedData).find((k) => k !== "_id");
|
|
1230
|
+
if (firstField) label = String(entry._resolvedData[firstField] || "");
|
|
1231
|
+
}
|
|
1232
|
+
}
|
|
1233
|
+
if (!label) label = ((_a2 = entry.recordId) == null ? void 0 : _a2.slice(-6)) || "...";
|
|
1234
|
+
if (isWhatsApp) {
|
|
1235
|
+
const rawPhone = actionPhoneCol ? (_b2 = entry._resolvedData) == null ? void 0 : _b2[actionPhoneCol] : null;
|
|
1236
|
+
const phone = rawPhone ? String(rawPhone).trim() : null;
|
|
1237
|
+
if (phone) {
|
|
1238
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
1239
|
+
"button",
|
|
1240
|
+
{
|
|
1241
|
+
type: "button",
|
|
1242
|
+
onClick: (e) => {
|
|
1243
|
+
e.stopPropagation();
|
|
1244
|
+
openWhatsAppChat(phone);
|
|
1245
|
+
},
|
|
1246
|
+
className: "inline-flex items-center gap-1 px-1.5 py-0.5 bg-emerald-50 hover:bg-emerald-100 text-emerald-800 border border-emerald-300 hover:border-emerald-400 rounded-full text-xs font-medium max-w-[150px] truncate cursor-pointer transition-colors shadow-xs",
|
|
1247
|
+
title: `\u05E4\u05EA\u05D9\u05D7\u05EA \u05D5\u05D5\u05D0\u05D8\u05E1\u05D0\u05E4 (${phone})`,
|
|
1248
|
+
children: [
|
|
1249
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { className: "w-3 h-3 text-emerald-600 shrink-0", fill: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M17.472 14.382c-.297-.149-1.758-.867-2.03-.967-.273-.099-.471-.148-.67.15-.197.297-.767.966-.94 1.164-.173.199-.347.223-.644.075-.297-.15-1.255-.463-2.39-1.475-.883-.788-1.48-1.761-1.653-2.059-.173-.297-.018-.458.13-.606.134-.133.298-.347.446-.52.149-.174.198-.298.298-.497.099-.198.05-.371-.025-.52-.075-.149-.669-1.612-.916-2.207-.242-.579-.487-.5-.669-.51a5.816 5.816 0 00-.571-.01c-.198 0-.52.074-.792.372-.272.297-1.04 1.016-1.04 2.479 0 1.462 1.065 2.875 1.213 3.074.149.198 2.096 3.2 5.077 4.487.709.306 1.262.489 1.694.625.712.227 1.36.195 1.871.118.571-.085 1.758-.719 2.006-1.413.248-.694.248-1.289.173-1.413-.074-.124-.272-.198-.57-.347m-5.421 7.403h-.004a9.87 9.87 0 01-5.031-1.378l-.361-.214-3.741.982.998-3.648-.235-.374a9.86 9.86 0 01-1.51-5.26c.001-5.45 4.436-9.884 9.888-9.884 2.64 0 5.122 1.03 6.988 2.898a9.825 9.825 0 012.893 6.994c-.003 5.45-4.437 9.884-9.885 9.884m8.413-18.297A11.815 11.815 0 0012.05 0C5.495 0 .16 5.335.157 11.892c0 2.096.547 4.142 1.588 5.945L.057 24l6.305-1.654a11.882 11.882 0 005.683 1.448h.005c6.554 0 11.89-5.335 11.893-11.893a11.821 11.821 0 00-3.48-8.413z" }) }),
|
|
1250
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "truncate", children: label })
|
|
1251
|
+
]
|
|
1252
|
+
},
|
|
1253
|
+
entry.recordId || idx
|
|
1254
|
+
);
|
|
1255
|
+
}
|
|
1256
|
+
}
|
|
1257
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1258
|
+
"span",
|
|
1259
|
+
{
|
|
1260
|
+
className: "inline-flex items-center px-1.5 py-0.5 bg-amber-50 text-amber-800 border border-amber-200 rounded-full text-xs font-medium max-w-[140px] truncate",
|
|
1261
|
+
title: label,
|
|
1262
|
+
children: label
|
|
1263
|
+
},
|
|
1264
|
+
entry.recordId || idx
|
|
1265
|
+
);
|
|
1266
|
+
}) });
|
|
1267
|
+
}
|
|
905
1268
|
};
|
|
906
1269
|
|
|
1270
|
+
// src/components/TableBlock/fields/SubTableViewer.tsx
|
|
1271
|
+
var import_react6 = require("react");
|
|
1272
|
+
|
|
1273
|
+
// src/utils/phone.ts
|
|
1274
|
+
function sanitizePhoneNumber(phone) {
|
|
1275
|
+
if (!phone) return "";
|
|
1276
|
+
const trimmed = phone.trim();
|
|
1277
|
+
const hasLeadingPlus = trimmed.startsWith("+");
|
|
1278
|
+
const digitsOnly = trimmed.replace(/\D/g, "");
|
|
1279
|
+
return hasLeadingPlus ? `+${digitsOnly}` : digitsOnly;
|
|
1280
|
+
}
|
|
1281
|
+
function isValidPhoneNumber(phone) {
|
|
1282
|
+
if (!phone) return false;
|
|
1283
|
+
const cleaned = sanitizePhoneNumber(phone);
|
|
1284
|
+
return /^\+?[0-9]{9,15}$/.test(cleaned);
|
|
1285
|
+
}
|
|
1286
|
+
|
|
1287
|
+
// src/components/TableBlock/fields/SubTableViewer.tsx
|
|
1288
|
+
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
1289
|
+
function validateCellValue(val, col) {
|
|
1290
|
+
var _a;
|
|
1291
|
+
const colType = ((_a = col.type) == null ? void 0 : _a.toUpperCase()) || "DEFAULT";
|
|
1292
|
+
const isEmpty = val === void 0 || val === null || typeof val === "string" && val.trim() === "";
|
|
1293
|
+
if (col.isRequired && isEmpty) {
|
|
1294
|
+
return {
|
|
1295
|
+
isValid: false,
|
|
1296
|
+
error: `\u05E9\u05D2\u05D9\u05D0\u05EA \u05D0\u05D9\u05DE\u05D5\u05EA: \u05E9\u05D3\u05D4 '${col.name}' \u05D4\u05D9\u05E0\u05D5 \u05E9\u05D3\u05D4 \u05D7\u05D5\u05D1\u05D4 \u05D5\u05DC\u05D0 \u05D9\u05DB\u05D5\u05DC \u05DC\u05D4\u05D9\u05E9\u05D0\u05E8 \u05E8\u05D9\u05E7.`
|
|
1297
|
+
};
|
|
1298
|
+
}
|
|
1299
|
+
if (isEmpty) {
|
|
1300
|
+
return { isValid: true };
|
|
1301
|
+
}
|
|
1302
|
+
if (colType === "PHONE") {
|
|
1303
|
+
const strVal = String(val).trim();
|
|
1304
|
+
if (!isValidPhoneNumber(strVal)) {
|
|
1305
|
+
return {
|
|
1306
|
+
isValid: false,
|
|
1307
|
+
error: `\u05DE\u05E1\u05E4\u05E8 \u05D4\u05D8\u05DC\u05E4\u05D5\u05DF \u05D1\u05E9\u05D3\u05D4 '${col.name}' \u05D0\u05D9\u05E0\u05D5 \u05EA\u05E7\u05D9\u05DF. \u05D9\u05E9 \u05DC\u05D4\u05D6\u05D9\u05DF \u05DE\u05E1\u05E4\u05E8 \u05D1\u05D0\u05D5\u05E8\u05DA 9-15 \u05E1\u05E4\u05E8\u05D5\u05EA (\u05DC\u05D3\u05D5\u05D2\u05DE\u05D4 0501234567 \u05D0\u05D5 +972501234567).`
|
|
1308
|
+
};
|
|
1309
|
+
}
|
|
1310
|
+
}
|
|
1311
|
+
if (colType === "NUMBER" || colType === "CURRENCY") {
|
|
1312
|
+
if (typeof val === "string" && isNaN(Number(val))) {
|
|
1313
|
+
return {
|
|
1314
|
+
isValid: false,
|
|
1315
|
+
error: `\u05D4\u05E2\u05E8\u05DA \u05D1\u05E9\u05D3\u05D4 '${col.name}' \u05D7\u05D9\u05D9\u05D1 \u05DC\u05D4\u05D9\u05D5\u05EA \u05DE\u05E1\u05E4\u05E8 \u05EA\u05E7\u05D9\u05DF.`
|
|
1316
|
+
};
|
|
1317
|
+
}
|
|
1318
|
+
}
|
|
1319
|
+
return { isValid: true };
|
|
1320
|
+
}
|
|
1321
|
+
function SubTableCell({
|
|
1322
|
+
record,
|
|
1323
|
+
column,
|
|
1324
|
+
targetSchema,
|
|
1325
|
+
referencedTableId,
|
|
1326
|
+
context,
|
|
1327
|
+
relationOptions,
|
|
1328
|
+
setRelationOptions,
|
|
1329
|
+
refetchRelation,
|
|
1330
|
+
onCommit
|
|
1331
|
+
}) {
|
|
1332
|
+
var _a, _b;
|
|
1333
|
+
const colType = ((_a = column.type) == null ? void 0 : _a.toUpperCase()) || "DEFAULT";
|
|
1334
|
+
const isContact = colType === "GOOGLE_CONTACT";
|
|
1335
|
+
const InputComponent = FORM_INPUTS[colType] || FORM_INPUTS.DEFAULT;
|
|
1336
|
+
const serverValue = (_b = record.data[column.name]) != null ? _b : colType === "BOOLEAN" ? false : "";
|
|
1337
|
+
const [draftValue, setDraftValue] = (0, import_react6.useState)(serverValue);
|
|
1338
|
+
const [isDirty, setIsDirty] = (0, import_react6.useState)(false);
|
|
1339
|
+
const [validationError, setValidationError] = (0, import_react6.useState)(null);
|
|
1340
|
+
const cellRef = (0, import_react6.useRef)(null);
|
|
1341
|
+
const draftRef = (0, import_react6.useRef)(draftValue);
|
|
1342
|
+
const isDirtyRef = (0, import_react6.useRef)(isDirty);
|
|
1343
|
+
const serverValueRef = (0, import_react6.useRef)(serverValue);
|
|
1344
|
+
const recordIdRef = (0, import_react6.useRef)(record.id);
|
|
1345
|
+
const columnRef = (0, import_react6.useRef)(column);
|
|
1346
|
+
const onCommitRef = (0, import_react6.useRef)(onCommit);
|
|
1347
|
+
const isCommittingRef = (0, import_react6.useRef)(false);
|
|
1348
|
+
const lastFailedValRef = (0, import_react6.useRef)(void 0);
|
|
1349
|
+
const { addToast } = useToast();
|
|
1350
|
+
draftRef.current = draftValue;
|
|
1351
|
+
isDirtyRef.current = isDirty;
|
|
1352
|
+
serverValueRef.current = serverValue;
|
|
1353
|
+
recordIdRef.current = record.id;
|
|
1354
|
+
columnRef.current = column;
|
|
1355
|
+
onCommitRef.current = onCommit;
|
|
1356
|
+
(0, import_react6.useEffect)(() => {
|
|
1357
|
+
if (!isDirtyRef.current) {
|
|
1358
|
+
setDraftValue(serverValue);
|
|
1359
|
+
draftRef.current = serverValue;
|
|
1360
|
+
setValidationError(null);
|
|
1361
|
+
lastFailedValRef.current = void 0;
|
|
1362
|
+
}
|
|
1363
|
+
}, [serverValue]);
|
|
1364
|
+
const commit = (0, import_react6.useCallback)(async (valToCommit) => {
|
|
1365
|
+
if (isCommittingRef.current) return false;
|
|
1366
|
+
if (!isDirtyRef.current) return true;
|
|
1367
|
+
if (valToCommit === serverValueRef.current) {
|
|
1368
|
+
setIsDirty(false);
|
|
1369
|
+
isDirtyRef.current = false;
|
|
1370
|
+
setValidationError(null);
|
|
1371
|
+
lastFailedValRef.current = void 0;
|
|
1372
|
+
return true;
|
|
1373
|
+
}
|
|
1374
|
+
const valRes = validateCellValue(valToCommit, columnRef.current);
|
|
1375
|
+
if (!valRes.isValid) {
|
|
1376
|
+
const errorMsg = valRes.error || "\u05E9\u05D2\u05D9\u05D0\u05EA \u05D0\u05D9\u05DE\u05D5\u05EA";
|
|
1377
|
+
setValidationError(errorMsg);
|
|
1378
|
+
if (lastFailedValRef.current !== valToCommit) {
|
|
1379
|
+
addToast({ type: "error", message: errorMsg });
|
|
1380
|
+
lastFailedValRef.current = valToCommit;
|
|
1381
|
+
}
|
|
1382
|
+
return false;
|
|
1383
|
+
}
|
|
1384
|
+
try {
|
|
1385
|
+
isCommittingRef.current = true;
|
|
1386
|
+
const success = await onCommitRef.current(recordIdRef.current, columnRef.current.name, valToCommit);
|
|
1387
|
+
if (success) {
|
|
1388
|
+
setIsDirty(false);
|
|
1389
|
+
isDirtyRef.current = false;
|
|
1390
|
+
serverValueRef.current = valToCommit;
|
|
1391
|
+
setValidationError(null);
|
|
1392
|
+
lastFailedValRef.current = void 0;
|
|
1393
|
+
return true;
|
|
1394
|
+
} else {
|
|
1395
|
+
setValidationError("\u05E9\u05D2\u05D9\u05D0\u05D4 \u05D1\u05E9\u05DE\u05D9\u05E8\u05EA \u05D4\u05E8\u05E9\u05D5\u05DE\u05D4");
|
|
1396
|
+
return false;
|
|
1397
|
+
}
|
|
1398
|
+
} catch (e) {
|
|
1399
|
+
setValidationError("\u05E9\u05D2\u05D9\u05D0\u05D4 \u05D1\u05E9\u05DE\u05D9\u05E8\u05EA \u05D4\u05E8\u05E9\u05D5\u05DE\u05D4");
|
|
1400
|
+
return false;
|
|
1401
|
+
} finally {
|
|
1402
|
+
isCommittingRef.current = false;
|
|
1403
|
+
}
|
|
1404
|
+
}, [addToast]);
|
|
1405
|
+
const discard = (0, import_react6.useCallback)(() => {
|
|
1406
|
+
setDraftValue(serverValueRef.current);
|
|
1407
|
+
draftRef.current = serverValueRef.current;
|
|
1408
|
+
setIsDirty(false);
|
|
1409
|
+
isDirtyRef.current = false;
|
|
1410
|
+
setValidationError(null);
|
|
1411
|
+
lastFailedValRef.current = void 0;
|
|
1412
|
+
}, []);
|
|
1413
|
+
(0, import_react6.useEffect)(() => {
|
|
1414
|
+
return () => {
|
|
1415
|
+
if (isDirtyRef.current && !isCommittingRef.current) {
|
|
1416
|
+
const val = draftRef.current;
|
|
1417
|
+
const orig = serverValueRef.current;
|
|
1418
|
+
if (val !== orig) {
|
|
1419
|
+
const valRes = validateCellValue(val, columnRef.current);
|
|
1420
|
+
if (valRes.isValid) {
|
|
1421
|
+
onCommitRef.current(recordIdRef.current, columnRef.current.name, val);
|
|
1422
|
+
}
|
|
1423
|
+
}
|
|
1424
|
+
}
|
|
1425
|
+
};
|
|
1426
|
+
}, []);
|
|
1427
|
+
const handleChange = (newVal) => {
|
|
1428
|
+
setDraftValue(newVal);
|
|
1429
|
+
draftRef.current = newVal;
|
|
1430
|
+
setIsDirty(true);
|
|
1431
|
+
isDirtyRef.current = true;
|
|
1432
|
+
if (validationError) {
|
|
1433
|
+
setValidationError(null);
|
|
1434
|
+
lastFailedValRef.current = void 0;
|
|
1435
|
+
}
|
|
1436
|
+
if (colType === "BOOLEAN" || colType === "GOOGLE_DRIVE_FILE") {
|
|
1437
|
+
commit(newVal);
|
|
1438
|
+
}
|
|
1439
|
+
};
|
|
1440
|
+
const handleBlur = (e) => {
|
|
1441
|
+
if (e.currentTarget.contains(e.relatedTarget)) {
|
|
1442
|
+
return;
|
|
1443
|
+
}
|
|
1444
|
+
if (isDirtyRef.current) {
|
|
1445
|
+
commit(draftRef.current);
|
|
1446
|
+
}
|
|
1447
|
+
};
|
|
1448
|
+
const handleKeyDown = (e) => {
|
|
1449
|
+
var _a2, _b2, _c, _d;
|
|
1450
|
+
if (e.key === "Enter") {
|
|
1451
|
+
e.preventDefault();
|
|
1452
|
+
if (isDirtyRef.current) {
|
|
1453
|
+
commit(draftRef.current);
|
|
1454
|
+
}
|
|
1455
|
+
(_b2 = (_a2 = e.target) == null ? void 0 : _a2.blur) == null ? void 0 : _b2.call(_a2);
|
|
1456
|
+
} else if (e.key === "Escape") {
|
|
1457
|
+
e.preventDefault();
|
|
1458
|
+
discard();
|
|
1459
|
+
(_d = (_c = e.target) == null ? void 0 : _c.blur) == null ? void 0 : _d.call(_c);
|
|
1460
|
+
}
|
|
1461
|
+
};
|
|
1462
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1463
|
+
"td",
|
|
1464
|
+
{
|
|
1465
|
+
ref: cellRef,
|
|
1466
|
+
onBlur: handleBlur,
|
|
1467
|
+
onKeyDown: handleKeyDown,
|
|
1468
|
+
title: validationError || void 0,
|
|
1469
|
+
className: `border border-slate-200 p-0 relative h-8 transition-colors ${isContact ? "min-w-[140px]" : ""} ${validationError ? "border-rose-400 ring-1 ring-rose-400 bg-rose-50/20" : ""}`,
|
|
1470
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1471
|
+
InputComponent,
|
|
1472
|
+
{
|
|
1473
|
+
value: draftValue,
|
|
1474
|
+
column,
|
|
1475
|
+
rowId: record.id,
|
|
1476
|
+
onChange: handleChange,
|
|
1477
|
+
context: __spreadProps(__spreadValues({}, context), {
|
|
1478
|
+
tableName: (targetSchema == null ? void 0 : targetSchema.name) || (targetSchema == null ? void 0 : targetSchema.tableName) || (targetSchema == null ? void 0 : targetSchema.title) || (targetSchema == null ? void 0 : targetSchema.id) || "Table",
|
|
1479
|
+
relationOptions,
|
|
1480
|
+
updateRelationOptions: (name, opts) => setRelationOptions((prev) => __spreadProps(__spreadValues({}, prev), { [name]: opts })),
|
|
1481
|
+
refetchRelation,
|
|
1482
|
+
parentRecord: { tableId: (context == null ? void 0 : context.parentTableId) || (context == null ? void 0 : context.tableId), data: context == null ? void 0 : context.rowData },
|
|
1483
|
+
rowData: record.data,
|
|
1484
|
+
tableId: (targetSchema == null ? void 0 : targetSchema.tableMetaId) || (targetSchema == null ? void 0 : targetSchema.id) || referencedTableId,
|
|
1485
|
+
updateQuietly: (rid, colName, val) => onCommitRef.current(rid, colName, val)
|
|
1486
|
+
})
|
|
1487
|
+
}
|
|
1488
|
+
)
|
|
1489
|
+
}
|
|
1490
|
+
);
|
|
1491
|
+
}
|
|
1492
|
+
function SubTableViewer({ rowId, column, value, onChange, context }) {
|
|
1493
|
+
var _a, _b;
|
|
1494
|
+
const { addToast } = useToast();
|
|
1495
|
+
const entries = Array.isArray(value) ? value : [];
|
|
1496
|
+
const [linkedRecords, setLinkedRecords] = (0, import_react6.useState)(() => {
|
|
1497
|
+
const initial = [];
|
|
1498
|
+
if (Array.isArray(value)) {
|
|
1499
|
+
for (const entry of value) {
|
|
1500
|
+
if (entry.recordId && entry._resolvedData) {
|
|
1501
|
+
initial.push({ id: entry.recordId, data: entry._resolvedData });
|
|
1502
|
+
}
|
|
1503
|
+
}
|
|
1504
|
+
}
|
|
1505
|
+
return initial;
|
|
1506
|
+
});
|
|
1507
|
+
const [targetSchema, setTargetSchema] = (0, import_react6.useState)(null);
|
|
1508
|
+
const [isLoading, setIsLoading] = (0, import_react6.useState)(true);
|
|
1509
|
+
const [isSearchOpen, setIsSearchOpen] = (0, import_react6.useState)(false);
|
|
1510
|
+
const [searchQuery, setSearchQuery] = (0, import_react6.useState)("");
|
|
1511
|
+
const [searchResults, setSearchResults] = (0, import_react6.useState)([]);
|
|
1512
|
+
const [isSearching, setIsSearching] = (0, import_react6.useState)(false);
|
|
1513
|
+
const [isCreating, setIsCreating] = (0, import_react6.useState)(false);
|
|
1514
|
+
const [newRecordData, setNewRecordData] = (0, import_react6.useState)({});
|
|
1515
|
+
const [conflictModalState, setConflictModalState] = (0, import_react6.useState)({
|
|
1516
|
+
isOpen: false,
|
|
1517
|
+
fieldName: "",
|
|
1518
|
+
matchingRecords: []
|
|
1519
|
+
});
|
|
1520
|
+
const searchRef = (0, import_react6.useRef)(null);
|
|
1521
|
+
const searchTimerRef = (0, import_react6.useRef)(null);
|
|
1522
|
+
const executeAction = context == null ? void 0 : context.executeAction;
|
|
1523
|
+
const referencedTableId = column.referencedTableId;
|
|
1524
|
+
const fetchedIdsRef = (0, import_react6.useRef)(/* @__PURE__ */ new Set());
|
|
1525
|
+
(0, import_react6.useEffect)(() => {
|
|
1526
|
+
if (entries.length > 0) {
|
|
1527
|
+
setLinkedRecords((prev) => {
|
|
1528
|
+
const existingIds = new Set(prev.map((r) => r.id));
|
|
1529
|
+
const toAdd = [];
|
|
1530
|
+
for (const entry of entries) {
|
|
1531
|
+
if (entry.recordId && entry._resolvedData && !existingIds.has(entry.recordId)) {
|
|
1532
|
+
toAdd.push({ id: entry.recordId, data: entry._resolvedData });
|
|
1533
|
+
existingIds.add(entry.recordId);
|
|
1534
|
+
}
|
|
1535
|
+
}
|
|
1536
|
+
return toAdd.length > 0 ? [...prev, ...toAdd] : prev;
|
|
1537
|
+
});
|
|
1538
|
+
}
|
|
1539
|
+
}, [entries]);
|
|
1540
|
+
(0, import_react6.useEffect)(() => {
|
|
1541
|
+
if (!referencedTableId || !executeAction) {
|
|
1542
|
+
setIsLoading(false);
|
|
1543
|
+
return;
|
|
1544
|
+
}
|
|
1545
|
+
const recordIdsToFetch = entries.map((e) => e.recordId).filter((id) => !fetchedIdsRef.current.has(id));
|
|
1546
|
+
if (recordIdsToFetch.length === 0 && targetSchema) return;
|
|
1547
|
+
if (recordIdsToFetch.length > 0) {
|
|
1548
|
+
recordIdsToFetch.forEach((id) => fetchedIdsRef.current.add(id));
|
|
1549
|
+
}
|
|
1550
|
+
setIsLoading(true);
|
|
1551
|
+
executeAction("FETCH_SUB_TABLE_RECORDS", { referencedTableId, recordIds: recordIdsToFetch }).then((res) => {
|
|
1552
|
+
const payload = (res == null ? void 0 : res.data) || res;
|
|
1553
|
+
if (payload == null ? void 0 : payload.records) {
|
|
1554
|
+
setLinkedRecords((prev) => {
|
|
1555
|
+
const map = new Map(prev.map((r) => [r.id, r]));
|
|
1556
|
+
payload.records.forEach((r) => map.set(r.id, r));
|
|
1557
|
+
return Array.from(map.values());
|
|
1558
|
+
});
|
|
1559
|
+
}
|
|
1560
|
+
if (payload == null ? void 0 : payload.schema) {
|
|
1561
|
+
setTargetSchema(payload.schema);
|
|
1562
|
+
}
|
|
1563
|
+
}).catch(() => {
|
|
1564
|
+
recordIdsToFetch.forEach((id) => fetchedIdsRef.current.delete(id));
|
|
1565
|
+
}).finally(() => setIsLoading(false));
|
|
1566
|
+
}, [referencedTableId, executeAction, entries, targetSchema]);
|
|
1567
|
+
(0, import_react6.useEffect)(() => {
|
|
1568
|
+
const handleClick = (e) => {
|
|
1569
|
+
if (searchRef.current && !searchRef.current.contains(e.target)) {
|
|
1570
|
+
setIsSearchOpen(false);
|
|
1571
|
+
}
|
|
1572
|
+
};
|
|
1573
|
+
if (isSearchOpen) document.addEventListener("mousedown", handleClick);
|
|
1574
|
+
return () => document.removeEventListener("mousedown", handleClick);
|
|
1575
|
+
}, [isSearchOpen]);
|
|
1576
|
+
const handleSearch = (0, import_react6.useCallback)((query) => {
|
|
1577
|
+
setSearchQuery(query);
|
|
1578
|
+
if (searchTimerRef.current) clearTimeout(searchTimerRef.current);
|
|
1579
|
+
if (!query.trim()) {
|
|
1580
|
+
setSearchResults([]);
|
|
1581
|
+
return;
|
|
1582
|
+
}
|
|
1583
|
+
searchTimerRef.current = setTimeout(async () => {
|
|
1584
|
+
if (!executeAction || !referencedTableId) return;
|
|
1585
|
+
setIsSearching(true);
|
|
1586
|
+
try {
|
|
1587
|
+
const excludeIds = entries.map((e) => e.recordId);
|
|
1588
|
+
const res = await executeAction("SEARCH_SUB_TABLE_RECORDS", {
|
|
1589
|
+
referencedTableId,
|
|
1590
|
+
query: query.trim(),
|
|
1591
|
+
excludeIds,
|
|
1592
|
+
limit: 15
|
|
1593
|
+
});
|
|
1594
|
+
setSearchResults(Array.isArray(res) ? res : []);
|
|
1595
|
+
} catch (e) {
|
|
1596
|
+
setSearchResults([]);
|
|
1597
|
+
} finally {
|
|
1598
|
+
setIsSearching(false);
|
|
1599
|
+
}
|
|
1600
|
+
}, 300);
|
|
1601
|
+
}, [executeAction, referencedTableId, entries]);
|
|
1602
|
+
const targetColumns = ((targetSchema == null ? void 0 : targetSchema.columns) || []).filter(
|
|
1603
|
+
(c) => {
|
|
1604
|
+
if (c.name === "_id" || c.type === "SUB_TABLE") return false;
|
|
1605
|
+
return true;
|
|
1606
|
+
}
|
|
1607
|
+
);
|
|
1608
|
+
const [relationOptions, setRelationOptions] = (0, import_react6.useState)({});
|
|
1609
|
+
(0, import_react6.useEffect)(() => {
|
|
1610
|
+
if (!executeAction || targetColumns.length === 0) return;
|
|
1611
|
+
const relationCols = targetColumns.filter((c) => {
|
|
1612
|
+
var _a2;
|
|
1613
|
+
return ((_a2 = c.type) == null ? void 0 : _a2.toUpperCase()) === "RELATION" && c.referencedTableId;
|
|
1614
|
+
});
|
|
1615
|
+
relationCols.forEach(async (col) => {
|
|
1616
|
+
try {
|
|
1617
|
+
const options = await executeAction("FETCH_RELATION", {
|
|
1618
|
+
referencedTableId: col.referencedTableId,
|
|
1619
|
+
displayField: col.displayField
|
|
1620
|
+
});
|
|
1621
|
+
if (options && Array.isArray(options)) {
|
|
1622
|
+
setRelationOptions((prev) => __spreadProps(__spreadValues({}, prev), { [col.name]: options }));
|
|
1623
|
+
}
|
|
1624
|
+
} catch (err) {
|
|
1625
|
+
console.warn(`[SubTableViewer] Could not fetch relation options for column ${col.name}:`, err);
|
|
1626
|
+
}
|
|
1627
|
+
});
|
|
1628
|
+
}, [executeAction, targetColumns]);
|
|
1629
|
+
const refetchRelation = (0, import_react6.useCallback)(async (colName) => {
|
|
1630
|
+
var _a2;
|
|
1631
|
+
const col = targetColumns.find((c) => c.name === colName);
|
|
1632
|
+
if (!col || ((_a2 = col.type) == null ? void 0 : _a2.toUpperCase()) !== "RELATION" || !col.referencedTableId || !executeAction) return;
|
|
1633
|
+
try {
|
|
1634
|
+
const options = await executeAction("FETCH_RELATION", { referencedTableId: col.referencedTableId, displayField: col.displayField });
|
|
1635
|
+
if (options && Array.isArray(options)) {
|
|
1636
|
+
setRelationOptions((prev) => __spreadProps(__spreadValues({}, prev), { [col.name]: options }));
|
|
1637
|
+
}
|
|
1638
|
+
} catch (err) {
|
|
1639
|
+
console.warn(`[SubTableViewer] Could not refetch relation options for column ${col.name}:`, err);
|
|
1640
|
+
}
|
|
1641
|
+
}, [targetColumns, executeAction]);
|
|
1642
|
+
const updateParentLinkage = async (updated) => {
|
|
1643
|
+
const isNewRow = rowId.startsWith("temp_");
|
|
1644
|
+
if (context == null ? void 0 : context.updateQuietly) {
|
|
1645
|
+
context.updateQuietly(rowId, column.name, updated);
|
|
1646
|
+
} else {
|
|
1647
|
+
onChange(updated);
|
|
1648
|
+
}
|
|
1649
|
+
if (executeAction && (context == null ? void 0 : context.parentTableId) && !isNewRow) {
|
|
1650
|
+
try {
|
|
1651
|
+
const payloadToSave = updated.map(({ recordId, isSelected }) => ({ recordId, isSelected }));
|
|
1652
|
+
await executeAction("UPDATE_RECORD", {
|
|
1653
|
+
tableId: context.parentTableId,
|
|
1654
|
+
recordId: rowId,
|
|
1655
|
+
data: { [column.name]: payloadToSave }
|
|
1656
|
+
});
|
|
1657
|
+
if (context == null ? void 0 : context.triggerSaveSuccess) {
|
|
1658
|
+
context.triggerSaveSuccess();
|
|
1659
|
+
}
|
|
1660
|
+
} catch (err) {
|
|
1661
|
+
console.error("Failed to auto-save parent linkage", err);
|
|
1662
|
+
}
|
|
1663
|
+
}
|
|
1664
|
+
};
|
|
1665
|
+
const handleLinkRecords = (recordsToLink) => {
|
|
1666
|
+
if (!recordsToLink || recordsToLink.length === 0) return;
|
|
1667
|
+
const existingEntryIds = new Set(entries.map((e) => e.recordId));
|
|
1668
|
+
const newEntries = [];
|
|
1669
|
+
const newRecordsToAdd = [];
|
|
1670
|
+
for (const record of recordsToLink) {
|
|
1671
|
+
fetchedIdsRef.current.add(record.id);
|
|
1672
|
+
const resolvedData = __spreadValues({}, record.data || {});
|
|
1673
|
+
targetColumns.forEach((col) => {
|
|
1674
|
+
if ((resolvedData[col.name] === void 0 || resolvedData[col.name] === null) && record[col.name] !== void 0) {
|
|
1675
|
+
resolvedData[col.name] = record[col.name];
|
|
1676
|
+
}
|
|
1677
|
+
});
|
|
1678
|
+
if (!existingEntryIds.has(record.id)) {
|
|
1679
|
+
newEntries.push({
|
|
1680
|
+
recordId: record.id,
|
|
1681
|
+
isSelected: true,
|
|
1682
|
+
_resolvedData: resolvedData
|
|
1683
|
+
});
|
|
1684
|
+
existingEntryIds.add(record.id);
|
|
1685
|
+
}
|
|
1686
|
+
newRecordsToAdd.push({
|
|
1687
|
+
id: record.id,
|
|
1688
|
+
data: resolvedData
|
|
1689
|
+
});
|
|
1690
|
+
}
|
|
1691
|
+
const updatedEntries = [...entries, ...newEntries];
|
|
1692
|
+
updateParentLinkage(updatedEntries);
|
|
1693
|
+
setLinkedRecords((prev) => {
|
|
1694
|
+
const map = new Map(prev.map((r) => [r.id, r]));
|
|
1695
|
+
newRecordsToAdd.forEach((r) => {
|
|
1696
|
+
const existing = map.get(r.id);
|
|
1697
|
+
if (existing) {
|
|
1698
|
+
map.set(r.id, __spreadProps(__spreadValues({}, existing), {
|
|
1699
|
+
data: __spreadValues(__spreadValues({}, existing.data), r.data)
|
|
1700
|
+
}));
|
|
1701
|
+
} else {
|
|
1702
|
+
map.set(r.id, r);
|
|
1703
|
+
}
|
|
1704
|
+
});
|
|
1705
|
+
return Array.from(map.values());
|
|
1706
|
+
});
|
|
1707
|
+
setSearchQuery("");
|
|
1708
|
+
setSearchResults([]);
|
|
1709
|
+
setIsSearchOpen(false);
|
|
1710
|
+
};
|
|
1711
|
+
const handleLinkRecord = (record) => {
|
|
1712
|
+
handleLinkRecords([record]);
|
|
1713
|
+
};
|
|
1714
|
+
const handleUniqueConflict = (conflictData) => {
|
|
1715
|
+
const rawMatching = Array.isArray(conflictData == null ? void 0 : conflictData.matchingRecords) ? conflictData.matchingRecords : [];
|
|
1716
|
+
const resolvedMatching = rawMatching.map((r) => {
|
|
1717
|
+
var _a2;
|
|
1718
|
+
const recordId = String(r.id || ((_a2 = r._id) == null ? void 0 : _a2.$oid) || r._id);
|
|
1719
|
+
let dataObj = {};
|
|
1720
|
+
if (r.data && typeof r.data === "object") {
|
|
1721
|
+
dataObj = __spreadValues({}, r.data);
|
|
1722
|
+
}
|
|
1723
|
+
targetColumns.forEach((col) => {
|
|
1724
|
+
if ((dataObj[col.name] === void 0 || dataObj[col.name] === null) && r[col.name] !== void 0) {
|
|
1725
|
+
dataObj[col.name] = r[col.name];
|
|
1726
|
+
}
|
|
1727
|
+
});
|
|
1728
|
+
return {
|
|
1729
|
+
id: recordId,
|
|
1730
|
+
data: dataObj
|
|
1731
|
+
};
|
|
1732
|
+
});
|
|
1733
|
+
setConflictModalState({
|
|
1734
|
+
isOpen: true,
|
|
1735
|
+
fieldName: (conflictData == null ? void 0 : conflictData.fieldName) || "",
|
|
1736
|
+
matchingRecords: resolvedMatching
|
|
1737
|
+
});
|
|
1738
|
+
};
|
|
1739
|
+
const handleCancelConflict = () => {
|
|
1740
|
+
setConflictModalState((prev) => __spreadProps(__spreadValues({}, prev), { isOpen: false }));
|
|
1741
|
+
};
|
|
1742
|
+
const handleConfirmLinkConflict = async () => {
|
|
1743
|
+
const { matchingRecords } = conflictModalState;
|
|
1744
|
+
if (matchingRecords && matchingRecords.length > 0) {
|
|
1745
|
+
handleLinkRecords(matchingRecords);
|
|
1746
|
+
setNewRecordData({});
|
|
1747
|
+
setIsCreating(false);
|
|
1748
|
+
setConflictModalState({
|
|
1749
|
+
isOpen: false,
|
|
1750
|
+
fieldName: "",
|
|
1751
|
+
matchingRecords: []
|
|
1752
|
+
});
|
|
1753
|
+
addToast({
|
|
1754
|
+
type: "success",
|
|
1755
|
+
message: "\u05D4\u05E8\u05E9\u05D5\u05DE\u05D4 \u05E7\u05D5\u05E9\u05E8\u05D4 \u05D1\u05D4\u05E6\u05DC\u05D7\u05D4"
|
|
1756
|
+
});
|
|
1757
|
+
} else {
|
|
1758
|
+
setConflictModalState((prev) => __spreadProps(__spreadValues({}, prev), { isOpen: false }));
|
|
1759
|
+
}
|
|
1760
|
+
};
|
|
1761
|
+
const handleUnlinkRecord = (recordId) => {
|
|
1762
|
+
const updated = entries.filter((e) => e.recordId !== recordId);
|
|
1763
|
+
updateParentLinkage(updated);
|
|
1764
|
+
setLinkedRecords((prev) => prev.filter((r) => r.id !== recordId));
|
|
1765
|
+
};
|
|
1766
|
+
const handleToggleSelected = (recordId) => {
|
|
1767
|
+
const record = linkedRecords.find((r) => r.id === recordId);
|
|
1768
|
+
const updated = entries.map(
|
|
1769
|
+
(e) => e.recordId === recordId ? __spreadProps(__spreadValues({}, e), { isSelected: !e.isSelected, _resolvedData: (record == null ? void 0 : record.data) || e._resolvedData }) : e
|
|
1770
|
+
);
|
|
1771
|
+
updateParentLinkage(updated);
|
|
1772
|
+
};
|
|
1773
|
+
const isMountedRef = (0, import_react6.useRef)(true);
|
|
1774
|
+
(0, import_react6.useEffect)(() => {
|
|
1775
|
+
isMountedRef.current = true;
|
|
1776
|
+
return () => {
|
|
1777
|
+
isMountedRef.current = false;
|
|
1778
|
+
};
|
|
1779
|
+
}, []);
|
|
1780
|
+
const handleCommitRecordCell = async (recordId, colName, value2) => {
|
|
1781
|
+
var _a2;
|
|
1782
|
+
const previousRecord = linkedRecords.find((r) => r.id === recordId);
|
|
1783
|
+
const previousValue = (_a2 = previousRecord == null ? void 0 : previousRecord.data) == null ? void 0 : _a2[colName];
|
|
1784
|
+
if (previousValue === value2) return true;
|
|
1785
|
+
const targetCol = targetColumns.find((c) => c.name === colName);
|
|
1786
|
+
const valRes = targetCol ? validateCellValue(value2, targetCol) : { isValid: true };
|
|
1787
|
+
if (!valRes.isValid) {
|
|
1788
|
+
addToast({
|
|
1789
|
+
type: "error",
|
|
1790
|
+
message: valRes.error || "\u05E9\u05D2\u05D9\u05D0\u05EA \u05D0\u05D9\u05DE\u05D5\u05EA"
|
|
1791
|
+
});
|
|
1792
|
+
return false;
|
|
1793
|
+
}
|
|
1794
|
+
if (executeAction && referencedTableId && !recordId.startsWith("temp_")) {
|
|
1795
|
+
try {
|
|
1796
|
+
const res = await executeAction("UPDATE_RECORD", {
|
|
1797
|
+
tableId: referencedTableId,
|
|
1798
|
+
recordId,
|
|
1799
|
+
data: { [colName]: value2 }
|
|
1800
|
+
});
|
|
1801
|
+
if (res && res.success === false) {
|
|
1802
|
+
const err = new Error(res.error || res.message || "Action execution failed");
|
|
1803
|
+
Object.assign(err, res);
|
|
1804
|
+
throw err;
|
|
1805
|
+
}
|
|
1806
|
+
if (isMountedRef.current) {
|
|
1807
|
+
const updatedRecords = linkedRecords.map(
|
|
1808
|
+
(r) => r.id === recordId ? __spreadProps(__spreadValues({}, r), { data: __spreadProps(__spreadValues({}, r.data), { [colName]: value2 }) }) : r
|
|
1809
|
+
);
|
|
1810
|
+
setLinkedRecords(updatedRecords);
|
|
1811
|
+
const targetRecord = updatedRecords.find((r) => r.id === recordId);
|
|
1812
|
+
const updatedEntries = entries.map(
|
|
1813
|
+
(e) => e.recordId === recordId ? __spreadProps(__spreadValues({}, e), { _resolvedData: targetRecord == null ? void 0 : targetRecord.data }) : e
|
|
1814
|
+
);
|
|
1815
|
+
if (context == null ? void 0 : context.updateQuietly) {
|
|
1816
|
+
context.updateQuietly(rowId, column.name, updatedEntries);
|
|
1817
|
+
} else {
|
|
1818
|
+
onChange(updatedEntries);
|
|
1819
|
+
}
|
|
1820
|
+
if (context == null ? void 0 : context.triggerSaveSuccess) {
|
|
1821
|
+
context.triggerSaveSuccess();
|
|
1822
|
+
}
|
|
1823
|
+
}
|
|
1824
|
+
return true;
|
|
1825
|
+
} catch (err) {
|
|
1826
|
+
console.error("[SubTableViewer] Failed to auto-save linked record field", err);
|
|
1827
|
+
let errorMsg = (err == null ? void 0 : err.message) || (err == null ? void 0 : err.error) || "\u05E9\u05D2\u05D9\u05D0\u05D4 \u05D1\u05E9\u05DE\u05D9\u05E8\u05EA \u05D4\u05E8\u05E9\u05D5\u05DE\u05D4";
|
|
1828
|
+
if ((err == null ? void 0 : err.error) === "UNIQUE_CONSTRAINT_CONFLICT" || (err == null ? void 0 : err.code) === "UNIQUE_CONSTRAINT_CONFLICT" || errorMsg.includes("must be unique") || errorMsg.includes("Duplicate value detected") || errorMsg.includes("\u05DB\u05D1\u05E8 \u05E7\u05D9\u05D9\u05DE\u05EA") || errorMsg.includes("UNIQUE_CONSTRAINT_CONFLICT")) {
|
|
1829
|
+
errorMsg = `\u05E9\u05D2\u05D9\u05D0\u05EA \u05D0\u05D9\u05DE\u05D5\u05EA: \u05D4\u05E2\u05E8\u05DA '${value2}' \u05DB\u05D1\u05E8 \u05E7\u05D9\u05D9\u05DD \u05D1\u05E9\u05D3\u05D4 '${colName}' (\u05E9\u05D3\u05D4 \u05D9\u05D9\u05D7\u05D5\u05D3\u05D9).`;
|
|
1830
|
+
} else if (errorMsg.includes("is required") || errorMsg.includes("\u05E9\u05D3\u05D4 \u05D7\u05D5\u05D1\u05D4") || errorMsg.toLowerCase().includes("required")) {
|
|
1831
|
+
errorMsg = `\u05E9\u05D2\u05D9\u05D0\u05EA \u05D0\u05D9\u05DE\u05D5\u05EA: \u05E9\u05D3\u05D4 '${colName}' \u05D4\u05D9\u05E0\u05D5 \u05E9\u05D3\u05D4 \u05D7\u05D5\u05D1\u05D4 \u05D5\u05DC\u05D0 \u05D9\u05DB\u05D5\u05DC \u05DC\u05D4\u05D9\u05E9\u05D0\u05E8 \u05E8\u05D9\u05E7.`;
|
|
1832
|
+
}
|
|
1833
|
+
addToast({
|
|
1834
|
+
type: "error",
|
|
1835
|
+
message: errorMsg
|
|
1836
|
+
});
|
|
1837
|
+
return false;
|
|
1838
|
+
}
|
|
1839
|
+
} else {
|
|
1840
|
+
if (isMountedRef.current) {
|
|
1841
|
+
const updatedRecords = linkedRecords.map(
|
|
1842
|
+
(r) => r.id === recordId ? __spreadProps(__spreadValues({}, r), { data: __spreadProps(__spreadValues({}, r.data), { [colName]: value2 }) }) : r
|
|
1843
|
+
);
|
|
1844
|
+
setLinkedRecords(updatedRecords);
|
|
1845
|
+
const targetRecord = updatedRecords.find((r) => r.id === recordId);
|
|
1846
|
+
const updatedEntries = entries.map(
|
|
1847
|
+
(e) => e.recordId === recordId ? __spreadProps(__spreadValues({}, e), { _resolvedData: targetRecord == null ? void 0 : targetRecord.data }) : e
|
|
1848
|
+
);
|
|
1849
|
+
if (context == null ? void 0 : context.updateQuietly) {
|
|
1850
|
+
context.updateQuietly(rowId, column.name, updatedEntries);
|
|
1851
|
+
} else {
|
|
1852
|
+
onChange(updatedEntries);
|
|
1853
|
+
}
|
|
1854
|
+
}
|
|
1855
|
+
return true;
|
|
1856
|
+
}
|
|
1857
|
+
};
|
|
1858
|
+
const handleRecordCellChange = handleCommitRecordCell;
|
|
1859
|
+
const handleCreateRecord = async () => {
|
|
1860
|
+
var _a2, _b2, _c, _d, _e;
|
|
1861
|
+
if (!executeAction || !referencedTableId) return;
|
|
1862
|
+
for (const col of targetColumns) {
|
|
1863
|
+
if (col.isRequired) {
|
|
1864
|
+
const val = newRecordData[col.name];
|
|
1865
|
+
if (val === void 0 || val === null || typeof val === "string" && val.trim() === "") {
|
|
1866
|
+
addToast({
|
|
1867
|
+
type: "error",
|
|
1868
|
+
message: `Validation Error: Field '${col.name}' is required but was not provided.`
|
|
1869
|
+
});
|
|
1870
|
+
return;
|
|
1871
|
+
}
|
|
1872
|
+
}
|
|
1873
|
+
if (((_a2 = col.type) == null ? void 0 : _a2.toUpperCase()) === "PHONE") {
|
|
1874
|
+
const val = newRecordData[col.name];
|
|
1875
|
+
if (val !== void 0 && val !== null && String(val).trim() !== "" && !isValidPhoneNumber(String(val))) {
|
|
1876
|
+
addToast({
|
|
1877
|
+
type: "error",
|
|
1878
|
+
message: `\u05DE\u05E1\u05E4\u05E8 \u05D4\u05D8\u05DC\u05E4\u05D5\u05DF \u05D1\u05E9\u05D3\u05D4 '${col.name}' \u05D0\u05D9\u05E0\u05D5 \u05EA\u05E7\u05D9\u05DF. \u05D9\u05E9 \u05DC\u05D4\u05D6\u05D9\u05DF \u05DE\u05E1\u05E4\u05E8 \u05D1\u05D0\u05D5\u05E8\u05DA 9-15 \u05E1\u05E4\u05E8\u05D5\u05EA.`
|
|
1879
|
+
});
|
|
1880
|
+
return;
|
|
1881
|
+
}
|
|
1882
|
+
}
|
|
1883
|
+
}
|
|
1884
|
+
try {
|
|
1885
|
+
const res = await executeAction("CREATE_RECORD", {
|
|
1886
|
+
tableId: referencedTableId,
|
|
1887
|
+
records: [newRecordData]
|
|
1888
|
+
});
|
|
1889
|
+
if (res && (res.error === "UNIQUE_CONSTRAINT_CONFLICT" || res.code === "UNIQUE_CONSTRAINT_CONFLICT")) {
|
|
1890
|
+
handleUniqueConflict(res);
|
|
1891
|
+
return;
|
|
1892
|
+
}
|
|
1893
|
+
if (res && res.success === false) {
|
|
1894
|
+
throw new Error(res.error || "Action execution failed");
|
|
1895
|
+
}
|
|
1896
|
+
const created = Array.isArray(res) ? res[0] : ((_b2 = res == null ? void 0 : res.data) == null ? void 0 : _b2[0]) || res;
|
|
1897
|
+
if (created) {
|
|
1898
|
+
const newRecord = {
|
|
1899
|
+
id: String(created.id || created._id),
|
|
1900
|
+
data: created.data || newRecordData
|
|
1901
|
+
};
|
|
1902
|
+
handleLinkRecord(newRecord);
|
|
1903
|
+
setIsCreating(false);
|
|
1904
|
+
setNewRecordData({});
|
|
1905
|
+
}
|
|
1906
|
+
} catch (err) {
|
|
1907
|
+
const isConflict = (err == null ? void 0 : err.error) === "UNIQUE_CONSTRAINT_CONFLICT" || (err == null ? void 0 : err.code) === "UNIQUE_CONSTRAINT_CONFLICT" || ((_c = err == null ? void 0 : err.data) == null ? void 0 : _c.error) === "UNIQUE_CONSTRAINT_CONFLICT" || ((_d = err == null ? void 0 : err.message) == null ? void 0 : _d.includes("UNIQUE_CONSTRAINT_CONFLICT"));
|
|
1908
|
+
if (isConflict) {
|
|
1909
|
+
const conflictPayload = (err == null ? void 0 : err.error) === "UNIQUE_CONSTRAINT_CONFLICT" ? err : ((_e = err == null ? void 0 : err.data) == null ? void 0 : _e.error) === "UNIQUE_CONSTRAINT_CONFLICT" ? err.data : err;
|
|
1910
|
+
handleUniqueConflict(conflictPayload);
|
|
1911
|
+
return;
|
|
1912
|
+
}
|
|
1913
|
+
const msg = (err == null ? void 0 : err.message) || String(err);
|
|
1914
|
+
addToast({
|
|
1915
|
+
type: "error",
|
|
1916
|
+
message: msg
|
|
1917
|
+
});
|
|
1918
|
+
}
|
|
1919
|
+
};
|
|
1920
|
+
const getDisplayLabel = (record) => {
|
|
1921
|
+
const fields = column.subTableDisplayFields || [];
|
|
1922
|
+
if (fields.length === 0) {
|
|
1923
|
+
const firstField = Object.keys(record.data).find((k) => k !== "_id");
|
|
1924
|
+
return firstField ? String(record.data[firstField] || "") : record.id;
|
|
1925
|
+
}
|
|
1926
|
+
return fields.map((f) => String(record.data[f] || "")).filter(Boolean).join(" ");
|
|
1927
|
+
};
|
|
1928
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "p-3 animate-in fade-in slide-in-from-top-2 duration-200", dir: "rtl", children: [
|
|
1929
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex items-center gap-4 mb-2.5", children: [
|
|
1930
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "flex items-center gap-2", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "text-xs font-bold text-slate-600", children: (_a = targetSchema == null ? void 0 : targetSchema.name) != null ? _a : column.referencedTableName }) }),
|
|
1931
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex items-center gap-1.5", children: [
|
|
1932
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "relative", ref: searchRef, children: [
|
|
1933
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
1934
|
+
"button",
|
|
1935
|
+
{
|
|
1936
|
+
type: "button",
|
|
1937
|
+
onClick: () => setIsSearchOpen((prev) => !prev),
|
|
1938
|
+
className: "h-7 px-2.5 text-[11px] font-semibold bg-blue-50 hover:bg-blue-100 text-blue-700 border border-blue-200 rounded-md transition-colors cursor-pointer flex items-center gap-1",
|
|
1939
|
+
children: [
|
|
1940
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { className: "w-3 h-3", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" }) }),
|
|
1941
|
+
"\u05E7\u05D9\u05E9\u05D5\u05E8 \u05E8\u05E9\u05D5\u05DE\u05D5\u05EA"
|
|
1942
|
+
]
|
|
1943
|
+
}
|
|
1944
|
+
),
|
|
1945
|
+
isSearchOpen && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "absolute right-0 top-full mt-1 w-72 bg-white border border-slate-200 rounded-lg shadow-xl z-50 p-2", children: [
|
|
1946
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1947
|
+
"input",
|
|
1948
|
+
{
|
|
1949
|
+
type: "text",
|
|
1950
|
+
value: searchQuery,
|
|
1951
|
+
onChange: (e) => handleSearch(e.target.value),
|
|
1952
|
+
placeholder: "\u05D7\u05E4\u05E9 \u05E8\u05E9\u05D5\u05DE\u05D5\u05EA...",
|
|
1953
|
+
className: "w-full h-8 px-2.5 text-xs border border-slate-300 rounded-md focus:outline-none focus:ring-1 focus:ring-blue-400 mb-1.5",
|
|
1954
|
+
autoFocus: true
|
|
1955
|
+
}
|
|
1956
|
+
),
|
|
1957
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "max-h-48 overflow-y-auto", children: isSearching ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "flex items-center justify-center py-4", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "w-4 h-4 border-2 border-blue-400 border-t-transparent rounded-full animate-spin" }) }) : searchResults.length > 0 ? searchResults.map((r) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1958
|
+
"button",
|
|
1959
|
+
{
|
|
1960
|
+
type: "button",
|
|
1961
|
+
onClick: () => handleLinkRecord(r),
|
|
1962
|
+
className: "w-full text-right px-2 py-1.5 text-xs hover:bg-blue-50 rounded cursor-pointer transition-colors",
|
|
1963
|
+
children: getDisplayLabel(r)
|
|
1964
|
+
},
|
|
1965
|
+
r.id
|
|
1966
|
+
)) : searchQuery.trim() ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "text-xs text-slate-400 text-center py-3", children: "\u05DC\u05D0 \u05E0\u05DE\u05E6\u05D0\u05D5 \u05EA\u05D5\u05E6\u05D0\u05D5\u05EA" }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "text-xs text-slate-400 text-center py-3", children: "\u05D4\u05E7\u05DC\u05D3 \u05DC\u05D7\u05D9\u05E4\u05D5\u05E9..." }) })
|
|
1967
|
+
] })
|
|
1968
|
+
] }),
|
|
1969
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
1970
|
+
"button",
|
|
1971
|
+
{
|
|
1972
|
+
type: "button",
|
|
1973
|
+
onClick: () => {
|
|
1974
|
+
setIsCreating(true);
|
|
1975
|
+
const initialData = {};
|
|
1976
|
+
targetColumns.forEach((c) => {
|
|
1977
|
+
if (c.defaultValue !== void 0 && c.defaultValue !== null) {
|
|
1978
|
+
initialData[c.name] = c.type === "NUMBER" || c.type === "CURRENCY" ? parseFloat(c.defaultValue) : c.type === "BOOLEAN" ? c.defaultValue === "true" || c.defaultValue === true : c.defaultValue;
|
|
1979
|
+
} else {
|
|
1980
|
+
if (c.type === "NUMBER" || c.type === "CURRENCY") initialData[c.name] = 0;
|
|
1981
|
+
else if (c.type === "BOOLEAN") initialData[c.name] = false;
|
|
1982
|
+
else initialData[c.name] = "";
|
|
1983
|
+
}
|
|
1984
|
+
});
|
|
1985
|
+
setNewRecordData(initialData);
|
|
1986
|
+
},
|
|
1987
|
+
className: "h-7 px-2.5 text-[11px] font-semibold bg-emerald-50 hover:bg-emerald-100 text-emerald-700 border border-emerald-200 rounded-md transition-colors cursor-pointer flex items-center gap-1",
|
|
1988
|
+
children: [
|
|
1989
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { className: "w-3 h-3", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2.5", d: "M12 4v16m8-8H4" }) }),
|
|
1990
|
+
"\u05E8\u05E9\u05D5\u05DE\u05D4 \u05D7\u05D3\u05E9\u05D4"
|
|
1991
|
+
]
|
|
1992
|
+
}
|
|
1993
|
+
)
|
|
1994
|
+
] })
|
|
1995
|
+
] }),
|
|
1996
|
+
isLoading ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "flex items-center justify-center py-6", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "w-5 h-5 border-2 border-blue-400 border-t-transparent rounded-full animate-spin" }) }) : entries.length === 0 && !isCreating ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "text-center py-6 text-xs text-slate-400", children: "\u05D0\u05D9\u05DF \u05E8\u05E9\u05D5\u05DE\u05D5\u05EA \u05DE\u05E7\u05D5\u05E9\u05E8\u05D5\u05EA. \u05D4\u05E9\u05EA\u05DE\u05E9 \u05D1\u05D7\u05D9\u05E4\u05D5\u05E9 \u05DB\u05D3\u05D9 \u05DC\u05E7\u05E9\u05E8 \u05E8\u05E9\u05D5\u05DE\u05D5\u05EA \u05E7\u05D9\u05D9\u05DE\u05D5\u05EA, \u05D0\u05D5 \u05D4\u05D5\u05E1\u05E3 \u05E8\u05E9\u05D5\u05DE\u05D4 \u05D7\u05D3\u05E9\u05D4." }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "overflow-x-auto pb-1", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("table", { className: "w-full text-xs border-collapse", children: [
|
|
1997
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("tr", { className: "bg-slate-100/80", children: [
|
|
1998
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("th", { className: "border border-slate-200 px-2 py-1.5 text-center w-10 font-semibold text-slate-500", children: "\u05E0\u05D1\u05D7\u05E8" }),
|
|
1999
|
+
targetColumns.map((col) => {
|
|
2000
|
+
var _a2;
|
|
2001
|
+
const isContact = ((_a2 = col.type) == null ? void 0 : _a2.toUpperCase()) === "GOOGLE_CONTACT";
|
|
2002
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
2003
|
+
"th",
|
|
2004
|
+
{
|
|
2005
|
+
className: `border border-slate-200 px-2 py-1.5 text-right font-semibold text-slate-600 whitespace-nowrap ${isContact ? "min-w-[140px]" : ""}`,
|
|
2006
|
+
children: col.name
|
|
2007
|
+
},
|
|
2008
|
+
col.name
|
|
2009
|
+
);
|
|
2010
|
+
}),
|
|
2011
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("th", { className: "border border-slate-200 px-2 py-1.5 w-14" })
|
|
2012
|
+
] }) }),
|
|
2013
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("tbody", { children: [
|
|
2014
|
+
entries.map((entry) => {
|
|
2015
|
+
var _a2;
|
|
2016
|
+
const record = linkedRecords.find((r) => r.id === entry.recordId);
|
|
2017
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("tr", { className: "hover:bg-blue-50/30 transition-colors", children: [
|
|
2018
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("td", { className: "border border-slate-200 px-2 py-1 text-center", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
2019
|
+
"input",
|
|
2020
|
+
{
|
|
2021
|
+
type: "checkbox",
|
|
2022
|
+
checked: entry.isSelected,
|
|
2023
|
+
onChange: () => handleToggleSelected(entry.recordId),
|
|
2024
|
+
className: "w-3.5 h-3.5 rounded border-slate-300 text-blue-600 cursor-pointer"
|
|
2025
|
+
}
|
|
2026
|
+
) }),
|
|
2027
|
+
targetColumns.map((col) => {
|
|
2028
|
+
var _a3;
|
|
2029
|
+
const isContact = ((_a3 = col.type) == null ? void 0 : _a3.toUpperCase()) === "GOOGLE_CONTACT";
|
|
2030
|
+
if (!record) {
|
|
2031
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
2032
|
+
"td",
|
|
2033
|
+
{
|
|
2034
|
+
className: `border border-slate-200 p-0 relative h-8 ${isContact ? "min-w-[140px]" : ""}`,
|
|
2035
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "text-slate-300 italic px-2", children: "\u05D8\u05D5\u05E2\u05DF..." })
|
|
2036
|
+
},
|
|
2037
|
+
col.name
|
|
2038
|
+
);
|
|
2039
|
+
}
|
|
2040
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
2041
|
+
SubTableCell,
|
|
2042
|
+
{
|
|
2043
|
+
record,
|
|
2044
|
+
column: col,
|
|
2045
|
+
targetSchema,
|
|
2046
|
+
referencedTableId,
|
|
2047
|
+
context,
|
|
2048
|
+
relationOptions,
|
|
2049
|
+
setRelationOptions,
|
|
2050
|
+
refetchRelation,
|
|
2051
|
+
onCommit: handleCommitRecordCell
|
|
2052
|
+
},
|
|
2053
|
+
`${record.id}_${col.name}`
|
|
2054
|
+
);
|
|
2055
|
+
}),
|
|
2056
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("td", { className: "border border-slate-200 px-1 py-1 text-center", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex items-center justify-center gap-1", children: [
|
|
2057
|
+
((_a2 = column.config) == null ? void 0 : _a2.actionType) === "WHATSAPP" && (() => {
|
|
2058
|
+
var _a3, _b2, _c;
|
|
2059
|
+
const actionPhoneCol = (_a3 = column.config) == null ? void 0 : _a3.actionPhoneColumn;
|
|
2060
|
+
const phone = actionPhoneCol ? ((_b2 = record == null ? void 0 : record.data) == null ? void 0 : _b2[actionPhoneCol]) || ((_c = entry._resolvedData) == null ? void 0 : _c[actionPhoneCol]) : null;
|
|
2061
|
+
if (phone) {
|
|
2062
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
2063
|
+
"button",
|
|
2064
|
+
{
|
|
2065
|
+
type: "button",
|
|
2066
|
+
onClick: (e) => {
|
|
2067
|
+
e.stopPropagation();
|
|
2068
|
+
openWhatsAppChat(String(phone));
|
|
2069
|
+
},
|
|
2070
|
+
className: "text-emerald-500 hover:text-emerald-600 p-0.5 rounded hover:bg-emerald-50 transition-colors cursor-pointer",
|
|
2071
|
+
title: `\u05E4\u05EA\u05D9\u05D7\u05EA \u05D5\u05D5\u05D0\u05D8\u05E1\u05D0\u05E4 (${phone})`,
|
|
2072
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { className: "w-3.5 h-3.5", fill: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M17.472 14.382c-.297-.149-1.758-.867-2.03-.967-.273-.099-.471-.148-.67.15-.197.297-.767.966-.94 1.164-.173.199-.347.223-.644.075-.297-.15-1.255-.463-2.39-1.475-.883-.788-1.48-1.761-1.653-2.059-.173-.297-.018-.458.13-.606.134-.133.298-.347.446-.52.149-.174.198-.298.298-.497.099-.198.05-.371-.025-.52-.075-.149-.669-1.612-.916-2.207-.242-.579-.487-.5-.669-.51a5.816 5.816 0 00-.571-.01c-.198 0-.52.074-.792.372-.272.297-1.04 1.016-1.04 2.479 0 1.462 1.065 2.875 1.213 3.074.149.198 2.096 3.2 5.077 4.487.709.306 1.262.489 1.694.625.712.227 1.36.195 1.871.118.571-.085 1.758-.719 2.006-1.413.248-.694.248-1.289.173-1.413-.074-.124-.272-.198-.57-.347m-5.421 7.403h-.004a9.87 9.87 0 01-5.031-1.378l-.361-.214-3.741.982.998-3.648-.235-.374a9.86 9.86 0 01-1.51-5.26c.001-5.45 4.436-9.884 9.888-9.884 2.64 0 5.122 1.03 6.988 2.898a9.825 9.825 0 012.893 6.994c-.003 5.45-4.437 9.884-9.885 9.884m8.413-18.297A11.815 11.815 0 0012.05 0C5.495 0 .16 5.335.157 11.892c0 2.096.547 4.142 1.588 5.945L.057 24l6.305-1.654a11.882 11.882 0 005.683 1.448h.005c6.554 0 11.89-5.335 11.893-11.893a11.821 11.821 0 00-3.48-8.413z" }) })
|
|
2073
|
+
}
|
|
2074
|
+
);
|
|
2075
|
+
}
|
|
2076
|
+
return null;
|
|
2077
|
+
})(),
|
|
2078
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
2079
|
+
"button",
|
|
2080
|
+
{
|
|
2081
|
+
type: "button",
|
|
2082
|
+
onClick: (e) => {
|
|
2083
|
+
e.stopPropagation();
|
|
2084
|
+
handleUnlinkRecord(entry.recordId);
|
|
2085
|
+
},
|
|
2086
|
+
className: "text-slate-400 hover:text-rose-500 p-0.5 rounded transition-colors cursor-pointer inline-flex items-center justify-center",
|
|
2087
|
+
title: "\u05D4\u05E1\u05E8 \u05E7\u05D9\u05E9\u05D5\u05E8",
|
|
2088
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { className: "w-3.5 h-3.5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M6 18L18 6M6 6l12 12" }) })
|
|
2089
|
+
}
|
|
2090
|
+
)
|
|
2091
|
+
] }) })
|
|
2092
|
+
] }, entry.recordId);
|
|
2093
|
+
}),
|
|
2094
|
+
isCreating && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("tr", { className: "bg-emerald-50/40", children: [
|
|
2095
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("td", { className: "border border-emerald-200 px-2 py-1 text-center", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "text-emerald-500 font-bold text-[10px]", children: "\u05D7\u05D3\u05E9" }) }),
|
|
2096
|
+
targetColumns.map((col) => {
|
|
2097
|
+
var _a2, _b2;
|
|
2098
|
+
const colType = ((_a2 = col.type) == null ? void 0 : _a2.toUpperCase()) || "DEFAULT";
|
|
2099
|
+
const InputComponent = FORM_INPUTS[colType] || FORM_INPUTS.DEFAULT;
|
|
2100
|
+
const isContact = colType === "GOOGLE_CONTACT";
|
|
2101
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
2102
|
+
"td",
|
|
2103
|
+
{
|
|
2104
|
+
className: `border border-emerald-200 p-0 relative h-8 ${isContact ? "min-w-[140px]" : ""}`,
|
|
2105
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
2106
|
+
InputComponent,
|
|
2107
|
+
{
|
|
2108
|
+
value: (_b2 = newRecordData[col.name]) != null ? _b2 : colType === "BOOLEAN" ? false : "",
|
|
2109
|
+
column: col,
|
|
2110
|
+
rowId: "new_record",
|
|
2111
|
+
onChange: (v) => setNewRecordData((prev) => __spreadProps(__spreadValues({}, prev), { [col.name]: v })),
|
|
2112
|
+
context: __spreadProps(__spreadValues({}, context), {
|
|
2113
|
+
tableName: (targetSchema == null ? void 0 : targetSchema.name) || (targetSchema == null ? void 0 : targetSchema.tableName) || (targetSchema == null ? void 0 : targetSchema.title) || (targetSchema == null ? void 0 : targetSchema.id) || "Table",
|
|
2114
|
+
relationOptions,
|
|
2115
|
+
refetchRelation,
|
|
2116
|
+
tableId: (targetSchema == null ? void 0 : targetSchema.tableMetaId) || (targetSchema == null ? void 0 : targetSchema.id) || referencedTableId
|
|
2117
|
+
})
|
|
2118
|
+
}
|
|
2119
|
+
)
|
|
2120
|
+
},
|
|
2121
|
+
`new_${col.name}`
|
|
2122
|
+
);
|
|
2123
|
+
}),
|
|
2124
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("td", { className: "border border-emerald-200 px-1 py-1 text-center", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex items-center justify-center gap-1", children: [
|
|
2125
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
2126
|
+
"button",
|
|
2127
|
+
{
|
|
2128
|
+
type: "button",
|
|
2129
|
+
onClick: handleCreateRecord,
|
|
2130
|
+
className: "p-1 text-emerald-600 hover:bg-emerald-100 rounded transition-colors",
|
|
2131
|
+
title: "\u05E9\u05DE\u05D5\u05E8",
|
|
2132
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { className: "w-3.5 h-3.5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2.5", d: "M5 13l4 4L19 7" }) })
|
|
2133
|
+
}
|
|
2134
|
+
),
|
|
2135
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
2136
|
+
"button",
|
|
2137
|
+
{
|
|
2138
|
+
type: "button",
|
|
2139
|
+
onClick: () => {
|
|
2140
|
+
setIsCreating(false);
|
|
2141
|
+
},
|
|
2142
|
+
className: "p-1 text-rose-500 hover:bg-rose-100 rounded transition-colors",
|
|
2143
|
+
title: "\u05D1\u05D9\u05D8\u05D5\u05DC",
|
|
2144
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { className: "w-3.5 h-3.5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2.5", d: "M6 18L18 6M6 6l12 12" }) })
|
|
2145
|
+
}
|
|
2146
|
+
)
|
|
2147
|
+
] }) })
|
|
2148
|
+
] })
|
|
2149
|
+
] })
|
|
2150
|
+
] }) }),
|
|
2151
|
+
conflictModalState.isOpen && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
2152
|
+
"div",
|
|
2153
|
+
{
|
|
2154
|
+
className: "fixed inset-0 z-50 flex items-center justify-center p-4 bg-slate-900/60 backdrop-blur-sm animate-in fade-in duration-200",
|
|
2155
|
+
dir: "rtl",
|
|
2156
|
+
onClick: handleCancelConflict,
|
|
2157
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
2158
|
+
"div",
|
|
2159
|
+
{
|
|
2160
|
+
className: "bg-white rounded-xl shadow-2xl w-full max-w-lg sm:max-w-xl overflow-hidden border border-slate-200 animate-in fade-in zoom-in-95 duration-200",
|
|
2161
|
+
onClick: (e) => e.stopPropagation(),
|
|
2162
|
+
children: [
|
|
2163
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "p-5 border-b border-slate-100 flex items-center gap-3", children: [
|
|
2164
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "w-10 h-10 rounded-full bg-blue-50 border border-blue-200 flex items-center justify-center text-blue-600 flex-shrink-0", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { className: "w-5 h-5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M13.828 10.172a4 4 0 00-5.656 0l-4 4a4 4 0 105.656 5.656l1.102-1.101m-.758-4.899a4 4 0 005.656 0l4-4a4 4 0 00-5.656-5.656l-1.1 1.1" }) }) }),
|
|
2165
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
|
|
2166
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("h3", { className: "text-base font-bold text-slate-800", children: conflictModalState.matchingRecords.length > 1 ? "\u05E8\u05E9\u05D5\u05DE\u05D5\u05EA \u05E7\u05D9\u05D9\u05DE\u05D5\u05EA \u05D1\u05D8\u05D1\u05DC\u05D4" : "\u05E8\u05E9\u05D5\u05DE\u05D4 \u05E7\u05D9\u05D9\u05DE\u05EA \u05D1\u05D8\u05D1\u05DC\u05D4" }),
|
|
2167
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "text-xs text-slate-500", children: "\u05E0\u05DE\u05E6\u05D0\u05D4 \u05E8\u05E9\u05D5\u05DE\u05D4 \u05E7\u05D9\u05D9\u05DE\u05EA \u05E2\u05DD \u05D0\u05D5\u05EA\u05D5 \u05E2\u05E8\u05DA \u05D9\u05D9\u05D7\u05D5\u05D3\u05D9" })
|
|
2168
|
+
] })
|
|
2169
|
+
] }),
|
|
2170
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "p-5 space-y-3", children: [
|
|
2171
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("p", { className: "text-sm text-slate-700 leading-relaxed", children: [
|
|
2172
|
+
"\u05E7\u05D9\u05D9\u05DE\u05EA \u05DB\u05D1\u05E8 \u05E8\u05E9\u05D5\u05DE\u05D4 \u05E2\u05DD \u05D4\u05E2\u05E8\u05DA \u05E9\u05E0\u05D1\u05D7\u05E8 \u05D1\u05E9\u05D3\u05D4",
|
|
2173
|
+
" ",
|
|
2174
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "font-bold text-slate-900 bg-slate-100 px-1.5 py-0.5 rounded border border-slate-200", children: conflictModalState.fieldName }),
|
|
2175
|
+
". \u05D4\u05D0\u05DD \u05EA\u05E8\u05E6\u05D4 \u05DC\u05E7\u05E9\u05E8 \u05D0\u05D5\u05EA\u05D4 \u05DC\u05EA\u05EA-\u05D4\u05D8\u05D1\u05DC\u05D4 \u05D1\u05DE\u05E7\u05D5\u05DD \u05DC\u05D9\u05E6\u05D5\u05E8 \u05D7\u05D3\u05E9\u05D4?"
|
|
2176
|
+
] }),
|
|
2177
|
+
conflictModalState.matchingRecords.length > 1 && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "p-3 bg-blue-50 border border-blue-200 rounded-lg text-xs font-semibold text-blue-800", children: [
|
|
2178
|
+
"\u05E0\u05DE\u05E6\u05D0\u05D5 ",
|
|
2179
|
+
conflictModalState.matchingRecords.length,
|
|
2180
|
+
" \u05E8\u05E9\u05D5\u05DE\u05D5\u05EA \u05E7\u05D9\u05D9\u05DE\u05D5\u05EA. \u05D4\u05D0\u05DD \u05DC\u05E7\u05E9\u05E8 \u05D0\u05EA \u05DB\u05D5\u05DC\u05DF?"
|
|
2181
|
+
] }),
|
|
2182
|
+
conflictModalState.matchingRecords.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "overflow-x-auto border border-slate-200 rounded-lg max-h-48 text-xs bg-white", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("table", { className: "w-full text-right border-collapse", children: [
|
|
2183
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("tr", { className: "bg-slate-100 text-slate-700 font-semibold border-b whitespace-nowrap", children: (targetColumns.length > 0 ? targetColumns.filter((c) => c.name !== "_id" && c.name !== "id") : Object.keys(((_b = conflictModalState.matchingRecords[0]) == null ? void 0 : _b.data) || {}).filter((k) => k !== "_id" && k !== "id").map((name) => ({ name }))).map((col) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
2184
|
+
"th",
|
|
2185
|
+
{
|
|
2186
|
+
className: "bg-slate-100 text-slate-700 font-semibold p-2 border-b whitespace-nowrap",
|
|
2187
|
+
children: col.name
|
|
2188
|
+
},
|
|
2189
|
+
col.name
|
|
2190
|
+
)) }) }),
|
|
2191
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("tbody", { children: conflictModalState.matchingRecords.map((r, idx) => {
|
|
2192
|
+
const cols = targetColumns.length > 0 ? targetColumns.filter((c) => c.name !== "_id" && c.name !== "id") : Object.keys(r.data || {}).filter((k) => k !== "_id" && k !== "id").map((name) => ({ name }));
|
|
2193
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("tr", { className: "hover:bg-slate-50/80 transition-colors", children: cols.map((col) => {
|
|
2194
|
+
var _a2;
|
|
2195
|
+
const rawVal = (_a2 = r.data) == null ? void 0 : _a2[col.name];
|
|
2196
|
+
let displayVal = "-";
|
|
2197
|
+
if (rawVal !== void 0 && rawVal !== null && rawVal !== "") {
|
|
2198
|
+
if (typeof rawVal === "boolean") {
|
|
2199
|
+
displayVal = rawVal ? "\u05DB\u05DF" : "\u05DC\u05D0";
|
|
2200
|
+
} else if (typeof rawVal === "object") {
|
|
2201
|
+
displayVal = Array.isArray(rawVal) ? rawVal.join(", ") : JSON.stringify(rawVal);
|
|
2202
|
+
} else {
|
|
2203
|
+
displayVal = String(rawVal);
|
|
2204
|
+
}
|
|
2205
|
+
}
|
|
2206
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
2207
|
+
"td",
|
|
2208
|
+
{
|
|
2209
|
+
className: "p-2 border-b border-slate-100 whitespace-nowrap text-slate-800",
|
|
2210
|
+
children: displayVal
|
|
2211
|
+
},
|
|
2212
|
+
col.name
|
|
2213
|
+
);
|
|
2214
|
+
}) }, r.id || idx);
|
|
2215
|
+
}) })
|
|
2216
|
+
] }) })
|
|
2217
|
+
] }),
|
|
2218
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "p-4 bg-slate-50 border-t border-slate-100 flex items-center justify-end gap-2.5", children: [
|
|
2219
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
2220
|
+
"button",
|
|
2221
|
+
{
|
|
2222
|
+
type: "button",
|
|
2223
|
+
onClick: handleCancelConflict,
|
|
2224
|
+
className: "px-4 py-2 text-sm font-medium text-slate-700 hover:bg-slate-200/70 rounded-lg border border-slate-300 transition-colors cursor-pointer",
|
|
2225
|
+
children: "\u05D1\u05D9\u05D8\u05D5\u05DC"
|
|
2226
|
+
}
|
|
2227
|
+
),
|
|
2228
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
2229
|
+
"button",
|
|
2230
|
+
{
|
|
2231
|
+
type: "button",
|
|
2232
|
+
onClick: handleConfirmLinkConflict,
|
|
2233
|
+
className: "px-4 py-2 text-sm font-semibold text-white bg-blue-600 hover:bg-blue-700 rounded-lg shadow transition-colors flex items-center gap-1.5 cursor-pointer",
|
|
2234
|
+
children: [
|
|
2235
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M13.828 10.172a4 4 0 00-5.656 0l-4 4a4 4 0 105.656 5.656l1.102-1.101m-.758-4.899a4 4 0 005.656 0l4-4a4 4 0 00-5.656-5.656l-1.1 1.1" }) }),
|
|
2236
|
+
conflictModalState.matchingRecords.length > 1 ? "\u05E7\u05E9\u05E8 \u05D0\u05EA \u05DB\u05D5\u05DC\u05DF" : "\u05E7\u05E9\u05E8 \u05E8\u05E9\u05D5\u05DE\u05D4"
|
|
2237
|
+
]
|
|
2238
|
+
}
|
|
2239
|
+
)
|
|
2240
|
+
] })
|
|
2241
|
+
]
|
|
2242
|
+
}
|
|
2243
|
+
)
|
|
2244
|
+
}
|
|
2245
|
+
)
|
|
2246
|
+
] });
|
|
2247
|
+
}
|
|
2248
|
+
|
|
907
2249
|
// src/components/TableBlock/TableBlockClient.tsx
|
|
908
2250
|
var import_lucide_react4 = require("lucide-react");
|
|
909
|
-
var
|
|
2251
|
+
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
910
2252
|
function TableBlockClient({
|
|
911
2253
|
data: initialRecords,
|
|
912
2254
|
settings: schema,
|
|
@@ -923,14 +2265,14 @@ function TableBlockClient({
|
|
|
923
2265
|
"data-testid": dataTestId
|
|
924
2266
|
}) {
|
|
925
2267
|
const { showError, addToast } = useToast();
|
|
926
|
-
const [columnWidths, setColumnWidths] = (0,
|
|
927
|
-
const [isMounted, setIsMounted] = (0,
|
|
2268
|
+
const [columnWidths, setColumnWidths] = (0, import_react7.useState)({});
|
|
2269
|
+
const [isMounted, setIsMounted] = (0, import_react7.useState)(false);
|
|
928
2270
|
const tableKey = (schema == null ? void 0 : schema.tableMetaId) || (schema == null ? void 0 : schema.tableId) || (schema == null ? void 0 : schema.id) || (schema == null ? void 0 : schema.name) || "default";
|
|
929
|
-
const [page, setPage] = (0,
|
|
930
|
-
const [limit, setLimit] = (0,
|
|
931
|
-
const [totalRecords, setTotalRecords] = (0,
|
|
932
|
-
const [totalPages, setTotalPages] = (0,
|
|
933
|
-
(0,
|
|
2271
|
+
const [page, setPage] = (0, import_react7.useState)(1);
|
|
2272
|
+
const [limit, setLimit] = (0, import_react7.useState)(50);
|
|
2273
|
+
const [totalRecords, setTotalRecords] = (0, import_react7.useState)(0);
|
|
2274
|
+
const [totalPages, setTotalPages] = (0, import_react7.useState)(1);
|
|
2275
|
+
(0, import_react7.useEffect)(() => {
|
|
934
2276
|
if (typeof window !== "undefined") {
|
|
935
2277
|
const savedWidths = localStorage.getItem(`table_widths_${tableKey}`);
|
|
936
2278
|
if (savedWidths) {
|
|
@@ -953,7 +2295,7 @@ function TableBlockClient({
|
|
|
953
2295
|
}
|
|
954
2296
|
setIsMounted(true);
|
|
955
2297
|
}, [tableKey]);
|
|
956
|
-
const [showSummary, setShowSummary] = (0,
|
|
2298
|
+
const [showSummary, setShowSummary] = (0, import_react7.useState)(false);
|
|
957
2299
|
const toggleSummary = () => {
|
|
958
2300
|
setShowSummary((prev) => {
|
|
959
2301
|
const next = !prev;
|
|
@@ -962,8 +2304,8 @@ function TableBlockClient({
|
|
|
962
2304
|
return next;
|
|
963
2305
|
});
|
|
964
2306
|
};
|
|
965
|
-
const [resizingCol, setResizingCol] = (0,
|
|
966
|
-
(0,
|
|
2307
|
+
const [resizingCol, setResizingCol] = (0, import_react7.useState)(null);
|
|
2308
|
+
(0, import_react7.useEffect)(() => {
|
|
967
2309
|
if (!resizingCol) return;
|
|
968
2310
|
const handleMouseMove = (e) => {
|
|
969
2311
|
const diffX = resizingCol.startX - e.clientX;
|
|
@@ -1010,7 +2352,7 @@ function TableBlockClient({
|
|
|
1010
2352
|
return __spreadProps(__spreadValues({}, row), { id: String(row.id || ""), data: rowData });
|
|
1011
2353
|
});
|
|
1012
2354
|
};
|
|
1013
|
-
const mergeColumnDefs = (0,
|
|
2355
|
+
const mergeColumnDefs = (0, import_react7.useCallback)((existingCols, incomingCols) => {
|
|
1014
2356
|
if (!incomingCols || incomingCols.length === 0) return existingCols || [];
|
|
1015
2357
|
if (!existingCols || existingCols.length === 0) return incomingCols;
|
|
1016
2358
|
const existingMap = new Map(existingCols.map((c) => [c.name, c]));
|
|
@@ -1030,18 +2372,18 @@ function TableBlockClient({
|
|
|
1030
2372
|
return ((_a = a.order) != null ? _a : 0) - ((_b = b.order) != null ? _b : 0);
|
|
1031
2373
|
});
|
|
1032
2374
|
}, []);
|
|
1033
|
-
const [localColumns, setLocalColumns] = (0,
|
|
1034
|
-
(0,
|
|
2375
|
+
const [localColumns, setLocalColumns] = (0, import_react7.useState)(() => (schema == null ? void 0 : schema.columns) || []);
|
|
2376
|
+
(0, import_react7.useEffect)(() => {
|
|
1035
2377
|
if ((schema == null ? void 0 : schema.columns) && schema.columns.length > 0) {
|
|
1036
2378
|
setLocalColumns((prev) => mergeColumnDefs(prev, schema.columns));
|
|
1037
2379
|
}
|
|
1038
2380
|
}, [schema == null ? void 0 : schema.columns, mergeColumnDefs]);
|
|
1039
|
-
const [dirty, setDirty] = (0,
|
|
1040
|
-
const dirtyRef = (0,
|
|
1041
|
-
(0,
|
|
2381
|
+
const [dirty, setDirty] = (0, import_react7.useState)({ added: [], modified: {}, deleted: [] });
|
|
2382
|
+
const dirtyRef = (0, import_react7.useRef)(dirty);
|
|
2383
|
+
(0, import_react7.useEffect)(() => {
|
|
1042
2384
|
dirtyRef.current = dirty;
|
|
1043
2385
|
}, [dirty]);
|
|
1044
|
-
const mergeWithDirty = (0,
|
|
2386
|
+
const mergeWithDirty = (0, import_react7.useCallback)((baseRecords) => {
|
|
1045
2387
|
const { added, modified, deleted } = dirtyRef.current;
|
|
1046
2388
|
const nonDeleted = (baseRecords || []).filter((r) => !deleted.includes(r.id));
|
|
1047
2389
|
const modifiedRecords = nonDeleted.map((r) => {
|
|
@@ -1054,8 +2396,8 @@ function TableBlockClient({
|
|
|
1054
2396
|
const uniqueAdded = added.filter((r) => !baseIds.has(r.id));
|
|
1055
2397
|
return [...uniqueAdded, ...modifiedRecords];
|
|
1056
2398
|
}, []);
|
|
1057
|
-
const [data, setData] = (0,
|
|
1058
|
-
(0,
|
|
2399
|
+
const [data, setData] = (0, import_react7.useState)(() => normalizeRecords(initialRecords));
|
|
2400
|
+
(0, import_react7.useEffect)(() => {
|
|
1059
2401
|
if (initialRecords) {
|
|
1060
2402
|
setData(mergeWithDirty(normalizeRecords(initialRecords)));
|
|
1061
2403
|
}
|
|
@@ -1070,19 +2412,19 @@ function TableBlockClient({
|
|
|
1070
2412
|
}
|
|
1071
2413
|
return false;
|
|
1072
2414
|
};
|
|
1073
|
-
const [baseRecordsMap, setBaseRecordsMap] = (0,
|
|
2415
|
+
const [baseRecordsMap, setBaseRecordsMap] = (0, import_react7.useState)(() => {
|
|
1074
2416
|
const map = /* @__PURE__ */ new Map();
|
|
1075
2417
|
(normalizeRecords(initialRecords) || []).forEach((r) => map.set(r.id, __spreadValues({}, r.data)));
|
|
1076
2418
|
return map;
|
|
1077
2419
|
});
|
|
1078
|
-
(0,
|
|
2420
|
+
(0, import_react7.useEffect)(() => {
|
|
1079
2421
|
if (initialRecords && initialRecords.length > 0) {
|
|
1080
2422
|
const map = /* @__PURE__ */ new Map();
|
|
1081
2423
|
(normalizeRecords(initialRecords) || []).forEach((r) => map.set(r.id, __spreadValues({}, r.data)));
|
|
1082
2424
|
setBaseRecordsMap(map);
|
|
1083
2425
|
}
|
|
1084
2426
|
}, [initialRecords]);
|
|
1085
|
-
const refetchTableData = (0,
|
|
2427
|
+
const refetchTableData = (0, import_react7.useCallback)((targetPage) => {
|
|
1086
2428
|
const tableId = (schema == null ? void 0 : schema.tableMetaId) || (schema == null ? void 0 : schema.tableId) || (schema == null ? void 0 : schema.id);
|
|
1087
2429
|
if (!tableId || !executeAction) return Promise.resolve();
|
|
1088
2430
|
const activePage = targetPage !== void 0 ? targetPage : page;
|
|
@@ -1116,8 +2458,8 @@ function TableBlockClient({
|
|
|
1116
2458
|
}).catch((err) => {
|
|
1117
2459
|
console.error("[TableBlock] Failed to auto-fetch table data:", err);
|
|
1118
2460
|
});
|
|
1119
|
-
}, [schema == null ? void 0 : schema.tableMetaId, schema == null ? void 0 : schema.tableId, schema == null ? void 0 : schema.id, page, limit, executeAction,
|
|
1120
|
-
(0,
|
|
2461
|
+
}, [schema == null ? void 0 : schema.tableMetaId, schema == null ? void 0 : schema.tableId, schema == null ? void 0 : schema.id, page, limit, executeAction, mergeColumnDefs]);
|
|
2462
|
+
(0, import_react7.useEffect)(() => {
|
|
1121
2463
|
refetchTableData();
|
|
1122
2464
|
}, [refetchTableData]);
|
|
1123
2465
|
const handleLimitChange = (newLimit) => {
|
|
@@ -1133,19 +2475,20 @@ function TableBlockClient({
|
|
|
1133
2475
|
const handleNextPage = () => {
|
|
1134
2476
|
setPage((prev) => Math.min(totalPages, prev + 1));
|
|
1135
2477
|
};
|
|
1136
|
-
(0,
|
|
2478
|
+
(0, import_react7.useEffect)(() => {
|
|
1137
2479
|
if (error) {
|
|
1138
2480
|
showError(error, "\u05E9\u05D2\u05D9\u05D0\u05D4 \u05D1\u05E8\u05DB\u05D9\u05D1");
|
|
1139
2481
|
}
|
|
1140
2482
|
}, [error, showError]);
|
|
1141
|
-
const [searchQuery, setSearchQuery] = (0,
|
|
1142
|
-
const [selectedIds, setSelectedIds] = (0,
|
|
1143
|
-
const [pendingDeletions, setPendingDeletions] = (0,
|
|
1144
|
-
const [isSaving, setIsSaving] = (0,
|
|
1145
|
-
const [isSaveSuccess, setIsSaveSuccess] = (0,
|
|
1146
|
-
const [relationOptions, setRelationOptions] = (0,
|
|
1147
|
-
const
|
|
1148
|
-
const
|
|
2483
|
+
const [searchQuery, setSearchQuery] = (0, import_react7.useState)("");
|
|
2484
|
+
const [selectedIds, setSelectedIds] = (0, import_react7.useState)(/* @__PURE__ */ new Set());
|
|
2485
|
+
const [pendingDeletions, setPendingDeletions] = (0, import_react7.useState)([]);
|
|
2486
|
+
const [isSaving, setIsSaving] = (0, import_react7.useState)(false);
|
|
2487
|
+
const [isSaveSuccess, setIsSaveSuccess] = (0, import_react7.useState)(false);
|
|
2488
|
+
const [relationOptions, setRelationOptions] = (0, import_react7.useState)({});
|
|
2489
|
+
const [expandedRowIds, setExpandedRowIds] = (0, import_react7.useState)(/* @__PURE__ */ new Set());
|
|
2490
|
+
const schemaColsString = (0, import_react7.useMemo)(() => JSON.stringify(localColumns || []), [localColumns]);
|
|
2491
|
+
const refetchRelation = (0, import_react7.useCallback)(async (colName) => {
|
|
1149
2492
|
var _a;
|
|
1150
2493
|
let parsedCols = [];
|
|
1151
2494
|
try {
|
|
@@ -1165,7 +2508,7 @@ function TableBlockClient({
|
|
|
1165
2508
|
console.warn(`[TableBlock] Could not fetch relation options for column ${colName}:`, err);
|
|
1166
2509
|
}
|
|
1167
2510
|
}, [schemaColsString, executeAction]);
|
|
1168
|
-
(0,
|
|
2511
|
+
(0, import_react7.useEffect)(() => {
|
|
1169
2512
|
let parsedCols = [];
|
|
1170
2513
|
try {
|
|
1171
2514
|
parsedCols = JSON.parse(schemaColsString);
|
|
@@ -1179,7 +2522,7 @@ function TableBlockClient({
|
|
|
1179
2522
|
refetchRelation(col.name);
|
|
1180
2523
|
});
|
|
1181
2524
|
}, [schemaColsString, refetchRelation]);
|
|
1182
|
-
const normalizedColumns = (0,
|
|
2525
|
+
const normalizedColumns = (0, import_react7.useMemo)(() => {
|
|
1183
2526
|
return (localColumns || []).map((col, idx) => {
|
|
1184
2527
|
const isRequired = col.isRequired === true || String(col.isRequired) === "true";
|
|
1185
2528
|
const isUnique = col.isUnique === true || String(col.isUnique) === "true";
|
|
@@ -1193,17 +2536,17 @@ function TableBlockClient({
|
|
|
1193
2536
|
return ((_a = a.order) != null ? _a : 0) - ((_b = b.order) != null ? _b : 0);
|
|
1194
2537
|
});
|
|
1195
2538
|
}, [localColumns]);
|
|
1196
|
-
const filteredColumns = (0,
|
|
2539
|
+
const filteredColumns = (0, import_react7.useMemo)(() => {
|
|
1197
2540
|
const systemFields = ["_id", "createdAt", "updatedAt", "orgId", "tableId"];
|
|
1198
2541
|
return normalizedColumns.filter((col) => !systemFields.includes(col.name) && !col.isHidden);
|
|
1199
2542
|
}, [normalizedColumns]);
|
|
1200
|
-
const customizableColumns = (0,
|
|
2543
|
+
const customizableColumns = (0, import_react7.useMemo)(() => {
|
|
1201
2544
|
const systemFields = ["_id", "createdAt", "updatedAt", "orgId", "tableId"];
|
|
1202
2545
|
return normalizedColumns.filter((col) => !systemFields.includes(col.name));
|
|
1203
2546
|
}, [normalizedColumns]);
|
|
1204
|
-
const [isColumnsDropdownOpen, setIsColumnsDropdownOpen] = (0,
|
|
1205
|
-
const dropdownRef = (0,
|
|
1206
|
-
(0,
|
|
2547
|
+
const [isColumnsDropdownOpen, setIsColumnsDropdownOpen] = (0, import_react7.useState)(false);
|
|
2548
|
+
const dropdownRef = (0, import_react7.useRef)(null);
|
|
2549
|
+
(0, import_react7.useEffect)(() => {
|
|
1207
2550
|
const handleClickOutside = (e) => {
|
|
1208
2551
|
if (dropdownRef.current && !dropdownRef.current.contains(e.target)) {
|
|
1209
2552
|
setIsColumnsDropdownOpen(false);
|
|
@@ -1281,8 +2624,8 @@ function TableBlockClient({
|
|
|
1281
2624
|
}
|
|
1282
2625
|
}
|
|
1283
2626
|
};
|
|
1284
|
-
const [draggedColName, setDraggedColName] = (0,
|
|
1285
|
-
const [dragOverColName, setDragOverColName] = (0,
|
|
2627
|
+
const [draggedColName, setDraggedColName] = (0, import_react7.useState)(null);
|
|
2628
|
+
const [dragOverColName, setDragOverColName] = (0, import_react7.useState)(null);
|
|
1286
2629
|
const handleColumnReorder = async (draggedName, dropTargetName) => {
|
|
1287
2630
|
var _a;
|
|
1288
2631
|
if (draggedName === dropTargetName) return;
|
|
@@ -1324,6 +2667,10 @@ function TableBlockClient({
|
|
|
1324
2667
|
var _a;
|
|
1325
2668
|
const typeUpper = (_a = col.type) == null ? void 0 : _a.toUpperCase();
|
|
1326
2669
|
let initialValue = col.defaultValue;
|
|
2670
|
+
if (typeUpper === "SUB_TABLE") {
|
|
2671
|
+
defaultData[col.name] = [];
|
|
2672
|
+
return;
|
|
2673
|
+
}
|
|
1327
2674
|
if (initialValue !== void 0 && initialValue !== null && initialValue !== "") {
|
|
1328
2675
|
if (typeUpper === "CURRENCY" || typeUpper === "NUMBER") {
|
|
1329
2676
|
initialValue = parseFloat(initialValue);
|
|
@@ -1407,6 +2754,36 @@ function TableBlockClient({
|
|
|
1407
2754
|
});
|
|
1408
2755
|
}
|
|
1409
2756
|
};
|
|
2757
|
+
const triggerSaveSuccess = (0, import_react7.useCallback)(() => {
|
|
2758
|
+
setIsSaveSuccess(true);
|
|
2759
|
+
setTimeout(() => {
|
|
2760
|
+
setIsSaveSuccess(false);
|
|
2761
|
+
}, 2500);
|
|
2762
|
+
}, []);
|
|
2763
|
+
const handleQuietCellChange = (0, import_react7.useCallback)((rowId, colName, value) => {
|
|
2764
|
+
setData((prev) => prev.map(
|
|
2765
|
+
(row) => row.id === rowId ? __spreadProps(__spreadValues({}, row), { data: __spreadProps(__spreadValues({}, row.data), { [colName]: value }) }) : row
|
|
2766
|
+
));
|
|
2767
|
+
if (rowId.startsWith("temp_")) {
|
|
2768
|
+
setDirty((prev) => {
|
|
2769
|
+
if (!prev.added.some((r) => r.id === rowId)) return prev;
|
|
2770
|
+
return __spreadProps(__spreadValues({}, prev), {
|
|
2771
|
+
added: prev.added.map(
|
|
2772
|
+
(r) => r.id === rowId ? __spreadProps(__spreadValues({}, r), { data: __spreadProps(__spreadValues({}, r.data), { [colName]: value }) }) : r
|
|
2773
|
+
)
|
|
2774
|
+
});
|
|
2775
|
+
});
|
|
2776
|
+
} else {
|
|
2777
|
+
setBaseRecordsMap((prev) => {
|
|
2778
|
+
const next = new Map(prev);
|
|
2779
|
+
const rowData = next.get(rowId);
|
|
2780
|
+
if (rowData) {
|
|
2781
|
+
next.set(rowId, __spreadProps(__spreadValues({}, rowData), { [colName]: value }));
|
|
2782
|
+
}
|
|
2783
|
+
return next;
|
|
2784
|
+
});
|
|
2785
|
+
}
|
|
2786
|
+
}, []);
|
|
1410
2787
|
const toggleSelectAll = (checked) => {
|
|
1411
2788
|
const nextSelected = checked ? new Set(filteredData.map((r) => r.id)) : /* @__PURE__ */ new Set();
|
|
1412
2789
|
setSelectedIds(nextSelected);
|
|
@@ -1436,9 +2813,15 @@ function TableBlockClient({
|
|
|
1436
2813
|
const row = data.find((r) => r.id === id);
|
|
1437
2814
|
if (row) {
|
|
1438
2815
|
driveCols.forEach((col) => {
|
|
1439
|
-
const
|
|
1440
|
-
if (
|
|
1441
|
-
|
|
2816
|
+
const fileVal = row.data[col.name];
|
|
2817
|
+
if (Array.isArray(fileVal)) {
|
|
2818
|
+
fileVal.forEach((fileObj) => {
|
|
2819
|
+
if (fileObj && fileObj.fileId) {
|
|
2820
|
+
filesToDelete.push(fileObj.fileId);
|
|
2821
|
+
}
|
|
2822
|
+
});
|
|
2823
|
+
} else if (fileVal && fileVal.fileId) {
|
|
2824
|
+
filesToDelete.push(fileVal.fileId);
|
|
1442
2825
|
}
|
|
1443
2826
|
});
|
|
1444
2827
|
}
|
|
@@ -1465,7 +2848,7 @@ function TableBlockClient({
|
|
|
1465
2848
|
const formatPayload = (payload) => {
|
|
1466
2849
|
const formatted = {};
|
|
1467
2850
|
(localColumns || []).forEach((col) => {
|
|
1468
|
-
var _a;
|
|
2851
|
+
var _a, _b, _c;
|
|
1469
2852
|
if (["_id", "id", "createdAt", "updatedAt", "orgId", "tableId", "isSelected"].includes(col.name)) return;
|
|
1470
2853
|
let val = payload[col.name];
|
|
1471
2854
|
if (val !== void 0) {
|
|
@@ -1475,6 +2858,13 @@ function TableBlockClient({
|
|
|
1475
2858
|
if (((_a = col.type) == null ? void 0 : _a.toUpperCase()) === "NUMBER") {
|
|
1476
2859
|
val = val === "" ? 0 : Number(val);
|
|
1477
2860
|
if (isNaN(val)) val = 0;
|
|
2861
|
+
} else if (((_b = col.type) == null ? void 0 : _b.toUpperCase()) === "PHONE") {
|
|
2862
|
+
val = sanitizePhoneNumber(String(val));
|
|
2863
|
+
} else if (((_c = col.type) == null ? void 0 : _c.toUpperCase()) === "SUB_TABLE" && Array.isArray(val)) {
|
|
2864
|
+
val = val.map((item) => {
|
|
2865
|
+
const _a2 = item, { _resolvedData } = _a2, rest = __objRest(_a2, ["_resolvedData"]);
|
|
2866
|
+
return rest;
|
|
2867
|
+
});
|
|
1478
2868
|
}
|
|
1479
2869
|
formatted[col.name] = val;
|
|
1480
2870
|
}
|
|
@@ -1484,7 +2874,7 @@ function TableBlockClient({
|
|
|
1484
2874
|
};
|
|
1485
2875
|
const hasChanges = dirty.added.length > 0 || Object.keys(dirty.modified).length > 0 || dirty.deleted.length > 0;
|
|
1486
2876
|
const handleSave = async () => {
|
|
1487
|
-
var _a;
|
|
2877
|
+
var _a, _b;
|
|
1488
2878
|
if (!hasChanges) {
|
|
1489
2879
|
return;
|
|
1490
2880
|
}
|
|
@@ -1507,6 +2897,28 @@ function TableBlockClient({
|
|
|
1507
2897
|
}
|
|
1508
2898
|
}
|
|
1509
2899
|
}
|
|
2900
|
+
const phoneCols = (localColumns || []).filter((c) => {
|
|
2901
|
+
var _a2;
|
|
2902
|
+
return ((_a2 = c.type) == null ? void 0 : _a2.toUpperCase()) === "PHONE";
|
|
2903
|
+
});
|
|
2904
|
+
for (const col of phoneCols) {
|
|
2905
|
+
for (const row of dirty.added) {
|
|
2906
|
+
const val = row.data[col.name];
|
|
2907
|
+
if (!isEmpty(val) && !isValidPhoneNumber(val)) {
|
|
2908
|
+
showError(`\u05DE\u05E1\u05E4\u05E8 \u05D4\u05D8\u05DC\u05E4\u05D5\u05DF \u05D1\u05E9\u05D3\u05D4 "${col.name}" \u05D0\u05D9\u05E0\u05D5 \u05EA\u05E7\u05D9\u05DF. \u05D9\u05E9 \u05DC\u05D4\u05D6\u05D9\u05DF \u05DE\u05E1\u05E4\u05E8 \u05D1\u05D0\u05D5\u05E8\u05DA 9-15 \u05E1\u05E4\u05E8\u05D5\u05EA (\u05DC\u05D3\u05D5\u05D2\u05DE\u05D4 0501234567 \u05D0\u05D5 +972501234567).`, "\u05E9\u05D2\u05D9\u05D0\u05D4 \u05D1\u05D5\u05D5\u05DC\u05D9\u05D3\u05E6\u05D9\u05D4");
|
|
2909
|
+
return;
|
|
2910
|
+
}
|
|
2911
|
+
}
|
|
2912
|
+
for (const [rowId, mods] of Object.entries(dirty.modified)) {
|
|
2913
|
+
const rowData = ((_b = data.find((r) => r.id === rowId)) == null ? void 0 : _b.data) || {};
|
|
2914
|
+
const mergedData = __spreadValues(__spreadValues({}, rowData), mods);
|
|
2915
|
+
const val = mergedData[col.name];
|
|
2916
|
+
if (!isEmpty(val) && !isValidPhoneNumber(val)) {
|
|
2917
|
+
showError(`\u05DE\u05E1\u05E4\u05E8 \u05D4\u05D8\u05DC\u05E4\u05D5\u05DF \u05D1\u05E9\u05D3\u05D4 "${col.name}" \u05D0\u05D9\u05E0\u05D5 \u05EA\u05E7\u05D9\u05DF. \u05D9\u05E9 \u05DC\u05D4\u05D6\u05D9\u05DF \u05DE\u05E1\u05E4\u05E8 \u05D1\u05D0\u05D5\u05E8\u05DA 9-15 \u05E1\u05E4\u05E8\u05D5\u05EA (\u05DC\u05D3\u05D5\u05D2\u05DE\u05D4 0501234567 \u05D0\u05D5 +972501234567).`, "\u05E9\u05D2\u05D9\u05D0\u05D4 \u05D1\u05D5\u05D5\u05DC\u05D9\u05D3\u05E6\u05D9\u05D4");
|
|
2918
|
+
return;
|
|
2919
|
+
}
|
|
2920
|
+
}
|
|
2921
|
+
}
|
|
1510
2922
|
setIsSaving(true);
|
|
1511
2923
|
try {
|
|
1512
2924
|
if (!executeAction) {
|
|
@@ -1607,7 +3019,7 @@ function TableBlockClient({
|
|
|
1607
3019
|
setIsSaving(false);
|
|
1608
3020
|
}
|
|
1609
3021
|
};
|
|
1610
|
-
const filteredData = (0,
|
|
3022
|
+
const filteredData = (0, import_react7.useMemo)(() => {
|
|
1611
3023
|
if (!searchQuery) return data;
|
|
1612
3024
|
const lowerQuery = searchQuery.toLowerCase();
|
|
1613
3025
|
return data.filter(
|
|
@@ -1618,7 +3030,7 @@ function TableBlockClient({
|
|
|
1618
3030
|
}, [data, searchQuery]);
|
|
1619
3031
|
const isUpdatingActive = Boolean(isUpdating || isSaving);
|
|
1620
3032
|
const errorMessage = error ? typeof error === "string" ? error : error.message || String(error) : null;
|
|
1621
|
-
const columnTotals = (0,
|
|
3033
|
+
const columnTotals = (0, import_react7.useMemo)(() => {
|
|
1622
3034
|
const totals = {};
|
|
1623
3035
|
if (!showSummary) return totals;
|
|
1624
3036
|
filteredColumns.forEach((col) => {
|
|
@@ -1636,7 +3048,7 @@ function TableBlockClient({
|
|
|
1636
3048
|
});
|
|
1637
3049
|
return totals;
|
|
1638
3050
|
}, [filteredData, filteredColumns, showSummary]);
|
|
1639
|
-
return /* @__PURE__ */ (0,
|
|
3051
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
1640
3052
|
"div",
|
|
1641
3053
|
{
|
|
1642
3054
|
id: componentId,
|
|
@@ -1644,34 +3056,34 @@ function TableBlockClient({
|
|
|
1644
3056
|
className: `flex flex-col w-full bg-white border border-slate-200 rounded-xl shadow-xs min-h-[350px] overflow-hidden ${className}`,
|
|
1645
3057
|
dir: "rtl",
|
|
1646
3058
|
children: [
|
|
1647
|
-
errorMessage && /* @__PURE__ */ (0,
|
|
1648
|
-
/* @__PURE__ */ (0,
|
|
1649
|
-
/* @__PURE__ */ (0,
|
|
3059
|
+
errorMessage && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "p-3 bg-rose-50 border-b border-rose-200 text-rose-700 text-sm flex items-center justify-between", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
3060
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("svg", { className: "w-4 h-4 text-rose-500 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" }) }),
|
|
3061
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { children: errorMessage })
|
|
1650
3062
|
] }) }),
|
|
1651
|
-
/* @__PURE__ */ (0,
|
|
1652
|
-
/* @__PURE__ */ (0,
|
|
1653
|
-
((schema == null ? void 0 : schema.title) || (schema == null ? void 0 : schema.name)) && /* @__PURE__ */ (0,
|
|
1654
|
-
/* @__PURE__ */ (0,
|
|
3063
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "flex flex-wrap items-center justify-between gap-3 p-3.5 sm:p-4 bg-slate-50 border-b border-slate-200", children: [
|
|
3064
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "flex flex-wrap items-center gap-2.5", children: [
|
|
3065
|
+
((schema == null ? void 0 : schema.title) || (schema == null ? void 0 : schema.name)) && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "font-bold text-slate-800 text-sm sm:text-base border-l border-slate-300 pl-3 ml-1", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { children: schema.title || schema.name }) }),
|
|
3066
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1655
3067
|
"button",
|
|
1656
3068
|
{
|
|
1657
3069
|
onClick: handleAddRow,
|
|
1658
3070
|
disabled: isLoading || isUpdatingActive,
|
|
1659
3071
|
className: "w-9 h-9 bg-emerald-600 hover:bg-emerald-700 active:bg-emerald-800 text-white rounded-lg shadow-xs flex items-center justify-center transition-all disabled:opacity-40 disabled:pointer-events-none cursor-pointer",
|
|
1660
3072
|
title: "\u05D4\u05D5\u05E1\u05E3 \u05E9\u05D5\u05E8\u05D4 \u05D7\u05D3\u05E9\u05D4",
|
|
1661
|
-
children: /* @__PURE__ */ (0,
|
|
3073
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("svg", { className: "w-4.5 h-4.5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2.5", d: "M12 4v16m8-8H4" }) })
|
|
1662
3074
|
}
|
|
1663
3075
|
),
|
|
1664
|
-
/* @__PURE__ */ (0,
|
|
3076
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1665
3077
|
"button",
|
|
1666
3078
|
{
|
|
1667
3079
|
onClick: handleDuplicateRow,
|
|
1668
3080
|
disabled: isLoading || isUpdatingActive || selectedIds.size !== 1,
|
|
1669
3081
|
className: "w-9 h-9 bg-blue-50 hover:bg-blue-100 border border-blue-200 text-blue-700 rounded-lg shadow-2xs flex items-center justify-center transition-all disabled:opacity-40 disabled:pointer-events-none cursor-pointer",
|
|
1670
3082
|
title: "\u05E9\u05DB\u05E4\u05DC \u05E9\u05D5\u05E8\u05D4 \u05E0\u05D1\u05D7\u05E8\u05EA",
|
|
1671
|
-
children: /* @__PURE__ */ (0,
|
|
3083
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_lucide_react4.Copy, { className: "w-4 h-4 text-blue-600 shrink-0" })
|
|
1672
3084
|
}
|
|
1673
3085
|
),
|
|
1674
|
-
/* @__PURE__ */ (0,
|
|
3086
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
1675
3087
|
"button",
|
|
1676
3088
|
{
|
|
1677
3089
|
onClick: handleDeleteSelected,
|
|
@@ -1679,12 +3091,12 @@ function TableBlockClient({
|
|
|
1679
3091
|
className: "w-9 h-9 bg-rose-50 hover:bg-rose-100 border border-rose-200 text-rose-700 rounded-lg shadow-2xs flex items-center justify-center relative transition-all disabled:opacity-40 disabled:pointer-events-none cursor-pointer",
|
|
1680
3092
|
title: "\u05DE\u05D7\u05E7 \u05E9\u05D5\u05E8\u05D5\u05EA \u05E0\u05D1\u05D7\u05E8\u05D5\u05EA",
|
|
1681
3093
|
children: [
|
|
1682
|
-
/* @__PURE__ */ (0,
|
|
1683
|
-
selectedIds.size > 0 && /* @__PURE__ */ (0,
|
|
3094
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("svg", { className: "w-4.5 h-4.5 text-rose-600 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" }) }),
|
|
3095
|
+
selectedIds.size > 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "absolute -top-1.5 -right-1.5 bg-rose-600 text-white min-w-[18px] h-[18px] px-1 rounded-full text-[10px] font-bold flex items-center justify-center shadow-xs", children: selectedIds.size })
|
|
1684
3096
|
]
|
|
1685
3097
|
}
|
|
1686
3098
|
),
|
|
1687
|
-
/* @__PURE__ */ (0,
|
|
3099
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
1688
3100
|
"button",
|
|
1689
3101
|
{
|
|
1690
3102
|
onClick: toggleSummary,
|
|
@@ -1692,13 +3104,13 @@ function TableBlockClient({
|
|
|
1692
3104
|
className: `h-9 px-3 border font-semibold rounded-lg shadow-2xs flex items-center gap-1.5 text-xs transition-all disabled:opacity-40 disabled:pointer-events-none cursor-pointer ${showSummary ? "bg-indigo-50 border-indigo-200 text-indigo-700 hover:bg-indigo-100" : "bg-white border-slate-300 text-slate-700 hover:bg-slate-100"}`,
|
|
1693
3105
|
title: "\u05D4\u05E6\u05D2/\u05D4\u05E1\u05EA\u05E8 \u05E9\u05D5\u05E8\u05EA \u05E1\u05D9\u05DB\u05D5\u05DD",
|
|
1694
3106
|
children: [
|
|
1695
|
-
/* @__PURE__ */ (0,
|
|
1696
|
-
/* @__PURE__ */ (0,
|
|
3107
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("svg", { className: "w-4 h-4 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M4 6h16M4 10h16M4 14h16M4 18h16" }) }),
|
|
3108
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "hidden sm:inline", children: "\u05E1\u05DB\u05D9\u05DE\u05D4" })
|
|
1697
3109
|
]
|
|
1698
3110
|
}
|
|
1699
3111
|
),
|
|
1700
|
-
/* @__PURE__ */ (0,
|
|
1701
|
-
/* @__PURE__ */ (0,
|
|
3112
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "relative", ref: dropdownRef, children: [
|
|
3113
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
1702
3114
|
"button",
|
|
1703
3115
|
{
|
|
1704
3116
|
onClick: () => setIsColumnsDropdownOpen((prev) => !prev),
|
|
@@ -1706,16 +3118,16 @@ function TableBlockClient({
|
|
|
1706
3118
|
className: "h-9 px-3 bg-white hover:bg-slate-100 border border-slate-300 text-slate-700 font-semibold rounded-lg shadow-2xs flex items-center gap-1.5 text-xs transition-all disabled:opacity-40 disabled:pointer-events-none cursor-pointer",
|
|
1707
3119
|
title: "\u05D4\u05E6\u05D2/\u05D4\u05E1\u05EA\u05E8 \u05E2\u05DE\u05D5\u05D3\u05D5\u05EA",
|
|
1708
3120
|
children: [
|
|
1709
|
-
/* @__PURE__ */ (0,
|
|
1710
|
-
/* @__PURE__ */ (0,
|
|
3121
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("svg", { className: "w-4 h-4 text-slate-600 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M9 17V7m0 10a2 2 0 01-2 2H5a2 2 0 01-2-2V7a2 2 0 012-2h2a2 2 0 012 2m0 10a2 2 0 002 2h2a2 2 0 002-2M9 7a2 2 0 012-2h2a2 2 0 012 2m0 10V7m0 10a2 2 0 002 2h2a2 2 0 002-2V7a2 2 0 00-2-2h-2a2 2 0 00-2 2" }) }),
|
|
3122
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("svg", { className: `w-3.5 h-3.5 text-slate-500 transition-transform ${isColumnsDropdownOpen ? "rotate-180" : ""}`, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M19 9l-7 7-7-7" }) })
|
|
1711
3123
|
]
|
|
1712
3124
|
}
|
|
1713
3125
|
),
|
|
1714
|
-
isColumnsDropdownOpen && /* @__PURE__ */ (0,
|
|
1715
|
-
/* @__PURE__ */ (0,
|
|
1716
|
-
/* @__PURE__ */ (0,
|
|
1717
|
-
/* @__PURE__ */ (0,
|
|
1718
|
-
/* @__PURE__ */ (0,
|
|
3126
|
+
isColumnsDropdownOpen && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "absolute right-0 top-full mt-1.5 w-56 bg-white border border-slate-200 rounded-xl shadow-xl z-50 p-1.5 dir-rtl animate-in fade-in slide-in-from-top-2 duration-150", children: [
|
|
3127
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "px-2 py-1.5 text-xs font-bold text-slate-500 border-b border-slate-100 mb-1 flex items-center justify-between", children: [
|
|
3128
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "flex items-center gap-1.5", children: [
|
|
3129
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { children: "\u05D4\u05E6\u05D2\u05EA \u05E2\u05DE\u05D5\u05D3\u05D5\u05EA" }),
|
|
3130
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "text-[10px] font-normal text-slate-400", children: [
|
|
1719
3131
|
"(",
|
|
1720
3132
|
customizableColumns.filter((c) => !c.isHidden).length,
|
|
1721
3133
|
"/",
|
|
@@ -1723,7 +3135,7 @@ function TableBlockClient({
|
|
|
1723
3135
|
")"
|
|
1724
3136
|
] })
|
|
1725
3137
|
] }),
|
|
1726
|
-
/* @__PURE__ */ (0,
|
|
3138
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1727
3139
|
"button",
|
|
1728
3140
|
{
|
|
1729
3141
|
type: "button",
|
|
@@ -1733,7 +3145,7 @@ function TableBlockClient({
|
|
|
1733
3145
|
}
|
|
1734
3146
|
)
|
|
1735
3147
|
] }),
|
|
1736
|
-
/* @__PURE__ */ (0,
|
|
3148
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "max-h-60 overflow-y-auto space-y-0.5", children: customizableColumns.map((col) => {
|
|
1737
3149
|
const isRequired = col.isRequired === true || String(col.isRequired) === "true";
|
|
1738
3150
|
const isUnique = col.isUnique === true || String(col.isUnique) === "true";
|
|
1739
3151
|
const isProtected = isRequired || isUnique;
|
|
@@ -1747,7 +3159,7 @@ function TableBlockClient({
|
|
|
1747
3159
|
protectedExplanation = "\u05E9\u05D3\u05D4 \u05D9\u05D9\u05D7\u05D5\u05D3\u05D9 - \u05DC\u05D0 \u05E0\u05D9\u05EA\u05DF \u05DC\u05D4\u05D5\u05E8\u05D9\u05D3 \u05E2\u05DE\u05D5\u05D3\u05D4 \u05D6\u05D5 \u05DE\u05D4\u05EA\u05E6\u05D5\u05D2\u05D4";
|
|
1748
3160
|
}
|
|
1749
3161
|
const badgeLabel = isRequired && isUnique ? "\u05D7\u05D5\u05D1\u05D4 + \u05D9\u05D9\u05D7\u05D5\u05D3\u05D9" : isRequired ? "\u05E9\u05D3\u05D4 \u05D7\u05D5\u05D1\u05D4" : "\u05E9\u05D3\u05D4 \u05D9\u05D9\u05D7\u05D5\u05D3\u05D9";
|
|
1750
|
-
return /* @__PURE__ */ (0,
|
|
3162
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
1751
3163
|
"div",
|
|
1752
3164
|
{
|
|
1753
3165
|
onClick: () => {
|
|
@@ -1758,8 +3170,8 @@ function TableBlockClient({
|
|
|
1758
3170
|
title: isProtected ? protectedExplanation : void 0,
|
|
1759
3171
|
className: `group flex items-center justify-between px-2.5 py-1.5 rounded-lg text-xs transition-colors select-none ${isProtected ? "opacity-75 bg-slate-50 border border-slate-100/70 cursor-not-allowed" : "hover:bg-slate-100 active:bg-slate-200 cursor-pointer"}`,
|
|
1760
3172
|
children: [
|
|
1761
|
-
/* @__PURE__ */ (0,
|
|
1762
|
-
/* @__PURE__ */ (0,
|
|
3173
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "flex items-center gap-2 min-w-0", children: [
|
|
3174
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1763
3175
|
"input",
|
|
1764
3176
|
{
|
|
1765
3177
|
type: "checkbox",
|
|
@@ -1770,16 +3182,16 @@ function TableBlockClient({
|
|
|
1770
3182
|
className: "w-3.5 h-3.5 rounded border-slate-300 text-brand focus:ring-brand/20 cursor-pointer disabled:cursor-not-allowed disabled:opacity-60"
|
|
1771
3183
|
}
|
|
1772
3184
|
),
|
|
1773
|
-
/* @__PURE__ */ (0,
|
|
3185
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: `font-medium truncate ${isProtected ? "text-slate-500" : "text-slate-700"}`, children: col.name })
|
|
1774
3186
|
] }),
|
|
1775
|
-
isProtected && /* @__PURE__ */ (0,
|
|
3187
|
+
isProtected && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
1776
3188
|
"div",
|
|
1777
3189
|
{
|
|
1778
3190
|
className: "flex items-center gap-1 px-1.5 py-0.5 rounded text-[10px] font-semibold bg-amber-50 text-amber-800 border border-amber-200/80 cursor-help",
|
|
1779
3191
|
title: protectedExplanation,
|
|
1780
3192
|
children: [
|
|
1781
|
-
/* @__PURE__ */ (0,
|
|
1782
|
-
/* @__PURE__ */ (0,
|
|
3193
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("svg", { className: "w-3 h-3 text-amber-600 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: "2.2", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z" }) }),
|
|
3194
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { children: badgeLabel })
|
|
1783
3195
|
]
|
|
1784
3196
|
}
|
|
1785
3197
|
)
|
|
@@ -1790,9 +3202,9 @@ function TableBlockClient({
|
|
|
1790
3202
|
}) })
|
|
1791
3203
|
] })
|
|
1792
3204
|
] }),
|
|
1793
|
-
/* @__PURE__ */ (0,
|
|
1794
|
-
/* @__PURE__ */ (0,
|
|
1795
|
-
/* @__PURE__ */ (0,
|
|
3205
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "h-5 w-px bg-slate-300 mx-1 hidden sm:block" }),
|
|
3206
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "relative flex-1 sm:w-64 max-w-xs", children: [
|
|
3207
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1796
3208
|
"input",
|
|
1797
3209
|
{
|
|
1798
3210
|
placeholder: "\u05D7\u05D9\u05E4\u05D5\u05E9 \u05D1\u05E8\u05E9\u05D5\u05DE\u05D5\u05EA...",
|
|
@@ -1802,45 +3214,45 @@ function TableBlockClient({
|
|
|
1802
3214
|
className: "w-full h-9 px-3 pr-9 text-xs border border-slate-300 rounded-lg bg-white shadow-2xs focus:outline-none focus:ring-2 focus:ring-blue-500/20 focus:border-blue-500 text-slate-800 disabled:opacity-50"
|
|
1803
3215
|
}
|
|
1804
3216
|
),
|
|
1805
|
-
searchQuery ? /* @__PURE__ */ (0,
|
|
3217
|
+
searchQuery ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1806
3218
|
"button",
|
|
1807
3219
|
{
|
|
1808
3220
|
type: "button",
|
|
1809
3221
|
onClick: () => setSearchQuery(""),
|
|
1810
3222
|
className: "absolute right-2.5 top-2.5 text-slate-400 hover:text-slate-600 transition-colors p-0.5 rounded-full hover:bg-slate-100 cursor-pointer",
|
|
1811
3223
|
title: "Clear search",
|
|
1812
|
-
children: /* @__PURE__ */ (0,
|
|
3224
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_lucide_react4.X, { className: "w-3.5 h-3.5" })
|
|
1813
3225
|
}
|
|
1814
|
-
) : /* @__PURE__ */ (0,
|
|
3226
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("svg", { className: "w-4 h-4 text-slate-400 absolute right-2.5 top-2.5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" }) })
|
|
1815
3227
|
] })
|
|
1816
3228
|
] }),
|
|
1817
|
-
/* @__PURE__ */ (0,
|
|
1818
|
-
isUpdatingActive ? /* @__PURE__ */ (0,
|
|
1819
|
-
/* @__PURE__ */ (0,
|
|
3229
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "flex items-center gap-3", children: [
|
|
3230
|
+
isUpdatingActive ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "text-xs text-blue-600 font-semibold flex items-center gap-1.5 bg-blue-50 border border-blue-200 px-3 py-1.5 rounded-lg animate-pulse", children: [
|
|
3231
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "w-2 h-2 rounded-full bg-blue-500 inline-block" }),
|
|
1820
3232
|
"\u05DE\u05E2\u05D3\u05DB\u05DF..."
|
|
1821
|
-
] }) : isSaveSuccess ? /* @__PURE__ */ (0,
|
|
1822
|
-
/* @__PURE__ */ (0,
|
|
3233
|
+
] }) : isSaveSuccess ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "text-xs text-emerald-700 font-semibold flex items-center gap-1.5 bg-emerald-50 border border-emerald-200 px-3 py-1.5 rounded-lg animate-in fade-in duration-200", children: [
|
|
3234
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("svg", { className: "w-4 h-4 text-emerald-600 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2.5", d: "M5 13l4 4L19 7" }) }),
|
|
1823
3235
|
"\u05E2\u05D5\u05D3\u05DB\u05DF \u05D1\u05D4\u05E6\u05DC\u05D7\u05D4"
|
|
1824
|
-
] }) : hasChanges ? /* @__PURE__ */ (0,
|
|
1825
|
-
/* @__PURE__ */ (0,
|
|
3236
|
+
] }) : hasChanges ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "text-xs font-semibold text-amber-700 animate-in fade-in", children: "\u05E9\u05D9\u05E0\u05D5\u05D9\u05D9\u05DD \u05E9\u05DC\u05D0 \u05E0\u05E9\u05DE\u05E8\u05D5" }) : null,
|
|
3237
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1826
3238
|
"button",
|
|
1827
3239
|
{
|
|
1828
3240
|
onClick: handleSave,
|
|
1829
3241
|
disabled: isUpdatingActive || isLoading || !hasChanges,
|
|
1830
3242
|
className: `h-9 px-4 text-xs font-bold rounded-lg shadow-2xs transition-all flex items-center justify-center cursor-pointer ${hasChanges && !isUpdatingActive && !isLoading ? "bg-brand hover:bg-brand-hover active:bg-[#00897b] text-white shadow-teal-500/20" : "opacity-50 grayscale bg-slate-200 text-slate-400 cursor-not-allowed"}`,
|
|
1831
|
-
children: /* @__PURE__ */ (0,
|
|
3243
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { children: isUpdatingActive ? "\u05E9\u05D5\u05DE\u05E8..." : "\u05E9\u05DE\u05D9\u05E8\u05EA \u05E9\u05D9\u05E0\u05D5\u05D9\u05D9\u05DD" })
|
|
1832
3244
|
}
|
|
1833
3245
|
)
|
|
1834
3246
|
] })
|
|
1835
3247
|
] }),
|
|
1836
|
-
/* @__PURE__ */ (0,
|
|
1837
|
-
isLoading && /* @__PURE__ */ (0,
|
|
1838
|
-
/* @__PURE__ */ (0,
|
|
1839
|
-
/* @__PURE__ */ (0,
|
|
3248
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: `overflow-x-auto relative min-h-[260px] flex-1 transition-opacity duration-200 ${isMounted ? "opacity-100" : "opacity-0"}`, children: [
|
|
3249
|
+
isLoading && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "absolute inset-0 bg-white/80 backdrop-blur-xs z-20 flex flex-col items-center justify-center gap-2", children: [
|
|
3250
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "w-6 h-6 border-2 border-brand border-t-transparent rounded-full animate-spin" }),
|
|
3251
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "text-sm font-medium text-slate-600", children: "\u05D8\u05D5\u05E2\u05DF \u05E0\u05EA\u05D5\u05E0\u05D9\u05DD..." })
|
|
1840
3252
|
] }),
|
|
1841
|
-
/* @__PURE__ */ (0,
|
|
1842
|
-
/* @__PURE__ */ (0,
|
|
1843
|
-
/* @__PURE__ */ (0,
|
|
3253
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("table", { className: "w-full text-sm text-right border-collapse table-auto", children: [
|
|
3254
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("thead", { className: "bg-slate-100/80 text-slate-700 sticky top-0 z-10", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("tr", { children: [
|
|
3255
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("th", { className: "border-b border-l border-slate-200 p-2.5 w-10 text-center shrink-0", style: { width: 50, minWidth: 50, maxWidth: 50 }, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1844
3256
|
"input",
|
|
1845
3257
|
{
|
|
1846
3258
|
type: "checkbox",
|
|
@@ -1854,7 +3266,7 @@ function TableBlockClient({
|
|
|
1854
3266
|
const isDragging = draggedColName === col.name;
|
|
1855
3267
|
const isDragOver = dragOverColName === col.name;
|
|
1856
3268
|
const currentWidth = columnWidths[col.name] || 200;
|
|
1857
|
-
return /* @__PURE__ */ (0,
|
|
3269
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
1858
3270
|
"th",
|
|
1859
3271
|
{
|
|
1860
3272
|
style: { width: currentWidth, minWidth: currentWidth, maxWidth: currentWidth },
|
|
@@ -1890,7 +3302,7 @@ function TableBlockClient({
|
|
|
1890
3302
|
},
|
|
1891
3303
|
className: `relative border-b border-l border-slate-200 px-4 py-2.5 font-semibold text-slate-700 whitespace-nowrap select-none cursor-grab active:cursor-grabbing transition-colors ${isDragging ? "opacity-40 bg-slate-200 border-dashed border-2 border-brand" : ""} ${isDragOver ? "bg-blue-50 border-r-4 border-r-brand text-brand font-bold" : "hover:bg-slate-200/60"}`,
|
|
1892
3304
|
children: [
|
|
1893
|
-
/* @__PURE__ */ (0,
|
|
3305
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1894
3306
|
"div",
|
|
1895
3307
|
{
|
|
1896
3308
|
onMouseDown: (e) => {
|
|
@@ -1902,16 +3314,16 @@ function TableBlockClient({
|
|
|
1902
3314
|
title: "\u05E9\u05E0\u05D4 \u05D2\u05D5\u05D3\u05DC \u05E2\u05DE\u05D5\u05D3\u05D4"
|
|
1903
3315
|
}
|
|
1904
3316
|
),
|
|
1905
|
-
/* @__PURE__ */ (0,
|
|
1906
|
-
/* @__PURE__ */ (0,
|
|
1907
|
-
/* @__PURE__ */ (0,
|
|
3317
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "flex items-center justify-between gap-2 group overflow-hidden", title: "\u05D2\u05E8\u05D5\u05E8 \u05DC\u05E9\u05D9\u05E0\u05D5\u05D9 \u05E1\u05D3\u05E8 \u05D4\u05E2\u05DE\u05D5\u05D3\u05D4", children: [
|
|
3318
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "truncate", children: col.name }),
|
|
3319
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1908
3320
|
"svg",
|
|
1909
3321
|
{
|
|
1910
3322
|
className: "w-3.5 h-3.5 text-slate-400 opacity-40 group-hover:opacity-100 transition-opacity shrink-0 cursor-grab",
|
|
1911
3323
|
fill: "none",
|
|
1912
3324
|
viewBox: "0 0 24 24",
|
|
1913
3325
|
stroke: "currentColor",
|
|
1914
|
-
children: /* @__PURE__ */ (0,
|
|
3326
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M8 9h.01M8 15h.01M16 9h.01M16 15h.01" })
|
|
1915
3327
|
}
|
|
1916
3328
|
)
|
|
1917
3329
|
] })
|
|
@@ -1920,59 +3332,112 @@ function TableBlockClient({
|
|
|
1920
3332
|
col.name
|
|
1921
3333
|
);
|
|
1922
3334
|
}),
|
|
1923
|
-
/* @__PURE__ */ (0,
|
|
3335
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("th", { className: "w-full min-w-[50px] border-b border-slate-200 pointer-events-none" })
|
|
1924
3336
|
] }) }),
|
|
1925
|
-
/* @__PURE__ */ (0,
|
|
1926
|
-
/* @__PURE__ */ (0,
|
|
1927
|
-
/* @__PURE__ */ (0,
|
|
1928
|
-
] }) }) }) : filteredData.map((row) =>
|
|
1929
|
-
|
|
1930
|
-
"input",
|
|
1931
|
-
{
|
|
1932
|
-
type: "checkbox",
|
|
1933
|
-
checked: selectedIds.has(row.id),
|
|
1934
|
-
onChange: (e) => toggleSelectRow(row.id, e.target.checked),
|
|
1935
|
-
disabled: isLoading || isUpdatingActive,
|
|
1936
|
-
className: "w-4 h-4 rounded border-slate-300 text-brand"
|
|
1937
|
-
}
|
|
1938
|
-
) }),
|
|
1939
|
-
filteredColumns.map((col) => {
|
|
3337
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("tbody", { className: "bg-white", children: (isStateEmpty || filteredData.length === 0) && !isLoading ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("tr", { children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("td", { colSpan: filteredColumns.length + 2, className: "text-center py-12 text-slate-400", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "flex flex-col items-center justify-center gap-2", children: [
|
|
3338
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("svg", { className: "w-8 h-8 text-slate-300", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "1.5", d: "M20 13V6a2 2 0 00-2-2H6a2 2 0 00-2 2v7m16 0v5a2 2 0 01-2 2H6a2 2 0 01-2-2v-5m16 0h-2.586a1 1 0 00-.707.293l-2.414 2.414a1 1 0 01-.707.293h-3.172a1 1 0 01-.707-.293l-2.414-2.414A1 1 0 006.586 13H4" }) }),
|
|
3339
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { children: "\u05D0\u05D9\u05DF \u05E8\u05E9\u05D5\u05DE\u05D5\u05EA \u05DC\u05D4\u05E6\u05D2\u05D4." })
|
|
3340
|
+
] }) }) }) : filteredData.map((row) => {
|
|
3341
|
+
const hasSubTableCols = filteredColumns.some((c) => {
|
|
1940
3342
|
var _a;
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
3343
|
+
return ((_a = c.type) == null ? void 0 : _a.toUpperCase()) === "SUB_TABLE";
|
|
3344
|
+
});
|
|
3345
|
+
const isExpanded = expandedRowIds.has(row.id);
|
|
3346
|
+
const subTableColumns = filteredColumns.filter((c) => {
|
|
3347
|
+
var _a;
|
|
3348
|
+
return ((_a = c.type) == null ? void 0 : _a.toUpperCase()) === "SUB_TABLE";
|
|
3349
|
+
});
|
|
3350
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_react7.default.Fragment, { children: [
|
|
3351
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("tr", { className: "hover:bg-blue-50/30 transition-colors group", children: [
|
|
3352
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("td", { className: "border-b border-l border-slate-200 p-1.5 text-center bg-white group-hover:bg-transparent", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "flex items-center justify-center gap-1", children: [
|
|
3353
|
+
hasSubTableCols && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
3354
|
+
"button",
|
|
3355
|
+
{
|
|
3356
|
+
type: "button",
|
|
3357
|
+
onClick: () => setExpandedRowIds((prev) => {
|
|
3358
|
+
const next = new Set(prev);
|
|
3359
|
+
if (next.has(row.id)) next.delete(row.id);
|
|
3360
|
+
else next.add(row.id);
|
|
3361
|
+
return next;
|
|
3362
|
+
}),
|
|
3363
|
+
className: "text-slate-400 hover:text-blue-600 p-0.5 rounded transition-colors cursor-pointer",
|
|
3364
|
+
title: isExpanded ? "\u05E1\u05D2\u05D5\u05E8 \u05EA\u05EA-\u05D8\u05D1\u05DC\u05D4" : "\u05E4\u05EA\u05D7 \u05EA\u05EA-\u05D8\u05D1\u05DC\u05D4",
|
|
3365
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("svg", { className: `w-3.5 h-3.5 transition-transform duration-150 ${isExpanded ? "rotate-90" : ""}`, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M9 5l7 7-7 7" }) })
|
|
3366
|
+
}
|
|
3367
|
+
),
|
|
3368
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
3369
|
+
"input",
|
|
3370
|
+
{
|
|
3371
|
+
type: "checkbox",
|
|
3372
|
+
checked: selectedIds.has(row.id),
|
|
3373
|
+
onChange: (e) => toggleSelectRow(row.id, e.target.checked),
|
|
3374
|
+
disabled: isLoading || isUpdatingActive,
|
|
3375
|
+
className: "w-4 h-4 rounded border-slate-300 text-brand"
|
|
3376
|
+
}
|
|
3377
|
+
)
|
|
3378
|
+
] }) }),
|
|
3379
|
+
filteredColumns.map((col) => {
|
|
3380
|
+
var _a;
|
|
3381
|
+
const colType = ((_a = col.type) == null ? void 0 : _a.toUpperCase()) || "DEFAULT";
|
|
3382
|
+
const InputComponent = FORM_INPUTS[colType] || FORM_INPUTS.DEFAULT;
|
|
3383
|
+
let value = (row == null ? void 0 : row.data) ? row.data[col.name] : void 0;
|
|
3384
|
+
if (value === void 0 && col.defaultValue !== void 0) {
|
|
3385
|
+
value = colType === "CURRENCY" || colType === "NUMBER" ? parseFloat(col.defaultValue) : col.defaultValue;
|
|
3386
|
+
if (colType === "CURRENCY" || colType === "NUMBER") {
|
|
3387
|
+
if (isNaN(value)) value = null;
|
|
3388
|
+
}
|
|
3389
|
+
}
|
|
3390
|
+
if (value === void 0) value = null;
|
|
3391
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("td", { className: "border-b border-l border-slate-200 p-0 relative", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
3392
|
+
InputComponent,
|
|
3393
|
+
{
|
|
3394
|
+
value,
|
|
3395
|
+
column: col,
|
|
3396
|
+
rowId: row.id,
|
|
3397
|
+
onChange: (v) => handleCellChange(row.id, col.name, v),
|
|
3398
|
+
context: {
|
|
3399
|
+
tableName: (schema == null ? void 0 : schema.name) || (schema == null ? void 0 : schema.tableName) || (schema == null ? void 0 : schema.title) || (schema == null ? void 0 : schema.id) || "Table",
|
|
3400
|
+
tableId: (schema == null ? void 0 : schema.tableMetaId) || (schema == null ? void 0 : schema.tableId) || (schema == null ? void 0 : schema.id),
|
|
3401
|
+
onMarkForDeletion: (fileId) => setPendingDeletions((prev) => [...prev, fileId]),
|
|
3402
|
+
relationOptions,
|
|
3403
|
+
refetchRelation,
|
|
3404
|
+
executeAction,
|
|
3405
|
+
emitEvent,
|
|
3406
|
+
pageState,
|
|
3407
|
+
componentId,
|
|
3408
|
+
orgId,
|
|
3409
|
+
updateQuietly: handleQuietCellChange,
|
|
3410
|
+
triggerSaveSuccess,
|
|
3411
|
+
rowData: row.data
|
|
3412
|
+
}
|
|
3413
|
+
}
|
|
3414
|
+
) }, col.name);
|
|
3415
|
+
}),
|
|
3416
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("td", { className: "border-b border-slate-200 bg-white pointer-events-none" })
|
|
3417
|
+
] }),
|
|
3418
|
+
isExpanded && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
3419
|
+
ExpandedSubTables,
|
|
1953
3420
|
{
|
|
1954
|
-
value,
|
|
1955
|
-
column: col,
|
|
1956
3421
|
rowId: row.id,
|
|
1957
|
-
|
|
3422
|
+
rowData: row.data,
|
|
3423
|
+
subTableColumns,
|
|
3424
|
+
filteredColumnsLength: filteredColumns.length,
|
|
3425
|
+
handleCellChange,
|
|
1958
3426
|
context: {
|
|
1959
|
-
tableName: (schema == null ? void 0 : schema.name) || (schema == null ? void 0 : schema.tableName) || (schema == null ? void 0 : schema.title) || (schema == null ? void 0 : schema.id) || "Table",
|
|
1960
|
-
onMarkForDeletion: (fileId) => setPendingDeletions((prev) => [...prev, fileId]),
|
|
1961
|
-
relationOptions,
|
|
1962
|
-
refetchRelation,
|
|
1963
3427
|
executeAction,
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
3428
|
+
orgId,
|
|
3429
|
+
parentTableId: (schema == null ? void 0 : schema.tableMetaId) || (schema == null ? void 0 : schema.tableId) || (schema == null ? void 0 : schema.id),
|
|
3430
|
+
tableId: (schema == null ? void 0 : schema.tableMetaId) || (schema == null ? void 0 : schema.tableId) || (schema == null ? void 0 : schema.id),
|
|
3431
|
+
rowData: row.data,
|
|
3432
|
+
updateQuietly: handleQuietCellChange,
|
|
3433
|
+
triggerSaveSuccess
|
|
1968
3434
|
}
|
|
1969
3435
|
}
|
|
1970
|
-
)
|
|
1971
|
-
})
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("td", { className: "border-b border-l border-slate-200 p-1.5 text-center font-bold text-slate-600 text-xs", children: '\u05E1\u05D4"\u05DB' }),
|
|
3436
|
+
)
|
|
3437
|
+
] }, row.id);
|
|
3438
|
+
}) }),
|
|
3439
|
+
showSummary && filteredData.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("tfoot", { className: "bg-slate-50 border-t-2 border-slate-300 sticky bottom-0 z-10 shadow-[0_-2px_4px_rgba(0,0,0,0.02)]", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("tr", { children: [
|
|
3440
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("td", { className: "border-b border-l border-slate-200 p-1.5 text-center font-bold text-slate-600 text-xs", children: '\u05E1\u05D4"\u05DB' }),
|
|
1976
3441
|
filteredColumns.map((col) => {
|
|
1977
3442
|
var _a;
|
|
1978
3443
|
const typeUpper = (_a = col.type) == null ? void 0 : _a.toUpperCase();
|
|
@@ -1986,16 +3451,16 @@ function TableBlockClient({
|
|
|
1986
3451
|
displayVal = symbol ? `${symbol} ${displayVal}` : displayVal;
|
|
1987
3452
|
}
|
|
1988
3453
|
}
|
|
1989
|
-
return /* @__PURE__ */ (0,
|
|
3454
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("td", { className: "border-b border-l border-slate-200 p-2 text-sm font-semibold text-slate-700 bg-slate-50 relative", children: isNumeric && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "flex items-center text-right justify-start", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "truncate", children: displayVal }) }) }, col.name);
|
|
1990
3455
|
}),
|
|
1991
|
-
/* @__PURE__ */ (0,
|
|
3456
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("td", { className: "border-b border-slate-200 bg-slate-50 pointer-events-none" })
|
|
1992
3457
|
] }) })
|
|
1993
3458
|
] })
|
|
1994
3459
|
] }),
|
|
1995
|
-
/* @__PURE__ */ (0,
|
|
1996
|
-
/* @__PURE__ */ (0,
|
|
1997
|
-
/* @__PURE__ */ (0,
|
|
1998
|
-
/* @__PURE__ */ (0,
|
|
3460
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "flex flex-col sm:flex-row items-center justify-between gap-3 px-4 py-3 bg-slate-50 border-t border-slate-200 text-xs text-slate-600 rounded-b-xl", children: [
|
|
3461
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
3462
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "font-medium text-slate-700", children: "\u05E9\u05D5\u05E8\u05D5\u05EA \u05DC\u05E2\u05DE\u05D5\u05D3:" }),
|
|
3463
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
1999
3464
|
"select",
|
|
2000
3465
|
{
|
|
2001
3466
|
value: limit,
|
|
@@ -2003,27 +3468,27 @@ function TableBlockClient({
|
|
|
2003
3468
|
disabled: isLoading || isUpdatingActive,
|
|
2004
3469
|
className: "bg-white border border-slate-300 rounded-lg px-2.5 py-1 text-slate-700 font-semibold shadow-2xs cursor-pointer focus:outline-none focus:ring-2 focus:ring-brand disabled:opacity-50",
|
|
2005
3470
|
children: [
|
|
2006
|
-
/* @__PURE__ */ (0,
|
|
2007
|
-
/* @__PURE__ */ (0,
|
|
2008
|
-
/* @__PURE__ */ (0,
|
|
3471
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("option", { value: 20, children: "20" }),
|
|
3472
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("option", { value: 50, children: "50" }),
|
|
3473
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("option", { value: 100, children: "100" })
|
|
2009
3474
|
]
|
|
2010
3475
|
}
|
|
2011
3476
|
)
|
|
2012
3477
|
] }),
|
|
2013
|
-
/* @__PURE__ */ (0,
|
|
2014
|
-
/* @__PURE__ */ (0,
|
|
3478
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "flex items-center gap-4", children: [
|
|
3479
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "font-medium text-slate-600", children: [
|
|
2015
3480
|
"\u05E2\u05DE\u05D5\u05D3 ",
|
|
2016
|
-
/* @__PURE__ */ (0,
|
|
3481
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("strong", { className: "text-slate-900", children: page }),
|
|
2017
3482
|
" \u05DE\u05EA\u05D5\u05DA ",
|
|
2018
|
-
/* @__PURE__ */ (0,
|
|
2019
|
-
totalRecords > 0 && /* @__PURE__ */ (0,
|
|
3483
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("strong", { className: "text-slate-900", children: totalPages || 1 }),
|
|
3484
|
+
totalRecords > 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "text-slate-500 font-normal", children: [
|
|
2020
3485
|
" (",
|
|
2021
3486
|
totalRecords,
|
|
2022
3487
|
' \u05E8\u05E9\u05D5\u05DE\u05D5\u05EA \u05D1\u05E1\u05D4"\u05DB)'
|
|
2023
3488
|
] })
|
|
2024
3489
|
] }),
|
|
2025
|
-
/* @__PURE__ */ (0,
|
|
2026
|
-
/* @__PURE__ */ (0,
|
|
3490
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "flex items-center gap-1.5", children: [
|
|
3491
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2027
3492
|
"button",
|
|
2028
3493
|
{
|
|
2029
3494
|
onClick: handlePrevPage,
|
|
@@ -2033,7 +3498,7 @@ function TableBlockClient({
|
|
|
2033
3498
|
children: "\u05D4\u05E7\u05D5\u05D3\u05DD"
|
|
2034
3499
|
}
|
|
2035
3500
|
),
|
|
2036
|
-
/* @__PURE__ */ (0,
|
|
3501
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2037
3502
|
"button",
|
|
2038
3503
|
{
|
|
2039
3504
|
onClick: handleNextPage,
|
|
@@ -2050,11 +3515,60 @@ function TableBlockClient({
|
|
|
2050
3515
|
}
|
|
2051
3516
|
);
|
|
2052
3517
|
}
|
|
3518
|
+
function ExpandedSubTables({
|
|
3519
|
+
rowId,
|
|
3520
|
+
rowData,
|
|
3521
|
+
subTableColumns,
|
|
3522
|
+
filteredColumnsLength,
|
|
3523
|
+
handleCellChange,
|
|
3524
|
+
context
|
|
3525
|
+
}) {
|
|
3526
|
+
var _a;
|
|
3527
|
+
const [activeTab, setActiveTab] = (0, import_react7.useState)((_a = subTableColumns[0]) == null ? void 0 : _a.name);
|
|
3528
|
+
if (subTableColumns.length === 0) return null;
|
|
3529
|
+
if (subTableColumns.length === 1) {
|
|
3530
|
+
const stCol = subTableColumns[0];
|
|
3531
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("tr", { children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("td", { colSpan: filteredColumnsLength + 2, className: "p-0 border-b border-slate-200 bg-slate-50/50", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
3532
|
+
SubTableViewer,
|
|
3533
|
+
{
|
|
3534
|
+
rowId,
|
|
3535
|
+
column: stCol,
|
|
3536
|
+
value: (rowData == null ? void 0 : rowData[stCol.name]) || [],
|
|
3537
|
+
onChange: (newVal) => handleCellChange(rowId, stCol.name, newVal),
|
|
3538
|
+
context
|
|
3539
|
+
}
|
|
3540
|
+
) }) });
|
|
3541
|
+
}
|
|
3542
|
+
const activeCol = subTableColumns.find((c) => c.name === activeTab) || subTableColumns[0];
|
|
3543
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("tr", { children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("td", { colSpan: filteredColumnsLength + 2, className: "p-0 border-b border-slate-200 bg-slate-50/50 overflow-hidden", children: [
|
|
3544
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "flex border-b border-slate-200 bg-slate-100/50 px-2 pt-2 gap-1 overflow-hidden", children: subTableColumns.map((col) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
3545
|
+
"button",
|
|
3546
|
+
{
|
|
3547
|
+
type: "button",
|
|
3548
|
+
onClick: () => setActiveTab(col.name),
|
|
3549
|
+
className: `px-4 py-2 text-sm font-semibold rounded-t-lg transition-colors whitespace-nowrap cursor-pointer relative top-[1px] ${activeTab === col.name ? "bg-white border border-slate-200 border-b-transparent text-brand" : "bg-transparent border border-transparent text-slate-500 hover:text-slate-700 hover:bg-slate-200/50"}`,
|
|
3550
|
+
children: col.name
|
|
3551
|
+
},
|
|
3552
|
+
col.name
|
|
3553
|
+
)) }),
|
|
3554
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "bg-white", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
3555
|
+
SubTableViewer,
|
|
3556
|
+
{
|
|
3557
|
+
rowId,
|
|
3558
|
+
column: activeCol,
|
|
3559
|
+
value: (rowData == null ? void 0 : rowData[activeCol.name]) || [],
|
|
3560
|
+
onChange: (newVal) => handleCellChange(rowId, activeCol.name, newVal),
|
|
3561
|
+
context
|
|
3562
|
+
},
|
|
3563
|
+
activeCol.name
|
|
3564
|
+
) })
|
|
3565
|
+
] }) });
|
|
3566
|
+
}
|
|
2053
3567
|
|
|
2054
3568
|
// src/components/TableBlock/TableBlock.tsx
|
|
2055
|
-
var
|
|
3569
|
+
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
2056
3570
|
function TableBlock(props) {
|
|
2057
|
-
return /* @__PURE__ */ (0,
|
|
3571
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(TableBlockClient, __spreadValues({}, props));
|
|
2058
3572
|
}
|
|
2059
3573
|
|
|
2060
3574
|
// src/registry.ts
|
|
@@ -2068,5 +3582,7 @@ var UNIVERSE_COMPONENTS = {
|
|
|
2068
3582
|
ToastProvider,
|
|
2069
3583
|
UNIVERSE_COMPONENTS,
|
|
2070
3584
|
cn,
|
|
3585
|
+
formatPhoneDisplay,
|
|
3586
|
+
openWhatsAppChat,
|
|
2071
3587
|
useToast
|
|
2072
3588
|
});
|