@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/index.mjs CHANGED
@@ -38,6 +38,36 @@ function cn(...inputs) {
38
38
  return twMerge(clsx(inputs));
39
39
  }
40
40
 
41
+ // src/utils/whatsapp.ts
42
+ function openWhatsAppChat(phone, defaultCountryCode = "972") {
43
+ if (!phone || typeof window === "undefined") return;
44
+ let cleaned = phone.replace(/\D/g, "");
45
+ if (cleaned.startsWith("0")) {
46
+ cleaned = defaultCountryCode + cleaned.substring(1);
47
+ }
48
+ const appUrl = `whatsapp://send?phone=${cleaned}`;
49
+ const webUrl = `https://web.whatsapp.com/send?phone=${cleaned}`;
50
+ const start = Date.now();
51
+ window.location.href = appUrl;
52
+ setTimeout(() => {
53
+ if (typeof document !== "undefined" && document.hasFocus() && Date.now() - start < 2e3) {
54
+ window.open(webUrl, "_blank", "noopener,noreferrer");
55
+ }
56
+ }, 1200);
57
+ }
58
+ function formatPhoneDisplay(phone) {
59
+ if (!phone) return "";
60
+ const digits = phone.replace(/\D/g, "");
61
+ if (digits.length === 10 && digits.startsWith("05")) {
62
+ return `${digits.slice(0, 3)}-${digits.slice(3, 6)}-${digits.slice(6)}`;
63
+ }
64
+ if (digits.length === 12 && digits.startsWith("9725")) {
65
+ const local = "0" + digits.slice(3);
66
+ return `${local.slice(0, 3)}-${local.slice(3, 6)}-${local.slice(6)}`;
67
+ }
68
+ return phone;
69
+ }
70
+
41
71
  // src/components/TableBlock/TableBlockClient.tsx
42
72
  import React6, { useState as useState5, useMemo as useMemo2, useEffect as useEffect4, useCallback as useCallback4, useRef as useRef4 } from "react";
43
73
 
@@ -889,16 +919,35 @@ var FORM_INPUTS = {
889
919
  }
890
920
  }
891
921
  ),
892
- PHONE: ({ value, onChange }) => /* @__PURE__ */ jsx4(
893
- "input",
894
- {
895
- type: "tel",
896
- className: "w-full h-8 px-2 bg-transparent focus:bg-white focus:outline-none focus:ring-1 focus:ring-blue-400 text-sm",
897
- value: value !== void 0 && value !== null ? String(value) : "",
898
- onChange: (e) => onChange(e.target.value),
899
- dir: "ltr"
900
- }
901
- ),
922
+ PHONE: ({ value, onChange, column }) => {
923
+ var _a;
924
+ const enableWhatsApp = (_a = column == null ? void 0 : column.config) == null ? void 0 : _a.enableWhatsApp;
925
+ return /* @__PURE__ */ jsxs4("div", { className: "flex items-center w-full h-full px-2 gap-1.5", children: [
926
+ /* @__PURE__ */ jsx4(
927
+ "input",
928
+ {
929
+ type: "tel",
930
+ className: "w-full h-8 bg-transparent focus:bg-white focus:outline-none focus:ring-1 focus:ring-blue-400 text-sm flex-1",
931
+ value: value !== void 0 && value !== null ? String(value) : "",
932
+ onChange: (e) => onChange(e.target.value),
933
+ dir: "ltr"
934
+ }
935
+ ),
936
+ enableWhatsApp && value && /* @__PURE__ */ jsx4(
937
+ "button",
938
+ {
939
+ type: "button",
940
+ className: "text-emerald-500 cursor-pointer hover:opacity-80 transition-opacity shrink-0 p-1 rounded hover:bg-emerald-50",
941
+ title: "\u05E4\u05EA\u05D9\u05D7\u05EA \u05D5\u05D5\u05D0\u05D8\u05E1\u05D0\u05E4",
942
+ onClick: (e) => {
943
+ e.stopPropagation();
944
+ openWhatsAppChat(String(value));
945
+ },
946
+ children: /* @__PURE__ */ jsx4("svg", { className: "w-4 h-4", fill: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx4("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" }) })
947
+ }
948
+ )
949
+ ] });
950
+ },
902
951
  GOOGLE_CONTACT: ({ value, column, rowId, onChange, context }) => {
903
952
  const [isSyncing, setIsSyncing] = React4.useState(false);
904
953
  const { addToast } = useToast();
@@ -1082,31 +1131,33 @@ var FORM_INPUTS = {
1082
1131
  }
1083
1132
  };
1084
1133
  if (value && value.synced && value.url) {
1085
- return /* @__PURE__ */ jsxs4("div", { className: "flex items-center gap-2 h-8 px-2 group", children: [
1086
- /* @__PURE__ */ jsx4("a", { href: value.url, target: "_blank", rel: "noopener noreferrer", className: "text-blue-600 hover:underline flex-1 truncate text-sm", children: "\u05D0\u05D9\u05E9 \u05E7\u05E9\u05E8 \u05D2\u05D5\u05D2\u05DC" }),
1134
+ return /* @__PURE__ */ jsxs4("div", { className: "flex items-center gap-1.5 h-8 px-2 group whitespace-nowrap", children: [
1135
+ /* @__PURE__ */ jsx4("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" }),
1087
1136
  /* @__PURE__ */ jsx4(
1088
1137
  "button",
1089
1138
  {
1139
+ type: "button",
1090
1140
  onClick: handleUnlink,
1091
- className: "text-slate-400 hover:text-rose-500 opacity-0 group-hover:opacity-100 transition-opacity p-1",
1141
+ className: "text-slate-400 hover:text-rose-500 opacity-0 group-hover:opacity-100 transition-opacity p-1 shrink-0",
1092
1142
  title: "\u05D1\u05D8\u05DC \u05E1\u05E0\u05DB\u05E8\u05D5\u05DF",
1093
- children: /* @__PURE__ */ jsx4("svg", { className: "w-4 h-4", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsx4("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M6 18L18 6M6 6l12 12" }) })
1143
+ children: /* @__PURE__ */ jsx4("svg", { className: "w-3.5 h-3.5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsx4("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M6 18L18 6M6 6l12 12" }) })
1094
1144
  }
1095
1145
  )
1096
1146
  ] });
1097
1147
  }
1098
- return /* @__PURE__ */ jsx4("div", { className: "flex items-center h-8 px-2", children: /* @__PURE__ */ jsxs4(
1148
+ return /* @__PURE__ */ jsx4("div", { className: "flex items-center h-8 px-2 whitespace-nowrap", children: /* @__PURE__ */ jsxs4(
1099
1149
  "button",
1100
1150
  {
1151
+ type: "button",
1101
1152
  onClick: handleSync,
1102
1153
  disabled: isSyncing,
1103
- className: "flex items-center gap-1.5 px-3 py-1 bg-blue-50 text-blue-600 hover:bg-blue-100 border border-blue-200 rounded-md text-xs font-medium transition-colors disabled:opacity-50",
1154
+ 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",
1104
1155
  children: [
1105
- isSyncing ? /* @__PURE__ */ jsxs4("svg", { className: "w-3.5 h-3.5 animate-spin", viewBox: "0 0 24 24", fill: "none", children: [
1156
+ isSyncing ? /* @__PURE__ */ jsxs4("svg", { className: "w-3.5 h-3.5 animate-spin shrink-0", viewBox: "0 0 24 24", fill: "none", children: [
1106
1157
  /* @__PURE__ */ jsx4("circle", { className: "opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4" }),
1107
1158
  /* @__PURE__ */ jsx4("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" })
1108
- ] }) : /* @__PURE__ */ jsx4("svg", { className: "w-3.5 h-3.5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsx4("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M12 4v16m8-8H4" }) }),
1109
- "\u05E1\u05E0\u05DB\u05E8\u05DF \u05DC\u05D2\u05D5\u05D2\u05DC"
1159
+ ] }) : /* @__PURE__ */ jsx4("svg", { className: "w-3.5 h-3.5 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsx4("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M12 4v16m8-8H4" }) }),
1160
+ /* @__PURE__ */ jsx4("span", { className: "whitespace-nowrap", children: "\u05E1\u05E0\u05DB\u05E8\u05DF \u05DC\u05D2\u05D5\u05D2\u05DC" })
1110
1161
  ]
1111
1162
  }
1112
1163
  ) });
@@ -1121,17 +1172,48 @@ var FORM_INPUTS = {
1121
1172
  }
1122
1173
  ),
1123
1174
  SUB_TABLE: ({ value, column }) => {
1175
+ var _a, _b;
1124
1176
  if (!Array.isArray(value)) return /* @__PURE__ */ jsx4("span", { className: "px-2 py-1 flex items-center h-full text-slate-300 text-xs italic", children: "\u05E8\u05D9\u05E7" });
1125
1177
  const selected = value.filter((e) => e == null ? void 0 : e.isSelected);
1126
1178
  if (selected.length === 0) return /* @__PURE__ */ jsx4("span", { className: "px-2 py-1 flex items-center h-full text-slate-300 text-xs italic", children: "\u05E8\u05D9\u05E7" });
1127
1179
  const displayFields = column.subTableDisplayFields || [];
1180
+ const isWhatsApp = ((_a = column.config) == null ? void 0 : _a.actionType) === "WHATSAPP";
1181
+ const actionPhoneCol = (_b = column.config) == null ? void 0 : _b.actionPhoneColumn;
1128
1182
  return /* @__PURE__ */ jsx4("div", { className: "px-1.5 py-1 flex flex-wrap items-center gap-1 h-full", children: selected.map((entry, idx) => {
1129
- var _a;
1183
+ var _a2, _b2;
1130
1184
  let label = "";
1131
- if (entry._resolvedData && displayFields.length > 0) {
1132
- label = displayFields.map((f) => String(entry._resolvedData[f] || "")).filter(Boolean).join(" ");
1185
+ if (entry._resolvedData) {
1186
+ if (displayFields.length > 0) {
1187
+ label = displayFields.map((f) => String(entry._resolvedData[f] || "")).filter(Boolean).join(" ");
1188
+ } else {
1189
+ const firstField = Object.keys(entry._resolvedData).find((k) => k !== "_id");
1190
+ if (firstField) label = String(entry._resolvedData[firstField] || "");
1191
+ }
1192
+ }
1193
+ if (!label) label = ((_a2 = entry.recordId) == null ? void 0 : _a2.slice(-6)) || "...";
1194
+ if (isWhatsApp) {
1195
+ const rawPhone = actionPhoneCol ? (_b2 = entry._resolvedData) == null ? void 0 : _b2[actionPhoneCol] : null;
1196
+ const phone = rawPhone ? String(rawPhone).trim() : null;
1197
+ if (phone) {
1198
+ return /* @__PURE__ */ jsxs4(
1199
+ "button",
1200
+ {
1201
+ type: "button",
1202
+ onClick: (e) => {
1203
+ e.stopPropagation();
1204
+ openWhatsAppChat(phone);
1205
+ },
1206
+ 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",
1207
+ title: `\u05E4\u05EA\u05D9\u05D7\u05EA \u05D5\u05D5\u05D0\u05D8\u05E1\u05D0\u05E4 (${phone})`,
1208
+ children: [
1209
+ /* @__PURE__ */ jsx4("svg", { className: "w-3 h-3 text-emerald-600 shrink-0", fill: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx4("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" }) }),
1210
+ /* @__PURE__ */ jsx4("span", { className: "truncate", children: label })
1211
+ ]
1212
+ },
1213
+ entry.recordId || idx
1214
+ );
1215
+ }
1133
1216
  }
1134
- if (!label) label = ((_a = entry.recordId) == null ? void 0 : _a.slice(-6)) || "...";
1135
1217
  return /* @__PURE__ */ jsx4(
1136
1218
  "span",
1137
1219
  {
@@ -1147,12 +1229,241 @@ var FORM_INPUTS = {
1147
1229
 
1148
1230
  // src/components/TableBlock/fields/SubTableViewer.tsx
1149
1231
  import { useState as useState4, useEffect as useEffect3, useRef as useRef3, useCallback as useCallback3 } from "react";
1232
+
1233
+ // src/utils/phone.ts
1234
+ function sanitizePhoneNumber(phone) {
1235
+ if (!phone) return "";
1236
+ const trimmed = phone.trim();
1237
+ const hasLeadingPlus = trimmed.startsWith("+");
1238
+ const digitsOnly = trimmed.replace(/\D/g, "");
1239
+ return hasLeadingPlus ? `+${digitsOnly}` : digitsOnly;
1240
+ }
1241
+ function isValidPhoneNumber(phone) {
1242
+ if (!phone) return false;
1243
+ const cleaned = sanitizePhoneNumber(phone);
1244
+ return /^\+?[0-9]{9,15}$/.test(cleaned);
1245
+ }
1246
+
1247
+ // src/components/TableBlock/fields/SubTableViewer.tsx
1150
1248
  import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
1151
- function SubTableViewer({ rowId, column, value, onChange, context }) {
1249
+ function validateCellValue(val, col) {
1152
1250
  var _a;
1251
+ const colType = ((_a = col.type) == null ? void 0 : _a.toUpperCase()) || "DEFAULT";
1252
+ const isEmpty = val === void 0 || val === null || typeof val === "string" && val.trim() === "";
1253
+ if (col.isRequired && isEmpty) {
1254
+ return {
1255
+ isValid: false,
1256
+ 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.`
1257
+ };
1258
+ }
1259
+ if (isEmpty) {
1260
+ return { isValid: true };
1261
+ }
1262
+ if (colType === "PHONE") {
1263
+ const strVal = String(val).trim();
1264
+ if (!isValidPhoneNumber(strVal)) {
1265
+ return {
1266
+ isValid: false,
1267
+ 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).`
1268
+ };
1269
+ }
1270
+ }
1271
+ if (colType === "NUMBER" || colType === "CURRENCY") {
1272
+ if (typeof val === "string" && isNaN(Number(val))) {
1273
+ return {
1274
+ isValid: false,
1275
+ 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.`
1276
+ };
1277
+ }
1278
+ }
1279
+ return { isValid: true };
1280
+ }
1281
+ function SubTableCell({
1282
+ record,
1283
+ column,
1284
+ targetSchema,
1285
+ referencedTableId,
1286
+ context,
1287
+ relationOptions,
1288
+ setRelationOptions,
1289
+ refetchRelation,
1290
+ onCommit
1291
+ }) {
1292
+ var _a, _b;
1293
+ const colType = ((_a = column.type) == null ? void 0 : _a.toUpperCase()) || "DEFAULT";
1294
+ const isContact = colType === "GOOGLE_CONTACT";
1295
+ const InputComponent = FORM_INPUTS[colType] || FORM_INPUTS.DEFAULT;
1296
+ const serverValue = (_b = record.data[column.name]) != null ? _b : colType === "BOOLEAN" ? false : "";
1297
+ const [draftValue, setDraftValue] = useState4(serverValue);
1298
+ const [isDirty, setIsDirty] = useState4(false);
1299
+ const [validationError, setValidationError] = useState4(null);
1300
+ const cellRef = useRef3(null);
1301
+ const draftRef = useRef3(draftValue);
1302
+ const isDirtyRef = useRef3(isDirty);
1303
+ const serverValueRef = useRef3(serverValue);
1304
+ const recordIdRef = useRef3(record.id);
1305
+ const columnRef = useRef3(column);
1306
+ const onCommitRef = useRef3(onCommit);
1307
+ const isCommittingRef = useRef3(false);
1308
+ const lastFailedValRef = useRef3(void 0);
1309
+ const { addToast } = useToast();
1310
+ draftRef.current = draftValue;
1311
+ isDirtyRef.current = isDirty;
1312
+ serverValueRef.current = serverValue;
1313
+ recordIdRef.current = record.id;
1314
+ columnRef.current = column;
1315
+ onCommitRef.current = onCommit;
1316
+ useEffect3(() => {
1317
+ if (!isDirtyRef.current) {
1318
+ setDraftValue(serverValue);
1319
+ draftRef.current = serverValue;
1320
+ setValidationError(null);
1321
+ lastFailedValRef.current = void 0;
1322
+ }
1323
+ }, [serverValue]);
1324
+ const commit = useCallback3(async (valToCommit) => {
1325
+ if (isCommittingRef.current) return false;
1326
+ if (!isDirtyRef.current) return true;
1327
+ if (valToCommit === serverValueRef.current) {
1328
+ setIsDirty(false);
1329
+ isDirtyRef.current = false;
1330
+ setValidationError(null);
1331
+ lastFailedValRef.current = void 0;
1332
+ return true;
1333
+ }
1334
+ const valRes = validateCellValue(valToCommit, columnRef.current);
1335
+ if (!valRes.isValid) {
1336
+ const errorMsg = valRes.error || "\u05E9\u05D2\u05D9\u05D0\u05EA \u05D0\u05D9\u05DE\u05D5\u05EA";
1337
+ setValidationError(errorMsg);
1338
+ if (lastFailedValRef.current !== valToCommit) {
1339
+ addToast({ type: "error", message: errorMsg });
1340
+ lastFailedValRef.current = valToCommit;
1341
+ }
1342
+ return false;
1343
+ }
1344
+ try {
1345
+ isCommittingRef.current = true;
1346
+ const success = await onCommitRef.current(recordIdRef.current, columnRef.current.name, valToCommit);
1347
+ if (success) {
1348
+ setIsDirty(false);
1349
+ isDirtyRef.current = false;
1350
+ serverValueRef.current = valToCommit;
1351
+ setValidationError(null);
1352
+ lastFailedValRef.current = void 0;
1353
+ return true;
1354
+ } else {
1355
+ setValidationError("\u05E9\u05D2\u05D9\u05D0\u05D4 \u05D1\u05E9\u05DE\u05D9\u05E8\u05EA \u05D4\u05E8\u05E9\u05D5\u05DE\u05D4");
1356
+ return false;
1357
+ }
1358
+ } catch (e) {
1359
+ setValidationError("\u05E9\u05D2\u05D9\u05D0\u05D4 \u05D1\u05E9\u05DE\u05D9\u05E8\u05EA \u05D4\u05E8\u05E9\u05D5\u05DE\u05D4");
1360
+ return false;
1361
+ } finally {
1362
+ isCommittingRef.current = false;
1363
+ }
1364
+ }, [addToast]);
1365
+ const discard = useCallback3(() => {
1366
+ setDraftValue(serverValueRef.current);
1367
+ draftRef.current = serverValueRef.current;
1368
+ setIsDirty(false);
1369
+ isDirtyRef.current = false;
1370
+ setValidationError(null);
1371
+ lastFailedValRef.current = void 0;
1372
+ }, []);
1373
+ useEffect3(() => {
1374
+ return () => {
1375
+ if (isDirtyRef.current && !isCommittingRef.current) {
1376
+ const val = draftRef.current;
1377
+ const orig = serverValueRef.current;
1378
+ if (val !== orig) {
1379
+ const valRes = validateCellValue(val, columnRef.current);
1380
+ if (valRes.isValid) {
1381
+ onCommitRef.current(recordIdRef.current, columnRef.current.name, val);
1382
+ }
1383
+ }
1384
+ }
1385
+ };
1386
+ }, []);
1387
+ const handleChange = (newVal) => {
1388
+ setDraftValue(newVal);
1389
+ draftRef.current = newVal;
1390
+ setIsDirty(true);
1391
+ isDirtyRef.current = true;
1392
+ if (validationError) {
1393
+ setValidationError(null);
1394
+ lastFailedValRef.current = void 0;
1395
+ }
1396
+ if (colType === "BOOLEAN" || colType === "GOOGLE_DRIVE_FILE") {
1397
+ commit(newVal);
1398
+ }
1399
+ };
1400
+ const handleBlur = (e) => {
1401
+ if (e.currentTarget.contains(e.relatedTarget)) {
1402
+ return;
1403
+ }
1404
+ if (isDirtyRef.current) {
1405
+ commit(draftRef.current);
1406
+ }
1407
+ };
1408
+ const handleKeyDown = (e) => {
1409
+ var _a2, _b2, _c, _d;
1410
+ if (e.key === "Enter") {
1411
+ e.preventDefault();
1412
+ if (isDirtyRef.current) {
1413
+ commit(draftRef.current);
1414
+ }
1415
+ (_b2 = (_a2 = e.target) == null ? void 0 : _a2.blur) == null ? void 0 : _b2.call(_a2);
1416
+ } else if (e.key === "Escape") {
1417
+ e.preventDefault();
1418
+ discard();
1419
+ (_d = (_c = e.target) == null ? void 0 : _c.blur) == null ? void 0 : _d.call(_c);
1420
+ }
1421
+ };
1422
+ return /* @__PURE__ */ jsx5(
1423
+ "td",
1424
+ {
1425
+ ref: cellRef,
1426
+ onBlur: handleBlur,
1427
+ onKeyDown: handleKeyDown,
1428
+ title: validationError || void 0,
1429
+ 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" : ""}`,
1430
+ children: /* @__PURE__ */ jsx5(
1431
+ InputComponent,
1432
+ {
1433
+ value: draftValue,
1434
+ column,
1435
+ rowId: record.id,
1436
+ onChange: handleChange,
1437
+ context: __spreadProps(__spreadValues({}, context), {
1438
+ 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",
1439
+ relationOptions,
1440
+ updateRelationOptions: (name, opts) => setRelationOptions((prev) => __spreadProps(__spreadValues({}, prev), { [name]: opts })),
1441
+ refetchRelation,
1442
+ parentRecord: { tableId: (context == null ? void 0 : context.parentTableId) || (context == null ? void 0 : context.tableId), data: context == null ? void 0 : context.rowData },
1443
+ rowData: record.data,
1444
+ tableId: (targetSchema == null ? void 0 : targetSchema.tableMetaId) || (targetSchema == null ? void 0 : targetSchema.id) || referencedTableId,
1445
+ updateQuietly: (rid, colName, val) => onCommitRef.current(rid, colName, val)
1446
+ })
1447
+ }
1448
+ )
1449
+ }
1450
+ );
1451
+ }
1452
+ function SubTableViewer({ rowId, column, value, onChange, context }) {
1453
+ var _a, _b;
1153
1454
  const { addToast } = useToast();
1154
1455
  const entries = Array.isArray(value) ? value : [];
1155
- const [linkedRecords, setLinkedRecords] = useState4([]);
1456
+ const [linkedRecords, setLinkedRecords] = useState4(() => {
1457
+ const initial = [];
1458
+ if (Array.isArray(value)) {
1459
+ for (const entry of value) {
1460
+ if (entry.recordId && entry._resolvedData) {
1461
+ initial.push({ id: entry.recordId, data: entry._resolvedData });
1462
+ }
1463
+ }
1464
+ }
1465
+ return initial;
1466
+ });
1156
1467
  const [targetSchema, setTargetSchema] = useState4(null);
1157
1468
  const [isLoading, setIsLoading] = useState4(true);
1158
1469
  const [isSearchOpen, setIsSearchOpen] = useState4(false);
@@ -1161,11 +1472,31 @@ function SubTableViewer({ rowId, column, value, onChange, context }) {
1161
1472
  const [isSearching, setIsSearching] = useState4(false);
1162
1473
  const [isCreating, setIsCreating] = useState4(false);
1163
1474
  const [newRecordData, setNewRecordData] = useState4({});
1475
+ const [conflictModalState, setConflictModalState] = useState4({
1476
+ isOpen: false,
1477
+ fieldName: "",
1478
+ matchingRecords: []
1479
+ });
1164
1480
  const searchRef = useRef3(null);
1165
1481
  const searchTimerRef = useRef3(null);
1166
1482
  const executeAction = context == null ? void 0 : context.executeAction;
1167
1483
  const referencedTableId = column.referencedTableId;
1168
1484
  const fetchedIdsRef = useRef3(/* @__PURE__ */ new Set());
1485
+ useEffect3(() => {
1486
+ if (entries.length > 0) {
1487
+ setLinkedRecords((prev) => {
1488
+ const existingIds = new Set(prev.map((r) => r.id));
1489
+ const toAdd = [];
1490
+ for (const entry of entries) {
1491
+ if (entry.recordId && entry._resolvedData && !existingIds.has(entry.recordId)) {
1492
+ toAdd.push({ id: entry.recordId, data: entry._resolvedData });
1493
+ existingIds.add(entry.recordId);
1494
+ }
1495
+ }
1496
+ return toAdd.length > 0 ? [...prev, ...toAdd] : prev;
1497
+ });
1498
+ }
1499
+ }, [entries]);
1169
1500
  useEffect3(() => {
1170
1501
  if (!referencedTableId || !executeAction) {
1171
1502
  setIsLoading(false);
@@ -1291,20 +1622,102 @@ function SubTableViewer({ rowId, column, value, onChange, context }) {
1291
1622
  }
1292
1623
  }
1293
1624
  };
1294
- const handleLinkRecord = (record) => {
1295
- fetchedIdsRef.current.add(record.id);
1296
- const newEntry = { recordId: record.id, isSelected: true, _resolvedData: record.data };
1297
- const updated = [...entries, newEntry];
1298
- updateParentLinkage(updated);
1625
+ const handleLinkRecords = (recordsToLink) => {
1626
+ if (!recordsToLink || recordsToLink.length === 0) return;
1627
+ const existingEntryIds = new Set(entries.map((e) => e.recordId));
1628
+ const newEntries = [];
1629
+ const newRecordsToAdd = [];
1630
+ for (const record of recordsToLink) {
1631
+ fetchedIdsRef.current.add(record.id);
1632
+ const resolvedData = __spreadValues({}, record.data || {});
1633
+ targetColumns.forEach((col) => {
1634
+ if ((resolvedData[col.name] === void 0 || resolvedData[col.name] === null) && record[col.name] !== void 0) {
1635
+ resolvedData[col.name] = record[col.name];
1636
+ }
1637
+ });
1638
+ if (!existingEntryIds.has(record.id)) {
1639
+ newEntries.push({
1640
+ recordId: record.id,
1641
+ isSelected: true,
1642
+ _resolvedData: resolvedData
1643
+ });
1644
+ existingEntryIds.add(record.id);
1645
+ }
1646
+ newRecordsToAdd.push({
1647
+ id: record.id,
1648
+ data: resolvedData
1649
+ });
1650
+ }
1651
+ const updatedEntries = [...entries, ...newEntries];
1652
+ updateParentLinkage(updatedEntries);
1299
1653
  setLinkedRecords((prev) => {
1300
- const exists = prev.find((r) => r.id === record.id);
1301
- if (exists) return prev;
1302
- return [...prev, record];
1654
+ const map = new Map(prev.map((r) => [r.id, r]));
1655
+ newRecordsToAdd.forEach((r) => {
1656
+ const existing = map.get(r.id);
1657
+ if (existing) {
1658
+ map.set(r.id, __spreadProps(__spreadValues({}, existing), {
1659
+ data: __spreadValues(__spreadValues({}, existing.data), r.data)
1660
+ }));
1661
+ } else {
1662
+ map.set(r.id, r);
1663
+ }
1664
+ });
1665
+ return Array.from(map.values());
1303
1666
  });
1304
1667
  setSearchQuery("");
1305
1668
  setSearchResults([]);
1306
1669
  setIsSearchOpen(false);
1307
1670
  };
1671
+ const handleLinkRecord = (record) => {
1672
+ handleLinkRecords([record]);
1673
+ };
1674
+ const handleUniqueConflict = (conflictData) => {
1675
+ const rawMatching = Array.isArray(conflictData == null ? void 0 : conflictData.matchingRecords) ? conflictData.matchingRecords : [];
1676
+ const resolvedMatching = rawMatching.map((r) => {
1677
+ var _a2;
1678
+ const recordId = String(r.id || ((_a2 = r._id) == null ? void 0 : _a2.$oid) || r._id);
1679
+ let dataObj = {};
1680
+ if (r.data && typeof r.data === "object") {
1681
+ dataObj = __spreadValues({}, r.data);
1682
+ }
1683
+ targetColumns.forEach((col) => {
1684
+ if ((dataObj[col.name] === void 0 || dataObj[col.name] === null) && r[col.name] !== void 0) {
1685
+ dataObj[col.name] = r[col.name];
1686
+ }
1687
+ });
1688
+ return {
1689
+ id: recordId,
1690
+ data: dataObj
1691
+ };
1692
+ });
1693
+ setConflictModalState({
1694
+ isOpen: true,
1695
+ fieldName: (conflictData == null ? void 0 : conflictData.fieldName) || "",
1696
+ matchingRecords: resolvedMatching
1697
+ });
1698
+ };
1699
+ const handleCancelConflict = () => {
1700
+ setConflictModalState((prev) => __spreadProps(__spreadValues({}, prev), { isOpen: false }));
1701
+ };
1702
+ const handleConfirmLinkConflict = async () => {
1703
+ const { matchingRecords } = conflictModalState;
1704
+ if (matchingRecords && matchingRecords.length > 0) {
1705
+ handleLinkRecords(matchingRecords);
1706
+ setNewRecordData({});
1707
+ setIsCreating(false);
1708
+ setConflictModalState({
1709
+ isOpen: false,
1710
+ fieldName: "",
1711
+ matchingRecords: []
1712
+ });
1713
+ addToast({
1714
+ type: "success",
1715
+ message: "\u05D4\u05E8\u05E9\u05D5\u05DE\u05D4 \u05E7\u05D5\u05E9\u05E8\u05D4 \u05D1\u05D4\u05E6\u05DC\u05D7\u05D4"
1716
+ });
1717
+ } else {
1718
+ setConflictModalState((prev) => __spreadProps(__spreadValues({}, prev), { isOpen: false }));
1719
+ }
1720
+ };
1308
1721
  const handleUnlinkRecord = (recordId) => {
1309
1722
  const updated = entries.filter((e) => e.recordId !== recordId);
1310
1723
  updateParentLinkage(updated);
@@ -1317,37 +1730,94 @@ function SubTableViewer({ rowId, column, value, onChange, context }) {
1317
1730
  );
1318
1731
  updateParentLinkage(updated);
1319
1732
  };
1320
- const handleRecordCellChange = async (recordId, colName, value2) => {
1321
- const updatedRecords = linkedRecords.map(
1322
- (r) => r.id === recordId ? __spreadProps(__spreadValues({}, r), { data: __spreadProps(__spreadValues({}, r.data), { [colName]: value2 }) }) : r
1323
- );
1324
- setLinkedRecords(updatedRecords);
1325
- const targetRecord = updatedRecords.find((r) => r.id === recordId);
1326
- const updatedEntries = entries.map(
1327
- (e) => e.recordId === recordId ? __spreadProps(__spreadValues({}, e), { _resolvedData: targetRecord == null ? void 0 : targetRecord.data }) : e
1328
- );
1329
- if (context == null ? void 0 : context.updateQuietly) {
1330
- context.updateQuietly(rowId, column.name, updatedEntries);
1331
- } else {
1332
- onChange(updatedEntries);
1733
+ const isMountedRef = useRef3(true);
1734
+ useEffect3(() => {
1735
+ isMountedRef.current = true;
1736
+ return () => {
1737
+ isMountedRef.current = false;
1738
+ };
1739
+ }, []);
1740
+ const handleCommitRecordCell = async (recordId, colName, value2) => {
1741
+ var _a2;
1742
+ const previousRecord = linkedRecords.find((r) => r.id === recordId);
1743
+ const previousValue = (_a2 = previousRecord == null ? void 0 : previousRecord.data) == null ? void 0 : _a2[colName];
1744
+ if (previousValue === value2) return true;
1745
+ const targetCol = targetColumns.find((c) => c.name === colName);
1746
+ const valRes = targetCol ? validateCellValue(value2, targetCol) : { isValid: true };
1747
+ if (!valRes.isValid) {
1748
+ addToast({
1749
+ type: "error",
1750
+ message: valRes.error || "\u05E9\u05D2\u05D9\u05D0\u05EA \u05D0\u05D9\u05DE\u05D5\u05EA"
1751
+ });
1752
+ return false;
1333
1753
  }
1334
1754
  if (executeAction && referencedTableId && !recordId.startsWith("temp_")) {
1335
1755
  try {
1336
- await executeAction("UPDATE_RECORD", {
1756
+ const res = await executeAction("UPDATE_RECORD", {
1337
1757
  tableId: referencedTableId,
1338
1758
  recordId,
1339
1759
  data: { [colName]: value2 }
1340
1760
  });
1341
- if (context == null ? void 0 : context.triggerSaveSuccess) {
1342
- context.triggerSaveSuccess();
1761
+ if (res && res.success === false) {
1762
+ const err = new Error(res.error || res.message || "Action execution failed");
1763
+ Object.assign(err, res);
1764
+ throw err;
1765
+ }
1766
+ if (isMountedRef.current) {
1767
+ const updatedRecords = linkedRecords.map(
1768
+ (r) => r.id === recordId ? __spreadProps(__spreadValues({}, r), { data: __spreadProps(__spreadValues({}, r.data), { [colName]: value2 }) }) : r
1769
+ );
1770
+ setLinkedRecords(updatedRecords);
1771
+ const targetRecord = updatedRecords.find((r) => r.id === recordId);
1772
+ const updatedEntries = entries.map(
1773
+ (e) => e.recordId === recordId ? __spreadProps(__spreadValues({}, e), { _resolvedData: targetRecord == null ? void 0 : targetRecord.data }) : e
1774
+ );
1775
+ if (context == null ? void 0 : context.updateQuietly) {
1776
+ context.updateQuietly(rowId, column.name, updatedEntries);
1777
+ } else {
1778
+ onChange(updatedEntries);
1779
+ }
1780
+ if (context == null ? void 0 : context.triggerSaveSuccess) {
1781
+ context.triggerSaveSuccess();
1782
+ }
1343
1783
  }
1784
+ return true;
1344
1785
  } catch (err) {
1345
1786
  console.error("[SubTableViewer] Failed to auto-save linked record field", err);
1787
+ 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";
1788
+ 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")) {
1789
+ 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).`;
1790
+ } else if (errorMsg.includes("is required") || errorMsg.includes("\u05E9\u05D3\u05D4 \u05D7\u05D5\u05D1\u05D4") || errorMsg.toLowerCase().includes("required")) {
1791
+ 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.`;
1792
+ }
1793
+ addToast({
1794
+ type: "error",
1795
+ message: errorMsg
1796
+ });
1797
+ return false;
1346
1798
  }
1799
+ } else {
1800
+ if (isMountedRef.current) {
1801
+ const updatedRecords = linkedRecords.map(
1802
+ (r) => r.id === recordId ? __spreadProps(__spreadValues({}, r), { data: __spreadProps(__spreadValues({}, r.data), { [colName]: value2 }) }) : r
1803
+ );
1804
+ setLinkedRecords(updatedRecords);
1805
+ const targetRecord = updatedRecords.find((r) => r.id === recordId);
1806
+ const updatedEntries = entries.map(
1807
+ (e) => e.recordId === recordId ? __spreadProps(__spreadValues({}, e), { _resolvedData: targetRecord == null ? void 0 : targetRecord.data }) : e
1808
+ );
1809
+ if (context == null ? void 0 : context.updateQuietly) {
1810
+ context.updateQuietly(rowId, column.name, updatedEntries);
1811
+ } else {
1812
+ onChange(updatedEntries);
1813
+ }
1814
+ }
1815
+ return true;
1347
1816
  }
1348
1817
  };
1818
+ const handleRecordCellChange = handleCommitRecordCell;
1349
1819
  const handleCreateRecord = async () => {
1350
- var _a2;
1820
+ var _a2, _b2, _c, _d, _e;
1351
1821
  if (!executeAction || !referencedTableId) return;
1352
1822
  for (const col of targetColumns) {
1353
1823
  if (col.isRequired) {
@@ -1360,16 +1830,30 @@ function SubTableViewer({ rowId, column, value, onChange, context }) {
1360
1830
  return;
1361
1831
  }
1362
1832
  }
1833
+ if (((_a2 = col.type) == null ? void 0 : _a2.toUpperCase()) === "PHONE") {
1834
+ const val = newRecordData[col.name];
1835
+ if (val !== void 0 && val !== null && String(val).trim() !== "" && !isValidPhoneNumber(String(val))) {
1836
+ addToast({
1837
+ type: "error",
1838
+ 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.`
1839
+ });
1840
+ return;
1841
+ }
1842
+ }
1363
1843
  }
1364
1844
  try {
1365
1845
  const res = await executeAction("CREATE_RECORD", {
1366
1846
  tableId: referencedTableId,
1367
1847
  records: [newRecordData]
1368
1848
  });
1849
+ if (res && (res.error === "UNIQUE_CONSTRAINT_CONFLICT" || res.code === "UNIQUE_CONSTRAINT_CONFLICT")) {
1850
+ handleUniqueConflict(res);
1851
+ return;
1852
+ }
1369
1853
  if (res && res.success === false) {
1370
1854
  throw new Error(res.error || "Action execution failed");
1371
1855
  }
1372
- const created = Array.isArray(res) ? res[0] : ((_a2 = res == null ? void 0 : res.data) == null ? void 0 : _a2[0]) || res;
1856
+ const created = Array.isArray(res) ? res[0] : ((_b2 = res == null ? void 0 : res.data) == null ? void 0 : _b2[0]) || res;
1373
1857
  if (created) {
1374
1858
  const newRecord = {
1375
1859
  id: String(created.id || created._id),
@@ -1380,6 +1864,12 @@ function SubTableViewer({ rowId, column, value, onChange, context }) {
1380
1864
  setNewRecordData({});
1381
1865
  }
1382
1866
  } catch (err) {
1867
+ 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"));
1868
+ if (isConflict) {
1869
+ 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;
1870
+ handleUniqueConflict(conflictPayload);
1871
+ return;
1872
+ }
1383
1873
  const msg = (err == null ? void 0 : err.message) || String(err);
1384
1874
  addToast({
1385
1875
  type: "error",
@@ -1466,11 +1956,23 @@ function SubTableViewer({ rowId, column, value, onChange, context }) {
1466
1956
  isLoading ? /* @__PURE__ */ jsx5("div", { className: "flex items-center justify-center py-6", children: /* @__PURE__ */ jsx5("div", { className: "w-5 h-5 border-2 border-blue-400 border-t-transparent rounded-full animate-spin" }) }) : entries.length === 0 && !isCreating ? /* @__PURE__ */ jsx5("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__ */ jsx5("div", { className: "overflow-x-auto pb-1", children: /* @__PURE__ */ jsxs5("table", { className: "w-full text-xs border-collapse", children: [
1467
1957
  /* @__PURE__ */ jsx5("thead", { children: /* @__PURE__ */ jsxs5("tr", { className: "bg-slate-100/80", children: [
1468
1958
  /* @__PURE__ */ jsx5("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" }),
1469
- targetColumns.map((col) => /* @__PURE__ */ jsx5("th", { className: "border border-slate-200 px-2 py-1.5 text-right font-semibold text-slate-600 whitespace-nowrap", children: col.name }, col.name)),
1959
+ targetColumns.map((col) => {
1960
+ var _a2;
1961
+ const isContact = ((_a2 = col.type) == null ? void 0 : _a2.toUpperCase()) === "GOOGLE_CONTACT";
1962
+ return /* @__PURE__ */ jsx5(
1963
+ "th",
1964
+ {
1965
+ className: `border border-slate-200 px-2 py-1.5 text-right font-semibold text-slate-600 whitespace-nowrap ${isContact ? "min-w-[140px]" : ""}`,
1966
+ children: col.name
1967
+ },
1968
+ col.name
1969
+ );
1970
+ }),
1470
1971
  /* @__PURE__ */ jsx5("th", { className: "border border-slate-200 px-2 py-1.5 w-14" })
1471
1972
  ] }) }),
1472
1973
  /* @__PURE__ */ jsxs5("tbody", { children: [
1473
1974
  entries.map((entry) => {
1975
+ var _a2;
1474
1976
  const record = linkedRecords.find((r) => r.id === entry.recordId);
1475
1977
  return /* @__PURE__ */ jsxs5("tr", { className: "hover:bg-blue-50/30 transition-colors", children: [
1476
1978
  /* @__PURE__ */ jsx5("td", { className: "border border-slate-200 px-2 py-1 text-center", children: /* @__PURE__ */ jsx5(
@@ -1483,61 +1985,101 @@ function SubTableViewer({ rowId, column, value, onChange, context }) {
1483
1985
  }
1484
1986
  ) }),
1485
1987
  targetColumns.map((col) => {
1486
- var _a2, _b;
1487
- const colType = ((_a2 = col.type) == null ? void 0 : _a2.toUpperCase()) || "DEFAULT";
1488
- const InputComponent = FORM_INPUTS[colType] || FORM_INPUTS.DEFAULT;
1489
- return /* @__PURE__ */ jsx5("td", { className: "border border-slate-200 p-0 relative h-8", children: record ? /* @__PURE__ */ jsx5(
1490
- InputComponent,
1988
+ var _a3;
1989
+ const isContact = ((_a3 = col.type) == null ? void 0 : _a3.toUpperCase()) === "GOOGLE_CONTACT";
1990
+ if (!record) {
1991
+ return /* @__PURE__ */ jsx5(
1992
+ "td",
1993
+ {
1994
+ className: `border border-slate-200 p-0 relative h-8 ${isContact ? "min-w-[140px]" : ""}`,
1995
+ children: /* @__PURE__ */ jsx5("span", { className: "text-slate-300 italic px-2", children: "\u05D8\u05D5\u05E2\u05DF..." })
1996
+ },
1997
+ col.name
1998
+ );
1999
+ }
2000
+ return /* @__PURE__ */ jsx5(
2001
+ SubTableCell,
1491
2002
  {
1492
- value: (_b = record.data[col.name]) != null ? _b : colType === "BOOLEAN" ? false : "",
2003
+ record,
1493
2004
  column: col,
1494
- rowId: record.id,
1495
- onChange: (v) => handleRecordCellChange(record.id, col.name, v),
1496
- context: __spreadProps(__spreadValues({}, context), {
1497
- 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",
1498
- relationOptions,
1499
- updateRelationOptions: (name, opts) => setRelationOptions((prev) => __spreadProps(__spreadValues({}, prev), { [name]: opts })),
1500
- refetchRelation,
1501
- parentRecord: { tableId: (context == null ? void 0 : context.parentTableId) || (context == null ? void 0 : context.tableId), data: context == null ? void 0 : context.rowData },
1502
- rowData: record.data,
1503
- tableId: targetSchema == null ? void 0 : targetSchema.id,
1504
- updateQuietly: (rid, colName, val) => handleRecordCellChange(rid, colName, val)
1505
- })
1506
- }
1507
- ) : /* @__PURE__ */ jsx5("span", { className: "text-slate-300 italic px-2", children: "\u05D8\u05D5\u05E2\u05DF..." }) }, col.name);
2005
+ targetSchema,
2006
+ referencedTableId,
2007
+ context,
2008
+ relationOptions,
2009
+ setRelationOptions,
2010
+ refetchRelation,
2011
+ onCommit: handleCommitRecordCell
2012
+ },
2013
+ `${record.id}_${col.name}`
2014
+ );
1508
2015
  }),
1509
- /* @__PURE__ */ jsx5("td", { className: "border border-slate-200 px-1 py-1 text-center", children: /* @__PURE__ */ jsx5(
1510
- "button",
1511
- {
1512
- type: "button",
1513
- onClick: () => handleUnlinkRecord(entry.recordId),
1514
- className: "text-slate-400 hover:text-rose-500 p-0.5 rounded transition-colors cursor-pointer inline-flex items-center justify-center w-full",
1515
- title: "\u05D4\u05E1\u05E8 \u05E7\u05D9\u05E9\u05D5\u05E8",
1516
- children: /* @__PURE__ */ jsx5("svg", { className: "w-3.5 h-3.5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsx5("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M6 18L18 6M6 6l12 12" }) })
1517
- }
1518
- ) })
2016
+ /* @__PURE__ */ jsx5("td", { className: "border border-slate-200 px-1 py-1 text-center", children: /* @__PURE__ */ jsxs5("div", { className: "flex items-center justify-center gap-1", children: [
2017
+ ((_a2 = column.config) == null ? void 0 : _a2.actionType) === "WHATSAPP" && (() => {
2018
+ var _a3, _b2, _c;
2019
+ const actionPhoneCol = (_a3 = column.config) == null ? void 0 : _a3.actionPhoneColumn;
2020
+ const phone = actionPhoneCol ? ((_b2 = record == null ? void 0 : record.data) == null ? void 0 : _b2[actionPhoneCol]) || ((_c = entry._resolvedData) == null ? void 0 : _c[actionPhoneCol]) : null;
2021
+ if (phone) {
2022
+ return /* @__PURE__ */ jsx5(
2023
+ "button",
2024
+ {
2025
+ type: "button",
2026
+ onClick: (e) => {
2027
+ e.stopPropagation();
2028
+ openWhatsAppChat(String(phone));
2029
+ },
2030
+ className: "text-emerald-500 hover:text-emerald-600 p-0.5 rounded hover:bg-emerald-50 transition-colors cursor-pointer",
2031
+ title: `\u05E4\u05EA\u05D9\u05D7\u05EA \u05D5\u05D5\u05D0\u05D8\u05E1\u05D0\u05E4 (${phone})`,
2032
+ children: /* @__PURE__ */ jsx5("svg", { className: "w-3.5 h-3.5", fill: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx5("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" }) })
2033
+ }
2034
+ );
2035
+ }
2036
+ return null;
2037
+ })(),
2038
+ /* @__PURE__ */ jsx5(
2039
+ "button",
2040
+ {
2041
+ type: "button",
2042
+ onClick: (e) => {
2043
+ e.stopPropagation();
2044
+ handleUnlinkRecord(entry.recordId);
2045
+ },
2046
+ className: "text-slate-400 hover:text-rose-500 p-0.5 rounded transition-colors cursor-pointer inline-flex items-center justify-center",
2047
+ title: "\u05D4\u05E1\u05E8 \u05E7\u05D9\u05E9\u05D5\u05E8",
2048
+ children: /* @__PURE__ */ jsx5("svg", { className: "w-3.5 h-3.5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsx5("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M6 18L18 6M6 6l12 12" }) })
2049
+ }
2050
+ )
2051
+ ] }) })
1519
2052
  ] }, entry.recordId);
1520
2053
  }),
1521
2054
  isCreating && /* @__PURE__ */ jsxs5("tr", { className: "bg-emerald-50/40", children: [
1522
2055
  /* @__PURE__ */ jsx5("td", { className: "border border-emerald-200 px-2 py-1 text-center", children: /* @__PURE__ */ jsx5("span", { className: "text-emerald-500 font-bold text-[10px]", children: "\u05D7\u05D3\u05E9" }) }),
1523
2056
  targetColumns.map((col) => {
1524
- var _a2, _b;
2057
+ var _a2, _b2;
1525
2058
  const colType = ((_a2 = col.type) == null ? void 0 : _a2.toUpperCase()) || "DEFAULT";
1526
2059
  const InputComponent = FORM_INPUTS[colType] || FORM_INPUTS.DEFAULT;
1527
- return /* @__PURE__ */ jsx5("td", { className: "border border-emerald-200 p-0 relative h-8", children: /* @__PURE__ */ jsx5(
1528
- InputComponent,
2060
+ const isContact = colType === "GOOGLE_CONTACT";
2061
+ return /* @__PURE__ */ jsx5(
2062
+ "td",
1529
2063
  {
1530
- value: (_b = newRecordData[col.name]) != null ? _b : colType === "BOOLEAN" ? false : "",
1531
- column: col,
1532
- rowId: "new_record",
1533
- onChange: (v) => setNewRecordData((prev) => __spreadProps(__spreadValues({}, prev), { [col.name]: v })),
1534
- context: __spreadProps(__spreadValues({}, context), {
1535
- 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",
1536
- relationOptions,
1537
- refetchRelation
1538
- })
1539
- }
1540
- ) }, `new_${col.name}`);
2064
+ className: `border border-emerald-200 p-0 relative h-8 ${isContact ? "min-w-[140px]" : ""}`,
2065
+ children: /* @__PURE__ */ jsx5(
2066
+ InputComponent,
2067
+ {
2068
+ value: (_b2 = newRecordData[col.name]) != null ? _b2 : colType === "BOOLEAN" ? false : "",
2069
+ column: col,
2070
+ rowId: "new_record",
2071
+ onChange: (v) => setNewRecordData((prev) => __spreadProps(__spreadValues({}, prev), { [col.name]: v })),
2072
+ context: __spreadProps(__spreadValues({}, context), {
2073
+ 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",
2074
+ relationOptions,
2075
+ refetchRelation,
2076
+ tableId: (targetSchema == null ? void 0 : targetSchema.tableMetaId) || (targetSchema == null ? void 0 : targetSchema.id) || referencedTableId
2077
+ })
2078
+ }
2079
+ )
2080
+ },
2081
+ `new_${col.name}`
2082
+ );
1541
2083
  }),
1542
2084
  /* @__PURE__ */ jsx5("td", { className: "border border-emerald-200 px-1 py-1 text-center", children: /* @__PURE__ */ jsxs5("div", { className: "flex items-center justify-center gap-1", children: [
1543
2085
  /* @__PURE__ */ jsx5(
@@ -1565,7 +2107,102 @@ function SubTableViewer({ rowId, column, value, onChange, context }) {
1565
2107
  ] }) })
1566
2108
  ] })
1567
2109
  ] })
1568
- ] }) })
2110
+ ] }) }),
2111
+ conflictModalState.isOpen && /* @__PURE__ */ jsx5(
2112
+ "div",
2113
+ {
2114
+ 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",
2115
+ dir: "rtl",
2116
+ onClick: handleCancelConflict,
2117
+ children: /* @__PURE__ */ jsxs5(
2118
+ "div",
2119
+ {
2120
+ 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",
2121
+ onClick: (e) => e.stopPropagation(),
2122
+ children: [
2123
+ /* @__PURE__ */ jsxs5("div", { className: "p-5 border-b border-slate-100 flex items-center gap-3", children: [
2124
+ /* @__PURE__ */ jsx5("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__ */ jsx5("svg", { className: "w-5 h-5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx5("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" }) }) }),
2125
+ /* @__PURE__ */ jsxs5("div", { children: [
2126
+ /* @__PURE__ */ jsx5("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" }),
2127
+ /* @__PURE__ */ jsx5("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" })
2128
+ ] })
2129
+ ] }),
2130
+ /* @__PURE__ */ jsxs5("div", { className: "p-5 space-y-3", children: [
2131
+ /* @__PURE__ */ jsxs5("p", { className: "text-sm text-slate-700 leading-relaxed", children: [
2132
+ "\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",
2133
+ " ",
2134
+ /* @__PURE__ */ jsx5("span", { className: "font-bold text-slate-900 bg-slate-100 px-1.5 py-0.5 rounded border border-slate-200", children: conflictModalState.fieldName }),
2135
+ ". \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?"
2136
+ ] }),
2137
+ conflictModalState.matchingRecords.length > 1 && /* @__PURE__ */ jsxs5("div", { className: "p-3 bg-blue-50 border border-blue-200 rounded-lg text-xs font-semibold text-blue-800", children: [
2138
+ "\u05E0\u05DE\u05E6\u05D0\u05D5 ",
2139
+ conflictModalState.matchingRecords.length,
2140
+ " \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?"
2141
+ ] }),
2142
+ conflictModalState.matchingRecords.length > 0 && /* @__PURE__ */ jsx5("div", { className: "overflow-x-auto border border-slate-200 rounded-lg max-h-48 text-xs bg-white", children: /* @__PURE__ */ jsxs5("table", { className: "w-full text-right border-collapse", children: [
2143
+ /* @__PURE__ */ jsx5("thead", { children: /* @__PURE__ */ jsx5("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__ */ jsx5(
2144
+ "th",
2145
+ {
2146
+ className: "bg-slate-100 text-slate-700 font-semibold p-2 border-b whitespace-nowrap",
2147
+ children: col.name
2148
+ },
2149
+ col.name
2150
+ )) }) }),
2151
+ /* @__PURE__ */ jsx5("tbody", { children: conflictModalState.matchingRecords.map((r, idx) => {
2152
+ 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 }));
2153
+ return /* @__PURE__ */ jsx5("tr", { className: "hover:bg-slate-50/80 transition-colors", children: cols.map((col) => {
2154
+ var _a2;
2155
+ const rawVal = (_a2 = r.data) == null ? void 0 : _a2[col.name];
2156
+ let displayVal = "-";
2157
+ if (rawVal !== void 0 && rawVal !== null && rawVal !== "") {
2158
+ if (typeof rawVal === "boolean") {
2159
+ displayVal = rawVal ? "\u05DB\u05DF" : "\u05DC\u05D0";
2160
+ } else if (typeof rawVal === "object") {
2161
+ displayVal = Array.isArray(rawVal) ? rawVal.join(", ") : JSON.stringify(rawVal);
2162
+ } else {
2163
+ displayVal = String(rawVal);
2164
+ }
2165
+ }
2166
+ return /* @__PURE__ */ jsx5(
2167
+ "td",
2168
+ {
2169
+ className: "p-2 border-b border-slate-100 whitespace-nowrap text-slate-800",
2170
+ children: displayVal
2171
+ },
2172
+ col.name
2173
+ );
2174
+ }) }, r.id || idx);
2175
+ }) })
2176
+ ] }) })
2177
+ ] }),
2178
+ /* @__PURE__ */ jsxs5("div", { className: "p-4 bg-slate-50 border-t border-slate-100 flex items-center justify-end gap-2.5", children: [
2179
+ /* @__PURE__ */ jsx5(
2180
+ "button",
2181
+ {
2182
+ type: "button",
2183
+ onClick: handleCancelConflict,
2184
+ 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",
2185
+ children: "\u05D1\u05D9\u05D8\u05D5\u05DC"
2186
+ }
2187
+ ),
2188
+ /* @__PURE__ */ jsxs5(
2189
+ "button",
2190
+ {
2191
+ type: "button",
2192
+ onClick: handleConfirmLinkConflict,
2193
+ 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",
2194
+ children: [
2195
+ /* @__PURE__ */ jsx5("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx5("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" }) }),
2196
+ conflictModalState.matchingRecords.length > 1 ? "\u05E7\u05E9\u05E8 \u05D0\u05EA \u05DB\u05D5\u05DC\u05DF" : "\u05E7\u05E9\u05E8 \u05E8\u05E9\u05D5\u05DE\u05D4"
2197
+ ]
2198
+ }
2199
+ )
2200
+ ] })
2201
+ ]
2202
+ }
2203
+ )
2204
+ }
2205
+ )
1569
2206
  ] });
1570
2207
  }
1571
2208
 
@@ -2171,7 +2808,7 @@ function TableBlockClient({
2171
2808
  const formatPayload = (payload) => {
2172
2809
  const formatted = {};
2173
2810
  (localColumns || []).forEach((col) => {
2174
- var _a, _b;
2811
+ var _a, _b, _c;
2175
2812
  if (["_id", "id", "createdAt", "updatedAt", "orgId", "tableId", "isSelected"].includes(col.name)) return;
2176
2813
  let val = payload[col.name];
2177
2814
  if (val !== void 0) {
@@ -2181,7 +2818,9 @@ function TableBlockClient({
2181
2818
  if (((_a = col.type) == null ? void 0 : _a.toUpperCase()) === "NUMBER") {
2182
2819
  val = val === "" ? 0 : Number(val);
2183
2820
  if (isNaN(val)) val = 0;
2184
- } else if (((_b = col.type) == null ? void 0 : _b.toUpperCase()) === "SUB_TABLE" && Array.isArray(val)) {
2821
+ } else if (((_b = col.type) == null ? void 0 : _b.toUpperCase()) === "PHONE") {
2822
+ val = sanitizePhoneNumber(String(val));
2823
+ } else if (((_c = col.type) == null ? void 0 : _c.toUpperCase()) === "SUB_TABLE" && Array.isArray(val)) {
2185
2824
  val = val.map((item) => {
2186
2825
  const _a2 = item, { _resolvedData } = _a2, rest = __objRest(_a2, ["_resolvedData"]);
2187
2826
  return rest;
@@ -2195,7 +2834,7 @@ function TableBlockClient({
2195
2834
  };
2196
2835
  const hasChanges = dirty.added.length > 0 || Object.keys(dirty.modified).length > 0 || dirty.deleted.length > 0;
2197
2836
  const handleSave = async () => {
2198
- var _a;
2837
+ var _a, _b;
2199
2838
  if (!hasChanges) {
2200
2839
  return;
2201
2840
  }
@@ -2218,6 +2857,28 @@ function TableBlockClient({
2218
2857
  }
2219
2858
  }
2220
2859
  }
2860
+ const phoneCols = (localColumns || []).filter((c) => {
2861
+ var _a2;
2862
+ return ((_a2 = c.type) == null ? void 0 : _a2.toUpperCase()) === "PHONE";
2863
+ });
2864
+ for (const col of phoneCols) {
2865
+ for (const row of dirty.added) {
2866
+ const val = row.data[col.name];
2867
+ if (!isEmpty(val) && !isValidPhoneNumber(val)) {
2868
+ 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");
2869
+ return;
2870
+ }
2871
+ }
2872
+ for (const [rowId, mods] of Object.entries(dirty.modified)) {
2873
+ const rowData = ((_b = data.find((r) => r.id === rowId)) == null ? void 0 : _b.data) || {};
2874
+ const mergedData = __spreadValues(__spreadValues({}, rowData), mods);
2875
+ const val = mergedData[col.name];
2876
+ if (!isEmpty(val) && !isValidPhoneNumber(val)) {
2877
+ 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");
2878
+ return;
2879
+ }
2880
+ }
2881
+ }
2221
2882
  setIsSaving(true);
2222
2883
  try {
2223
2884
  if (!executeAction) {
@@ -2880,5 +3541,7 @@ export {
2880
3541
  ToastProvider,
2881
3542
  UNIVERSE_COMPONENTS,
2882
3543
  cn,
3544
+ formatPhoneDisplay,
3545
+ openWhatsAppChat,
2883
3546
  useToast
2884
3547
  };