@universe-platform/ui 0.1.0-beta.7 → 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 +136 -3
- package/dist/index.d.mts +21 -2
- package/dist/index.d.ts +21 -2
- package/dist/index.js +768 -103
- package/dist/index.mjs +763 -100
- 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,6 +78,36 @@ 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
112
|
var import_react7 = __toESM(require("react"));
|
|
81
113
|
|
|
@@ -927,16 +959,35 @@ var FORM_INPUTS = {
|
|
|
927
959
|
}
|
|
928
960
|
}
|
|
929
961
|
),
|
|
930
|
-
PHONE: ({ value, onChange }) =>
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
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
|
+
},
|
|
940
991
|
GOOGLE_CONTACT: ({ value, column, rowId, onChange, context }) => {
|
|
941
992
|
const [isSyncing, setIsSyncing] = import_react5.default.useState(false);
|
|
942
993
|
const { addToast } = useToast();
|
|
@@ -1120,31 +1171,33 @@ var FORM_INPUTS = {
|
|
|
1120
1171
|
}
|
|
1121
1172
|
};
|
|
1122
1173
|
if (value && value.synced && value.url) {
|
|
1123
|
-
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "flex items-center gap-
|
|
1124
|
-
/* @__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-
|
|
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" }),
|
|
1125
1176
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1126
1177
|
"button",
|
|
1127
1178
|
{
|
|
1179
|
+
type: "button",
|
|
1128
1180
|
onClick: handleUnlink,
|
|
1129
|
-
className: "text-slate-400 hover:text-rose-500 opacity-0 group-hover:opacity-100 transition-opacity p-1",
|
|
1181
|
+
className: "text-slate-400 hover:text-rose-500 opacity-0 group-hover:opacity-100 transition-opacity p-1 shrink-0",
|
|
1130
1182
|
title: "\u05D1\u05D8\u05DC \u05E1\u05E0\u05DB\u05E8\u05D5\u05DF",
|
|
1131
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { className: "w-
|
|
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" }) })
|
|
1132
1184
|
}
|
|
1133
1185
|
)
|
|
1134
1186
|
] });
|
|
1135
1187
|
}
|
|
1136
|
-
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "flex items-center h-8 px-2", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
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)(
|
|
1137
1189
|
"button",
|
|
1138
1190
|
{
|
|
1191
|
+
type: "button",
|
|
1139
1192
|
onClick: handleSync,
|
|
1140
1193
|
disabled: isSyncing,
|
|
1141
|
-
className: "flex items-center gap-1.5 px-
|
|
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",
|
|
1142
1195
|
children: [
|
|
1143
|
-
isSyncing ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("svg", { className: "w-3.5 h-3.5 animate-spin", viewBox: "0 0 24 24", fill: "none", 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: [
|
|
1144
1197
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("circle", { className: "opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4" }),
|
|
1145
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" })
|
|
1146
|
-
] }) : /* @__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: "M12 4v16m8-8H4" }) }),
|
|
1147
|
-
"\u05E1\u05E0\u05DB\u05E8\u05DF \u05DC\u05D2\u05D5\u05D2\u05DC"
|
|
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" })
|
|
1148
1201
|
]
|
|
1149
1202
|
}
|
|
1150
1203
|
) });
|
|
@@ -1159,17 +1212,48 @@ var FORM_INPUTS = {
|
|
|
1159
1212
|
}
|
|
1160
1213
|
),
|
|
1161
1214
|
SUB_TABLE: ({ value, column }) => {
|
|
1215
|
+
var _a, _b;
|
|
1162
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" });
|
|
1163
1217
|
const selected = value.filter((e) => e == null ? void 0 : e.isSelected);
|
|
1164
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" });
|
|
1165
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;
|
|
1166
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) => {
|
|
1167
|
-
var
|
|
1223
|
+
var _a2, _b2;
|
|
1168
1224
|
let label = "";
|
|
1169
|
-
if (entry._resolvedData
|
|
1170
|
-
|
|
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
|
+
}
|
|
1171
1256
|
}
|
|
1172
|
-
if (!label) label = ((_a = entry.recordId) == null ? void 0 : _a.slice(-6)) || "...";
|
|
1173
1257
|
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1174
1258
|
"span",
|
|
1175
1259
|
{
|
|
@@ -1185,12 +1269,241 @@ var FORM_INPUTS = {
|
|
|
1185
1269
|
|
|
1186
1270
|
// src/components/TableBlock/fields/SubTableViewer.tsx
|
|
1187
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
|
|
1188
1288
|
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
1189
|
-
function
|
|
1289
|
+
function validateCellValue(val, col) {
|
|
1190
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;
|
|
1191
1494
|
const { addToast } = useToast();
|
|
1192
1495
|
const entries = Array.isArray(value) ? value : [];
|
|
1193
|
-
const [linkedRecords, setLinkedRecords] = (0, import_react6.useState)(
|
|
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
|
+
});
|
|
1194
1507
|
const [targetSchema, setTargetSchema] = (0, import_react6.useState)(null);
|
|
1195
1508
|
const [isLoading, setIsLoading] = (0, import_react6.useState)(true);
|
|
1196
1509
|
const [isSearchOpen, setIsSearchOpen] = (0, import_react6.useState)(false);
|
|
@@ -1199,11 +1512,31 @@ function SubTableViewer({ rowId, column, value, onChange, context }) {
|
|
|
1199
1512
|
const [isSearching, setIsSearching] = (0, import_react6.useState)(false);
|
|
1200
1513
|
const [isCreating, setIsCreating] = (0, import_react6.useState)(false);
|
|
1201
1514
|
const [newRecordData, setNewRecordData] = (0, import_react6.useState)({});
|
|
1515
|
+
const [conflictModalState, setConflictModalState] = (0, import_react6.useState)({
|
|
1516
|
+
isOpen: false,
|
|
1517
|
+
fieldName: "",
|
|
1518
|
+
matchingRecords: []
|
|
1519
|
+
});
|
|
1202
1520
|
const searchRef = (0, import_react6.useRef)(null);
|
|
1203
1521
|
const searchTimerRef = (0, import_react6.useRef)(null);
|
|
1204
1522
|
const executeAction = context == null ? void 0 : context.executeAction;
|
|
1205
1523
|
const referencedTableId = column.referencedTableId;
|
|
1206
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]);
|
|
1207
1540
|
(0, import_react6.useEffect)(() => {
|
|
1208
1541
|
if (!referencedTableId || !executeAction) {
|
|
1209
1542
|
setIsLoading(false);
|
|
@@ -1329,20 +1662,102 @@ function SubTableViewer({ rowId, column, value, onChange, context }) {
|
|
|
1329
1662
|
}
|
|
1330
1663
|
}
|
|
1331
1664
|
};
|
|
1332
|
-
const
|
|
1333
|
-
|
|
1334
|
-
const
|
|
1335
|
-
const
|
|
1336
|
-
|
|
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);
|
|
1337
1693
|
setLinkedRecords((prev) => {
|
|
1338
|
-
const
|
|
1339
|
-
|
|
1340
|
-
|
|
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());
|
|
1341
1706
|
});
|
|
1342
1707
|
setSearchQuery("");
|
|
1343
1708
|
setSearchResults([]);
|
|
1344
1709
|
setIsSearchOpen(false);
|
|
1345
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
|
+
};
|
|
1346
1761
|
const handleUnlinkRecord = (recordId) => {
|
|
1347
1762
|
const updated = entries.filter((e) => e.recordId !== recordId);
|
|
1348
1763
|
updateParentLinkage(updated);
|
|
@@ -1355,37 +1770,94 @@ function SubTableViewer({ rowId, column, value, onChange, context }) {
|
|
|
1355
1770
|
);
|
|
1356
1771
|
updateParentLinkage(updated);
|
|
1357
1772
|
};
|
|
1358
|
-
const
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
)
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
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;
|
|
1371
1793
|
}
|
|
1372
1794
|
if (executeAction && referencedTableId && !recordId.startsWith("temp_")) {
|
|
1373
1795
|
try {
|
|
1374
|
-
await executeAction("UPDATE_RECORD", {
|
|
1796
|
+
const res = await executeAction("UPDATE_RECORD", {
|
|
1375
1797
|
tableId: referencedTableId,
|
|
1376
1798
|
recordId,
|
|
1377
1799
|
data: { [colName]: value2 }
|
|
1378
1800
|
});
|
|
1379
|
-
if (
|
|
1380
|
-
|
|
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
|
+
}
|
|
1381
1823
|
}
|
|
1824
|
+
return true;
|
|
1382
1825
|
} catch (err) {
|
|
1383
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;
|
|
1384
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;
|
|
1385
1856
|
}
|
|
1386
1857
|
};
|
|
1858
|
+
const handleRecordCellChange = handleCommitRecordCell;
|
|
1387
1859
|
const handleCreateRecord = async () => {
|
|
1388
|
-
var _a2;
|
|
1860
|
+
var _a2, _b2, _c, _d, _e;
|
|
1389
1861
|
if (!executeAction || !referencedTableId) return;
|
|
1390
1862
|
for (const col of targetColumns) {
|
|
1391
1863
|
if (col.isRequired) {
|
|
@@ -1398,16 +1870,30 @@ function SubTableViewer({ rowId, column, value, onChange, context }) {
|
|
|
1398
1870
|
return;
|
|
1399
1871
|
}
|
|
1400
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
|
+
}
|
|
1401
1883
|
}
|
|
1402
1884
|
try {
|
|
1403
1885
|
const res = await executeAction("CREATE_RECORD", {
|
|
1404
1886
|
tableId: referencedTableId,
|
|
1405
1887
|
records: [newRecordData]
|
|
1406
1888
|
});
|
|
1889
|
+
if (res && (res.error === "UNIQUE_CONSTRAINT_CONFLICT" || res.code === "UNIQUE_CONSTRAINT_CONFLICT")) {
|
|
1890
|
+
handleUniqueConflict(res);
|
|
1891
|
+
return;
|
|
1892
|
+
}
|
|
1407
1893
|
if (res && res.success === false) {
|
|
1408
1894
|
throw new Error(res.error || "Action execution failed");
|
|
1409
1895
|
}
|
|
1410
|
-
const created = Array.isArray(res) ? res[0] : ((
|
|
1896
|
+
const created = Array.isArray(res) ? res[0] : ((_b2 = res == null ? void 0 : res.data) == null ? void 0 : _b2[0]) || res;
|
|
1411
1897
|
if (created) {
|
|
1412
1898
|
const newRecord = {
|
|
1413
1899
|
id: String(created.id || created._id),
|
|
@@ -1418,6 +1904,12 @@ function SubTableViewer({ rowId, column, value, onChange, context }) {
|
|
|
1418
1904
|
setNewRecordData({});
|
|
1419
1905
|
}
|
|
1420
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
|
+
}
|
|
1421
1913
|
const msg = (err == null ? void 0 : err.message) || String(err);
|
|
1422
1914
|
addToast({
|
|
1423
1915
|
type: "error",
|
|
@@ -1504,11 +1996,23 @@ function SubTableViewer({ rowId, column, value, onChange, context }) {
|
|
|
1504
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: [
|
|
1505
1997
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("tr", { className: "bg-slate-100/80", children: [
|
|
1506
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" }),
|
|
1507
|
-
targetColumns.map((col) =>
|
|
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
|
+
}),
|
|
1508
2011
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("th", { className: "border border-slate-200 px-2 py-1.5 w-14" })
|
|
1509
2012
|
] }) }),
|
|
1510
2013
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("tbody", { children: [
|
|
1511
2014
|
entries.map((entry) => {
|
|
2015
|
+
var _a2;
|
|
1512
2016
|
const record = linkedRecords.find((r) => r.id === entry.recordId);
|
|
1513
2017
|
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("tr", { className: "hover:bg-blue-50/30 transition-colors", children: [
|
|
1514
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)(
|
|
@@ -1521,61 +2025,101 @@ function SubTableViewer({ rowId, column, value, onChange, context }) {
|
|
|
1521
2025
|
}
|
|
1522
2026
|
) }),
|
|
1523
2027
|
targetColumns.map((col) => {
|
|
1524
|
-
var
|
|
1525
|
-
const
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
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,
|
|
1529
2042
|
{
|
|
1530
|
-
|
|
2043
|
+
record,
|
|
1531
2044
|
column: col,
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
context
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
updateQuietly: (rid, colName, val) => handleRecordCellChange(rid, colName, val)
|
|
1543
|
-
})
|
|
1544
|
-
}
|
|
1545
|
-
) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "text-slate-300 italic px-2", children: "\u05D8\u05D5\u05E2\u05DF..." }) }, col.name);
|
|
2045
|
+
targetSchema,
|
|
2046
|
+
referencedTableId,
|
|
2047
|
+
context,
|
|
2048
|
+
relationOptions,
|
|
2049
|
+
setRelationOptions,
|
|
2050
|
+
refetchRelation,
|
|
2051
|
+
onCommit: handleCommitRecordCell
|
|
2052
|
+
},
|
|
2053
|
+
`${record.id}_${col.name}`
|
|
2054
|
+
);
|
|
1546
2055
|
}),
|
|
1547
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("td", { className: "border border-slate-200 px-1 py-1 text-center", children: /* @__PURE__ */ (0, import_jsx_runtime5.
|
|
1548
|
-
"
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
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
|
+
] }) })
|
|
1557
2092
|
] }, entry.recordId);
|
|
1558
2093
|
}),
|
|
1559
2094
|
isCreating && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("tr", { className: "bg-emerald-50/40", children: [
|
|
1560
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" }) }),
|
|
1561
2096
|
targetColumns.map((col) => {
|
|
1562
|
-
var _a2,
|
|
2097
|
+
var _a2, _b2;
|
|
1563
2098
|
const colType = ((_a2 = col.type) == null ? void 0 : _a2.toUpperCase()) || "DEFAULT";
|
|
1564
2099
|
const InputComponent = FORM_INPUTS[colType] || FORM_INPUTS.DEFAULT;
|
|
1565
|
-
|
|
1566
|
-
|
|
2100
|
+
const isContact = colType === "GOOGLE_CONTACT";
|
|
2101
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
2102
|
+
"td",
|
|
1567
2103
|
{
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
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
|
+
);
|
|
1579
2123
|
}),
|
|
1580
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: [
|
|
1581
2125
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
@@ -1603,7 +2147,102 @@ function SubTableViewer({ rowId, column, value, onChange, context }) {
|
|
|
1603
2147
|
] }) })
|
|
1604
2148
|
] })
|
|
1605
2149
|
] })
|
|
1606
|
-
] }) })
|
|
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
|
+
)
|
|
1607
2246
|
] });
|
|
1608
2247
|
}
|
|
1609
2248
|
|
|
@@ -2209,7 +2848,7 @@ function TableBlockClient({
|
|
|
2209
2848
|
const formatPayload = (payload) => {
|
|
2210
2849
|
const formatted = {};
|
|
2211
2850
|
(localColumns || []).forEach((col) => {
|
|
2212
|
-
var _a, _b;
|
|
2851
|
+
var _a, _b, _c;
|
|
2213
2852
|
if (["_id", "id", "createdAt", "updatedAt", "orgId", "tableId", "isSelected"].includes(col.name)) return;
|
|
2214
2853
|
let val = payload[col.name];
|
|
2215
2854
|
if (val !== void 0) {
|
|
@@ -2219,7 +2858,9 @@ function TableBlockClient({
|
|
|
2219
2858
|
if (((_a = col.type) == null ? void 0 : _a.toUpperCase()) === "NUMBER") {
|
|
2220
2859
|
val = val === "" ? 0 : Number(val);
|
|
2221
2860
|
if (isNaN(val)) val = 0;
|
|
2222
|
-
} else if (((_b = col.type) == null ? void 0 : _b.toUpperCase()) === "
|
|
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)) {
|
|
2223
2864
|
val = val.map((item) => {
|
|
2224
2865
|
const _a2 = item, { _resolvedData } = _a2, rest = __objRest(_a2, ["_resolvedData"]);
|
|
2225
2866
|
return rest;
|
|
@@ -2233,7 +2874,7 @@ function TableBlockClient({
|
|
|
2233
2874
|
};
|
|
2234
2875
|
const hasChanges = dirty.added.length > 0 || Object.keys(dirty.modified).length > 0 || dirty.deleted.length > 0;
|
|
2235
2876
|
const handleSave = async () => {
|
|
2236
|
-
var _a;
|
|
2877
|
+
var _a, _b;
|
|
2237
2878
|
if (!hasChanges) {
|
|
2238
2879
|
return;
|
|
2239
2880
|
}
|
|
@@ -2256,6 +2897,28 @@ function TableBlockClient({
|
|
|
2256
2897
|
}
|
|
2257
2898
|
}
|
|
2258
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
|
+
}
|
|
2259
2922
|
setIsSaving(true);
|
|
2260
2923
|
try {
|
|
2261
2924
|
if (!executeAction) {
|
|
@@ -2919,5 +3582,7 @@ var UNIVERSE_COMPONENTS = {
|
|
|
2919
3582
|
ToastProvider,
|
|
2920
3583
|
UNIVERSE_COMPONENTS,
|
|
2921
3584
|
cn,
|
|
3585
|
+
formatPhoneDisplay,
|
|
3586
|
+
openWhatsAppChat,
|
|
2922
3587
|
useToast
|
|
2923
3588
|
});
|