@embedreach/components 0.3.13 → 0.3.15
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/chunks/index.js +1715 -475
- package/dist/chunks/sandbox-loading-screen.js +10 -0
- package/dist/index.d.ts +4 -2
- package/dist/index.umd.js +14 -14
- package/dist/styles.css +1 -1
- package/package.json +1 -1
package/dist/chunks/index.js
CHANGED
|
@@ -2788,6 +2788,57 @@ const duplicateBusinessAutomation = async (automationId, name, description2) =>
|
|
|
2788
2788
|
);
|
|
2789
2789
|
return response.data;
|
|
2790
2790
|
};
|
|
2791
|
+
const findSegmentByName = async (name) => {
|
|
2792
|
+
const response = await baseRequest(
|
|
2793
|
+
`/automations/internal/segments/find-by-name?name=${encodeURIComponent(name)}`,
|
|
2794
|
+
{
|
|
2795
|
+
method: "GET"
|
|
2796
|
+
}
|
|
2797
|
+
);
|
|
2798
|
+
return response.data;
|
|
2799
|
+
};
|
|
2800
|
+
var AutomationTriggerType = /* @__PURE__ */ ((AutomationTriggerType2) => {
|
|
2801
|
+
AutomationTriggerType2["ONE_TIME"] = "one_time";
|
|
2802
|
+
AutomationTriggerType2["TRIGGER_BASED"] = "trigger_based";
|
|
2803
|
+
AutomationTriggerType2["DATE_BASED"] = "date_based";
|
|
2804
|
+
return AutomationTriggerType2;
|
|
2805
|
+
})(AutomationTriggerType || {});
|
|
2806
|
+
var ReachEventNamesEnum = /* @__PURE__ */ ((ReachEventNamesEnum2) => {
|
|
2807
|
+
ReachEventNamesEnum2["USER_ENTERS_SEGMENT"] = "USER_ENTERS_SEGMENT";
|
|
2808
|
+
return ReachEventNamesEnum2;
|
|
2809
|
+
})(ReachEventNamesEnum || {});
|
|
2810
|
+
var BusinessAutomationTypeEnum = /* @__PURE__ */ ((BusinessAutomationTypeEnum2) => {
|
|
2811
|
+
BusinessAutomationTypeEnum2["MANAGED"] = "managed";
|
|
2812
|
+
BusinessAutomationTypeEnum2["CUSTOM"] = "custom";
|
|
2813
|
+
return BusinessAutomationTypeEnum2;
|
|
2814
|
+
})(BusinessAutomationTypeEnum || {});
|
|
2815
|
+
var ActionType = /* @__PURE__ */ ((ActionType2) => {
|
|
2816
|
+
ActionType2["SEND_COMMUNICATION"] = "send_communication";
|
|
2817
|
+
ActionType2["WAIT_UNTIL_NEXT_FIXED_TIME"] = "wait_until_next_fixed_time";
|
|
2818
|
+
return ActionType2;
|
|
2819
|
+
})(ActionType || {});
|
|
2820
|
+
var AutomationStatus = /* @__PURE__ */ ((AutomationStatus2) => {
|
|
2821
|
+
AutomationStatus2["DRAFT"] = "draft";
|
|
2822
|
+
AutomationStatus2["ACTIVE"] = "active";
|
|
2823
|
+
AutomationStatus2["RUNNING"] = "running";
|
|
2824
|
+
AutomationStatus2["COMPLETED"] = "completed";
|
|
2825
|
+
AutomationStatus2["FAILED"] = "failed";
|
|
2826
|
+
AutomationStatus2["DEACTIVATED"] = "deactivated";
|
|
2827
|
+
AutomationStatus2["SENDING"] = "sending";
|
|
2828
|
+
AutomationStatus2["SCHEDULED"] = "scheduled";
|
|
2829
|
+
AutomationStatus2["PARTIALLY_CANCELLED"] = "partially_cancelled";
|
|
2830
|
+
AutomationStatus2["CANCELLED"] = "cancelled";
|
|
2831
|
+
AutomationStatus2["ARCHIVED"] = "archived";
|
|
2832
|
+
return AutomationStatus2;
|
|
2833
|
+
})(AutomationStatus || {});
|
|
2834
|
+
var ChannelIntegrationTypeEnum = /* @__PURE__ */ ((ChannelIntegrationTypeEnum2) => {
|
|
2835
|
+
ChannelIntegrationTypeEnum2["EMAIL"] = "email";
|
|
2836
|
+
ChannelIntegrationTypeEnum2["SMS"] = "sms";
|
|
2837
|
+
return ChannelIntegrationTypeEnum2;
|
|
2838
|
+
})(ChannelIntegrationTypeEnum || {});
|
|
2839
|
+
const shouldPoll = (automationStatus) => {
|
|
2840
|
+
return automationStatus !== AutomationStatus.DRAFT && automationStatus !== AutomationStatus.COMPLETED && automationStatus !== AutomationStatus.PARTIALLY_CANCELLED && automationStatus !== AutomationStatus.CANCELLED;
|
|
2841
|
+
};
|
|
2791
2842
|
const TOAST_LIMIT = 1;
|
|
2792
2843
|
const TOAST_REMOVE_DELAY = 1e6;
|
|
2793
2844
|
let count$8 = 0;
|
|
@@ -2961,6 +3012,16 @@ const resetCommunicationGroupToDefault = async (args) => {
|
|
|
2961
3012
|
);
|
|
2962
3013
|
return response.data;
|
|
2963
3014
|
};
|
|
3015
|
+
const postBusinessMergeFieldFallbacks = async (mergeFieldFallbacks) => {
|
|
3016
|
+
const response = await baseRequest(
|
|
3017
|
+
`/businesses/merge-field-fallbacks`,
|
|
3018
|
+
{
|
|
3019
|
+
method: "PATCH",
|
|
3020
|
+
body: JSON.stringify({ mergeFieldFallbacks })
|
|
3021
|
+
}
|
|
3022
|
+
);
|
|
3023
|
+
return response.data;
|
|
3024
|
+
};
|
|
2964
3025
|
const getLinkClickStats = async (automationId) => {
|
|
2965
3026
|
const response = await baseRequest(
|
|
2966
3027
|
`${COMMUNICATION_GROUP_PATH}/${automationId}/link-click-stats`
|
|
@@ -3079,6 +3140,36 @@ const useResetCommunicationGroupToDefault = () => {
|
|
|
3079
3140
|
isPending: resetCommunicationGroupToDefaultMutation.isPending
|
|
3080
3141
|
};
|
|
3081
3142
|
};
|
|
3143
|
+
const usePostBusinessMergeFieldFallbacks = () => {
|
|
3144
|
+
const queryClient = useQueryClient();
|
|
3145
|
+
const { toast: toast2 } = useToast();
|
|
3146
|
+
const mutation = useMutation({
|
|
3147
|
+
mutationFn: ({
|
|
3148
|
+
mergeFieldFallbacks
|
|
3149
|
+
}) => postBusinessMergeFieldFallbacks(mergeFieldFallbacks),
|
|
3150
|
+
onSuccess: () => {
|
|
3151
|
+
queryClient.invalidateQueries({
|
|
3152
|
+
queryKey: communicationGroupQueryKeys.all
|
|
3153
|
+
});
|
|
3154
|
+
toast2({
|
|
3155
|
+
title: "Merge field fallbacks updated",
|
|
3156
|
+
description: "Merge field fallbacks have been updated"
|
|
3157
|
+
});
|
|
3158
|
+
},
|
|
3159
|
+
onError: () => {
|
|
3160
|
+
toast2({
|
|
3161
|
+
title: "Failed to update merge field fallbacks",
|
|
3162
|
+
description: "Please reach out to your administrator"
|
|
3163
|
+
});
|
|
3164
|
+
}
|
|
3165
|
+
});
|
|
3166
|
+
return {
|
|
3167
|
+
postBusinessMergeFieldFallbacks: mutation.mutate,
|
|
3168
|
+
isPosting: mutation.isPending,
|
|
3169
|
+
postError: mutation.error,
|
|
3170
|
+
isPostSuccess: mutation.isSuccess
|
|
3171
|
+
};
|
|
3172
|
+
};
|
|
3082
3173
|
const useGetLinkClickStats = (automationId) => {
|
|
3083
3174
|
const query = useQuery({
|
|
3084
3175
|
queryKey: ["link-click-stats", automationId],
|
|
@@ -3096,7 +3187,14 @@ const useGetBusinessAutomation = (automationId) => {
|
|
|
3096
3187
|
const queryClient = useQueryClient();
|
|
3097
3188
|
const getAutomationQuery = useQuery({
|
|
3098
3189
|
queryKey: automationKeys.single(automationId),
|
|
3099
|
-
queryFn: () => getAutomation(automationId)
|
|
3190
|
+
queryFn: () => getAutomation(automationId),
|
|
3191
|
+
refetchInterval: (data) => {
|
|
3192
|
+
const shouldPollResult = shouldPoll(data?.state.data?.status);
|
|
3193
|
+
if (shouldPollResult) {
|
|
3194
|
+
return 2e3;
|
|
3195
|
+
}
|
|
3196
|
+
return false;
|
|
3197
|
+
}
|
|
3100
3198
|
});
|
|
3101
3199
|
return {
|
|
3102
3200
|
// Get automation query
|
|
@@ -3124,7 +3222,13 @@ const useGetBusinessAutomationSentCommunications = (args) => {
|
|
|
3124
3222
|
// It will be false if placeholder data is being shown, even though a new fetch is in progress (`isFetching` will be true).
|
|
3125
3223
|
// This provides a much smoother UX, as the UI doesn't jump to a loading state on pagination or filter changes
|
|
3126
3224
|
// if previous data is available to show in the meantime.
|
|
3127
|
-
placeholderData: keepPreviousData
|
|
3225
|
+
placeholderData: keepPreviousData,
|
|
3226
|
+
refetchInterval: () => {
|
|
3227
|
+
if (shouldPoll(args.automationStatus)) {
|
|
3228
|
+
return 2e3;
|
|
3229
|
+
}
|
|
3230
|
+
return false;
|
|
3231
|
+
}
|
|
3128
3232
|
});
|
|
3129
3233
|
return {
|
|
3130
3234
|
// Get automation sent communications query
|
|
@@ -3255,45 +3359,6 @@ const useDuplicateBusinessAutomation = () => {
|
|
|
3255
3359
|
isDuplicateSuccess: duplicateAutomationMutation.isSuccess
|
|
3256
3360
|
};
|
|
3257
3361
|
};
|
|
3258
|
-
var AutomationTriggerType = /* @__PURE__ */ ((AutomationTriggerType2) => {
|
|
3259
|
-
AutomationTriggerType2["ONE_TIME"] = "one_time";
|
|
3260
|
-
AutomationTriggerType2["TRIGGER_BASED"] = "trigger_based";
|
|
3261
|
-
AutomationTriggerType2["DATE_BASED"] = "date_based";
|
|
3262
|
-
return AutomationTriggerType2;
|
|
3263
|
-
})(AutomationTriggerType || {});
|
|
3264
|
-
var ReachEventNamesEnum = /* @__PURE__ */ ((ReachEventNamesEnum2) => {
|
|
3265
|
-
ReachEventNamesEnum2["USER_ENTERS_SEGMENT"] = "USER_ENTERS_SEGMENT";
|
|
3266
|
-
return ReachEventNamesEnum2;
|
|
3267
|
-
})(ReachEventNamesEnum || {});
|
|
3268
|
-
var BusinessAutomationTypeEnum = /* @__PURE__ */ ((BusinessAutomationTypeEnum2) => {
|
|
3269
|
-
BusinessAutomationTypeEnum2["MANAGED"] = "managed";
|
|
3270
|
-
BusinessAutomationTypeEnum2["CUSTOM"] = "custom";
|
|
3271
|
-
return BusinessAutomationTypeEnum2;
|
|
3272
|
-
})(BusinessAutomationTypeEnum || {});
|
|
3273
|
-
var ActionType = /* @__PURE__ */ ((ActionType2) => {
|
|
3274
|
-
ActionType2["SEND_COMMUNICATION"] = "send_communication";
|
|
3275
|
-
ActionType2["WAIT_UNTIL_NEXT_FIXED_TIME"] = "wait_until_next_fixed_time";
|
|
3276
|
-
return ActionType2;
|
|
3277
|
-
})(ActionType || {});
|
|
3278
|
-
var AutomationStatus = /* @__PURE__ */ ((AutomationStatus2) => {
|
|
3279
|
-
AutomationStatus2["DRAFT"] = "draft";
|
|
3280
|
-
AutomationStatus2["ACTIVE"] = "active";
|
|
3281
|
-
AutomationStatus2["RUNNING"] = "running";
|
|
3282
|
-
AutomationStatus2["COMPLETED"] = "completed";
|
|
3283
|
-
AutomationStatus2["FAILED"] = "failed";
|
|
3284
|
-
AutomationStatus2["DEACTIVATED"] = "deactivated";
|
|
3285
|
-
AutomationStatus2["SENDING"] = "sending";
|
|
3286
|
-
AutomationStatus2["SCHEDULED"] = "scheduled";
|
|
3287
|
-
AutomationStatus2["PARTIALLY_CANCELLED"] = "partially_cancelled";
|
|
3288
|
-
AutomationStatus2["CANCELLED"] = "cancelled";
|
|
3289
|
-
AutomationStatus2["ARCHIVED"] = "archived";
|
|
3290
|
-
return AutomationStatus2;
|
|
3291
|
-
})(AutomationStatus || {});
|
|
3292
|
-
var ChannelIntegrationTypeEnum = /* @__PURE__ */ ((ChannelIntegrationTypeEnum2) => {
|
|
3293
|
-
ChannelIntegrationTypeEnum2["EMAIL"] = "email";
|
|
3294
|
-
ChannelIntegrationTypeEnum2["SMS"] = "sms";
|
|
3295
|
-
return ChannelIntegrationTypeEnum2;
|
|
3296
|
-
})(ChannelIntegrationTypeEnum || {});
|
|
3297
3362
|
class InvalidTokenError extends Error {
|
|
3298
3363
|
}
|
|
3299
3364
|
InvalidTokenError.prototype.name = "InvalidTokenError";
|
|
@@ -25678,6 +25743,16 @@ const Info = createLucideIcon("Info", [
|
|
|
25678
25743
|
["path", { d: "M12 16v-4", key: "1dtifu" }],
|
|
25679
25744
|
["path", { d: "M12 8h.01", key: "e9boi3" }]
|
|
25680
25745
|
]);
|
|
25746
|
+
/**
|
|
25747
|
+
* @license lucide-react v0.464.0 - ISC
|
|
25748
|
+
*
|
|
25749
|
+
* This source code is licensed under the ISC license.
|
|
25750
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
25751
|
+
*/
|
|
25752
|
+
const Link$1 = createLucideIcon("Link", [
|
|
25753
|
+
["path", { d: "M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71", key: "1cjeqo" }],
|
|
25754
|
+
["path", { d: "M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71", key: "19qd67" }]
|
|
25755
|
+
]);
|
|
25681
25756
|
/**
|
|
25682
25757
|
* @license lucide-react v0.464.0 - ISC
|
|
25683
25758
|
*
|
|
@@ -29244,6 +29319,47 @@ const applyThemeStyles = (styles2, darkStyles) => {
|
|
|
29244
29319
|
if (existingStyles) {
|
|
29245
29320
|
existingStyles.remove();
|
|
29246
29321
|
}
|
|
29322
|
+
const isGoogleFont = (font) => {
|
|
29323
|
+
if (!font) return null;
|
|
29324
|
+
const match2 = font.match(/^["']?([\w\s]+)["']?/);
|
|
29325
|
+
if (!match2) return null;
|
|
29326
|
+
const fontName = match2[1].trim();
|
|
29327
|
+
const systemFonts = [
|
|
29328
|
+
"Inter",
|
|
29329
|
+
"system-ui",
|
|
29330
|
+
"-apple-system",
|
|
29331
|
+
"BlinkMacSystemFont",
|
|
29332
|
+
"Segoe UI",
|
|
29333
|
+
"Roboto",
|
|
29334
|
+
"sans-serif",
|
|
29335
|
+
"serif",
|
|
29336
|
+
"monospace",
|
|
29337
|
+
"Arial",
|
|
29338
|
+
"Georgia",
|
|
29339
|
+
"Times New Roman",
|
|
29340
|
+
"Courier New",
|
|
29341
|
+
"Plus Jakarta Sans"
|
|
29342
|
+
];
|
|
29343
|
+
if (systemFonts.some((sys) => fontName === sys)) return null;
|
|
29344
|
+
return fontName;
|
|
29345
|
+
};
|
|
29346
|
+
const googleFonts = /* @__PURE__ */ new Set();
|
|
29347
|
+
const fontBody = styles2["font-body"];
|
|
29348
|
+
const fontHeading = styles2["font-heading"];
|
|
29349
|
+
const bodyFont = isGoogleFont(fontBody);
|
|
29350
|
+
const headingFont = isGoogleFont(fontHeading);
|
|
29351
|
+
if (bodyFont) googleFonts.add(bodyFont);
|
|
29352
|
+
if (headingFont) googleFonts.add(headingFont);
|
|
29353
|
+
googleFonts.forEach((fontName) => {
|
|
29354
|
+
const fontId = `reach-google-font-${fontName.replace(/\s+/g, "-")}`;
|
|
29355
|
+
if (!document.getElementById(fontId)) {
|
|
29356
|
+
const link2 = document.createElement("link");
|
|
29357
|
+
link2.id = fontId;
|
|
29358
|
+
link2.rel = "stylesheet";
|
|
29359
|
+
link2.href = `https://fonts.googleapis.com/css?family=${encodeURIComponent(fontName)}:400,500,700&display=swap`;
|
|
29360
|
+
document.head.appendChild(link2);
|
|
29361
|
+
}
|
|
29362
|
+
});
|
|
29247
29363
|
const styleElement2 = document.createElement("style");
|
|
29248
29364
|
styleElement2.id = "reach-theme-styles";
|
|
29249
29365
|
let cssText = `
|
|
@@ -32360,6 +32476,8 @@ const measure$1 = {
|
|
|
32360
32476
|
total_revenue: "Total Revenue",
|
|
32361
32477
|
total_revenue_description: "The complete revenue generated by your business during the selected period from all sources, not just advertising campaigns. \n\nThis includes revenue from direct traffic, organic search, referrals, and any other channels in addition to paid advertising.",
|
|
32362
32478
|
website_visitors: "Website Visitors",
|
|
32479
|
+
unknown_revenue: "Unknown Revenue",
|
|
32480
|
+
unknown_revenue_description: "Revenue from purchases where we were unable to find customer interactions (like site visits or phone calls) in the 90 days before buying.",
|
|
32363
32481
|
website_visitors_description: "The number of unique visitors who came to your website from your advertising campaigns during the selected period. \n\nThis metric is tracked using analytics tools and represents actual people who successfully navigated from your ads to your website."
|
|
32364
32482
|
},
|
|
32365
32483
|
settings: {
|
|
@@ -32367,7 +32485,6 @@ const measure$1 = {
|
|
|
32367
32485
|
description: "Manage your account settings",
|
|
32368
32486
|
connected_accounts: "Connected Accounts",
|
|
32369
32487
|
not_running_paid_ads: "Not running paid ads? Use AI to create a Google Ads campaign",
|
|
32370
|
-
not_running_paid_ads_tooltip: "Contact your administrator to learn more about this feature and how to activate it for your account",
|
|
32371
32488
|
privacy_policy: "Privacy Policy",
|
|
32372
32489
|
quick_links: "Quick Links",
|
|
32373
32490
|
setup_tracking_pixel: "Setup tracking pixel",
|
|
@@ -32388,7 +32505,11 @@ const measure$1 = {
|
|
|
32388
32505
|
purchases_tooltip: "Purchases are the number of times a user made a purchase after clicking on your ad. \n\nThe percentage is calculated by dividing the number of purchases by the number of clicks (from the previous bar line)"
|
|
32389
32506
|
},
|
|
32390
32507
|
roas_chart: {
|
|
32391
|
-
title: "Return on Ad Spend Trends"
|
|
32508
|
+
title: "Return on Ad Spend Trends",
|
|
32509
|
+
attribution_tooltip_title: "How revenue is counted in this chart",
|
|
32510
|
+
attribution_tooltip_description: "For each day, we show the total ad spend, revenue, and ROAS (return on ad spend) from people who clicked an ad that day.\n\nIf someone clicks an ad and buys within 90 days, their purchase is counted for the day they clicked the ad.\n\nThe most recent 90 days may look low, since more purchases can still come in.",
|
|
32511
|
+
incomplete_banner: "Revenue and ROAS for recent days may be lower than their final values, since we continue to count purchases made up to 90 days after someone clicks an ad.",
|
|
32512
|
+
incomplete_tooltip: "Still updating (<90 days)"
|
|
32392
32513
|
}
|
|
32393
32514
|
},
|
|
32394
32515
|
campaigns: {
|
|
@@ -32466,7 +32587,8 @@ const dates$1 = {
|
|
|
32466
32587
|
last_week: "Last week",
|
|
32467
32588
|
last_month: "Last month",
|
|
32468
32589
|
last_quarter: "Last 90 days",
|
|
32469
|
-
last_year: "Last year"
|
|
32590
|
+
last_year: "Last year",
|
|
32591
|
+
all_time: "All time"
|
|
32470
32592
|
};
|
|
32471
32593
|
const campaigns$1 = {
|
|
32472
32594
|
setup: {
|
|
@@ -32545,16 +32667,15 @@ const analytics$1 = {
|
|
|
32545
32667
|
google_tag_manager: {
|
|
32546
32668
|
step_1: "Go to https://tagmanager.google.com",
|
|
32547
32669
|
step_2: "Sign in to your Google Account",
|
|
32548
|
-
step_3:
|
|
32549
|
-
step_4: "
|
|
32550
|
-
step_5: "
|
|
32551
|
-
step_6:
|
|
32552
|
-
step_7: "
|
|
32553
|
-
step_8: "
|
|
32554
|
-
step_9: "
|
|
32555
|
-
step_10: "
|
|
32556
|
-
step_11: "
|
|
32557
|
-
step_12: 'Select "Google Analytics: Universal Analytics" as the tag type',
|
|
32670
|
+
step_3: 'In the Tags tab, click the "New" button to create a new tag',
|
|
32671
|
+
step_4: 'Choose "Custom HTML" as the tag type',
|
|
32672
|
+
step_5: "Paste the tracking code above into the HTML field",
|
|
32673
|
+
step_6: "Click anywhere in the triggering section to edit this setting",
|
|
32674
|
+
step_7: 'Select "Initialization - All Pages" as the trigger',
|
|
32675
|
+
step_8: "Click Save to save the tag",
|
|
32676
|
+
step_9: "Click Submit in the top right",
|
|
32677
|
+
step_10: "Add a version name and description",
|
|
32678
|
+
step_11: "Click Publish to deploy your changes",
|
|
32558
32679
|
special_note: "Make sure you have the Google Tag Manager container code already installed on your site before adding this tag."
|
|
32559
32680
|
},
|
|
32560
32681
|
hubspot: {
|
|
@@ -32774,6 +32895,8 @@ const broadcast_other$1 = "Broadcasts";
|
|
|
32774
32895
|
const trigger_based$1 = "Trigger Based";
|
|
32775
32896
|
const insight$1 = "Insight";
|
|
32776
32897
|
const insight_other$1 = "Insights";
|
|
32898
|
+
const merge_field$1 = "Merge Field";
|
|
32899
|
+
const merge_field_other$1 = "Merge Fields";
|
|
32777
32900
|
const enEngage = {
|
|
32778
32901
|
user: user$1,
|
|
32779
32902
|
user_other: user_other$1,
|
|
@@ -32785,7 +32908,9 @@ const enEngage = {
|
|
|
32785
32908
|
broadcast_other: broadcast_other$1,
|
|
32786
32909
|
trigger_based: trigger_based$1,
|
|
32787
32910
|
insight: insight$1,
|
|
32788
|
-
insight_other: insight_other$1
|
|
32911
|
+
insight_other: insight_other$1,
|
|
32912
|
+
merge_field: merge_field$1,
|
|
32913
|
+
merge_field_other: merge_field_other$1
|
|
32789
32914
|
};
|
|
32790
32915
|
const account_id = "ID de cuenta";
|
|
32791
32916
|
const account_name = "Nombre de cuenta";
|
|
@@ -32908,6 +33033,8 @@ const measure = {
|
|
|
32908
33033
|
total_revenue: "Ingresos totales",
|
|
32909
33034
|
total_revenue_description: "Los ingresos totales generados por tu negocio durante el período seleccionado, no solo a través de campañas de anuncios. \n\nEsto incluye ingresos de tráfico directo, búsqueda orgánica, referencias y cualquier otro canal además de campañas de anuncios.",
|
|
32910
33035
|
website_visitors: "Visitantes de tu sitio web",
|
|
33036
|
+
unknown_revenue: "Ingresos desconocidos",
|
|
33037
|
+
unknown_revenue_description: "Ingresos de compras donde no pudimos encontrar interacciones del cliente (como visitas al sitio o llamadas telefónicas) en los 90 días antes de la compra.",
|
|
32911
33038
|
website_visitors_description: "El número de visitantes únicos que llegaron a tu sitio web a través de tus campañas de anuncios durante el período seleccionado. \n\nEsta métrica se rastrea usando herramientas de analytics y representa a las personas que realmente navegaron desde tus anuncios a tu sitio web."
|
|
32912
33039
|
},
|
|
32913
33040
|
settings: {
|
|
@@ -32915,7 +33042,6 @@ const measure = {
|
|
|
32915
33042
|
description: "Gestiona tus ajustes de cuenta",
|
|
32916
33043
|
connected_accounts: "Cuentas conectadas",
|
|
32917
33044
|
not_running_paid_ads: "¿No estás ejecutando anuncios pagados? Usa IA para crear una campaña de Google Ads",
|
|
32918
|
-
not_running_paid_ads_tooltip: "Contacta a tu administrador para aprender más sobre esta función y cómo activarla para tu cuenta",
|
|
32919
33045
|
privacy_policy: "Política de privacidad",
|
|
32920
33046
|
quick_links: "Enlaces rápidos",
|
|
32921
33047
|
setup_tracking_pixel: "Configurar pixel de seguimiento",
|
|
@@ -32936,7 +33062,11 @@ const measure = {
|
|
|
32936
33062
|
purchases_tooltip: "Las compras son el número de veces que un usuario hizo una compra después de hacer clic en tu anuncio. \n\nEl porcentaje se calcula dividiendo el número de compras por el número de clics (de la línea anterior)"
|
|
32937
33063
|
},
|
|
32938
33064
|
roas_chart: {
|
|
32939
|
-
title: "Tendencias de Retorno de Inversión en Anuncios"
|
|
33065
|
+
title: "Tendencias de Retorno de Inversión en Anuncios",
|
|
33066
|
+
attribution_tooltip_title: "Cómo se cuentan los ingresos en este gráfico",
|
|
33067
|
+
attribution_tooltip_description: "Para cada día, mostramos el gasto total en anuncios, ingresos y ROAS (retorno de inversión en anuncios) de personas que hicieron clic en un anuncio ese día.\n\nSi alguien hace clic en un anuncio y compra dentro de 90 días, su compra se cuenta para el día en que hizo clic en el anuncio.\n\nLos últimos 90 días pueden parecer bajos, ya que pueden seguir llegando más compras.",
|
|
33068
|
+
incomplete_banner: "Los ingresos y ROAS de los días más recientes pueden ser inferiores a sus valores finales, ya que seguimos contando compras realizadas hasta 90 días después de que alguien haga clic en un anuncio.",
|
|
33069
|
+
incomplete_tooltip: "Aún actualizando (<90 días)"
|
|
32940
33070
|
}
|
|
32941
33071
|
},
|
|
32942
33072
|
campaigns: {
|
|
@@ -33014,7 +33144,8 @@ const dates = {
|
|
|
33014
33144
|
last_week: "Semana pasada",
|
|
33015
33145
|
last_month: "Mes pasado",
|
|
33016
33146
|
last_quarter: "Últimos 90 días",
|
|
33017
|
-
last_year: "Año pasado"
|
|
33147
|
+
last_year: "Año pasado",
|
|
33148
|
+
all_time: "Todo el tiempo"
|
|
33018
33149
|
};
|
|
33019
33150
|
const campaigns = {
|
|
33020
33151
|
setup: {
|
|
@@ -33093,16 +33224,15 @@ const analytics = {
|
|
|
33093
33224
|
google_tag_manager: {
|
|
33094
33225
|
step_1: "Ve a https://tagmanager.google.com",
|
|
33095
33226
|
step_2: "Inicia sesión en tu cuenta de Google",
|
|
33096
|
-
step_3:
|
|
33097
|
-
step_4: "
|
|
33098
|
-
step_5: "
|
|
33099
|
-
step_6:
|
|
33100
|
-
step_7: "
|
|
33101
|
-
step_8: "
|
|
33102
|
-
step_9: "
|
|
33103
|
-
step_10: "
|
|
33104
|
-
step_11: "
|
|
33105
|
-
step_12: 'Selecciona "Google Analytics: Universal Analytics" como tipo de etiqueta',
|
|
33227
|
+
step_3: 'En la pestaña de Etiquetas, haz click en el botón "Nuevo" para crear una nueva etiqueta',
|
|
33228
|
+
step_4: 'Elige "Código personalizado" como tipo de etiqueta',
|
|
33229
|
+
step_5: "Pega el código de seguimiento en el campo HTML",
|
|
33230
|
+
step_6: "Haz click en cualquier sección del trigger para editar esta configuración",
|
|
33231
|
+
step_7: 'Elige "Inicialización - Todas las páginas" como trigger',
|
|
33232
|
+
step_8: "Haz click en Guardar para guardar la etiqueta",
|
|
33233
|
+
step_9: "Haz click en Enviar en la parte superior derecha",
|
|
33234
|
+
step_10: "Añade un nombre y descripción de la versión",
|
|
33235
|
+
step_11: "Haz click en Publicar para desplegar tus cambios",
|
|
33106
33236
|
special_note: "Asegúrate de tener el código del contenedor de Google Tag Manager instalado en tu sitio web antes de agregar esta etiqueta."
|
|
33107
33237
|
},
|
|
33108
33238
|
hubspot: {
|
|
@@ -33322,6 +33452,8 @@ const broadcast_other = "Transmisiones";
|
|
|
33322
33452
|
const trigger_based = "Basado en un disparador";
|
|
33323
33453
|
const insight = "Estadísticas";
|
|
33324
33454
|
const insight_other = "Estadísticas";
|
|
33455
|
+
const merge_field = "Campo de fusión";
|
|
33456
|
+
const merge_field_other = "Campos de fusión";
|
|
33325
33457
|
const esEngage = {
|
|
33326
33458
|
user,
|
|
33327
33459
|
user_other,
|
|
@@ -33333,7 +33465,9 @@ const esEngage = {
|
|
|
33333
33465
|
broadcast_other,
|
|
33334
33466
|
trigger_based,
|
|
33335
33467
|
insight,
|
|
33336
|
-
insight_other
|
|
33468
|
+
insight_other,
|
|
33469
|
+
merge_field,
|
|
33470
|
+
merge_field_other
|
|
33337
33471
|
};
|
|
33338
33472
|
const transaction_table_id_header$1 = "Transaction ID";
|
|
33339
33473
|
const transaction_table_created_header$1 = "Transaction Created";
|
|
@@ -33521,6 +33655,8 @@ const defaultTranslations = {
|
|
|
33521
33655
|
total_revenue: "Total Revenue",
|
|
33522
33656
|
total_revenue_description: "The complete revenue generated by your business during the selected period from all sources, not just advertising campaigns. \n\nThis includes revenue from direct traffic, organic search, referrals, and any other channels in addition to paid advertising.",
|
|
33523
33657
|
website_visitors: "Website Visitors",
|
|
33658
|
+
unknown_revenue: "Unknown Revenue",
|
|
33659
|
+
unknown_revenue_description: "Revenue from purchases where we were unable to find customer interactions (like site visits or phone calls) in the 90 days before buying.",
|
|
33524
33660
|
website_visitors_description: "The number of unique visitors who came to your website from your advertising campaigns during the selected period. \n\nThis metric is tracked using analytics tools and represents actual people who successfully navigated from your ads to your website."
|
|
33525
33661
|
},
|
|
33526
33662
|
settings: {
|
|
@@ -33528,7 +33664,6 @@ const defaultTranslations = {
|
|
|
33528
33664
|
description: "Manage your account settings",
|
|
33529
33665
|
connected_accounts: "Connected Accounts",
|
|
33530
33666
|
not_running_paid_ads: "Not running paid ads? Use AI to create a Google Ads campaign",
|
|
33531
|
-
not_running_paid_ads_tooltip: "Contact your administrator to learn more about this feature and how to activate it for your account",
|
|
33532
33667
|
privacy_policy: "Privacy Policy",
|
|
33533
33668
|
quick_links: "Quick Links",
|
|
33534
33669
|
setup_tracking_pixel: "Setup tracking pixel",
|
|
@@ -33549,7 +33684,11 @@ const defaultTranslations = {
|
|
|
33549
33684
|
purchases_tooltip: "Purchases are the number of times a user made a purchase after clicking on your ad. \n\nThe percentage is calculated by dividing the number of purchases by the number of clicks (from the previous bar line)"
|
|
33550
33685
|
},
|
|
33551
33686
|
roas_chart: {
|
|
33552
|
-
title: "Return on Ad Spend Trends"
|
|
33687
|
+
title: "Return on Ad Spend Trends",
|
|
33688
|
+
attribution_tooltip_title: "How revenue is counted in this chart",
|
|
33689
|
+
attribution_tooltip_description: "For each day, we show the total ad spend, revenue, and ROAS (return on ad spend) from people who clicked an ad that day.\n\nIf someone clicks an ad and buys within 90 days, their purchase is counted for the day they clicked the ad.\n\nThe most recent 90 days may look low, since more purchases can still come in.",
|
|
33690
|
+
incomplete_banner: "Revenue and ROAS for recent days may be lower than their final values, since we continue to count purchases made up to 90 days after someone clicks an ad.",
|
|
33691
|
+
incomplete_tooltip: "Still updating (<90 days)"
|
|
33553
33692
|
}
|
|
33554
33693
|
},
|
|
33555
33694
|
campaigns: {
|
|
@@ -33628,7 +33767,8 @@ const defaultTranslations = {
|
|
|
33628
33767
|
last_week: "Last week",
|
|
33629
33768
|
last_month: "Last month",
|
|
33630
33769
|
last_quarter: "Last 90 days",
|
|
33631
|
-
last_year: "Last year"
|
|
33770
|
+
last_year: "Last year",
|
|
33771
|
+
all_time: "All time"
|
|
33632
33772
|
},
|
|
33633
33773
|
campaigns: {
|
|
33634
33774
|
setup: {
|
|
@@ -33707,16 +33847,15 @@ const defaultTranslations = {
|
|
|
33707
33847
|
google_tag_manager: {
|
|
33708
33848
|
step_1: "Go to https://tagmanager.google.com",
|
|
33709
33849
|
step_2: "Sign in to your Google Account",
|
|
33710
|
-
step_3:
|
|
33711
|
-
step_4: "
|
|
33712
|
-
step_5: "
|
|
33713
|
-
step_6:
|
|
33714
|
-
step_7: "
|
|
33715
|
-
step_8: "
|
|
33716
|
-
step_9: "
|
|
33717
|
-
step_10: "
|
|
33718
|
-
step_11: "
|
|
33719
|
-
step_12: 'Select "Google Analytics: Universal Analytics" as the tag type',
|
|
33850
|
+
step_3: 'In the Tags tab, click the "New" button to create a new tag',
|
|
33851
|
+
step_4: 'Choose "Custom HTML" as the tag type',
|
|
33852
|
+
step_5: "Paste the tracking code above into the HTML field",
|
|
33853
|
+
step_6: "Click anywhere in the triggering section to edit this setting",
|
|
33854
|
+
step_7: 'Select "Initialization - All Pages" as the trigger',
|
|
33855
|
+
step_8: "Click Save to save the tag",
|
|
33856
|
+
step_9: "Click Submit in the top right",
|
|
33857
|
+
step_10: "Add a version name and description",
|
|
33858
|
+
step_11: "Click Publish to deploy your changes",
|
|
33720
33859
|
special_note: "Make sure you have the Google Tag Manager container code already installed on your site before adding this tag."
|
|
33721
33860
|
},
|
|
33722
33861
|
hubspot: {
|
|
@@ -48907,16 +49046,16 @@ const getSegment = async (segmentId) => {
|
|
|
48907
49046
|
return null;
|
|
48908
49047
|
}
|
|
48909
49048
|
const response = await baseRequest(
|
|
48910
|
-
`${BUSINESS_SEGMENT_PATH}/${segmentId}
|
|
49049
|
+
`${BUSINESS_SEGMENT_PATH}/${segmentId}`,
|
|
49050
|
+
{
|
|
49051
|
+
method: "GET"
|
|
49052
|
+
}
|
|
48911
49053
|
);
|
|
48912
49054
|
return response.data;
|
|
48913
49055
|
};
|
|
48914
|
-
const updateSegment = async (
|
|
48915
|
-
if (!segmentId) {
|
|
48916
|
-
return null;
|
|
48917
|
-
}
|
|
49056
|
+
const updateSegment = async (id2, params) => {
|
|
48918
49057
|
const response = await baseRequest(
|
|
48919
|
-
`${BUSINESS_SEGMENT_PATH}/${
|
|
49058
|
+
`${BUSINESS_SEGMENT_PATH}/${id2}`,
|
|
48920
49059
|
{
|
|
48921
49060
|
method: "PATCH",
|
|
48922
49061
|
body: JSON.stringify(params)
|
|
@@ -48924,16 +49063,12 @@ const updateSegment = async (params, segmentId) => {
|
|
|
48924
49063
|
);
|
|
48925
49064
|
return response.data;
|
|
48926
49065
|
};
|
|
48927
|
-
const textToSegment = async (
|
|
48928
|
-
const { userInput, userCustomVerb } = args;
|
|
49066
|
+
const textToSegment = async (params) => {
|
|
48929
49067
|
const response = await baseRequest(
|
|
48930
49068
|
`${BUSINESS_SEGMENT_PATH}/text-to-segment`,
|
|
48931
49069
|
{
|
|
48932
49070
|
method: "POST",
|
|
48933
|
-
body: JSON.stringify(
|
|
48934
|
-
text: userInput,
|
|
48935
|
-
userCustomVerb: userCustomVerb || "user"
|
|
48936
|
-
})
|
|
49071
|
+
body: JSON.stringify(params)
|
|
48937
49072
|
}
|
|
48938
49073
|
);
|
|
48939
49074
|
return response.data;
|
|
@@ -49047,7 +49182,12 @@ const useGetSegment = (segmentId) => {
|
|
|
49047
49182
|
const useUpdateSegment = (segmentId) => {
|
|
49048
49183
|
const queryClient = useQueryClient();
|
|
49049
49184
|
const updateSegmentMutation = useMutation({
|
|
49050
|
-
mutationFn: (params) =>
|
|
49185
|
+
mutationFn: (params) => {
|
|
49186
|
+
if (!segmentId) {
|
|
49187
|
+
throw new Error("Segment ID is required");
|
|
49188
|
+
}
|
|
49189
|
+
return updateSegment(segmentId, params);
|
|
49190
|
+
},
|
|
49051
49191
|
onSuccess: () => {
|
|
49052
49192
|
queryClient.invalidateQueries({ queryKey: segmentKeys.all });
|
|
49053
49193
|
}
|
|
@@ -49074,6 +49214,7 @@ var BusinessSegmentTypeEnum = /* @__PURE__ */ ((BusinessSegmentTypeEnum2) => {
|
|
|
49074
49214
|
BusinessSegmentTypeEnum2["ALL_USERS"] = "all_users";
|
|
49075
49215
|
BusinessSegmentTypeEnum2["MANAGED"] = "managed";
|
|
49076
49216
|
BusinessSegmentTypeEnum2["CUSTOM"] = "custom";
|
|
49217
|
+
BusinessSegmentTypeEnum2["ONE_OFF"] = "one_off";
|
|
49077
49218
|
return BusinessSegmentTypeEnum2;
|
|
49078
49219
|
})(BusinessSegmentTypeEnum || {});
|
|
49079
49220
|
var ConditionOperatorEnumType = /* @__PURE__ */ ((ConditionOperatorEnumType2) => {
|
|
@@ -49297,22 +49438,29 @@ const ActionButtons = ({
|
|
|
49297
49438
|
)
|
|
49298
49439
|
] }) });
|
|
49299
49440
|
};
|
|
49300
|
-
const BigSelector = ({
|
|
49441
|
+
const BigSelector = ({
|
|
49442
|
+
onClick,
|
|
49443
|
+
title: title2,
|
|
49444
|
+
subtitle,
|
|
49445
|
+
icon,
|
|
49446
|
+
selected,
|
|
49447
|
+
disabled = false,
|
|
49448
|
+
hideSelectedText = false
|
|
49449
|
+
}) => {
|
|
49301
49450
|
return /* @__PURE__ */ jsxs(
|
|
49302
49451
|
"button",
|
|
49303
49452
|
{
|
|
49304
49453
|
onClick,
|
|
49305
|
-
className: `relative flex flex-col items-center justify-center rounded-lg border-2 p-6 transition-all duration-300 ease-in-out hover:shadow-lg ${selected ? "border-
|
|
49454
|
+
className: `relative flex flex-col items-center justify-center rounded-lg border-2 p-6 transition-all duration-300 ease-in-out hover:shadow-lg ${selected ? "[border-color:hsl(var(--reach-primary))] shadow-lg" : "border-gray-200 "} ${disabled ? "opacity-50 cursor-not-allowed hover:shadow-none" : "hover:scale-[1.04] scale-[1.02]"} ${!selected && !disabled && "hover:[border-color:hsl(var(--reach-primary))] hover:bg-gray-50"}`,
|
|
49306
49455
|
children: [
|
|
49307
49456
|
icon,
|
|
49308
49457
|
/* @__PURE__ */ jsxs("div", { className: "text-center mt-3", children: [
|
|
49309
49458
|
/* @__PURE__ */ jsx("div", { className: "text-sm font-medium text-primary", children: title2 }),
|
|
49310
49459
|
/* @__PURE__ */ jsx("div", { className: "text-xs text-muted-foreground mt-1", children: subtitle })
|
|
49311
49460
|
] }),
|
|
49312
|
-
selected &&
|
|
49313
|
-
|
|
49314
|
-
/* @__PURE__ */ jsx(
|
|
49315
|
-
/* @__PURE__ */ jsx("span", { className: "text-card text-xs hidden md:inline", children: "Selected" })
|
|
49461
|
+
selected && /* @__PURE__ */ jsxs("div", { className: "absolute top-1 right-1 bg-card rounded-full px-3 py-1 flex items-center gap-1", children: [
|
|
49462
|
+
/* @__PURE__ */ jsx(Check, { className: "w-4 h-4 text-card-foreground" }),
|
|
49463
|
+
!hideSelectedText && /* @__PURE__ */ jsx("span", { className: "text-card-foreground text-xs hidden md:inline", children: "Selected" })
|
|
49316
49464
|
] })
|
|
49317
49465
|
]
|
|
49318
49466
|
}
|
|
@@ -49477,6 +49625,7 @@ const statusArchived = "reach-styles-module__statusArchived___XlN-L";
|
|
|
49477
49625
|
const segmentAllUsers = "reach-styles-module__segmentAllUsers___1aXpc";
|
|
49478
49626
|
const segmentManaged = "reach-styles-module__segmentManaged___o0gOu";
|
|
49479
49627
|
const segmentCustom = "reach-styles-module__segmentCustom___xc3lG";
|
|
49628
|
+
const beta = "reach-styles-module__beta___n9qPf";
|
|
49480
49629
|
const styles$5 = {
|
|
49481
49630
|
base: base$4,
|
|
49482
49631
|
"default": "reach-styles-module__default___zeGU1",
|
|
@@ -49503,7 +49652,8 @@ const styles$5 = {
|
|
|
49503
49652
|
statusArchived,
|
|
49504
49653
|
segmentAllUsers,
|
|
49505
49654
|
segmentManaged,
|
|
49506
|
-
segmentCustom
|
|
49655
|
+
segmentCustom,
|
|
49656
|
+
beta
|
|
49507
49657
|
};
|
|
49508
49658
|
const badgeVariants = cva([styles$5.base], {
|
|
49509
49659
|
variants: {
|
|
@@ -49523,11 +49673,14 @@ const badgeVariants = cva([styles$5.base], {
|
|
|
49523
49673
|
segmentAllUsers: styles$5.segmentAllUsers,
|
|
49524
49674
|
segmentManaged: styles$5.segmentManaged,
|
|
49525
49675
|
segmentCustom: styles$5.segmentCustom,
|
|
49676
|
+
// Not real since we'll never show it
|
|
49677
|
+
segmentOneOff: styles$5.segmentManaged,
|
|
49526
49678
|
statusScheduled: styles$5.statusScheduled,
|
|
49527
49679
|
statusQueued: styles$5.statusQueued,
|
|
49528
49680
|
statusPartiallyCancelled: styles$5.statusPartiallyCancelled,
|
|
49529
49681
|
statusCancelled: styles$5.statusCancelled,
|
|
49530
|
-
statusArchived: styles$5.statusArchived
|
|
49682
|
+
statusArchived: styles$5.statusArchived,
|
|
49683
|
+
beta: styles$5.beta
|
|
49531
49684
|
},
|
|
49532
49685
|
size: {
|
|
49533
49686
|
default: styles$5.sizeDefault,
|
|
@@ -67062,6 +67215,8 @@ const getTypeDescription = (type) => {
|
|
|
67062
67215
|
return `System-defined ${t$2("engage:segment").toLowerCase()} that are not editable or deletable.`;
|
|
67063
67216
|
case BusinessSegmentTypeEnum.CUSTOM:
|
|
67064
67217
|
return `Custom ${t$2("engage:segment").toLowerCase()} that you can edit and delete as needed.`;
|
|
67218
|
+
case BusinessSegmentTypeEnum.ONE_OFF:
|
|
67219
|
+
return `One-off ${t$2("engage:segment").toLowerCase()} that is not editable or deletable.`;
|
|
67065
67220
|
default:
|
|
67066
67221
|
throw UnreachableCaseStatement(type, BusinessSegmentTypeEnum);
|
|
67067
67222
|
}
|
|
@@ -67074,6 +67229,8 @@ const getSegmentTypeVariant = (type) => {
|
|
|
67074
67229
|
return "segmentManaged";
|
|
67075
67230
|
case BusinessSegmentTypeEnum.CUSTOM:
|
|
67076
67231
|
return "segmentCustom";
|
|
67232
|
+
case BusinessSegmentTypeEnum.ONE_OFF:
|
|
67233
|
+
return "segmentOneOff";
|
|
67077
67234
|
default:
|
|
67078
67235
|
throw UnreachableCaseStatement(type, BusinessSegmentTypeEnum);
|
|
67079
67236
|
}
|
|
@@ -67109,7 +67266,9 @@ function createNameColumn(nameAccessor = "name", headerText, showDescription = f
|
|
|
67109
67266
|
const typeDotStyles = {
|
|
67110
67267
|
[BusinessSegmentTypeEnum.ALL_USERS]: "bg-purple-500",
|
|
67111
67268
|
[BusinessSegmentTypeEnum.MANAGED]: "bg-teal-500",
|
|
67112
|
-
[BusinessSegmentTypeEnum.CUSTOM]: "bg-amber-500"
|
|
67269
|
+
[BusinessSegmentTypeEnum.CUSTOM]: "bg-amber-500",
|
|
67270
|
+
// Not real since we'll never show it
|
|
67271
|
+
[BusinessSegmentTypeEnum.ONE_OFF]: "bg-gray-500"
|
|
67113
67272
|
};
|
|
67114
67273
|
const dotColor = type ? typeDotStyles[type] : status ? badgeStyles[status] : "bg-blue-500";
|
|
67115
67274
|
return /* @__PURE__ */ jsx("div", { className: "w-full flex gap-6 justify-between items-center", children: /* @__PURE__ */ jsxs("div", { className: "flex gap-1 items-center w-full", children: [
|
|
@@ -67487,16 +67646,16 @@ const AttributionDialogContent = () => {
|
|
|
67487
67646
|
return /* @__PURE__ */ jsxs(
|
|
67488
67647
|
motion.div,
|
|
67489
67648
|
{
|
|
67490
|
-
className: "space-y-8 p-
|
|
67649
|
+
className: "space-y-8 p-2",
|
|
67491
67650
|
variants: containerVariants,
|
|
67492
67651
|
initial: "hidden",
|
|
67493
67652
|
animate: "visible",
|
|
67494
67653
|
children: [
|
|
67495
|
-
/* @__PURE__ */ jsxs(motion.div, { className: "
|
|
67654
|
+
/* @__PURE__ */ jsxs(motion.div, { className: "space-y-3", variants: itemVariants, children: [
|
|
67496
67655
|
/* @__PURE__ */ jsxs(
|
|
67497
67656
|
motion.h2,
|
|
67498
67657
|
{
|
|
67499
|
-
className: "text-2xl font-semibold flex items-center justify-
|
|
67658
|
+
className: "text-2xl font-semibold flex items-center justify-start gap-2",
|
|
67500
67659
|
initial: { scale: 0.9 },
|
|
67501
67660
|
animate: { scale: 1 },
|
|
67502
67661
|
transition: { duration: 0.5, ease: "easeOut" },
|
|
@@ -67630,6 +67789,41 @@ const AttributionDialogContent = () => {
|
|
|
67630
67789
|
] })
|
|
67631
67790
|
] }, scenario.id)) }) })
|
|
67632
67791
|
] }),
|
|
67792
|
+
/* @__PURE__ */ jsxs(Card, { children: [
|
|
67793
|
+
/* @__PURE__ */ jsxs(CardHeader, { children: [
|
|
67794
|
+
/* @__PURE__ */ jsxs(CardTitle, { className: "flex items-center gap-2", children: [
|
|
67795
|
+
/* @__PURE__ */ jsx(Eye, { className: "h-5 w-5" }),
|
|
67796
|
+
'Understanding "Unknown" Revenue'
|
|
67797
|
+
] }),
|
|
67798
|
+
/* @__PURE__ */ jsx(CardDescription, { children: "Sometimes purchases can't be attributed to specific marketing touchpoints" })
|
|
67799
|
+
] }),
|
|
67800
|
+
/* @__PURE__ */ jsxs(CardContent, { className: "space-y-4", children: [
|
|
67801
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: `Revenue appears as "Unknown" when we can't connect a purchase to any marketing touchpoint within our 90-day attribution window. Here are common scenarios:` }),
|
|
67802
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
|
|
67803
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-start gap-3", children: [
|
|
67804
|
+
/* @__PURE__ */ jsx("div", { className: "w-2 h-2 rounded-full bg-amber-500 mt-2 flex-shrink-0" }),
|
|
67805
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
67806
|
+
/* @__PURE__ */ jsx("h5", { className: "font-medium text-sm", children: "Attribution Window Expired" }),
|
|
67807
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: "Customer clicked an ad and purchased 91+ days later, outside our tracking window" })
|
|
67808
|
+
] })
|
|
67809
|
+
] }),
|
|
67810
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-start gap-3", children: [
|
|
67811
|
+
/* @__PURE__ */ jsx("div", { className: "w-2 h-2 rounded-full bg-amber-500 mt-2 flex-shrink-0" }),
|
|
67812
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
67813
|
+
/* @__PURE__ */ jsx("h5", { className: "font-medium text-sm", children: "Identity Mismatch" }),
|
|
67814
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: "Customer used different email/phone or didn't provide contact information when they visited your site vs. when they made the purchase." })
|
|
67815
|
+
] })
|
|
67816
|
+
] }),
|
|
67817
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-start gap-3", children: [
|
|
67818
|
+
/* @__PURE__ */ jsx("div", { className: "w-2 h-2 rounded-full bg-amber-500 mt-2 flex-shrink-0" }),
|
|
67819
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
67820
|
+
/* @__PURE__ */ jsx("h5", { className: "font-medium text-sm", children: "Technical Limitations" }),
|
|
67821
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: "Ad blockers, privacy settings, or technical issues prevented tracking" })
|
|
67822
|
+
] })
|
|
67823
|
+
] })
|
|
67824
|
+
] })
|
|
67825
|
+
] })
|
|
67826
|
+
] }),
|
|
67633
67827
|
/* @__PURE__ */ jsx(Card, { className: "bg-blue-50 border-blue-200", children: /* @__PURE__ */ jsx(CardContent, { className: "pt-6", children: /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-3", children: [
|
|
67634
67828
|
/* @__PURE__ */ jsx(Clock, { className: "h-5 w-5 text-blue-600 mt-0.5 flex-shrink-0" }),
|
|
67635
67829
|
/* @__PURE__ */ jsxs("div", { children: [
|
|
@@ -67738,7 +67932,7 @@ const InfoTooltip = ({
|
|
|
67738
67932
|
onClick: handleAttributionClick,
|
|
67739
67933
|
variant: "ghost",
|
|
67740
67934
|
size: "sm",
|
|
67741
|
-
className: "flex justify-start w-full items-start gap-2 text-xs text-blue-400 hover:text-blue-200 hover:bg-transparent underline my-1 py-2 px-0 h-auto text-pretty",
|
|
67935
|
+
className: "flex justify-start w-full items-start gap-2 text-xs text-blue-400 hover:text-blue-200 hover:bg-transparent underline my-1 py-2 px-0 h-auto text-pretty text-left",
|
|
67742
67936
|
children: [
|
|
67743
67937
|
/* @__PURE__ */ jsx(ExternalLink, { className: "text-blue-400 h-3 w-3" }),
|
|
67744
67938
|
t3("measure.dashboard.methodology.tooltip")
|
|
@@ -90213,9 +90407,9 @@ var ChannelType = /* @__PURE__ */ ((ChannelType2) => {
|
|
|
90213
90407
|
return ChannelType2;
|
|
90214
90408
|
})(ChannelType || {});
|
|
90215
90409
|
const HEIGHT_BUFFER = 10;
|
|
90216
|
-
const CHECK_DELAYS = [0, 100, 500];
|
|
90410
|
+
const CHECK_DELAYS = [0, 100, 500, 1e3, 2e3];
|
|
90217
90411
|
const DEFAULT_EMAIL_PREVIEW_HEIGHT = 400;
|
|
90218
|
-
const EMAIL_PREVIEW_HEIGHT_CALCULATION_TIMEOUT =
|
|
90412
|
+
const EMAIL_PREVIEW_HEIGHT_CALCULATION_TIMEOUT = 5e3;
|
|
90219
90413
|
const SMS_LIMITS = {
|
|
90220
90414
|
RECOMMENDED_LIMIT: 320
|
|
90221
90415
|
};
|
|
@@ -90276,53 +90470,146 @@ const createHeightMonitor = () => {
|
|
|
90276
90470
|
return `
|
|
90277
90471
|
(function() {
|
|
90278
90472
|
let lastHeight = 0;
|
|
90473
|
+
let checkCount = 0;
|
|
90474
|
+
const MAX_CHECKS = 20; // Prevent infinite loops
|
|
90279
90475
|
|
|
90280
|
-
// Calculate max height from various measurements
|
|
90476
|
+
// Calculate max height from various measurements with better error handling
|
|
90281
90477
|
function getContentHeight() {
|
|
90282
|
-
|
|
90283
|
-
|
|
90284
|
-
body
|
|
90285
|
-
|
|
90286
|
-
|
|
90287
|
-
|
|
90288
|
-
|
|
90289
|
-
|
|
90478
|
+
try {
|
|
90479
|
+
const { body, documentElement: html } = document;
|
|
90480
|
+
if (!body || !html) {
|
|
90481
|
+
return 0;
|
|
90482
|
+
}
|
|
90483
|
+
|
|
90484
|
+
const measurements = [
|
|
90485
|
+
body.scrollHeight,
|
|
90486
|
+
body.offsetHeight,
|
|
90487
|
+
html.clientHeight,
|
|
90488
|
+
html.scrollHeight,
|
|
90489
|
+
html.offsetHeight
|
|
90490
|
+
].filter(h => h > 0 && isFinite(h));
|
|
90491
|
+
|
|
90492
|
+
if (measurements.length === 0) {
|
|
90493
|
+
console.warn('HeightMonitor: No valid height measurements found');
|
|
90494
|
+
return 0;
|
|
90495
|
+
}
|
|
90496
|
+
|
|
90497
|
+
return Math.max(...measurements);
|
|
90498
|
+
} catch (error) {
|
|
90499
|
+
console.warn('HeightMonitor: Error calculating height', error);
|
|
90500
|
+
return 0;
|
|
90501
|
+
}
|
|
90290
90502
|
}
|
|
90291
90503
|
|
|
90292
90504
|
function reportHeight() {
|
|
90293
|
-
|
|
90294
|
-
|
|
90295
|
-
|
|
90296
|
-
|
|
90297
|
-
|
|
90298
|
-
|
|
90299
|
-
|
|
90505
|
+
try {
|
|
90506
|
+
const height = getContentHeight();
|
|
90507
|
+
if (height > 0 && height !== lastHeight) {
|
|
90508
|
+
lastHeight = height;
|
|
90509
|
+
window.parent.postMessage({
|
|
90510
|
+
type: 'IFRAME_HEIGHT_UPDATE',
|
|
90511
|
+
height: height + ${HEIGHT_BUFFER}
|
|
90512
|
+
}, '*');
|
|
90513
|
+
}
|
|
90514
|
+
} catch (error) {
|
|
90515
|
+
console.warn('HeightMonitor: Error reporting height', error);
|
|
90516
|
+
}
|
|
90517
|
+
}
|
|
90518
|
+
|
|
90519
|
+
// Enhanced height monitoring with multiple strategies
|
|
90520
|
+
function setupHeightMonitoring() {
|
|
90521
|
+
try {
|
|
90522
|
+
// Strategy 1: ResizeObserver for real-time monitoring
|
|
90523
|
+
if (window.ResizeObserver) {
|
|
90524
|
+
const observer = new ResizeObserver(() => {
|
|
90525
|
+
requestAnimationFrame(() => {
|
|
90526
|
+
reportHeight();
|
|
90527
|
+
checkCount++;
|
|
90528
|
+
});
|
|
90529
|
+
});
|
|
90530
|
+
observer.observe(document.body);
|
|
90531
|
+
observer.observe(document.documentElement);
|
|
90532
|
+
} else {
|
|
90533
|
+
console.warn('HeightMonitor: ResizeObserver not available, using fallback');
|
|
90534
|
+
}
|
|
90535
|
+
|
|
90536
|
+
// Strategy 2: Handle image loading with better error handling
|
|
90537
|
+
const images = document.querySelectorAll('img');
|
|
90538
|
+
images.forEach(img => {
|
|
90539
|
+
if (!img.complete) {
|
|
90540
|
+
img.addEventListener('load', () => {
|
|
90541
|
+
setTimeout(reportHeight, 100); // Small delay to ensure layout is complete
|
|
90542
|
+
});
|
|
90543
|
+
img.addEventListener('error', () => {
|
|
90544
|
+
setTimeout(reportHeight, 100);
|
|
90545
|
+
});
|
|
90546
|
+
}
|
|
90547
|
+
});
|
|
90548
|
+
|
|
90549
|
+
// Strategy 3: Watch for DOM changes with throttling
|
|
90550
|
+
let mutationTimeout;
|
|
90551
|
+
new MutationObserver(() => {
|
|
90552
|
+
if (mutationTimeout) clearTimeout(mutationTimeout);
|
|
90553
|
+
mutationTimeout = setTimeout(() => {
|
|
90554
|
+
requestAnimationFrame(reportHeight);
|
|
90555
|
+
checkCount++;
|
|
90556
|
+
}, 100); // Throttle mutations
|
|
90557
|
+
}).observe(document.body, {
|
|
90558
|
+
childList: true,
|
|
90559
|
+
subtree: true,
|
|
90560
|
+
attributes: true,
|
|
90561
|
+
attributeFilter: ['style', 'class']
|
|
90562
|
+
});
|
|
90563
|
+
|
|
90564
|
+
// Strategy 4: Periodic checks with exponential backoff
|
|
90565
|
+
let checkDelay = 100;
|
|
90566
|
+
const periodicCheck = () => {
|
|
90567
|
+
if (checkCount >= MAX_CHECKS) {
|
|
90568
|
+
console.warn('HeightMonitor: Max checks reached, stopping periodic checks');
|
|
90569
|
+
return;
|
|
90570
|
+
}
|
|
90571
|
+
|
|
90572
|
+
reportHeight();
|
|
90573
|
+
checkCount++;
|
|
90574
|
+
|
|
90575
|
+
// Exponential backoff for periodic checks
|
|
90576
|
+
checkDelay = Math.min(checkDelay * 1.5, 2000);
|
|
90577
|
+
setTimeout(periodicCheck, checkDelay);
|
|
90578
|
+
};
|
|
90579
|
+
|
|
90580
|
+
// Start periodic checks after initial setup
|
|
90581
|
+
setTimeout(periodicCheck, 500);
|
|
90582
|
+
|
|
90583
|
+
} catch (error) {
|
|
90584
|
+
console.warn('HeightMonitor: Error setting up monitoring', error);
|
|
90300
90585
|
}
|
|
90301
90586
|
}
|
|
90302
90587
|
|
|
90303
|
-
//
|
|
90304
|
-
if (
|
|
90305
|
-
|
|
90306
|
-
|
|
90307
|
-
|
|
90588
|
+
// Initial setup with multiple triggers
|
|
90589
|
+
if (document.readyState === 'loading') {
|
|
90590
|
+
document.addEventListener('DOMContentLoaded', setupHeightMonitoring);
|
|
90591
|
+
} else {
|
|
90592
|
+
setupHeightMonitoring();
|
|
90308
90593
|
}
|
|
90309
90594
|
|
|
90310
|
-
|
|
90311
|
-
|
|
90312
|
-
|
|
90313
|
-
|
|
90314
|
-
|
|
90315
|
-
}
|
|
90595
|
+
window.addEventListener('load', () => {
|
|
90596
|
+
setTimeout(() => {
|
|
90597
|
+
reportHeight();
|
|
90598
|
+
checkCount++;
|
|
90599
|
+
}, 100);
|
|
90316
90600
|
});
|
|
90317
90601
|
|
|
90318
|
-
// Watch for DOM changes
|
|
90319
|
-
new MutationObserver(() => requestAnimationFrame(reportHeight))
|
|
90320
|
-
.observe(document.body, { childList: true, subtree: true });
|
|
90321
|
-
|
|
90322
90602
|
// Initial checks with progressive delays
|
|
90323
|
-
|
|
90324
|
-
|
|
90325
|
-
|
|
90603
|
+
${CHECK_DELAYS.map((delay2) => `setTimeout(() => { reportHeight(); checkCount++; }, ${delay2});`).join("\n ")}
|
|
90604
|
+
|
|
90605
|
+
// Final fallback check
|
|
90606
|
+
setTimeout(() => {
|
|
90607
|
+
if (lastHeight === 0) {
|
|
90608
|
+
console.warn('HeightMonitor: No height reported, forcing final check');
|
|
90609
|
+
reportHeight();
|
|
90610
|
+
}
|
|
90611
|
+
}, 4000);
|
|
90612
|
+
|
|
90326
90613
|
})();
|
|
90327
90614
|
`;
|
|
90328
90615
|
};
|
|
@@ -90330,9 +90617,16 @@ const EmailPreviewHtmlRenderer = ({
|
|
|
90330
90617
|
html,
|
|
90331
90618
|
onHeightChange
|
|
90332
90619
|
}) => {
|
|
90333
|
-
const iframeRef = useRef(null);
|
|
90334
90620
|
const timeoutRef = useRef();
|
|
90335
90621
|
const [state, setState] = useState({ type: "loading" });
|
|
90622
|
+
const [iframeElement, setIframeElement] = useState(
|
|
90623
|
+
null
|
|
90624
|
+
);
|
|
90625
|
+
const setIframeRef = useCallback((element) => {
|
|
90626
|
+
if (element) {
|
|
90627
|
+
setIframeElement(element);
|
|
90628
|
+
}
|
|
90629
|
+
}, []);
|
|
90336
90630
|
const communicationGroup = useCommunicationGroup();
|
|
90337
90631
|
const { getMergeFields: getMergeFields2, isGetting: isGettingMergeFields } = useGetMergeFields(
|
|
90338
90632
|
communicationGroup?.id ?? void 0
|
|
@@ -90357,6 +90651,24 @@ const EmailPreviewHtmlRenderer = ({
|
|
|
90357
90651
|
},
|
|
90358
90652
|
[onHeightChange]
|
|
90359
90653
|
);
|
|
90654
|
+
const handleFallback = useCallback(() => {
|
|
90655
|
+
setState({ type: "error", fallbackHeight: DEFAULT_EMAIL_PREVIEW_HEIGHT });
|
|
90656
|
+
handleHeightUpdate(DEFAULT_EMAIL_PREVIEW_HEIGHT);
|
|
90657
|
+
}, [handleHeightUpdate]);
|
|
90658
|
+
const estimateHeightFromContent = useCallback((htmlContent) => {
|
|
90659
|
+
try {
|
|
90660
|
+
const lines = htmlContent.split("\n").length;
|
|
90661
|
+
const estimatedHeight = Math.max(200, Math.min(800, lines * 20));
|
|
90662
|
+
return estimatedHeight;
|
|
90663
|
+
} catch (error2) {
|
|
90664
|
+
return DEFAULT_EMAIL_PREVIEW_HEIGHT;
|
|
90665
|
+
}
|
|
90666
|
+
}, []);
|
|
90667
|
+
const forceStateChange = useCallback(() => {
|
|
90668
|
+
const estimatedHeight = estimateHeightFromContent(prettyHtml);
|
|
90669
|
+
setState({ type: "error", fallbackHeight: estimatedHeight });
|
|
90670
|
+
handleHeightUpdate(estimatedHeight);
|
|
90671
|
+
}, [prettyHtml, estimateHeightFromContent, handleHeightUpdate]);
|
|
90360
90672
|
useEffect(() => {
|
|
90361
90673
|
if (prettyHtml) {
|
|
90362
90674
|
setState({ type: "calculating" });
|
|
@@ -90366,68 +90678,83 @@ const EmailPreviewHtmlRenderer = ({
|
|
|
90366
90678
|
}
|
|
90367
90679
|
}, [prettyHtml]);
|
|
90368
90680
|
useEffect(() => {
|
|
90369
|
-
if (!prettyHtml || !
|
|
90370
|
-
|
|
90681
|
+
if (!prettyHtml || !iframeElement) {
|
|
90682
|
+
return;
|
|
90683
|
+
}
|
|
90684
|
+
if (state.type === "ready") {
|
|
90685
|
+
return;
|
|
90686
|
+
}
|
|
90687
|
+
const iframe = iframeElement;
|
|
90688
|
+
const timeoutDuration = Math.max(
|
|
90689
|
+
EMAIL_PREVIEW_HEIGHT_CALCULATION_TIMEOUT,
|
|
90690
|
+
5e3
|
|
90691
|
+
);
|
|
90371
90692
|
timeoutRef.current = setTimeout(() => {
|
|
90372
|
-
|
|
90373
|
-
|
|
90374
|
-
|
|
90693
|
+
handleFallback();
|
|
90694
|
+
}, timeoutDuration);
|
|
90695
|
+
const aggressiveTimeout = setTimeout(() => {
|
|
90696
|
+
if (state.type === "calculating") {
|
|
90697
|
+
forceStateChange();
|
|
90698
|
+
}
|
|
90699
|
+
}, 1e4);
|
|
90700
|
+
const estimatedHeight = estimateHeightFromContent(prettyHtml);
|
|
90375
90701
|
const setupHeightMonitoring = () => {
|
|
90376
90702
|
try {
|
|
90377
90703
|
const doc2 = iframe.contentDocument || iframe.contentWindow?.document;
|
|
90378
90704
|
if (!doc2) {
|
|
90379
|
-
setState({
|
|
90380
|
-
|
|
90381
|
-
fallbackHeight: DEFAULT_EMAIL_PREVIEW_HEIGHT
|
|
90382
|
-
});
|
|
90705
|
+
setState({ type: "error", fallbackHeight: estimatedHeight });
|
|
90706
|
+
handleHeightUpdate(estimatedHeight);
|
|
90383
90707
|
return;
|
|
90384
90708
|
}
|
|
90385
90709
|
const injectStyles2 = () => {
|
|
90386
|
-
|
|
90387
|
-
|
|
90388
|
-
|
|
90389
|
-
|
|
90390
|
-
|
|
90391
|
-
|
|
90392
|
-
|
|
90393
|
-
|
|
90394
|
-
|
|
90395
|
-
|
|
90396
|
-
.
|
|
90397
|
-
|
|
90398
|
-
|
|
90399
|
-
|
|
90400
|
-
|
|
90401
|
-
|
|
90402
|
-
|
|
90403
|
-
|
|
90404
|
-
|
|
90405
|
-
|
|
90406
|
-
|
|
90407
|
-
|
|
90408
|
-
|
|
90409
|
-
|
|
90410
|
-
|
|
90411
|
-
|
|
90412
|
-
|
|
90413
|
-
|
|
90414
|
-
|
|
90415
|
-
|
|
90416
|
-
|
|
90417
|
-
|
|
90418
|
-
|
|
90419
|
-
|
|
90420
|
-
|
|
90421
|
-
|
|
90422
|
-
|
|
90423
|
-
|
|
90424
|
-
|
|
90425
|
-
|
|
90426
|
-
|
|
90427
|
-
|
|
90428
|
-
|
|
90429
|
-
|
|
90430
|
-
|
|
90710
|
+
try {
|
|
90711
|
+
const existingStyles = doc2.querySelectorAll(
|
|
90712
|
+
"style[data-merge-field-pills]"
|
|
90713
|
+
);
|
|
90714
|
+
existingStyles.forEach((style22) => style22.remove());
|
|
90715
|
+
const style2 = doc2.createElement("style");
|
|
90716
|
+
style2.textContent = "html, body { height: auto !important; min-height: 0 !important; }";
|
|
90717
|
+
doc2.head.appendChild(style2);
|
|
90718
|
+
const pillStyle = doc2.createElement("style");
|
|
90719
|
+
pillStyle.setAttribute("data-merge-field-pills", "true");
|
|
90720
|
+
pillStyle.textContent = `
|
|
90721
|
+
.merge-field-pill {
|
|
90722
|
+
display: inline-block !important;
|
|
90723
|
+
padding: 4px 8px !important;
|
|
90724
|
+
border-radius: 6px !important;
|
|
90725
|
+
background: #f3f4f6 !important;
|
|
90726
|
+
color: #6b7280 !important;
|
|
90727
|
+
font-size: 0.875rem !important;
|
|
90728
|
+
border: 1px solid #e5e7eb !important;
|
|
90729
|
+
font-weight: 500 !important;
|
|
90730
|
+
margin: 0 2px !important;
|
|
90731
|
+
vertical-align: middle !important;
|
|
90732
|
+
line-height: 1.2 !important;
|
|
90733
|
+
white-space: nowrap !important;
|
|
90734
|
+
box-sizing: border-box !important;
|
|
90735
|
+
}
|
|
90736
|
+
|
|
90737
|
+
/* Ensure pills are visible even with conflicting styles */
|
|
90738
|
+
span.merge-field-pill {
|
|
90739
|
+
display: inline-block !important;
|
|
90740
|
+
background: #f3f4f6 !important;
|
|
90741
|
+
color: #6b7280 !important;
|
|
90742
|
+
border: 1px solid #e5e7eb !important;
|
|
90743
|
+
}
|
|
90744
|
+
|
|
90745
|
+
/* Force override any inherited styles */
|
|
90746
|
+
* .merge-field-pill {
|
|
90747
|
+
display: inline-block !important;
|
|
90748
|
+
background: #f3f4f6 !important;
|
|
90749
|
+
color: #6b7280 !important;
|
|
90750
|
+
border: 1px solid #e5e7eb !important;
|
|
90751
|
+
padding: 4px 8px !important;
|
|
90752
|
+
border-radius: 6px !important;
|
|
90753
|
+
}
|
|
90754
|
+
`;
|
|
90755
|
+
doc2.head.appendChild(pillStyle);
|
|
90756
|
+
} catch (styleError) {
|
|
90757
|
+
}
|
|
90431
90758
|
};
|
|
90432
90759
|
if (doc2.readyState === "complete" || doc2.readyState === "interactive") {
|
|
90433
90760
|
injectStyles2();
|
|
@@ -90435,14 +90762,57 @@ const EmailPreviewHtmlRenderer = ({
|
|
|
90435
90762
|
doc2.addEventListener("DOMContentLoaded", injectStyles2);
|
|
90436
90763
|
doc2.addEventListener("load", injectStyles2);
|
|
90437
90764
|
}
|
|
90438
|
-
|
|
90439
|
-
|
|
90440
|
-
|
|
90765
|
+
try {
|
|
90766
|
+
const script = doc2.createElement("script");
|
|
90767
|
+
script.textContent = createHeightMonitor();
|
|
90768
|
+
doc2.body.appendChild(script);
|
|
90769
|
+
setTimeout(() => {
|
|
90770
|
+
if (state.type === "calculating") {
|
|
90771
|
+
try {
|
|
90772
|
+
const iframeDoc = iframe.contentDocument || iframe.contentWindow?.document;
|
|
90773
|
+
if (iframeDoc) {
|
|
90774
|
+
const bodyHeight = iframeDoc.body?.scrollHeight || iframeDoc.body?.offsetHeight;
|
|
90775
|
+
if (bodyHeight && bodyHeight > 0) {
|
|
90776
|
+
handleHeightUpdate(bodyHeight + 10);
|
|
90777
|
+
} else {
|
|
90778
|
+
setState({
|
|
90779
|
+
type: "error",
|
|
90780
|
+
fallbackHeight: estimatedHeight
|
|
90781
|
+
});
|
|
90782
|
+
handleHeightUpdate(estimatedHeight);
|
|
90783
|
+
}
|
|
90784
|
+
}
|
|
90785
|
+
} catch (directError) {
|
|
90786
|
+
setState({ type: "error", fallbackHeight: estimatedHeight });
|
|
90787
|
+
handleHeightUpdate(estimatedHeight);
|
|
90788
|
+
}
|
|
90789
|
+
}
|
|
90790
|
+
}, 2e3);
|
|
90791
|
+
} catch (scriptError) {
|
|
90792
|
+
setTimeout(() => {
|
|
90793
|
+
try {
|
|
90794
|
+
const iframeDoc = iframe.contentDocument || iframe.contentWindow?.document;
|
|
90795
|
+
if (iframeDoc) {
|
|
90796
|
+
const bodyHeight = iframeDoc.body?.scrollHeight || iframeDoc.body?.offsetHeight;
|
|
90797
|
+
if (bodyHeight && bodyHeight > 0) {
|
|
90798
|
+
handleHeightUpdate(bodyHeight + 10);
|
|
90799
|
+
} else {
|
|
90800
|
+
setState({ type: "error", fallbackHeight: estimatedHeight });
|
|
90801
|
+
handleHeightUpdate(estimatedHeight);
|
|
90802
|
+
}
|
|
90803
|
+
} else {
|
|
90804
|
+
setState({ type: "error", fallbackHeight: estimatedHeight });
|
|
90805
|
+
handleHeightUpdate(estimatedHeight);
|
|
90806
|
+
}
|
|
90807
|
+
} catch (error2) {
|
|
90808
|
+
setState({ type: "error", fallbackHeight: estimatedHeight });
|
|
90809
|
+
handleHeightUpdate(estimatedHeight);
|
|
90810
|
+
}
|
|
90811
|
+
}, 1e3);
|
|
90812
|
+
}
|
|
90441
90813
|
} catch (error2) {
|
|
90442
|
-
setState({
|
|
90443
|
-
|
|
90444
|
-
fallbackHeight: DEFAULT_EMAIL_PREVIEW_HEIGHT
|
|
90445
|
-
});
|
|
90814
|
+
setState({ type: "error", fallbackHeight: estimatedHeight });
|
|
90815
|
+
handleHeightUpdate(estimatedHeight);
|
|
90446
90816
|
}
|
|
90447
90817
|
};
|
|
90448
90818
|
const handleHeightMessage = (event) => {
|
|
@@ -90457,20 +90827,49 @@ const EmailPreviewHtmlRenderer = ({
|
|
|
90457
90827
|
}
|
|
90458
90828
|
};
|
|
90459
90829
|
const handleError = () => {
|
|
90460
|
-
setState({ type: "error", fallbackHeight:
|
|
90830
|
+
setState({ type: "error", fallbackHeight: estimatedHeight });
|
|
90831
|
+
handleHeightUpdate(estimatedHeight);
|
|
90832
|
+
};
|
|
90833
|
+
const handleLoad = () => {
|
|
90834
|
+
setupHeightMonitoring();
|
|
90461
90835
|
};
|
|
90462
|
-
iframe.addEventListener("load",
|
|
90836
|
+
iframe.addEventListener("load", handleLoad);
|
|
90463
90837
|
iframe.addEventListener("error", handleError);
|
|
90464
90838
|
window.addEventListener("message", handleHeightMessage);
|
|
90839
|
+
setTimeout(() => {
|
|
90840
|
+
if (state.type === "calculating") {
|
|
90841
|
+
try {
|
|
90842
|
+
const iframeDoc = iframe.contentDocument || iframe.contentWindow?.document;
|
|
90843
|
+
if (iframeDoc && iframeDoc.readyState === "complete") {
|
|
90844
|
+
setupHeightMonitoring();
|
|
90845
|
+
} else {
|
|
90846
|
+
setState({ type: "error", fallbackHeight: estimatedHeight });
|
|
90847
|
+
handleHeightUpdate(estimatedHeight);
|
|
90848
|
+
}
|
|
90849
|
+
} catch (error2) {
|
|
90850
|
+
setState({ type: "error", fallbackHeight: estimatedHeight });
|
|
90851
|
+
handleHeightUpdate(estimatedHeight);
|
|
90852
|
+
}
|
|
90853
|
+
}
|
|
90854
|
+
}, 1e3);
|
|
90465
90855
|
return () => {
|
|
90466
|
-
iframe.removeEventListener("load",
|
|
90856
|
+
iframe.removeEventListener("load", handleLoad);
|
|
90467
90857
|
iframe.removeEventListener("error", handleError);
|
|
90468
90858
|
window.removeEventListener("message", handleHeightMessage);
|
|
90469
90859
|
if (timeoutRef.current) {
|
|
90470
90860
|
clearTimeout(timeoutRef.current);
|
|
90471
90861
|
}
|
|
90862
|
+
clearTimeout(aggressiveTimeout);
|
|
90472
90863
|
};
|
|
90473
|
-
}, [
|
|
90864
|
+
}, [
|
|
90865
|
+
prettyHtml,
|
|
90866
|
+
handleHeightUpdate,
|
|
90867
|
+
handleFallback,
|
|
90868
|
+
forceStateChange,
|
|
90869
|
+
estimateHeightFromContent,
|
|
90870
|
+
state.type,
|
|
90871
|
+
iframeElement
|
|
90872
|
+
]);
|
|
90474
90873
|
if (isGettingMergeFields && getMergeFields2 === void 0) {
|
|
90475
90874
|
return /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center py-5", children: /* @__PURE__ */ jsx(BasicLoader, { text: "Fetching merge fields..." }) });
|
|
90476
90875
|
}
|
|
@@ -90483,7 +90882,7 @@ const EmailPreviewHtmlRenderer = ({
|
|
|
90483
90882
|
/* @__PURE__ */ jsx(
|
|
90484
90883
|
"iframe",
|
|
90485
90884
|
{
|
|
90486
|
-
ref:
|
|
90885
|
+
ref: setIframeRef,
|
|
90487
90886
|
title: "Email Preview",
|
|
90488
90887
|
srcDoc: prettyHtml,
|
|
90489
90888
|
className: "w-full block",
|
|
@@ -90551,32 +90950,32 @@ const EmailPreviewHtmlRenderer = ({
|
|
|
90551
90950
|
) })
|
|
90552
90951
|
] });
|
|
90553
90952
|
};
|
|
90554
|
-
const HELP_TOPICS = [
|
|
90555
|
-
{
|
|
90556
|
-
id: "dynamic-content",
|
|
90557
|
-
title: "Dynamic Content",
|
|
90558
|
-
image: "https://cdn.embedreach.com/assets/engage/merge-tags-demo.gif",
|
|
90559
|
-
imageAlt: "Merge Tags Demo",
|
|
90560
|
-
imageDesc: "Demonstration: Adding merge tags to personalize your emails",
|
|
90561
|
-
selectorTitle: "Dynamic Content",
|
|
90562
|
-
selectorSubtitle: "Dynamic content is a way to insert dynamic content into your email like name, email, or other details.",
|
|
90563
|
-
selectorIcon: /* @__PURE__ */ jsx(Merge, {})
|
|
90564
|
-
},
|
|
90565
|
-
{
|
|
90566
|
-
id: "responsive-design",
|
|
90567
|
-
title: "Responsive Design",
|
|
90568
|
-
image: "https://cdn.embedreach.com/assets/engage/layout-mobile-desktop.gif",
|
|
90569
|
-
imageAlt: "Mobile Desktop Switch Demo",
|
|
90570
|
-
imageDesc: "Demonstration: Switching between mobile and desktop preview modes",
|
|
90571
|
-
selectorTitle: "Responsive Design",
|
|
90572
|
-
selectorSubtitle: "Switch between mobile and desktop preview modes to ensure your emails look great on all devices.",
|
|
90573
|
-
selectorIcon: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
|
|
90574
|
-
/* @__PURE__ */ jsx(Smartphone, { className: "w-4 h-4" }),
|
|
90575
|
-
/* @__PURE__ */ jsx(Monitor, { className: "w-4 h-4" })
|
|
90576
|
-
] })
|
|
90577
|
-
}
|
|
90578
|
-
];
|
|
90579
90953
|
const EmailPreviewHelpDialog = () => {
|
|
90954
|
+
const HELP_TOPICS = [
|
|
90955
|
+
{
|
|
90956
|
+
id: "dynamic-content",
|
|
90957
|
+
title: "Dynamic Content",
|
|
90958
|
+
image: "https://cdn.embedreach.com/assets/engage/merge-tags-demo.gif",
|
|
90959
|
+
imageAlt: `${t$2("engage:merge_field")} Demo`,
|
|
90960
|
+
imageDesc: `Demonstration: Adding ${t$2("engage:merge_field").toLowerCase()} to personalize your emails`,
|
|
90961
|
+
selectorTitle: "Dynamic Content",
|
|
90962
|
+
selectorSubtitle: "Dynamic content is a way to insert dynamic content into your email like name, email, or other details.",
|
|
90963
|
+
selectorIcon: /* @__PURE__ */ jsx(Merge, {})
|
|
90964
|
+
},
|
|
90965
|
+
{
|
|
90966
|
+
id: "responsive-design",
|
|
90967
|
+
title: "Responsive Design",
|
|
90968
|
+
image: "https://cdn.embedreach.com/assets/engage/layout-mobile-desktop.gif",
|
|
90969
|
+
imageAlt: "Mobile Desktop Switch Demo",
|
|
90970
|
+
imageDesc: "Demonstration: Switching between mobile and desktop preview modes",
|
|
90971
|
+
selectorTitle: "Responsive Design",
|
|
90972
|
+
selectorSubtitle: "Switch between mobile and desktop preview modes to ensure your emails look great on all devices.",
|
|
90973
|
+
selectorIcon: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
|
|
90974
|
+
/* @__PURE__ */ jsx(Smartphone, { className: "w-4 h-4" }),
|
|
90975
|
+
/* @__PURE__ */ jsx(Monitor, { className: "w-4 h-4" })
|
|
90976
|
+
] })
|
|
90977
|
+
}
|
|
90978
|
+
];
|
|
90580
90979
|
const { toggleEmailHelpDialog: toggleEmailHelpDialog2, data: business } = useBusiness$1();
|
|
90581
90980
|
const { toast: toast2 } = useToast();
|
|
90582
90981
|
const [selectedTopic, setSelectedTopic] = useState("dynamic-content");
|
|
@@ -90587,7 +90986,7 @@ const EmailPreviewHelpDialog = () => {
|
|
|
90587
90986
|
});
|
|
90588
90987
|
};
|
|
90589
90988
|
const shouldShowDontShowAgainButton = business?.uiDefaults?.emailHelpDialogShow !== false;
|
|
90590
|
-
const topic = HELP_TOPICS.find((
|
|
90989
|
+
const topic = HELP_TOPICS.find((t22) => t22.id === selectedTopic) ?? HELP_TOPICS[0];
|
|
90591
90990
|
return /* @__PURE__ */ jsxs("div", { className: "p-6 overflow-y-auto", children: [
|
|
90592
90991
|
/* @__PURE__ */ jsxs("div", { className: "mb-8 text-center", children: [
|
|
90593
90992
|
/* @__PURE__ */ jsx("h2", { className: "text-2xl font-semibold mb-2", children: "Email Editor Help Center" }),
|
|
@@ -90618,16 +91017,16 @@ const EmailPreviewHelpDialog = () => {
|
|
|
90618
91017
|
},
|
|
90619
91018
|
topic.id
|
|
90620
91019
|
) }) }),
|
|
90621
|
-
/* @__PURE__ */ jsx("div", { className: "flex flex-col gap-4 sm:flex-row sm:gap-6 max-w-xl mx-auto", children: HELP_TOPICS.map((
|
|
91020
|
+
/* @__PURE__ */ jsx("div", { className: "flex flex-col gap-4 sm:flex-row sm:gap-6 max-w-xl mx-auto", children: HELP_TOPICS.map((t22) => /* @__PURE__ */ jsx("div", { className: "flex-1", children: /* @__PURE__ */ jsx(
|
|
90622
91021
|
BigSelector,
|
|
90623
91022
|
{
|
|
90624
|
-
onClick: () => setSelectedTopic(
|
|
90625
|
-
title:
|
|
90626
|
-
subtitle:
|
|
90627
|
-
icon:
|
|
90628
|
-
selected: selectedTopic ===
|
|
91023
|
+
onClick: () => setSelectedTopic(t22.id),
|
|
91024
|
+
title: t22.selectorTitle,
|
|
91025
|
+
subtitle: t22.selectorSubtitle,
|
|
91026
|
+
icon: t22.selectorIcon,
|
|
91027
|
+
selected: selectedTopic === t22.id
|
|
90629
91028
|
}
|
|
90630
|
-
) },
|
|
91029
|
+
) }, t22.id)) }),
|
|
90631
91030
|
shouldShowDontShowAgainButton && /* @__PURE__ */ jsx("div", { className: "flex justify-center pt-4", children: /* @__PURE__ */ jsx(Button$1, { size: "sm", onClick: handleDontShowAgain, children: "Don't show me again" }) })
|
|
90632
91031
|
] });
|
|
90633
91032
|
};
|
|
@@ -90790,6 +91189,17 @@ const StripoEditor = ({ containerRef, stripoDialogDimensions, showSaving }) => {
|
|
|
90790
91189
|
}
|
|
90791
91190
|
});
|
|
90792
91191
|
});
|
|
91192
|
+
const mergeTagsElements = shadowRoot.querySelectorAll(
|
|
91193
|
+
"span.service-element.caption.ng-star-inserted"
|
|
91194
|
+
);
|
|
91195
|
+
mergeTagsElements.forEach((element) => {
|
|
91196
|
+
const htmlElement = element;
|
|
91197
|
+
if (htmlElement.textContent?.trim() === "Merge Tags") {
|
|
91198
|
+
htmlElement.textContent = t$2("engage:merge_field", {
|
|
91199
|
+
count: 2
|
|
91200
|
+
});
|
|
91201
|
+
}
|
|
91202
|
+
});
|
|
90793
91203
|
};
|
|
90794
91204
|
let shadowObserver = null;
|
|
90795
91205
|
const setupShadowObserver = () => {
|
|
@@ -90937,115 +91347,174 @@ const StripoWrapper = ({
|
|
|
90937
91347
|
mergeFieldsResponse,
|
|
90938
91348
|
cancelClicked,
|
|
90939
91349
|
setCancelClicked,
|
|
90940
|
-
actionId
|
|
91350
|
+
actionId,
|
|
91351
|
+
onEditorReadyChange
|
|
90941
91352
|
}) => {
|
|
91353
|
+
const [stripoEmailSaved, setStripoEmailSaved] = useState(false);
|
|
91354
|
+
const [stripoEmailCompiled, setStripoEmailCompiled] = useState(false);
|
|
91355
|
+
const [isEditorReady, setIsEditorReady] = useState(false);
|
|
90942
91356
|
const stripoOpenedOnce = useRef(false);
|
|
90943
91357
|
const containerRef = useRef(null);
|
|
90944
|
-
const
|
|
91358
|
+
const editorReadyCheckInterval = useRef(null);
|
|
91359
|
+
const {
|
|
91360
|
+
data: template,
|
|
91361
|
+
isLoading: isTemplateLoading,
|
|
91362
|
+
error: templateError
|
|
91363
|
+
} = useStripoTemplateForActionId({
|
|
90945
91364
|
automationId: automation2.id,
|
|
90946
91365
|
actionId
|
|
90947
91366
|
});
|
|
90948
|
-
const {
|
|
90949
|
-
|
|
90950
|
-
|
|
91367
|
+
const {
|
|
91368
|
+
data: editorData,
|
|
91369
|
+
isLoading: isEditorDataLoading,
|
|
91370
|
+
error: editorDataError
|
|
91371
|
+
} = useStripoEditorData();
|
|
90951
91372
|
const { updateCommunicationGroup: updateCommunicationGroup2 } = useUpdateCommunicationGroup();
|
|
91373
|
+
const checkEditorReady = useCallback(() => {
|
|
91374
|
+
const isReady = !!(window.StripoEditorApi?.actionsApi && typeof window.StripoEditorApi.actionsApi.save === "function" && typeof window.StripoEditorApi.actionsApi.compileEmail === "function");
|
|
91375
|
+
if (isReady && !isEditorReady) {
|
|
91376
|
+
setIsEditorReady(true);
|
|
91377
|
+
onEditorReadyChange?.(true);
|
|
91378
|
+
if (editorReadyCheckInterval.current) {
|
|
91379
|
+
clearInterval(editorReadyCheckInterval.current);
|
|
91380
|
+
editorReadyCheckInterval.current = null;
|
|
91381
|
+
}
|
|
91382
|
+
}
|
|
91383
|
+
return isReady;
|
|
91384
|
+
}, [isEditorReady, onEditorReadyChange]);
|
|
90952
91385
|
const resetAndCloseEditor = useCallback(() => {
|
|
90953
91386
|
setSaveClicked(false);
|
|
90954
91387
|
setCancelClicked(false);
|
|
90955
91388
|
setStripoEmailSaved(false);
|
|
90956
91389
|
setStripoEmailCompiled(false);
|
|
91390
|
+
setIsEditorReady(false);
|
|
91391
|
+
onEditorReadyChange?.(false);
|
|
90957
91392
|
setShowStripoEditor(false);
|
|
91393
|
+
if (editorReadyCheckInterval.current) {
|
|
91394
|
+
clearInterval(editorReadyCheckInterval.current);
|
|
91395
|
+
editorReadyCheckInterval.current = null;
|
|
91396
|
+
}
|
|
90958
91397
|
}, [
|
|
90959
91398
|
setSaveClicked,
|
|
90960
91399
|
setCancelClicked,
|
|
90961
91400
|
setStripoEmailSaved,
|
|
90962
91401
|
setStripoEmailCompiled,
|
|
91402
|
+
setIsEditorReady,
|
|
91403
|
+
onEditorReadyChange,
|
|
90963
91404
|
setShowStripoEditor
|
|
90964
91405
|
]);
|
|
90965
|
-
|
|
90966
|
-
if (
|
|
90967
|
-
|
|
90968
|
-
|
|
90969
|
-
|
|
90970
|
-
|
|
90971
|
-
|
|
90972
|
-
|
|
90973
|
-
|
|
90974
|
-
|
|
90975
|
-
|
|
91406
|
+
const executeSave = useCallback(async () => {
|
|
91407
|
+
if (!isEditorReady) {
|
|
91408
|
+
console.warn("Save operation blocked - editor not ready yet");
|
|
91409
|
+
return;
|
|
91410
|
+
}
|
|
91411
|
+
if (!window.StripoEditorApi?.actionsApi || !template?.communicationGroupId) {
|
|
91412
|
+
console.warn("Save operation blocked - preconditions not met");
|
|
91413
|
+
return;
|
|
91414
|
+
}
|
|
91415
|
+
try {
|
|
91416
|
+
const saveOperation = () => new Promise((resolve, reject) => {
|
|
91417
|
+
const compileEmailCallback = async function(error2, html) {
|
|
91418
|
+
if (error2) {
|
|
91419
|
+
reject(new Error(`Compile failed: ${error2}`));
|
|
91420
|
+
return;
|
|
91421
|
+
}
|
|
91422
|
+
try {
|
|
91423
|
+
await updateCommunicationGroup2({
|
|
91424
|
+
groupId: template.communicationGroupId,
|
|
91425
|
+
params: { emailHtmlBody: html }
|
|
91426
|
+
});
|
|
91427
|
+
} catch (err) {
|
|
91428
|
+
reject(err);
|
|
90976
91429
|
}
|
|
91430
|
+
setStripoEmailCompiled(true);
|
|
91431
|
+
resolve();
|
|
91432
|
+
};
|
|
91433
|
+
const saveCallback = function(error2) {
|
|
91434
|
+
if (error2) {
|
|
91435
|
+
reject(new Error(`Save failed: ${error2}`));
|
|
91436
|
+
return;
|
|
91437
|
+
}
|
|
91438
|
+
setStripoEmailSaved(true);
|
|
91439
|
+
};
|
|
91440
|
+
window.StripoEditorApi.actionsApi.compileEmail({
|
|
91441
|
+
callback: compileEmailCallback,
|
|
91442
|
+
minimize: true,
|
|
91443
|
+
mergeTags: [],
|
|
91444
|
+
forceAmp: false,
|
|
91445
|
+
resetDataSavedFlag: false,
|
|
91446
|
+
disableLineHeightsReplace: true
|
|
90977
91447
|
});
|
|
90978
|
-
|
|
90979
|
-
};
|
|
90980
|
-
window.StripoEditorApi.actionsApi.compileEmail({
|
|
90981
|
-
callback: compileEmailCallback,
|
|
90982
|
-
minimize: true,
|
|
90983
|
-
mergeTags: [],
|
|
90984
|
-
forceAmp: false,
|
|
90985
|
-
resetDataSavedFlag: false,
|
|
90986
|
-
disableLineHeightsReplace: true
|
|
91448
|
+
window.StripoEditorApi.actionsApi.save(saveCallback);
|
|
90987
91449
|
});
|
|
90988
|
-
|
|
90989
|
-
|
|
90990
|
-
|
|
90991
|
-
return;
|
|
90992
|
-
}
|
|
90993
|
-
setStripoEmailSaved(true);
|
|
90994
|
-
};
|
|
90995
|
-
window.StripoEditorApi.actionsApi.save(saveCallback);
|
|
91450
|
+
await saveOperation();
|
|
91451
|
+
} catch (error2) {
|
|
91452
|
+
console.error("Save operation failed:", error2);
|
|
90996
91453
|
}
|
|
90997
|
-
}, [
|
|
90998
|
-
saveClicked,
|
|
90999
|
-
containerRef,
|
|
91000
|
-
setSaveClicked,
|
|
91001
|
-
setShowStripoEditor,
|
|
91002
|
-
template,
|
|
91003
|
-
updateCommunicationGroup2
|
|
91004
|
-
]);
|
|
91454
|
+
}, [template, updateCommunicationGroup2, isEditorReady]);
|
|
91005
91455
|
useEffect(() => {
|
|
91006
|
-
|
|
91007
|
-
|
|
91008
|
-
|
|
91009
|
-
|
|
91010
|
-
|
|
91011
|
-
|
|
91012
|
-
|
|
91013
|
-
|
|
91014
|
-
|
|
91456
|
+
if (saveClicked && isEditorReady) {
|
|
91457
|
+
executeSave();
|
|
91458
|
+
} else if (saveClicked && !isEditorReady) {
|
|
91459
|
+
console.warn("Save clicked but editor not ready - ignoring save request");
|
|
91460
|
+
setSaveClicked(false);
|
|
91461
|
+
}
|
|
91462
|
+
}, [saveClicked, executeSave, isEditorReady, setSaveClicked]);
|
|
91463
|
+
useEffect(() => {
|
|
91464
|
+
if (stripoEmailSaved && stripoEmailCompiled || showStripoEditor === false) {
|
|
91465
|
+
resetAndCloseEditor();
|
|
91466
|
+
}
|
|
91015
91467
|
}, [
|
|
91016
91468
|
stripoEmailSaved,
|
|
91017
91469
|
stripoEmailCompiled,
|
|
91018
91470
|
showStripoEditor,
|
|
91019
|
-
setShowStripoEditor,
|
|
91020
|
-
setSaveClicked,
|
|
91021
91471
|
resetAndCloseEditor
|
|
91022
91472
|
]);
|
|
91023
91473
|
useEffect(() => {
|
|
91024
91474
|
if (cancelClicked) {
|
|
91025
|
-
if (window.UIEditor && window.UIEditor.removeEditor && typeof window.UIEditor.removeEditor === "function") {
|
|
91026
|
-
window.UIEditor.removeEditor();
|
|
91027
|
-
}
|
|
91028
91475
|
resetAndCloseEditor();
|
|
91029
91476
|
}
|
|
91030
91477
|
}, [cancelClicked, resetAndCloseEditor]);
|
|
91031
91478
|
useEffect(() => {
|
|
91032
|
-
if (editorData?.businessId && containerRef.current && template) {
|
|
91033
|
-
|
|
91034
|
-
|
|
91035
|
-
|
|
91036
|
-
|
|
91037
|
-
|
|
91038
|
-
|
|
91039
|
-
|
|
91040
|
-
|
|
91041
|
-
|
|
91042
|
-
|
|
91043
|
-
|
|
91044
|
-
|
|
91045
|
-
|
|
91046
|
-
|
|
91479
|
+
if (editorData?.businessId && containerRef.current && template && !stripoOpenedOnce.current) {
|
|
91480
|
+
const initializeEditor = async () => {
|
|
91481
|
+
try {
|
|
91482
|
+
await initStripo({
|
|
91483
|
+
emailId: template.communicationGroupId,
|
|
91484
|
+
html: template.html || "<div></div>",
|
|
91485
|
+
css: template.css || "",
|
|
91486
|
+
container: containerRef.current,
|
|
91487
|
+
businessId: editorData.businessId,
|
|
91488
|
+
mergeFields: mergeFieldsResponse.mergeFields || [],
|
|
91489
|
+
forceRecreate: template.forceRecreate
|
|
91490
|
+
});
|
|
91491
|
+
stripoOpenedOnce.current = true;
|
|
91492
|
+
console.log(
|
|
91493
|
+
"Stripo initStripo completed, starting readiness check..."
|
|
91494
|
+
);
|
|
91495
|
+
editorReadyCheckInterval.current = setInterval(() => {
|
|
91496
|
+
checkEditorReady();
|
|
91497
|
+
}, 500);
|
|
91498
|
+
} catch (error2) {
|
|
91499
|
+
console.error("Failed to initialize Stripo editor:", error2);
|
|
91500
|
+
}
|
|
91501
|
+
};
|
|
91502
|
+
initializeEditor();
|
|
91047
91503
|
}
|
|
91048
|
-
}, [editorData, mergeFieldsResponse, template]);
|
|
91504
|
+
}, [editorData, mergeFieldsResponse, template, checkEditorReady]);
|
|
91505
|
+
useEffect(() => {
|
|
91506
|
+
return () => {
|
|
91507
|
+
if (editorReadyCheckInterval.current) {
|
|
91508
|
+
clearInterval(editorReadyCheckInterval.current);
|
|
91509
|
+
}
|
|
91510
|
+
};
|
|
91511
|
+
}, []);
|
|
91512
|
+
if (templateError || editorDataError) {
|
|
91513
|
+
return /* @__PURE__ */ jsxs("div", { className: "w-full h-full flex flex-col items-center justify-center", children: [
|
|
91514
|
+
/* @__PURE__ */ jsx("div", { className: "text-red-500 mb-4", children: "Failed to load editor data" }),
|
|
91515
|
+
/* @__PURE__ */ jsx(Button$1, { onClick: () => window.location.reload(), variant: "outline", children: "Retry" })
|
|
91516
|
+
] });
|
|
91517
|
+
}
|
|
91049
91518
|
if (isTemplateLoading || isEditorDataLoading || !editorData || !template) {
|
|
91050
91519
|
return /* @__PURE__ */ jsx("div", { className: "w-full h-full flex flex-col items-center justify-center", children: /* @__PURE__ */ jsx(BasicLoader, { text: ["Loading editor..."] }) });
|
|
91051
91520
|
}
|
|
@@ -91054,7 +91523,7 @@ const StripoWrapper = ({
|
|
|
91054
91523
|
{
|
|
91055
91524
|
containerRef,
|
|
91056
91525
|
stripoDialogDimensions,
|
|
91057
|
-
showSaving: saveClicked
|
|
91526
|
+
showSaving: saveClicked && isEditorReady
|
|
91058
91527
|
}
|
|
91059
91528
|
) });
|
|
91060
91529
|
};
|
|
@@ -91095,11 +91564,12 @@ const EmailPreview = ({
|
|
|
91095
91564
|
communicationGroup?.emailPreviewText || null
|
|
91096
91565
|
);
|
|
91097
91566
|
const [body, setBody] = useState(
|
|
91098
|
-
communicationGroup?.
|
|
91567
|
+
communicationGroup?.emailHtmlBody || null
|
|
91099
91568
|
);
|
|
91100
91569
|
const [showStripoEditor, setShowStripoEditor] = useState(false);
|
|
91101
91570
|
const [saveClicked, setSaveClicked] = useState(false);
|
|
91102
91571
|
const [cancelClicked, setCancelClicked] = useState(false);
|
|
91572
|
+
const [isEditorReady, setIsEditorReady] = useState(false);
|
|
91103
91573
|
const [fromName, setFromName] = useState("");
|
|
91104
91574
|
const [replyToEmail, setReplyToEmail] = useState("");
|
|
91105
91575
|
const [showHelpDialog, setShowHelpDialog] = useState(null);
|
|
@@ -91202,7 +91672,6 @@ const EmailPreview = ({
|
|
|
91202
91672
|
groupId: communicationGroup.id,
|
|
91203
91673
|
params: {
|
|
91204
91674
|
emailChannelSenderId: fromEmail,
|
|
91205
|
-
emailHtmlBody: body,
|
|
91206
91675
|
emailSubject: debouncedSubject,
|
|
91207
91676
|
...debouncedPreviewText && {
|
|
91208
91677
|
emailPreviewText: debouncedPreviewText
|
|
@@ -91319,6 +91788,7 @@ const EmailPreview = ({
|
|
|
91319
91788
|
{
|
|
91320
91789
|
onClick: () => setSaveClicked(true),
|
|
91321
91790
|
className: "text-sm px-3 py-1 rounded",
|
|
91791
|
+
disabled: !isEditorReady,
|
|
91322
91792
|
children: "Save"
|
|
91323
91793
|
}
|
|
91324
91794
|
)
|
|
@@ -91336,7 +91806,8 @@ const EmailPreview = ({
|
|
|
91336
91806
|
setSaveClicked,
|
|
91337
91807
|
stripoDialogDimensions,
|
|
91338
91808
|
mergeFieldsResponse,
|
|
91339
|
-
actionId: selectedActionId
|
|
91809
|
+
actionId: selectedActionId,
|
|
91810
|
+
onEditorReadyChange: setIsEditorReady
|
|
91340
91811
|
}
|
|
91341
91812
|
)
|
|
91342
91813
|
] })
|
|
@@ -94246,6 +94717,7 @@ var ENGAGE_STEPS = /* @__PURE__ */ ((ENGAGE_STEPS2) => {
|
|
|
94246
94717
|
ENGAGE_STEPS2["BUSINESS"] = "business";
|
|
94247
94718
|
ENGAGE_STEPS2["EMAIL"] = "email";
|
|
94248
94719
|
ENGAGE_STEPS2["SMS"] = "sms";
|
|
94720
|
+
ENGAGE_STEPS2["MERGE_FIELDS"] = "merge-fields";
|
|
94249
94721
|
ENGAGE_STEPS2["SPLASH"] = "splash";
|
|
94250
94722
|
ENGAGE_STEPS2["BUSINESS_SKIP_INTERSTITIAL"] = "business-skip-interstitial";
|
|
94251
94723
|
ENGAGE_STEPS2["SMS_INTERSTITIAL"] = "sms-interstitial";
|
|
@@ -94263,6 +94735,7 @@ const ENGAGE_STRINGS = {
|
|
|
94263
94735
|
BUSINESS_INFORMATION_TITLE: "Business Information",
|
|
94264
94736
|
EMAIL_CHANNEL_TITLE: "Email Channel",
|
|
94265
94737
|
SMS_CHANNEL_TITLE: "SMS Channel",
|
|
94738
|
+
MERGE_FIELDS_TITLE: "Merge Fields",
|
|
94266
94739
|
// Step titles - Onboarding mode
|
|
94267
94740
|
BRAND_ONBOARDING_TITLE: "Customize Your Brand",
|
|
94268
94741
|
BUSINESS_ONBOARDING_TITLE: "Business Settings",
|
|
@@ -94301,7 +94774,11 @@ const SHARED_STEP_CONFIGS = {
|
|
|
94301
94774
|
[
|
|
94302
94775
|
"sms"
|
|
94303
94776
|
/* SMS */
|
|
94304
|
-
]: { label: ENGAGE_STRINGS.SMS_CHANNEL_TITLE }
|
|
94777
|
+
]: { label: ENGAGE_STRINGS.SMS_CHANNEL_TITLE },
|
|
94778
|
+
[
|
|
94779
|
+
"merge-fields"
|
|
94780
|
+
/* MERGE_FIELDS */
|
|
94781
|
+
]: { label: ENGAGE_STRINGS.MERGE_FIELDS_TITLE }
|
|
94305
94782
|
};
|
|
94306
94783
|
const SETTINGS_STEP_CONFIGS = [
|
|
94307
94784
|
{
|
|
@@ -94331,6 +94808,13 @@ const SETTINGS_STEP_CONFIGS = [
|
|
|
94331
94808
|
"sms"
|
|
94332
94809
|
/* SMS */
|
|
94333
94810
|
].label
|
|
94811
|
+
},
|
|
94812
|
+
{
|
|
94813
|
+
key: "merge-fields",
|
|
94814
|
+
label: SHARED_STEP_CONFIGS[
|
|
94815
|
+
"merge-fields"
|
|
94816
|
+
/* MERGE_FIELDS */
|
|
94817
|
+
].label
|
|
94334
94818
|
}
|
|
94335
94819
|
];
|
|
94336
94820
|
const ONBOARDING_STEP_CONFIGS = [
|
|
@@ -94362,6 +94846,13 @@ const ONBOARDING_STEP_CONFIGS = [
|
|
|
94362
94846
|
/* SMS */
|
|
94363
94847
|
].label
|
|
94364
94848
|
},
|
|
94849
|
+
{
|
|
94850
|
+
key: "merge-fields",
|
|
94851
|
+
label: SHARED_STEP_CONFIGS[
|
|
94852
|
+
"merge-fields"
|
|
94853
|
+
/* MERGE_FIELDS */
|
|
94854
|
+
].label
|
|
94855
|
+
},
|
|
94365
94856
|
{
|
|
94366
94857
|
key: "completion",
|
|
94367
94858
|
label: ENGAGE_STRINGS.COMPLETION_TITLE
|
|
@@ -94901,6 +95392,20 @@ function extractBase64Data(dataUrl) {
|
|
|
94901
95392
|
}
|
|
94902
95393
|
return parts[1];
|
|
94903
95394
|
}
|
|
95395
|
+
const capitalize = (str) => {
|
|
95396
|
+
if (!str) return str;
|
|
95397
|
+
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
95398
|
+
};
|
|
95399
|
+
const getMergeFieldsFromUrl = (url, getMergeFields2) => {
|
|
95400
|
+
if (!url || !getMergeFields2) return [];
|
|
95401
|
+
const regex = /\{\{([^}]+)\}\}/g;
|
|
95402
|
+
const matches2 = [...url.matchAll(regex)];
|
|
95403
|
+
return matches2.map((match2) => {
|
|
95404
|
+
const mergeFieldValue = match2[1];
|
|
95405
|
+
const mergeField = getMergeFields2.mergeFields?.flatMap((f2) => f2.entries).find((entry) => entry.value === `{{${mergeFieldValue}}}`);
|
|
95406
|
+
return mergeField ? mergeField.label : mergeFieldValue;
|
|
95407
|
+
}).filter(Boolean);
|
|
95408
|
+
};
|
|
94904
95409
|
const convertToHtml = (text2, mergeFields, variant) => {
|
|
94905
95410
|
if (!text2) return "";
|
|
94906
95411
|
const regex = /\{\{.*?\}\}/g;
|
|
@@ -94964,13 +95469,28 @@ const SMSPreview = ({ body, imageUrls }) => {
|
|
|
94964
95469
|
const { getMergeFields: getMergeFields2, isGetting } = useGetMergeFields(
|
|
94965
95470
|
communicationGroup?.id ?? void 0
|
|
94966
95471
|
);
|
|
95472
|
+
const hasMergeFieldsInUrl = React__default.useCallback((url) => {
|
|
95473
|
+
return /\{\{[^}]+\}\}/.test(url);
|
|
95474
|
+
}, []);
|
|
94967
95475
|
if (isGetting || getMergeFields2 === void 0) {
|
|
94968
95476
|
return null;
|
|
94969
95477
|
}
|
|
94970
95478
|
return /* @__PURE__ */ jsx("div", { className: "sms-preview-outer @container", children: /* @__PURE__ */ jsxs("div", { className: "sms-phone-mockup", children: [
|
|
94971
95479
|
/* @__PURE__ */ jsx("div", { className: "sms-phone-notch" }),
|
|
94972
95480
|
/* @__PURE__ */ jsxs("div", { className: "sms-phone-inner", children: [
|
|
94973
|
-
imageUrls && imageUrls.length > 0 && imageUrls.map((url, idx) => /* @__PURE__ */ jsx("div", { className: "sms-message-row", children: /* @__PURE__ */ jsx("div", { className: "sms-message-bubble", children: /* @__PURE__ */ jsx(
|
|
95481
|
+
imageUrls && imageUrls.length > 0 && imageUrls.map((url, idx) => /* @__PURE__ */ jsx("div", { className: "sms-message-row", children: /* @__PURE__ */ jsx("div", { className: "sms-message-bubble", children: hasMergeFieldsInUrl(url) ? /* @__PURE__ */ jsx("div", { className: "sms-message-image-placeholder", children: /* @__PURE__ */ jsxs("div", { className: "text-center text-white text-[10px] leading-tight", children: [
|
|
95482
|
+
/* @__PURE__ */ jsx("div", { className: "font-medium mb-1", children: "Image will be populated at send time based on the following merge fields:" }),
|
|
95483
|
+
/* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-1 justify-center", children: getMergeFieldsFromUrl(url, getMergeFields2).map(
|
|
95484
|
+
(fieldName, fieldIndex) => /* @__PURE__ */ jsx(
|
|
95485
|
+
"span",
|
|
95486
|
+
{
|
|
95487
|
+
className: "inline-flex items-center px-1 py-0.5 rounded text-[10px] bg-green-500/30 text-white font-medium border border-green-400/40",
|
|
95488
|
+
children: fieldName
|
|
95489
|
+
},
|
|
95490
|
+
fieldIndex
|
|
95491
|
+
)
|
|
95492
|
+
) })
|
|
95493
|
+
] }) }) : /* @__PURE__ */ jsx(
|
|
94974
95494
|
"img",
|
|
94975
95495
|
{
|
|
94976
95496
|
src: url,
|
|
@@ -97330,9 +97850,16 @@ const SMSEditor = ({
|
|
|
97330
97850
|
initialImageUrls,
|
|
97331
97851
|
imageBase64,
|
|
97332
97852
|
isUpdating,
|
|
97333
|
-
hasUnsavedChanges
|
|
97853
|
+
hasUnsavedChanges,
|
|
97854
|
+
communicationGroupId
|
|
97334
97855
|
}) => {
|
|
97335
97856
|
const [characterCount, setCharacterCount] = useState(0);
|
|
97857
|
+
const [isAddImagePopoverOpen, setIsAddImagePopoverOpen] = useState(false);
|
|
97858
|
+
const [isUrlDialogOpen, setIsUrlDialogOpen] = useState(false);
|
|
97859
|
+
const [imageUrl, setImageUrl] = useState("");
|
|
97860
|
+
const [isSavingUrl, setIsSavingUrl] = useState(false);
|
|
97861
|
+
const { updateCommunicationGroup: updateCommunicationGroup2 } = useUpdateCommunicationGroup();
|
|
97862
|
+
const { toast: toast2 } = useToast();
|
|
97336
97863
|
const allMergeFields = useMemo(
|
|
97337
97864
|
() => mergeFieldsResponse?.mergeFields?.flatMap((f2) => f2.entries) ?? [],
|
|
97338
97865
|
[mergeFieldsResponse]
|
|
@@ -97407,6 +97934,43 @@ const SMSEditor = ({
|
|
|
97407
97934
|
characterCount,
|
|
97408
97935
|
maxLength
|
|
97409
97936
|
);
|
|
97937
|
+
const handleAddImageFromFile = useCallback(() => {
|
|
97938
|
+
setIsAddImagePopoverOpen(false);
|
|
97939
|
+
onAddImage?.();
|
|
97940
|
+
}, [onAddImage]);
|
|
97941
|
+
const handleAddImageFromUrl = useCallback(() => {
|
|
97942
|
+
setIsAddImagePopoverOpen(false);
|
|
97943
|
+
setIsUrlDialogOpen(true);
|
|
97944
|
+
}, []);
|
|
97945
|
+
const handleUrlSubmit = useCallback(async () => {
|
|
97946
|
+
if (!imageUrl.trim() || !communicationGroupId) {
|
|
97947
|
+
return;
|
|
97948
|
+
}
|
|
97949
|
+
setIsSavingUrl(true);
|
|
97950
|
+
try {
|
|
97951
|
+
await updateCommunicationGroup2({
|
|
97952
|
+
groupId: communicationGroupId,
|
|
97953
|
+
params: {
|
|
97954
|
+
textMessageMediaUrls: [imageUrl.trim()]
|
|
97955
|
+
}
|
|
97956
|
+
});
|
|
97957
|
+
setImageUrl("");
|
|
97958
|
+
setIsUrlDialogOpen(false);
|
|
97959
|
+
toast2({
|
|
97960
|
+
title: "Image URL added",
|
|
97961
|
+
description: "The image URL has been added to your SMS message."
|
|
97962
|
+
});
|
|
97963
|
+
} catch (error2) {
|
|
97964
|
+
console.error("Failed to save image URL:", error2);
|
|
97965
|
+
toast2({
|
|
97966
|
+
title: "Failed to add image URL",
|
|
97967
|
+
description: "Please try again.",
|
|
97968
|
+
variant: "destructive"
|
|
97969
|
+
});
|
|
97970
|
+
} finally {
|
|
97971
|
+
setIsSavingUrl(false);
|
|
97972
|
+
}
|
|
97973
|
+
}, [imageUrl, communicationGroupId, updateCommunicationGroup2, toast2]);
|
|
97410
97974
|
if (!editor) {
|
|
97411
97975
|
return /* @__PURE__ */ jsx("div", { children: "Loading editor..." });
|
|
97412
97976
|
}
|
|
@@ -97422,15 +97986,98 @@ const SMSEditor = ({
|
|
|
97422
97986
|
disabled: isRemovingImage || isUpdatingCommunicationGroup,
|
|
97423
97987
|
children: "Remove Image"
|
|
97424
97988
|
}
|
|
97425
|
-
) : /* @__PURE__ */
|
|
97426
|
-
|
|
97989
|
+
) : /* @__PURE__ */ jsxs(
|
|
97990
|
+
Popover,
|
|
97427
97991
|
{
|
|
97428
|
-
|
|
97429
|
-
|
|
97430
|
-
|
|
97431
|
-
children:
|
|
97992
|
+
modal: true,
|
|
97993
|
+
open: isAddImagePopoverOpen,
|
|
97994
|
+
onOpenChange: setIsAddImagePopoverOpen,
|
|
97995
|
+
children: [
|
|
97996
|
+
/* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(
|
|
97997
|
+
Button$1,
|
|
97998
|
+
{
|
|
97999
|
+
variant: "outline",
|
|
98000
|
+
disabled: (initialImageUrls?.length || 0) >= 1 || isRemovingImage || imageBase64 !== null || isUpdatingCommunicationGroup,
|
|
98001
|
+
className: "flex items-center gap-2",
|
|
98002
|
+
children: [
|
|
98003
|
+
"Add Image",
|
|
98004
|
+
/* @__PURE__ */ jsx(ChevronDown, { className: "h-3 w-3" })
|
|
98005
|
+
]
|
|
98006
|
+
}
|
|
98007
|
+
) }),
|
|
98008
|
+
/* @__PURE__ */ jsx(PopoverContent, { className: "w-56 p-3 z-[100]", align: "start", children: /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
98009
|
+
/* @__PURE__ */ jsxs(
|
|
98010
|
+
Button$1,
|
|
98011
|
+
{
|
|
98012
|
+
variant: "ghost",
|
|
98013
|
+
size: "sm",
|
|
98014
|
+
onClick: handleAddImageFromFile,
|
|
98015
|
+
className: "w-full justify-start gap-2 h-9",
|
|
98016
|
+
children: [
|
|
98017
|
+
/* @__PURE__ */ jsx(Upload, { className: "h-4 w-4" }),
|
|
98018
|
+
"Upload from file"
|
|
98019
|
+
]
|
|
98020
|
+
}
|
|
98021
|
+
),
|
|
98022
|
+
/* @__PURE__ */ jsxs(
|
|
98023
|
+
Button$1,
|
|
98024
|
+
{
|
|
98025
|
+
variant: "ghost",
|
|
98026
|
+
size: "sm",
|
|
98027
|
+
onClick: handleAddImageFromUrl,
|
|
98028
|
+
className: "w-full justify-start gap-2 h-9",
|
|
98029
|
+
children: [
|
|
98030
|
+
/* @__PURE__ */ jsx(Link$1, { className: "h-4 w-4" }),
|
|
98031
|
+
"Add from URL"
|
|
98032
|
+
]
|
|
98033
|
+
}
|
|
98034
|
+
),
|
|
98035
|
+
/* @__PURE__ */ jsx("div", { className: "text-xs text-muted-foreground pt-1 border-t", children: "Maximum file size: 5MB. We will try to compress the image if possible." })
|
|
98036
|
+
] }) })
|
|
98037
|
+
]
|
|
97432
98038
|
}
|
|
97433
98039
|
),
|
|
98040
|
+
/* @__PURE__ */ jsx(Dialog, { open: isUrlDialogOpen, onOpenChange: setIsUrlDialogOpen, children: /* @__PURE__ */ jsxs(DialogContent, { className: "sm:max-w-md", children: [
|
|
98041
|
+
/* @__PURE__ */ jsxs(DialogHeader, { children: [
|
|
98042
|
+
/* @__PURE__ */ jsx(DialogTitle, { children: "Add Image from URL" }),
|
|
98043
|
+
/* @__PURE__ */ jsxs(DialogDescription, { children: [
|
|
98044
|
+
"Enter the URL of the image you want to add to your SMS message. You can use merge fields to make the URL dynamic (e.g., https://example.com/images/{{customer_name}}.jpg).",
|
|
98045
|
+
/* @__PURE__ */ jsx("br", {}),
|
|
98046
|
+
/* @__PURE__ */ jsx("br", {}),
|
|
98047
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm text-muted-foreground", children: "Maximum file size: 5MB. We will try to compress the image if possible." })
|
|
98048
|
+
] })
|
|
98049
|
+
] }),
|
|
98050
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
|
|
98051
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
98052
|
+
/* @__PURE__ */ jsx(Label$1, { htmlFor: "image-url", children: "Image URL" }),
|
|
98053
|
+
/* @__PURE__ */ jsx(
|
|
98054
|
+
RichTextInputWithMergeFields,
|
|
98055
|
+
{
|
|
98056
|
+
value: imageUrl,
|
|
98057
|
+
onChange: setImageUrl,
|
|
98058
|
+
mergeFieldsResponse,
|
|
98059
|
+
placeholder: "https://example.com/image.jpg",
|
|
98060
|
+
className: "bg-background hover:bg-accent/50 focus:bg-accent transition-colors placeholder:text-muted-foreground/50",
|
|
98061
|
+
ariaLabel: "Insert merge field into image URL"
|
|
98062
|
+
}
|
|
98063
|
+
)
|
|
98064
|
+
] }),
|
|
98065
|
+
/* @__PURE__ */ jsxs("div", { className: "flex justify-end gap-2", children: [
|
|
98066
|
+
/* @__PURE__ */ jsx(
|
|
98067
|
+
Button$1,
|
|
98068
|
+
{
|
|
98069
|
+
variant: "outline",
|
|
98070
|
+
onClick: () => {
|
|
98071
|
+
setImageUrl("");
|
|
98072
|
+
setIsUrlDialogOpen(false);
|
|
98073
|
+
},
|
|
98074
|
+
children: "Cancel"
|
|
98075
|
+
}
|
|
98076
|
+
),
|
|
98077
|
+
/* @__PURE__ */ jsx(Button$1, { onClick: handleUrlSubmit, disabled: isSavingUrl, children: isSavingUrl ? "Adding..." : "Add Image" })
|
|
98078
|
+
] })
|
|
98079
|
+
] })
|
|
98080
|
+
] }) }),
|
|
97434
98081
|
/* @__PURE__ */ jsx(
|
|
97435
98082
|
MultiSelectDialog,
|
|
97436
98083
|
{
|
|
@@ -97439,7 +98086,7 @@ const SMSEditor = ({
|
|
|
97439
98086
|
setSelectedValues: () => {
|
|
97440
98087
|
},
|
|
97441
98088
|
onValueChange: handleMergeFieldInsert,
|
|
97442
|
-
placeholder:
|
|
98089
|
+
placeholder: `Add ${t$2("engage:merge_field")}`,
|
|
97443
98090
|
title: "Merge Fields",
|
|
97444
98091
|
searchPlaceholder: "Search merge fields...",
|
|
97445
98092
|
emptyMessage: "No merge fields found",
|
|
@@ -97702,6 +98349,9 @@ const SMSEditorContent = ({
|
|
|
97702
98349
|
const { toast: toast2 } = useToast();
|
|
97703
98350
|
const { updateCommunicationGroup: updateCommunicationGroup2, isUpdating: isUpdatingCommunicationGroup } = useUpdateCommunicationGroup();
|
|
97704
98351
|
const { getMergeFields: getMergeFields2 } = useGetMergeFields(communicationGroupId);
|
|
98352
|
+
const hasMergeFieldsInUrl = useCallback((url) => {
|
|
98353
|
+
return /\{\{[^}]+\}\}/.test(url);
|
|
98354
|
+
}, []);
|
|
97705
98355
|
const [editingMessage, setEditingMessage] = useState(initialMessage);
|
|
97706
98356
|
const [imagePreview, setImagePreview] = useState(
|
|
97707
98357
|
initialImageUrls.length > 0 ? initialImageUrls[0] : null
|
|
@@ -97718,6 +98368,7 @@ const SMSEditorContent = ({
|
|
|
97718
98368
|
const lastSavedStateRef = useRef({
|
|
97719
98369
|
message: initialMessage
|
|
97720
98370
|
});
|
|
98371
|
+
const { communicationGroup } = useGetCommunicationGroup(communicationGroupId);
|
|
97721
98372
|
const debouncedMessage = useDebounce(editingMessage, 1e3);
|
|
97722
98373
|
const autoSave = useCallback(async () => {
|
|
97723
98374
|
if (isInitialMountRef.current) {
|
|
@@ -97835,6 +98486,16 @@ const SMSEditorContent = ({
|
|
|
97835
98486
|
if (fileInputRef.current) {
|
|
97836
98487
|
fileInputRef.current.value = "";
|
|
97837
98488
|
}
|
|
98489
|
+
const MAX_FILE_SIZE = 20 * 1024 * 1024;
|
|
98490
|
+
if (file.size > MAX_FILE_SIZE) {
|
|
98491
|
+
console.log("File too large", file.size, MAX_FILE_SIZE);
|
|
98492
|
+
toast2({
|
|
98493
|
+
title: "File too large",
|
|
98494
|
+
description: `Image must be 5MB or smaller. Your file is ${(file.size / (1024 * 1024)).toFixed(1)}MB.`,
|
|
98495
|
+
variant: "destructive"
|
|
98496
|
+
});
|
|
98497
|
+
return;
|
|
98498
|
+
}
|
|
97838
98499
|
setIsUploadingImage(true);
|
|
97839
98500
|
try {
|
|
97840
98501
|
const reader = new FileReader();
|
|
@@ -97842,19 +98503,40 @@ const SMSEditorContent = ({
|
|
|
97842
98503
|
try {
|
|
97843
98504
|
const pngDataUrl = await convertToPng(reader.result);
|
|
97844
98505
|
const base64String = extractBase64Data(pngDataUrl);
|
|
97845
|
-
|
|
97846
|
-
|
|
97847
|
-
|
|
97848
|
-
|
|
98506
|
+
updateCommunicationGroup2(
|
|
98507
|
+
{
|
|
98508
|
+
groupId: communicationGroupId,
|
|
98509
|
+
params: {
|
|
98510
|
+
textMessageMedia: [base64String]
|
|
98511
|
+
}
|
|
98512
|
+
},
|
|
98513
|
+
{
|
|
98514
|
+
onSuccess: () => {
|
|
98515
|
+
setImageBase64(base64String);
|
|
98516
|
+
setImagePreview(pngDataUrl);
|
|
98517
|
+
setIsRemovingImage(false);
|
|
98518
|
+
toast2({
|
|
98519
|
+
title: "Image uploaded",
|
|
98520
|
+
description: "The image has been added to your SMS"
|
|
98521
|
+
});
|
|
98522
|
+
},
|
|
98523
|
+
onError: (data) => {
|
|
98524
|
+
if (data.message.includes("Image is still too large")) {
|
|
98525
|
+
toast2({
|
|
98526
|
+
title: "Image too large",
|
|
98527
|
+
description: "The image is too large. Please try again with a smaller image.",
|
|
98528
|
+
variant: "destructive"
|
|
98529
|
+
});
|
|
98530
|
+
} else {
|
|
98531
|
+
toast2({
|
|
98532
|
+
title: "Error uploading image",
|
|
98533
|
+
description: "Failed to process or upload the image",
|
|
98534
|
+
variant: "destructive"
|
|
98535
|
+
});
|
|
98536
|
+
}
|
|
98537
|
+
}
|
|
97849
98538
|
}
|
|
97850
|
-
|
|
97851
|
-
setImageBase64(base64String);
|
|
97852
|
-
setImagePreview(pngDataUrl);
|
|
97853
|
-
setIsRemovingImage(false);
|
|
97854
|
-
toast2({
|
|
97855
|
-
title: "Image uploaded",
|
|
97856
|
-
description: "The image has been added to your SMS"
|
|
97857
|
-
});
|
|
98539
|
+
);
|
|
97858
98540
|
} catch (error2) {
|
|
97859
98541
|
console.error("Failed to convert or upload image:", error2);
|
|
97860
98542
|
toast2({
|
|
@@ -97886,6 +98568,22 @@ const SMSEditorContent = ({
|
|
|
97886
98568
|
return /* @__PURE__ */ jsx("div", { className: "flex justify-center items-center p-8", children: /* @__PURE__ */ jsx("div", { className: "text-sm text-muted-foreground", children: "Loading editor..." }) });
|
|
97887
98569
|
}
|
|
97888
98570
|
return /* @__PURE__ */ jsxs("div", { className: cn$2("w-full @container", className), children: [
|
|
98571
|
+
!communicationGroup?.smsChannelSenderId && /* @__PURE__ */ jsx("div", { className: "mb-6 p-4 bg-amber-50 border border-amber-200 rounded-lg", children: /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-3", children: [
|
|
98572
|
+
/* @__PURE__ */ jsx(
|
|
98573
|
+
InfoTooltip,
|
|
98574
|
+
{
|
|
98575
|
+
title: "SMS Sender Required",
|
|
98576
|
+
description: "You need to select an SMS sender before you can send SMS messages. Click 'Edit Sender & Company' above to configure your SMS sender.",
|
|
98577
|
+
alertText: "Action Required",
|
|
98578
|
+
size: "medium",
|
|
98579
|
+
iconColor: "text-amber-500"
|
|
98580
|
+
}
|
|
98581
|
+
),
|
|
98582
|
+
/* @__PURE__ */ jsxs("div", { className: "flex-1", children: [
|
|
98583
|
+
/* @__PURE__ */ jsx("h3", { className: "text-sm font-medium text-amber-800 mb-1", children: "SMS Sender Not Selected" }),
|
|
98584
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm text-amber-700", children: 'Please select an SMS sender to enable SMS messaging. Click the "Edit Sender & Company" button to configure your sender.' })
|
|
98585
|
+
] })
|
|
98586
|
+
] }) }),
|
|
97889
98587
|
/* @__PURE__ */ jsx("div", { className: "flex items-center justify-between mb-6", children: /* @__PURE__ */ jsx(
|
|
97890
98588
|
MemoizedSMSSenderAndCompanyEditor$1,
|
|
97891
98589
|
{
|
|
@@ -97896,7 +98594,20 @@ const SMSEditorContent = ({
|
|
|
97896
98594
|
) }),
|
|
97897
98595
|
/* @__PURE__ */ jsxs("div", { className: "flex flex-col lg:flex-row gap-6 h-full", children: [
|
|
97898
98596
|
/* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
|
|
97899
|
-
imagePreview && /* @__PURE__ */ jsx("div", { className: "flex justify-center mb-6", children: /* @__PURE__ */ jsx("div", { className: "relative group w-fit", children: /* @__PURE__ */ jsx(
|
|
98597
|
+
imagePreview && /* @__PURE__ */ jsx("div", { className: "flex justify-center mb-6", children: /* @__PURE__ */ jsx("div", { className: "relative group w-fit", children: hasMergeFieldsInUrl(imagePreview) ? /* @__PURE__ */ jsx("div", { className: "max-h-48 max-w-xs rounded-xl shadow-lg border border-gray-200 bg-gray-50 p-4 flex items-center justify-center", children: /* @__PURE__ */ jsxs("div", { className: "text-center", children: [
|
|
98598
|
+
/* @__PURE__ */ jsx("div", { className: "text-sm font-medium text-gray-700 mb-2", children: "Image will be populated at send time based on the following merge fields:" }),
|
|
98599
|
+
/* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-1 justify-center", children: getMergeFieldsFromUrl(
|
|
98600
|
+
imagePreview,
|
|
98601
|
+
getMergeFields2
|
|
98602
|
+
).map((fieldName, index2) => /* @__PURE__ */ jsx(
|
|
98603
|
+
"span",
|
|
98604
|
+
{
|
|
98605
|
+
className: "inline-flex items-center px-2 py-1 rounded text-xs bg-blue-100 text-blue-800 font-medium border border-blue-200",
|
|
98606
|
+
children: fieldName
|
|
98607
|
+
},
|
|
98608
|
+
index2
|
|
98609
|
+
)) })
|
|
98610
|
+
] }) }) : /* @__PURE__ */ jsx(
|
|
97900
98611
|
"img",
|
|
97901
98612
|
{
|
|
97902
98613
|
src: imagePreview,
|
|
@@ -97932,7 +98643,8 @@ const SMSEditorContent = ({
|
|
|
97932
98643
|
initialImageUrls,
|
|
97933
98644
|
imageBase64,
|
|
97934
98645
|
isUpdating: isUpdatingCommunicationGroup || isUploadingImage,
|
|
97935
|
-
hasUnsavedChanges
|
|
98646
|
+
hasUnsavedChanges,
|
|
98647
|
+
communicationGroupId
|
|
97936
98648
|
}
|
|
97937
98649
|
)
|
|
97938
98650
|
] }),
|
|
@@ -99826,6 +100538,7 @@ const AutomationEditorEmailPreview = ({
|
|
|
99826
100538
|
const [showHelpDialog, setShowHelpDialog] = useState(null);
|
|
99827
100539
|
const [saveClicked, setSaveClicked] = useState(false);
|
|
99828
100540
|
const [cancelClicked, setCancelClicked] = useState(false);
|
|
100541
|
+
const [isEditorReady, setIsEditorReady] = useState(false);
|
|
99829
100542
|
const [stripoDialogDimensions, setStripoDialogDimensions] = useState({
|
|
99830
100543
|
width: 0,
|
|
99831
100544
|
height: 0
|
|
@@ -99968,6 +100681,7 @@ const AutomationEditorEmailPreview = ({
|
|
|
99968
100681
|
Button$1,
|
|
99969
100682
|
{
|
|
99970
100683
|
onClick: () => setSaveClicked(true),
|
|
100684
|
+
disabled: !isEditorReady,
|
|
99971
100685
|
className: "text-sm px-3 py-1 rounded",
|
|
99972
100686
|
children: "Save"
|
|
99973
100687
|
}
|
|
@@ -99986,7 +100700,8 @@ const AutomationEditorEmailPreview = ({
|
|
|
99986
100700
|
setSaveClicked,
|
|
99987
100701
|
stripoDialogDimensions,
|
|
99988
100702
|
mergeFieldsResponse: getMergeFields2,
|
|
99989
|
-
actionId: selectedActionId
|
|
100703
|
+
actionId: selectedActionId,
|
|
100704
|
+
onEditorReadyChange: setIsEditorReady
|
|
99990
100705
|
}
|
|
99991
100706
|
)
|
|
99992
100707
|
] })
|
|
@@ -100087,12 +100802,6 @@ const SMSDetailField = ({ label: label2, value, className }) => /* @__PURE__ */
|
|
|
100087
100802
|
] }),
|
|
100088
100803
|
/* @__PURE__ */ jsx("span", { className: cn$2("truncate", className), children: value })
|
|
100089
100804
|
] });
|
|
100090
|
-
const MemoizedTriggerButton = React__default.memo(
|
|
100091
|
-
React__default.forwardRef((props2, ref) => /* @__PURE__ */ jsxs(Button$1, { size: "sm", variant: "outline", ref, ...props2, children: [
|
|
100092
|
-
/* @__PURE__ */ jsx(IconDefinitions.EditIcon, { className: "w-3 h-3" }),
|
|
100093
|
-
"Edit"
|
|
100094
|
-
] }))
|
|
100095
|
-
);
|
|
100096
100805
|
const MemoizedSMSSenderAndCompanyEditor = React__default.memo(
|
|
100097
100806
|
({
|
|
100098
100807
|
trigger,
|
|
@@ -100111,7 +100820,7 @@ const MemoizedSMSSenderAndCompanyEditor = React__default.memo(
|
|
|
100111
100820
|
);
|
|
100112
100821
|
}
|
|
100113
100822
|
);
|
|
100114
|
-
const SMSDetailsPreview = ({ disableEditContent }) => {
|
|
100823
|
+
const SMSDetailsPreview = ({ disableEditContent, mergeFieldsResponse }) => {
|
|
100115
100824
|
const automation2 = useAutomation();
|
|
100116
100825
|
const communicationGroup = useCommunicationGroup();
|
|
100117
100826
|
const { channelSenders } = useChannelSender();
|
|
@@ -100135,6 +100844,22 @@ const SMSDetailsPreview = ({ disableEditContent }) => {
|
|
|
100135
100844
|
return null;
|
|
100136
100845
|
}
|
|
100137
100846
|
const messagePreview = messageBody ? messageBody.length > 50 ? messageBody.substring(0, 50) + "..." : messageBody : null;
|
|
100847
|
+
const MemoizedTriggerButton = React__default.memo(
|
|
100848
|
+
React__default.forwardRef((props2, ref) => /* @__PURE__ */ jsxs(
|
|
100849
|
+
Button$1,
|
|
100850
|
+
{
|
|
100851
|
+
size: "sm",
|
|
100852
|
+
variant: "outline",
|
|
100853
|
+
ref,
|
|
100854
|
+
...props2,
|
|
100855
|
+
disabled: automation2?.status !== AutomationStatus.DRAFT,
|
|
100856
|
+
children: [
|
|
100857
|
+
/* @__PURE__ */ jsx(IconDefinitions.EditIcon, { className: "w-3 h-3" }),
|
|
100858
|
+
"Edit"
|
|
100859
|
+
]
|
|
100860
|
+
}
|
|
100861
|
+
))
|
|
100862
|
+
);
|
|
100138
100863
|
return /* @__PURE__ */ jsx("div", { className: "w-full bg-background rounded-lg p-3", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
|
|
100139
100864
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 overflow-hidden flex-1", children: [
|
|
100140
100865
|
fromPhone && /* @__PURE__ */ jsx(
|
|
@@ -100157,7 +100882,15 @@ const SMSDetailsPreview = ({ disableEditContent }) => {
|
|
|
100157
100882
|
SMSDetailField,
|
|
100158
100883
|
{
|
|
100159
100884
|
label: "Message",
|
|
100160
|
-
value:
|
|
100885
|
+
value: /* @__PURE__ */ jsx(
|
|
100886
|
+
MergeFieldRenderer,
|
|
100887
|
+
{
|
|
100888
|
+
content: messagePreview,
|
|
100889
|
+
mergeFieldsResponse,
|
|
100890
|
+
variant: "minimal",
|
|
100891
|
+
className: "text-muted-foreground/50 italic"
|
|
100892
|
+
}
|
|
100893
|
+
),
|
|
100161
100894
|
className: "text-muted-foreground/50 italic"
|
|
100162
100895
|
}
|
|
100163
100896
|
)
|
|
@@ -100200,6 +100933,9 @@ const AutomationEditorSMSPreview = ({
|
|
|
100200
100933
|
[communicationGroup?.textMessageMediaUrls]
|
|
100201
100934
|
);
|
|
100202
100935
|
const smsBody = communicationGroup?.smsMessageBody || "";
|
|
100936
|
+
const { getMergeFields: getMergeFields2 } = useGetMergeFields(
|
|
100937
|
+
communicationGroup?.id ?? void 0
|
|
100938
|
+
);
|
|
100203
100939
|
const hasAnySMSsenders = smsChannelSenders.length > 0;
|
|
100204
100940
|
useEffect(() => {
|
|
100205
100941
|
if (hasProcessedInitialSetupRef.current) {
|
|
@@ -100350,7 +101086,8 @@ const AutomationEditorSMSPreview = ({
|
|
|
100350
101086
|
/* @__PURE__ */ jsx("div", { className: "w-full flex-shrink-0 max-w-2xl mx-auto rounded-md", children: /* @__PURE__ */ jsx(
|
|
100351
101087
|
SMSDetailsPreview,
|
|
100352
101088
|
{
|
|
100353
|
-
disableEditContent
|
|
101089
|
+
disableEditContent,
|
|
101090
|
+
mergeFieldsResponse: getMergeFields2
|
|
100354
101091
|
}
|
|
100355
101092
|
) }),
|
|
100356
101093
|
/* @__PURE__ */ jsxs("div", { className: "rounded-lg bg-background flex-1 min-h-0 flex flex-col items-center max-w-2xl mx-auto w-full", children: [
|
|
@@ -104364,6 +105101,15 @@ const AutomationSelectTimeMain = ({ title: title2 = "Edit Schedule Time" }) => {
|
|
|
104364
105101
|
const Schedule = () => {
|
|
104365
105102
|
return /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(AutomationSelectTimeMain, { title: "Set Schedule Time" }) });
|
|
104366
105103
|
};
|
|
105104
|
+
var AutomationAudienceSelectorType = /* @__PURE__ */ ((AutomationAudienceSelectorType2) => {
|
|
105105
|
+
AutomationAudienceSelectorType2["ALL"] = "all";
|
|
105106
|
+
AutomationAudienceSelectorType2["SEGMENTS"] = "segments";
|
|
105107
|
+
AutomationAudienceSelectorType2["INDIVIDUAL"] = "individual";
|
|
105108
|
+
return AutomationAudienceSelectorType2;
|
|
105109
|
+
})(AutomationAudienceSelectorType || {});
|
|
105110
|
+
const generateOneOffSegmentName = (automationId) => {
|
|
105111
|
+
return `ONE-OFF-SEGMENT-${automationId}`;
|
|
105112
|
+
};
|
|
104367
105113
|
var DateUnit = /* @__PURE__ */ ((DateUnit2) => {
|
|
104368
105114
|
DateUnit2["DAYS"] = "days";
|
|
104369
105115
|
return DateUnit2;
|
|
@@ -104431,7 +105177,7 @@ const operatorToHumanReadable = (operator, type) => {
|
|
|
104431
105177
|
return "Less than";
|
|
104432
105178
|
}
|
|
104433
105179
|
case ConditionOperatorEnumType.EXISTS:
|
|
104434
|
-
return "
|
|
105180
|
+
return "Is Known";
|
|
104435
105181
|
case ConditionOperatorEnumType.EQUALS_MONTH_DAY:
|
|
104436
105182
|
return "Month and Day Matches";
|
|
104437
105183
|
case ConditionOperatorEnumType.EQUALS_MONTH_DAY_YEAR:
|
|
@@ -105419,6 +106165,39 @@ const ConditionRow = ({
|
|
|
105419
106165
|
] })
|
|
105420
106166
|
] });
|
|
105421
106167
|
};
|
|
106168
|
+
const BetaTag = React.forwardRef(
|
|
106169
|
+
({
|
|
106170
|
+
children = "BETA",
|
|
106171
|
+
size: size2 = "default",
|
|
106172
|
+
animated = false,
|
|
106173
|
+
className,
|
|
106174
|
+
...props2
|
|
106175
|
+
}, ref) => {
|
|
106176
|
+
const sizeClasses = {
|
|
106177
|
+
sm: "px-1.5 py-0.5 text-[10px]",
|
|
106178
|
+
default: "px-2 py-0.5 text-xs",
|
|
106179
|
+
lg: "px-2.5 py-1 text-sm"
|
|
106180
|
+
};
|
|
106181
|
+
return /* @__PURE__ */ jsx(
|
|
106182
|
+
"span",
|
|
106183
|
+
{
|
|
106184
|
+
ref,
|
|
106185
|
+
className: cn$2(
|
|
106186
|
+
"inline-flex items-center justify-center rounded-full font-medium leading-none",
|
|
106187
|
+
"bg-gray-100 text-gray-600 border border-gray-200",
|
|
106188
|
+
"dark:bg-gray-800 dark:text-gray-300 dark:border-gray-700",
|
|
106189
|
+
"relative select-none",
|
|
106190
|
+
sizeClasses[size2],
|
|
106191
|
+
animated && "animate-pulse",
|
|
106192
|
+
className
|
|
106193
|
+
),
|
|
106194
|
+
...props2,
|
|
106195
|
+
children
|
|
106196
|
+
}
|
|
106197
|
+
);
|
|
106198
|
+
}
|
|
106199
|
+
);
|
|
106200
|
+
BetaTag.displayName = "BetaTag";
|
|
105422
106201
|
const PromptBuilderStyle = ({ onSelectStyle }) => {
|
|
105423
106202
|
const [selectedStyle, setSelectedStyle] = useState(
|
|
105424
106203
|
null
|
|
@@ -105431,7 +106210,10 @@ const PromptBuilderStyle = ({ onSelectStyle }) => {
|
|
|
105431
106210
|
setSelectedStyle("ai");
|
|
105432
106211
|
onSelectStyle("ai");
|
|
105433
106212
|
},
|
|
105434
|
-
title: "
|
|
106213
|
+
title: /* @__PURE__ */ jsxs("div", { className: "inline-flex items-center gap-2", children: [
|
|
106214
|
+
/* @__PURE__ */ jsx("span", { children: "Build with AI" }),
|
|
106215
|
+
/* @__PURE__ */ jsx(BetaTag, { size: "sm" })
|
|
106216
|
+
] }),
|
|
105435
106217
|
subtitle: "Describe your audience in plain language and let AI create the conditions",
|
|
105436
106218
|
icon: /* @__PURE__ */ jsx("div", { className: "h-12 w-12 rounded-full bg-primary/10 flex items-center justify-center", children: /* @__PURE__ */ jsx("div", { className: "w-6 h-6 text-[hsl(var(--reach-primary))]", children: /* @__PURE__ */ jsx(Sparkles, { className: "w-full h-full" }) }) }),
|
|
105437
106219
|
selected: selectedStyle === "ai"
|
|
@@ -105511,6 +106293,7 @@ const TextToSegment = ({ setTextToSegment, setSegment }) => {
|
|
|
105511
106293
|
const [userInput, setUserInput] = React__default.useState("");
|
|
105512
106294
|
const [isLoading, setIsLoading] = React__default.useState(false);
|
|
105513
106295
|
const { toast: toast2 } = useToast();
|
|
106296
|
+
const { sendNotificationAsync } = useSlackNotification();
|
|
105514
106297
|
const getSegment2 = async () => {
|
|
105515
106298
|
if (!userInput) {
|
|
105516
106299
|
toast2({
|
|
@@ -105522,9 +106305,14 @@ const TextToSegment = ({ setTextToSegment, setSegment }) => {
|
|
|
105522
106305
|
}
|
|
105523
106306
|
setIsLoading(true);
|
|
105524
106307
|
const response = await textToSegment({
|
|
105525
|
-
userInput,
|
|
106308
|
+
text: userInput,
|
|
105526
106309
|
userCustomVerb: t$2("engage:user")
|
|
105527
106310
|
});
|
|
106311
|
+
sendNotificationAsync({
|
|
106312
|
+
message: "💬 New AI Segment requested",
|
|
106313
|
+
product: "engage",
|
|
106314
|
+
details: { userInput, response }
|
|
106315
|
+
});
|
|
105528
106316
|
if (response.success && response.conditions) {
|
|
105529
106317
|
toast2({
|
|
105530
106318
|
title: `${t$2("engage:segment")} conditions built successfully 🚀`,
|
|
@@ -106091,9 +106879,14 @@ const TotalExplanationTooltip = () => {
|
|
|
106091
106879
|
return /* @__PURE__ */ jsx(
|
|
106092
106880
|
InfoTooltip,
|
|
106093
106881
|
{
|
|
106094
|
-
title: `
|
|
106882
|
+
title: `The total number of ${t$2("engage:user", {
|
|
106095
106883
|
count: 2
|
|
106096
|
-
}).toLocaleLowerCase()}
|
|
106884
|
+
}).toLocaleLowerCase()} may not match your SMS and email counts because some ${t$2(
|
|
106885
|
+
"engage:user",
|
|
106886
|
+
{
|
|
106887
|
+
count: 2
|
|
106888
|
+
}
|
|
106889
|
+
).toLocaleLowerCase()} may have unsubscribed, invalid contact information, or haven't opted into marketing messages.`
|
|
106097
106890
|
}
|
|
106098
106891
|
);
|
|
106099
106892
|
};
|
|
@@ -106104,7 +106897,8 @@ const StatCard$1 = ({
|
|
|
106104
106897
|
variant,
|
|
106105
106898
|
isLoading,
|
|
106106
106899
|
selected,
|
|
106107
|
-
onClick
|
|
106900
|
+
onClick,
|
|
106901
|
+
tooltip
|
|
106108
106902
|
}) => {
|
|
106109
106903
|
const variantStyles = {
|
|
106110
106904
|
default: "bg-gray-100/50 text-gray-700",
|
|
@@ -106123,13 +106917,16 @@ const StatCard$1 = ({
|
|
|
106123
106917
|
children: [
|
|
106124
106918
|
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1 items-start w-full min-w-0", children: [
|
|
106125
106919
|
/* @__PURE__ */ jsx("div", { className: "flex items-baseline gap-2 w-full min-w-0 @container/num", children: isLoading ? /* @__PURE__ */ jsx("span", { className: "animate-pulse", children: "..." }) : /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
106126
|
-
/* @__PURE__ */
|
|
106127
|
-
|
|
106128
|
-
|
|
106129
|
-
|
|
106130
|
-
|
|
106131
|
-
|
|
106132
|
-
|
|
106920
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
|
|
106921
|
+
/* @__PURE__ */ jsx(
|
|
106922
|
+
"span",
|
|
106923
|
+
{
|
|
106924
|
+
className: "font-semibold pl-2 break-words max-w-full min-w-0 truncate\n text-xl @[250px]/card:text-2xl @[350px]/card:text-3xl @[500px]/card:text-4xl text-primary",
|
|
106925
|
+
children: value.toLocaleString()
|
|
106926
|
+
}
|
|
106927
|
+
),
|
|
106928
|
+
tooltip && /* @__PURE__ */ jsx(InfoTooltip, { title: tooltip })
|
|
106929
|
+
] }),
|
|
106133
106930
|
percentage2 !== void 0 && value.toLocaleString().replace(/,/g, "").length < 5 && /* @__PURE__ */ jsxs("span", { className: "text-muted-foreground/50 text-sm hidden @[120px]/num:inline", children: [
|
|
106134
106931
|
"(",
|
|
106135
106932
|
percentage2,
|
|
@@ -106162,11 +106959,28 @@ const EstimatedMatchesView = ({ countResponse, selectedFilter = "all", onFilterC
|
|
|
106162
106959
|
);
|
|
106163
106960
|
}, [countResponse]);
|
|
106164
106961
|
const calculatePercentage = (value) => Math.round(value / (stats.total || 1) * 100);
|
|
106962
|
+
const showReassuranceBanner = stats.total > Math.max(stats.emails, stats.phones);
|
|
106165
106963
|
return /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
106166
106964
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
106167
106965
|
/* @__PURE__ */ jsx(MinorText, { children: "Estimated Matches" }),
|
|
106168
106966
|
/* @__PURE__ */ jsx(TotalExplanationTooltip, {})
|
|
106169
106967
|
] }),
|
|
106968
|
+
showReassuranceBanner && /* @__PURE__ */ jsx("div", { className: "mt-2 p-3 bg-secondary/50 border border-border rounded-lg", children: /* @__PURE__ */ jsxs("p", { className: "text-xs text-muted-foreground", children: [
|
|
106969
|
+
/* @__PURE__ */ jsx("span", { className: "font-medium", children: "Total vs. Subscribed mismatch?" }),
|
|
106970
|
+
" ",
|
|
106971
|
+
"Some ",
|
|
106972
|
+
t$2("engage:user", { count: 2 }).toLowerCase(),
|
|
106973
|
+
" may have unsubscribed or had hard bounces.",
|
|
106974
|
+
/* @__PURE__ */ jsx(
|
|
106975
|
+
InfoTooltip,
|
|
106976
|
+
{
|
|
106977
|
+
description: "This can happen when customers unsubscribe, emails bounces, or contact info is missing. This is normal and expected.",
|
|
106978
|
+
size: "small",
|
|
106979
|
+
iconColor: "text-muted-foreground",
|
|
106980
|
+
children: /* @__PURE__ */ jsx("span", { className: "underline cursor-help", children: "Learn more" })
|
|
106981
|
+
}
|
|
106982
|
+
)
|
|
106983
|
+
] }) }),
|
|
106170
106984
|
/* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 md:grid-cols-3 md:mb-6 w-full gap-4 mt-3 px-1", children: [
|
|
106171
106985
|
/* @__PURE__ */ jsx(
|
|
106172
106986
|
StatCard$1,
|
|
@@ -106176,7 +106990,15 @@ const EstimatedMatchesView = ({ countResponse, selectedFilter = "all", onFilterC
|
|
|
106176
106990
|
variant: "default",
|
|
106177
106991
|
isLoading: countResponse === void 0,
|
|
106178
106992
|
selected: selectedFilter === "all",
|
|
106179
|
-
onClick: onFilterChange ? () => onFilterChange("all") : void 0
|
|
106993
|
+
onClick: onFilterChange ? () => onFilterChange("all") : void 0,
|
|
106994
|
+
tooltip: `Total includes all ${t$2("engage:user", {
|
|
106995
|
+
count: 2
|
|
106996
|
+
}).toLocaleLowerCase()} in your system. This does not factor in ${t$2(
|
|
106997
|
+
"engage:user",
|
|
106998
|
+
{
|
|
106999
|
+
count: 2
|
|
107000
|
+
}
|
|
107001
|
+
).toLocaleLowerCase()} who might have opted out of email or sms.`
|
|
106180
107002
|
}
|
|
106181
107003
|
),
|
|
106182
107004
|
/* @__PURE__ */ jsx(
|
|
@@ -106206,7 +107028,7 @@ const EstimatedMatchesView = ({ countResponse, selectedFilter = "all", onFilterC
|
|
|
106206
107028
|
] })
|
|
106207
107029
|
] });
|
|
106208
107030
|
};
|
|
106209
|
-
const getDisplayName = (recipient) => {
|
|
107031
|
+
const getDisplayName$1 = (recipient) => {
|
|
106210
107032
|
const fullName = `${recipient.firstName || ""} ${recipient.lastName || ""}`.trim();
|
|
106211
107033
|
if (fullName) return fullName;
|
|
106212
107034
|
if (recipient.firstName) return recipient.firstName;
|
|
@@ -106215,7 +107037,7 @@ const getDisplayName = (recipient) => {
|
|
|
106215
107037
|
if (recipient.phone) return recipient.phone;
|
|
106216
107038
|
return `Unnamed ${t$2("engage:user")}`;
|
|
106217
107039
|
};
|
|
106218
|
-
const RecipientsTable = ({ recipients, filter: filter2 = "all" }) => {
|
|
107040
|
+
const RecipientsTable = ({ recipients, filter: filter2 = "all", audienceMode }) => {
|
|
106219
107041
|
const filteredRecipients = recipients?.filter((recipient) => {
|
|
106220
107042
|
const hasEmail = !!recipient.email;
|
|
106221
107043
|
const hasPhone = !!recipient.phone;
|
|
@@ -106230,14 +107052,45 @@ const RecipientsTable = ({ recipients, filter: filter2 = "all" }) => {
|
|
|
106230
107052
|
return true;
|
|
106231
107053
|
}
|
|
106232
107054
|
});
|
|
106233
|
-
if (!filteredRecipients?.length)
|
|
107055
|
+
if (!filteredRecipients?.length) {
|
|
107056
|
+
return /* @__PURE__ */ jsx("div", { className: "bg-foreground/5 rounded-lg h-full relative overflow-hidden", children: /* @__PURE__ */ jsx("div", { className: "absolute inset-0 w-full h-full flex items-center justify-center", children: /* @__PURE__ */ jsx("div", { className: "text-center max-w-sm", children: /* @__PURE__ */ jsxs("div", { className: "text-gray-400 text-sm mb-2", children: [
|
|
107057
|
+
filter2 === "email" && "No recipients with email addresses",
|
|
107058
|
+
filter2 === "phone" && "No recipients with phone numbers",
|
|
107059
|
+
filter2 === "all" && (audienceMode === "segments" ? /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
107060
|
+
/* @__PURE__ */ jsxs("div", { className: "text-gray-500 font-medium mb-1", children: [
|
|
107061
|
+
"No ",
|
|
107062
|
+
t$2("engage:segment").toLowerCase(),
|
|
107063
|
+
" selected"
|
|
107064
|
+
] }),
|
|
107065
|
+
/* @__PURE__ */ jsxs("div", { className: "text-gray-400 text-xs", children: [
|
|
107066
|
+
"Select one or more",
|
|
107067
|
+
" ",
|
|
107068
|
+
t$2("engage:segment", { count: 2 }).toLowerCase(),
|
|
107069
|
+
" from the list above to see your recipients"
|
|
107070
|
+
] })
|
|
107071
|
+
] }) : audienceMode === "individual" ? /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
107072
|
+
/* @__PURE__ */ jsxs("div", { className: "text-gray-500 font-medium mb-1", children: [
|
|
107073
|
+
"No individual",
|
|
107074
|
+
" ",
|
|
107075
|
+
t$2("engage:user", { count: 2 }).toLowerCase(),
|
|
107076
|
+
" selected"
|
|
107077
|
+
] }),
|
|
107078
|
+
/* @__PURE__ */ jsxs("div", { className: "text-gray-400 text-xs", children: [
|
|
107079
|
+
"Choose specific",
|
|
107080
|
+
" ",
|
|
107081
|
+
t$2("engage:user", { count: 2 }).toLowerCase(),
|
|
107082
|
+
"from the dropdown above to see your recipients"
|
|
107083
|
+
] })
|
|
107084
|
+
] }) : "No recipients found")
|
|
107085
|
+
] }) }) }) });
|
|
107086
|
+
}
|
|
106234
107087
|
return /* @__PURE__ */ jsx("div", { className: "bg-foreground/5 rounded-lg h-full relative overflow-hidden", children: /* @__PURE__ */ jsx("div", { className: "absolute inset-0 w-full h-full overflow-y-auto", children: /* @__PURE__ */ jsxs("table", { className: "w-full", children: [
|
|
106235
107088
|
/* @__PURE__ */ jsx("thead", { className: "sticky top-0 bg-foreground/5 backdrop-blur-sm", children: /* @__PURE__ */ jsxs("tr", { children: [
|
|
106236
107089
|
/* @__PURE__ */ jsx("th", { className: "px-3 sm:px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wide", children: "Name" }),
|
|
106237
107090
|
/* @__PURE__ */ jsx("th", { className: "px-3 sm:px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wide", children: "Contact" })
|
|
106238
107091
|
] }) }),
|
|
106239
107092
|
/* @__PURE__ */ jsx("tbody", { className: "divide-y divide-gray-200/50", children: filteredRecipients.map((recipient, index2) => /* @__PURE__ */ jsxs("tr", { className: "hover:bg-white/50 transition-colors", children: [
|
|
106240
|
-
/* @__PURE__ */ jsx("td", { className: "px-3 sm:px-4 py-3 text-sm text-gray-900", children: getDisplayName(recipient) }),
|
|
107093
|
+
/* @__PURE__ */ jsx("td", { className: "px-3 sm:px-4 py-3 text-sm text-gray-900", children: getDisplayName$1(recipient) }),
|
|
106241
107094
|
/* @__PURE__ */ jsx("td", { className: "px-3 sm:px-4 py-3", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap gap-1.5 sm:gap-2", children: [
|
|
106242
107095
|
recipient.email && /* @__PURE__ */ jsx("span", { className: "px-2 sm:px-2.5 py-1 text-xs font-medium bg-blue-100/50 text-blue-700 rounded-lg", children: "Email" }),
|
|
106243
107096
|
recipient.phone && /* @__PURE__ */ jsx("span", { className: "px-2 sm:px-2.5 py-1 text-xs font-medium bg-green-100/50 text-green-700 rounded-lg", children: "Phone" })
|
|
@@ -106245,7 +107098,11 @@ const RecipientsTable = ({ recipients, filter: filter2 = "all" }) => {
|
|
|
106245
107098
|
] }, index2)) })
|
|
106246
107099
|
] }) }) });
|
|
106247
107100
|
};
|
|
106248
|
-
const AllOrSelectSegmentPicker = ({
|
|
107101
|
+
const AllOrSelectSegmentPicker = ({
|
|
107102
|
+
onSelectionChange,
|
|
107103
|
+
defaultValue = AutomationAudienceSelectorType.ALL,
|
|
107104
|
+
canEditAudience = true
|
|
107105
|
+
}) => {
|
|
106249
107106
|
const [selected, setSelected] = useState(defaultValue);
|
|
106250
107107
|
const handleSelect = (value) => {
|
|
106251
107108
|
if (!canEditAudience) return;
|
|
@@ -106257,32 +107114,124 @@ const AllOrSelectSegmentPicker = ({ onSelectionChange, defaultValue = "all", can
|
|
|
106257
107114
|
/* @__PURE__ */ jsx(MinorText, { children: "Filter" }),
|
|
106258
107115
|
!canEditAudience && /* @__PURE__ */ jsx(InfoTooltip, { title: "You cannot edit the audience unless you are in draft mode" })
|
|
106259
107116
|
] }),
|
|
106260
|
-
/* @__PURE__ */ jsxs("div", { className: "grid grid-cols-
|
|
107117
|
+
/* @__PURE__ */ jsxs("div", { className: "grid grid-cols-3 gap-4 p-1", children: [
|
|
106261
107118
|
/* @__PURE__ */ jsx(
|
|
106262
107119
|
BigSelector,
|
|
106263
107120
|
{
|
|
106264
|
-
onClick: () => handleSelect(
|
|
107121
|
+
onClick: () => handleSelect(AutomationAudienceSelectorType.ALL),
|
|
106265
107122
|
title: `All ${t$2("engage:user", { count: 2 })}`,
|
|
106266
107123
|
subtitle: "Send to everyone",
|
|
106267
107124
|
icon: /* @__PURE__ */ jsx(IconDefinitions.UsersIcon, { className: "w-5 h-5 mb-2 text-gray-600" }),
|
|
106268
107125
|
selected: selected === "all",
|
|
106269
|
-
disabled: !canEditAudience
|
|
107126
|
+
disabled: !canEditAudience,
|
|
107127
|
+
hideSelectedText: true
|
|
106270
107128
|
}
|
|
106271
107129
|
),
|
|
106272
107130
|
/* @__PURE__ */ jsx(
|
|
106273
107131
|
BigSelector,
|
|
106274
107132
|
{
|
|
106275
|
-
onClick: () => handleSelect(
|
|
106276
|
-
title: `Select ${t$2("engage:
|
|
107133
|
+
onClick: () => handleSelect(AutomationAudienceSelectorType.SEGMENTS),
|
|
107134
|
+
title: `Select ${t$2("engage:segment", { count: 2 })}`,
|
|
106277
107135
|
subtitle: `Choose from ${t$2("engage:segment", { count: 2 })}`,
|
|
106278
107136
|
icon: /* @__PURE__ */ jsx(IconDefinitions.UserEdit, { className: "w-5 h-5 mb-2 text-gray-600" }),
|
|
106279
107137
|
selected: selected === "segments",
|
|
106280
|
-
disabled: !canEditAudience
|
|
107138
|
+
disabled: !canEditAudience,
|
|
107139
|
+
hideSelectedText: true
|
|
107140
|
+
}
|
|
107141
|
+
),
|
|
107142
|
+
/* @__PURE__ */ jsx(
|
|
107143
|
+
BigSelector,
|
|
107144
|
+
{
|
|
107145
|
+
onClick: () => handleSelect(AutomationAudienceSelectorType.INDIVIDUAL),
|
|
107146
|
+
title: "Select Individual",
|
|
107147
|
+
subtitle: `Pick ${t$2("engage:user", { count: 2 }).toLowerCase()} one by one`,
|
|
107148
|
+
icon: /* @__PURE__ */ jsx(IconDefinitions.UserIcon, { className: "w-5 h-5 mb-2 text-gray-600" }),
|
|
107149
|
+
selected: selected === "individual",
|
|
107150
|
+
disabled: !canEditAudience,
|
|
107151
|
+
hideSelectedText: true
|
|
106281
107152
|
}
|
|
106282
107153
|
)
|
|
106283
107154
|
] })
|
|
106284
107155
|
] });
|
|
106285
107156
|
};
|
|
107157
|
+
const getDisplayName = (recipient) => {
|
|
107158
|
+
const fullName = `${recipient.firstName || ""} ${recipient.lastName || ""}`.trim();
|
|
107159
|
+
if (fullName) return fullName;
|
|
107160
|
+
if (recipient.firstName) return recipient.firstName;
|
|
107161
|
+
if (recipient.lastName) return recipient.lastName;
|
|
107162
|
+
if (recipient.email) return recipient.email;
|
|
107163
|
+
if (recipient.phone) return recipient.phone;
|
|
107164
|
+
return `Unnamed User`;
|
|
107165
|
+
};
|
|
107166
|
+
const SelectIndividualUsersContent = ({ selectedUserIds, onUserSelectionChange, canEditAudience = true }) => {
|
|
107167
|
+
const [tempSelectedUserIds, setTempSelectedUserIds] = useState(selectedUserIds);
|
|
107168
|
+
const [allUsersForDropdown, setAllUsersForDropdown] = useState();
|
|
107169
|
+
const { segments } = useListSegments();
|
|
107170
|
+
useEffect(() => {
|
|
107171
|
+
setTempSelectedUserIds(selectedUserIds);
|
|
107172
|
+
}, [selectedUserIds]);
|
|
107173
|
+
useEffect(() => {
|
|
107174
|
+
const fetchAllUsers = async () => {
|
|
107175
|
+
if (!segments) return;
|
|
107176
|
+
const allUsersSegment = segments.find(
|
|
107177
|
+
(segment2) => segment2.type === BusinessSegmentTypeEnum.ALL_USERS
|
|
107178
|
+
);
|
|
107179
|
+
if (allUsersSegment) {
|
|
107180
|
+
try {
|
|
107181
|
+
const allUsersResponse = await getCountOfBusinessAutomationRecipients(
|
|
107182
|
+
{
|
|
107183
|
+
includeSegments: [allUsersSegment.id],
|
|
107184
|
+
excludeSegments: []
|
|
107185
|
+
}
|
|
107186
|
+
);
|
|
107187
|
+
setAllUsersForDropdown(allUsersResponse);
|
|
107188
|
+
} catch (error2) {
|
|
107189
|
+
console.error("Error fetching all users for dropdown:", error2);
|
|
107190
|
+
}
|
|
107191
|
+
}
|
|
107192
|
+
};
|
|
107193
|
+
fetchAllUsers();
|
|
107194
|
+
}, [segments]);
|
|
107195
|
+
const userOptions = React__default.useMemo(() => {
|
|
107196
|
+
if (!allUsersForDropdown?.recipients) return [];
|
|
107197
|
+
return allUsersForDropdown.recipients.map((recipient) => ({
|
|
107198
|
+
label: getDisplayName(recipient),
|
|
107199
|
+
value: recipient.externalId
|
|
107200
|
+
}));
|
|
107201
|
+
}, [allUsersForDropdown?.recipients]);
|
|
107202
|
+
const handleUserSelectionChange = (newSelectedUserIds) => {
|
|
107203
|
+
setTempSelectedUserIds(newSelectedUserIds);
|
|
107204
|
+
onUserSelectionChange(newSelectedUserIds);
|
|
107205
|
+
};
|
|
107206
|
+
return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
|
|
107207
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
|
|
107208
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
107209
|
+
/* @__PURE__ */ jsx("h3", { className: "text-sm font-medium text-gray-900", children: "Select Individual Users" }),
|
|
107210
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm text-gray-500", children: "Choose specific users to include in your automation" })
|
|
107211
|
+
] }),
|
|
107212
|
+
selectedUserIds.length > 0 && /* @__PURE__ */ jsxs("div", { className: "text-sm text-gray-500", children: [
|
|
107213
|
+
selectedUserIds.length,
|
|
107214
|
+
" user",
|
|
107215
|
+
selectedUserIds.length !== 1 ? "s" : "",
|
|
107216
|
+
" selected"
|
|
107217
|
+
] })
|
|
107218
|
+
] }),
|
|
107219
|
+
/* @__PURE__ */ jsx(
|
|
107220
|
+
MultiSelectDialog,
|
|
107221
|
+
{
|
|
107222
|
+
options: userOptions,
|
|
107223
|
+
onValueChange: handleUserSelectionChange,
|
|
107224
|
+
selectedValues: tempSelectedUserIds,
|
|
107225
|
+
setSelectedValues: setTempSelectedUserIds,
|
|
107226
|
+
placeholder: "Select users...",
|
|
107227
|
+
title: "Select Individual Users",
|
|
107228
|
+
searchPlaceholder: "Search users...",
|
|
107229
|
+
emptyMessage: "No users found",
|
|
107230
|
+
canOpen: canEditAudience
|
|
107231
|
+
}
|
|
107232
|
+
)
|
|
107233
|
+
] });
|
|
107234
|
+
};
|
|
106286
107235
|
const SegmentSection = ({
|
|
106287
107236
|
segments,
|
|
106288
107237
|
allSegments,
|
|
@@ -106313,8 +107262,9 @@ const SegmentSection = ({
|
|
|
106313
107262
|
setSelectedValues: setSegmentSelectedIds,
|
|
106314
107263
|
options,
|
|
106315
107264
|
onValueChange: handleValueChange,
|
|
106316
|
-
placeholder:
|
|
107265
|
+
placeholder: `Select ${t$2("engage:segment", { count: 2 })}`,
|
|
106317
107266
|
maxCount: 5,
|
|
107267
|
+
title: `Select ${t$2("engage:segment", { count: 2 })}`,
|
|
106318
107268
|
extraCommandItems: [
|
|
106319
107269
|
(closePopup) => /* @__PURE__ */ jsxs(
|
|
106320
107270
|
CommandItem,
|
|
@@ -106408,7 +107358,7 @@ const SelectSegmentsContent = ({
|
|
|
106408
107358
|
const AutomationAudienceSelectorMain = ({ title: title2 = "Preview Audience" }) => {
|
|
106409
107359
|
const automation2 = useAutomation();
|
|
106410
107360
|
const [selectedAudience, setSelectedAudience] = useState(
|
|
106411
|
-
|
|
107361
|
+
AutomationAudienceSelectorType.ALL
|
|
106412
107362
|
);
|
|
106413
107363
|
const [includedSegments, setIncludedSegments] = useState(
|
|
106414
107364
|
automation2?.includeSegmentIds || []
|
|
@@ -106416,6 +107366,7 @@ const AutomationAudienceSelectorMain = ({ title: title2 = "Preview Audience" })
|
|
|
106416
107366
|
const [excludedSegments, setExcludedSegments] = useState(
|
|
106417
107367
|
automation2?.excludeSegmentIds || []
|
|
106418
107368
|
);
|
|
107369
|
+
const [selectedIndividualUserIds, setSelectedIndividualUserIds] = useState([]);
|
|
106419
107370
|
const [openCreateSegmentDialog, setOpenCreateSegmentDialog] = useState(false);
|
|
106420
107371
|
const [initialStateSet, setInitialStateSet] = useState(false);
|
|
106421
107372
|
const [selectedFilter, setSelectedFilter] = useState("all");
|
|
@@ -106427,35 +107378,58 @@ const AutomationAudienceSelectorMain = ({ title: title2 = "Preview Audience" })
|
|
|
106427
107378
|
const allUsersSelected = includedSegments.length === 1 && excludedSegments.length === 0 && segments?.find(
|
|
106428
107379
|
(segment2) => segment2.type === BusinessSegmentTypeEnum.ALL_USERS && segment2.id === includedSegments[0]
|
|
106429
107380
|
) !== void 0;
|
|
107381
|
+
const segmentIdToFetch = includedSegments.length === 1 && excludedSegments.length === 0 && !allUsersSelected ? includedSegments[0] : "";
|
|
107382
|
+
const { segment: singleSegment } = useGetSegment(segmentIdToFetch);
|
|
107383
|
+
const oneOffSegmentSelected = singleSegment?.type === BusinessSegmentTypeEnum.ONE_OFF;
|
|
106430
107384
|
useEffect(() => {
|
|
106431
|
-
|
|
106432
|
-
if (
|
|
106433
|
-
(
|
|
106434
|
-
|
|
106435
|
-
|
|
106436
|
-
|
|
106437
|
-
|
|
107385
|
+
const initializeState = async () => {
|
|
107386
|
+
if (automation2 && !initialStateSet && isLoading === false) {
|
|
107387
|
+
if (includedSegments.length === 1 && segments.find(
|
|
107388
|
+
(segment2) => segment2.type === BusinessSegmentTypeEnum.ALL_USERS && segment2.id === includedSegments[0]
|
|
107389
|
+
) !== void 0) {
|
|
107390
|
+
setSelectedAudience(AutomationAudienceSelectorType.ALL);
|
|
107391
|
+
} else if (oneOffSegmentSelected && singleSegment) {
|
|
107392
|
+
setSelectedAudience(AutomationAudienceSelectorType.INDIVIDUAL);
|
|
107393
|
+
if (singleSegment.conditions) {
|
|
107394
|
+
const userIds = [];
|
|
107395
|
+
singleSegment.conditions.forEach((condition) => {
|
|
107396
|
+
if (condition.field === "userId" && condition.operator === ConditionOperatorEnumType.EQUALS) {
|
|
107397
|
+
condition.value.forEach((val) => {
|
|
107398
|
+
if (typeof val === "string") {
|
|
107399
|
+
userIds.push(val);
|
|
107400
|
+
}
|
|
107401
|
+
});
|
|
107402
|
+
}
|
|
107403
|
+
});
|
|
107404
|
+
setSelectedIndividualUserIds(userIds);
|
|
107405
|
+
}
|
|
107406
|
+
} else {
|
|
107407
|
+
setSelectedAudience(AutomationAudienceSelectorType.SEGMENTS);
|
|
107408
|
+
}
|
|
107409
|
+
getCountOfBusinessAutomationRecipients({
|
|
107410
|
+
includeSegments: includedSegments,
|
|
107411
|
+
excludeSegments: excludedSegments
|
|
107412
|
+
}).then((response) => {
|
|
107413
|
+
setCountResponse(response);
|
|
107414
|
+
});
|
|
107415
|
+
setInitialStateSet(true);
|
|
106438
107416
|
}
|
|
106439
|
-
|
|
106440
|
-
|
|
106441
|
-
excludeSegments: excludedSegments
|
|
106442
|
-
}).then((response) => {
|
|
106443
|
-
setCountResponse(response);
|
|
106444
|
-
});
|
|
106445
|
-
setInitialStateSet(true);
|
|
106446
|
-
}
|
|
107417
|
+
};
|
|
107418
|
+
initializeState();
|
|
106447
107419
|
}, [
|
|
106448
107420
|
automation2,
|
|
106449
107421
|
allUsersSelected,
|
|
107422
|
+
oneOffSegmentSelected,
|
|
106450
107423
|
initialStateSet,
|
|
106451
107424
|
includedSegments,
|
|
106452
107425
|
excludedSegments,
|
|
106453
107426
|
segments,
|
|
106454
|
-
isLoading
|
|
107427
|
+
isLoading,
|
|
107428
|
+
singleSegment
|
|
106455
107429
|
]);
|
|
106456
|
-
const handleAudienceSelectionChange = (value) => {
|
|
107430
|
+
const handleAudienceSelectionChange = async (value) => {
|
|
106457
107431
|
setSelectedAudience(value);
|
|
106458
|
-
if (value ===
|
|
107432
|
+
if (value === AutomationAudienceSelectorType.ALL) {
|
|
106459
107433
|
const allUsersSegment = segments?.find(
|
|
106460
107434
|
(segment2) => segment2.type === BusinessSegmentTypeEnum.ALL_USERS
|
|
106461
107435
|
);
|
|
@@ -106465,6 +107439,61 @@ const AutomationAudienceSelectorMain = ({ title: title2 = "Preview Audience" })
|
|
|
106465
107439
|
}
|
|
106466
107440
|
setIncludedSegments([allUsersSegment.id]);
|
|
106467
107441
|
setExcludedSegments([]);
|
|
107442
|
+
setSelectedIndividualUserIds([]);
|
|
107443
|
+
} else if (value === AutomationAudienceSelectorType.INDIVIDUAL) {
|
|
107444
|
+
if (automation2?.id) {
|
|
107445
|
+
try {
|
|
107446
|
+
const segmentName = generateOneOffSegmentName(automation2.id);
|
|
107447
|
+
let segment2;
|
|
107448
|
+
try {
|
|
107449
|
+
segment2 = await findSegmentByName(segmentName);
|
|
107450
|
+
} catch (error2) {
|
|
107451
|
+
}
|
|
107452
|
+
if (segment2) {
|
|
107453
|
+
setIncludedSegments([segment2.id]);
|
|
107454
|
+
setExcludedSegments([]);
|
|
107455
|
+
if (segment2.conditions) {
|
|
107456
|
+
const userIds = [];
|
|
107457
|
+
segment2.conditions.forEach((condition) => {
|
|
107458
|
+
if (condition.field === "userId" && condition.operator === ConditionOperatorEnumType.EQUALS) {
|
|
107459
|
+
condition.value.forEach((val) => {
|
|
107460
|
+
if (typeof val === "string") {
|
|
107461
|
+
userIds.push(val);
|
|
107462
|
+
}
|
|
107463
|
+
});
|
|
107464
|
+
}
|
|
107465
|
+
});
|
|
107466
|
+
setSelectedIndividualUserIds(userIds);
|
|
107467
|
+
}
|
|
107468
|
+
} else {
|
|
107469
|
+
const newSegment = await createSegment({
|
|
107470
|
+
name: segmentName,
|
|
107471
|
+
description: "One-off segment for individual user selection",
|
|
107472
|
+
type: BusinessSegmentTypeEnum.ONE_OFF,
|
|
107473
|
+
conditions: [
|
|
107474
|
+
{
|
|
107475
|
+
field: "userId",
|
|
107476
|
+
operator: ConditionOperatorEnumType.EQUALS,
|
|
107477
|
+
value: []
|
|
107478
|
+
}
|
|
107479
|
+
]
|
|
107480
|
+
});
|
|
107481
|
+
if (newSegment?.id) {
|
|
107482
|
+
setIncludedSegments([newSegment.id]);
|
|
107483
|
+
setExcludedSegments([]);
|
|
107484
|
+
}
|
|
107485
|
+
}
|
|
107486
|
+
} catch (error2) {
|
|
107487
|
+
console.error("Error creating ONE_OFF segment:", error2);
|
|
107488
|
+
}
|
|
107489
|
+
}
|
|
107490
|
+
} else if (value === AutomationAudienceSelectorType.SEGMENTS) {
|
|
107491
|
+
setIncludedSegments([]);
|
|
107492
|
+
setExcludedSegments([]);
|
|
107493
|
+
setCountResponse({
|
|
107494
|
+
count: 0,
|
|
107495
|
+
recipients: []
|
|
107496
|
+
});
|
|
106468
107497
|
}
|
|
106469
107498
|
};
|
|
106470
107499
|
const handleAddSegment = (segmentId, type) => {
|
|
@@ -106481,8 +107510,75 @@ const AutomationAudienceSelectorMain = ({ title: title2 = "Preview Audience" })
|
|
|
106481
107510
|
setExcludedSegments((prev) => prev.filter((id2) => id2 !== segmentId));
|
|
106482
107511
|
}
|
|
106483
107512
|
};
|
|
107513
|
+
const handleIndividualUserSelectionChange = async (userIds) => {
|
|
107514
|
+
setSelectedIndividualUserIds(userIds);
|
|
107515
|
+
if (automation2?.id) {
|
|
107516
|
+
try {
|
|
107517
|
+
const segmentName = generateOneOffSegmentName(automation2.id);
|
|
107518
|
+
let segment2;
|
|
107519
|
+
try {
|
|
107520
|
+
segment2 = await findSegmentByName(segmentName);
|
|
107521
|
+
} catch (error2) {
|
|
107522
|
+
}
|
|
107523
|
+
if (segment2) {
|
|
107524
|
+
const updatedSegment = await updateSegment(segment2.id, {
|
|
107525
|
+
conditions: userIds.length > 0 ? [
|
|
107526
|
+
{
|
|
107527
|
+
field: "userId",
|
|
107528
|
+
operator: ConditionOperatorEnumType.EQUALS,
|
|
107529
|
+
value: userIds
|
|
107530
|
+
}
|
|
107531
|
+
] : [
|
|
107532
|
+
{
|
|
107533
|
+
field: "userId",
|
|
107534
|
+
operator: ConditionOperatorEnumType.EQUALS,
|
|
107535
|
+
value: []
|
|
107536
|
+
}
|
|
107537
|
+
]
|
|
107538
|
+
});
|
|
107539
|
+
segment2 = updatedSegment;
|
|
107540
|
+
} else {
|
|
107541
|
+
segment2 = await createSegment({
|
|
107542
|
+
name: segmentName,
|
|
107543
|
+
description: "One-off segment for individual user selection",
|
|
107544
|
+
type: BusinessSegmentTypeEnum.ONE_OFF,
|
|
107545
|
+
conditions: userIds.length > 0 ? [
|
|
107546
|
+
{
|
|
107547
|
+
field: "userId",
|
|
107548
|
+
operator: ConditionOperatorEnumType.EQUALS,
|
|
107549
|
+
value: userIds
|
|
107550
|
+
}
|
|
107551
|
+
] : [
|
|
107552
|
+
{
|
|
107553
|
+
field: "userId",
|
|
107554
|
+
operator: ConditionOperatorEnumType.EQUALS,
|
|
107555
|
+
value: []
|
|
107556
|
+
}
|
|
107557
|
+
]
|
|
107558
|
+
});
|
|
107559
|
+
}
|
|
107560
|
+
if (segment2?.id) {
|
|
107561
|
+
await updateAutomation2({
|
|
107562
|
+
includeSegments: [segment2.id],
|
|
107563
|
+
excludeSegments: []
|
|
107564
|
+
});
|
|
107565
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
107566
|
+
const countResponse2 = await getCountOfBusinessAutomationRecipients({
|
|
107567
|
+
includeSegments: [segment2.id],
|
|
107568
|
+
excludeSegments: []
|
|
107569
|
+
});
|
|
107570
|
+
setCountResponse(countResponse2);
|
|
107571
|
+
}
|
|
107572
|
+
} catch (error2) {
|
|
107573
|
+
console.error("Error creating/updating ONE_OFF segment:", error2);
|
|
107574
|
+
}
|
|
107575
|
+
}
|
|
107576
|
+
};
|
|
106484
107577
|
useEffect(() => {
|
|
106485
107578
|
if (automation2 && initialStateSet) {
|
|
107579
|
+
if (selectedAudience === AutomationAudienceSelectorType.INDIVIDUAL && includedSegments.length === 0 && excludedSegments.length === 0) {
|
|
107580
|
+
return;
|
|
107581
|
+
}
|
|
106486
107582
|
if (JSON.stringify(includedSegments) !== JSON.stringify(automation2.includeSegmentIds) || JSON.stringify(excludedSegments) !== JSON.stringify(automation2.excludeSegmentIds)) {
|
|
106487
107583
|
updateAutomation2({
|
|
106488
107584
|
includeSegments: includedSegments,
|
|
@@ -106501,7 +107597,8 @@ const AutomationAudienceSelectorMain = ({ title: title2 = "Preview Audience" })
|
|
|
106501
107597
|
excludedSegments,
|
|
106502
107598
|
automation2,
|
|
106503
107599
|
initialStateSet,
|
|
106504
|
-
updateAutomation2
|
|
107600
|
+
updateAutomation2,
|
|
107601
|
+
selectedAudience
|
|
106505
107602
|
]);
|
|
106506
107603
|
const onSegmentUpdated = (id2) => {
|
|
106507
107604
|
if (id2) {
|
|
@@ -106528,7 +107625,7 @@ const AutomationAudienceSelectorMain = ({ title: title2 = "Preview Audience" })
|
|
|
106528
107625
|
canEditAudience
|
|
106529
107626
|
}
|
|
106530
107627
|
),
|
|
106531
|
-
/* @__PURE__ */ jsx(AnimatePresence, { children: selectedAudience ===
|
|
107628
|
+
/* @__PURE__ */ jsx(AnimatePresence, { children: selectedAudience === AutomationAudienceSelectorType.SEGMENTS && /* @__PURE__ */ jsx(
|
|
106532
107629
|
motion.div,
|
|
106533
107630
|
{
|
|
106534
107631
|
initial: { opacity: 0, height: 0 },
|
|
@@ -106550,13 +107647,33 @@ const AutomationAudienceSelectorMain = ({ title: title2 = "Preview Audience" })
|
|
|
106550
107647
|
}
|
|
106551
107648
|
)
|
|
106552
107649
|
}
|
|
107650
|
+
) }),
|
|
107651
|
+
/* @__PURE__ */ jsx(AnimatePresence, { children: selectedAudience === AutomationAudienceSelectorType.INDIVIDUAL && /* @__PURE__ */ jsx(
|
|
107652
|
+
motion.div,
|
|
107653
|
+
{
|
|
107654
|
+
initial: { opacity: 0, height: 0 },
|
|
107655
|
+
animate: { opacity: 1, height: "auto" },
|
|
107656
|
+
exit: { opacity: 0, height: 0 },
|
|
107657
|
+
transition: { duration: 0.3, ease: "easeInOut" },
|
|
107658
|
+
className: "w-full pt-4",
|
|
107659
|
+
children: /* @__PURE__ */ jsx(
|
|
107660
|
+
SelectIndividualUsersContent,
|
|
107661
|
+
{
|
|
107662
|
+
countResponse,
|
|
107663
|
+
selectedUserIds: selectedIndividualUserIds,
|
|
107664
|
+
onUserSelectionChange: handleIndividualUserSelectionChange,
|
|
107665
|
+
canEditAudience
|
|
107666
|
+
}
|
|
107667
|
+
)
|
|
107668
|
+
}
|
|
106553
107669
|
) })
|
|
106554
107670
|
] }),
|
|
106555
107671
|
/* @__PURE__ */ jsx("div", { className: "flex flex-col flex-1 relative overflow-hidden", children: countResponse?.recipients && /* @__PURE__ */ jsx(
|
|
106556
107672
|
RecipientsTable,
|
|
106557
107673
|
{
|
|
106558
107674
|
recipients: countResponse.recipients,
|
|
106559
|
-
filter: selectedFilter
|
|
107675
|
+
filter: selectedFilter,
|
|
107676
|
+
audienceMode: selectedAudience
|
|
106560
107677
|
}
|
|
106561
107678
|
) })
|
|
106562
107679
|
] }),
|
|
@@ -106997,7 +108114,7 @@ const validateAutomationStep = async (args) => {
|
|
|
106997
108114
|
const smsChannelSender = smsChannelSenders.find(
|
|
106998
108115
|
(sender) => sender.channelSender.id === communicationGroup.smsChannelSenderId
|
|
106999
108116
|
);
|
|
107000
|
-
if (!smsChannelSender) {
|
|
108117
|
+
if (!smsChannelSender && !communicationGroup.emailChannelSenderId) {
|
|
107001
108118
|
return {
|
|
107002
108119
|
canMove: false,
|
|
107003
108120
|
errorMessage: "Please ensure you have selected a text sender"
|
|
@@ -107009,7 +108126,7 @@ const validateAutomationStep = async (args) => {
|
|
|
107009
108126
|
errorMessage: "Please ensure you have a text body"
|
|
107010
108127
|
};
|
|
107011
108128
|
}
|
|
107012
|
-
if (smsChannelSender.smsApplication && smsChannelSender.smsApplication.status !== SmsRegistrationApplicationStatus.APPROVED) {
|
|
108129
|
+
if (smsChannelSender && smsChannelSender.smsApplication && smsChannelSender.smsApplication.status !== SmsRegistrationApplicationStatus.APPROVED) {
|
|
107013
108130
|
return {
|
|
107014
108131
|
canMove: true,
|
|
107015
108132
|
errorMessage: null,
|
|
@@ -107037,10 +108154,10 @@ const validateAutomationStep = async (args) => {
|
|
|
107037
108154
|
errorMessage: "Please ensure you have selected a communication group"
|
|
107038
108155
|
};
|
|
107039
108156
|
}
|
|
107040
|
-
if (!communicationGroup.emailChannelSenderId) {
|
|
108157
|
+
if (!communicationGroup.emailChannelSenderId && !communicationGroup.smsChannelSenderId) {
|
|
107041
108158
|
return {
|
|
107042
108159
|
canMove: false,
|
|
107043
|
-
errorMessage: "Please ensure you have selected
|
|
108160
|
+
errorMessage: "Please ensure you have selected an email or SMS sender"
|
|
107044
108161
|
};
|
|
107045
108162
|
}
|
|
107046
108163
|
if (!communicationGroup.emailHtmlBody || !communicationGroup.emailSubject) {
|
|
@@ -107359,6 +108476,8 @@ const OneTimeWizardMain = ({ onFinish, getExtraMergeFields, onBeforeSchedule })
|
|
|
107359
108476
|
if (currentStep > AutomationSteps.SelectAudience) {
|
|
107360
108477
|
if (currentStep === AutomationSteps.EditSmsContent && selectedChannels.length === 1 && selectedChannels[0] === "sms") {
|
|
107361
108478
|
setCurrentStep(currentStep - 2);
|
|
108479
|
+
} else if (currentStep === AutomationSteps.Schedule && selectedChannels.length === 1 && selectedChannels[0] === "email") {
|
|
108480
|
+
setCurrentStep(currentStep - 2);
|
|
107362
108481
|
} else {
|
|
107363
108482
|
setCurrentStep(currentStep - 1);
|
|
107364
108483
|
}
|
|
@@ -107754,8 +108873,7 @@ function CreateAutomationDialog({
|
|
|
107754
108873
|
replyToSettingsText,
|
|
107755
108874
|
replyToSettingsLink,
|
|
107756
108875
|
fromNameSettingsText,
|
|
107757
|
-
fromNameSettingsLink
|
|
107758
|
-
onBeforeSchedule
|
|
108876
|
+
fromNameSettingsLink
|
|
107759
108877
|
}) {
|
|
107760
108878
|
const onCloseInner = (createdAutomation) => {
|
|
107761
108879
|
onClose?.(createdAutomation);
|
|
@@ -107795,8 +108913,7 @@ function CreateAutomationDialog({
|
|
|
107795
108913
|
automationType,
|
|
107796
108914
|
currentStep,
|
|
107797
108915
|
setCurrentStep,
|
|
107798
|
-
getExtraMergeFields
|
|
107799
|
-
onBeforeSchedule
|
|
108916
|
+
getExtraMergeFields
|
|
107800
108917
|
}
|
|
107801
108918
|
)
|
|
107802
108919
|
]
|
|
@@ -108016,14 +109133,20 @@ const generateBrandSettings = async () => {
|
|
|
108016
109133
|
return response.data;
|
|
108017
109134
|
};
|
|
108018
109135
|
const useBrandSettingsMutation = () => {
|
|
109136
|
+
const { sendNotificationAsync } = useSlackNotification();
|
|
108019
109137
|
return useMutation({
|
|
108020
109138
|
mutationFn: generateBrandSettings,
|
|
108021
109139
|
mutationKey: websiteContentKeys.brandSettings(),
|
|
108022
|
-
onSuccess: () => {
|
|
109140
|
+
onSuccess: (data) => {
|
|
108023
109141
|
toast({
|
|
108024
109142
|
title: "Brand settings generated successfully!",
|
|
108025
109143
|
description: "Your brand identity has been analyzed."
|
|
108026
109144
|
});
|
|
109145
|
+
sendNotificationAsync({
|
|
109146
|
+
message: "💬 New brand settings generated",
|
|
109147
|
+
product: "engage",
|
|
109148
|
+
details: { brandSettingsResponse: data }
|
|
109149
|
+
});
|
|
108027
109150
|
},
|
|
108028
109151
|
onError: () => {
|
|
108029
109152
|
toast({
|
|
@@ -109460,6 +110583,123 @@ const EmailChannelStep = ({
|
|
|
109460
110583
|
}
|
|
109461
110584
|
);
|
|
109462
110585
|
};
|
|
110586
|
+
const MergeFieldForm = forwardRef(({ onSubmit }, ref) => {
|
|
110587
|
+
const { getMergeFields: getMergeFields2, isGetting, getError } = useGetMergeFields("all");
|
|
110588
|
+
const { data: business } = useBusiness();
|
|
110589
|
+
const [fallbacks, setFallbacks] = useState([]);
|
|
110590
|
+
useEffect(() => {
|
|
110591
|
+
if (getMergeFields2?.mergeFields && business) {
|
|
110592
|
+
setFallbacks(
|
|
110593
|
+
getMergeFields2.mergeFields.flatMap(
|
|
110594
|
+
(category) => category.entries.map((entry) => ({
|
|
110595
|
+
label: entry.label,
|
|
110596
|
+
value: entry.value,
|
|
110597
|
+
// Keep the template name (value) for backend
|
|
110598
|
+
fallbackValue: business.merge_field_fallbacks[entry.label] || ""
|
|
110599
|
+
}))
|
|
110600
|
+
)
|
|
110601
|
+
);
|
|
110602
|
+
}
|
|
110603
|
+
}, [getMergeFields2, business]);
|
|
110604
|
+
const handleFallbackChange = (index2, value) => {
|
|
110605
|
+
setFallbacks(
|
|
110606
|
+
(fallbacks2) => fallbacks2.map(
|
|
110607
|
+
(f2, i3) => i3 === index2 ? { ...f2, fallbackValue: value } : f2
|
|
110608
|
+
)
|
|
110609
|
+
);
|
|
110610
|
+
};
|
|
110611
|
+
const handleSubmit = (e4) => {
|
|
110612
|
+
e4.preventDefault();
|
|
110613
|
+
onSubmit(fallbacks);
|
|
110614
|
+
};
|
|
110615
|
+
useImperativeHandle(
|
|
110616
|
+
ref,
|
|
110617
|
+
() => ({
|
|
110618
|
+
submit: () => {
|
|
110619
|
+
onSubmit(fallbacks);
|
|
110620
|
+
},
|
|
110621
|
+
getData: () => fallbacks
|
|
110622
|
+
}),
|
|
110623
|
+
[fallbacks, onSubmit]
|
|
110624
|
+
);
|
|
110625
|
+
const hasMergeFields = Array.isArray(getMergeFields2?.mergeFields) && getMergeFields2.mergeFields.some(
|
|
110626
|
+
(category) => Array.isArray(category.entries) && category.entries.length > 0
|
|
110627
|
+
);
|
|
110628
|
+
if (isGetting) {
|
|
110629
|
+
return /* @__PURE__ */ jsx("div", { className: "py-8", children: /* @__PURE__ */ jsx(BasicLoader, { text: "Loading merge fields..." }) });
|
|
110630
|
+
}
|
|
110631
|
+
if (getError) {
|
|
110632
|
+
return /* @__PURE__ */ jsx("div", { className: "py-8 text-center text-destructive", children: "Error loading merge fields" });
|
|
110633
|
+
}
|
|
110634
|
+
if (!hasMergeFields) {
|
|
110635
|
+
return /* @__PURE__ */ jsx("div", { className: "py-8 text-center text-muted-foreground", children: "No merge fields available" });
|
|
110636
|
+
}
|
|
110637
|
+
return /* @__PURE__ */ jsx("form", { onSubmit: handleSubmit, className: "space-y-6 p-8", children: /* @__PURE__ */ jsx("div", { className: "overflow-x-auto", children: /* @__PURE__ */ jsxs("table", { className: "min-w-full border-separate border-spacing-y-2", children: [
|
|
110638
|
+
/* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { children: [
|
|
110639
|
+
/* @__PURE__ */ jsx("th", { className: "text-left text-sm font-semibold text-foreground pb-2", children: "Merge Field" }),
|
|
110640
|
+
/* @__PURE__ */ jsx("th", { className: "text-left text-sm font-semibold text-foreground pb-2", children: "Fallback Value" })
|
|
110641
|
+
] }) }),
|
|
110642
|
+
/* @__PURE__ */ jsx("tbody", { children: fallbacks.map((field, idx) => /* @__PURE__ */ jsxs("tr", { className: "align-top", children: [
|
|
110643
|
+
/* @__PURE__ */ jsx("td", { className: "pr-4 py-1 text-base text-foreground whitespace-nowrap", children: field.label }),
|
|
110644
|
+
/* @__PURE__ */ jsx("td", { className: "py-1", children: /* @__PURE__ */ jsx(
|
|
110645
|
+
Input,
|
|
110646
|
+
{
|
|
110647
|
+
value: field.fallbackValue,
|
|
110648
|
+
onChange: (e4) => handleFallbackChange(idx, e4.target.value),
|
|
110649
|
+
placeholder: "Enter fallback value",
|
|
110650
|
+
className: "w-full max-w-xs"
|
|
110651
|
+
}
|
|
110652
|
+
) })
|
|
110653
|
+
] }, field.value)) })
|
|
110654
|
+
] }) }) });
|
|
110655
|
+
});
|
|
110656
|
+
const MergeFieldSettings = ({
|
|
110657
|
+
onBack,
|
|
110658
|
+
title: title2,
|
|
110659
|
+
description: description2
|
|
110660
|
+
}) => {
|
|
110661
|
+
const { navigation } = useEngageSettingsContext();
|
|
110662
|
+
const { postBusinessMergeFieldFallbacks: postBusinessMergeFieldFallbacks2, isPosting, postError } = usePostBusinessMergeFieldFallbacks();
|
|
110663
|
+
const wizardContext = useContext(
|
|
110664
|
+
WizardContext
|
|
110665
|
+
);
|
|
110666
|
+
const goToPreviousStep = onBack || wizardContext?.goToPreviousStep || navigation?.goToPreviousStep || (() => {
|
|
110667
|
+
});
|
|
110668
|
+
const stepTitle = title2 || ENGAGE_STRINGS.MERGE_FIELDS_TITLE;
|
|
110669
|
+
const stepDescription = description2 || "Manage merge fields for personalizing your communications with dynamic content.";
|
|
110670
|
+
const formRef = useRef(null);
|
|
110671
|
+
const handleFormSubmit = () => {
|
|
110672
|
+
if (formRef.current) {
|
|
110673
|
+
const mergeFields = formRef.current.getData();
|
|
110674
|
+
const mapping = Object.fromEntries(
|
|
110675
|
+
mergeFields.filter((field) => field.fallbackValue.trim()).map((field) => [
|
|
110676
|
+
field.value.replace(/[{}]/g, ""),
|
|
110677
|
+
// Remove {{}} syntax
|
|
110678
|
+
field.fallbackValue.trim()
|
|
110679
|
+
])
|
|
110680
|
+
);
|
|
110681
|
+
postBusinessMergeFieldFallbacks2({
|
|
110682
|
+
mergeFieldFallbacks: mapping
|
|
110683
|
+
});
|
|
110684
|
+
}
|
|
110685
|
+
};
|
|
110686
|
+
return /* @__PURE__ */ jsxs(
|
|
110687
|
+
WizardFormWrapper,
|
|
110688
|
+
{
|
|
110689
|
+
title: stepTitle,
|
|
110690
|
+
description: stepDescription,
|
|
110691
|
+
onBack: goToPreviousStep,
|
|
110692
|
+
onNext: handleFormSubmit,
|
|
110693
|
+
submitLabel: "Save",
|
|
110694
|
+
mode: "settings",
|
|
110695
|
+
isSubmitting: isPosting,
|
|
110696
|
+
children: [
|
|
110697
|
+
postError && /* @__PURE__ */ jsx("div", { className: "text-destructive text-center py-2", children: "Error saving merge fields" }),
|
|
110698
|
+
/* @__PURE__ */ jsx(MergeFieldForm, { ref: formRef, onSubmit: handleFormSubmit })
|
|
110699
|
+
]
|
|
110700
|
+
}
|
|
110701
|
+
);
|
|
110702
|
+
};
|
|
109463
110703
|
const SMSChannelSettings = ({
|
|
109464
110704
|
hideSubmitButton = false,
|
|
109465
110705
|
formRef,
|
|
@@ -109724,7 +110964,8 @@ const EngageSettings = () => {
|
|
|
109724
110964
|
[ENGAGE_STEPS.BRAND]: /* @__PURE__ */ jsx(BrandSettingsStep, {}),
|
|
109725
110965
|
[ENGAGE_STEPS.BUSINESS]: /* @__PURE__ */ jsx(BusinessSettingsStep, {}),
|
|
109726
110966
|
[ENGAGE_STEPS.EMAIL]: /* @__PURE__ */ jsx(EmailChannelStep, {}),
|
|
109727
|
-
[ENGAGE_STEPS.SMS]: /* @__PURE__ */ jsx(SMSChannelStep, {})
|
|
110967
|
+
[ENGAGE_STEPS.SMS]: /* @__PURE__ */ jsx(SMSChannelStep, {}),
|
|
110968
|
+
[ENGAGE_STEPS.MERGE_FIELDS]: /* @__PURE__ */ jsx(MergeFieldSettings, {})
|
|
109728
110969
|
}[currentStep] || null
|
|
109729
110970
|
}
|
|
109730
110971
|
);
|
|
@@ -110108,6 +111349,7 @@ const EngageOnboarding = () => {
|
|
|
110108
111349
|
[ENGAGE_STEPS.BUSINESS_SKIP_INTERSTITIAL]: /* @__PURE__ */ jsx(BusinessSkipInterstitialStep, {}),
|
|
110109
111350
|
[ENGAGE_STEPS.SMS_INTERSTITIAL]: /* @__PURE__ */ jsx(SMSInterstitialStep, {}),
|
|
110110
111351
|
[ENGAGE_STEPS.SMS]: /* @__PURE__ */ jsx(SMSChannelStep, {}),
|
|
111352
|
+
[ENGAGE_STEPS.MERGE_FIELDS]: /* @__PURE__ */ jsx(MergeFieldSettings, { isOnboarding: true }),
|
|
110111
111353
|
[ENGAGE_STEPS.COMPLETION]: /* @__PURE__ */ jsx(CompletionStep, {})
|
|
110112
111354
|
};
|
|
110113
111355
|
const handleOpenChange = (isOpen) => {
|
|
@@ -110809,6 +112051,9 @@ function SegmentList() {
|
|
|
110809
112051
|
case BusinessSegmentTypeEnum.MANAGED:
|
|
110810
112052
|
typeOfSegment = "Managed";
|
|
110811
112053
|
break;
|
|
112054
|
+
case BusinessSegmentTypeEnum.ONE_OFF:
|
|
112055
|
+
typeOfSegment = "One-off";
|
|
112056
|
+
break;
|
|
110812
112057
|
default:
|
|
110813
112058
|
throw UnreachableCaseStatement(
|
|
110814
112059
|
row.type,
|
|
@@ -111219,10 +112464,6 @@ function InlineEditor({
|
|
|
111219
112464
|
}
|
|
111220
112465
|
) });
|
|
111221
112466
|
}
|
|
111222
|
-
const capitalize = (str) => {
|
|
111223
|
-
if (!str) return str;
|
|
111224
|
-
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
111225
|
-
};
|
|
111226
112467
|
function AutomationCancelRunningDialog({
|
|
111227
112468
|
open,
|
|
111228
112469
|
onOpenChange
|
|
@@ -111738,6 +112979,7 @@ const AutomationsEditorHeader = ({ showBackButton, onDuplicationCreated, onBefor
|
|
|
111738
112979
|
);
|
|
111739
112980
|
const noEmailSubjectORnoEmailHtmlBody = communicationGroup?.emailChannelSenderId && (!communicationGroup?.emailSubject || !communicationGroup?.emailHtmlBody);
|
|
111740
112981
|
const noSmsMessageBody = communicationGroup?.smsChannelSenderId && !communicationGroup?.smsMessageBody;
|
|
112982
|
+
const noIncludeSegments = automation2.includeSegmentIds?.length === 0;
|
|
111741
112983
|
const missingScheduledAt = automationOneTime && (!automation2.triggerMetadata || !("scheduledAt" in automation2.triggerMetadata) || !automation2.triggerMetadata?.scheduledAt);
|
|
111742
112984
|
let disableSwitch = false;
|
|
111743
112985
|
let showSwitch = true;
|
|
@@ -111751,7 +112993,7 @@ const AutomationsEditorHeader = ({ showBackButton, onDuplicationCreated, onBefor
|
|
|
111751
112993
|
/**
|
|
111752
112994
|
* If we have a emailChannelSenderId, we need to have a emailSubject and emailHtmlBody
|
|
111753
112995
|
*/
|
|
111754
|
-
noEmailANDnoSmsSender || noEmailSubjectORnoEmailHtmlBody || noSmsMessageBody
|
|
112996
|
+
noEmailANDnoSmsSender || noEmailSubjectORnoEmailHtmlBody || noSmsMessageBody || noIncludeSegments
|
|
111755
112997
|
) {
|
|
111756
112998
|
disableSwitch = true;
|
|
111757
112999
|
if (noEmailSubjectORnoEmailHtmlBody) {
|
|
@@ -111760,6 +113002,9 @@ const AutomationsEditorHeader = ({ showBackButton, onDuplicationCreated, onBefor
|
|
|
111760
113002
|
if (noSmsMessageBody) {
|
|
111761
113003
|
infoOnDisabled = "Missing SMS message in SMS communication";
|
|
111762
113004
|
}
|
|
113005
|
+
if (noIncludeSegments) {
|
|
113006
|
+
infoOnDisabled = "Missing include segment";
|
|
113007
|
+
}
|
|
111763
113008
|
}
|
|
111764
113009
|
if (missingScheduledAt) {
|
|
111765
113010
|
disableSwitch = true;
|
|
@@ -111858,7 +113103,7 @@ const AutomationsEditorHeader = ({ showBackButton, onDuplicationCreated, onBefor
|
|
|
111858
113103
|
}
|
|
111859
113104
|
);
|
|
111860
113105
|
}
|
|
111861
|
-
if (noTriggerMetadata || oneTimeNoScheduledAt || noEmailANDnoSmsSender || smsApplicationNotApproved || noEmailSubjectORnoEmailHtmlBody || noSmsMessageBody) {
|
|
113106
|
+
if (noTriggerMetadata || oneTimeNoScheduledAt || noEmailANDnoSmsSender || smsApplicationNotApproved || noEmailSubjectORnoEmailHtmlBody || noSmsMessageBody || noIncludeSegments) {
|
|
111862
113107
|
const renderInfoTooltip = () => {
|
|
111863
113108
|
const sendText = automation2.triggerMetadata && "scheduledAt" in automation2.triggerMetadata && automation2.triggerMetadata?.scheduledAt === "now" ? `Start ${automationLanguage}` : "Schedule Send";
|
|
111864
113109
|
if (automation2.status !== AutomationStatus.DRAFT) {
|
|
@@ -111900,6 +113145,13 @@ const AutomationsEditorHeader = ({ showBackButton, onDuplicationCreated, onBefor
|
|
|
111900
113145
|
"Please add a message to your SMS communication"
|
|
111901
113146
|
);
|
|
111902
113147
|
}
|
|
113148
|
+
if (noIncludeSegments) {
|
|
113149
|
+
alertMessages.push(
|
|
113150
|
+
`Please select at least one ${t$2("engage:segment", {
|
|
113151
|
+
count: 1
|
|
113152
|
+
}).toLowerCase()}`
|
|
113153
|
+
);
|
|
113154
|
+
}
|
|
111903
113155
|
const formattedMessages = alertMessages.map(
|
|
111904
113156
|
(msg) => capitalize(msg)
|
|
111905
113157
|
);
|
|
@@ -112174,7 +113426,8 @@ const AutomationRecipientsTable = () => {
|
|
|
112174
113426
|
automationId: automation2?.id ?? "",
|
|
112175
113427
|
cursor: cursorForQuery,
|
|
112176
113428
|
limit: pageSizeForQuery,
|
|
112177
|
-
search: searchQuery || void 0
|
|
113429
|
+
search: searchQuery || void 0,
|
|
113430
|
+
automationStatus: automation2?.status
|
|
112178
113431
|
});
|
|
112179
113432
|
const handleQueryParametersChange = useCallback(
|
|
112180
113433
|
(params) => {
|
|
@@ -114584,47 +115837,32 @@ const AutomationAudienceSelector = () => {
|
|
|
114584
115837
|
setActionId: setActionId2,
|
|
114585
115838
|
state: { selectedActionId }
|
|
114586
115839
|
} = useContext(Context$1);
|
|
114587
|
-
const [includeSegmentIds, setIncludeSegmentIds] = useState(
|
|
114588
|
-
automation2?.includeSegmentIds || null
|
|
114589
|
-
);
|
|
114590
|
-
const [excludeSegmentIds, setExcludeSegmentIds] = useState(
|
|
114591
|
-
automation2?.excludeSegmentIds || null
|
|
114592
|
-
);
|
|
114593
115840
|
const { segments } = useListSegments();
|
|
114594
|
-
const
|
|
114595
|
-
|
|
114596
|
-
|
|
114597
|
-
);
|
|
114598
|
-
}, [segments]);
|
|
114599
|
-
useEffect(() => {
|
|
114600
|
-
if (!automation2 || !segments) {
|
|
114601
|
-
return;
|
|
114602
|
-
}
|
|
114603
|
-
if (includeSegmentIds === null && excludeSegmentIds === null) {
|
|
114604
|
-
setIncludeSegmentIds(automation2?.includeSegmentIds || null);
|
|
114605
|
-
setExcludeSegmentIds(automation2?.excludeSegmentIds || null);
|
|
114606
|
-
if (automation2.includeSegmentIds.length === 0 && automation2.excludeSegmentIds.length === 0) {
|
|
114607
|
-
setIncludeSegmentIds([getAllUsersSegment()?.id || ""]);
|
|
114608
|
-
setExcludeSegmentIds([]);
|
|
114609
|
-
}
|
|
114610
|
-
} else {
|
|
114611
|
-
if (JSON.stringify(automation2.includeSegmentIds) !== JSON.stringify(includeSegmentIds)) {
|
|
114612
|
-
setIncludeSegmentIds(automation2.includeSegmentIds);
|
|
114613
|
-
}
|
|
114614
|
-
if (JSON.stringify(automation2.excludeSegmentIds) !== JSON.stringify(excludeSegmentIds)) {
|
|
114615
|
-
setExcludeSegmentIds(automation2.excludeSegmentIds);
|
|
114616
|
-
}
|
|
114617
|
-
}
|
|
114618
|
-
}, [
|
|
114619
|
-
automation2,
|
|
114620
|
-
excludeSegmentIds,
|
|
114621
|
-
includeSegmentIds,
|
|
114622
|
-
segments,
|
|
114623
|
-
getAllUsersSegment
|
|
114624
|
-
]);
|
|
114625
|
-
if (!automation2 || !includeSegmentIds || !excludeSegmentIds) {
|
|
115841
|
+
const segmentIdToFetch = automation2?.includeSegmentIds?.length === 1 && automation2?.excludeSegmentIds?.length === 0 ? automation2.includeSegmentIds[0] : "";
|
|
115842
|
+
const { segment: singleSegment } = useGetSegment(segmentIdToFetch);
|
|
115843
|
+
if (!automation2 || !segments) {
|
|
114626
115844
|
return null;
|
|
114627
115845
|
}
|
|
115846
|
+
const includeSegmentIds = automation2.includeSegmentIds;
|
|
115847
|
+
let copyText;
|
|
115848
|
+
let showSegmentPills = true;
|
|
115849
|
+
if (singleSegment?.type === BusinessSegmentTypeEnum.ALL_USERS) {
|
|
115850
|
+
copyText = `Send to all ${t$2("engage:user", { count: 2 })}`;
|
|
115851
|
+
showSegmentPills = false;
|
|
115852
|
+
} else if (singleSegment?.type === BusinessSegmentTypeEnum.ONE_OFF) {
|
|
115853
|
+
copyText = `Send to specific ${t$2("engage:user", { count: 2 })}`;
|
|
115854
|
+
showSegmentPills = false;
|
|
115855
|
+
} else {
|
|
115856
|
+
copyText = `Send to all ${t$2("engage:user", {
|
|
115857
|
+
count: 2
|
|
115858
|
+
})} in ${includeSegmentIds.length === 1 ? "this" : "these"} ${t$2(
|
|
115859
|
+
"engage:segment",
|
|
115860
|
+
{
|
|
115861
|
+
count: includeSegmentIds.length
|
|
115862
|
+
}
|
|
115863
|
+
).toLowerCase()}`;
|
|
115864
|
+
showSegmentPills = true;
|
|
115865
|
+
}
|
|
114628
115866
|
return /* @__PURE__ */ jsx(Fragment$1, { children: /* @__PURE__ */ jsx(
|
|
114629
115867
|
BasicsButton,
|
|
114630
115868
|
{
|
|
@@ -114638,20 +115876,8 @@ const AutomationAudienceSelector = () => {
|
|
|
114638
115876
|
children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-0.5 flex-1", children: [
|
|
114639
115877
|
/* @__PURE__ */ jsx(MinorText, { children: "Audience" }),
|
|
114640
115878
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 flex-wrap", children: [
|
|
114641
|
-
/* @__PURE__ */ jsx(
|
|
114642
|
-
|
|
114643
|
-
{
|
|
114644
|
-
copyText: `Send to all ${t$2("engage:user", {
|
|
114645
|
-
count: 2
|
|
114646
|
-
})} in ${includeSegmentIds.length === 1 ? "this" : "these"} ${t$2(
|
|
114647
|
-
"engage:segment",
|
|
114648
|
-
{
|
|
114649
|
-
count: includeSegmentIds.length
|
|
114650
|
-
}
|
|
114651
|
-
).toLowerCase()}`
|
|
114652
|
-
}
|
|
114653
|
-
),
|
|
114654
|
-
/* @__PURE__ */ jsx("div", { className: "flex gap-1 flex-wrap", children: includeSegmentIds.map((id2) => {
|
|
115879
|
+
/* @__PURE__ */ jsx(AutomationFlowLabel, { copyText }),
|
|
115880
|
+
showSegmentPills && /* @__PURE__ */ jsx("div", { className: "flex gap-1 flex-wrap", children: includeSegmentIds.map((id2) => {
|
|
114655
115881
|
const segment2 = segments?.find((segment22) => segment22.id === id2);
|
|
114656
115882
|
if (!segment2) return null;
|
|
114657
115883
|
return /* @__PURE__ */ jsx(SegmentPill, { segmentName: segment2.name }, id2);
|
|
@@ -115028,7 +116254,10 @@ const AutomationEditorSubStep = ({
|
|
|
115028
116254
|
return;
|
|
115029
116255
|
}
|
|
115030
116256
|
try {
|
|
115031
|
-
const params = {
|
|
116257
|
+
const params = {
|
|
116258
|
+
emailChannelSenderId: communicationGroup.emailChannelSenderId,
|
|
116259
|
+
smsChannelSenderId: communicationGroup.smsChannelSenderId
|
|
116260
|
+
};
|
|
115032
116261
|
switch (type) {
|
|
115033
116262
|
case CommunicationSubStepType.EMAIL:
|
|
115034
116263
|
if (channelEnabled && communicationGroup.emailChannelSenderId) {
|
|
@@ -115051,10 +116280,21 @@ const AutomationEditorSubStep = ({
|
|
|
115051
116280
|
}
|
|
115052
116281
|
break;
|
|
115053
116282
|
}
|
|
115054
|
-
await updateCommunicationGroup2(
|
|
115055
|
-
|
|
115056
|
-
|
|
115057
|
-
|
|
116283
|
+
await updateCommunicationGroup2(
|
|
116284
|
+
{
|
|
116285
|
+
groupId: communicationGroup.id,
|
|
116286
|
+
params
|
|
116287
|
+
},
|
|
116288
|
+
{
|
|
116289
|
+
onError: () => {
|
|
116290
|
+
toast2({
|
|
116291
|
+
title: "Error toggling channel",
|
|
116292
|
+
description: "Please contact your administrator",
|
|
116293
|
+
variant: "destructive"
|
|
116294
|
+
});
|
|
116295
|
+
}
|
|
116296
|
+
}
|
|
116297
|
+
);
|
|
115058
116298
|
} catch (error2) {
|
|
115059
116299
|
console.error("Error toggling channel:", error2);
|
|
115060
116300
|
}
|