@universe-platform/ui 0.1.0-beta.21 → 0.1.0-beta.23

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 CHANGED
@@ -1072,6 +1072,9 @@
1072
1072
  .border-emerald-500 {
1073
1073
  border-color: var(--color-emerald-500);
1074
1074
  }
1075
+ .border-emerald-600 {
1076
+ border-color: var(--color-emerald-600);
1077
+ }
1075
1078
  .border-fuchsia-200 {
1076
1079
  border-color: var(--color-fuchsia-200);
1077
1080
  }
package/dist/index.d.mts CHANGED
@@ -53,10 +53,14 @@ declare function isValidPhoneNumber(phone: string): boolean;
53
53
  */
54
54
  declare function generateWhatsAppLink(phone: string, defaultCountryCode?: string): string | null;
55
55
  /**
56
- * Normalizes a phone number for WhatsApp sending (E.164 without leading '+').
57
- * - Strips spaces, dashes, and special characters.
58
- * - If it starts with '05' (10 digits), replaces the leading '0' with '972' (e.g., '0586812807' -> '972586812807').
59
- * - If it starts with '+', strips the '+'.
56
+ * Normalizes a phone number for WhatsApp sending (Meta international format without leading '+').
57
+ * - Returns empty string if input is falsy.
58
+ * - Trims input and removes leading '+' if it exists.
59
+ * - Strips all non-digit characters.
60
+ * - If starting with '972', returns it as is.
61
+ * - If starting with '0' (Israeli mobile/landline), strips '0' and prepends '972'.
62
+ * - If exactly 9 digits long (omitted leading zero), prepends '972'.
63
+ * - Returns the processed digits string.
60
64
  */
61
65
  declare function normalizePhoneForWhatsApp(phone: string): string;
62
66
 
@@ -547,6 +551,8 @@ declare function useWhatsAppState(props: WhatsAppComponentProps): {
547
551
  isTestDisabled: boolean;
548
552
  sendButtonTitle: string;
549
553
  testButtonTitle: string;
554
+ requiresMediaHeader: boolean;
555
+ isMediaMissing: boolean;
550
556
  templates: MetaWhatsAppTemplate[];
551
557
  selectedTemplateId: string | null;
552
558
  setSelectedTemplateId: react.Dispatch<react.SetStateAction<string | null>>;
@@ -556,6 +562,8 @@ declare function useWhatsAppState(props: WhatsAppComponentProps): {
556
562
  headerMediaUrl: string;
557
563
  handleHeaderMediaUrlChange: (newUrl: string) => void;
558
564
  handleResetHeaderMediaUrl: () => void;
565
+ isUploadingMedia: boolean;
566
+ handleFileUpload: (file: File, templateName?: string) => Promise<void>;
559
567
  templateVariables: string[];
560
568
  variableMapping: TemplateVariableMapping;
561
569
  textableColumnOptions: TextableColumnOption[];
package/dist/index.d.ts CHANGED
@@ -53,10 +53,14 @@ declare function isValidPhoneNumber(phone: string): boolean;
53
53
  */
54
54
  declare function generateWhatsAppLink(phone: string, defaultCountryCode?: string): string | null;
55
55
  /**
56
- * Normalizes a phone number for WhatsApp sending (E.164 without leading '+').
57
- * - Strips spaces, dashes, and special characters.
58
- * - If it starts with '05' (10 digits), replaces the leading '0' with '972' (e.g., '0586812807' -> '972586812807').
59
- * - If it starts with '+', strips the '+'.
56
+ * Normalizes a phone number for WhatsApp sending (Meta international format without leading '+').
57
+ * - Returns empty string if input is falsy.
58
+ * - Trims input and removes leading '+' if it exists.
59
+ * - Strips all non-digit characters.
60
+ * - If starting with '972', returns it as is.
61
+ * - If starting with '0' (Israeli mobile/landline), strips '0' and prepends '972'.
62
+ * - If exactly 9 digits long (omitted leading zero), prepends '972'.
63
+ * - Returns the processed digits string.
60
64
  */
61
65
  declare function normalizePhoneForWhatsApp(phone: string): string;
62
66
 
@@ -547,6 +551,8 @@ declare function useWhatsAppState(props: WhatsAppComponentProps): {
547
551
  isTestDisabled: boolean;
548
552
  sendButtonTitle: string;
549
553
  testButtonTitle: string;
554
+ requiresMediaHeader: boolean;
555
+ isMediaMissing: boolean;
550
556
  templates: MetaWhatsAppTemplate[];
551
557
  selectedTemplateId: string | null;
552
558
  setSelectedTemplateId: react.Dispatch<react.SetStateAction<string | null>>;
@@ -556,6 +562,8 @@ declare function useWhatsAppState(props: WhatsAppComponentProps): {
556
562
  headerMediaUrl: string;
557
563
  handleHeaderMediaUrlChange: (newUrl: string) => void;
558
564
  handleResetHeaderMediaUrl: () => void;
565
+ isUploadingMedia: boolean;
566
+ handleFileUpload: (file: File, templateName?: string) => Promise<void>;
559
567
  templateVariables: string[];
560
568
  variableMapping: TemplateVariableMapping;
561
569
  textableColumnOptions: TextableColumnOption[];
package/dist/index.js CHANGED
@@ -202,9 +202,15 @@ function normalizePhoneForWhatsApp(phone) {
202
202
  cleaned = cleaned.substring(1);
203
203
  }
204
204
  const digitsOnly = cleaned.replace(/\D/g, "");
205
- if (digitsOnly.startsWith("05") && digitsOnly.length === 10) {
205
+ if (digitsOnly.startsWith("972")) {
206
+ return digitsOnly;
207
+ }
208
+ if (digitsOnly.startsWith("0")) {
206
209
  return `972${digitsOnly.substring(1)}`;
207
210
  }
211
+ if (digitsOnly.length === 9) {
212
+ return `972${digitsOnly}`;
213
+ }
208
214
  return digitsOnly;
209
215
  }
210
216
 
@@ -9727,9 +9733,12 @@ function buildTemplateComponents(params) {
9727
9733
  const format = (headerComp.format || "TEXT").toUpperCase();
9728
9734
  if (format === "IMAGE" || format === "DOCUMENT" || format === "VIDEO") {
9729
9735
  const validMediaUrl = resolveHeaderMediaUrl(headerComp, mediaUrl, selectedTemplate.name);
9736
+ console.log(
9737
+ `[MEDIA_DEBUG] template: ${selectedTemplate.name}, format: ${format}, resolvedUrl: ${validMediaUrl}`
9738
+ );
9730
9739
  if (validMediaUrl) {
9731
9740
  if (format === "DOCUMENT") {
9732
- const docFilename = resolveDocumentFilename(headerComp, validMediaUrl);
9741
+ const docFilename = resolveDocumentFilename(headerComp, validMediaUrl) || "document.pdf";
9733
9742
  components.push({
9734
9743
  type: "header",
9735
9744
  parameters: [
@@ -9898,11 +9907,6 @@ function findColumnDef(colOption, tableColumns) {
9898
9907
  }
9899
9908
  return null;
9900
9909
  }
9901
- var DEFAULT_FALLBACK_MEDIA_URLS = {
9902
- image: "https://images.unsplash.com/photo-1579202673506-ca3ce28943ef?q=80&w=800&fm=jpg&fit=crop",
9903
- document: "https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf",
9904
- video: "https://www.w3schools.com/html/mov_bbb.mp4"
9905
- };
9906
9910
  function resolveDocumentFilename(headerComp, mediaUrl) {
9907
9911
  var _a, _b, _c;
9908
9912
  if ((_a = headerComp == null ? void 0 : headerComp.document) == null ? void 0 : _a.filename) {
@@ -9916,8 +9920,11 @@ function resolveDocumentFilename(headerComp, mediaUrl) {
9916
9920
  const urlObj = new URL(mediaUrl);
9917
9921
  const pathname = urlObj.pathname;
9918
9922
  const lastSegment = pathname.substring(pathname.lastIndexOf("/") + 1);
9919
- if (lastSegment && lastSegment.toLowerCase().endsWith(".pdf")) {
9920
- return decodeURIComponent(lastSegment);
9923
+ if (lastSegment) {
9924
+ const decoded = decodeURIComponent(lastSegment).trim();
9925
+ if (decoded) {
9926
+ return decoded.includes(".") ? decoded : `${decoded}.pdf`;
9927
+ }
9921
9928
  }
9922
9929
  } catch (e) {
9923
9930
  }
@@ -9925,61 +9932,73 @@ function resolveDocumentFilename(headerComp, mediaUrl) {
9925
9932
  return "document.pdf";
9926
9933
  }
9927
9934
  function resolveHeaderMediaUrl(headerComp, customMediaUrl, templateName) {
9928
- var _a, _b, _c, _d, _e, _f, _g;
9929
- const isImageFormat = ((headerComp == null ? void 0 : headerComp.format) || "").toUpperCase() === "IMAGE";
9935
+ const format = ((headerComp == null ? void 0 : headerComp.format) || "").toUpperCase();
9936
+ const isImageFormat = format === "IMAGE";
9930
9937
  const sanitizeCandidate = (rawUrl) => {
9938
+ if (!rawUrl || typeof rawUrl !== "string") {
9939
+ return null;
9940
+ }
9931
9941
  let trimmed = rawUrl.trim();
9942
+ if (trimmed.startsWith("4:")) {
9943
+ return null;
9944
+ }
9932
9945
  if (!trimmed.startsWith("http://") && !trimmed.startsWith("https://")) {
9933
9946
  return null;
9934
9947
  }
9948
+ const lower = trimmed.toLowerCase();
9949
+ if (lower.includes("scontent.whatsapp.net") || lower.includes("lookaside.fbsbx.com")) {
9950
+ return null;
9951
+ }
9935
9952
  if (isImageFormat) {
9936
- if (trimmed.includes("unsplash.com") && trimmed.includes("auto=format")) {
9937
- trimmed = trimmed.replace("auto=format", "fm=jpg");
9953
+ if (lower.includes("unsplash.com") && lower.includes("auto=format")) {
9954
+ trimmed = trimmed.replace(/auto=format/gi, "fm=jpg");
9938
9955
  }
9939
- if (trimmed.toLowerCase().includes(".webp")) {
9956
+ if (lower.includes(".webp")) {
9940
9957
  return null;
9941
9958
  }
9942
9959
  }
9943
9960
  return trimmed;
9944
9961
  };
9945
- if (customMediaUrl && typeof customMediaUrl === "string") {
9946
- const sanitized = sanitizeCandidate(customMediaUrl);
9947
- if (sanitized) return sanitized;
9948
- }
9949
- if (headerComp) {
9950
- const candidates = [
9951
- headerComp.url,
9952
- headerComp.link,
9953
- (_a = headerComp.image) == null ? void 0 : _a.link,
9954
- (_b = headerComp.document) == null ? void 0 : _b.link,
9955
- (_c = headerComp.video) == null ? void 0 : _c.link,
9956
- (_e = (_d = headerComp.example) == null ? void 0 : _d.header_url) == null ? void 0 : _e[0],
9957
- (_g = (_f = headerComp.example) == null ? void 0 : _f.header_handle) == null ? void 0 : _g[0]
9958
- ];
9959
- for (const candidate of candidates) {
9960
- if (typeof candidate === "string") {
9961
- const sanitized = sanitizeCandidate(candidate);
9962
- if (sanitized) return sanitized;
9962
+ const computeUrl = () => {
9963
+ var _a, _b, _c, _d, _e, _f, _g;
9964
+ if (customMediaUrl && typeof customMediaUrl === "string") {
9965
+ const sanitized = sanitizeCandidate(customMediaUrl);
9966
+ if (sanitized) return sanitized;
9967
+ }
9968
+ if (templateName && typeof window !== "undefined") {
9969
+ try {
9970
+ const persisted = localStorage.getItem(`whatsapp_template_media_${templateName}`) || localStorage.getItem(`whatsapp_template_media_${templateName.toLowerCase()}`);
9971
+ if (persisted && typeof persisted === "string") {
9972
+ const sanitized = sanitizeCandidate(persisted);
9973
+ if (sanitized) return sanitized;
9974
+ }
9975
+ } catch (e) {
9963
9976
  }
9964
9977
  }
9965
- }
9966
- if (templateName && typeof window !== "undefined") {
9967
- try {
9968
- const persisted = localStorage.getItem(`whatsapp_template_media_${templateName}`);
9969
- if (persisted && typeof persisted === "string") {
9970
- const sanitized = sanitizeCandidate(persisted);
9971
- if (sanitized) return sanitized;
9978
+ if (headerComp) {
9979
+ const candidates = [
9980
+ headerComp.url,
9981
+ headerComp.link,
9982
+ (_a = headerComp.image) == null ? void 0 : _a.link,
9983
+ (_b = headerComp.document) == null ? void 0 : _b.link,
9984
+ (_c = headerComp.video) == null ? void 0 : _c.link,
9985
+ (_e = (_d = headerComp.example) == null ? void 0 : _d.header_url) == null ? void 0 : _e[0],
9986
+ (_g = (_f = headerComp.example) == null ? void 0 : _f.header_handle) == null ? void 0 : _g[0]
9987
+ ];
9988
+ for (const candidate of candidates) {
9989
+ if (typeof candidate === "string") {
9990
+ const sanitized = sanitizeCandidate(candidate);
9991
+ if (sanitized) return sanitized;
9992
+ }
9972
9993
  }
9973
- } catch (e) {
9974
9994
  }
9975
- }
9976
- if (headerComp) {
9977
- const format = (headerComp.format || "").toUpperCase();
9978
- if (format === "DOCUMENT") return DEFAULT_FALLBACK_MEDIA_URLS.document;
9979
- if (format === "VIDEO") return DEFAULT_FALLBACK_MEDIA_URLS.video;
9980
- return DEFAULT_FALLBACK_MEDIA_URLS.image;
9981
- }
9982
- return DEFAULT_FALLBACK_MEDIA_URLS.image;
9995
+ return null;
9996
+ };
9997
+ const validMediaUrl = computeUrl();
9998
+ console.log(
9999
+ `[MEDIA_DEBUG] template: ${templateName || "unknown"}, format: ${format}, resolvedUrl: ${validMediaUrl}`
10000
+ );
10001
+ return validMediaUrl;
9983
10002
  }
9984
10003
  function buildWhatsAppPayload(to, templateName, languageCode, components) {
9985
10004
  const payload = {
@@ -10000,6 +10019,10 @@ function buildWhatsAppPayload(to, templateName, languageCode, components) {
10000
10019
  }
10001
10020
  async function sendWhatsAppMessage(payload, executeAction, orgId) {
10002
10021
  try {
10022
+ console.log(
10023
+ "[whatsappApi] Dispatching WhatsApp message action with payload:",
10024
+ JSON.stringify(payload, null, 2)
10025
+ );
10003
10026
  const actionPayload = {
10004
10027
  payload
10005
10028
  };
@@ -10009,12 +10032,18 @@ async function sendWhatsAppMessage(payload, executeAction, orgId) {
10009
10032
  }
10010
10033
  const result = await executeAction("SEND_WHATSAPP_MESSAGE", actionPayload);
10011
10034
  if (result && result.success === false) {
10035
+ console.error(
10036
+ "[whatsappApi] SEND_WHATSAPP_MESSAGE dispatch failed:",
10037
+ result.error,
10038
+ result.details || result
10039
+ );
10012
10040
  return {
10013
10041
  success: false,
10014
10042
  error: result.error || "\u05E9\u05DC\u05D9\u05D7\u05EA \u05D4\u05D5\u05D3\u05E2\u05EA WhatsApp \u05E0\u05DB\u05E9\u05DC\u05D4",
10015
10043
  data: result
10016
10044
  };
10017
10045
  }
10046
+ console.log("[whatsappApi] SEND_WHATSAPP_MESSAGE dispatch succeeded:", result);
10018
10047
  return {
10019
10048
  success: true,
10020
10049
  data: result
@@ -11123,6 +11152,48 @@ function useWhatsAppState(props) {
11123
11152
  );
11124
11153
  setHeaderMediaUrl(defaultUrl || "");
11125
11154
  }, [templateHeaderComp, selectedTemplate == null ? void 0 : selectedTemplate.name]);
11155
+ const [isUploadingMedia, setIsUploadingMedia] = (0, import_react17.useState)(false);
11156
+ const handleFileUpload = (0, import_react17.useCallback)(
11157
+ async (file, templateName) => {
11158
+ const tplName = templateName || (selectedTemplate == null ? void 0 : selectedTemplate.name) || "";
11159
+ if (!file) return;
11160
+ setIsUploadingMedia(true);
11161
+ try {
11162
+ const formData = new FormData();
11163
+ formData.append("file", file);
11164
+ const res = await fetch("/api/whatsapp/upload-media", {
11165
+ method: "POST",
11166
+ body: formData
11167
+ });
11168
+ const data = await res.json().catch(() => ({}));
11169
+ if (!res.ok || !(data == null ? void 0 : data.url)) {
11170
+ throw new Error((data == null ? void 0 : data.error) || `\u05D4\u05E2\u05DC\u05D0\u05EA \u05D4\u05E7\u05D5\u05D1\u05E5 \u05E0\u05DB\u05E9\u05DC\u05D4 (${res.status})`);
11171
+ }
11172
+ const publicUrl = data.url;
11173
+ setHeaderMediaUrl(publicUrl);
11174
+ if (tplName && typeof window !== "undefined") {
11175
+ try {
11176
+ localStorage.setItem(`whatsapp_template_media_${tplName}`, publicUrl);
11177
+ localStorage.setItem(`whatsapp_template_media_${tplName.toLowerCase()}`, publicUrl);
11178
+ } catch (e) {
11179
+ }
11180
+ }
11181
+ setFeedback({
11182
+ type: "success",
11183
+ message: "\u05E7\u05D5\u05D1\u05E5 \u05D4\u05DE\u05D3\u05D9\u05D4 \u05D4\u05D5\u05E2\u05DC\u05D4 \u05D1\u05D4\u05E6\u05DC\u05D7\u05D4 \u05D5\u05E9\u05D5\u05D9\u05DA \u05DC\u05EA\u05D1\u05E0\u05D9\u05EA"
11184
+ });
11185
+ } catch (err) {
11186
+ console.error("[useWhatsAppState] handleFileUpload error:", err);
11187
+ setFeedback({
11188
+ type: "error",
11189
+ message: (err == null ? void 0 : err.message) || "\u05E9\u05D2\u05D9\u05D0\u05D4 \u05D1\u05E2\u05EA \u05D4\u05E2\u05DC\u05D0\u05EA \u05E7\u05D5\u05D1\u05E5 \u05D4\u05DE\u05D3\u05D9\u05D4"
11190
+ });
11191
+ } finally {
11192
+ setIsUploadingMedia(false);
11193
+ }
11194
+ },
11195
+ [selectedTemplate == null ? void 0 : selectedTemplate.name]
11196
+ );
11126
11197
  const templateVariables = (0, import_react17.useMemo)(() => {
11127
11198
  return extractTemplateVariables(selectedTemplate);
11128
11199
  }, [selectedTemplate]);
@@ -11240,13 +11311,20 @@ function useWhatsAppState(props) {
11240
11311
  const isTemplateValid = Boolean(
11241
11312
  selectedTemplate && getStatusConfig(selectedTemplate.status).isSelectable
11242
11313
  );
11243
- const isSendDisabled = isSendingBroadcast || isScanningPhoneColumns || !hasPhoneColumn || !isTemplateValid || selectedRowIds.length === 0 || finalRecipientCount === 0 || isSubtableFilterIncomplete || isPostSendActionIncomplete || isStaticVariableMissing;
11244
- const isTestDisabled = isSendingTest || isScanningPhoneColumns || !hasPhoneColumn || !isTemplateValid || isSubtableFilterIncomplete || isPostSendActionIncomplete || isStaticVariableMissing;
11245
- const sendButtonTitle = isSendingBroadcast ? "\u05E9\u05D5\u05DC\u05D7 \u05D4\u05D5\u05D3\u05E2\u05D5\u05EA \u05D1\u05EA\u05E4\u05D5\u05E6\u05D4..." : isScanningPhoneColumns ? "\u05D8\u05D5\u05E2\u05DF \u05E2\u05DE\u05D5\u05D3\u05D5\u05EA \u05D8\u05DC\u05E4\u05D5\u05DF..." : !hasPhoneColumn ? "\u05DC\u05D0 \u05E0\u05DE\u05E6\u05D0\u05D4 \u05E2\u05DE\u05D5\u05D3\u05EA \u05D8\u05DC\u05E4\u05D5\u05DF \u05D1\u05D8\u05D1\u05DC\u05D4" : !isTemplateValid ? "\u05D9\u05E9 \u05DC\u05D1\u05D7\u05D5\u05E8 \u05EA\u05D1\u05E0\u05D9\u05EA \u05DE\u05D0\u05D5\u05E9\u05E8\u05EA \u05EA\u05D7\u05D9\u05DC\u05D4" : isSubtableFilterIncomplete ? "\u05D9\u05E9 \u05DC\u05D1\u05D7\u05D5\u05E8 \u05E2\u05E8\u05DA \u05DC\u05E1\u05D9\u05E0\u05D5\u05DF \u05D1\u05E8\u05E9\u05D5\u05DE\u05D5\u05EA \u05D4\u05DE\u05E7\u05D5\u05E9\u05E8\u05D5\u05EA" : isPostSendActionIncomplete ? "\u05D9\u05E9 \u05DC\u05D1\u05D7\u05D5\u05E8 \u05E2\u05E8\u05DA \u05D9\u05E2\u05D3 \u05DC\u05E2\u05D3\u05DB\u05D5\u05DF \u05DC\u05D0\u05D7\u05E8 \u05E9\u05DC\u05D9\u05D7\u05D4" : isStaticVariableMissing ? "\u05D9\u05E9 \u05DC\u05D4\u05D6\u05D9\u05DF \u05E2\u05E8\u05DA \u05E2\u05D1\u05D5\u05E8 \u05DB\u05DC \u05DE\u05E9\u05EA\u05E0\u05D4 \u05D1\u05D8\u05E7\u05E1\u05D8 \u05E7\u05D1\u05D5\u05E2" : selectedRowIds.length === 0 ? "\u05D9\u05E9 \u05DC\u05D1\u05D7\u05D5\u05E8 \u05DC\u05E4\u05D7\u05D5\u05EA \u05E9\u05D5\u05E8\u05D4 \u05D0\u05D7\u05EA \u05DE\u05D4\u05D8\u05D1\u05DC\u05D4" : finalRecipientCount === 0 ? "\u05DC\u05D0 \u05E0\u05DE\u05E6\u05D0\u05D5 \u05E0\u05DE\u05E2\u05E0\u05D9\u05DD \u05E2\u05DD \u05D8\u05DC\u05E4\u05D5\u05DF \u05EA\u05E7\u05D9\u05DF \u05D4\u05EA\u05D5\u05D0\u05DE\u05D9\u05DD \u05DC\u05E1\u05D9\u05E0\u05D5\u05DF" : `\u05E9\u05DC\u05D7 \u05DC-${finalRecipientCount} \u05E0\u05DE\u05E2\u05E0\u05D9\u05DD (\u05DE\u05EA\u05D5\u05DA ${validMainRowsCount} \u05E9\u05D5\u05E8\u05D5\u05EA \u05E8\u05D0\u05E9\u05D9\u05D5\u05EA)`;
11246
- const testButtonTitle = isScanningPhoneColumns ? "\u05D8\u05D5\u05E2\u05DF \u05E2\u05DE\u05D5\u05D3\u05D5\u05EA \u05D8\u05DC\u05E4\u05D5\u05DF..." : !hasPhoneColumn ? "\u05DC\u05D0 \u05E0\u05DE\u05E6\u05D0\u05D4 \u05E2\u05DE\u05D5\u05D3\u05EA \u05D8\u05DC\u05E4\u05D5\u05DF \u05D1\u05D8\u05D1\u05DC\u05D4" : !isTemplateValid ? "\u05D9\u05E9 \u05DC\u05D1\u05D7\u05D5\u05E8 \u05EA\u05D1\u05E0\u05D9\u05EA \u05DE\u05D0\u05D5\u05E9\u05E8\u05EA \u05EA\u05D7\u05D9\u05DC\u05D4" : isSubtableFilterIncomplete ? "\u05D9\u05E9 \u05DC\u05D1\u05D7\u05D5\u05E8 \u05E2\u05E8\u05DA \u05DC\u05E1\u05D9\u05E0\u05D5\u05DF \u05D1\u05E8\u05E9\u05D5\u05DE\u05D5\u05EA \u05D4\u05DE\u05E7\u05D5\u05E9\u05E8\u05D5\u05EA" : isPostSendActionIncomplete ? "\u05D9\u05E9 \u05DC\u05D1\u05D7\u05D5\u05E8 \u05E2\u05E8\u05DA \u05D9\u05E2\u05D3 \u05DC\u05E2\u05D3\u05DB\u05D5\u05DF \u05DC\u05D0\u05D7\u05E8 \u05E9\u05DC\u05D9\u05D7\u05D4" : isStaticVariableMissing ? "\u05D9\u05E9 \u05DC\u05D4\u05D6\u05D9\u05DF \u05E2\u05E8\u05DA \u05E2\u05D1\u05D5\u05E8 \u05DB\u05DC \u05DE\u05E9\u05EA\u05E0\u05D4 \u05D1\u05D8\u05E7\u05E1\u05D8 \u05E7\u05D1\u05D5\u05E2" : "\u05E9\u05DC\u05D9\u05D7\u05EA \u05D4\u05D5\u05D3\u05E2\u05EA \u05D1\u05D3\u05D9\u05E7\u05D4 \u05DC\u05DE\u05E1\u05E4\u05E8 \u05D1\u05D3\u05D9\u05E7\u05D4";
11314
+ const headerFormat = ((templateHeaderComp == null ? void 0 : templateHeaderComp.format) || "").toUpperCase();
11315
+ const requiresMediaHeader = headerFormat === "IMAGE" || headerFormat === "DOCUMENT" || headerFormat === "VIDEO";
11316
+ const isMediaMissing = requiresMediaHeader && (!headerMediaUrl || !headerMediaUrl.trim() || !headerMediaUrl.startsWith("http"));
11317
+ const isSendDisabled = isSendingBroadcast || isScanningPhoneColumns || !hasPhoneColumn || !isTemplateValid || selectedRowIds.length === 0 || finalRecipientCount === 0 || isSubtableFilterIncomplete || isPostSendActionIncomplete || isStaticVariableMissing || isMediaMissing;
11318
+ const isTestDisabled = isSendingTest || isScanningPhoneColumns || !hasPhoneColumn || !isTemplateValid || isSubtableFilterIncomplete || isPostSendActionIncomplete || isStaticVariableMissing || isMediaMissing;
11319
+ const sendButtonTitle = isSendingBroadcast ? "\u05E9\u05D5\u05DC\u05D7 \u05D4\u05D5\u05D3\u05E2\u05D5\u05EA \u05D1\u05EA\u05E4\u05D5\u05E6\u05D4..." : isScanningPhoneColumns ? "\u05D8\u05D5\u05E2\u05DF \u05E2\u05DE\u05D5\u05D3\u05D5\u05EA \u05D8\u05DC\u05E4\u05D5\u05DF..." : !hasPhoneColumn ? "\u05DC\u05D0 \u05E0\u05DE\u05E6\u05D0\u05D4 \u05E2\u05DE\u05D5\u05D3\u05EA \u05D8\u05DC\u05E4\u05D5\u05DF \u05D1\u05D8\u05D1\u05DC\u05D4" : !isTemplateValid ? "\u05D9\u05E9 \u05DC\u05D1\u05D7\u05D5\u05E8 \u05EA\u05D1\u05E0\u05D9\u05EA \u05DE\u05D0\u05D5\u05E9\u05E8\u05EA \u05EA\u05D7\u05D9\u05DC\u05D4" : isMediaMissing ? "\u05D9\u05E9 \u05DC\u05D4\u05E2\u05DC\u05D5\u05EA \u05E7\u05D5\u05D1\u05E5 \u05E2\u05D1\u05D5\u05E8 \u05EA\u05D1\u05E0\u05D9\u05EA \u05D6\u05D5 \u05DB\u05D3\u05D9 \u05DC\u05E9\u05DC\u05D5\u05D7" : isSubtableFilterIncomplete ? "\u05D9\u05E9 \u05DC\u05D1\u05D7\u05D5\u05E8 \u05E2\u05E8\u05DA \u05DC\u05E1\u05D9\u05E0\u05D5\u05DF \u05D1\u05E8\u05E9\u05D5\u05DE\u05D5\u05EA \u05D4\u05DE\u05E7\u05D5\u05E9\u05E8\u05D5\u05EA" : isPostSendActionIncomplete ? "\u05D9\u05E9 \u05DC\u05D1\u05D7\u05D5\u05E8 \u05E2\u05E8\u05DA \u05D9\u05E2\u05D3 \u05DC\u05E2\u05D3\u05DB\u05D5\u05DF \u05DC\u05D0\u05D7\u05E8 \u05E9\u05DC\u05D9\u05D7\u05D4" : isStaticVariableMissing ? "\u05D9\u05E9 \u05DC\u05D4\u05D6\u05D9\u05DF \u05E2\u05E8\u05DA \u05E2\u05D1\u05D5\u05E8 \u05DB\u05DC \u05DE\u05E9\u05EA\u05E0\u05D4 \u05D1\u05D8\u05E7\u05E1\u05D8 \u05E7\u05D1\u05D5\u05E2" : selectedRowIds.length === 0 ? "\u05D9\u05E9 \u05DC\u05D1\u05D7\u05D5\u05E8 \u05DC\u05E4\u05D7\u05D5\u05EA \u05E9\u05D5\u05E8\u05D4 \u05D0\u05D7\u05EA \u05DE\u05D4\u05D8\u05D1\u05DC\u05D4" : finalRecipientCount === 0 ? "\u05DC\u05D0 \u05E0\u05DE\u05E6\u05D0\u05D5 \u05E0\u05DE\u05E2\u05E0\u05D9\u05DD \u05E2\u05DD \u05D8\u05DC\u05E4\u05D5\u05DF \u05EA\u05E7\u05D9\u05DF \u05D4\u05EA\u05D5\u05D0\u05DE\u05D9\u05DD \u05DC\u05E1\u05D9\u05E0\u05D5\u05DF" : `\u05E9\u05DC\u05D7 \u05DC-${finalRecipientCount} \u05E0\u05DE\u05E2\u05E0\u05D9\u05DD (\u05DE\u05EA\u05D5\u05DA ${validMainRowsCount} \u05E9\u05D5\u05E8\u05D5\u05EA \u05E8\u05D0\u05E9\u05D9\u05D5\u05EA)`;
11320
+ const testButtonTitle = isScanningPhoneColumns ? "\u05D8\u05D5\u05E2\u05DF \u05E2\u05DE\u05D5\u05D3\u05D5\u05EA \u05D8\u05DC\u05E4\u05D5\u05DF..." : !hasPhoneColumn ? "\u05DC\u05D0 \u05E0\u05DE\u05E6\u05D0\u05D4 \u05E2\u05DE\u05D5\u05D3\u05EA \u05D8\u05DC\u05E4\u05D5\u05DF \u05D1\u05D8\u05D1\u05DC\u05D4" : !isTemplateValid ? "\u05D9\u05E9 \u05DC\u05D1\u05D7\u05D5\u05E8 \u05EA\u05D1\u05E0\u05D9\u05EA \u05DE\u05D0\u05D5\u05E9\u05E8\u05EA \u05EA\u05D7\u05D9\u05DC\u05D4" : isMediaMissing ? "\u05D9\u05E9 \u05DC\u05D4\u05E2\u05DC\u05D5\u05EA \u05E7\u05D5\u05D1\u05E5 \u05E2\u05D1\u05D5\u05E8 \u05EA\u05D1\u05E0\u05D9\u05EA \u05D6\u05D5 \u05DB\u05D3\u05D9 \u05DC\u05E9\u05DC\u05D5\u05D7" : isSubtableFilterIncomplete ? "\u05D9\u05E9 \u05DC\u05D1\u05D7\u05D5\u05E8 \u05E2\u05E8\u05DA \u05DC\u05E1\u05D9\u05E0\u05D5\u05DF \u05D1\u05E8\u05E9\u05D5\u05DE\u05D5\u05EA \u05D4\u05DE\u05E7\u05D5\u05E9\u05E8\u05D5\u05EA" : isPostSendActionIncomplete ? "\u05D9\u05E9 \u05DC\u05D1\u05D7\u05D5\u05E8 \u05E2\u05E8\u05DA \u05D9\u05E2\u05D3 \u05DC\u05E2\u05D3\u05DB\u05D5\u05DF \u05DC\u05D0\u05D7\u05E8 \u05E9\u05DC\u05D9\u05D7\u05D4" : isStaticVariableMissing ? "\u05D9\u05E9 \u05DC\u05D4\u05D6\u05D9\u05DF \u05E2\u05E8\u05DA \u05E2\u05D1\u05D5\u05E8 \u05DB\u05DC \u05DE\u05E9\u05EA\u05E0\u05D4 \u05D1\u05D8\u05E7\u05E1\u05D8 \u05E7\u05D1\u05D5\u05E2" : "\u05E9\u05DC\u05D9\u05D7\u05EA \u05D4\u05D5\u05D3\u05E2\u05EA \u05D1\u05D3\u05D9\u05E7\u05D4 \u05DC\u05DE\u05E1\u05E4\u05E8 \u05D1\u05D3\u05D9\u05E7\u05D4";
11247
11321
  const handleSendTest = async () => {
11248
11322
  var _a2;
11249
11323
  if (isSendingTest) return;
11324
+ if (isMediaMissing) {
11325
+ setTestFeedback("\u05D9\u05E9 \u05DC\u05D4\u05E2\u05DC\u05D5\u05EA \u05E7\u05D5\u05D1\u05E5 \u05E2\u05D1\u05D5\u05E8 \u05EA\u05D1\u05E0\u05D9\u05EA \u05D6\u05D5 \u05DB\u05D3\u05D9 \u05DC\u05E9\u05DC\u05D5\u05D7");
11326
+ return;
11327
+ }
11250
11328
  if (isSubtableFilterIncomplete) {
11251
11329
  setTestFeedback("\u05D9\u05E9 \u05DC\u05D1\u05D7\u05D5\u05E8 \u05E2\u05E8\u05DA \u05DC\u05E1\u05D9\u05E0\u05D5\u05DF \u05D1\u05E8\u05E9\u05D5\u05DE\u05D5\u05EA \u05D4\u05DE\u05E7\u05D5\u05E9\u05E8\u05D5\u05EA");
11252
11330
  return;
@@ -11588,6 +11666,8 @@ function useWhatsAppState(props) {
11588
11666
  isTestDisabled,
11589
11667
  sendButtonTitle,
11590
11668
  testButtonTitle,
11669
+ requiresMediaHeader,
11670
+ isMediaMissing,
11591
11671
  // Templates & Meta API
11592
11672
  templates,
11593
11673
  selectedTemplateId,
@@ -11598,6 +11678,8 @@ function useWhatsAppState(props) {
11598
11678
  headerMediaUrl,
11599
11679
  handleHeaderMediaUrlChange,
11600
11680
  handleResetHeaderMediaUrl,
11681
+ isUploadingMedia,
11682
+ handleFileUpload,
11601
11683
  templateVariables,
11602
11684
  variableMapping,
11603
11685
  textableColumnOptions,
@@ -11634,6 +11716,7 @@ function useWhatsAppState(props) {
11634
11716
  }
11635
11717
 
11636
11718
  // src/components/WhatsAppComponent/ui/TemplateSelectionBlock.tsx
11719
+ var import_react18 = require("react");
11637
11720
  var import_lucide_react11 = require("lucide-react");
11638
11721
  var import_jsx_runtime15 = require("react/jsx-runtime");
11639
11722
  function TemplateSelectionBlock({
@@ -11657,8 +11740,11 @@ function TemplateSelectionBlock({
11657
11740
  handleDeleteTemplate,
11658
11741
  isDeleting,
11659
11742
  setIsModalOpen,
11660
- setFeedback
11743
+ setFeedback,
11744
+ isUploadingMedia = false,
11745
+ handleFileUpload
11661
11746
  }) {
11747
+ const fileInputRef = (0, import_react18.useRef)(null);
11662
11748
  return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "col-span-12 lg:col-span-5 min-h-[26rem] h-full flex flex-col bg-slate-50/70 border border-slate-200 rounded-2xl p-3.5 relative", children: [
11663
11749
  /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "space-y-1.5 shrink-0", children: [
11664
11750
  /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex items-center justify-between pb-1.5 border-b border-slate-200/70 shrink-0 gap-2", children: [
@@ -11838,10 +11924,15 @@ function TemplateSelectionBlock({
11838
11924
  })(),
11839
11925
  templateHeaderComp && (() => {
11840
11926
  const headerFormat = (templateHeaderComp.format || "").toUpperCase();
11927
+ if (headerFormat !== "IMAGE" && headerFormat !== "DOCUMENT" && headerFormat !== "VIDEO") {
11928
+ return null;
11929
+ }
11841
11930
  const docFilename = resolveDocumentFilename(templateHeaderComp, headerMediaUrl);
11931
+ const hasValidMedia = Boolean(headerMediaUrl && headerMediaUrl.trim() && headerMediaUrl.startsWith("http"));
11932
+ const uploadButtonLabel = headerFormat === "DOCUMENT" ? "\u05D4\u05E2\u05DC\u05D4 \u05DE\u05E1\u05DE\u05DA" : headerFormat === "IMAGE" ? "\u05D4\u05E2\u05DC\u05D4 \u05EA\u05DE\u05D5\u05E0\u05D4" : "\u05D4\u05E2\u05DC\u05D4 \u05E7\u05D5\u05D1\u05E5";
11842
11933
  return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "p-2.5 bg-slate-50 border border-slate-200/90 rounded-xl flex items-center justify-between gap-3 shrink-0 shadow-2xs", children: [
11843
11934
  /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "flex items-center gap-2.5 overflow-hidden", children: headerFormat === "IMAGE" ? /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_jsx_runtime15.Fragment, { children: [
11844
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "w-8 h-8 rounded-lg overflow-hidden border border-slate-200 shrink-0 bg-slate-100 flex items-center justify-center", children: headerMediaUrl && headerMediaUrl.startsWith("http") ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
11935
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "w-8 h-8 rounded-lg overflow-hidden border border-slate-200 shrink-0 bg-slate-100 flex items-center justify-center", children: hasValidMedia ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
11845
11936
  "img",
11846
11937
  {
11847
11938
  src: headerMediaUrl,
@@ -11851,26 +11942,33 @@ function TemplateSelectionBlock({
11851
11942
  e.currentTarget.style.display = "none";
11852
11943
  }
11853
11944
  }
11854
- ) : /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_lucide_react11.Image, { className: "w-4 h-4 text-emerald-600" }) }),
11945
+ ) : /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_lucide_react11.Image, { className: "w-4 h-4 text-amber-600" }) }),
11855
11946
  /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "overflow-hidden", children: [
11856
11947
  /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "text-xs font-bold text-slate-800 block truncate", children: "\u05EA\u05DE\u05D5\u05E0\u05EA \u05DB\u05D5\u05EA\u05E8\u05EA" }),
11857
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "text-[10px] text-slate-400 block truncate", children: "\u05E7\u05D5\u05D1\u05E5 \u05DE\u05D3\u05D9\u05D4 \u05DE\u05E6\u05D5\u05E8\u05E3 \u05D1-Header" })
11948
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "text-[10px] text-slate-400 block truncate", children: hasValidMedia ? "\u05E7\u05D5\u05D1\u05E5 \u05EA\u05DE\u05D5\u05E0\u05D4 \u05DE\u05E7\u05D5\u05E9\u05E8 \u05DC\u05EA\u05D1\u05E0\u05D9\u05EA" : "\u05D8\u05E8\u05DD \u05D4\u05D5\u05E2\u05DC\u05D4 \u05E7\u05D5\u05D1\u05E5 \u05EA\u05DE\u05D5\u05E0\u05D4" })
11858
11949
  ] })
11859
11950
  ] }) : headerFormat === "DOCUMENT" ? /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_jsx_runtime15.Fragment, { children: [
11860
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "w-8 h-8 rounded-lg bg-rose-50 text-rose-600 border border-rose-100 flex items-center justify-center shrink-0", children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_lucide_react11.FileText, { className: "w-4 h-4" }) }),
11951
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: `w-8 h-8 rounded-lg flex items-center justify-center shrink-0 border ${hasValidMedia ? "bg-rose-50 text-rose-600 border-rose-100" : "bg-slate-100 text-slate-400 border-slate-200"}`, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_lucide_react11.FileText, { className: "w-4 h-4" }) }),
11861
11952
  /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "overflow-hidden", children: [
11862
11953
  /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "text-xs font-bold text-slate-800 block truncate", children: "\u05DE\u05E1\u05DE\u05DA \u05DB\u05D5\u05EA\u05E8\u05EA (PDF)" }),
11863
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "text-[10px] text-slate-500 font-mono block truncate", title: docFilename, children: docFilename })
11954
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "text-[10px] text-slate-500 font-mono block truncate", title: hasValidMedia ? docFilename : void 0, children: hasValidMedia ? docFilename : "\u05D8\u05E8\u05DD \u05D4\u05D5\u05E2\u05DC\u05D4 \u05E7\u05D5\u05D1\u05E5 \u05DE\u05E1\u05DE\u05DA" })
11864
11955
  ] })
11865
11956
  ] }) : /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_jsx_runtime15.Fragment, { children: [
11866
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "w-8 h-8 rounded-lg bg-indigo-50 text-indigo-600 border border-indigo-100 flex items-center justify-center shrink-0", children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_lucide_react11.Video, { className: "w-4 h-4" }) }),
11957
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: `w-8 h-8 rounded-lg flex items-center justify-center shrink-0 border ${hasValidMedia ? "bg-indigo-50 text-indigo-600 border-indigo-100" : "bg-slate-100 text-slate-400 border-slate-200"}`, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_lucide_react11.Video, { className: "w-4 h-4" }) }),
11867
11958
  /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "overflow-hidden", children: [
11868
11959
  /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "text-xs font-bold text-slate-800 block truncate", children: "\u05E1\u05E8\u05D8\u05D5\u05DF \u05DB\u05D5\u05EA\u05E8\u05EA" }),
11869
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "text-[10px] text-slate-400 block truncate", children: "\u05E7\u05D5\u05D1\u05E5 \u05D5\u05D9\u05D3\u05D0\u05D5 \u05DE\u05E6\u05D5\u05E8\u05E3 \u05D1-Header" })
11960
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "text-[10px] text-slate-400 block truncate", children: hasValidMedia ? "\u05E7\u05D5\u05D1\u05E5 \u05D5\u05D9\u05D3\u05D0\u05D5 \u05DE\u05E7\u05D5\u05E9\u05E8 \u05DC\u05EA\u05D1\u05E0\u05D9\u05EA" : "\u05D8\u05E8\u05DD \u05D4\u05D5\u05E2\u05DC\u05D4 \u05E7\u05D5\u05D1\u05E5 \u05D5\u05D9\u05D3\u05D0\u05D5" })
11870
11961
  ] })
11871
11962
  ] }) }),
11872
- /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex items-center gap-1.5 shrink-0", children: [
11873
- headerMediaUrl && headerMediaUrl.startsWith("http") && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
11963
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex items-center gap-2 shrink-0", children: [
11964
+ hasValidMedia ? /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("span", { className: "inline-flex items-center gap-1 text-[10px] font-medium text-emerald-800 px-2 py-0.5 bg-emerald-50 border border-emerald-200 rounded-lg", children: [
11965
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_lucide_react11.CheckCircle2, { className: "w-3 h-3 text-emerald-600" }),
11966
+ "\u05E7\u05D5\u05D1\u05E5 \u05DE\u05E6\u05D5\u05E8\u05E3 \u05EA\u05E7\u05D9\u05DF"
11967
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("span", { className: "inline-flex items-center gap-1 text-[10px] font-semibold text-amber-800 px-2 py-0.5 bg-amber-50 border border-amber-200 rounded-lg", children: [
11968
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_lucide_react11.AlertCircle, { className: "w-3 h-3 text-amber-600 shrink-0" }),
11969
+ "\u05E0\u05D3\u05E8\u05E9 \u05E6\u05D9\u05E8\u05D5\u05E3 \u05E7\u05D5\u05D1\u05E5 \u05DC\u05EA\u05D1\u05E0\u05D9\u05EA \u05D6\u05D5"
11970
+ ] }),
11971
+ hasValidMedia && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
11874
11972
  "a",
11875
11973
  {
11876
11974
  href: headerMediaUrl,
@@ -11881,7 +11979,44 @@ function TemplateSelectionBlock({
11881
11979
  children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_lucide_react11.ExternalLink, { className: "w-3.5 h-3.5" })
11882
11980
  }
11883
11981
  ),
11884
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "text-[9px] text-emerald-800 font-semibold px-1.5 py-0.5 bg-emerald-50 border border-emerald-200 rounded-md", children: "\u05DE\u05E6\u05D5\u05E8\u05E3 \u05D0\u05D5\u05D8\u05D5\u05DE\u05D8\u05D9\u05EA" })
11982
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
11983
+ "input",
11984
+ {
11985
+ ref: fileInputRef,
11986
+ type: "file",
11987
+ className: "hidden",
11988
+ accept: headerFormat === "DOCUMENT" ? ".pdf,application/pdf" : headerFormat === "VIDEO" ? "video/mp4,video/*" : "image/png,image/jpeg,image/jpg",
11989
+ onChange: (e) => {
11990
+ var _a;
11991
+ const file = (_a = e.target.files) == null ? void 0 : _a[0];
11992
+ if (file && handleFileUpload && (selectedTemplate == null ? void 0 : selectedTemplate.name)) {
11993
+ handleFileUpload(file, selectedTemplate.name);
11994
+ }
11995
+ e.target.value = "";
11996
+ },
11997
+ disabled: isUploadingMedia
11998
+ }
11999
+ ),
12000
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
12001
+ "button",
12002
+ {
12003
+ type: "button",
12004
+ disabled: isUploadingMedia,
12005
+ onClick: () => {
12006
+ var _a;
12007
+ return (_a = fileInputRef.current) == null ? void 0 : _a.click();
12008
+ },
12009
+ className: `inline-flex items-center gap-1.5 px-2.5 py-1 text-[11px] font-medium rounded-lg transition-colors border shadow-2xs ${isUploadingMedia ? "bg-slate-100 text-slate-400 border-slate-200 cursor-not-allowed" : hasValidMedia ? "bg-white text-slate-700 hover:bg-slate-50 border-slate-200 hover:border-slate-300" : "bg-emerald-600 text-white hover:bg-emerald-700 border-emerald-600"}`,
12010
+ title: hasValidMedia ? "\u05D4\u05D7\u05DC\u05E3 \u05E7\u05D5\u05D1\u05E5 \u05DE\u05D3\u05D9\u05D4 \u05DC\u05EA\u05D1\u05E0\u05D9\u05EA \u05D6\u05D5" : `${uploadButtonLabel} \u05DC\u05EA\u05D1\u05E0\u05D9\u05EA \u05D6\u05D5`,
12011
+ children: isUploadingMedia ? /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_jsx_runtime15.Fragment, { children: [
12012
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_lucide_react11.Loader2, { className: "w-3.5 h-3.5 animate-spin" }),
12013
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { children: "\u05DE\u05E2\u05DC\u05D4..." })
12014
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_jsx_runtime15.Fragment, { children: [
12015
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_lucide_react11.Upload, { className: "w-3.5 h-3.5" }),
12016
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { children: hasValidMedia ? "\u05D4\u05D7\u05DC\u05E3 \u05E7\u05D5\u05D1\u05E5" : uploadButtonLabel })
12017
+ ] })
12018
+ }
12019
+ )
11885
12020
  ] })
11886
12021
  ] });
11887
12022
  })(),
@@ -12637,7 +12772,9 @@ function WhatsAppComponent(props) {
12637
12772
  handleDeleteTemplate: state.handleDeleteTemplate,
12638
12773
  isDeleting: state.isDeleting,
12639
12774
  setIsModalOpen: state.setIsModalOpen,
12640
- setFeedback: state.setFeedback
12775
+ setFeedback: state.setFeedback,
12776
+ isUploadingMedia: state.isUploadingMedia,
12777
+ handleFileUpload: state.handleFileUpload
12641
12778
  }
12642
12779
  ),
12643
12780
  /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
@@ -12823,7 +12960,7 @@ function WhatsAppComponent(props) {
12823
12960
  /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "w-7 h-7 rounded-md bg-indigo-50 text-indigo-600 border border-indigo-100 flex items-center justify-center shrink-0", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_lucide_react14.Video, { className: "w-3.5 h-3.5" }) }),
12824
12961
  /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "font-semibold text-slate-800 truncate", children: "\u05E1\u05E8\u05D8\u05D5\u05DF \u05DB\u05D5\u05EA\u05E8\u05EA" })
12825
12962
  ] }) }),
12826
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "text-[10px] text-emerald-700 bg-emerald-50 border border-emerald-200 px-1.5 py-0.5 rounded font-medium shrink-0", children: "\u05DE\u05E6\u05D5\u05E8\u05E3 \u05D0\u05D5\u05D8\u05D5\u05DE\u05D8\u05D9\u05EA" })
12963
+ state.headerMediaUrl && state.headerMediaUrl.startsWith("http") ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "text-[10px] text-emerald-700 bg-emerald-50 border border-emerald-200 px-1.5 py-0.5 rounded font-medium shrink-0", children: "\u05E7\u05D5\u05D1\u05E5 \u05DE\u05E6\u05D5\u05E8\u05E3 \u05EA\u05E7\u05D9\u05DF" }) : /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "text-[10px] text-amber-700 bg-amber-50 border border-amber-200 px-1.5 py-0.5 rounded font-medium shrink-0", children: "\u05E0\u05D3\u05E8\u05E9 \u05E6\u05D9\u05E8\u05D5\u05E3 \u05E7\u05D5\u05D1\u05E5 \u05DC\u05EA\u05D1\u05E0\u05D9\u05EA \u05D6\u05D5" })
12827
12964
  ] });
12828
12965
  })(),
12829
12966
  /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "space-y-1.5", children: [
@@ -12882,9 +13019,10 @@ function WhatsAppComponent(props) {
12882
13019
  "button",
12883
13020
  {
12884
13021
  type: "button",
12885
- disabled: !state.testPhoneNumber.trim() || state.isSendingTest,
13022
+ disabled: !state.testPhoneNumber.trim() || state.isSendingTest || state.isTestDisabled,
12886
13023
  onClick: state.handleSendTest,
12887
- className: `px-4 py-2 text-xs font-bold rounded-xl transition-all flex items-center gap-1.5 ${!state.testPhoneNumber.trim() || state.isSendingTest ? "bg-emerald-600/40 text-white/70 cursor-not-allowed" : "bg-emerald-600 hover:bg-emerald-700 active:scale-[0.98] text-white shadow-xs cursor-pointer"}`,
13024
+ title: state.testButtonTitle,
13025
+ className: `px-4 py-2 text-xs font-bold rounded-xl transition-all flex items-center gap-1.5 ${!state.testPhoneNumber.trim() || state.isSendingTest || state.isTestDisabled ? "bg-emerald-600/40 text-white/70 cursor-not-allowed" : "bg-emerald-600 hover:bg-emerald-700 active:scale-[0.98] text-white shadow-xs cursor-pointer"}`,
12888
13026
  children: state.isSendingTest ? /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_jsx_runtime18.Fragment, { children: [
12889
13027
  /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_lucide_react14.Loader2, { className: "w-3.5 h-3.5 animate-spin" }),
12890
13028
  /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { children: "\u05E9\u05D5\u05DC\u05D7..." })
package/dist/index.mjs CHANGED
@@ -97,9 +97,15 @@ function normalizePhoneForWhatsApp(phone) {
97
97
  cleaned = cleaned.substring(1);
98
98
  }
99
99
  const digitsOnly = cleaned.replace(/\D/g, "");
100
- if (digitsOnly.startsWith("05") && digitsOnly.length === 10) {
100
+ if (digitsOnly.startsWith("972")) {
101
+ return digitsOnly;
102
+ }
103
+ if (digitsOnly.startsWith("0")) {
101
104
  return `972${digitsOnly.substring(1)}`;
102
105
  }
106
+ if (digitsOnly.length === 9) {
107
+ return `972${digitsOnly}`;
108
+ }
103
109
  return digitsOnly;
104
110
  }
105
111
 
@@ -7713,7 +7719,7 @@ function TableBlock(props) {
7713
7719
  }
7714
7720
 
7715
7721
  // src/components/WhatsAppComponent/WhatsAppComponent.tsx
7716
- import { CheckCircle2 as CheckCircle23, AlertCircle as AlertCircle4, X as X12, Loader2 as Loader27, Phone as Phone4, Send as Send2, Image as ImageIcon3, FileText as FileText4, Video as Video3 } from "lucide-react";
7722
+ import { CheckCircle2 as CheckCircle24, AlertCircle as AlertCircle5, X as X12, Loader2 as Loader27, Phone as Phone4, Send as Send2, Image as ImageIcon3, FileText as FileText4, Video as Video3 } from "lucide-react";
7717
7723
 
7718
7724
  // src/components/WhatsAppComponent/CreateTemplateModal.tsx
7719
7725
  import { useState as useState14, useEffect as useEffect12, useRef as useRef11, useMemo as useMemo7 } from "react";
@@ -9645,9 +9651,12 @@ function buildTemplateComponents(params) {
9645
9651
  const format = (headerComp.format || "TEXT").toUpperCase();
9646
9652
  if (format === "IMAGE" || format === "DOCUMENT" || format === "VIDEO") {
9647
9653
  const validMediaUrl = resolveHeaderMediaUrl(headerComp, mediaUrl, selectedTemplate.name);
9654
+ console.log(
9655
+ `[MEDIA_DEBUG] template: ${selectedTemplate.name}, format: ${format}, resolvedUrl: ${validMediaUrl}`
9656
+ );
9648
9657
  if (validMediaUrl) {
9649
9658
  if (format === "DOCUMENT") {
9650
- const docFilename = resolveDocumentFilename(headerComp, validMediaUrl);
9659
+ const docFilename = resolveDocumentFilename(headerComp, validMediaUrl) || "document.pdf";
9651
9660
  components.push({
9652
9661
  type: "header",
9653
9662
  parameters: [
@@ -9816,11 +9825,6 @@ function findColumnDef(colOption, tableColumns) {
9816
9825
  }
9817
9826
  return null;
9818
9827
  }
9819
- var DEFAULT_FALLBACK_MEDIA_URLS = {
9820
- image: "https://images.unsplash.com/photo-1579202673506-ca3ce28943ef?q=80&w=800&fm=jpg&fit=crop",
9821
- document: "https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf",
9822
- video: "https://www.w3schools.com/html/mov_bbb.mp4"
9823
- };
9824
9828
  function resolveDocumentFilename(headerComp, mediaUrl) {
9825
9829
  var _a, _b, _c;
9826
9830
  if ((_a = headerComp == null ? void 0 : headerComp.document) == null ? void 0 : _a.filename) {
@@ -9834,8 +9838,11 @@ function resolveDocumentFilename(headerComp, mediaUrl) {
9834
9838
  const urlObj = new URL(mediaUrl);
9835
9839
  const pathname = urlObj.pathname;
9836
9840
  const lastSegment = pathname.substring(pathname.lastIndexOf("/") + 1);
9837
- if (lastSegment && lastSegment.toLowerCase().endsWith(".pdf")) {
9838
- return decodeURIComponent(lastSegment);
9841
+ if (lastSegment) {
9842
+ const decoded = decodeURIComponent(lastSegment).trim();
9843
+ if (decoded) {
9844
+ return decoded.includes(".") ? decoded : `${decoded}.pdf`;
9845
+ }
9839
9846
  }
9840
9847
  } catch (e) {
9841
9848
  }
@@ -9843,61 +9850,73 @@ function resolveDocumentFilename(headerComp, mediaUrl) {
9843
9850
  return "document.pdf";
9844
9851
  }
9845
9852
  function resolveHeaderMediaUrl(headerComp, customMediaUrl, templateName) {
9846
- var _a, _b, _c, _d, _e, _f, _g;
9847
- const isImageFormat = ((headerComp == null ? void 0 : headerComp.format) || "").toUpperCase() === "IMAGE";
9853
+ const format = ((headerComp == null ? void 0 : headerComp.format) || "").toUpperCase();
9854
+ const isImageFormat = format === "IMAGE";
9848
9855
  const sanitizeCandidate = (rawUrl) => {
9856
+ if (!rawUrl || typeof rawUrl !== "string") {
9857
+ return null;
9858
+ }
9849
9859
  let trimmed = rawUrl.trim();
9860
+ if (trimmed.startsWith("4:")) {
9861
+ return null;
9862
+ }
9850
9863
  if (!trimmed.startsWith("http://") && !trimmed.startsWith("https://")) {
9851
9864
  return null;
9852
9865
  }
9866
+ const lower = trimmed.toLowerCase();
9867
+ if (lower.includes("scontent.whatsapp.net") || lower.includes("lookaside.fbsbx.com")) {
9868
+ return null;
9869
+ }
9853
9870
  if (isImageFormat) {
9854
- if (trimmed.includes("unsplash.com") && trimmed.includes("auto=format")) {
9855
- trimmed = trimmed.replace("auto=format", "fm=jpg");
9871
+ if (lower.includes("unsplash.com") && lower.includes("auto=format")) {
9872
+ trimmed = trimmed.replace(/auto=format/gi, "fm=jpg");
9856
9873
  }
9857
- if (trimmed.toLowerCase().includes(".webp")) {
9874
+ if (lower.includes(".webp")) {
9858
9875
  return null;
9859
9876
  }
9860
9877
  }
9861
9878
  return trimmed;
9862
9879
  };
9863
- if (customMediaUrl && typeof customMediaUrl === "string") {
9864
- const sanitized = sanitizeCandidate(customMediaUrl);
9865
- if (sanitized) return sanitized;
9866
- }
9867
- if (headerComp) {
9868
- const candidates = [
9869
- headerComp.url,
9870
- headerComp.link,
9871
- (_a = headerComp.image) == null ? void 0 : _a.link,
9872
- (_b = headerComp.document) == null ? void 0 : _b.link,
9873
- (_c = headerComp.video) == null ? void 0 : _c.link,
9874
- (_e = (_d = headerComp.example) == null ? void 0 : _d.header_url) == null ? void 0 : _e[0],
9875
- (_g = (_f = headerComp.example) == null ? void 0 : _f.header_handle) == null ? void 0 : _g[0]
9876
- ];
9877
- for (const candidate of candidates) {
9878
- if (typeof candidate === "string") {
9879
- const sanitized = sanitizeCandidate(candidate);
9880
- if (sanitized) return sanitized;
9880
+ const computeUrl = () => {
9881
+ var _a, _b, _c, _d, _e, _f, _g;
9882
+ if (customMediaUrl && typeof customMediaUrl === "string") {
9883
+ const sanitized = sanitizeCandidate(customMediaUrl);
9884
+ if (sanitized) return sanitized;
9885
+ }
9886
+ if (templateName && typeof window !== "undefined") {
9887
+ try {
9888
+ const persisted = localStorage.getItem(`whatsapp_template_media_${templateName}`) || localStorage.getItem(`whatsapp_template_media_${templateName.toLowerCase()}`);
9889
+ if (persisted && typeof persisted === "string") {
9890
+ const sanitized = sanitizeCandidate(persisted);
9891
+ if (sanitized) return sanitized;
9892
+ }
9893
+ } catch (e) {
9881
9894
  }
9882
9895
  }
9883
- }
9884
- if (templateName && typeof window !== "undefined") {
9885
- try {
9886
- const persisted = localStorage.getItem(`whatsapp_template_media_${templateName}`);
9887
- if (persisted && typeof persisted === "string") {
9888
- const sanitized = sanitizeCandidate(persisted);
9889
- if (sanitized) return sanitized;
9896
+ if (headerComp) {
9897
+ const candidates = [
9898
+ headerComp.url,
9899
+ headerComp.link,
9900
+ (_a = headerComp.image) == null ? void 0 : _a.link,
9901
+ (_b = headerComp.document) == null ? void 0 : _b.link,
9902
+ (_c = headerComp.video) == null ? void 0 : _c.link,
9903
+ (_e = (_d = headerComp.example) == null ? void 0 : _d.header_url) == null ? void 0 : _e[0],
9904
+ (_g = (_f = headerComp.example) == null ? void 0 : _f.header_handle) == null ? void 0 : _g[0]
9905
+ ];
9906
+ for (const candidate of candidates) {
9907
+ if (typeof candidate === "string") {
9908
+ const sanitized = sanitizeCandidate(candidate);
9909
+ if (sanitized) return sanitized;
9910
+ }
9890
9911
  }
9891
- } catch (e) {
9892
9912
  }
9893
- }
9894
- if (headerComp) {
9895
- const format = (headerComp.format || "").toUpperCase();
9896
- if (format === "DOCUMENT") return DEFAULT_FALLBACK_MEDIA_URLS.document;
9897
- if (format === "VIDEO") return DEFAULT_FALLBACK_MEDIA_URLS.video;
9898
- return DEFAULT_FALLBACK_MEDIA_URLS.image;
9899
- }
9900
- return DEFAULT_FALLBACK_MEDIA_URLS.image;
9913
+ return null;
9914
+ };
9915
+ const validMediaUrl = computeUrl();
9916
+ console.log(
9917
+ `[MEDIA_DEBUG] template: ${templateName || "unknown"}, format: ${format}, resolvedUrl: ${validMediaUrl}`
9918
+ );
9919
+ return validMediaUrl;
9901
9920
  }
9902
9921
  function buildWhatsAppPayload(to, templateName, languageCode, components) {
9903
9922
  const payload = {
@@ -9918,6 +9937,10 @@ function buildWhatsAppPayload(to, templateName, languageCode, components) {
9918
9937
  }
9919
9938
  async function sendWhatsAppMessage(payload, executeAction, orgId) {
9920
9939
  try {
9940
+ console.log(
9941
+ "[whatsappApi] Dispatching WhatsApp message action with payload:",
9942
+ JSON.stringify(payload, null, 2)
9943
+ );
9921
9944
  const actionPayload = {
9922
9945
  payload
9923
9946
  };
@@ -9927,12 +9950,18 @@ async function sendWhatsAppMessage(payload, executeAction, orgId) {
9927
9950
  }
9928
9951
  const result = await executeAction("SEND_WHATSAPP_MESSAGE", actionPayload);
9929
9952
  if (result && result.success === false) {
9953
+ console.error(
9954
+ "[whatsappApi] SEND_WHATSAPP_MESSAGE dispatch failed:",
9955
+ result.error,
9956
+ result.details || result
9957
+ );
9930
9958
  return {
9931
9959
  success: false,
9932
9960
  error: result.error || "\u05E9\u05DC\u05D9\u05D7\u05EA \u05D4\u05D5\u05D3\u05E2\u05EA WhatsApp \u05E0\u05DB\u05E9\u05DC\u05D4",
9933
9961
  data: result
9934
9962
  };
9935
9963
  }
9964
+ console.log("[whatsappApi] SEND_WHATSAPP_MESSAGE dispatch succeeded:", result);
9936
9965
  return {
9937
9966
  success: true,
9938
9967
  data: result
@@ -11041,6 +11070,48 @@ function useWhatsAppState(props) {
11041
11070
  );
11042
11071
  setHeaderMediaUrl(defaultUrl || "");
11043
11072
  }, [templateHeaderComp, selectedTemplate == null ? void 0 : selectedTemplate.name]);
11073
+ const [isUploadingMedia, setIsUploadingMedia] = useState15(false);
11074
+ const handleFileUpload = useCallback12(
11075
+ async (file, templateName) => {
11076
+ const tplName = templateName || (selectedTemplate == null ? void 0 : selectedTemplate.name) || "";
11077
+ if (!file) return;
11078
+ setIsUploadingMedia(true);
11079
+ try {
11080
+ const formData = new FormData();
11081
+ formData.append("file", file);
11082
+ const res = await fetch("/api/whatsapp/upload-media", {
11083
+ method: "POST",
11084
+ body: formData
11085
+ });
11086
+ const data = await res.json().catch(() => ({}));
11087
+ if (!res.ok || !(data == null ? void 0 : data.url)) {
11088
+ throw new Error((data == null ? void 0 : data.error) || `\u05D4\u05E2\u05DC\u05D0\u05EA \u05D4\u05E7\u05D5\u05D1\u05E5 \u05E0\u05DB\u05E9\u05DC\u05D4 (${res.status})`);
11089
+ }
11090
+ const publicUrl = data.url;
11091
+ setHeaderMediaUrl(publicUrl);
11092
+ if (tplName && typeof window !== "undefined") {
11093
+ try {
11094
+ localStorage.setItem(`whatsapp_template_media_${tplName}`, publicUrl);
11095
+ localStorage.setItem(`whatsapp_template_media_${tplName.toLowerCase()}`, publicUrl);
11096
+ } catch (e) {
11097
+ }
11098
+ }
11099
+ setFeedback({
11100
+ type: "success",
11101
+ message: "\u05E7\u05D5\u05D1\u05E5 \u05D4\u05DE\u05D3\u05D9\u05D4 \u05D4\u05D5\u05E2\u05DC\u05D4 \u05D1\u05D4\u05E6\u05DC\u05D7\u05D4 \u05D5\u05E9\u05D5\u05D9\u05DA \u05DC\u05EA\u05D1\u05E0\u05D9\u05EA"
11102
+ });
11103
+ } catch (err) {
11104
+ console.error("[useWhatsAppState] handleFileUpload error:", err);
11105
+ setFeedback({
11106
+ type: "error",
11107
+ message: (err == null ? void 0 : err.message) || "\u05E9\u05D2\u05D9\u05D0\u05D4 \u05D1\u05E2\u05EA \u05D4\u05E2\u05DC\u05D0\u05EA \u05E7\u05D5\u05D1\u05E5 \u05D4\u05DE\u05D3\u05D9\u05D4"
11108
+ });
11109
+ } finally {
11110
+ setIsUploadingMedia(false);
11111
+ }
11112
+ },
11113
+ [selectedTemplate == null ? void 0 : selectedTemplate.name]
11114
+ );
11044
11115
  const templateVariables = useMemo8(() => {
11045
11116
  return extractTemplateVariables(selectedTemplate);
11046
11117
  }, [selectedTemplate]);
@@ -11158,13 +11229,20 @@ function useWhatsAppState(props) {
11158
11229
  const isTemplateValid = Boolean(
11159
11230
  selectedTemplate && getStatusConfig(selectedTemplate.status).isSelectable
11160
11231
  );
11161
- const isSendDisabled = isSendingBroadcast || isScanningPhoneColumns || !hasPhoneColumn || !isTemplateValid || selectedRowIds.length === 0 || finalRecipientCount === 0 || isSubtableFilterIncomplete || isPostSendActionIncomplete || isStaticVariableMissing;
11162
- const isTestDisabled = isSendingTest || isScanningPhoneColumns || !hasPhoneColumn || !isTemplateValid || isSubtableFilterIncomplete || isPostSendActionIncomplete || isStaticVariableMissing;
11163
- const sendButtonTitle = isSendingBroadcast ? "\u05E9\u05D5\u05DC\u05D7 \u05D4\u05D5\u05D3\u05E2\u05D5\u05EA \u05D1\u05EA\u05E4\u05D5\u05E6\u05D4..." : isScanningPhoneColumns ? "\u05D8\u05D5\u05E2\u05DF \u05E2\u05DE\u05D5\u05D3\u05D5\u05EA \u05D8\u05DC\u05E4\u05D5\u05DF..." : !hasPhoneColumn ? "\u05DC\u05D0 \u05E0\u05DE\u05E6\u05D0\u05D4 \u05E2\u05DE\u05D5\u05D3\u05EA \u05D8\u05DC\u05E4\u05D5\u05DF \u05D1\u05D8\u05D1\u05DC\u05D4" : !isTemplateValid ? "\u05D9\u05E9 \u05DC\u05D1\u05D7\u05D5\u05E8 \u05EA\u05D1\u05E0\u05D9\u05EA \u05DE\u05D0\u05D5\u05E9\u05E8\u05EA \u05EA\u05D7\u05D9\u05DC\u05D4" : isSubtableFilterIncomplete ? "\u05D9\u05E9 \u05DC\u05D1\u05D7\u05D5\u05E8 \u05E2\u05E8\u05DA \u05DC\u05E1\u05D9\u05E0\u05D5\u05DF \u05D1\u05E8\u05E9\u05D5\u05DE\u05D5\u05EA \u05D4\u05DE\u05E7\u05D5\u05E9\u05E8\u05D5\u05EA" : isPostSendActionIncomplete ? "\u05D9\u05E9 \u05DC\u05D1\u05D7\u05D5\u05E8 \u05E2\u05E8\u05DA \u05D9\u05E2\u05D3 \u05DC\u05E2\u05D3\u05DB\u05D5\u05DF \u05DC\u05D0\u05D7\u05E8 \u05E9\u05DC\u05D9\u05D7\u05D4" : isStaticVariableMissing ? "\u05D9\u05E9 \u05DC\u05D4\u05D6\u05D9\u05DF \u05E2\u05E8\u05DA \u05E2\u05D1\u05D5\u05E8 \u05DB\u05DC \u05DE\u05E9\u05EA\u05E0\u05D4 \u05D1\u05D8\u05E7\u05E1\u05D8 \u05E7\u05D1\u05D5\u05E2" : selectedRowIds.length === 0 ? "\u05D9\u05E9 \u05DC\u05D1\u05D7\u05D5\u05E8 \u05DC\u05E4\u05D7\u05D5\u05EA \u05E9\u05D5\u05E8\u05D4 \u05D0\u05D7\u05EA \u05DE\u05D4\u05D8\u05D1\u05DC\u05D4" : finalRecipientCount === 0 ? "\u05DC\u05D0 \u05E0\u05DE\u05E6\u05D0\u05D5 \u05E0\u05DE\u05E2\u05E0\u05D9\u05DD \u05E2\u05DD \u05D8\u05DC\u05E4\u05D5\u05DF \u05EA\u05E7\u05D9\u05DF \u05D4\u05EA\u05D5\u05D0\u05DE\u05D9\u05DD \u05DC\u05E1\u05D9\u05E0\u05D5\u05DF" : `\u05E9\u05DC\u05D7 \u05DC-${finalRecipientCount} \u05E0\u05DE\u05E2\u05E0\u05D9\u05DD (\u05DE\u05EA\u05D5\u05DA ${validMainRowsCount} \u05E9\u05D5\u05E8\u05D5\u05EA \u05E8\u05D0\u05E9\u05D9\u05D5\u05EA)`;
11164
- const testButtonTitle = isScanningPhoneColumns ? "\u05D8\u05D5\u05E2\u05DF \u05E2\u05DE\u05D5\u05D3\u05D5\u05EA \u05D8\u05DC\u05E4\u05D5\u05DF..." : !hasPhoneColumn ? "\u05DC\u05D0 \u05E0\u05DE\u05E6\u05D0\u05D4 \u05E2\u05DE\u05D5\u05D3\u05EA \u05D8\u05DC\u05E4\u05D5\u05DF \u05D1\u05D8\u05D1\u05DC\u05D4" : !isTemplateValid ? "\u05D9\u05E9 \u05DC\u05D1\u05D7\u05D5\u05E8 \u05EA\u05D1\u05E0\u05D9\u05EA \u05DE\u05D0\u05D5\u05E9\u05E8\u05EA \u05EA\u05D7\u05D9\u05DC\u05D4" : isSubtableFilterIncomplete ? "\u05D9\u05E9 \u05DC\u05D1\u05D7\u05D5\u05E8 \u05E2\u05E8\u05DA \u05DC\u05E1\u05D9\u05E0\u05D5\u05DF \u05D1\u05E8\u05E9\u05D5\u05DE\u05D5\u05EA \u05D4\u05DE\u05E7\u05D5\u05E9\u05E8\u05D5\u05EA" : isPostSendActionIncomplete ? "\u05D9\u05E9 \u05DC\u05D1\u05D7\u05D5\u05E8 \u05E2\u05E8\u05DA \u05D9\u05E2\u05D3 \u05DC\u05E2\u05D3\u05DB\u05D5\u05DF \u05DC\u05D0\u05D7\u05E8 \u05E9\u05DC\u05D9\u05D7\u05D4" : isStaticVariableMissing ? "\u05D9\u05E9 \u05DC\u05D4\u05D6\u05D9\u05DF \u05E2\u05E8\u05DA \u05E2\u05D1\u05D5\u05E8 \u05DB\u05DC \u05DE\u05E9\u05EA\u05E0\u05D4 \u05D1\u05D8\u05E7\u05E1\u05D8 \u05E7\u05D1\u05D5\u05E2" : "\u05E9\u05DC\u05D9\u05D7\u05EA \u05D4\u05D5\u05D3\u05E2\u05EA \u05D1\u05D3\u05D9\u05E7\u05D4 \u05DC\u05DE\u05E1\u05E4\u05E8 \u05D1\u05D3\u05D9\u05E7\u05D4";
11232
+ const headerFormat = ((templateHeaderComp == null ? void 0 : templateHeaderComp.format) || "").toUpperCase();
11233
+ const requiresMediaHeader = headerFormat === "IMAGE" || headerFormat === "DOCUMENT" || headerFormat === "VIDEO";
11234
+ const isMediaMissing = requiresMediaHeader && (!headerMediaUrl || !headerMediaUrl.trim() || !headerMediaUrl.startsWith("http"));
11235
+ const isSendDisabled = isSendingBroadcast || isScanningPhoneColumns || !hasPhoneColumn || !isTemplateValid || selectedRowIds.length === 0 || finalRecipientCount === 0 || isSubtableFilterIncomplete || isPostSendActionIncomplete || isStaticVariableMissing || isMediaMissing;
11236
+ const isTestDisabled = isSendingTest || isScanningPhoneColumns || !hasPhoneColumn || !isTemplateValid || isSubtableFilterIncomplete || isPostSendActionIncomplete || isStaticVariableMissing || isMediaMissing;
11237
+ const sendButtonTitle = isSendingBroadcast ? "\u05E9\u05D5\u05DC\u05D7 \u05D4\u05D5\u05D3\u05E2\u05D5\u05EA \u05D1\u05EA\u05E4\u05D5\u05E6\u05D4..." : isScanningPhoneColumns ? "\u05D8\u05D5\u05E2\u05DF \u05E2\u05DE\u05D5\u05D3\u05D5\u05EA \u05D8\u05DC\u05E4\u05D5\u05DF..." : !hasPhoneColumn ? "\u05DC\u05D0 \u05E0\u05DE\u05E6\u05D0\u05D4 \u05E2\u05DE\u05D5\u05D3\u05EA \u05D8\u05DC\u05E4\u05D5\u05DF \u05D1\u05D8\u05D1\u05DC\u05D4" : !isTemplateValid ? "\u05D9\u05E9 \u05DC\u05D1\u05D7\u05D5\u05E8 \u05EA\u05D1\u05E0\u05D9\u05EA \u05DE\u05D0\u05D5\u05E9\u05E8\u05EA \u05EA\u05D7\u05D9\u05DC\u05D4" : isMediaMissing ? "\u05D9\u05E9 \u05DC\u05D4\u05E2\u05DC\u05D5\u05EA \u05E7\u05D5\u05D1\u05E5 \u05E2\u05D1\u05D5\u05E8 \u05EA\u05D1\u05E0\u05D9\u05EA \u05D6\u05D5 \u05DB\u05D3\u05D9 \u05DC\u05E9\u05DC\u05D5\u05D7" : isSubtableFilterIncomplete ? "\u05D9\u05E9 \u05DC\u05D1\u05D7\u05D5\u05E8 \u05E2\u05E8\u05DA \u05DC\u05E1\u05D9\u05E0\u05D5\u05DF \u05D1\u05E8\u05E9\u05D5\u05DE\u05D5\u05EA \u05D4\u05DE\u05E7\u05D5\u05E9\u05E8\u05D5\u05EA" : isPostSendActionIncomplete ? "\u05D9\u05E9 \u05DC\u05D1\u05D7\u05D5\u05E8 \u05E2\u05E8\u05DA \u05D9\u05E2\u05D3 \u05DC\u05E2\u05D3\u05DB\u05D5\u05DF \u05DC\u05D0\u05D7\u05E8 \u05E9\u05DC\u05D9\u05D7\u05D4" : isStaticVariableMissing ? "\u05D9\u05E9 \u05DC\u05D4\u05D6\u05D9\u05DF \u05E2\u05E8\u05DA \u05E2\u05D1\u05D5\u05E8 \u05DB\u05DC \u05DE\u05E9\u05EA\u05E0\u05D4 \u05D1\u05D8\u05E7\u05E1\u05D8 \u05E7\u05D1\u05D5\u05E2" : selectedRowIds.length === 0 ? "\u05D9\u05E9 \u05DC\u05D1\u05D7\u05D5\u05E8 \u05DC\u05E4\u05D7\u05D5\u05EA \u05E9\u05D5\u05E8\u05D4 \u05D0\u05D7\u05EA \u05DE\u05D4\u05D8\u05D1\u05DC\u05D4" : finalRecipientCount === 0 ? "\u05DC\u05D0 \u05E0\u05DE\u05E6\u05D0\u05D5 \u05E0\u05DE\u05E2\u05E0\u05D9\u05DD \u05E2\u05DD \u05D8\u05DC\u05E4\u05D5\u05DF \u05EA\u05E7\u05D9\u05DF \u05D4\u05EA\u05D5\u05D0\u05DE\u05D9\u05DD \u05DC\u05E1\u05D9\u05E0\u05D5\u05DF" : `\u05E9\u05DC\u05D7 \u05DC-${finalRecipientCount} \u05E0\u05DE\u05E2\u05E0\u05D9\u05DD (\u05DE\u05EA\u05D5\u05DA ${validMainRowsCount} \u05E9\u05D5\u05E8\u05D5\u05EA \u05E8\u05D0\u05E9\u05D9\u05D5\u05EA)`;
11238
+ const testButtonTitle = isScanningPhoneColumns ? "\u05D8\u05D5\u05E2\u05DF \u05E2\u05DE\u05D5\u05D3\u05D5\u05EA \u05D8\u05DC\u05E4\u05D5\u05DF..." : !hasPhoneColumn ? "\u05DC\u05D0 \u05E0\u05DE\u05E6\u05D0\u05D4 \u05E2\u05DE\u05D5\u05D3\u05EA \u05D8\u05DC\u05E4\u05D5\u05DF \u05D1\u05D8\u05D1\u05DC\u05D4" : !isTemplateValid ? "\u05D9\u05E9 \u05DC\u05D1\u05D7\u05D5\u05E8 \u05EA\u05D1\u05E0\u05D9\u05EA \u05DE\u05D0\u05D5\u05E9\u05E8\u05EA \u05EA\u05D7\u05D9\u05DC\u05D4" : isMediaMissing ? "\u05D9\u05E9 \u05DC\u05D4\u05E2\u05DC\u05D5\u05EA \u05E7\u05D5\u05D1\u05E5 \u05E2\u05D1\u05D5\u05E8 \u05EA\u05D1\u05E0\u05D9\u05EA \u05D6\u05D5 \u05DB\u05D3\u05D9 \u05DC\u05E9\u05DC\u05D5\u05D7" : isSubtableFilterIncomplete ? "\u05D9\u05E9 \u05DC\u05D1\u05D7\u05D5\u05E8 \u05E2\u05E8\u05DA \u05DC\u05E1\u05D9\u05E0\u05D5\u05DF \u05D1\u05E8\u05E9\u05D5\u05DE\u05D5\u05EA \u05D4\u05DE\u05E7\u05D5\u05E9\u05E8\u05D5\u05EA" : isPostSendActionIncomplete ? "\u05D9\u05E9 \u05DC\u05D1\u05D7\u05D5\u05E8 \u05E2\u05E8\u05DA \u05D9\u05E2\u05D3 \u05DC\u05E2\u05D3\u05DB\u05D5\u05DF \u05DC\u05D0\u05D7\u05E8 \u05E9\u05DC\u05D9\u05D7\u05D4" : isStaticVariableMissing ? "\u05D9\u05E9 \u05DC\u05D4\u05D6\u05D9\u05DF \u05E2\u05E8\u05DA \u05E2\u05D1\u05D5\u05E8 \u05DB\u05DC \u05DE\u05E9\u05EA\u05E0\u05D4 \u05D1\u05D8\u05E7\u05E1\u05D8 \u05E7\u05D1\u05D5\u05E2" : "\u05E9\u05DC\u05D9\u05D7\u05EA \u05D4\u05D5\u05D3\u05E2\u05EA \u05D1\u05D3\u05D9\u05E7\u05D4 \u05DC\u05DE\u05E1\u05E4\u05E8 \u05D1\u05D3\u05D9\u05E7\u05D4";
11165
11239
  const handleSendTest = async () => {
11166
11240
  var _a2;
11167
11241
  if (isSendingTest) return;
11242
+ if (isMediaMissing) {
11243
+ setTestFeedback("\u05D9\u05E9 \u05DC\u05D4\u05E2\u05DC\u05D5\u05EA \u05E7\u05D5\u05D1\u05E5 \u05E2\u05D1\u05D5\u05E8 \u05EA\u05D1\u05E0\u05D9\u05EA \u05D6\u05D5 \u05DB\u05D3\u05D9 \u05DC\u05E9\u05DC\u05D5\u05D7");
11244
+ return;
11245
+ }
11168
11246
  if (isSubtableFilterIncomplete) {
11169
11247
  setTestFeedback("\u05D9\u05E9 \u05DC\u05D1\u05D7\u05D5\u05E8 \u05E2\u05E8\u05DA \u05DC\u05E1\u05D9\u05E0\u05D5\u05DF \u05D1\u05E8\u05E9\u05D5\u05DE\u05D5\u05EA \u05D4\u05DE\u05E7\u05D5\u05E9\u05E8\u05D5\u05EA");
11170
11248
  return;
@@ -11506,6 +11584,8 @@ function useWhatsAppState(props) {
11506
11584
  isTestDisabled,
11507
11585
  sendButtonTitle,
11508
11586
  testButtonTitle,
11587
+ requiresMediaHeader,
11588
+ isMediaMissing,
11509
11589
  // Templates & Meta API
11510
11590
  templates,
11511
11591
  selectedTemplateId,
@@ -11516,6 +11596,8 @@ function useWhatsAppState(props) {
11516
11596
  headerMediaUrl,
11517
11597
  handleHeaderMediaUrlChange,
11518
11598
  handleResetHeaderMediaUrl,
11599
+ isUploadingMedia,
11600
+ handleFileUpload,
11519
11601
  templateVariables,
11520
11602
  variableMapping,
11521
11603
  textableColumnOptions,
@@ -11552,6 +11634,7 @@ function useWhatsAppState(props) {
11552
11634
  }
11553
11635
 
11554
11636
  // src/components/WhatsAppComponent/ui/TemplateSelectionBlock.tsx
11637
+ import { useRef as useRef13 } from "react";
11555
11638
  import {
11556
11639
  FileText as FileText3,
11557
11640
  Trash2 as Trash23,
@@ -11563,7 +11646,10 @@ import {
11563
11646
  Video as Video2,
11564
11647
  Phone as Phone2,
11565
11648
  Copy as Copy4,
11566
- MessageSquare as MessageSquare2
11649
+ MessageSquare as MessageSquare2,
11650
+ Upload as Upload3,
11651
+ CheckCircle2 as CheckCircle23,
11652
+ AlertCircle as AlertCircle3
11567
11653
  } from "lucide-react";
11568
11654
  import { Fragment as Fragment4, jsx as jsx15, jsxs as jsxs14 } from "react/jsx-runtime";
11569
11655
  function TemplateSelectionBlock({
@@ -11587,8 +11673,11 @@ function TemplateSelectionBlock({
11587
11673
  handleDeleteTemplate,
11588
11674
  isDeleting,
11589
11675
  setIsModalOpen,
11590
- setFeedback
11676
+ setFeedback,
11677
+ isUploadingMedia = false,
11678
+ handleFileUpload
11591
11679
  }) {
11680
+ const fileInputRef = useRef13(null);
11592
11681
  return /* @__PURE__ */ jsxs14("div", { className: "col-span-12 lg:col-span-5 min-h-[26rem] h-full flex flex-col bg-slate-50/70 border border-slate-200 rounded-2xl p-3.5 relative", children: [
11593
11682
  /* @__PURE__ */ jsxs14("div", { className: "space-y-1.5 shrink-0", children: [
11594
11683
  /* @__PURE__ */ jsxs14("div", { className: "flex items-center justify-between pb-1.5 border-b border-slate-200/70 shrink-0 gap-2", children: [
@@ -11768,10 +11857,15 @@ function TemplateSelectionBlock({
11768
11857
  })(),
11769
11858
  templateHeaderComp && (() => {
11770
11859
  const headerFormat = (templateHeaderComp.format || "").toUpperCase();
11860
+ if (headerFormat !== "IMAGE" && headerFormat !== "DOCUMENT" && headerFormat !== "VIDEO") {
11861
+ return null;
11862
+ }
11771
11863
  const docFilename = resolveDocumentFilename(templateHeaderComp, headerMediaUrl);
11864
+ const hasValidMedia = Boolean(headerMediaUrl && headerMediaUrl.trim() && headerMediaUrl.startsWith("http"));
11865
+ const uploadButtonLabel = headerFormat === "DOCUMENT" ? "\u05D4\u05E2\u05DC\u05D4 \u05DE\u05E1\u05DE\u05DA" : headerFormat === "IMAGE" ? "\u05D4\u05E2\u05DC\u05D4 \u05EA\u05DE\u05D5\u05E0\u05D4" : "\u05D4\u05E2\u05DC\u05D4 \u05E7\u05D5\u05D1\u05E5";
11772
11866
  return /* @__PURE__ */ jsxs14("div", { className: "p-2.5 bg-slate-50 border border-slate-200/90 rounded-xl flex items-center justify-between gap-3 shrink-0 shadow-2xs", children: [
11773
11867
  /* @__PURE__ */ jsx15("div", { className: "flex items-center gap-2.5 overflow-hidden", children: headerFormat === "IMAGE" ? /* @__PURE__ */ jsxs14(Fragment4, { children: [
11774
- /* @__PURE__ */ jsx15("div", { className: "w-8 h-8 rounded-lg overflow-hidden border border-slate-200 shrink-0 bg-slate-100 flex items-center justify-center", children: headerMediaUrl && headerMediaUrl.startsWith("http") ? /* @__PURE__ */ jsx15(
11868
+ /* @__PURE__ */ jsx15("div", { className: "w-8 h-8 rounded-lg overflow-hidden border border-slate-200 shrink-0 bg-slate-100 flex items-center justify-center", children: hasValidMedia ? /* @__PURE__ */ jsx15(
11775
11869
  "img",
11776
11870
  {
11777
11871
  src: headerMediaUrl,
@@ -11781,26 +11875,33 @@ function TemplateSelectionBlock({
11781
11875
  e.currentTarget.style.display = "none";
11782
11876
  }
11783
11877
  }
11784
- ) : /* @__PURE__ */ jsx15(ImageIcon2, { className: "w-4 h-4 text-emerald-600" }) }),
11878
+ ) : /* @__PURE__ */ jsx15(ImageIcon2, { className: "w-4 h-4 text-amber-600" }) }),
11785
11879
  /* @__PURE__ */ jsxs14("div", { className: "overflow-hidden", children: [
11786
11880
  /* @__PURE__ */ jsx15("span", { className: "text-xs font-bold text-slate-800 block truncate", children: "\u05EA\u05DE\u05D5\u05E0\u05EA \u05DB\u05D5\u05EA\u05E8\u05EA" }),
11787
- /* @__PURE__ */ jsx15("span", { className: "text-[10px] text-slate-400 block truncate", children: "\u05E7\u05D5\u05D1\u05E5 \u05DE\u05D3\u05D9\u05D4 \u05DE\u05E6\u05D5\u05E8\u05E3 \u05D1-Header" })
11881
+ /* @__PURE__ */ jsx15("span", { className: "text-[10px] text-slate-400 block truncate", children: hasValidMedia ? "\u05E7\u05D5\u05D1\u05E5 \u05EA\u05DE\u05D5\u05E0\u05D4 \u05DE\u05E7\u05D5\u05E9\u05E8 \u05DC\u05EA\u05D1\u05E0\u05D9\u05EA" : "\u05D8\u05E8\u05DD \u05D4\u05D5\u05E2\u05DC\u05D4 \u05E7\u05D5\u05D1\u05E5 \u05EA\u05DE\u05D5\u05E0\u05D4" })
11788
11882
  ] })
11789
11883
  ] }) : headerFormat === "DOCUMENT" ? /* @__PURE__ */ jsxs14(Fragment4, { children: [
11790
- /* @__PURE__ */ jsx15("div", { className: "w-8 h-8 rounded-lg bg-rose-50 text-rose-600 border border-rose-100 flex items-center justify-center shrink-0", children: /* @__PURE__ */ jsx15(FileText3, { className: "w-4 h-4" }) }),
11884
+ /* @__PURE__ */ jsx15("div", { className: `w-8 h-8 rounded-lg flex items-center justify-center shrink-0 border ${hasValidMedia ? "bg-rose-50 text-rose-600 border-rose-100" : "bg-slate-100 text-slate-400 border-slate-200"}`, children: /* @__PURE__ */ jsx15(FileText3, { className: "w-4 h-4" }) }),
11791
11885
  /* @__PURE__ */ jsxs14("div", { className: "overflow-hidden", children: [
11792
11886
  /* @__PURE__ */ jsx15("span", { className: "text-xs font-bold text-slate-800 block truncate", children: "\u05DE\u05E1\u05DE\u05DA \u05DB\u05D5\u05EA\u05E8\u05EA (PDF)" }),
11793
- /* @__PURE__ */ jsx15("span", { className: "text-[10px] text-slate-500 font-mono block truncate", title: docFilename, children: docFilename })
11887
+ /* @__PURE__ */ jsx15("span", { className: "text-[10px] text-slate-500 font-mono block truncate", title: hasValidMedia ? docFilename : void 0, children: hasValidMedia ? docFilename : "\u05D8\u05E8\u05DD \u05D4\u05D5\u05E2\u05DC\u05D4 \u05E7\u05D5\u05D1\u05E5 \u05DE\u05E1\u05DE\u05DA" })
11794
11888
  ] })
11795
11889
  ] }) : /* @__PURE__ */ jsxs14(Fragment4, { children: [
11796
- /* @__PURE__ */ jsx15("div", { className: "w-8 h-8 rounded-lg bg-indigo-50 text-indigo-600 border border-indigo-100 flex items-center justify-center shrink-0", children: /* @__PURE__ */ jsx15(Video2, { className: "w-4 h-4" }) }),
11890
+ /* @__PURE__ */ jsx15("div", { className: `w-8 h-8 rounded-lg flex items-center justify-center shrink-0 border ${hasValidMedia ? "bg-indigo-50 text-indigo-600 border-indigo-100" : "bg-slate-100 text-slate-400 border-slate-200"}`, children: /* @__PURE__ */ jsx15(Video2, { className: "w-4 h-4" }) }),
11797
11891
  /* @__PURE__ */ jsxs14("div", { className: "overflow-hidden", children: [
11798
11892
  /* @__PURE__ */ jsx15("span", { className: "text-xs font-bold text-slate-800 block truncate", children: "\u05E1\u05E8\u05D8\u05D5\u05DF \u05DB\u05D5\u05EA\u05E8\u05EA" }),
11799
- /* @__PURE__ */ jsx15("span", { className: "text-[10px] text-slate-400 block truncate", children: "\u05E7\u05D5\u05D1\u05E5 \u05D5\u05D9\u05D3\u05D0\u05D5 \u05DE\u05E6\u05D5\u05E8\u05E3 \u05D1-Header" })
11893
+ /* @__PURE__ */ jsx15("span", { className: "text-[10px] text-slate-400 block truncate", children: hasValidMedia ? "\u05E7\u05D5\u05D1\u05E5 \u05D5\u05D9\u05D3\u05D0\u05D5 \u05DE\u05E7\u05D5\u05E9\u05E8 \u05DC\u05EA\u05D1\u05E0\u05D9\u05EA" : "\u05D8\u05E8\u05DD \u05D4\u05D5\u05E2\u05DC\u05D4 \u05E7\u05D5\u05D1\u05E5 \u05D5\u05D9\u05D3\u05D0\u05D5" })
11800
11894
  ] })
11801
11895
  ] }) }),
11802
- /* @__PURE__ */ jsxs14("div", { className: "flex items-center gap-1.5 shrink-0", children: [
11803
- headerMediaUrl && headerMediaUrl.startsWith("http") && /* @__PURE__ */ jsx15(
11896
+ /* @__PURE__ */ jsxs14("div", { className: "flex items-center gap-2 shrink-0", children: [
11897
+ hasValidMedia ? /* @__PURE__ */ jsxs14("span", { className: "inline-flex items-center gap-1 text-[10px] font-medium text-emerald-800 px-2 py-0.5 bg-emerald-50 border border-emerald-200 rounded-lg", children: [
11898
+ /* @__PURE__ */ jsx15(CheckCircle23, { className: "w-3 h-3 text-emerald-600" }),
11899
+ "\u05E7\u05D5\u05D1\u05E5 \u05DE\u05E6\u05D5\u05E8\u05E3 \u05EA\u05E7\u05D9\u05DF"
11900
+ ] }) : /* @__PURE__ */ jsxs14("span", { className: "inline-flex items-center gap-1 text-[10px] font-semibold text-amber-800 px-2 py-0.5 bg-amber-50 border border-amber-200 rounded-lg", children: [
11901
+ /* @__PURE__ */ jsx15(AlertCircle3, { className: "w-3 h-3 text-amber-600 shrink-0" }),
11902
+ "\u05E0\u05D3\u05E8\u05E9 \u05E6\u05D9\u05E8\u05D5\u05E3 \u05E7\u05D5\u05D1\u05E5 \u05DC\u05EA\u05D1\u05E0\u05D9\u05EA \u05D6\u05D5"
11903
+ ] }),
11904
+ hasValidMedia && /* @__PURE__ */ jsx15(
11804
11905
  "a",
11805
11906
  {
11806
11907
  href: headerMediaUrl,
@@ -11811,7 +11912,44 @@ function TemplateSelectionBlock({
11811
11912
  children: /* @__PURE__ */ jsx15(ExternalLink4, { className: "w-3.5 h-3.5" })
11812
11913
  }
11813
11914
  ),
11814
- /* @__PURE__ */ jsx15("span", { className: "text-[9px] text-emerald-800 font-semibold px-1.5 py-0.5 bg-emerald-50 border border-emerald-200 rounded-md", children: "\u05DE\u05E6\u05D5\u05E8\u05E3 \u05D0\u05D5\u05D8\u05D5\u05DE\u05D8\u05D9\u05EA" })
11915
+ /* @__PURE__ */ jsx15(
11916
+ "input",
11917
+ {
11918
+ ref: fileInputRef,
11919
+ type: "file",
11920
+ className: "hidden",
11921
+ accept: headerFormat === "DOCUMENT" ? ".pdf,application/pdf" : headerFormat === "VIDEO" ? "video/mp4,video/*" : "image/png,image/jpeg,image/jpg",
11922
+ onChange: (e) => {
11923
+ var _a;
11924
+ const file = (_a = e.target.files) == null ? void 0 : _a[0];
11925
+ if (file && handleFileUpload && (selectedTemplate == null ? void 0 : selectedTemplate.name)) {
11926
+ handleFileUpload(file, selectedTemplate.name);
11927
+ }
11928
+ e.target.value = "";
11929
+ },
11930
+ disabled: isUploadingMedia
11931
+ }
11932
+ ),
11933
+ /* @__PURE__ */ jsx15(
11934
+ "button",
11935
+ {
11936
+ type: "button",
11937
+ disabled: isUploadingMedia,
11938
+ onClick: () => {
11939
+ var _a;
11940
+ return (_a = fileInputRef.current) == null ? void 0 : _a.click();
11941
+ },
11942
+ className: `inline-flex items-center gap-1.5 px-2.5 py-1 text-[11px] font-medium rounded-lg transition-colors border shadow-2xs ${isUploadingMedia ? "bg-slate-100 text-slate-400 border-slate-200 cursor-not-allowed" : hasValidMedia ? "bg-white text-slate-700 hover:bg-slate-50 border-slate-200 hover:border-slate-300" : "bg-emerald-600 text-white hover:bg-emerald-700 border-emerald-600"}`,
11943
+ title: hasValidMedia ? "\u05D4\u05D7\u05DC\u05E3 \u05E7\u05D5\u05D1\u05E5 \u05DE\u05D3\u05D9\u05D4 \u05DC\u05EA\u05D1\u05E0\u05D9\u05EA \u05D6\u05D5" : `${uploadButtonLabel} \u05DC\u05EA\u05D1\u05E0\u05D9\u05EA \u05D6\u05D5`,
11944
+ children: isUploadingMedia ? /* @__PURE__ */ jsxs14(Fragment4, { children: [
11945
+ /* @__PURE__ */ jsx15(Loader25, { className: "w-3.5 h-3.5 animate-spin" }),
11946
+ /* @__PURE__ */ jsx15("span", { children: "\u05DE\u05E2\u05DC\u05D4..." })
11947
+ ] }) : /* @__PURE__ */ jsxs14(Fragment4, { children: [
11948
+ /* @__PURE__ */ jsx15(Upload3, { className: "w-3.5 h-3.5" }),
11949
+ /* @__PURE__ */ jsx15("span", { children: hasValidMedia ? "\u05D4\u05D7\u05DC\u05E3 \u05E7\u05D5\u05D1\u05E5" : uploadButtonLabel })
11950
+ ] })
11951
+ }
11952
+ )
11815
11953
  ] })
11816
11954
  ] });
11817
11955
  })(),
@@ -12021,7 +12159,7 @@ import {
12021
12159
  Users,
12022
12160
  ChevronDown as ChevronDown5,
12023
12161
  Loader2 as Loader26,
12024
- AlertCircle as AlertCircle3,
12162
+ AlertCircle as AlertCircle4,
12025
12163
  Send,
12026
12164
  X as X11,
12027
12165
  CheckSquare as CheckSquare2
@@ -12080,7 +12218,7 @@ function SettingsAndActionsBlock({
12080
12218
  /* @__PURE__ */ jsx17(Loader26, { className: "w-4 h-4 animate-spin text-emerald-600 shrink-0" }),
12081
12219
  /* @__PURE__ */ jsx17("span", { className: "font-medium text-[11px] text-slate-600", children: "\u05E1\u05D5\u05E8\u05E7 \u05E2\u05DE\u05D5\u05D3\u05D5\u05EA \u05D8\u05DC\u05E4\u05D5\u05DF \u05D1\u05D8\u05D1\u05DC\u05D4 \u05D5\u05D1\u05D8\u05D1\u05DC\u05D0\u05D5\u05EA \u05DE\u05E7\u05D5\u05E9\u05E8\u05D5\u05EA..." })
12082
12220
  ] }) : targetPhoneOptions.length === 0 ? /* @__PURE__ */ jsxs16("div", { className: "p-2.5 bg-amber-50 border border-amber-200 rounded-xl text-amber-900 text-xs flex items-center gap-2 shadow-2xs", children: [
12083
- /* @__PURE__ */ jsx17(AlertCircle3, { className: "w-4 h-4 text-amber-600 shrink-0" }),
12221
+ /* @__PURE__ */ jsx17(AlertCircle4, { className: "w-4 h-4 text-amber-600 shrink-0" }),
12084
12222
  /* @__PURE__ */ jsx17("span", { className: "font-semibold text-[11px]", children: "\u05DC\u05D0 \u05E0\u05DE\u05E6\u05D0\u05D4 \u05E2\u05DE\u05D5\u05D3\u05EA \u05D8\u05DC\u05E4\u05D5\u05DF \u05D1\u05D8\u05D1\u05DC\u05D4" })
12085
12223
  ] }) : targetPhoneOptions.length === 1 && targetPhoneOptions[0].type === "DIRECT" ? /* @__PURE__ */ jsxs16("div", { className: "space-y-1", children: [
12086
12224
  /* @__PURE__ */ jsxs16("div", { className: "flex items-center justify-between", children: [
@@ -12524,7 +12662,7 @@ function WhatsAppComponent(props) {
12524
12662
  className: `px-6 py-3 border-b text-xs flex items-center justify-between gap-3 ${state.feedback.type === "success" ? "bg-emerald-50 border-emerald-200 text-emerald-800" : "bg-rose-50 border-rose-200 text-rose-800"}`,
12525
12663
  children: [
12526
12664
  /* @__PURE__ */ jsxs17("div", { className: "flex items-center gap-2", children: [
12527
- state.feedback.type === "success" ? /* @__PURE__ */ jsx18(CheckCircle23, { className: "w-4 h-4 text-emerald-600 shrink-0" }) : /* @__PURE__ */ jsx18(AlertCircle4, { className: "w-4 h-4 text-rose-600 shrink-0" }),
12665
+ state.feedback.type === "success" ? /* @__PURE__ */ jsx18(CheckCircle24, { className: "w-4 h-4 text-emerald-600 shrink-0" }) : /* @__PURE__ */ jsx18(AlertCircle5, { className: "w-4 h-4 text-rose-600 shrink-0" }),
12528
12666
  /* @__PURE__ */ jsx18("span", { children: state.feedback.message })
12529
12667
  ] }),
12530
12668
  /* @__PURE__ */ jsx18(
@@ -12541,7 +12679,7 @@ function WhatsAppComponent(props) {
12541
12679
  ),
12542
12680
  state.fetchError && !state.isLoadingTemplates && /* @__PURE__ */ jsxs17("div", { className: "px-6 py-3 bg-amber-50 border-b border-amber-200 text-xs text-amber-900 flex items-center justify-between", children: [
12543
12681
  /* @__PURE__ */ jsxs17("div", { className: "flex items-center gap-2", children: [
12544
- /* @__PURE__ */ jsx18(AlertCircle4, { className: "w-4 h-4 text-amber-600 shrink-0" }),
12682
+ /* @__PURE__ */ jsx18(AlertCircle5, { className: "w-4 h-4 text-amber-600 shrink-0" }),
12545
12683
  /* @__PURE__ */ jsxs17("span", { children: [
12546
12684
  "\u05E9\u05D2\u05D9\u05D0\u05D4 \u05D1\u05D8\u05E2\u05D9\u05E0\u05EA \u05EA\u05D1\u05E0\u05D9\u05D5\u05EA \u05DE-Meta: ",
12547
12685
  state.fetchError
@@ -12582,7 +12720,9 @@ function WhatsAppComponent(props) {
12582
12720
  handleDeleteTemplate: state.handleDeleteTemplate,
12583
12721
  isDeleting: state.isDeleting,
12584
12722
  setIsModalOpen: state.setIsModalOpen,
12585
- setFeedback: state.setFeedback
12723
+ setFeedback: state.setFeedback,
12724
+ isUploadingMedia: state.isUploadingMedia,
12725
+ handleFileUpload: state.handleFileUpload
12586
12726
  }
12587
12727
  ),
12588
12728
  /* @__PURE__ */ jsx18(
@@ -12652,7 +12792,7 @@ function WhatsAppComponent(props) {
12652
12792
  /* @__PURE__ */ jsx18(Loader27, { className: "w-6 h-6 animate-spin text-emerald-600" }),
12653
12793
  /* @__PURE__ */ jsx18("span", { children: "\u05D8\u05D5\u05E2\u05DF \u05E8\u05E9\u05D5\u05DE\u05D5\u05EA \u05DE\u05D4\u05D8\u05D1\u05DC\u05D4..." })
12654
12794
  ] }) : state.tableError ? /* @__PURE__ */ jsxs17("div", { className: "flex-1 flex items-center justify-center p-6 text-center text-xs text-rose-600 bg-rose-50 gap-2", children: [
12655
- /* @__PURE__ */ jsx18(AlertCircle4, { className: "w-4 h-4 text-rose-500 shrink-0" }),
12795
+ /* @__PURE__ */ jsx18(AlertCircle5, { className: "w-4 h-4 text-rose-500 shrink-0" }),
12656
12796
  /* @__PURE__ */ jsx18("span", { children: state.tableError })
12657
12797
  ] }) : !(settings == null ? void 0 : settings.tableMetaId) ? /* @__PURE__ */ jsx18("div", { className: "flex-1 flex items-center justify-center p-10 text-center text-xs text-slate-400", children: "\u05DC\u05D0 \u05E0\u05D1\u05D7\u05E8\u05D4 \u05D8\u05D1\u05DC\u05EA \u05DE\u05E7\u05D5\u05E8 \u05E2\u05D1\u05D5\u05E8 \u05E8\u05DB\u05D9\u05D1 WhatsApp \u05D6\u05D4" }) : /* @__PURE__ */ jsx18(
12658
12798
  TableBlockClient,
@@ -12768,7 +12908,7 @@ function WhatsAppComponent(props) {
12768
12908
  /* @__PURE__ */ jsx18("div", { className: "w-7 h-7 rounded-md bg-indigo-50 text-indigo-600 border border-indigo-100 flex items-center justify-center shrink-0", children: /* @__PURE__ */ jsx18(Video3, { className: "w-3.5 h-3.5" }) }),
12769
12909
  /* @__PURE__ */ jsx18("span", { className: "font-semibold text-slate-800 truncate", children: "\u05E1\u05E8\u05D8\u05D5\u05DF \u05DB\u05D5\u05EA\u05E8\u05EA" })
12770
12910
  ] }) }),
12771
- /* @__PURE__ */ jsx18("span", { className: "text-[10px] text-emerald-700 bg-emerald-50 border border-emerald-200 px-1.5 py-0.5 rounded font-medium shrink-0", children: "\u05DE\u05E6\u05D5\u05E8\u05E3 \u05D0\u05D5\u05D8\u05D5\u05DE\u05D8\u05D9\u05EA" })
12911
+ state.headerMediaUrl && state.headerMediaUrl.startsWith("http") ? /* @__PURE__ */ jsx18("span", { className: "text-[10px] text-emerald-700 bg-emerald-50 border border-emerald-200 px-1.5 py-0.5 rounded font-medium shrink-0", children: "\u05E7\u05D5\u05D1\u05E5 \u05DE\u05E6\u05D5\u05E8\u05E3 \u05EA\u05E7\u05D9\u05DF" }) : /* @__PURE__ */ jsx18("span", { className: "text-[10px] text-amber-700 bg-amber-50 border border-amber-200 px-1.5 py-0.5 rounded font-medium shrink-0", children: "\u05E0\u05D3\u05E8\u05E9 \u05E6\u05D9\u05E8\u05D5\u05E3 \u05E7\u05D5\u05D1\u05E5 \u05DC\u05EA\u05D1\u05E0\u05D9\u05EA \u05D6\u05D5" })
12772
12912
  ] });
12773
12913
  })(),
12774
12914
  /* @__PURE__ */ jsxs17("div", { className: "space-y-1.5", children: [
@@ -12804,7 +12944,7 @@ function WhatsAppComponent(props) {
12804
12944
  /* @__PURE__ */ jsx18("p", { className: "text-[11px] text-slate-500 leading-normal", children: "\u05D4\u05D5\u05D3\u05E2\u05EA \u05D4\u05D1\u05D3\u05D9\u05E7\u05D4 \u05EA\u05D9\u05E9\u05DC\u05D7 \u05D9\u05E9\u05D9\u05E8\u05D5\u05EA \u05DC\u05DE\u05E1\u05E4\u05E8 \u05D6\u05D4 \u05DC\u05E6\u05D5\u05E8\u05DA \u05D5\u05D9\u05D3\u05D5\u05D0 \u05EA\u05E7\u05D9\u05E0\u05D5\u05EA \u05EA\u05D5\u05DB\u05DF \u05D4\u05D4\u05D5\u05D3\u05E2\u05D4 \u05D5\u05D4\u05E2\u05D9\u05E6\u05D5\u05D1." })
12805
12945
  ] }),
12806
12946
  state.testFeedback && /* @__PURE__ */ jsxs17("div", { className: "p-2.5 bg-rose-50 border border-rose-200 rounded-xl text-xs text-rose-700 flex items-center gap-2", children: [
12807
- /* @__PURE__ */ jsx18(AlertCircle4, { className: "w-4 h-4 text-rose-500 shrink-0" }),
12947
+ /* @__PURE__ */ jsx18(AlertCircle5, { className: "w-4 h-4 text-rose-500 shrink-0" }),
12808
12948
  /* @__PURE__ */ jsx18("span", { children: state.testFeedback })
12809
12949
  ] })
12810
12950
  ] }),
@@ -12827,9 +12967,10 @@ function WhatsAppComponent(props) {
12827
12967
  "button",
12828
12968
  {
12829
12969
  type: "button",
12830
- disabled: !state.testPhoneNumber.trim() || state.isSendingTest,
12970
+ disabled: !state.testPhoneNumber.trim() || state.isSendingTest || state.isTestDisabled,
12831
12971
  onClick: state.handleSendTest,
12832
- className: `px-4 py-2 text-xs font-bold rounded-xl transition-all flex items-center gap-1.5 ${!state.testPhoneNumber.trim() || state.isSendingTest ? "bg-emerald-600/40 text-white/70 cursor-not-allowed" : "bg-emerald-600 hover:bg-emerald-700 active:scale-[0.98] text-white shadow-xs cursor-pointer"}`,
12972
+ title: state.testButtonTitle,
12973
+ className: `px-4 py-2 text-xs font-bold rounded-xl transition-all flex items-center gap-1.5 ${!state.testPhoneNumber.trim() || state.isSendingTest || state.isTestDisabled ? "bg-emerald-600/40 text-white/70 cursor-not-allowed" : "bg-emerald-600 hover:bg-emerald-700 active:scale-[0.98] text-white shadow-xs cursor-pointer"}`,
12833
12974
  children: state.isSendingTest ? /* @__PURE__ */ jsxs17(Fragment7, { children: [
12834
12975
  /* @__PURE__ */ jsx18(Loader27, { className: "w-3.5 h-3.5 animate-spin" }),
12835
12976
  /* @__PURE__ */ jsx18("span", { children: "\u05E9\u05D5\u05DC\u05D7..." })
package/dist/phone.d.mts CHANGED
@@ -35,10 +35,14 @@ declare function isValidPhoneNumber(phone: string): boolean;
35
35
  */
36
36
  declare function generateWhatsAppLink(phone: string, defaultCountryCode?: string): string | null;
37
37
  /**
38
- * Normalizes a phone number for WhatsApp sending (E.164 without leading '+').
39
- * - Strips spaces, dashes, and special characters.
40
- * - If it starts with '05' (10 digits), replaces the leading '0' with '972' (e.g., '0586812807' -> '972586812807').
41
- * - If it starts with '+', strips the '+'.
38
+ * Normalizes a phone number for WhatsApp sending (Meta international format without leading '+').
39
+ * - Returns empty string if input is falsy.
40
+ * - Trims input and removes leading '+' if it exists.
41
+ * - Strips all non-digit characters.
42
+ * - If starting with '972', returns it as is.
43
+ * - If starting with '0' (Israeli mobile/landline), strips '0' and prepends '972'.
44
+ * - If exactly 9 digits long (omitted leading zero), prepends '972'.
45
+ * - Returns the processed digits string.
42
46
  */
43
47
  declare function normalizePhoneForWhatsApp(phone: string): string;
44
48
 
package/dist/phone.d.ts CHANGED
@@ -35,10 +35,14 @@ declare function isValidPhoneNumber(phone: string): boolean;
35
35
  */
36
36
  declare function generateWhatsAppLink(phone: string, defaultCountryCode?: string): string | null;
37
37
  /**
38
- * Normalizes a phone number for WhatsApp sending (E.164 without leading '+').
39
- * - Strips spaces, dashes, and special characters.
40
- * - If it starts with '05' (10 digits), replaces the leading '0' with '972' (e.g., '0586812807' -> '972586812807').
41
- * - If it starts with '+', strips the '+'.
38
+ * Normalizes a phone number for WhatsApp sending (Meta international format without leading '+').
39
+ * - Returns empty string if input is falsy.
40
+ * - Trims input and removes leading '+' if it exists.
41
+ * - Strips all non-digit characters.
42
+ * - If starting with '972', returns it as is.
43
+ * - If starting with '0' (Israeli mobile/landline), strips '0' and prepends '972'.
44
+ * - If exactly 9 digits long (omitted leading zero), prepends '972'.
45
+ * - Returns the processed digits string.
42
46
  */
43
47
  declare function normalizePhoneForWhatsApp(phone: string): string;
44
48
 
package/dist/phone.js CHANGED
@@ -88,9 +88,15 @@ function normalizePhoneForWhatsApp(phone) {
88
88
  cleaned = cleaned.substring(1);
89
89
  }
90
90
  const digitsOnly = cleaned.replace(/\D/g, "");
91
- if (digitsOnly.startsWith("05") && digitsOnly.length === 10) {
91
+ if (digitsOnly.startsWith("972")) {
92
+ return digitsOnly;
93
+ }
94
+ if (digitsOnly.startsWith("0")) {
92
95
  return `972${digitsOnly.substring(1)}`;
93
96
  }
97
+ if (digitsOnly.length === 9) {
98
+ return `972${digitsOnly}`;
99
+ }
94
100
  return digitsOnly;
95
101
  }
96
102
  // Annotate the CommonJS export names for ESM import in node:
package/dist/phone.mjs CHANGED
@@ -57,9 +57,15 @@ function normalizePhoneForWhatsApp(phone) {
57
57
  cleaned = cleaned.substring(1);
58
58
  }
59
59
  const digitsOnly = cleaned.replace(/\D/g, "");
60
- if (digitsOnly.startsWith("05") && digitsOnly.length === 10) {
60
+ if (digitsOnly.startsWith("972")) {
61
+ return digitsOnly;
62
+ }
63
+ if (digitsOnly.startsWith("0")) {
61
64
  return `972${digitsOnly.substring(1)}`;
62
65
  }
66
+ if (digitsOnly.length === 9) {
67
+ return `972${digitsOnly}`;
68
+ }
63
69
  return digitsOnly;
64
70
  }
65
71
  export {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@universe-platform/ui",
3
- "version": "0.1.0-beta.21",
3
+ "version": "0.1.0-beta.23",
4
4
  "main": "./dist/index.js",
5
5
  "module": "./dist/index.mjs",
6
6
  "types": "./dist/index.d.ts",