@embedreach/components 0.3.43 → 0.3.45

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.
@@ -177,6 +177,21 @@ const Brain = createLucideIcon("Brain", [
177
177
  ["path", { d: "M6 18a4 4 0 0 1-1.967-.516", key: "2e4loj" }],
178
178
  ["path", { d: "M19.967 17.484A4 4 0 0 1 18 18", key: "159ez6" }]
179
179
  ]);
180
+ /**
181
+ * @license lucide-react v0.464.0 - ISC
182
+ *
183
+ * This source code is licensed under the ISC license.
184
+ * See the LICENSE file in the root directory of this source tree.
185
+ */
186
+ const Building2 = createLucideIcon("Building2", [
187
+ ["path", { d: "M6 22V4a2 2 0 0 1 2-2h8a2 2 0 0 1 2 2v18Z", key: "1b4qmf" }],
188
+ ["path", { d: "M6 12H4a2 2 0 0 0-2 2v6a2 2 0 0 0 2 2h2", key: "i71pzd" }],
189
+ ["path", { d: "M18 9h2a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2h-2", key: "10jefs" }],
190
+ ["path", { d: "M10 6h4", key: "1itunk" }],
191
+ ["path", { d: "M10 10h4", key: "tcdvrf" }],
192
+ ["path", { d: "M10 14h4", key: "kelpxr" }],
193
+ ["path", { d: "M10 18h4", key: "1ulq68" }]
194
+ ]);
180
195
  /**
181
196
  * @license lucide-react v0.464.0 - ISC
182
197
  *
@@ -4563,15 +4578,15 @@ function arrayRemove$2(array, item) {
4563
4578
  function removeLinks$2(items) {
4564
4579
  return items.filter((item) => item.tagName !== "A");
4565
4580
  }
4566
- var PORTAL_NAME$7 = "Portal";
4567
- var Portal$6 = React.forwardRef((props2, forwardedRef) => {
4581
+ var PORTAL_NAME$8 = "Portal";
4582
+ var Portal$8 = React.forwardRef((props2, forwardedRef) => {
4568
4583
  const { container: containerProp, ...portalProps } = props2;
4569
4584
  const [mounted, setMounted] = React.useState(false);
4570
4585
  useLayoutEffect2$7(() => setMounted(true), []);
4571
4586
  const container2 = containerProp || mounted && globalThis?.document?.body;
4572
4587
  return container2 ? ReactDOM__default.createPortal(/* @__PURE__ */ jsx(Primitive$9.div, { ...portalProps, ref: forwardedRef }), container2) : null;
4573
4588
  });
4574
- Portal$6.displayName = PORTAL_NAME$7;
4589
+ Portal$8.displayName = PORTAL_NAME$8;
4575
4590
  function useStateMachine$7(initialState2, machine) {
4576
4591
  return React.useReducer((state, event) => {
4577
4592
  const nextState = machine[state][event];
@@ -5551,16 +5566,16 @@ var DialogTrigger$1 = React.forwardRef(
5551
5566
  }
5552
5567
  );
5553
5568
  DialogTrigger$1.displayName = TRIGGER_NAME$5;
5554
- var PORTAL_NAME$6 = "DialogPortal";
5555
- var [PortalProvider$2, usePortalContext$2] = createDialogContext(PORTAL_NAME$6, {
5569
+ var PORTAL_NAME$7 = "DialogPortal";
5570
+ var [PortalProvider$2, usePortalContext$2] = createDialogContext(PORTAL_NAME$7, {
5556
5571
  forceMount: void 0
5557
5572
  });
5558
5573
  var DialogPortal$1 = (props2) => {
5559
5574
  const { __scopeDialog, forceMount, children, container: container2 } = props2;
5560
- const context2 = useDialogContext(PORTAL_NAME$6, __scopeDialog);
5561
- return /* @__PURE__ */ jsx(PortalProvider$2, { scope: __scopeDialog, forceMount, children: React.Children.map(children, (child) => /* @__PURE__ */ jsx(Presence$6, { present: forceMount || context2.open, children: /* @__PURE__ */ jsx(Portal$6, { asChild: true, container: container2, children: child }) })) });
5575
+ const context2 = useDialogContext(PORTAL_NAME$7, __scopeDialog);
5576
+ return /* @__PURE__ */ jsx(PortalProvider$2, { scope: __scopeDialog, forceMount, children: React.Children.map(children, (child) => /* @__PURE__ */ jsx(Presence$6, { present: forceMount || context2.open, children: /* @__PURE__ */ jsx(Portal$8, { asChild: true, container: container2, children: child }) })) });
5562
5577
  };
5563
- DialogPortal$1.displayName = PORTAL_NAME$6;
5578
+ DialogPortal$1.displayName = PORTAL_NAME$7;
5564
5579
  var OVERLAY_NAME = "DialogOverlay";
5565
5580
  var DialogOverlay$1 = React.forwardRef(
5566
5581
  (props2, forwardedRef) => {
@@ -5787,7 +5802,7 @@ var DescriptionWarning = ({ contentRef, descriptionId }) => {
5787
5802
  };
5788
5803
  var Root$d = Dialog$1;
5789
5804
  var Trigger$4 = DialogTrigger$1;
5790
- var Portal$5 = DialogPortal$1;
5805
+ var Portal$7 = DialogPortal$1;
5791
5806
  var Overlay = DialogOverlay$1;
5792
5807
  var Content$4 = DialogContent$1;
5793
5808
  var Title$1 = DialogTitle$1;
@@ -5798,7 +5813,7 @@ function cn$1(...inputs) {
5798
5813
  }
5799
5814
  const Dialog = Root$d;
5800
5815
  const DialogTrigger = Trigger$4;
5801
- const DialogPortal = ({ ...props2 }) => /* @__PURE__ */ jsx(Portal$5, { children: /* @__PURE__ */ jsx("div", { "data-reach-root": true, children: props2.children }) });
5816
+ const DialogPortal = ({ ...props2 }) => /* @__PURE__ */ jsx(Portal$7, { children: /* @__PURE__ */ jsx("div", { "data-reach-root": true, children: props2.children }) });
5802
5817
  const DialogOverlay = React.forwardRef(({ className, ...props2 }, ref) => /* @__PURE__ */ jsx(
5803
5818
  Overlay,
5804
5819
  {
@@ -5897,7 +5912,7 @@ const DialogVisuallyHidden = React.forwardRef(({ className, children, ...props2
5897
5912
  DialogVisuallyHidden.displayName = "DialogVisuallyHidden";
5898
5913
  const Sheet = Root$d;
5899
5914
  const SheetTrigger = Trigger$4;
5900
- const SheetPortal = Portal$5;
5915
+ const SheetPortal = Portal$7;
5901
5916
  const SheetOverlay = React.forwardRef(({ className, ...props2 }, ref) => /* @__PURE__ */ jsx(
5902
5917
  Overlay,
5903
5918
  {
@@ -16835,7 +16850,7 @@ var me$2 = React.forwardRef((r2, o2) => {
16835
16850
  }, []), React.createElement(Primitive$7.div, { ref: G$2([d4, o2]), ...c3, "cmdk-list": "", role: "listbox", "aria-label": u3, id: p2.listId }, j$3(r2, (v2) => React.createElement("div", { ref: G$2([f2, p2.listInnerRef]), "cmdk-list-sizer": "" }, v2)));
16836
16851
  }), Pe$2 = React.forwardRef((r2, o2) => {
16837
16852
  let { open: t3, onOpenChange: u3, overlayClassName: c3, contentClassName: d4, container: f2, ...p2 } = r2;
16838
- return React.createElement(Root$d, { open: t3, onOpenChange: u3 }, React.createElement(Portal$5, { container: f2 }, React.createElement(Overlay, { "cmdk-overlay": "", className: c3 }), React.createElement(Content$4, { "aria-label": r2.label, "cmdk-dialog": "", className: d4 }, React.createElement(me$2, { ref: o2, ...p2 }))));
16853
+ return React.createElement(Root$d, { open: t3, onOpenChange: u3 }, React.createElement(Portal$7, { container: f2 }, React.createElement(Overlay, { "cmdk-overlay": "", className: c3 }), React.createElement(Content$4, { "aria-label": r2.label, "cmdk-dialog": "", className: d4 }, React.createElement(me$2, { ref: o2, ...p2 }))));
16839
16854
  }), we$2 = React.forwardRef((r2, o2) => T$2((u3) => u3.filtered.count === 0) ? React.createElement(Primitive$7.div, { ref: o2, ...r2, "cmdk-empty": "", role: "presentation" }) : null), De$2 = React.forwardRef((r2, o2) => {
16840
16855
  let { progress: t3, children: u3, label: c3 = "Loading...", ...d4 } = r2;
16841
16856
  return React.createElement(Primitive$7.div, { ref: o2, ...d4, "cmdk-loading": "", role: "progressbar", "aria-valuenow": t3, "aria-valuemin": 0, "aria-valuemax": 100, "aria-label": c3 }, j$3(r2, (f2) => React.createElement("div", { "aria-hidden": true }, f2)));
@@ -19647,6 +19662,15 @@ var Root2$6 = Popper$2;
19647
19662
  var Anchor$2 = PopperAnchor$2;
19648
19663
  var Content$3 = PopperContent$2;
19649
19664
  var Arrow$4 = PopperArrow$2;
19665
+ var PORTAL_NAME$6 = "Portal";
19666
+ var Portal$6 = React.forwardRef((props2, forwardedRef) => {
19667
+ const { container: containerProp, ...portalProps } = props2;
19668
+ const [mounted, setMounted] = React.useState(false);
19669
+ useLayoutEffect2$6(() => setMounted(true), []);
19670
+ const container2 = containerProp || mounted && globalThis?.document?.body;
19671
+ return container2 ? ReactDOM__default.createPortal(/* @__PURE__ */ jsx(Primitive$7.div, { ...portalProps, ref: forwardedRef }), container2) : null;
19672
+ });
19673
+ Portal$6.displayName = PORTAL_NAME$6;
19650
19674
  function useStateMachine$6(initialState2, machine) {
19651
19675
  return React.useReducer((state, event) => {
19652
19676
  const nextState = machine[state][event];
@@ -19893,6 +19917,12 @@ var PORTAL_NAME$5 = "PopoverPortal";
19893
19917
  var [PortalProvider$1, usePortalContext$1] = createPopoverContext(PORTAL_NAME$5, {
19894
19918
  forceMount: void 0
19895
19919
  });
19920
+ var PopoverPortal = (props2) => {
19921
+ const { __scopePopover, forceMount, children, container: container2 } = props2;
19922
+ const context2 = usePopoverContext(PORTAL_NAME$5, __scopePopover);
19923
+ return /* @__PURE__ */ jsx(PortalProvider$1, { scope: __scopePopover, forceMount, children: /* @__PURE__ */ jsx(Presence$5, { present: forceMount || context2.open, children: /* @__PURE__ */ jsx(Portal$6, { asChild: true, container: container2, children }) }) });
19924
+ };
19925
+ PopoverPortal.displayName = PORTAL_NAME$5;
19896
19926
  var CONTENT_NAME$6 = "PopoverContent";
19897
19927
  var PopoverContent$1 = React.forwardRef(
19898
19928
  (props2, forwardedRef) => {
@@ -20077,6 +20107,7 @@ function getState$3(open) {
20077
20107
  }
20078
20108
  var Root2$5 = Popover$1;
20079
20109
  var Trigger$3 = PopoverTrigger$1;
20110
+ var Portal$5 = PopoverPortal;
20080
20111
  var Content2$2 = PopoverContent$1;
20081
20112
  const Popover = Root2$5;
20082
20113
  const PopoverTrigger = Trigger$3;
@@ -26730,24 +26761,25 @@ const useFeatureConfig = () => {
26730
26761
  const BrandColorsPreview = ({
26731
26762
  primaryColor = "var(--primary)",
26732
26763
  // secondaryColors = ['var(--secondary)', 'var(--accent)'],
26733
- hideLabel = false
26764
+ hideLabel = false,
26765
+ brandName,
26766
+ logoUrl
26734
26767
  }) => {
26735
26768
  const buttonColor = primaryColor;
26736
26769
  return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
26737
- !hideLabel && /* @__PURE__ */ jsx(FormLabel, { children: "This is how your brand colors will look on email" }),
26770
+ !hideLabel && /* @__PURE__ */ jsx("h3", { className: "text-lg font-semibold", children: "Branding Preview" }),
26738
26771
  /* @__PURE__ */ jsx("div", { className: "bg-muted/50 p-6 rounded-lg w-full mx-auto border border-muted", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col bg-background items-center space-y-4 max-w-md border rounded-lg mx-auto pb-8 overflow-hidden", children: [
26739
- /* @__PURE__ */ jsx(
26740
- "div",
26741
- {
26742
- className: "h-20 w-full -mb-10 bg-secondary"
26743
- }
26744
- ),
26745
- /* @__PURE__ */ jsx(
26746
- "div",
26747
- {
26748
- className: "w-12 h-12 rounded-lg"
26749
- }
26750
- ),
26772
+ /* @__PURE__ */ jsx("div", { className: "w-full px-6 pt-6 pb-2", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center", children: [
26773
+ /* @__PURE__ */ jsx("div", { className: "flex-shrink-0", children: logoUrl ? /* @__PURE__ */ jsx(
26774
+ "img",
26775
+ {
26776
+ src: logoUrl,
26777
+ alt: brandName || "Brand logo",
26778
+ className: "h-12 w-auto max-w-[80px] object-contain"
26779
+ }
26780
+ ) : /* @__PURE__ */ jsx("div", { className: "h-12 w-12 rounded bg-muted flex items-center justify-center", children: /* @__PURE__ */ jsx(Building2, { className: "h-6 w-6 text-muted-foreground" }) }) }),
26781
+ /* @__PURE__ */ jsx("div", { className: "flex-1 text-center", children: brandName ? /* @__PURE__ */ jsx("span", { className: "font-semibold text-lg text-foreground", children: brandName }) : /* @__PURE__ */ jsx("div", { className: "h-5 w-24 bg-muted rounded mx-auto" }) })
26782
+ ] }) }),
26751
26783
  /* @__PURE__ */ jsxs("div", { className: "w-full space-y-3 flex flex-col items-center px-8 pb-4 max-w-sm", children: [
26752
26784
  /* @__PURE__ */ jsx("div", { className: "h-2 rounded w-3/4 mx-auto bg-muted-foreground" }),
26753
26785
  /* @__PURE__ */ jsx("div", { className: "h-2 bg-muted rounded w-full" }),
@@ -34447,6 +34479,24 @@ const updateBusinessUiDefaultProperty = async (key, value) => {
34447
34479
  const toggleEmailHelpDialog = async (show) => {
34448
34480
  return updateBusinessUiDefaultProperty("emailHelpDialogShow", show);
34449
34481
  };
34482
+ const updateIntegrationWebhookSecret = async (integrationType, secret) => {
34483
+ const response = await baseRequest(BUSINESS_PATH, {
34484
+ method: "PATCH",
34485
+ body: JSON.stringify({
34486
+ integrationWebhookSecret: { integrationType, secret }
34487
+ })
34488
+ });
34489
+ return response.data;
34490
+ };
34491
+ const removeIntegrationWebhookSecret = async (integrationType) => {
34492
+ const response = await baseRequest(
34493
+ `${BUSINESS_PATH}/integration-webhook-secret/${integrationType}`,
34494
+ {
34495
+ method: "DELETE"
34496
+ }
34497
+ );
34498
+ return response.data;
34499
+ };
34450
34500
  const reputationCommunicationGroupsQueryKey = [
34451
34501
  "reputation",
34452
34502
  "communication-groups"
@@ -34591,6 +34641,76 @@ const useBusiness$1 = () => {
34591
34641
  });
34592
34642
  }
34593
34643
  });
34644
+ const updateCallRailWebhookSecretMutation = useMutation({
34645
+ mutationFn: (secret) => updateIntegrationWebhookSecret("callrail", secret),
34646
+ onSuccess: (updatedBusiness) => {
34647
+ queryClient.setQueryData(meQueryKey, updatedBusiness);
34648
+ queryClient.invalidateQueries({ queryKey: meQueryKey });
34649
+ toast2({
34650
+ title: "CallRail secret saved successfully",
34651
+ description: "Your CallRail webhook is now connected."
34652
+ });
34653
+ },
34654
+ onError: () => {
34655
+ toast2({
34656
+ title: "Failed to save CallRail secret",
34657
+ description: "Please try again",
34658
+ variant: "destructive"
34659
+ });
34660
+ }
34661
+ });
34662
+ const removeCallRailWebhookSecretMutation = useMutation({
34663
+ mutationFn: () => removeIntegrationWebhookSecret("callrail"),
34664
+ onSuccess: async () => {
34665
+ await queryClient.invalidateQueries({ queryKey: meQueryKey });
34666
+ toast2({
34667
+ title: "CallRail secret removed successfully",
34668
+ description: "Your CallRail webhook connection has been removed."
34669
+ });
34670
+ },
34671
+ onError: () => {
34672
+ toast2({
34673
+ title: "Failed to remove CallRail secret",
34674
+ description: "Please try again",
34675
+ variant: "destructive"
34676
+ });
34677
+ }
34678
+ });
34679
+ const updateCtmWebhookSecretMutation = useMutation({
34680
+ mutationFn: (secret) => updateIntegrationWebhookSecret("ctm", secret),
34681
+ onSuccess: (updatedBusiness) => {
34682
+ queryClient.setQueryData(meQueryKey, updatedBusiness);
34683
+ queryClient.invalidateQueries({ queryKey: meQueryKey });
34684
+ toast2({
34685
+ title: "CTM secret saved successfully",
34686
+ description: "Copy the secret below - it will not be shown again."
34687
+ });
34688
+ },
34689
+ onError: () => {
34690
+ toast2({
34691
+ title: "Failed to save CTM secret",
34692
+ description: "Please try again",
34693
+ variant: "destructive"
34694
+ });
34695
+ }
34696
+ });
34697
+ const removeCtmWebhookSecretMutation = useMutation({
34698
+ mutationFn: () => removeIntegrationWebhookSecret("ctm"),
34699
+ onSuccess: async () => {
34700
+ await queryClient.invalidateQueries({ queryKey: meQueryKey });
34701
+ toast2({
34702
+ title: "CTM secret removed successfully",
34703
+ description: "Your CTM webhook connection has been removed."
34704
+ });
34705
+ },
34706
+ onError: () => {
34707
+ toast2({
34708
+ title: "Failed to remove CTM secret",
34709
+ description: "Please try again",
34710
+ variant: "destructive"
34711
+ });
34712
+ }
34713
+ });
34594
34714
  return {
34595
34715
  data: meQuery.data,
34596
34716
  isLoading: meQuery.isLoading,
@@ -34617,7 +34737,19 @@ const useBusiness$1 = () => {
34617
34737
  isUpdatingBusinessUiDefaults: updateBusinessUiDefaultsMutation.isPending,
34618
34738
  isUpdatingBusinessUiDefaultProperty: updateBusinessUiDefaultPropertyMutation.isPending,
34619
34739
  isTogglingEmailHelpDialog: toggleEmailHelpDialogMutation.isPending,
34620
- isTogglingEngageOnboarding: toggleEngageOnboardingMutation.isPending
34740
+ isTogglingEngageOnboarding: toggleEngageOnboardingMutation.isPending,
34741
+ updateCallRailWebhookSecret: updateCallRailWebhookSecretMutation.mutate,
34742
+ updateCallRailWebhookSecretAsync: updateCallRailWebhookSecretMutation.mutateAsync,
34743
+ isUpdatingCallRailSecret: updateCallRailWebhookSecretMutation.isPending,
34744
+ removeCallRailWebhookSecret: removeCallRailWebhookSecretMutation.mutate,
34745
+ removeCallRailWebhookSecretAsync: removeCallRailWebhookSecretMutation.mutateAsync,
34746
+ isRemovingCallRailSecret: removeCallRailWebhookSecretMutation.isPending,
34747
+ updateCtmWebhookSecret: updateCtmWebhookSecretMutation.mutate,
34748
+ updateCtmWebhookSecretAsync: updateCtmWebhookSecretMutation.mutateAsync,
34749
+ isUpdatingCtmSecret: updateCtmWebhookSecretMutation.isPending,
34750
+ removeCtmWebhookSecret: removeCtmWebhookSecretMutation.mutate,
34751
+ removeCtmWebhookSecretAsync: removeCtmWebhookSecretMutation.mutateAsync,
34752
+ isRemovingCtmSecret: removeCtmWebhookSecretMutation.isPending
34621
34753
  };
34622
34754
  };
34623
34755
  const websiteContentKeys = {
@@ -39896,7 +40028,14 @@ const BrandSettingsForm = forwardRef(({ onSubmit, defaultValues }, ref) => {
39896
40028
  }
39897
40029
  )
39898
40030
  ] }) }),
39899
- /* @__PURE__ */ jsx(BrandColorsPreview, { primaryColor: form.watch("primaryColor") })
40031
+ /* @__PURE__ */ jsx(
40032
+ BrandColorsPreview,
40033
+ {
40034
+ primaryColor: form.watch("primaryColor"),
40035
+ brandName: form.watch("brandName"),
40036
+ logoUrl: imagePreview || void 0
40037
+ }
40038
+ )
39900
40039
  ]
39901
40040
  }
39902
40041
  ) })
@@ -45966,6 +46105,12 @@ const dashboardFilterReducer = (state, action) => {
45966
46105
  ...state,
45967
46106
  tabCanUseTransactionAttribution: action.payload
45968
46107
  };
46108
+ case "SET_ACTIVE_TAB":
46109
+ return { ...state, activeTab: action.payload };
46110
+ case "SET_LEAD_STATUSES":
46111
+ return { ...state, leadStatuses: action.payload };
46112
+ case "SET_IDENTIFICATION_SOURCES":
46113
+ return { ...state, identificationSources: action.payload };
45969
46114
  default:
45970
46115
  return state;
45971
46116
  }
@@ -45988,11 +46133,21 @@ const updateTabCanUseTransactionAttribution = (dispatch2) => (tabCanUseTransacti
45988
46133
  payload: tabCanUseTransactionAttribution
45989
46134
  });
45990
46135
  };
46136
+ const updateActiveTab = (dispatch2) => (activeTab) => {
46137
+ dispatch2({ type: "SET_ACTIVE_TAB", payload: activeTab });
46138
+ };
46139
+ const updateLeadStatuses = (dispatch2) => (leadStatuses) => {
46140
+ dispatch2({ type: "SET_LEAD_STATUSES", payload: leadStatuses });
46141
+ };
46142
+ const updateIdentificationSources = (dispatch2) => (sources) => {
46143
+ dispatch2({ type: "SET_IDENTIFICATION_SOURCES", payload: sources });
46144
+ };
45991
46145
  const defaultState$1 = {
45992
46146
  dateRange: void 0,
45993
46147
  channel: void 0,
45994
46148
  campaignId: void 0,
45995
- attributionStyle: DateAttributionStyle.CLICK
46149
+ attributionStyle: DateAttributionStyle.CLICK,
46150
+ activeTab: "overview"
45996
46151
  };
45997
46152
  createDataContext(
45998
46153
  dashboardFilterReducer,
@@ -46001,7 +46156,10 @@ createDataContext(
46001
46156
  updateChannel,
46002
46157
  updateCampaignId,
46003
46158
  updateAttributionStyle,
46004
- updateTabCanUseTransactionAttribution
46159
+ updateTabCanUseTransactionAttribution,
46160
+ updateActiveTab,
46161
+ updateLeadStatuses,
46162
+ updateIdentificationSources
46005
46163
  },
46006
46164
  defaultState$1
46007
46165
  );
@@ -48696,6 +48854,24 @@ const measure$1 = {
48696
48854
  new_customers_description: "The number of first-time customers acquired through your advertising campaigns during the selected period. \n\nThis metric specifically tracks customers who have never purchased from your business before and made their first purchase after interacting with your ads.",
48697
48855
  new_leads: "New Leads",
48698
48856
  new_leads_description: "The number of new potential customers who provided their contact information through your advertising campaigns during the selected period. \n\nLeads are typically generated through form submissions, newsletter signups, download requests, or other lead magnets promoted in your ads.",
48857
+ open_leads: "Open Leads",
48858
+ open_leads_description: "The number of leads who have not yet made a purchase and have had activity within the last 90 days. These are active leads that are still in your pipeline.",
48859
+ converted_leads: "Converted Leads",
48860
+ converted_leads_description: "The number of leads who have made at least one purchase. These leads have successfully converted into paying customers.",
48861
+ stale_leads: "Stale Leads",
48862
+ stale_leads_description: "Leads with no activity (no new identifications, visits, or purchases) for more than 90 days. Consider re-engagement campaigns for these leads.",
48863
+ leads_from_ads: "Leads From Ads",
48864
+ leads_from_ads_description: "The number of new leads attributed to paid advertising during the selected period. \n\nA lead is counted when a visitor provides contact information after interacting with your ads.",
48865
+ cost_per_lead: "Cost Per Lead",
48866
+ cost_per_lead_description: "The average amount spent to acquire each new lead from ads, calculated by dividing ad spend by leads from ads.",
48867
+ lead_to_purchase_rate: "Lead to Purchase Rate",
48868
+ lead_to_purchase_rate_description: "The percentage of leads who went on to make a purchase during the selected period.",
48869
+ total_value_of_open_leads: "Est. Value of Open Leads",
48870
+ total_value_of_open_leads_description: "Estimated potential revenue from leads who have not yet converted. Calculated by multiplying the number of open (unconverted) leads by the average revenue per converted lead. This is a projection, not actual revenue.",
48871
+ total_value_of_converted_leads: "Total Value of Converted Leads",
48872
+ total_value_of_converted_leads_description: "The total revenue from all purchases made by leads who converted during the selected period.",
48873
+ average_lead_value: "Average Lead Value",
48874
+ average_lead_value_description: "The average revenue per converted lead, calculated by dividing converted lead revenue by the number of converted leads.",
48699
48875
  reengaged_customers: "Reengaged Customers",
48700
48876
  reengaged_customers_description: "The number of previously inactive customers who made a purchase after being targeted by your advertising campaigns during the selected period. \n\nThese are customers who had purchased from your business before but had been dormant for a significant period.",
48701
48877
  revenue_per_click: "Revenue Per Click",
@@ -48726,6 +48902,9 @@ const measure$1 = {
48726
48902
  not_running_paid_ads: "Not running paid ads? Use AI to create a Google Ads campaign",
48727
48903
  privacy_policy: "Privacy Policy",
48728
48904
  quick_links: "Quick Links",
48905
+ quick_links_and_integrations: "Quick Links + Integrations",
48906
+ connect_callrail: "Connect CallRail",
48907
+ connect_ctm: "Connect CTM",
48729
48908
  setup_tracking_pixel: "Setup tracking pixel",
48730
48909
  understand_attribution_model: "Understand our attribution model",
48731
48910
  update_ad_campaign_settings: "Update ad campaign settings",
@@ -48830,6 +49009,11 @@ For example: If someone clicks your Google ad, we'll show "Google Ads" even if t
48830
49009
  utm_medium_description: "Revenue grouped by the marketing medium from your tracking URLs. If you add UTM parameters to your links (like ?utm_medium=email or ?utm_medium=cpc), this shows which types of marketing efforts drive the most sales. Helps you understand if email campaigns convert better than paid ads.",
48831
49010
  referrer_description: "Revenue grouped by the website that sent visitors to you before they made a purchase. This shows the actual domains like google.com, facebook.com, or partner websites that are driving sales. Useful for discovering unexpected traffic sources or measuring the value of partnerships."
48832
49011
  }
49012
+ },
49013
+ leads: {
49014
+ title: "Leads",
49015
+ prototype_banner_title: "New feature — we're still optimizing",
49016
+ prototype_banner_description: "This experience is actively being improved. We'd love your feedback to help us get it right."
48833
49017
  }
48834
49018
  }
48835
49019
  },
@@ -48841,6 +49025,75 @@ For example: If someone clicks your Google ad, we'll show "Google Ads" even if t
48841
49025
  platform_settings: "{{provider}} Settings",
48842
49026
  disconnect_account_description: "Remove connection to your {{provider}} account",
48843
49027
  finalizing_connection: "Finalizing connection..."
49028
+ },
49029
+ callrail: {
49030
+ connect: "Connect Account",
49031
+ connected: "Connected",
49032
+ connected_description: "CallRail is connected and receiving webhook events.",
49033
+ setup: {
49034
+ title: "Connect CallRail",
49035
+ description: "Follow these steps to connect your CallRail account and start tracking phone calls.",
49036
+ step_1_title: "Step 1: Copy the webhook URL",
49037
+ step_1_description: "Copy the webhook URL below. You'll need to paste this into CallRail in the next step.",
49038
+ step_2_title: "Step 2: Add webhook in CallRail",
49039
+ step_2_1: "Log in to your CallRail account",
49040
+ step_2_2: "Go to Settings → Integrations → Webhooks",
49041
+ step_2_3: "Scroll down to the Post-Call section.",
49042
+ step_2_4: 'Paste the webhook URL from Step 1 into the "Webhook URL" field',
49043
+ step_2_5: "Scroll to the bottom of the page and click Update.",
49044
+ step_3_title: "Step 3: Get your Webhook Signature Secret Token",
49045
+ step_3_description: 'Above the Update button you will see "Advanced Settings >". Click on this to expand the section. Here you will see Webhook Signature Secret Token. Copy the secret you are shown here.',
49046
+ step_4_title: "Step 4: Enter your Webhook Signature Secret Token",
49047
+ step_4_description: "Paste your CallRail Webhook Signature Secret Token below to complete the connection.",
49048
+ secret_label: "Webhook Signature Secret Token",
49049
+ secret_placeholder: "Paste your Webhook Signature Secret Token here",
49050
+ change_token: "Change",
49051
+ close: "Close",
49052
+ remove: "Remove",
49053
+ confirm_remove: "Are you sure you want to remove the CallRail connection? This will stop receiving webhook events.",
49054
+ copy: "Copy",
49055
+ copied: "Copied",
49056
+ cancel: "Cancel",
49057
+ save: "Save & Connect",
49058
+ saving: "Saving..."
49059
+ }
49060
+ },
49061
+ ctm: {
49062
+ connected_status: "CTM is connected and receiving webhook events.",
49063
+ setup: {
49064
+ title: "Connect CTM",
49065
+ description: "Follow these steps to connect your CTM account and start tracking phone calls.",
49066
+ step_1_title: "Step 1: Get your Secret Key from CTM",
49067
+ step_1_description: 'Log in to your CTM account and navigate to Account Settings → Api Integration. Copy your "Secret Key" from that page.',
49068
+ step_2_title: "Step 2: Paste your Secret Key",
49069
+ step_2_description: "Paste the Secret Key from CTM below. This allows us to verify that webhook requests are genuinely from CTM.",
49070
+ step_3_title: "Step 3: Copy the webhook URL",
49071
+ step_3_description: "Copy the webhook URL below. You'll paste this into CTM in Step 4.",
49072
+ step_4_title: "Step 4: Configure webhook in CTM",
49073
+ step_4_description: "Follow these steps to configure the webhook in your CTM account:",
49074
+ step_4_1: "Log in to your CTM account",
49075
+ step_4_2: "Click on Settings (in side navigation)",
49076
+ step_4_3: "Under Configuration, click on Webhooks",
49077
+ step_4_4: "Click New Webhook button",
49078
+ step_4_5: "Enter a name for your webhook (e.g., 'Ads Call Tracking')",
49079
+ step_4_6: "Under Trigger, select 'When a call ends immediately without delay'",
49080
+ step_4_7: "Paste the webhook URL from Step 3 into the Callback URL field",
49081
+ step_4_8: "Select 'Log Data' for Request Body Type",
49082
+ step_4_9: "Click Save Changes",
49083
+ ready_message: "You're all set! CTM will now start sending webhook events, and your phone calls will be tracked automatically.",
49084
+ secret_saved: "Your CTM Secret Key is saved. To update it, enter a new key below:",
49085
+ secret_label: "CTM Secret Key",
49086
+ secret_placeholder: "Paste your CTM Secret Key here...",
49087
+ save: "Save",
49088
+ saving: "Saving...",
49089
+ update: "Update",
49090
+ remove: "Remove",
49091
+ cancel: "Cancel",
49092
+ close: "Close",
49093
+ copy: "Copy",
49094
+ copied: "Copied",
49095
+ confirm_remove: "Are you sure you want to remove the CTM connection? This will stop receiving webhook events."
49096
+ }
48844
49097
  }
48845
49098
  };
48846
49099
  const authentication$1 = {
@@ -48908,7 +49161,7 @@ const analytics$1 = {
48908
49161
  copied_to_clipboard: "Copied to clipboard",
48909
49162
  copied_to_clipboard_description: "The tracking pixel code has been copied to your clipboard.",
48910
49163
  title: "Install our Tracking Pixel",
48911
- description: "In order to get a complete picture of how users are interacting with your website, it’s important for the Reach analytics code to be on every page of your website and within as many third-party tools that you use as possible.",
49164
+ description: "In order to get a complete picture of how users are interacting with your website, it’s important for the analytics code to be on every page of your website and within as many third-party tools that you use as possible.",
48912
49165
  card_title: "Install the Snippet inside the <HEAD> of every page",
48913
49166
  third_party_pages_your_tracking_pixel: "Your Tracking Pixel:",
48914
49167
  card_description: "Copy this following text and insert it inside of the <HEAD> tags on all pages.",
@@ -48927,7 +49180,7 @@ const analytics$1 = {
48927
49180
  },
48928
49181
  third_party_installation_guides: {
48929
49182
  title: "Installation Guides",
48930
- description: "These guides will help you add the Reach analytics snippet to your website. The process works with any website builder or platform and most third-party tools.",
49183
+ description: "These guides will help you add the analytics snippet to your website. The process works with any website builder or platform and most third-party tools.",
48931
49184
  installation_guide: "{{name}} Installation Guide",
48932
49185
  official_guide: "Official Guide",
48933
49186
  shopify: {
@@ -48938,18 +49191,20 @@ const analytics$1 = {
48938
49191
  step_5: "Paste the code snippet from the section above just before it"
48939
49192
  },
48940
49193
  google_tag_manager: {
48941
- step_1: "Go to https://tagmanager.google.com",
48942
- step_2: "Sign in to your Google Account",
48943
- step_3: 'In the Tags tab, click the "New" button to create a new tag',
48944
- step_4: 'Choose "Custom HTML" as the tag type',
48945
- step_5: "Paste the tracking code above into the HTML field",
48946
- step_6: "Click anywhere in the triggering section to edit this setting",
48947
- step_7: 'Select "Initialization - All Pages" as the trigger',
48948
- step_8: "Click Save to save the tag",
48949
- step_9: "Click Submit in the top right",
48950
- step_10: "Add a version name and description",
48951
- step_11: "Click Publish to deploy your changes",
48952
- special_note: "Make sure you have the Google Tag Manager container code already installed on your site before adding this tag."
49194
+ step_1: "Go to tagmanager.google.com and sign in with your Google account",
49195
+ step_2: "Select the container for your website (or create one if you haven't already)",
49196
+ step_3: "Important: Make sure your GTM container code is already installed on your website. If not, follow Google's installation instructions first, then return here.",
49197
+ step_3_link: "https://support.google.com/tagmanager/answer/6103696",
49198
+ step_4: 'In the left sidebar, click "Tags", then click the "New" button in the top right',
49199
+ step_5: 'Give your tag a name at the top (e.g., "Source Attribution Pixel")',
49200
+ step_6: 'Click anywhere in the "Tag Configuration" box, then select "Custom HTML" from the tag type menu',
49201
+ step_7: "Paste the tracking code from above into the HTML field (the code already includes the required <script> tags)",
49202
+ step_8: 'Click anywhere in the "Triggering" box below the tag configuration',
49203
+ step_9: 'Select "Initialization - All Pages" to ensure the pixel loads before other tags (recommended), or "All Pages" for standard page load timing',
49204
+ step_10: 'Click "Save" in the top right corner to save your tag',
49205
+ step_11: 'Click "Submit" in the top right corner of the workspace',
49206
+ step_12: 'Add a version name (e.g., "Added source attribution pixel") and click "Publish" to deploy your changes',
49207
+ special_note: "Google Tag Manager works with any website platform. If you already have GTM installed on your site, you can use this method instead of adding code directly to your website's HTML."
48953
49208
  },
48954
49209
  hubspot: {
48955
49210
  step_1: "Go to Settings → Content → Pages",
@@ -48958,18 +49213,30 @@ const analytics$1 = {
48958
49213
  step_4: 'Click "Save"'
48959
49214
  },
48960
49215
  wordpress: {
48961
- step_1: "We recommend using the popular WPCode Plugin",
48962
- step_2: 'In the plugin, select "+ Add Snippet"',
48963
- step_3: 'When presented with a menu of options, navigate to "Add Your Custom Code (New Snippet)" and select "Use snippet"',
48964
- step_4: "Paste the code snippet from the section above",
48965
- step_5: 'For Insert Method, choose "Auto Insert"',
48966
- step_6: 'For Location, select "Site Wide Header"',
48967
- step_7: "Be sure to save your snippet"
49216
+ intro: "WordPress sites can add tracking code to the header using various plugins or theme settings. Find your method below and paste the tracking code into the Header section.",
49217
+ methods: [
49218
+ {
49219
+ id: "wpcode",
49220
+ name: "WPCode",
49221
+ description: 'Code Snippets Header & Footer → paste in "Header" section → Save Changes',
49222
+ link: "https://wpcode.com/docs/using-the-global-header-footer-settings/"
49223
+ },
49224
+ {
49225
+ id: "elementor",
49226
+ name: "Elementor",
49227
+ description: 'Elementor → Custom Code → Add New → set location to "<head>" → set conditions to "Entire Site" → Publish',
49228
+ link: "https://elementor.com/help/custom-code-pro/"
49229
+ }
49230
+ ],
49231
+ special_note: "Important: After adding tracking code, clear your WordPress cache if you use a caching plugin (WP Rocket, LiteSpeed Cache, W3 Total Cache, Cloudflare, etc.). The code won't appear on your site until the cache is cleared.\n\nIf you're using a different plugin for custom JavaScript or code injection, check your WordPress Plugins section to identify the plugin and follow that plugin's specific instructions for adding code to the header."
48968
49232
  },
48969
49233
  squarespace: {
48970
- step_1: "Go to Settings Advanced Code Injection",
48971
- step_2: 'Paste the code from the section above into the "Header" field',
48972
- step_3: 'Click "Save"'
49234
+ step_1: "Sign in to your Squarespace account at account.squarespace.com",
49235
+ step_2: 'On the Dashboard, click the "Website" button for the site you want to modify',
49236
+ step_3: 'From the main menu, click "Pages" under the "Website" section',
49237
+ step_4: 'Scroll to the bottom and click "Custom Code", then click "Code Injection". Note: on older versions of Squarespace, "Custom Code" may be labeled "Website Tools"',
49238
+ step_5: 'Under "Header", paste the tracking code from above and click "Save"',
49239
+ special_note: "Code Injection requires a Squarespace Business or Commerce plan. If you don't see the Code Injection option, you may need to upgrade your plan."
48973
49240
  },
48974
49241
  wix: {
48975
49242
  step_1: "Go to Settings → Custom Code",
@@ -49291,7 +49558,7 @@ const oauth$1 = {
49291
49558
  fetchAccounts: "Fetching accounts...",
49292
49559
  noAccountSelected: "No account selected",
49293
49560
  enableTrackingParams: "Enable Tracking Parameters",
49294
- enableTrackingParamsDescription: "Append the reach campaign id parameter to your ad platform tracking settings. We will not overwrite any existing tracking parameters. Required for accurate tracking.",
49561
+ enableTrackingParamsDescription: "Append the 'ER' campaign id parameter to your ad platform tracking settings. We will not overwrite any existing tracking parameters. Required for accurate tracking.",
49295
49562
  google: {
49296
49563
  selectAccountDescription: "Select the Google Ads account you want to connect to view your data. These will be linked to our MCC for optimal tracking.",
49297
49564
  mccAccounts: "MCC Accounts",
@@ -49589,6 +49856,22 @@ const measure = {
49589
49856
  new_customers_description: "El número de nuevos clientes adquiridos a través de tus campañas de anuncios durante el período seleccionado. \n\nEsta métrica rastrea clientes que nunca han comprado de tu negocio antes y han realizado su primera compra después de interactuar con tus anuncios.",
49590
49857
  new_leads: "Nuevos leads",
49591
49858
  new_leads_description: "El número de nuevos clientes potenciales que proporcionaron su información de contacto a través de tus campañas de anuncios durante el período seleccionado. \n\nLos leads son típicamente generados a través de envíos de formularios, suscripciones a newsletters, solicitudes de descarga, o otros magnetos de leads promovidos en tus anuncios.",
49859
+ open_leads: "Leads abiertos",
49860
+ open_leads_description: "El número de leads que aún no han realizado una compra y han tenido actividad en los últimos 90 días. Estos son leads activos que aún están en tu pipeline.",
49861
+ converted_leads: "Leads convertidos",
49862
+ converted_leads_description: "El número de leads que han realizado al menos una compra. Estos leads se han convertido exitosamente en clientes de pago.",
49863
+ stale_leads: "Leads inactivos",
49864
+ stale_leads_description: "Leads sin actividad (sin nuevas identificaciones, visitas o compras) por más de 90 días. Considera campañas de reactivación para estos leads.",
49865
+ leads_from_ads: "Leads de anuncios",
49866
+ leads_from_ads_description: "El número de nuevos leads atribuidos a anuncios pagos durante el período seleccionado. \n\nUn lead se cuenta cuando un visitante proporciona su información de contacto después de interactuar con tus anuncios.",
49867
+ cost_per_lead: "Costo por lead",
49868
+ cost_per_lead_description: "El costo promedio para adquirir cada nuevo lead desde anuncios, calculado dividiendo el gasto en anuncios entre los leads de anuncios.",
49869
+ lead_to_purchase_rate: "Tasa de lead a compra",
49870
+ lead_to_purchase_rate_description: "El porcentaje de leads que realizaron una compra durante el período seleccionado.",
49871
+ total_value_of_converted_leads: "Valor total de leads convertidos",
49872
+ total_value_of_converted_leads_description: "El total de ingresos de todas las compras realizadas por leads que se convirtieron durante el período seleccionado.",
49873
+ average_lead_value: "Valor promedio por lead",
49874
+ average_lead_value_description: "El ingreso promedio por lead convertido, calculado dividiendo el ingreso de leads convertidos entre la cantidad de leads convertidos.",
49592
49875
  reengaged_customers: "Clientes reactivados",
49593
49876
  reengaged_customers_description: "El número de clientes anteriores que hicieron una compra después de ser targetizados por tus campañas de anuncios durante el período seleccionado. \n\nEstos son clientes que habían comprado de tu negocio antes pero habían estado inactivos durante un período significativo.",
49594
49877
  revenue_per_click: "Ingresos por clic",
@@ -53944,14 +54227,18 @@ const automationKeys = {
53944
54227
  args.automationId,
53945
54228
  "orders",
53946
54229
  ...args.cursor ? [args.cursor] : [],
53947
- ...args.limit ? [args.limit] : []
54230
+ ...args.limit ? [args.limit] : [],
54231
+ args.startDate ? formatDateToString(args.startDate) : "no-start",
54232
+ args.endDate ? formatDateToString(args.endDate) : "no-end"
53948
54233
  ],
53949
54234
  businessOrders: (args) => [
53950
54235
  ...automationKeys.all,
53951
54236
  "business",
53952
54237
  "orders",
53953
54238
  ...args.cursor ? [args.cursor] : [],
53954
- ...args.limit ? [args.limit] : []
54239
+ ...args.limit ? [args.limit] : [],
54240
+ args.startDate ? formatDateToString(args.startDate) : "no-start",
54241
+ args.endDate ? formatDateToString(args.endDate) : "no-end"
53955
54242
  ],
53956
54243
  businessStatistics: (startDate, endDate) => [
53957
54244
  ...automationKeys.all,
@@ -53976,7 +54263,9 @@ const automationKeys = {
53976
54263
  ...args?.limit ? [args.limit] : [],
53977
54264
  ...args?.status ? [args.status] : [],
53978
54265
  ...args?.search ? [args.search] : [],
53979
- ...args?.triggerTypes ? [...args.triggerTypes] : []
54266
+ ...args?.triggerTypes ? [...args.triggerTypes] : [],
54267
+ args?.startDate ? formatDateToString(args.startDate) : "no-start",
54268
+ args?.endDate ? formatDateToString(args.endDate) : "no-end"
53980
54269
  ],
53981
54270
  aiContent: () => [...automationKeys.all, "ai-content"],
53982
54271
  reputationTemplate: () => [...automationKeys.all, "template", "reputation"]
@@ -54067,6 +54356,12 @@ const listBusinessAutomations = async (args) => {
54067
54356
  if (args.triggerTypes) {
54068
54357
  params.append("triggerTypes", args.triggerTypes.join(","));
54069
54358
  }
54359
+ if (args.startDate) {
54360
+ params.append("startDate", formatDateToString(args.startDate));
54361
+ }
54362
+ if (args.endDate) {
54363
+ params.append("endDate", formatDateToString(args.endDate));
54364
+ }
54070
54365
  const response = await baseRequest(
54071
54366
  `${BUSINESS_AUTOMATION_PATH}?${params.toString()}`,
54072
54367
  {
@@ -54119,14 +54414,23 @@ const getEstimatedRecipients = async (args) => {
54119
54414
  return response.data;
54120
54415
  };
54121
54416
  const getAutomationOrders = async (args) => {
54122
- const params = new URLSearchParams();
54417
+ const searchParams = new URLSearchParams();
54123
54418
  if (args.cursor) {
54124
- params.append("cursor", args.cursor);
54419
+ searchParams.append("cursor", args.cursor);
54125
54420
  }
54126
54421
  if (args.limit) {
54127
- params.append("limit", args.limit.toString());
54422
+ searchParams.append("limit", args.limit.toString());
54423
+ }
54424
+ if (args.startDate) {
54425
+ searchParams.append("startDate", formatDateToString(args.startDate));
54426
+ }
54427
+ if (args.endDate) {
54428
+ searchParams.append("endDate", formatDateToString(args.endDate));
54128
54429
  }
54129
- const response = await baseRequest(`/automations/internal/${args.automationId}/orders?${params.toString()}`, {
54430
+ const basePath = `/automations/internal/${args.automationId}/orders`;
54431
+ const queryString = searchParams.toString();
54432
+ const url = queryString ? `${basePath}?${queryString}` : basePath;
54433
+ const response = await baseRequest(url, {
54130
54434
  method: "GET"
54131
54435
  });
54132
54436
  return response.data;
@@ -54139,6 +54443,12 @@ const getBusinessOrders = async (params) => {
54139
54443
  if (params.limit) {
54140
54444
  queryParams.append("limit", params.limit.toString());
54141
54445
  }
54446
+ if (params.startDate) {
54447
+ queryParams.append("startDate", formatDateToString(params.startDate));
54448
+ }
54449
+ if (params.endDate) {
54450
+ queryParams.append("endDate", formatDateToString(params.endDate));
54451
+ }
54142
54452
  const response = await baseRequest(`/automations/internal/orders?${queryParams.toString()}`, {
54143
54453
  method: "GET"
54144
54454
  });
@@ -54355,6 +54665,12 @@ const useUpdateCommunicationGroup = () => {
54355
54665
  queryClient.invalidateQueries({
54356
54666
  queryKey: automationKeys.list()
54357
54667
  });
54668
+ queryClient.invalidateQueries({
54669
+ queryKey: ["automations"],
54670
+ predicate: (query) => {
54671
+ return Array.isArray(query.queryKey) && query.queryKey.length >= 3 && query.queryKey[0] === "automations" && query.queryKey[2] === "estimated-recipients";
54672
+ }
54673
+ });
54358
54674
  }
54359
54675
  });
54360
54676
  return {
@@ -55155,178 +55471,190 @@ const SMSSetupBusinessForm = forwardRef(({ isSubmitting, onSubmit, hideSubmitBut
55155
55471
  };
55156
55472
  await onSubmit(data);
55157
55473
  };
55158
- return /* @__PURE__ */ jsx("div", { className: "w-full max-w-4xl text-left", children: /* @__PURE__ */ jsx(Form$1, { ...form, children: /* @__PURE__ */ jsxs("form", { onSubmit: form.handleSubmit(handleSubmit), className: "space-y-6", children: [
55159
- /* @__PURE__ */ jsxs(
55160
- FormSection,
55161
- {
55162
- title: "Legal Business Settings",
55163
- description: "Provide your legal business information required for SMS channel verification and future communications.",
55164
- children: [
55165
- /* @__PURE__ */ jsx(
55166
- CompanyInfoFields,
55167
- {
55168
- control: form.control,
55169
- disabled: isSubmitting,
55170
- context: "sms",
55171
- showInfoCard: true
55172
- }
55173
- ),
55174
- watchedCountry === "US" && /* @__PURE__ */ jsxs(Fragment$1, { children: [
55175
- /* @__PURE__ */ jsx(
55176
- TextField,
55177
- {
55178
- control: form.control,
55179
- name: "company.businessRegistrationNumber",
55180
- label: "Employer Identification Number (EIN)",
55181
- placeholder: "12-3456789",
55182
- toolTipComponent: /* @__PURE__ */ jsx(
55183
- InfoTooltip,
55184
- {
55185
- title: "Why do we need this?",
55186
- description: "Starting February 17th, 2026, all US businesses are required to provide their EIN (Employer Identification Number) when registering for SMS. Your EIN must match the legal business name you've provided above."
55187
- }
55188
- ),
55189
- disabled: isSoleProprietor || isSubmitting
55190
- }
55191
- ),
55192
- /* @__PURE__ */ jsxs("div", { className: "flex items-center space-x-2", children: [
55474
+ return /* @__PURE__ */ jsx("div", { className: "w-full max-w-4xl text-left", children: /* @__PURE__ */ jsx(Form$1, { ...form, children: /* @__PURE__ */ jsxs(
55475
+ "form",
55476
+ {
55477
+ onSubmit: form.handleSubmit(handleSubmit),
55478
+ onKeyDown: (e4) => {
55479
+ if (e4.key === "Enter" && e4.target instanceof HTMLInputElement) {
55480
+ e4.preventDefault();
55481
+ }
55482
+ },
55483
+ className: "space-y-6",
55484
+ children: [
55485
+ /* @__PURE__ */ jsxs(
55486
+ FormSection,
55487
+ {
55488
+ title: "Legal Business Settings",
55489
+ description: "Provide your legal business information required for SMS channel verification and future communications.",
55490
+ children: [
55193
55491
  /* @__PURE__ */ jsx(
55194
- Checkbox,
55195
- {
55196
- checked: isSoleProprietor,
55197
- onCheckedChange: (checked) => {
55198
- const isChecked = !!checked;
55199
- if (isChecked) {
55200
- form.setValue(
55201
- "company.businessType",
55202
- "SOLE_PROPRIETOR"
55203
- );
55204
- form.setValue("company.businessRegistrationNumber", "");
55205
- } else {
55206
- form.setValue("company.businessType", void 0);
55207
- }
55208
- },
55209
- disabled: isSubmitting
55210
- }
55211
- ),
55212
- /* @__PURE__ */ jsx("label", { className: "text-sm text-muted-foreground cursor-pointer", children: "I am a sole proprietor without an EIN" })
55213
- ] }),
55214
- /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground text-pretty", children: "If no EIN is available (e.g., a self-run business or sole prop with no employees), please check the box above." })
55215
- ] })
55216
- ]
55217
- }
55218
- ),
55219
- /* @__PURE__ */ jsx(
55220
- FormSection,
55221
- {
55222
- title: "Contact Information",
55223
- description: "Provide the contact information of the person authorized to represent your business.",
55224
- children: /* @__PURE__ */ jsx(ContactInfoFields, { control: form.control, disabled: isSubmitting })
55225
- }
55226
- ),
55227
- /* @__PURE__ */ jsxs(
55228
- FormSection,
55229
- {
55230
- title: "Messaging Use Case",
55231
- description: "Tell us about how you plan to use SMS messaging.",
55232
- children: [
55233
- /* @__PURE__ */ jsx(
55234
- TextField,
55235
- {
55236
- control: form.control,
55237
- name: "messagingUseCase.monthlyVolume",
55238
- label: "Expected Monthly Volume",
55239
- placeholder: "1000",
55240
- type: "number",
55241
- disabled: isSubmitting
55242
- }
55243
- ),
55244
- /* @__PURE__ */ jsx(
55245
- TextField,
55246
- {
55247
- control: form.control,
55248
- name: "messagingUseCase.useCaseDetails",
55249
- label: "Use Case Details",
55250
- placeholder: "Describe your use case in detail",
55251
- toolTipComponent: /* @__PURE__ */ jsx(
55252
- InfoTooltip,
55492
+ CompanyInfoFields,
55253
55493
  {
55254
- title: "What does this summary look like?",
55255
- description: `This is the summary of how the phone number will be used. For example: "This number is used to send out promotional offers and coupons to the customers of ${business?.name || "my company"}"`
55494
+ control: form.control,
55495
+ disabled: isSubmitting,
55496
+ context: "sms",
55497
+ showInfoCard: true
55256
55498
  }
55257
55499
  ),
55258
- disabled: isSubmitting
55259
- }
55260
- )
55261
- ]
55262
- }
55263
- ),
55264
- /* @__PURE__ */ jsxs(
55265
- FormSection,
55266
- {
55267
- title: "Message Samples",
55268
- description: "Provide examples of messages you plan to send (up to 3 samples).",
55269
- children: [
55270
- /* @__PURE__ */ jsx(AnimatePresence, { children: messageSamples.map((sample, index2) => /* @__PURE__ */ jsxs(
55271
- motion.div,
55272
- {
55273
- initial: { opacity: 0, y: 20 },
55274
- animate: { opacity: 1, y: 0 },
55275
- exit: { opacity: 0, y: -20 },
55276
- transition: { duration: 0.2 },
55277
- className: "relative",
55278
- children: [
55500
+ watchedCountry === "US" && /* @__PURE__ */ jsxs(Fragment$1, { children: [
55279
55501
  /* @__PURE__ */ jsx(
55280
55502
  TextField,
55281
55503
  {
55282
55504
  control: form.control,
55283
- name: `messageSamples.${index2}`,
55284
- label: `Sample Message ${index2 + 1}`,
55285
- placeholder: "Enter a sample message",
55505
+ name: "company.businessRegistrationNumber",
55506
+ label: "Employer Identification Number (EIN)",
55507
+ placeholder: "12-3456789",
55286
55508
  toolTipComponent: /* @__PURE__ */ jsx(
55287
55509
  InfoTooltip,
55288
55510
  {
55289
- title: "Sample Message",
55290
- description: `This is an example message that the shop would send. Don't forget to append the Unsubscribe message to the end. For example: "Stop in at ${business?.name || "my company"} tomorrow for a free Coffee! Reply UNSUBSCRIBE to opt out."`
55511
+ title: "Why do we need this?",
55512
+ description: "Starting February 17th, 2026, all US businesses are required to provide their EIN (Employer Identification Number) when registering for SMS. Your EIN must match the legal business name you've provided above."
55291
55513
  }
55292
55514
  ),
55293
- disabled: isSubmitting
55515
+ disabled: isSoleProprietor || isSubmitting
55294
55516
  }
55295
55517
  ),
55296
- messageSamples.length > 1 && /* @__PURE__ */ jsx(
55297
- motion.button,
55298
- {
55299
- type: "button",
55300
- onClick: () => removeMessageSample(index2),
55301
- className: "absolute -right-2 -top-2 rounded-full bg-destructive/10 p-1 text-destructive hover:bg-destructive/20",
55302
- whileHover: { scale: 1.1 },
55303
- whileTap: { scale: 0.9 },
55304
- children: /* @__PURE__ */ jsx(IconDefinitions.CloseButton, { className: "h-4 w-4" })
55305
- }
55306
- )
55307
- ]
55308
- },
55309
- index2
55310
- )) }),
55311
- messageSamples.length < 3 && /* @__PURE__ */ jsxs(
55312
- motion.button,
55313
- {
55314
- type: "button",
55315
- onClick: addMessageSample,
55316
- className: "mt-4 flex items-center gap-2 rounded-lg border border-dashed border-border px-4 py-2 text-sm text-muted-foreground hover:border-border/80 hover:text-foreground",
55317
- whileHover: { scale: 1.02 },
55318
- whileTap: { scale: 0.98 },
55319
- children: [
55320
- /* @__PURE__ */ jsx(IconDefinitions.PlusIcon, { className: "h-4 w-4" }),
55321
- "Add another sample"
55322
- ]
55323
- }
55324
- )
55325
- ]
55326
- }
55327
- ),
55328
- !hideSubmitButton && /* @__PURE__ */ jsx("div", { className: "flex gap-3 pt-4 justify-end", children: /* @__PURE__ */ jsx(Button$1, { type: "submit", disabled: isSubmitting, children: isSubmitting ? "Submitting..." : "Submit for approval" }) })
55329
- ] }) }) });
55518
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center space-x-2", children: [
55519
+ /* @__PURE__ */ jsx(
55520
+ Checkbox,
55521
+ {
55522
+ checked: isSoleProprietor,
55523
+ onCheckedChange: (checked) => {
55524
+ const isChecked = !!checked;
55525
+ if (isChecked) {
55526
+ form.setValue(
55527
+ "company.businessType",
55528
+ "SOLE_PROPRIETOR"
55529
+ );
55530
+ form.setValue("company.businessRegistrationNumber", "");
55531
+ } else {
55532
+ form.setValue("company.businessType", void 0);
55533
+ }
55534
+ },
55535
+ disabled: isSubmitting
55536
+ }
55537
+ ),
55538
+ /* @__PURE__ */ jsx("label", { className: "text-sm text-muted-foreground cursor-pointer", children: "I am a sole proprietor without an EIN" })
55539
+ ] }),
55540
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground text-pretty", children: "If no EIN is available (e.g., a self-run business or sole prop with no employees), please check the box above." })
55541
+ ] })
55542
+ ]
55543
+ }
55544
+ ),
55545
+ /* @__PURE__ */ jsx(
55546
+ FormSection,
55547
+ {
55548
+ title: "Contact Information",
55549
+ description: "Provide the contact information of the person authorized to represent your business.",
55550
+ children: /* @__PURE__ */ jsx(ContactInfoFields, { control: form.control, disabled: isSubmitting })
55551
+ }
55552
+ ),
55553
+ /* @__PURE__ */ jsxs(
55554
+ FormSection,
55555
+ {
55556
+ title: "Messaging Use Case",
55557
+ description: "Tell us about how you plan to use SMS messaging.",
55558
+ children: [
55559
+ /* @__PURE__ */ jsx(
55560
+ TextField,
55561
+ {
55562
+ control: form.control,
55563
+ name: "messagingUseCase.monthlyVolume",
55564
+ label: "Expected Monthly Volume",
55565
+ placeholder: "1000",
55566
+ type: "number",
55567
+ disabled: isSubmitting
55568
+ }
55569
+ ),
55570
+ /* @__PURE__ */ jsx(
55571
+ TextField,
55572
+ {
55573
+ control: form.control,
55574
+ name: "messagingUseCase.useCaseDetails",
55575
+ label: "Use Case Details",
55576
+ placeholder: "Describe your use case in detail",
55577
+ toolTipComponent: /* @__PURE__ */ jsx(
55578
+ InfoTooltip,
55579
+ {
55580
+ title: "What does this summary look like?",
55581
+ description: `This is the summary of how the phone number will be used. For example: "This number is used to send out promotional offers and coupons to the customers of ${business?.name || "my company"}"`
55582
+ }
55583
+ ),
55584
+ disabled: isSubmitting
55585
+ }
55586
+ )
55587
+ ]
55588
+ }
55589
+ ),
55590
+ /* @__PURE__ */ jsxs(
55591
+ FormSection,
55592
+ {
55593
+ title: "Message Samples",
55594
+ description: "Provide examples of messages you plan to send (up to 3 samples).",
55595
+ children: [
55596
+ /* @__PURE__ */ jsx(AnimatePresence, { children: messageSamples.map((sample, index2) => /* @__PURE__ */ jsxs(
55597
+ motion.div,
55598
+ {
55599
+ initial: { opacity: 0, y: 20 },
55600
+ animate: { opacity: 1, y: 0 },
55601
+ exit: { opacity: 0, y: -20 },
55602
+ transition: { duration: 0.2 },
55603
+ className: "relative",
55604
+ children: [
55605
+ /* @__PURE__ */ jsx(
55606
+ TextField,
55607
+ {
55608
+ control: form.control,
55609
+ name: `messageSamples.${index2}`,
55610
+ label: `Sample Message ${index2 + 1}`,
55611
+ placeholder: "Enter a sample message",
55612
+ toolTipComponent: /* @__PURE__ */ jsx(
55613
+ InfoTooltip,
55614
+ {
55615
+ title: "Sample Message",
55616
+ description: `This is an example message that the shop would send. Don't forget to append the Unsubscribe message to the end. For example: "Stop in at ${business?.name || "my company"} tomorrow for a free Coffee! Reply UNSUBSCRIBE to opt out."`
55617
+ }
55618
+ ),
55619
+ disabled: isSubmitting
55620
+ }
55621
+ ),
55622
+ messageSamples.length > 1 && /* @__PURE__ */ jsx(
55623
+ motion.button,
55624
+ {
55625
+ type: "button",
55626
+ onClick: () => removeMessageSample(index2),
55627
+ className: "absolute -right-2 -top-2 rounded-full bg-destructive/10 p-1 text-destructive hover:bg-destructive/20",
55628
+ whileHover: { scale: 1.1 },
55629
+ whileTap: { scale: 0.9 },
55630
+ children: /* @__PURE__ */ jsx(IconDefinitions.CloseButton, { className: "h-4 w-4" })
55631
+ }
55632
+ )
55633
+ ]
55634
+ },
55635
+ index2
55636
+ )) }),
55637
+ messageSamples.length < 3 && /* @__PURE__ */ jsxs(
55638
+ motion.button,
55639
+ {
55640
+ type: "button",
55641
+ onClick: addMessageSample,
55642
+ className: "mt-4 flex items-center gap-2 rounded-lg border border-dashed border-border px-4 py-2 text-sm text-muted-foreground hover:border-border/80 hover:text-foreground",
55643
+ whileHover: { scale: 1.02 },
55644
+ whileTap: { scale: 0.98 },
55645
+ children: [
55646
+ /* @__PURE__ */ jsx(IconDefinitions.PlusIcon, { className: "h-4 w-4" }),
55647
+ "Add another sample"
55648
+ ]
55649
+ }
55650
+ )
55651
+ ]
55652
+ }
55653
+ ),
55654
+ !hideSubmitButton && /* @__PURE__ */ jsx("div", { className: "flex gap-3 pt-4 justify-end", children: /* @__PURE__ */ jsx(Button$1, { type: "submit", disabled: isSubmitting, children: isSubmitting ? "Submitting..." : "Submit for approval" }) })
55655
+ ]
55656
+ }
55657
+ ) }) });
55330
55658
  });
55331
55659
  const SMSSetup = ({
55332
55660
  onSubmit,
@@ -55345,6 +55673,9 @@ const SMSSetup = ({
55345
55673
  onFormVisibilityChange?.(showForm);
55346
55674
  }, [showForm, onFormVisibilityChange]);
55347
55675
  const handleSubmit = async (data) => {
55676
+ if (isSubmitting) {
55677
+ return;
55678
+ }
55348
55679
  try {
55349
55680
  createSmsRegistrationApplication2({
55350
55681
  application: data,
@@ -55680,33 +56011,31 @@ const SMSChannelSettings = ({
55680
56011
  /* @__PURE__ */ jsx("span", { className: "w-2 h-2 bg-blue-500 rounded-full mr-2" }),
55681
56012
  "Ready to send"
55682
56013
  ] }),
55683
- /* @__PURE__ */ jsx("div", { className: "w-full flex flex-col gap-3 mx-auto", children: smsChannelSenders.map((sender) => {
56014
+ /* @__PURE__ */ jsx("div", { className: "flex flex-col items-center gap-3", children: smsChannelSenders.map((sender) => {
55684
56015
  const isPending = !!sender.channelSender.channelSenderMetadata.friendlyName?.toLowerCase().includes("pending approval");
55685
56016
  const displayName = sender.channelSender.channelSenderMetadata.friendlyName || sender.channelSender.channelSenderMetadata.from || "Unknown Number";
55686
- return /* @__PURE__ */ jsxs(
56017
+ return /* @__PURE__ */ jsx(
55687
56018
  "div",
55688
56019
  {
55689
56020
  className: cn$2(
55690
- "flex items-start rounded-xl px-4 py-3 border shadow-sm",
56021
+ "inline-flex items-center justify-center rounded-full px-5 py-2.5 border shadow-sm",
55691
56022
  isPending ? "bg-gray-50 border-gray-200 text-gray-500" : "bg-blue-50 border-blue-200 text-blue-900 font-semibold"
55692
56023
  ),
55693
- children: [
55694
- /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-3 flex-1 min-w-0", children: [
55695
- isPending ? /* @__PURE__ */ jsx(IconDefinitions.AlertCircleIcon, { className: "w-5 h-5 text-yellow-500 shrink-0 mt-0.5" }) : /* @__PURE__ */ jsx(IconDefinitions.CheckIcon, { className: "w-5 h-5 text-blue-500 shrink-0 mt-0.5" }),
55696
- /* @__PURE__ */ jsx(
55697
- "span",
55698
- {
55699
- className: cn$2(
55700
- "text-sm leading-relaxed",
55701
- isPending ? "break-words" : "truncate"
55702
- ),
55703
- title: displayName,
55704
- children: displayName
55705
- }
55706
- )
55707
- ] }),
56024
+ children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
56025
+ isPending ? /* @__PURE__ */ jsx(IconDefinitions.AlertCircleIcon, { className: "w-5 h-5 text-yellow-500 shrink-0" }) : /* @__PURE__ */ jsx(IconDefinitions.CheckIcon, { className: "w-5 h-5 text-blue-500 shrink-0" }),
56026
+ /* @__PURE__ */ jsx(
56027
+ "span",
56028
+ {
56029
+ className: cn$2(
56030
+ "text-sm leading-relaxed",
56031
+ isPending ? "break-words" : ""
56032
+ ),
56033
+ title: displayName,
56034
+ children: displayName
56035
+ }
56036
+ ),
55708
56037
  !isPending && sender.channelSender.channelSenderMetadata.from && sender.channelSender.channelSenderMetadata.friendlyName !== sender.channelSender.channelSenderMetadata.from && /* @__PURE__ */ jsx("span", { className: "font-mono text-xs text-blue-700 ml-2 shrink-0", children: sender.channelSender.channelSenderMetadata.from })
55709
- ]
56038
+ ] })
55710
56039
  },
55711
56040
  sender.channelSender.id
55712
56041
  );
@@ -56265,7 +56594,10 @@ const useUpdateBusinessAutomation = (automationId) => {
56265
56594
  queryClient.invalidateQueries({
56266
56595
  queryKey: communicationGroupQueryKeys.all
56267
56596
  });
56268
- queryClient.invalidateQueries({ queryKey: automationKeys.list() });
56597
+ queryClient.invalidateQueries({ queryKey: automationKeys.all });
56598
+ queryClient.invalidateQueries({
56599
+ queryKey: automationKeys.estimatedRecipients(automationId)
56600
+ });
56269
56601
  },
56270
56602
  onError: () => {
56271
56603
  }
@@ -56292,7 +56624,7 @@ const useArchiveBusinessAutomation = () => {
56292
56624
  queryClient.invalidateQueries({
56293
56625
  queryKey: communicationGroupQueryKeys.all
56294
56626
  });
56295
- queryClient.invalidateQueries({ queryKey: automationKeys.list() });
56627
+ queryClient.invalidateQueries({ queryKey: automationKeys.all });
56296
56628
  toast2({
56297
56629
  title: "Successfully archived"
56298
56630
  });
@@ -77708,6 +78040,15 @@ const Observability = ({
77708
78040
  flags,
77709
78041
  debug2
77710
78042
  ]);
78043
+ useEffect(() => {
78044
+ try {
78045
+ setReachClient(clientEntryPoint);
78046
+ } catch (e4) {
78047
+ if (debug2) {
78048
+ console.error("Failed to set reach client:", e4);
78049
+ }
78050
+ }
78051
+ }, [clientEntryPoint, debug2]);
77711
78052
  useEffect(() => {
77712
78053
  if (sdk || !isFeHoneycombLogsEnabled || !sessionId) {
77713
78054
  if (debug2) {
@@ -77757,13 +78098,6 @@ const Observability = ({
77757
78098
  ["posthog.sessionId"]: sessionId
77758
78099
  }
77759
78100
  });
77760
- try {
77761
- setReachClient(clientEntryPoint);
77762
- } catch (e4) {
77763
- if (debug2) {
77764
- console.error("Failed to set reach client:", e4);
77765
- }
77766
- }
77767
78101
  sdk.start();
77768
78102
  if (debug2) {
77769
78103
  console.log(
@@ -84466,64 +84800,6 @@ const defaultTranslations = {
84466
84800
  transaction_table_created_header: "Transaction Created"
84467
84801
  },
84468
84802
  common: {
84469
- day: "Day",
84470
- day_other: "Days",
84471
- view_as_table: "View as table",
84472
- view_as_chart: "View as chart",
84473
- total: "Total",
84474
- hour: "Hour",
84475
- hour_other: "Hours",
84476
- minute: "Minute",
84477
- minute_other: "Minutes",
84478
- second: "Second",
84479
- second_other: "Seconds",
84480
- account_id: "Account ID",
84481
- account_name: "Account Name",
84482
- ad_spend: "Ad Spend",
84483
- all: "All",
84484
- apply: "Apply",
84485
- date: "Date",
84486
- campaign: "Campaign",
84487
- close: "Close",
84488
- continue: "Continue",
84489
- connected: "Connected",
84490
- connecting: "Connecting...",
84491
- custom: "Custom",
84492
- disconnect: "Disconnect",
84493
- finish: "Finish",
84494
- reauthenticate: "Reauthenticate",
84495
- account_settings: "Account Settings",
84496
- manage_account_settings: "Manage your account settings",
84497
- copy: "Copy",
84498
- copied: "Copied",
84499
- error: "An error occurred",
84500
- filter: "Filter",
84501
- filter_other: "Filters",
84502
- finishingUp: "Finishing up...",
84503
- loading: "Loading...",
84504
- need_help: "Need help? let us know",
84505
- next: "Next",
84506
- next_steps: "Next steps:",
84507
- number: "{{number}}",
84508
- percentage: "Percentage",
84509
- previous: "Previous",
84510
- reset: "Reset",
84511
- revenue: "Revenue",
84512
- revenue_from_ads: "Revenue From Ads",
84513
- roas: "ROAS",
84514
- source: "Source",
84515
- channel: "Channel",
84516
- referrer: "Referrer",
84517
- group_by: "Group by",
84518
- transactions: "Transactions",
84519
- no_results_found: "No results found",
84520
- utm_campaign: "UTM Campaign",
84521
- utm_medium: "UTM Medium",
84522
- spend: "Spend",
84523
- return_on_ad_spend: "Return on Ad Spend",
84524
- select_dates: "Select dates",
84525
- total_ads_spend: "Total Ads Spend",
84526
- search: "Search...",
84527
84803
  measure: {
84528
84804
  dashboard: {
84529
84805
  chart_empty_state: "No data available for the selected period",
@@ -84594,6 +84870,24 @@ const defaultTranslations = {
84594
84870
  new_customers_description: "The number of first-time customers acquired through your advertising campaigns during the selected period. \n\nThis metric specifically tracks customers who have never purchased from your business before and made their first purchase after interacting with your ads.",
84595
84871
  new_leads: "New Leads",
84596
84872
  new_leads_description: "The number of new potential customers who provided their contact information through your advertising campaigns during the selected period. \n\nLeads are typically generated through form submissions, newsletter signups, download requests, or other lead magnets promoted in your ads.",
84873
+ open_leads: "Open Leads",
84874
+ open_leads_description: "The number of leads who have not yet made a purchase and have had activity within the last 90 days. These are active leads that are still in your pipeline.",
84875
+ converted_leads: "Converted Leads",
84876
+ converted_leads_description: "The number of leads who have made at least one purchase. These leads have successfully converted into paying customers.",
84877
+ stale_leads: "Stale Leads",
84878
+ stale_leads_description: "Leads with no activity (no new identifications, visits, or purchases) for more than 90 days. Consider re-engagement campaigns for these leads.",
84879
+ leads_from_ads: "Leads From Ads",
84880
+ leads_from_ads_description: "The number of new leads attributed to paid advertising during the selected period. \n\nA lead is counted when a visitor provides contact information after interacting with your ads.",
84881
+ cost_per_lead: "Cost Per Lead",
84882
+ cost_per_lead_description: "The average amount spent to acquire each new lead from ads, calculated by dividing ad spend by leads from ads.",
84883
+ lead_to_purchase_rate: "Lead to Purchase Rate",
84884
+ lead_to_purchase_rate_description: "The percentage of leads who went on to make a purchase during the selected period.",
84885
+ total_value_of_open_leads: "Est. Value of Open Leads",
84886
+ total_value_of_open_leads_description: "Estimated potential revenue from leads who have not yet converted. Calculated by multiplying the number of open (unconverted) leads by the average revenue per converted lead. This is a projection, not actual revenue.",
84887
+ total_value_of_converted_leads: "Total Value of Converted Leads",
84888
+ total_value_of_converted_leads_description: "The total revenue from all purchases made by leads who converted during the selected period.",
84889
+ average_lead_value: "Average Lead Value",
84890
+ average_lead_value_description: "The average revenue per converted lead, calculated by dividing converted lead revenue by the number of converted leads.",
84597
84891
  reengaged_customers: "Reengaged Customers",
84598
84892
  reengaged_customers_description: "The number of previously inactive customers who made a purchase after being targeted by your advertising campaigns during the selected period. \n\nThese are customers who had purchased from your business before but had been dormant for a significant period.",
84599
84893
  revenue_per_click: "Revenue Per Click",
@@ -84624,6 +84918,9 @@ const defaultTranslations = {
84624
84918
  not_running_paid_ads: "Not running paid ads? Use AI to create a Google Ads campaign",
84625
84919
  privacy_policy: "Privacy Policy",
84626
84920
  quick_links: "Quick Links",
84921
+ quick_links_and_integrations: "Quick Links + Integrations",
84922
+ connect_callrail: "Connect CallRail",
84923
+ connect_ctm: "Connect CTM",
84627
84924
  setup_tracking_pixel: "Setup tracking pixel",
84628
84925
  understand_attribution_model: "Understand our attribution model",
84629
84926
  update_ad_campaign_settings: "Update ad campaign settings",
@@ -84728,6 +85025,11 @@ For example: If someone clicks your Google ad, we'll show "Google Ads" even if t
84728
85025
  transaction_attributed_description: "Shows all transactions created in the selected date range.",
84729
85026
  transaction_attributed_why_it_matters: "Why it matters: \nUse this to understand actual sales performance during a specific period and where they came from. Transactions are shown based on when the transaction was created, regardless of when or how the customer first discovered your business. This helps you see all revenue that occurred during the selected timeframe, and which digital marketing efforts they are associated to. \n\nExample: \nA customer clicks your ad on Oct 15 but completes their transaction on Nov 3. With Nov 1-30 selected, this transaction appears in your data. With Oct 1-31 selected, it doesn't."
84730
85027
  }
85028
+ },
85029
+ leads: {
85030
+ title: "Leads",
85031
+ prototype_banner_title: "New feature — we're still optimizing",
85032
+ prototype_banner_description: "This experience is actively being improved. We'd love your feedback to help us get it right."
84731
85033
  }
84732
85034
  }
84733
85035
  },
@@ -84741,6 +85043,64 @@ For example: If someone clicks your Google ad, we'll show "Google Ads" even if t
84741
85043
  finalizing_connection: "Finalizing connection..."
84742
85044
  }
84743
85045
  },
85046
+ day: "Day",
85047
+ day_other: "Days",
85048
+ view_as_table: "View as table",
85049
+ view_as_chart: "View as chart",
85050
+ total: "Total",
85051
+ hour: "Hour",
85052
+ hour_other: "Hours",
85053
+ minute: "Minute",
85054
+ minute_other: "Minutes",
85055
+ second: "Second",
85056
+ second_other: "Seconds",
85057
+ account_id: "Account ID",
85058
+ account_name: "Account Name",
85059
+ ad_spend: "Ad Spend",
85060
+ all: "All",
85061
+ apply: "Apply",
85062
+ date: "Date",
85063
+ campaign: "Campaign",
85064
+ close: "Close",
85065
+ continue: "Continue",
85066
+ connected: "Connected",
85067
+ connecting: "Connecting...",
85068
+ custom: "Custom",
85069
+ disconnect: "Disconnect",
85070
+ finish: "Finish",
85071
+ reauthenticate: "Reauthenticate",
85072
+ account_settings: "Account Settings",
85073
+ manage_account_settings: "Manage your account settings",
85074
+ copy: "Copy",
85075
+ copied: "Copied",
85076
+ error: "An error occurred",
85077
+ filter: "Filter",
85078
+ filter_other: "Filters",
85079
+ finishingUp: "Finishing up...",
85080
+ loading: "Loading...",
85081
+ need_help: "Need help? let us know",
85082
+ next: "Next",
85083
+ next_steps: "Next steps:",
85084
+ number: "{{number}}",
85085
+ percentage: "Percentage",
85086
+ previous: "Previous",
85087
+ reset: "Reset",
85088
+ revenue: "Revenue",
85089
+ revenue_from_ads: "Revenue From Ads",
85090
+ roas: "ROAS",
85091
+ source: "Source",
85092
+ channel: "Channel",
85093
+ referrer: "Referrer",
85094
+ group_by: "Group by",
85095
+ transactions: "Transactions",
85096
+ no_results_found: "No results found",
85097
+ utm_campaign: "UTM Campaign",
85098
+ utm_medium: "UTM Medium",
85099
+ spend: "Spend",
85100
+ return_on_ad_spend: "Return on Ad Spend",
85101
+ select_dates: "Select dates",
85102
+ total_ads_spend: "Total Ads Spend",
85103
+ search: "Search...",
84744
85104
  // DELETE
84745
85105
  authentication: {
84746
85106
  required: "Authentication required",
@@ -84807,7 +85167,7 @@ For example: If someone clicks your Google ad, we'll show "Google Ads" even if t
84807
85167
  copied_to_clipboard: "Copied to clipboard",
84808
85168
  copied_to_clipboard_description: "The tracking pixel code has been copied to your clipboard.",
84809
85169
  title: "Install our Tracking Pixel",
84810
- description: "In order to get a complete picture of how users are interacting with your website, it’s important for the Reach analytics code to be on every page of your website and within as many third-party tools that you use as possible.",
85170
+ description: "In order to get a complete picture of how users are interacting with your website, it’s important for the analytics code to be on every page of your website and within as many third-party tools that you use as possible.",
84811
85171
  card_title: "Install the Snippet inside the <HEAD> of every page",
84812
85172
  third_party_pages_your_tracking_pixel: "Your Tracking Pixel:",
84813
85173
  card_description: "Copy this following text and insert it inside of the <HEAD> tags on all pages.",
@@ -84826,7 +85186,7 @@ For example: If someone clicks your Google ad, we'll show "Google Ads" even if t
84826
85186
  },
84827
85187
  third_party_installation_guides: {
84828
85188
  title: "Installation Guides",
84829
- description: "These guides will help you add the Reach analytics snippet to your website. The process works with any website builder or platform and most third-party tools.",
85189
+ description: "These guides will help you add the analytics snippet to your website. The process works with any website builder or platform and most third-party tools.",
84830
85190
  installation_guide: "{{name}} Installation Guide",
84831
85191
  official_guide: "Official Guide",
84832
85192
  shopify: {
@@ -84837,18 +85197,20 @@ For example: If someone clicks your Google ad, we'll show "Google Ads" even if t
84837
85197
  step_5: "Paste the code snippet from the section above just before it"
84838
85198
  },
84839
85199
  google_tag_manager: {
84840
- step_1: "Go to https://tagmanager.google.com",
84841
- step_2: "Sign in to your Google Account",
84842
- step_3: 'In the Tags tab, click the "New" button to create a new tag',
84843
- step_4: 'Choose "Custom HTML" as the tag type',
84844
- step_5: "Paste the tracking code above into the HTML field",
84845
- step_6: "Click anywhere in the triggering section to edit this setting",
84846
- step_7: 'Select "Initialization - All Pages" as the trigger',
84847
- step_8: "Click Save to save the tag",
84848
- step_9: "Click Submit in the top right",
84849
- step_10: "Add a version name and description",
84850
- step_11: "Click Publish to deploy your changes",
84851
- special_note: "Make sure you have the Google Tag Manager container code already installed on your site before adding this tag."
85200
+ step_1: "Go to tagmanager.google.com and sign in with your Google account",
85201
+ step_2: "Select the container for your website (or create one if you haven't already)",
85202
+ step_3: "Important: Make sure your GTM container code is already installed on your website. If not, follow Google's installation instructions first, then return here.",
85203
+ step_3_link: "https://support.google.com/tagmanager/answer/6103696",
85204
+ step_4: 'In the left sidebar, click "Tags", then click the "New" button in the top right',
85205
+ step_5: 'Give your tag a name at the top (e.g., "Source Attribution Pixel")',
85206
+ step_6: 'Click anywhere in the "Tag Configuration" box, then select "Custom HTML" from the tag type menu',
85207
+ step_7: "Paste the tracking code from above into the HTML field (the code already includes the required <script> tags)",
85208
+ step_8: 'Click anywhere in the "Triggering" box below the tag configuration',
85209
+ step_9: 'Select "Initialization - All Pages" to ensure the pixel loads before other tags (recommended), or "All Pages" for standard page load timing',
85210
+ step_10: 'Click "Save" in the top right corner to save your tag',
85211
+ step_11: 'Click "Submit" in the top right corner of the workspace',
85212
+ step_12: 'Add a version name (e.g., "Added source attribution pixel") and click "Publish" to deploy your changes',
85213
+ special_note: "Google Tag Manager works with any website platform. If you already have GTM installed on your site, you can use this method instead of adding code directly to your website's HTML."
84852
85214
  },
84853
85215
  hubspot: {
84854
85216
  step_1: "Go to Settings → Content → Pages",
@@ -84857,18 +85219,30 @@ For example: If someone clicks your Google ad, we'll show "Google Ads" even if t
84857
85219
  step_4: 'Click "Save"'
84858
85220
  },
84859
85221
  wordpress: {
84860
- step_1: "We recommend using the popular WPCode Plugin",
84861
- step_2: 'In the plugin, select "+ Add Snippet"',
84862
- step_3: 'When presented with a menu of options, navigate to "Add Your Custom Code (New Snippet)" and select "Use snippet"',
84863
- step_4: "Paste the code snippet from the section above",
84864
- step_5: 'For Insert Method, choose "Auto Insert"',
84865
- step_6: 'For Location, select "Site Wide Header"',
84866
- step_7: "Be sure to save your snippet"
85222
+ intro: "WordPress sites can add tracking code to the header using various plugins or theme settings. Find your method below and paste the tracking code into the Header section.",
85223
+ methods: [
85224
+ {
85225
+ id: "wpcode",
85226
+ name: "WPCode",
85227
+ description: 'Code Snippets Header & Footer → paste in "Header" section → Save Changes',
85228
+ link: "https://wpcode.com/docs/using-the-global-header-footer-settings/"
85229
+ },
85230
+ {
85231
+ id: "elementor",
85232
+ name: "Elementor",
85233
+ description: 'Elementor → Custom Code → Add New → set location to "<head>" → set conditions to "Entire Site" → Publish',
85234
+ link: "https://elementor.com/help/custom-code-pro/"
85235
+ }
85236
+ ],
85237
+ special_note: "Important: After adding tracking code, clear your WordPress cache if you use a caching plugin (WP Rocket, LiteSpeed Cache, W3 Total Cache, Cloudflare, etc.). The code won't appear on your site until the cache is cleared.\n\nIf you're using a different plugin for custom JavaScript or code injection, check your WordPress Plugins section to identify the plugin and follow that plugin's specific instructions for adding code to the header."
84867
85238
  },
84868
85239
  squarespace: {
84869
- step_1: "Go to Settings Advanced Code Injection",
84870
- step_2: 'Paste the code from the section above into the "Header" field',
84871
- step_3: 'Click "Save"'
85240
+ step_1: "Sign in to your Squarespace account at account.squarespace.com",
85241
+ step_2: 'On the Dashboard, click the "Website" button for the site you want to modify',
85242
+ step_3: 'From the main menu, click "Pages" under the "Website" section',
85243
+ step_4: 'Scroll to the bottom and click "Custom Code", then click "Code Injection". Note: on older versions of Squarespace, "Custom Code" may be labeled "Website Tools"',
85244
+ step_5: 'Under "Header", paste the tracking code from above and click "Save"',
85245
+ special_note: "Code Injection requires a Squarespace Business or Commerce plan. If you don't see the Code Injection option, you may need to upgrade your plan."
84872
85246
  },
84873
85247
  wix: {
84874
85248
  step_1: "Go to Settings → Custom Code",
@@ -85190,7 +85564,7 @@ For example: If someone clicks your Google ad, we'll show "Google Ads" even if t
85190
85564
  fetchAccounts: "Fetching accounts...",
85191
85565
  noAccountSelected: "No account selected",
85192
85566
  enableTrackingParams: "Enable Tracking Parameters",
85193
- enableTrackingParamsDescription: "Append the reach campaign id parameter to your ad platform tracking settings. We will not overwrite any existing tracking parameters. Required for accurate tracking.",
85567
+ enableTrackingParamsDescription: "Append the 'ER' campaign id parameter to your ad platform tracking settings. We will not overwrite any existing tracking parameters. Required for accurate tracking.",
85194
85568
  google: {
85195
85569
  selectAccountDescription: "Select the Google Ads account you want to connect to view your data. These will be linked to our MCC for optimal tracking.",
85196
85570
  mccAccounts: "MCC Accounts",
@@ -86570,448 +86944,19 @@ const previewSegmentRecipients = async (params) => {
86570
86944
  pagination: result2.data.pagination
86571
86945
  };
86572
86946
  };
86573
- var DateUnit;
86574
- (function(DateUnit2) {
86575
- DateUnit2["DAYS"] = "days";
86576
- })(DateUnit || (DateUnit = {}));
86577
- var RelativeDateDirection;
86578
- (function(RelativeDateDirection2) {
86579
- RelativeDateDirection2["BEFORE"] = "before";
86580
- RelativeDateDirection2["AFTER"] = "after";
86581
- })(RelativeDateDirection || (RelativeDateDirection = {}));
86582
- const ConditionFieldEnum = z$2.enum([
86583
- "userId",
86584
- "email",
86585
- "phone",
86586
- "firstName",
86587
- "lastName"
86588
- ]);
86589
- const sqlSegmentConditionSchema = z$2.object({
86590
- sql_segment_id: z$2.string()
86591
- });
86592
- var ConditionOperatorEnumType;
86593
- (function(ConditionOperatorEnumType2) {
86594
- ConditionOperatorEnumType2["EQUALS"] = "equals";
86595
- ConditionOperatorEnumType2["NOT_EQUALS"] = "not_equals";
86596
- ConditionOperatorEnumType2["GREATER_THAN"] = "greater_than";
86597
- ConditionOperatorEnumType2["LESS_THAN"] = "less_than";
86598
- ConditionOperatorEnumType2["EXISTS"] = "exists";
86599
- ConditionOperatorEnumType2["NOT_EXISTS"] = "not_exists";
86600
- ConditionOperatorEnumType2["EQUALS_MONTH_DAY"] = "equals_month_day";
86601
- ConditionOperatorEnumType2["EQUALS_MONTH_DAY_YEAR"] = "equals_month_day_year";
86602
- ConditionOperatorEnumType2["BETWEEN_MONTH_DAY"] = "between_month_day";
86603
- ConditionOperatorEnumType2["BETWEEN_MONTH_DAY_YEAR"] = "between_month_day_year";
86604
- ConditionOperatorEnumType2["ARRAY_CONTAINS"] = "array_contains";
86605
- })(ConditionOperatorEnumType || (ConditionOperatorEnumType = {}));
86606
- const ConditionOperatorEnum = z$2.nativeEnum(ConditionOperatorEnumType);
86607
- const relativeDateSchema = z$2.object({
86608
- type: z$2.literal("relative"),
86609
- value: z$2.number().describe("Number of days to add/subtract from today"),
86610
- unit: z$2.nativeEnum(DateUnit),
86611
- direction: z$2.nativeEnum(RelativeDateDirection)
86612
- });
86613
- const betweenDateSchema = z$2.object({
86614
- startDate: z$2.union([z$2.coerce.date(), relativeDateSchema]),
86615
- endDate: z$2.union([z$2.coerce.date(), relativeDateSchema])
86616
- });
86617
- const fieldConditionSchema = z$2.object({
86618
- field: z$2.union([ConditionFieldEnum, z$2.string()]),
86619
- value: z$2.array(z$2.union([
86620
- z$2.string(),
86621
- z$2.number(),
86622
- z$2.boolean(),
86623
- z$2.date(),
86624
- relativeDateSchema,
86625
- betweenDateSchema
86626
- ])).describe("The value to compare the field against (string, number, boolean, date)"),
86627
- operator: ConditionOperatorEnum
86628
- });
86629
- function isFieldCondition(condition) {
86630
- return "field" in condition;
86631
- }
86632
- const ConditionSchema = z$2.union([
86633
- fieldConditionSchema,
86634
- sqlSegmentConditionSchema
86635
- ]);
86636
- z$2.array(fieldConditionSchema);
86637
- z$2.array(ConditionSchema);
86638
- var CurrencyCode;
86639
- (function(CurrencyCode2) {
86640
- CurrencyCode2["USD"] = "USD";
86641
- CurrencyCode2["CAD"] = "CAD";
86642
- CurrencyCode2["EUR"] = "EUR";
86643
- CurrencyCode2["AED"] = "AED";
86644
- CurrencyCode2["AFN"] = "AFN";
86645
- CurrencyCode2["ALL"] = "ALL";
86646
- CurrencyCode2["AMD"] = "AMD";
86647
- CurrencyCode2["ARS"] = "ARS";
86648
- CurrencyCode2["AUD"] = "AUD";
86649
- CurrencyCode2["AZN"] = "AZN";
86650
- CurrencyCode2["BAM"] = "BAM";
86651
- CurrencyCode2["BDT"] = "BDT";
86652
- CurrencyCode2["BGN"] = "BGN";
86653
- CurrencyCode2["BHD"] = "BHD";
86654
- CurrencyCode2["BIF"] = "BIF";
86655
- CurrencyCode2["BND"] = "BND";
86656
- CurrencyCode2["BOB"] = "BOB";
86657
- CurrencyCode2["BRL"] = "BRL";
86658
- CurrencyCode2["BWP"] = "BWP";
86659
- CurrencyCode2["BYN"] = "BYN";
86660
- CurrencyCode2["BZD"] = "BZD";
86661
- CurrencyCode2["CDF"] = "CDF";
86662
- CurrencyCode2["CHF"] = "CHF";
86663
- CurrencyCode2["CLP"] = "CLP";
86664
- CurrencyCode2["CNY"] = "CNY";
86665
- CurrencyCode2["COP"] = "COP";
86666
- CurrencyCode2["CRC"] = "CRC";
86667
- CurrencyCode2["CVE"] = "CVE";
86668
- CurrencyCode2["CZK"] = "CZK";
86669
- CurrencyCode2["DJF"] = "DJF";
86670
- CurrencyCode2["DKK"] = "DKK";
86671
- CurrencyCode2["DOP"] = "DOP";
86672
- CurrencyCode2["DZD"] = "DZD";
86673
- CurrencyCode2["EEK"] = "EEK";
86674
- CurrencyCode2["EGP"] = "EGP";
86675
- CurrencyCode2["ERN"] = "ERN";
86676
- CurrencyCode2["ETB"] = "ETB";
86677
- CurrencyCode2["GBP"] = "GBP";
86678
- CurrencyCode2["GEL"] = "GEL";
86679
- CurrencyCode2["GHS"] = "GHS";
86680
- CurrencyCode2["GNF"] = "GNF";
86681
- CurrencyCode2["GTQ"] = "GTQ";
86682
- CurrencyCode2["HKD"] = "HKD";
86683
- CurrencyCode2["HNL"] = "HNL";
86684
- CurrencyCode2["HRK"] = "HRK";
86685
- CurrencyCode2["HUF"] = "HUF";
86686
- CurrencyCode2["IDR"] = "IDR";
86687
- CurrencyCode2["ILS"] = "ILS";
86688
- CurrencyCode2["INR"] = "INR";
86689
- CurrencyCode2["IQD"] = "IQD";
86690
- CurrencyCode2["IRR"] = "IRR";
86691
- CurrencyCode2["ISK"] = "ISK";
86692
- CurrencyCode2["JMD"] = "JMD";
86693
- CurrencyCode2["JOD"] = "JOD";
86694
- CurrencyCode2["JPY"] = "JPY";
86695
- CurrencyCode2["KES"] = "KES";
86696
- CurrencyCode2["KHR"] = "KHR";
86697
- CurrencyCode2["KMF"] = "KMF";
86698
- CurrencyCode2["KRW"] = "KRW";
86699
- CurrencyCode2["KWD"] = "KWD";
86700
- CurrencyCode2["KZT"] = "KZT";
86701
- CurrencyCode2["LBP"] = "LBP";
86702
- CurrencyCode2["LKR"] = "LKR";
86703
- CurrencyCode2["LTL"] = "LTL";
86704
- CurrencyCode2["LVL"] = "LVL";
86705
- CurrencyCode2["LYD"] = "LYD";
86706
- CurrencyCode2["MAD"] = "MAD";
86707
- CurrencyCode2["MDL"] = "MDL";
86708
- CurrencyCode2["MGA"] = "MGA";
86709
- CurrencyCode2["MKD"] = "MKD";
86710
- CurrencyCode2["MMK"] = "MMK";
86711
- CurrencyCode2["MOP"] = "MOP";
86712
- CurrencyCode2["MUR"] = "MUR";
86713
- CurrencyCode2["MXN"] = "MXN";
86714
- CurrencyCode2["MYR"] = "MYR";
86715
- CurrencyCode2["MZN"] = "MZN";
86716
- CurrencyCode2["NAD"] = "NAD";
86717
- CurrencyCode2["NGN"] = "NGN";
86718
- CurrencyCode2["NIO"] = "NIO";
86719
- CurrencyCode2["NOK"] = "NOK";
86720
- CurrencyCode2["NPR"] = "NPR";
86721
- CurrencyCode2["NZD"] = "NZD";
86722
- CurrencyCode2["OMR"] = "OMR";
86723
- CurrencyCode2["PAB"] = "PAB";
86724
- CurrencyCode2["PEN"] = "PEN";
86725
- CurrencyCode2["PHP"] = "PHP";
86726
- CurrencyCode2["PKR"] = "PKR";
86727
- CurrencyCode2["PLN"] = "PLN";
86728
- CurrencyCode2["PYG"] = "PYG";
86729
- CurrencyCode2["QAR"] = "QAR";
86730
- CurrencyCode2["RON"] = "RON";
86731
- CurrencyCode2["RSD"] = "RSD";
86732
- CurrencyCode2["RUB"] = "RUB";
86733
- CurrencyCode2["RWF"] = "RWF";
86734
- CurrencyCode2["SAR"] = "SAR";
86735
- CurrencyCode2["SDG"] = "SDG";
86736
- CurrencyCode2["SEK"] = "SEK";
86737
- CurrencyCode2["SGD"] = "SGD";
86738
- CurrencyCode2["SOS"] = "SOS";
86739
- CurrencyCode2["SYP"] = "SYP";
86740
- CurrencyCode2["THB"] = "THB";
86741
- CurrencyCode2["TND"] = "TND";
86742
- CurrencyCode2["TOP"] = "TOP";
86743
- CurrencyCode2["TRY"] = "TRY";
86744
- CurrencyCode2["TTD"] = "TTD";
86745
- CurrencyCode2["TWD"] = "TWD";
86746
- CurrencyCode2["TZS"] = "TZS";
86747
- CurrencyCode2["UAH"] = "UAH";
86748
- CurrencyCode2["UGX"] = "UGX";
86749
- CurrencyCode2["UYU"] = "UYU";
86750
- CurrencyCode2["UZS"] = "UZS";
86751
- CurrencyCode2["VEF"] = "VEF";
86752
- CurrencyCode2["VND"] = "VND";
86753
- CurrencyCode2["XAF"] = "XAF";
86754
- CurrencyCode2["XOF"] = "XOF";
86755
- CurrencyCode2["YER"] = "YER";
86756
- CurrencyCode2["ZAR"] = "ZAR";
86757
- CurrencyCode2["ZMK"] = "ZMK";
86758
- CurrencyCode2["ZWL"] = "ZWL";
86759
- })(CurrencyCode || (CurrencyCode = {}));
86760
- const jsonLogicSchema = z$2.union([
86761
- z$2.boolean(),
86762
- z$2.string(),
86763
- z$2.number(),
86764
- z$2.null(),
86765
- z$2.record(z$2.any()),
86766
- z$2.array(z$2.any())
86767
- ]);
86768
- const schemaMappingEnum = z$2.enum([
86769
- "contacts_schema",
86770
- "transactions_schema",
86771
- "custom_schema",
86772
- "combined_schema",
86773
- // this is a combined schema that contains both contacts and transactions data
86774
- "locations_schema",
86775
- /**
86776
- * This is a schema that contains customer fields for a business (e.g. number of dogs owned, etc.)
86777
- */
86778
- "customer_fields"
86779
- ]);
86780
- var JSONSchemaType;
86781
- (function(JSONSchemaType2) {
86782
- JSONSchemaType2["String"] = "string";
86783
- JSONSchemaType2["Number"] = "number";
86784
- JSONSchemaType2["Integer"] = "integer";
86785
- JSONSchemaType2["Boolean"] = "boolean";
86786
- JSONSchemaType2["Array"] = "array";
86787
- JSONSchemaType2["Date"] = "date";
86788
- JSONSchemaType2["DateTime"] = "date-time";
86789
- JSONSchemaType2["ReachResource"] = "reach-resource";
86790
- })(JSONSchemaType || (JSONSchemaType = {}));
86791
- const contactStatusSchema = z$2.object({
86792
- field: z$2.string(),
86793
- activeValue: z$2.string(),
86794
- deactivatedValue: z$2.string()
86795
- });
86796
- const contactSourceSchema = z$2.object({
86797
- type: z$2.literal(schemaMappingEnum.enum.contacts_schema),
86798
- schemaId: z$2.string().uuid("schemaID must be a UUID referencing a schema definition of type contacts_schema"),
86799
- email: z$2.string().optional(),
86800
- phone: z$2.string().optional(),
86801
- userId: z$2.string().min(1, "User ID field is required"),
86802
- firstName: z$2.string().optional(),
86803
- lastName: z$2.string().optional(),
86804
- fullName: z$2.string().optional(),
86805
- location: z$2.string().optional(),
86806
- status: contactStatusSchema.optional(),
86807
- createdDate: z$2.string().optional(),
86808
- emailOptOut: z$2.string().optional(),
86809
- emailOptIn: z$2.string().optional(),
86810
- emailOptOutTimestamp: z$2.string().optional(),
86811
- smsOptOut: z$2.string().optional(),
86812
- smsOptIn: z$2.string().optional(),
86813
- urlPattern: z$2.string().optional(),
86814
- smsOptOutTimestamp: z$2.string().optional()
86815
- }).refine((data) => {
86816
- const hasFirstAndLast = data.firstName && data.lastName;
86817
- const hasFullName = data.fullName;
86818
- return hasFirstAndLast || hasFullName;
86819
- }, {
86820
- message: "Either both first name and last name, or full name must be provided",
86821
- path: ["firstName"]
86822
- // This will show the error on the firstName field
86823
- }).refine((data) => {
86824
- const hasEmail = data.email && data.email.trim().length > 0;
86825
- const hasPhone = data.phone && data.phone.trim().length > 0;
86826
- return hasEmail || hasPhone;
86827
- }, {
86828
- message: "Either email or phone (or both) must be provided",
86829
- path: ["email"]
86830
- // This will show the error on the email field
86831
- });
86832
- const locationSourceSchema = z$2.object({
86833
- type: z$2.literal(schemaMappingEnum.enum.locations_schema),
86834
- schemaId: z$2.string().uuid("schemaID must be a UUID referencing a schema definition of type locations_schema"),
86835
- id_field: z$2.string().min(1, "ID field is required"),
86836
- name: z$2.string().optional(),
86837
- address_line_1: z$2.string().optional(),
86838
- address_line_2: z$2.string().optional(),
86839
- address_line_3: z$2.string().optional(),
86840
- locality: z$2.string().optional(),
86841
- district: z$2.string().optional(),
86842
- postal_code: z$2.string().optional(),
86843
- country_code: z$2.string().optional(),
86844
- phone: z$2.string().optional(),
86845
- email: z$2.string().optional(),
86846
- website: z$2.string().optional(),
86847
- urlPattern: z$2.string().optional()
86848
- });
86849
- const contactSchemaMappingSchema = z$2.object({
86850
- primarySource: contactSourceSchema,
86851
- additionalSources: z$2.array(contactSourceSchema).optional()
86852
- });
86853
- const billableEventFilterConditionSchema = z$2.object({
86854
- path: z$2.string().describe('Dot notation path to the value, e.g., "primaryServiceType.serviceType.isVisit"'),
86855
- operator: z$2.enum([
86856
- "eq",
86857
- "neq",
86858
- "gt",
86859
- "lt",
86860
- "gte",
86861
- "lte",
86862
- "exists",
86863
- "not_exists"
86864
- ]),
86865
- value: z$2.any().describe('The value to compare against. Not used for "exists" and "not_exists"')
86866
- });
86867
- z$2.object({
86868
- logicalOperator: z$2.enum(["AND", "OR"]).default("AND"),
86869
- conditions: z$2.array(billableEventFilterConditionSchema)
86870
- });
86871
- const transactionAmountSchema = z$2.object({
86872
- field: z$2.string().min(1, "Amount field is required"),
86873
- // the field that contains the amount
86874
- currencyField: z$2.string().optional(),
86875
- // the field that contains the currency
86876
- currency: z$2.nativeEnum(CurrencyCode).optional()
86877
- // the currency of the amount (If has currency field, this is ignored)
86878
- });
86879
- const transactionDatesSchema = z$2.object({
86880
- createdDate: z$2.string().optional(),
86881
- paidDate: z$2.string().optional(),
86882
- dueDate: z$2.string().optional(),
86883
- startDate: z$2.string().optional(),
86884
- endDate: z$2.string().optional()
86885
- });
86886
- const transactionSchema = z$2.object({
86887
- type: z$2.literal(schemaMappingEnum.enum.transactions_schema),
86888
- eventType: z$2.string(),
86889
- schemaId: z$2.string().uuid("schemaID must be a UUID referencing a schema definition of type transactions_schema"),
86890
- id_field: z$2.string().min(1, "ID field is required"),
86891
- userId: z$2.string().min(1, "User ID field is required"),
86892
- amount: transactionAmountSchema,
86893
- dates: transactionDatesSchema,
86894
- locationId: z$2.string().optional().describe("Location ID field"),
86895
- metadata: z$2.array(z$2.string()).optional(),
86896
- filter: jsonLogicSchema.optional().describe("JSONLogic rule to conditionally create billable events from resources. See: https://jsonlogic.com/"),
86897
- urlPattern: z$2.string().optional()
86898
- });
86899
- const customEventSchema = z$2.object({
86900
- type: z$2.literal(schemaMappingEnum.enum.custom_schema),
86901
- id_field: z$2.string().min(1, "ID field is required"),
86902
- date: z$2.string().min(1, "Date field is required"),
86903
- userId: z$2.string().min(1, "User ID field is required"),
86904
- metadata: z$2.array(z$2.string()).optional(),
86905
- schemaId: z$2.string().min(1, "Schema ID is required")
86906
- });
86907
- z$2.object({
86908
- type: z$2.literal(schemaMappingEnum.enum.combined_schema),
86909
- contactsSchema: contactSchemaMappingSchema.optional(),
86910
- transactionsSchema: z$2.array(transactionSchema).optional(),
86911
- customSchema: z$2.array(customEventSchema).optional(),
86912
- locationsSchema: z$2.array(locationSourceSchema).optional()
86913
- });
86914
- var BusinessSegmentTypeEnum;
86915
- (function(BusinessSegmentTypeEnum2) {
86916
- BusinessSegmentTypeEnum2["ALL_USERS"] = "all_users";
86917
- BusinessSegmentTypeEnum2["MANAGED"] = "managed";
86918
- BusinessSegmentTypeEnum2["CUSTOM"] = "custom";
86919
- BusinessSegmentTypeEnum2["ONE_OFF"] = "one_off";
86920
- BusinessSegmentTypeEnum2["SQL"] = "sql";
86921
- })(BusinessSegmentTypeEnum || (BusinessSegmentTypeEnum = {}));
86922
- z$2.object({
86923
- name: z$2.string().describe("A friendly name for the segment"),
86924
- description: z$2.string().describe("A friendly description for the segment").optional(),
86925
- conditions: z$2.array(ConditionSchema).describe("The conditions to include in the segment"),
86926
- type: z$2.enum([BusinessSegmentTypeEnum.CUSTOM, BusinessSegmentTypeEnum.ONE_OFF]).describe("The type of segment").default(BusinessSegmentTypeEnum.CUSTOM).optional()
86927
- });
86928
- z$2.object({
86929
- id: z$2.string().describe("The id of the segment"),
86930
- name: z$2.string().describe("A friendly name for the segment"),
86931
- description: z$2.string().describe("A friendly description for the segment").optional(),
86932
- createdAt: z$2.date().nullable().describe("The date and time the segment was created"),
86933
- type: z$2.nativeEnum(BusinessSegmentTypeEnum).describe("The type of segment")
86934
- });
86935
- z$2.object({
86936
- name: z$2.string().optional().describe("A friendly name for the segment"),
86937
- description: z$2.string().optional().describe("A friendly description for the segment"),
86938
- conditions: z$2.array(ConditionSchema).optional().describe("The conditions to include in the segment")
86939
- });
86940
- z$2.object({
86941
- id: z$2.string().describe("The id of the segment"),
86942
- name: z$2.string().describe("A friendly name for the segment"),
86943
- description: z$2.string().describe("A friendly description for the segment").optional(),
86944
- createdAt: z$2.date().nullable().describe("The date and time the segment was created"),
86945
- type: z$2.nativeEnum(BusinessSegmentTypeEnum).describe("The type of segment")
86946
- });
86947
- z$2.object({
86948
- results: z$2.array(z$2.object({
86949
- id: z$2.string().describe("The id of the segment"),
86950
- name: z$2.string().describe("A friendly name for the segment"),
86951
- description: z$2.string().describe("A friendly description for the segment").optional(),
86952
- createdAt: z$2.date().nullable().describe("The date and time the segment was created"),
86953
- type: z$2.nativeEnum(BusinessSegmentTypeEnum).describe("The type of segment"),
86954
- userCount: z$2.number().describe("The number of users in the segment"),
86955
- phoneCount: z$2.number().describe("The number of phone numbers in the segment"),
86956
- emailCount: z$2.number().describe("The number of emails in the segment"),
86957
- userCountUpdatedAt: z$2.date().describe("The date and time the user count was updated")
86958
- })).describe("The segments"),
86959
- pagination: z$2.object({
86960
- hasNextPage: z$2.boolean().nullable().describe("Whether there is a next page"),
86961
- cursor: z$2.string().nullable().describe("The cursor to start from"),
86962
- total: z$2.number().nullable().describe("The total number of segments")
86963
- })
86964
- });
86965
- z$2.object({
86966
- id: z$2.string().describe("The id of the segment"),
86967
- name: z$2.string().describe("A friendly name for the segment"),
86968
- description: z$2.string().describe("A friendly description for the segment").optional(),
86969
- createdAt: z$2.date().nullable().describe("The date and time the segment was created"),
86970
- type: z$2.nativeEnum(BusinessSegmentTypeEnum).describe("The type of segment"),
86971
- conditions: z$2.array(ConditionSchema).describe("The conditions to include in the segment")
86972
- });
86973
- z$2.object({
86974
- conditions: z$2.array(z$2.object({
86975
- field: z$2.string().describe("The field to include in the segment"),
86976
- operators: z$2.array(ConditionOperatorEnum).describe("The operators to include in the segment"),
86977
- type: z$2.nativeEnum(JSONSchemaType).describe("The type of segment"),
86978
- itemType: z$2.nativeEnum(JSONSchemaType).optional().describe("If the type is an array, this is the type of the items"),
86979
- options: z$2.array(z$2.object({
86980
- displayName: z$2.string().describe("The display name of the option"),
86981
- id: z$2.string().describe("The id of the option")
86982
- })).optional().describe("The options to include in the segment"),
86983
- description: z$2.string().optional().describe("The description of the condition")
86984
- })).describe("The conditions to include in the segment")
86985
- });
86986
- z$2.object({
86987
- count: z$2.number().describe("The number of users in the segment"),
86988
- recipients: z$2.array(z$2.object({
86989
- firstName: z$2.string().nullable().describe("The first name of the recipient"),
86990
- lastName: z$2.string().nullable().describe("The last name of the recipient"),
86991
- email: z$2.string().nullable().describe("The email of the recipient"),
86992
- phone: z$2.string().nullable().describe("The phone of the recipient"),
86993
- id: z$2.string().nullable().describe("The reach id of the recipient"),
86994
- externalId: z$2.string().nullable().describe("The external id of the recipient"),
86995
- emailOptedOut: z$2.boolean().optional().describe("Whether the user has opted out of email"),
86996
- smsOptedOut: z$2.boolean().optional().describe("Whether the user has opted out of SMS")
86997
- })).describe("The recipients in the segment (paginated)"),
86998
- pagination: z$2.object({
86999
- hasNextPage: z$2.boolean().describe("Whether there are more pages"),
87000
- cursor: z$2.string().nullable().describe("Cursor for the next page (null if no more pages)")
87001
- }).describe("Pagination metadata")
87002
- });
87003
- z$2.object({
87004
- success: z$2.boolean().describe("Whether the text to segment was successful"),
87005
- failureReason: z$2.string().optional().describe("The reason the text to segment was not successful."),
87006
- conditions: z$2.array(ConditionSchema).optional().describe("The conditions to include in the segment. If the text to segment was not successful, this will be null"),
87007
- title: z$2.string().optional().describe("A suggested title for the segment generated by AI"),
87008
- description: z$2.string().optional().describe("A suggested description for the segment generated by AI")
87009
- });
87010
- z$2.object({
87011
- cursor: z$2.string().optional().describe("The cursor to start from"),
87012
- limit: z$2.coerce.number().optional().describe("The limit of items to return, default is 100"),
87013
- search: z$2.string().optional().describe("The search query to filter by segment name")
87014
- });
86947
+ var SegmentDefinitionsStatusEnum;
86948
+ (function(SegmentDefinitionsStatusEnum2) {
86949
+ SegmentDefinitionsStatusEnum2["ACTIVE"] = "active";
86950
+ SegmentDefinitionsStatusEnum2["DEACTIVATED"] = "deactivated";
86951
+ })(SegmentDefinitionsStatusEnum || (SegmentDefinitionsStatusEnum = {}));
86952
+ var SegmentDefinitionTypeEnum;
86953
+ (function(SegmentDefinitionTypeEnum2) {
86954
+ SegmentDefinitionTypeEnum2["ALL_USERS"] = "all_users";
86955
+ SegmentDefinitionTypeEnum2["MANAGED"] = "managed";
86956
+ SegmentDefinitionTypeEnum2["CUSTOM"] = "custom";
86957
+ SegmentDefinitionTypeEnum2["ONE_OFF"] = "one_off";
86958
+ SegmentDefinitionTypeEnum2["SQL"] = "sql";
86959
+ })(SegmentDefinitionTypeEnum || (SegmentDefinitionTypeEnum = {}));
87015
86960
  const segmentKeys = {
87016
86961
  all: ["segments"],
87017
86962
  lists: (params) => [
@@ -87284,6 +87229,9 @@ const useParseDate = () => {
87284
87229
  };
87285
87230
  const usePreviewSegmentRecipients = (type, conditions, businessId, options, existingSegmentConditions) => {
87286
87231
  const [debouncedConditions, setDebouncedConditions] = useState(conditions);
87232
+ const [debouncedConditionGroups, setDebouncedConditionGroups] = useState(
87233
+ options?.conditionGroups
87234
+ );
87287
87235
  const [debouncedSearch, setDebouncedSearch] = useState(options?.search || "");
87288
87236
  useEffect(() => {
87289
87237
  const timer = setTimeout(() => {
@@ -87291,6 +87239,12 @@ const usePreviewSegmentRecipients = (type, conditions, businessId, options, exis
87291
87239
  }, options?.debounceMs);
87292
87240
  return () => clearTimeout(timer);
87293
87241
  }, [conditions, options?.debounceMs]);
87242
+ useEffect(() => {
87243
+ const timer = setTimeout(() => {
87244
+ setDebouncedConditionGroups(options?.conditionGroups);
87245
+ }, options?.debounceMs);
87246
+ return () => clearTimeout(timer);
87247
+ }, [options?.conditionGroups, options?.debounceMs]);
87294
87248
  useEffect(() => {
87295
87249
  const timer = setTimeout(() => {
87296
87250
  setDebouncedSearch(options?.search || "");
@@ -87298,7 +87252,7 @@ const usePreviewSegmentRecipients = (type, conditions, businessId, options, exis
87298
87252
  return () => clearTimeout(timer);
87299
87253
  }, [options?.search]);
87300
87254
  const areConditionsValid = (conditions2, type2) => {
87301
- if (type2 === BusinessSegmentTypeEnum.SQL) {
87255
+ if (type2 === SegmentDefinitionTypeEnum.SQL) {
87302
87256
  return true;
87303
87257
  }
87304
87258
  if (conditions2.length === 0) {
@@ -87315,7 +87269,18 @@ const usePreviewSegmentRecipients = (type, conditions, businessId, options, exis
87315
87269
  });
87316
87270
  return isValid2;
87317
87271
  };
87272
+ const areConditionGroupsValid = (conditionGroups) => {
87273
+ if (!conditionGroups || conditionGroups.length === 0) {
87274
+ return false;
87275
+ }
87276
+ return conditionGroups.some(
87277
+ (group) => group.conditions && group.conditions.length > 0
87278
+ );
87279
+ };
87280
+ const hasConditionGroups = areConditionGroupsValid(debouncedConditionGroups);
87281
+ const hasConditions = areConditionsValid(debouncedConditions, type);
87318
87282
  const conditionsKey = JSON.stringify(debouncedConditions);
87283
+ const conditionGroupsKey = JSON.stringify(debouncedConditionGroups || []);
87319
87284
  const existingConditionsKey = JSON.stringify(existingSegmentConditions || []);
87320
87285
  const query = useQuery({
87321
87286
  queryKey: [
@@ -87323,20 +87288,29 @@ const usePreviewSegmentRecipients = (type, conditions, businessId, options, exis
87323
87288
  businessId,
87324
87289
  type,
87325
87290
  conditionsKey,
87291
+ conditionGroupsKey,
87326
87292
  existingConditionsKey,
87327
87293
  debouncedSearch || "",
87328
87294
  options?.limit ?? 100
87329
87295
  ],
87330
87296
  queryFn: () => {
87297
+ if (hasConditionGroups) {
87298
+ return previewSegmentRecipients({
87299
+ businessId,
87300
+ conditionGroups: debouncedConditionGroups,
87301
+ limit: options?.limit ?? 100,
87302
+ search: debouncedSearch || void 0
87303
+ });
87304
+ }
87331
87305
  return previewSegmentRecipients({
87332
87306
  businessId,
87333
87307
  // If the segment is a SQL segment, use the existing segment conditions
87334
- conditions: type === BusinessSegmentTypeEnum.SQL && existingSegmentConditions ? existingSegmentConditions : debouncedConditions,
87308
+ conditions: type === SegmentDefinitionTypeEnum.SQL && existingSegmentConditions ? existingSegmentConditions : debouncedConditions,
87335
87309
  limit: options?.limit ?? 100,
87336
87310
  search: debouncedSearch || void 0
87337
87311
  });
87338
87312
  },
87339
- enabled: (options?.enabled ?? true) && areConditionsValid(debouncedConditions, type),
87313
+ enabled: (options?.enabled ?? true) && (hasConditionGroups || hasConditions),
87340
87314
  staleTime: 3e4,
87341
87315
  // 30 seconds
87342
87316
  gcTime: 5 * 60 * 1e3,
@@ -87356,6 +87330,437 @@ const usePreviewSegmentRecipients = (type, conditions, businessId, options, exis
87356
87330
  refetch: query.refetch
87357
87331
  };
87358
87332
  };
87333
+ var DateUnit;
87334
+ (function(DateUnit2) {
87335
+ DateUnit2["DAYS"] = "days";
87336
+ })(DateUnit || (DateUnit = {}));
87337
+ var RelativeDateDirection;
87338
+ (function(RelativeDateDirection2) {
87339
+ RelativeDateDirection2["BEFORE"] = "before";
87340
+ RelativeDateDirection2["AFTER"] = "after";
87341
+ })(RelativeDateDirection || (RelativeDateDirection = {}));
87342
+ const ConditionFieldEnum = z$2.enum([
87343
+ "userId",
87344
+ "email",
87345
+ "phone",
87346
+ "firstName",
87347
+ "lastName"
87348
+ ]);
87349
+ const sqlSegmentConditionSchema = z$2.object({
87350
+ sql_segment_id: z$2.string()
87351
+ });
87352
+ var ConditionOperatorEnumType;
87353
+ (function(ConditionOperatorEnumType2) {
87354
+ ConditionOperatorEnumType2["EQUALS"] = "equals";
87355
+ ConditionOperatorEnumType2["NOT_EQUALS"] = "not_equals";
87356
+ ConditionOperatorEnumType2["GREATER_THAN"] = "greater_than";
87357
+ ConditionOperatorEnumType2["LESS_THAN"] = "less_than";
87358
+ ConditionOperatorEnumType2["EXISTS"] = "exists";
87359
+ ConditionOperatorEnumType2["NOT_EXISTS"] = "not_exists";
87360
+ ConditionOperatorEnumType2["EQUALS_MONTH_DAY"] = "equals_month_day";
87361
+ ConditionOperatorEnumType2["EQUALS_MONTH_DAY_YEAR"] = "equals_month_day_year";
87362
+ ConditionOperatorEnumType2["BETWEEN_MONTH_DAY"] = "between_month_day";
87363
+ ConditionOperatorEnumType2["BETWEEN_MONTH_DAY_YEAR"] = "between_month_day_year";
87364
+ ConditionOperatorEnumType2["ARRAY_CONTAINS"] = "array_contains";
87365
+ ConditionOperatorEnumType2["CONTAINS"] = "contains";
87366
+ ConditionOperatorEnumType2["NOT_CONTAINS"] = "not_contains";
87367
+ ConditionOperatorEnumType2["IN"] = "in";
87368
+ })(ConditionOperatorEnumType || (ConditionOperatorEnumType = {}));
87369
+ const ConditionOperatorEnum = z$2.nativeEnum(ConditionOperatorEnumType);
87370
+ const relativeDateSchema = z$2.object({
87371
+ type: z$2.literal("relative"),
87372
+ value: z$2.number().describe("Number of days to add/subtract from today"),
87373
+ unit: z$2.nativeEnum(DateUnit),
87374
+ direction: z$2.nativeEnum(RelativeDateDirection)
87375
+ });
87376
+ const betweenDateSchema = z$2.object({
87377
+ startDate: z$2.union([z$2.coerce.date(), relativeDateSchema]),
87378
+ endDate: z$2.union([z$2.coerce.date(), relativeDateSchema])
87379
+ });
87380
+ const fieldConditionSchema = z$2.object({
87381
+ type: z$2.literal("property").optional(),
87382
+ field: z$2.union([ConditionFieldEnum, z$2.string()]),
87383
+ value: z$2.array(z$2.union([
87384
+ z$2.string(),
87385
+ z$2.number(),
87386
+ z$2.boolean(),
87387
+ z$2.date(),
87388
+ relativeDateSchema,
87389
+ betweenDateSchema
87390
+ ])).describe("The value to compare the field against (string, number, boolean, date)"),
87391
+ operator: ConditionOperatorEnum
87392
+ });
87393
+ var CountOperator;
87394
+ (function(CountOperator2) {
87395
+ CountOperator2["EQ"] = "eq";
87396
+ CountOperator2["GT"] = "gt";
87397
+ CountOperator2["GTE"] = "gte";
87398
+ CountOperator2["LT"] = "lt";
87399
+ CountOperator2["LTE"] = "lte";
87400
+ })(CountOperator || (CountOperator = {}));
87401
+ const relatedResourceSchema = z$2.object({
87402
+ /**
87403
+ * The schema definition ID of the related resource to query
87404
+ * (e.g., the PolicyLift policy schema ID)
87405
+ */
87406
+ schemaId: z$2.string(),
87407
+ /**
87408
+ * JSON path in the related resource's data that links to the contact's external_id
87409
+ * (e.g., "customerId" for policies that have a customerId field)
87410
+ */
87411
+ foreignKeyPath: z$2.string()
87412
+ });
87413
+ const relatedResourceConditionSchema = z$2.object({
87414
+ type: z$2.literal("related_resource"),
87415
+ /**
87416
+ * Which related resource to query and how it links to the contact
87417
+ */
87418
+ relatedResource: relatedResourceSchema,
87419
+ /**
87420
+ * How to compare the count of matching resources (eq, gt, gte, lt, lte)
87421
+ */
87422
+ countOperator: z$2.nativeEnum(CountOperator),
87423
+ /**
87424
+ * The count value to compare against (e.g., 0 for "none", 1 for "at least one")
87425
+ */
87426
+ countValue: z$2.number().int().min(0),
87427
+ /**
87428
+ * Conditions to filter the related resources (applied as AND logic)
87429
+ * These conditions are evaluated against the related resource's data
87430
+ */
87431
+ conditions: z$2.array(fieldConditionSchema)
87432
+ });
87433
+ function isFieldCondition(condition) {
87434
+ if (typeof condition !== "object" || condition === null)
87435
+ return false;
87436
+ const c3 = condition;
87437
+ if (c3.type === "property")
87438
+ return true;
87439
+ if (c3.type === "related_resource" || c3.type === "group")
87440
+ return false;
87441
+ return "field" in c3;
87442
+ }
87443
+ var ConditionGroupLogic;
87444
+ (function(ConditionGroupLogic2) {
87445
+ ConditionGroupLogic2["AND"] = "and";
87446
+ ConditionGroupLogic2["OR"] = "or";
87447
+ })(ConditionGroupLogic || (ConditionGroupLogic = {}));
87448
+ const baseConditionItemSchema = z$2.union([
87449
+ fieldConditionSchema,
87450
+ relatedResourceConditionSchema
87451
+ ]);
87452
+ const level2GroupSchema = z$2.object({
87453
+ type: z$2.literal("group").optional().default("group"),
87454
+ logic: z$2.nativeEnum(ConditionGroupLogic),
87455
+ conditions: z$2.array(baseConditionItemSchema)
87456
+ }).transform((val) => ({ ...val, type: "group" }));
87457
+ const level1GroupSchema = z$2.object({
87458
+ type: z$2.literal("group").optional().default("group"),
87459
+ logic: z$2.nativeEnum(ConditionGroupLogic),
87460
+ conditions: z$2.array(z$2.union([baseConditionItemSchema, level2GroupSchema]))
87461
+ }).transform((val) => ({ ...val, type: "group" }));
87462
+ const conditionGroupSchemaFlat = z$2.object({
87463
+ type: z$2.literal("group").optional().default("group"),
87464
+ logic: z$2.nativeEnum(ConditionGroupLogic),
87465
+ conditions: z$2.array(z$2.union([baseConditionItemSchema, level1GroupSchema]))
87466
+ }).transform((val) => ({
87467
+ ...val,
87468
+ type: "group"
87469
+ }));
87470
+ const conditionGroupSchemaRecursive = z$2.lazy(() => z$2.object({
87471
+ type: z$2.literal("group").optional().default("group"),
87472
+ logic: z$2.nativeEnum(ConditionGroupLogic),
87473
+ conditions: z$2.array(z$2.union([
87474
+ fieldConditionSchema,
87475
+ relatedResourceConditionSchema,
87476
+ conditionGroupSchemaRecursive
87477
+ ]))
87478
+ }).transform((val) => ({ ...val, type: "group" })));
87479
+ const conditionGroupSchema = typeof process !== "undefined" && process.env?.GENERATE_DOCS === "true" ? conditionGroupSchemaFlat : conditionGroupSchemaRecursive;
87480
+ const ConditionSchema = z$2.union([
87481
+ fieldConditionSchema,
87482
+ sqlSegmentConditionSchema,
87483
+ relatedResourceConditionSchema
87484
+ ]);
87485
+ z$2.array(fieldConditionSchema);
87486
+ z$2.array(conditionGroupSchema);
87487
+ z$2.array(ConditionSchema);
87488
+ var CurrencyCode;
87489
+ (function(CurrencyCode2) {
87490
+ CurrencyCode2["USD"] = "USD";
87491
+ CurrencyCode2["CAD"] = "CAD";
87492
+ CurrencyCode2["EUR"] = "EUR";
87493
+ CurrencyCode2["AED"] = "AED";
87494
+ CurrencyCode2["AFN"] = "AFN";
87495
+ CurrencyCode2["ALL"] = "ALL";
87496
+ CurrencyCode2["AMD"] = "AMD";
87497
+ CurrencyCode2["ARS"] = "ARS";
87498
+ CurrencyCode2["AUD"] = "AUD";
87499
+ CurrencyCode2["AZN"] = "AZN";
87500
+ CurrencyCode2["BAM"] = "BAM";
87501
+ CurrencyCode2["BDT"] = "BDT";
87502
+ CurrencyCode2["BGN"] = "BGN";
87503
+ CurrencyCode2["BHD"] = "BHD";
87504
+ CurrencyCode2["BIF"] = "BIF";
87505
+ CurrencyCode2["BND"] = "BND";
87506
+ CurrencyCode2["BOB"] = "BOB";
87507
+ CurrencyCode2["BRL"] = "BRL";
87508
+ CurrencyCode2["BWP"] = "BWP";
87509
+ CurrencyCode2["BYN"] = "BYN";
87510
+ CurrencyCode2["BZD"] = "BZD";
87511
+ CurrencyCode2["CDF"] = "CDF";
87512
+ CurrencyCode2["CHF"] = "CHF";
87513
+ CurrencyCode2["CLP"] = "CLP";
87514
+ CurrencyCode2["CNY"] = "CNY";
87515
+ CurrencyCode2["COP"] = "COP";
87516
+ CurrencyCode2["CRC"] = "CRC";
87517
+ CurrencyCode2["CVE"] = "CVE";
87518
+ CurrencyCode2["CZK"] = "CZK";
87519
+ CurrencyCode2["DJF"] = "DJF";
87520
+ CurrencyCode2["DKK"] = "DKK";
87521
+ CurrencyCode2["DOP"] = "DOP";
87522
+ CurrencyCode2["DZD"] = "DZD";
87523
+ CurrencyCode2["EEK"] = "EEK";
87524
+ CurrencyCode2["EGP"] = "EGP";
87525
+ CurrencyCode2["ERN"] = "ERN";
87526
+ CurrencyCode2["ETB"] = "ETB";
87527
+ CurrencyCode2["GBP"] = "GBP";
87528
+ CurrencyCode2["GEL"] = "GEL";
87529
+ CurrencyCode2["GHS"] = "GHS";
87530
+ CurrencyCode2["GNF"] = "GNF";
87531
+ CurrencyCode2["GTQ"] = "GTQ";
87532
+ CurrencyCode2["HKD"] = "HKD";
87533
+ CurrencyCode2["HNL"] = "HNL";
87534
+ CurrencyCode2["HRK"] = "HRK";
87535
+ CurrencyCode2["HUF"] = "HUF";
87536
+ CurrencyCode2["IDR"] = "IDR";
87537
+ CurrencyCode2["ILS"] = "ILS";
87538
+ CurrencyCode2["INR"] = "INR";
87539
+ CurrencyCode2["IQD"] = "IQD";
87540
+ CurrencyCode2["IRR"] = "IRR";
87541
+ CurrencyCode2["ISK"] = "ISK";
87542
+ CurrencyCode2["JMD"] = "JMD";
87543
+ CurrencyCode2["JOD"] = "JOD";
87544
+ CurrencyCode2["JPY"] = "JPY";
87545
+ CurrencyCode2["KES"] = "KES";
87546
+ CurrencyCode2["KHR"] = "KHR";
87547
+ CurrencyCode2["KMF"] = "KMF";
87548
+ CurrencyCode2["KRW"] = "KRW";
87549
+ CurrencyCode2["KWD"] = "KWD";
87550
+ CurrencyCode2["KZT"] = "KZT";
87551
+ CurrencyCode2["LBP"] = "LBP";
87552
+ CurrencyCode2["LKR"] = "LKR";
87553
+ CurrencyCode2["LTL"] = "LTL";
87554
+ CurrencyCode2["LVL"] = "LVL";
87555
+ CurrencyCode2["LYD"] = "LYD";
87556
+ CurrencyCode2["MAD"] = "MAD";
87557
+ CurrencyCode2["MDL"] = "MDL";
87558
+ CurrencyCode2["MGA"] = "MGA";
87559
+ CurrencyCode2["MKD"] = "MKD";
87560
+ CurrencyCode2["MMK"] = "MMK";
87561
+ CurrencyCode2["MOP"] = "MOP";
87562
+ CurrencyCode2["MUR"] = "MUR";
87563
+ CurrencyCode2["MXN"] = "MXN";
87564
+ CurrencyCode2["MYR"] = "MYR";
87565
+ CurrencyCode2["MZN"] = "MZN";
87566
+ CurrencyCode2["NAD"] = "NAD";
87567
+ CurrencyCode2["NGN"] = "NGN";
87568
+ CurrencyCode2["NIO"] = "NIO";
87569
+ CurrencyCode2["NOK"] = "NOK";
87570
+ CurrencyCode2["NPR"] = "NPR";
87571
+ CurrencyCode2["NZD"] = "NZD";
87572
+ CurrencyCode2["OMR"] = "OMR";
87573
+ CurrencyCode2["PAB"] = "PAB";
87574
+ CurrencyCode2["PEN"] = "PEN";
87575
+ CurrencyCode2["PHP"] = "PHP";
87576
+ CurrencyCode2["PKR"] = "PKR";
87577
+ CurrencyCode2["PLN"] = "PLN";
87578
+ CurrencyCode2["PYG"] = "PYG";
87579
+ CurrencyCode2["QAR"] = "QAR";
87580
+ CurrencyCode2["RON"] = "RON";
87581
+ CurrencyCode2["RSD"] = "RSD";
87582
+ CurrencyCode2["RUB"] = "RUB";
87583
+ CurrencyCode2["RWF"] = "RWF";
87584
+ CurrencyCode2["SAR"] = "SAR";
87585
+ CurrencyCode2["SDG"] = "SDG";
87586
+ CurrencyCode2["SEK"] = "SEK";
87587
+ CurrencyCode2["SGD"] = "SGD";
87588
+ CurrencyCode2["SOS"] = "SOS";
87589
+ CurrencyCode2["SYP"] = "SYP";
87590
+ CurrencyCode2["THB"] = "THB";
87591
+ CurrencyCode2["TND"] = "TND";
87592
+ CurrencyCode2["TOP"] = "TOP";
87593
+ CurrencyCode2["TRY"] = "TRY";
87594
+ CurrencyCode2["TTD"] = "TTD";
87595
+ CurrencyCode2["TWD"] = "TWD";
87596
+ CurrencyCode2["TZS"] = "TZS";
87597
+ CurrencyCode2["UAH"] = "UAH";
87598
+ CurrencyCode2["UGX"] = "UGX";
87599
+ CurrencyCode2["UYU"] = "UYU";
87600
+ CurrencyCode2["UZS"] = "UZS";
87601
+ CurrencyCode2["VEF"] = "VEF";
87602
+ CurrencyCode2["VND"] = "VND";
87603
+ CurrencyCode2["XAF"] = "XAF";
87604
+ CurrencyCode2["XOF"] = "XOF";
87605
+ CurrencyCode2["YER"] = "YER";
87606
+ CurrencyCode2["ZAR"] = "ZAR";
87607
+ CurrencyCode2["ZMK"] = "ZMK";
87608
+ CurrencyCode2["ZWL"] = "ZWL";
87609
+ })(CurrencyCode || (CurrencyCode = {}));
87610
+ const jsonLogicSchema = z$2.union([
87611
+ z$2.boolean(),
87612
+ z$2.string(),
87613
+ z$2.number(),
87614
+ z$2.null(),
87615
+ z$2.record(z$2.any()),
87616
+ z$2.array(z$2.any())
87617
+ ]);
87618
+ const schemaMappingEnum = z$2.enum([
87619
+ "contacts_schema",
87620
+ "transactions_schema",
87621
+ "custom_schema",
87622
+ "combined_schema",
87623
+ // this is a combined schema that contains both contacts and transactions data
87624
+ "locations_schema",
87625
+ /**
87626
+ * This is a schema that contains customer fields for a business (e.g. number of dogs owned, etc.)
87627
+ */
87628
+ "customer_fields"
87629
+ ]);
87630
+ var JSONSchemaType;
87631
+ (function(JSONSchemaType2) {
87632
+ JSONSchemaType2["String"] = "string";
87633
+ JSONSchemaType2["Number"] = "number";
87634
+ JSONSchemaType2["Integer"] = "integer";
87635
+ JSONSchemaType2["Boolean"] = "boolean";
87636
+ JSONSchemaType2["Array"] = "array";
87637
+ JSONSchemaType2["Date"] = "date";
87638
+ JSONSchemaType2["DateTime"] = "date-time";
87639
+ JSONSchemaType2["ReachResource"] = "reach-resource";
87640
+ })(JSONSchemaType || (JSONSchemaType = {}));
87641
+ const contactStatusSchema = z$2.object({
87642
+ field: z$2.string(),
87643
+ activeValue: z$2.string(),
87644
+ deactivatedValue: z$2.string()
87645
+ });
87646
+ const contactSourceSchema = z$2.object({
87647
+ type: z$2.literal(schemaMappingEnum.enum.contacts_schema),
87648
+ schemaId: z$2.string().uuid("schemaID must be a UUID referencing a schema definition of type contacts_schema"),
87649
+ email: z$2.string().optional(),
87650
+ phone: z$2.string().optional(),
87651
+ userId: z$2.string().min(1, "User ID field is required"),
87652
+ firstName: z$2.string().optional(),
87653
+ lastName: z$2.string().optional(),
87654
+ fullName: z$2.string().optional(),
87655
+ location: z$2.string().optional(),
87656
+ status: contactStatusSchema.optional(),
87657
+ createdDate: z$2.string().optional(),
87658
+ emailOptOut: z$2.string().optional(),
87659
+ emailOptIn: z$2.string().optional(),
87660
+ emailOptOutTimestamp: z$2.string().optional(),
87661
+ smsOptOut: z$2.string().optional(),
87662
+ smsOptIn: z$2.string().optional(),
87663
+ urlPattern: z$2.string().optional(),
87664
+ smsOptOutTimestamp: z$2.string().optional()
87665
+ }).refine((data) => {
87666
+ const hasFirstAndLast = data.firstName && data.lastName;
87667
+ const hasFullName = data.fullName;
87668
+ return hasFirstAndLast || hasFullName;
87669
+ }, {
87670
+ message: "Either both first name and last name, or full name must be provided",
87671
+ path: ["firstName"]
87672
+ // This will show the error on the firstName field
87673
+ }).refine((data) => {
87674
+ const hasEmail = data.email && data.email.trim().length > 0;
87675
+ const hasPhone = data.phone && data.phone.trim().length > 0;
87676
+ return hasEmail || hasPhone;
87677
+ }, {
87678
+ message: "Either email or phone (or both) must be provided",
87679
+ path: ["email"]
87680
+ // This will show the error on the email field
87681
+ });
87682
+ const locationSourceSchema = z$2.object({
87683
+ type: z$2.literal(schemaMappingEnum.enum.locations_schema),
87684
+ schemaId: z$2.string().uuid("schemaID must be a UUID referencing a schema definition of type locations_schema"),
87685
+ id_field: z$2.string().min(1, "ID field is required"),
87686
+ name: z$2.string().optional(),
87687
+ address_line_1: z$2.string().optional(),
87688
+ address_line_2: z$2.string().optional(),
87689
+ address_line_3: z$2.string().optional(),
87690
+ locality: z$2.string().optional(),
87691
+ district: z$2.string().optional(),
87692
+ postal_code: z$2.string().optional(),
87693
+ country_code: z$2.string().optional(),
87694
+ phone: z$2.string().optional(),
87695
+ email: z$2.string().optional(),
87696
+ website: z$2.string().optional(),
87697
+ urlPattern: z$2.string().optional()
87698
+ });
87699
+ const contactSchemaMappingSchema = z$2.object({
87700
+ primarySource: contactSourceSchema,
87701
+ additionalSources: z$2.array(contactSourceSchema).optional()
87702
+ });
87703
+ const billableEventFilterConditionSchema = z$2.object({
87704
+ path: z$2.string().describe('Dot notation path to the value, e.g., "primaryServiceType.serviceType.isVisit"'),
87705
+ operator: z$2.enum([
87706
+ "eq",
87707
+ "neq",
87708
+ "gt",
87709
+ "lt",
87710
+ "gte",
87711
+ "lte",
87712
+ "exists",
87713
+ "not_exists"
87714
+ ]),
87715
+ value: z$2.any().describe('The value to compare against. Not used for "exists" and "not_exists"')
87716
+ });
87717
+ z$2.object({
87718
+ logicalOperator: z$2.enum(["AND", "OR"]).default("AND"),
87719
+ conditions: z$2.array(billableEventFilterConditionSchema)
87720
+ });
87721
+ const transactionAmountSchema = z$2.object({
87722
+ field: z$2.string().min(1, "Amount field is required"),
87723
+ // the field that contains the amount
87724
+ currencyField: z$2.string().optional(),
87725
+ // the field that contains the currency
87726
+ currency: z$2.nativeEnum(CurrencyCode).optional()
87727
+ // the currency of the amount (If has currency field, this is ignored)
87728
+ });
87729
+ const transactionDatesSchema = z$2.object({
87730
+ createdDate: z$2.string().optional(),
87731
+ paidDate: z$2.string().optional(),
87732
+ dueDate: z$2.string().optional(),
87733
+ startDate: z$2.string().optional(),
87734
+ endDate: z$2.string().optional()
87735
+ });
87736
+ const transactionSchema = z$2.object({
87737
+ type: z$2.literal(schemaMappingEnum.enum.transactions_schema),
87738
+ eventType: z$2.string(),
87739
+ schemaId: z$2.string().uuid("schemaID must be a UUID referencing a schema definition of type transactions_schema"),
87740
+ id_field: z$2.string().min(1, "ID field is required"),
87741
+ userId: z$2.string().min(1, "User ID field is required"),
87742
+ amount: transactionAmountSchema,
87743
+ dates: transactionDatesSchema,
87744
+ locationId: z$2.string().optional().describe("Location ID field"),
87745
+ metadata: z$2.array(z$2.string()).optional(),
87746
+ filter: jsonLogicSchema.optional().describe("JSONLogic rule to conditionally create billable events from resources. See: https://jsonlogic.com/"),
87747
+ urlPattern: z$2.string().optional()
87748
+ });
87749
+ const customEventSchema = z$2.object({
87750
+ type: z$2.literal(schemaMappingEnum.enum.custom_schema),
87751
+ id_field: z$2.string().min(1, "ID field is required"),
87752
+ date: z$2.string().min(1, "Date field is required"),
87753
+ userId: z$2.string().min(1, "User ID field is required"),
87754
+ metadata: z$2.array(z$2.string()).optional(),
87755
+ schemaId: z$2.string().min(1, "Schema ID is required")
87756
+ });
87757
+ z$2.object({
87758
+ type: z$2.literal(schemaMappingEnum.enum.combined_schema),
87759
+ contactsSchema: contactSchemaMappingSchema.optional(),
87760
+ transactionsSchema: z$2.array(transactionSchema).optional(),
87761
+ customSchema: z$2.array(customEventSchema).optional(),
87762
+ locationsSchema: z$2.array(locationSourceSchema).optional()
87763
+ });
87359
87764
  const useRecipientStats$1 = (automation2) => {
87360
87765
  const { data: estimatedMatches } = useGetCountOfBusinessAutomationRecipients({
87361
87766
  includeSegments: automation2?.includeSegmentIds ?? [],
@@ -87471,10 +87876,6 @@ const useCurrentCommunicationGroup = () => {
87471
87876
  isGetSuccess: false
87472
87877
  };
87473
87878
  };
87474
- const useValidationStats = () => {
87475
- const { state } = useViewAutomationContext();
87476
- return state.recipientStats;
87477
- };
87478
87879
  const useRecipientStatsTracking = (existingAutomation) => {
87479
87880
  const { setRecipientStats: setRecipientStats2, state } = useViewAutomationContext();
87480
87881
  const automation2 = state.automation || existingAutomation;
@@ -91061,6 +91462,7 @@ function useTanstackTable({
91061
91462
  initialPageIndex = 0,
91062
91463
  cursorPaginationQueryResult,
91063
91464
  onQueryParametersChange,
91465
+ resetPaginationKey,
91064
91466
  manualPageCount,
91065
91467
  enableSorting = true,
91066
91468
  initialSorting = [],
@@ -91176,6 +91578,16 @@ function useTanstackTable({
91176
91578
  pageIndex: initialPageIndex,
91177
91579
  pageSize: initialPageSize
91178
91580
  });
91581
+ useEffect(() => {
91582
+ if (resetPaginationKey !== void 0) {
91583
+ setLogicalPage(initialPageIndex);
91584
+ setPageCursors([void 0]);
91585
+ setPagination({
91586
+ pageIndex: initialPageIndex,
91587
+ pageSize: pagination.pageSize
91588
+ });
91589
+ }
91590
+ }, [resetPaginationKey]);
91179
91591
  const handleCursorNavigation = useCallback(
91180
91592
  (action) => {
91181
91593
  if (!isCursorPagination || !onQueryParametersChange) return;
@@ -91384,6 +91796,7 @@ function TanstackTable({
91384
91796
  hideLoadingState = false,
91385
91797
  cursorPaginationQueryResult,
91386
91798
  onQueryParametersChange,
91799
+ resetPaginationKey,
91387
91800
  searchValue,
91388
91801
  onSearchChange,
91389
91802
  onRowClick,
@@ -91437,6 +91850,7 @@ function TanstackTable({
91437
91850
  initialPageIndex,
91438
91851
  cursorPaginationQueryResult,
91439
91852
  onQueryParametersChange,
91853
+ resetPaginationKey,
91440
91854
  enableSorting,
91441
91855
  initialSorting,
91442
91856
  manualSorting,
@@ -94503,40 +94917,40 @@ const getAutomationStatusVariant = (status) => {
94503
94917
  };
94504
94918
  const getTypeDescription = (type) => {
94505
94919
  switch (type) {
94506
- case BusinessSegmentTypeEnum.ALL_USERS:
94920
+ case SegmentDefinitionTypeEnum.ALL_USERS:
94507
94921
  return `Default ${t$2("engage:segment").toLowerCase()} that contains all ${t$2("engage:user", { count: 2 }).toLowerCase()}. This is not editable or deletable.`;
94508
- case BusinessSegmentTypeEnum.MANAGED:
94922
+ case SegmentDefinitionTypeEnum.MANAGED:
94509
94923
  return `System-defined ${t$2("engage:segment").toLowerCase()} that are not editable or deletable.`;
94510
- case BusinessSegmentTypeEnum.CUSTOM:
94924
+ case SegmentDefinitionTypeEnum.CUSTOM:
94511
94925
  return `Custom ${t$2("engage:segment").toLowerCase()} that you can edit and delete as needed.`;
94512
- case BusinessSegmentTypeEnum.SQL:
94926
+ case SegmentDefinitionTypeEnum.SQL:
94513
94927
  return `SQL-defined ${t$2("engage:segment").toLowerCase()} that are not editable or deletable.`;
94514
- case BusinessSegmentTypeEnum.ONE_OFF:
94928
+ case SegmentDefinitionTypeEnum.ONE_OFF:
94515
94929
  return `One-off ${t$2("engage:segment").toLowerCase()} that are not editable or deletable.`;
94516
94930
  default:
94517
- throw UnreachableCaseStatement(type, BusinessSegmentTypeEnum);
94931
+ throw UnreachableCaseStatement(type, SegmentDefinitionTypeEnum);
94518
94932
  }
94519
94933
  };
94520
94934
  const getSegmentTypeVariant = (type) => {
94521
94935
  switch (type) {
94522
- case BusinessSegmentTypeEnum.ALL_USERS:
94936
+ case SegmentDefinitionTypeEnum.ALL_USERS:
94523
94937
  return "segmentAllUsers";
94524
- case BusinessSegmentTypeEnum.MANAGED:
94938
+ case SegmentDefinitionTypeEnum.MANAGED:
94525
94939
  return "segmentManaged";
94526
- case BusinessSegmentTypeEnum.CUSTOM:
94940
+ case SegmentDefinitionTypeEnum.CUSTOM:
94527
94941
  return "segmentCustom";
94528
- case BusinessSegmentTypeEnum.ONE_OFF:
94529
- case BusinessSegmentTypeEnum.SQL:
94942
+ case SegmentDefinitionTypeEnum.ONE_OFF:
94943
+ case SegmentDefinitionTypeEnum.SQL:
94530
94944
  return "segmentManaged";
94531
94945
  default:
94532
- throw UnreachableCaseStatement(type, BusinessSegmentTypeEnum);
94946
+ throw UnreachableCaseStatement(type, SegmentDefinitionTypeEnum);
94533
94947
  }
94534
94948
  };
94535
94949
  function createNameColumn(nameAccessor = "name", headerText, showDescription = false) {
94536
94950
  return createTextColumn({
94537
94951
  accessorKey: nameAccessor,
94538
94952
  header: headerText,
94539
- enableSorting: false,
94953
+ enableSorting: true,
94540
94954
  meta: {
94541
94955
  align: "left",
94542
94956
  displayName: headerText,
@@ -94562,12 +94976,12 @@ function createNameColumn(nameAccessor = "name", headerText, showDescription = f
94562
94976
  [AutomationStatus.ARCHIVED]: "bg-gray-500"
94563
94977
  };
94564
94978
  const typeDotStyles = {
94565
- [BusinessSegmentTypeEnum.ALL_USERS]: "bg-purple-500",
94566
- [BusinessSegmentTypeEnum.MANAGED]: "bg-teal-500",
94567
- [BusinessSegmentTypeEnum.CUSTOM]: "bg-amber-500",
94568
- [BusinessSegmentTypeEnum.SQL]: "bg-teal-500",
94979
+ [SegmentDefinitionTypeEnum.ALL_USERS]: "bg-purple-500",
94980
+ [SegmentDefinitionTypeEnum.MANAGED]: "bg-teal-500",
94981
+ [SegmentDefinitionTypeEnum.CUSTOM]: "bg-amber-500",
94982
+ [SegmentDefinitionTypeEnum.SQL]: "bg-teal-500",
94569
94983
  // Same as managed
94570
- [BusinessSegmentTypeEnum.ONE_OFF]: "bg-orange-500"
94984
+ [SegmentDefinitionTypeEnum.ONE_OFF]: "bg-orange-500"
94571
94985
  };
94572
94986
  const dotColor = type ? typeDotStyles[type] : status ? badgeStyles[status] : "bg-blue-500";
94573
94987
  return /* @__PURE__ */ jsx("div", { className: "w-full flex gap-2 sm:gap-4 md:gap-6 justify-between items-center", children: /* @__PURE__ */ jsxs("div", { className: "flex gap-1 items-center w-full min-w-0", children: [
@@ -94589,7 +95003,7 @@ function createUsersColumn() {
94589
95003
  return createTextColumn({
94590
95004
  accessorKey: "user_count",
94591
95005
  header: t$2("engage:user_other"),
94592
- enableSorting: false,
95006
+ enableSorting: true,
94593
95007
  size: 120,
94594
95008
  minSize: 100,
94595
95009
  headerClassName: "justify-end text-right w-full",
@@ -94610,7 +95024,7 @@ function createTypeColumn() {
94610
95024
  return createTextColumn({
94611
95025
  accessorKey: "type",
94612
95026
  header: "Type",
94613
- enableSorting: false,
95027
+ enableSorting: true,
94614
95028
  size: 110,
94615
95029
  minSize: 90,
94616
95030
  headerClassName: "justify-end text-right w-full",
@@ -94621,15 +95035,15 @@ function createTypeColumn() {
94621
95035
  cellClassName: "pr-2 sm:pr-3 md:pr-4",
94622
95036
  cellFormatter: (info) => {
94623
95037
  const typeFromCell = info.getValue();
94624
- const displayText = typeFromCell ? typeFromCell === BusinessSegmentTypeEnum.SQL ? "Managed" : typeFromCell.split("_").map((word) => word[0].toUpperCase() + word.slice(1).toLowerCase()).join(" ") : "Unknown";
95038
+ const displayText = typeFromCell ? typeFromCell === SegmentDefinitionTypeEnum.SQL ? "Managed" : typeFromCell.split("_").map((word) => word[0].toUpperCase() + word.slice(1).toLowerCase()).join(" ") : "Unknown";
94625
95039
  let badgeVariant;
94626
- if (typeFromCell && (typeFromCell === BusinessSegmentTypeEnum.ALL_USERS || typeFromCell === BusinessSegmentTypeEnum.MANAGED || typeFromCell === BusinessSegmentTypeEnum.CUSTOM || typeFromCell === BusinessSegmentTypeEnum.SQL)) {
95040
+ if (typeFromCell && (typeFromCell === SegmentDefinitionTypeEnum.ALL_USERS || typeFromCell === SegmentDefinitionTypeEnum.MANAGED || typeFromCell === SegmentDefinitionTypeEnum.CUSTOM || typeFromCell === SegmentDefinitionTypeEnum.SQL)) {
94627
95041
  try {
94628
95042
  badgeVariant = getSegmentTypeVariant(typeFromCell);
94629
95043
  } catch (e4) {
94630
95044
  if (e4 instanceof UnreachableCaseStatement) {
94631
95045
  console.error(
94632
- `Unhandled BusinessSegmentTypeEnum member in getSegmentTypeVariant: ${typeFromCell}`,
95046
+ `Unhandled SegmentDefinitionTypeEnum member in getSegmentTypeVariant: ${typeFromCell}`,
94633
95047
  e4
94634
95048
  );
94635
95049
  badgeVariant = "statusDraft";
@@ -94666,7 +95080,7 @@ function createModifiedColumn(dateAccessor = "updated_at") {
94666
95080
  formatType: "relative",
94667
95081
  size: 160,
94668
95082
  minSize: 120,
94669
- enableSorting: false,
95083
+ enableSorting: true,
94670
95084
  headerClassName: "justify-end text-right w-full",
94671
95085
  meta: {
94672
95086
  align: "right",
@@ -94846,6 +95260,57 @@ function createColumns(args) {
94846
95260
  ];
94847
95261
  }
94848
95262
  const DEFAULT_LOGO_URL = "https://assets.embedreach.com/defaults/logo-placeholder-128.png";
95263
+ var ChannelType = /* @__PURE__ */ ((ChannelType2) => {
95264
+ ChannelType2["EMAIL"] = "email";
95265
+ ChannelType2["SMS"] = "sms";
95266
+ return ChannelType2;
95267
+ })(ChannelType || {});
95268
+ var CommunicationSubStepType$1 = /* @__PURE__ */ ((CommunicationSubStepType2) => {
95269
+ CommunicationSubStepType2["EMAIL"] = "email";
95270
+ CommunicationSubStepType2["SMS"] = "sms";
95271
+ return CommunicationSubStepType2;
95272
+ })(CommunicationSubStepType$1 || {});
95273
+ const capitalize = (str) => {
95274
+ if (!str) return str;
95275
+ return str.charAt(0).toUpperCase() + str.slice(1);
95276
+ };
95277
+ const getDisplayName = (recipient, fallbackText = "Unnamed User") => {
95278
+ const fullName = `${recipient.firstName || ""} ${recipient.lastName || ""}`.trim();
95279
+ if (fullName) return fullName;
95280
+ if (recipient.firstName) return recipient.firstName;
95281
+ if (recipient.lastName) return recipient.lastName;
95282
+ if (recipient.email) return recipient.email;
95283
+ if (recipient.phone) return recipient.phone;
95284
+ return fallbackText;
95285
+ };
95286
+ const RECIPIENT_SEARCH_PLACEHOLDER = `Search by name, email, or phone...`;
95287
+ const getMergeFieldsFromUrl = (url, getMergeFields2) => {
95288
+ if (!url || !getMergeFields2) return [];
95289
+ const regex = /\{\{([^}]+)\}\}/g;
95290
+ const matches2 = [...url.matchAll(regex)];
95291
+ return matches2.map((match2) => {
95292
+ const mergeFieldValue = match2[1];
95293
+ const mergeField = getMergeFields2.mergeFields?.flatMap((f2) => f2.entries).find((entry) => entry.value === `{{${mergeFieldValue}}}`);
95294
+ return mergeField ? mergeField.label : mergeFieldValue;
95295
+ }).filter(Boolean);
95296
+ };
95297
+ const convertScheduledAtToScheduleSendAt = (scheduledAt) => {
95298
+ if (scheduledAt === null || scheduledAt === void 0) {
95299
+ return null;
95300
+ }
95301
+ if (scheduledAt === "now") {
95302
+ return (/* @__PURE__ */ new Date()).toISOString();
95303
+ }
95304
+ return scheduledAt;
95305
+ };
95306
+ const getScheduleSendAtFromAutomation = (automation2) => {
95307
+ if (automation2?.triggerMetadata && automation2.triggerMetadata.triggerType === AutomationTriggerType.ONE_TIME && "scheduledAt" in automation2.triggerMetadata) {
95308
+ return convertScheduledAtToScheduleSendAt(
95309
+ automation2.triggerMetadata.scheduledAt
95310
+ );
95311
+ }
95312
+ return null;
95313
+ };
94849
95314
  const BackNextButtonGroup = ({
94850
95315
  handleBack,
94851
95316
  handleNext,
@@ -95455,27 +95920,17 @@ var BuiltInActionIds = /* @__PURE__ */ ((BuiltInActionIds2) => {
95455
95920
  BuiltInActionIds2["EditTime"] = "edit-time";
95456
95921
  return BuiltInActionIds2;
95457
95922
  })(BuiltInActionIds || {});
95458
- var CommunicationSubStepType$1 = /* @__PURE__ */ ((CommunicationSubStepType2) => {
95923
+ var CommunicationSubStepType = /* @__PURE__ */ ((CommunicationSubStepType2) => {
95459
95924
  CommunicationSubStepType2["EMAIL"] = "email";
95460
95925
  CommunicationSubStepType2["SMS"] = "sms";
95461
95926
  return CommunicationSubStepType2;
95462
- })(CommunicationSubStepType$1 || {});
95927
+ })(CommunicationSubStepType || {});
95463
95928
  var AutomationTabs = /* @__PURE__ */ ((AutomationTabs2) => {
95464
95929
  AutomationTabs2["WORKFLOW"] = "workflow";
95465
95930
  AutomationTabs2["RECIPIENTS"] = "recipients";
95466
95931
  AutomationTabs2["INSIGHTS"] = "insights";
95467
95932
  return AutomationTabs2;
95468
95933
  })(AutomationTabs || {});
95469
- var ChannelType = /* @__PURE__ */ ((ChannelType2) => {
95470
- ChannelType2["EMAIL"] = "email";
95471
- ChannelType2["SMS"] = "sms";
95472
- return ChannelType2;
95473
- })(ChannelType || {});
95474
- var CommunicationSubStepType = /* @__PURE__ */ ((CommunicationSubStepType2) => {
95475
- CommunicationSubStepType2["EMAIL"] = "email";
95476
- CommunicationSubStepType2["SMS"] = "sms";
95477
- return CommunicationSubStepType2;
95478
- })(CommunicationSubStepType || {});
95479
95934
  const DEFAULT_EMAIL_PREVIEW_HEIGHT = 400;
95480
95935
  const SMS_LIMITS = {
95481
95936
  ABSOLUTE_LIMIT: 1500,
@@ -95826,164 +96281,6 @@ const EmailPreviewHtmlRenderer = ({
95826
96281
  }
95827
96282
  ) });
95828
96283
  };
95829
- const truncateTextForIcon = (text2, maxWidth = 200, iconWidth = 32) => {
95830
- if (text2.length <= 20) return text2;
95831
- const avgCharWidth = 8;
95832
- const availableWidth = maxWidth - iconWidth - 16;
95833
- const maxChars = Math.floor(availableWidth / avgCharWidth);
95834
- if (text2.length <= maxChars) return text2;
95835
- return text2.substring(0, maxChars - 3) + "...";
95836
- };
95837
- const ComboboxSelect = ({
95838
- options,
95839
- value,
95840
- onChange: onChange2,
95841
- placeholder,
95842
- className = "",
95843
- disableInput = false,
95844
- disabled = false,
95845
- onOpenChange,
95846
- limitWhenNotSearching,
95847
- onSearchChange,
95848
- isLoading = false,
95849
- shouldFilter = true,
95850
- showEmptyState = true
95851
- }) => {
95852
- const [open, setOpen2] = React.useState(false);
95853
- const [searchQuery, setSearchQuery] = React.useState("");
95854
- const triggerRef = React.useRef(null);
95855
- const [triggerWidth, setTriggerWidth] = React.useState();
95856
- React.useEffect(() => {
95857
- if (triggerRef.current && open) {
95858
- setTriggerWidth(triggerRef.current.offsetWidth);
95859
- }
95860
- }, [open]);
95861
- const handleOpenChange = (newOpen) => {
95862
- setOpen2(newOpen);
95863
- if (!newOpen && !onSearchChange) {
95864
- setSearchQuery("");
95865
- }
95866
- onOpenChange?.(newOpen);
95867
- };
95868
- const handleSearchChange = (search2) => {
95869
- setSearchQuery(search2);
95870
- onSearchChange?.(search2);
95871
- };
95872
- const displayOptions = React.useMemo(() => {
95873
- if (!shouldFilter) return options;
95874
- if (!limitWhenNotSearching) return options;
95875
- const query = searchQuery.trim().toLowerCase();
95876
- if (!query) {
95877
- return options.slice(0, limitWhenNotSearching);
95878
- }
95879
- const filtered = options.filter((option) => {
95880
- const searchableText = [
95881
- option.label,
95882
- option.description || "",
95883
- option.value
95884
- ].join(" ").toLowerCase();
95885
- return searchableText.includes(query);
95886
- });
95887
- return filtered.slice(0, 200);
95888
- }, [options, searchQuery, limitWhenNotSearching, shouldFilter]);
95889
- return /* @__PURE__ */ jsxs(
95890
- Popover,
95891
- {
95892
- modal: true,
95893
- open: disabled ? false : open,
95894
- onOpenChange: disabled ? void 0 : handleOpenChange,
95895
- children: [
95896
- /* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(
95897
- Button$1,
95898
- {
95899
- ref: triggerRef,
95900
- "aria-expanded": open,
95901
- disabled,
95902
- className: cn$2(
95903
- "w-full overflow-hidden justify-between",
95904
- disabled && "bg-gray-50 text-gray-700 cursor-not-allowed",
95905
- className
95906
- ),
95907
- variant: "outline",
95908
- children: [
95909
- /* @__PURE__ */ jsx(
95910
- "span",
95911
- {
95912
- className: "truncate",
95913
- title: value ? options.find((option) => option.value === value)?.label : placeholder,
95914
- children: value ? truncateTextForIcon(
95915
- options.find((option) => option.value === value)?.label || "",
95916
- 200,
95917
- 32
95918
- ) : placeholder
95919
- }
95920
- ),
95921
- /* @__PURE__ */ jsx(ChevronsUpDown, { className: "ml-2 h-4 w-4 flex-shrink-0 opacity-50" })
95922
- ]
95923
- }
95924
- ) }),
95925
- /* @__PURE__ */ jsx(
95926
- PopoverContent,
95927
- {
95928
- align: "start",
95929
- style: {
95930
- width: triggerWidth ? `${triggerWidth}px` : "300px",
95931
- minWidth: triggerWidth ? `${triggerWidth}px` : "300px"
95932
- },
95933
- className: cn$2("p-0", className),
95934
- children: /* @__PURE__ */ jsxs(Command, { shouldFilter, children: [
95935
- !disableInput && /* @__PURE__ */ jsx(
95936
- CommandInput,
95937
- {
95938
- placeholder: `${placeholder}...`,
95939
- onValueChange: handleSearchChange
95940
- }
95941
- ),
95942
- /* @__PURE__ */ jsxs(CommandList, { children: [
95943
- !isLoading && showEmptyState && /* @__PURE__ */ jsx(CommandEmpty, { children: "No results found." }),
95944
- /* @__PURE__ */ jsx(CommandGroup, { children: isLoading ? (
95945
- // Show skeleton loaders while loading
95946
- Array.from({ length: 5 }).map((_2, index2) => /* @__PURE__ */ jsx(CommandItem, { disabled: true, children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 w-full", children: [
95947
- /* @__PURE__ */ jsx("div", { className: "h-4 w-4 bg-gray-200 rounded animate-pulse" }),
95948
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1 flex-1", children: [
95949
- /* @__PURE__ */ jsx("div", { className: "h-4 bg-gray-200 rounded animate-pulse w-3/4" }),
95950
- /* @__PURE__ */ jsx("div", { className: "h-3 bg-gray-200 rounded animate-pulse w-1/2" })
95951
- ] })
95952
- ] }) }, `skeleton-${index2}`))
95953
- ) : displayOptions.map((option) => /* @__PURE__ */ jsxs(
95954
- CommandItem,
95955
- {
95956
- value: option.value,
95957
- onSelect: () => {
95958
- onChange2(option.value === value ? "" : option.value);
95959
- handleOpenChange(false);
95960
- },
95961
- children: [
95962
- /* @__PURE__ */ jsx(
95963
- Check,
95964
- {
95965
- className: cn$2(
95966
- "mr-2 h-4 w-4 flex-shrink-0",
95967
- value === option.value ? "opacity-100" : "opacity-0"
95968
- )
95969
- }
95970
- ),
95971
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col overflow-hidden flex-1 min-w-0", children: [
95972
- /* @__PURE__ */ jsx("span", { className: "font-medium break-words", children: option.label }),
95973
- option.description && /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground break-words", children: option.description })
95974
- ] })
95975
- ]
95976
- },
95977
- option.id || option.value
95978
- )) })
95979
- ] })
95980
- ] })
95981
- }
95982
- )
95983
- ]
95984
- }
95985
- );
95986
- };
95987
96284
  const SendPreviewPopup = ({ type, setOpenSendPreviewPopup, open }) => {
95988
96285
  const [recipient, setRecipient] = useState("");
95989
96286
  const [error2, setError2] = useState("");
@@ -96017,7 +96314,7 @@ const SendPreviewPopup = ({ type, setOpenSendPreviewPopup, open }) => {
96017
96314
  setIsLoadingUsers(true);
96018
96315
  try {
96019
96316
  const allUsersSegment = segments.find(
96020
- (segment2) => segment2.type === BusinessSegmentTypeEnum.ALL_USERS
96317
+ (segment2) => segment2.type === SegmentDefinitionTypeEnum.ALL_USERS
96021
96318
  );
96022
96319
  if (allUsersSegment) {
96023
96320
  const searchResponse = await getCountOfBusinessAutomationRecipients({
@@ -96130,9 +96427,6 @@ const SendPreviewPopup = ({ type, setOpenSendPreviewPopup, open }) => {
96130
96427
  setSearchResults(void 0);
96131
96428
  }
96132
96429
  }, [open]);
96133
- useEffect(() => {
96134
- setTimeout(() => document.body.style.pointerEvents = "", 0);
96135
- }, []);
96136
96430
  const humanReadableTypeLong = type === "email" ? "email address" : "phone number";
96137
96431
  const humanReadableTypeShort = type === "email" ? "email" : "text";
96138
96432
  const handleSendPreview = () => {
@@ -96238,52 +96532,86 @@ const SendPreviewPopup = ({ type, setOpenSendPreviewPopup, open }) => {
96238
96532
  /* @__PURE__ */ jsx("span", { className: "text-gray-500 font-normal", children: "(optional)" })
96239
96533
  ] })
96240
96534
  ] }),
96241
- /* @__PURE__ */ jsxs("div", { className: "flex items-stretch gap-2", children: [
96242
- /* @__PURE__ */ jsx("div", { className: "flex-1 min-w-0", children: /* @__PURE__ */ jsx(
96243
- ComboboxSelect,
96244
- {
96245
- options: recipientOptions,
96246
- value: selectedPreviewAsRecipientId,
96247
- onChange: (value) => {
96248
- setSelectedPreviewAsRecipientId(value);
96249
- },
96250
- placeholder: "Search for a customer...",
96251
- disableInput: false,
96252
- disabled: cantSendEmail,
96253
- onSearchChange: setSearchQuery,
96254
- isLoading: isLoadingUsers,
96255
- shouldFilter: false,
96256
- showEmptyState: debouncedSearchQuery.trim().length > 0
96257
- }
96258
- ) }),
96259
- selectedPreviewAsRecipientId && /* @__PURE__ */ jsx(
96535
+ selectedPreviewAsRecipientId && /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between p-2 bg-blue-50 border border-blue-200 rounded-lg", children: [
96536
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-medium text-blue-900 truncate", children: recipientOptions.find(
96537
+ (o2) => o2.value === selectedPreviewAsRecipientId
96538
+ )?.label || selectedPreviewAsRecipientId }),
96539
+ /* @__PURE__ */ jsx(
96260
96540
  Button$1,
96261
96541
  {
96262
96542
  variant: "ghost",
96263
96543
  size: "icon",
96264
96544
  onClick: () => {
96265
96545
  setSelectedPreviewAsRecipientId("");
96546
+ setSearchQuery("");
96266
96547
  },
96267
- disabled: cantSendEmail,
96268
- className: `h-10 w-10 flex-shrink-0 rounded-lg hover:bg-gray-100 transition-colors ${cantSendEmail && "cursor-not-allowed"}`,
96548
+ className: "h-7 w-7 flex-shrink-0 rounded hover:bg-blue-100",
96269
96549
  title: "Clear selection",
96270
- children: /* @__PURE__ */ jsx(IconDefinitions.CloseButton, { className: "h-4 w-4 text-gray-500" })
96550
+ children: /* @__PURE__ */ jsx(IconDefinitions.CloseButton, { className: "h-3.5 w-3.5 text-blue-600" })
96271
96551
  }
96272
96552
  )
96273
96553
  ] }),
96274
- /* @__PURE__ */ jsxs("div", { className: "space-y-2 pl-6", children: [
96275
- /* @__PURE__ */ jsxs("p", { className: "text-sm text-gray-600 leading-relaxed", children: [
96276
- "Preview what the ",
96277
- humanReadableTypeShort,
96278
- " would look like with real customer data (merge tags like",
96279
- " ",
96280
- /* @__PURE__ */ jsx("code", { className: "px-1.5 py-0.5 bg-gray-100 text-gray-800 rounded text-xs font-mono", children: "{{First Name}}" }),
96281
- "). The ",
96282
- humanReadableTypeShort,
96283
- " will still be sent to the address you entered above."
96284
- ] }),
96285
- cantSendEmail && selectedPreviewAsRecipientId && /* @__PURE__ */ jsx("p", { className: "text-xs text-amber-600 font-medium", children: "⚠️ Please select a sender and subject first" })
96286
- ] })
96554
+ /* @__PURE__ */ jsxs(
96555
+ Command,
96556
+ {
96557
+ shouldFilter: false,
96558
+ className: "rounded-lg border overflow-visible",
96559
+ children: [
96560
+ /* @__PURE__ */ jsx(
96561
+ CommandInput,
96562
+ {
96563
+ placeholder: "Search for a customer...",
96564
+ onValueChange: setSearchQuery,
96565
+ disabled: cantSendEmail
96566
+ }
96567
+ ),
96568
+ (searchQuery.trim().length > 0 || isLoadingUsers) && /* @__PURE__ */ jsxs(CommandList, { className: "max-h-[150px] border-t", children: [
96569
+ !isLoadingUsers && debouncedSearchQuery.trim().length > 0 && recipientOptions.length === 0 && /* @__PURE__ */ jsx(CommandEmpty, { children: "No results found." }),
96570
+ /* @__PURE__ */ jsx(CommandGroup, { children: isLoadingUsers ? Array.from({ length: 3 }).map((_2, index2) => /* @__PURE__ */ jsx(CommandItem, { disabled: true, children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 w-full", children: [
96571
+ /* @__PURE__ */ jsx("div", { className: "h-4 w-4 bg-gray-200 rounded animate-pulse" }),
96572
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1 flex-1", children: [
96573
+ /* @__PURE__ */ jsx("div", { className: "h-4 bg-gray-200 rounded animate-pulse w-3/4" }),
96574
+ /* @__PURE__ */ jsx("div", { className: "h-3 bg-gray-200 rounded animate-pulse w-1/2" })
96575
+ ] })
96576
+ ] }) }, `skeleton-${index2}`)) : recipientOptions.map((option) => /* @__PURE__ */ jsxs(
96577
+ CommandItem,
96578
+ {
96579
+ value: option.value,
96580
+ onSelect: () => {
96581
+ setSelectedPreviewAsRecipientId(
96582
+ option.value === selectedPreviewAsRecipientId ? "" : option.value
96583
+ );
96584
+ setSearchQuery("");
96585
+ },
96586
+ children: [
96587
+ /* @__PURE__ */ jsx(
96588
+ Check,
96589
+ {
96590
+ className: cn$2(
96591
+ "mr-2 h-4 w-4 flex-shrink-0",
96592
+ selectedPreviewAsRecipientId === option.value ? "opacity-100" : "opacity-0"
96593
+ )
96594
+ }
96595
+ ),
96596
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col overflow-hidden flex-1 min-w-0", children: [
96597
+ /* @__PURE__ */ jsx("span", { className: "font-medium break-words text-sm", children: option.label }),
96598
+ option.description && /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground break-words", children: option.description })
96599
+ ] })
96600
+ ]
96601
+ },
96602
+ option.id || option.value
96603
+ )) })
96604
+ ] })
96605
+ ]
96606
+ }
96607
+ ),
96608
+ /* @__PURE__ */ jsxs("p", { className: "text-xs text-gray-500 leading-relaxed", children: [
96609
+ "Optionally preview with real customer data (merge tags). The",
96610
+ " ",
96611
+ humanReadableTypeShort,
96612
+ " still goes to the address above."
96613
+ ] }),
96614
+ cantSendEmail && selectedPreviewAsRecipientId && /* @__PURE__ */ jsx("p", { className: "text-xs text-amber-600 font-medium", children: "⚠️ Please select a sender and subject first" })
96287
96615
  ] }),
96288
96616
  error2 && /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-2 p-3 bg-red-50 border border-red-200 rounded-lg", children: [
96289
96617
  /* @__PURE__ */ jsx(IconDefinitions.AlertCircleIcon, { className: "h-4 w-4 text-red-600 mt-0.5 flex-shrink-0" }),
@@ -117090,30 +117418,6 @@ const extractMergeFieldNamesUtil = (text2) => {
117090
117418
  if (!matches2) return [];
117091
117419
  return matches2.map((match2) => match2.slice(2, -2));
117092
117420
  };
117093
- const capitalize = (str) => {
117094
- if (!str) return str;
117095
- return str.charAt(0).toUpperCase() + str.slice(1);
117096
- };
117097
- const getDisplayName = (recipient, fallbackText = "Unnamed User") => {
117098
- const fullName = `${recipient.firstName || ""} ${recipient.lastName || ""}`.trim();
117099
- if (fullName) return fullName;
117100
- if (recipient.firstName) return recipient.firstName;
117101
- if (recipient.lastName) return recipient.lastName;
117102
- if (recipient.email) return recipient.email;
117103
- if (recipient.phone) return recipient.phone;
117104
- return fallbackText;
117105
- };
117106
- const RECIPIENT_SEARCH_PLACEHOLDER = `Search by name, email, or phone...`;
117107
- const getMergeFieldsFromUrl = (url, getMergeFields2) => {
117108
- if (!url || !getMergeFields2) return [];
117109
- const regex = /\{\{([^}]+)\}\}/g;
117110
- const matches2 = [...url.matchAll(regex)];
117111
- return matches2.map((match2) => {
117112
- const mergeFieldValue = match2[1];
117113
- const mergeField = getMergeFields2.mergeFields?.flatMap((f2) => f2.entries).find((entry) => entry.value === `{{${mergeFieldValue}}}`);
117114
- return mergeField ? mergeField.label : mergeFieldValue;
117115
- }).filter(Boolean);
117116
- };
117117
117421
  const convertToHtml = (text2, mergeFields, variant) => {
117118
117422
  if (!text2) return "";
117119
117423
  const regex = /\{\{.*?\}\}/g;
@@ -117686,15 +117990,22 @@ function MultiSelectDialog({
117686
117990
  variant: "outline",
117687
117991
  disabled: !canOpen,
117688
117992
  className: cn$2(
117689
- "w-full justify-between text-left font-normal h-9 p-3",
117993
+ "w-full justify-between text-left font-normal min-h-9 h-auto p-3",
117690
117994
  !canOpen && "opacity-50 cursor-not-allowed"
117691
117995
  ),
117692
117996
  children: [
117693
- /* @__PURE__ */ jsx("div", { className: "flex flex-nowrap items-center gap-1 max-w-[70%]", children: selectedDisplay.length === 0 ? /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: placeholder }) : singleSelect ? /* @__PURE__ */ jsx(Badge, { variant: "secondary", className: "text-xs whitespace-nowrap", children: selectedDisplay[0].label }) : selectedDisplay.length <= 2 ? selectedDisplay.map((item) => /* @__PURE__ */ jsx(
117997
+ /* @__PURE__ */ jsx("div", { className: "flex flex-wrap items-center gap-1 min-w-0 overflow-hidden", children: selectedDisplay.length === 0 ? /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: placeholder }) : singleSelect ? /* @__PURE__ */ jsx(
117998
+ Badge,
117999
+ {
118000
+ variant: "secondary",
118001
+ className: "text-xs truncate max-w-[200px]",
118002
+ children: selectedDisplay[0].label
118003
+ }
118004
+ ) : selectedDisplay.length <= 2 ? selectedDisplay.map((item) => /* @__PURE__ */ jsx(
117694
118005
  Badge,
117695
118006
  {
117696
118007
  variant: "secondary",
117697
- className: "text-xs whitespace-nowrap",
118008
+ className: "text-xs truncate max-w-[200px]",
117698
118009
  children: item.label
117699
118010
  },
117700
118011
  item.value
@@ -117703,7 +118014,7 @@ function MultiSelectDialog({
117703
118014
  Badge,
117704
118015
  {
117705
118016
  variant: "secondary",
117706
- className: "text-xs whitespace-nowrap",
118017
+ className: "text-xs truncate max-w-[200px]",
117707
118018
  children: selectedDisplay[0].label
117708
118019
  },
117709
118020
  selectedDisplay[0].value
@@ -117712,7 +118023,7 @@ function MultiSelectDialog({
117712
118023
  Badge,
117713
118024
  {
117714
118025
  variant: "secondary",
117715
- className: "text-xs whitespace-nowrap",
118026
+ className: "text-xs truncate max-w-[200px]",
117716
118027
  children: [
117717
118028
  "+",
117718
118029
  selectedDisplay.length - 1,
@@ -118008,7 +118319,9 @@ const SMSEditor = ({
118008
118319
  isUpdating,
118009
118320
  hasUnsavedChanges,
118010
118321
  communicationGroupId,
118011
- hasDynamicMergeFieldImage = false
118322
+ hasDynamicMergeFieldImage = false,
118323
+ hasAttachedImage = false,
118324
+ extraMergeFields = null
118012
118325
  }) => {
118013
118326
  const [characterCount, setCharacterCount] = useState(0);
118014
118327
  const [isAddImagePopoverOpen, setIsAddImagePopoverOpen] = useState(false);
@@ -118075,6 +118388,24 @@ const SMSEditor = ({
118075
118388
  if (selected.length > 0 && editor) {
118076
118389
  const mergeField = allMergeFields.flatMap((f2) => f2.entries).find((f2) => f2.value === selected[0]);
118077
118390
  if (mergeField) {
118391
+ if (hasAttachedImage && extraMergeFields) {
118392
+ const normalizedTemplateName = mergeField.value.startsWith("{{") && mergeField.value.endsWith("}}") ? mergeField.value.slice(2, -2) : mergeField.value;
118393
+ for (const extraMergeField of extraMergeFields) {
118394
+ if (extraMergeField.type === ReachMergeFieldTypeEnum.DYNAMIC) {
118395
+ const foundField = extraMergeField.mergeFields.find(
118396
+ (field) => field.templateName === normalizedTemplateName
118397
+ );
118398
+ if (foundField?.image) {
118399
+ toast2({
118400
+ title: "Cannot add QR code merge field",
118401
+ description: "An image is already attached to this message. To ensure image quality, we don't allow adding QR code merge fields when an image is already attached.",
118402
+ variant: "destructive"
118403
+ });
118404
+ return;
118405
+ }
118406
+ }
118407
+ }
118408
+ }
118078
118409
  editor.chain().focus().insertContent({
118079
118410
  type: "mergeField",
118080
118411
  attrs: {
@@ -118085,7 +118416,7 @@ const SMSEditor = ({
118085
118416
  }
118086
118417
  }
118087
118418
  },
118088
- [editor, allMergeFields]
118419
+ [editor, allMergeFields, hasAttachedImage, extraMergeFields, toast2]
118089
118420
  );
118090
118421
  const mergeFieldOptions = useMemo(
118091
118422
  () => allMergeFields.map((entry) => ({
@@ -118181,7 +118512,7 @@ const SMSEditor = ({
118181
118512
  ]
118182
118513
  }
118183
118514
  ),
118184
- /* @__PURE__ */ jsx("div", { className: "text-xs text-muted-foreground pt-1 border-t", children: "Maximum size of all images: 5MB. We will try to compress the image if possible." })
118515
+ /* @__PURE__ */ jsx("div", { className: "text-xs text-muted-foreground pt-1 border-t", children: "Images are converted to PNG and compressed if needed. After processing, the total size must be under 5MB. Large or complex images may need to be reduced in dimensions or quality before uploading." })
118185
118516
  ] }) })
118186
118517
  ]
118187
118518
  }
@@ -118245,7 +118576,7 @@ const SMSEditor = ({
118245
118576
  "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).",
118246
118577
  /* @__PURE__ */ jsx("br", {}),
118247
118578
  /* @__PURE__ */ jsx("br", {}),
118248
- /* @__PURE__ */ jsx("span", { className: "text-sm text-muted-foreground", children: "Maximum size of all images: 5MB. We will try to compress the image if possible." })
118579
+ /* @__PURE__ */ jsx("span", { className: "text-sm text-muted-foreground", children: "Images are converted to PNG and compressed if needed. After processing, the total size must be under 5MB. Large or complex images may need to be reduced in dimensions or quality before uploading." })
118249
118580
  ] })
118250
118581
  ] }),
118251
118582
  /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
@@ -118868,6 +119199,26 @@ const SMSEditorContent = React__default.memo(
118868
119199
  if (fileInputRef.current) {
118869
119200
  fileInputRef.current.value = "";
118870
119201
  }
119202
+ const supportedTypes = [
119203
+ "image/jpeg",
119204
+ "image/jpg",
119205
+ "image/png",
119206
+ "image/gif",
119207
+ "image/webp"
119208
+ ];
119209
+ const fileExtension = file.name.split(".").pop()?.toLowerCase();
119210
+ const isUnsupportedFormat = !supportedTypes.includes(file.type) && !["jpg", "jpeg", "png", "gif", "webp"].includes(
119211
+ fileExtension || ""
119212
+ );
119213
+ if (isUnsupportedFormat) {
119214
+ const formatName = fileExtension?.toUpperCase() || "this format";
119215
+ toast2({
119216
+ title: "Unsupported image format",
119217
+ description: `${formatName} files are not supported. Please convert your image to JPEG, PNG, GIF, or WebP format before uploading.`,
119218
+ variant: "destructive"
119219
+ });
119220
+ return;
119221
+ }
118871
119222
  const MAX_FILE_SIZE = 20 * 1024 * 1024;
118872
119223
  if (file.size > MAX_FILE_SIZE) {
118873
119224
  console.log("File too large", file.size, MAX_FILE_SIZE);
@@ -118903,10 +119254,12 @@ const SMSEditorContent = React__default.memo(
118903
119254
  });
118904
119255
  },
118905
119256
  onError: (data) => {
118906
- if (data.message.includes("Image is still too large")) {
119257
+ console.error("Failed to upload image:", data);
119258
+ const errorMessage = data.message || "";
119259
+ if (errorMessage.includes("too large") || errorMessage.includes("exceeds") || errorMessage.includes("Unable to compress") || errorMessage.includes("4.95MB") || errorMessage.includes("5MB")) {
118907
119260
  toast2({
118908
- title: "Image too large",
118909
- description: "The image is too large. Please try again with a smaller image.",
119261
+ title: "Image too large after processing",
119262
+ description: "Your image was converted to PNG format, which may have increased its size. The processed image must be under 5MB. Try reducing the image dimensions or quality before uploading.",
118910
119263
  variant: "destructive"
118911
119264
  });
118912
119265
  } else {
@@ -118920,12 +119273,24 @@ const SMSEditorContent = React__default.memo(
118920
119273
  }
118921
119274
  );
118922
119275
  } catch (error2) {
119276
+ console.error("Failed to upload image:", error2);
118923
119277
  console.error("Failed to convert or upload image:", error2);
118924
- toast2({
118925
- title: "Error uploading image",
118926
- description: "Failed to process or upload the image",
118927
- variant: "destructive"
118928
- });
119278
+ const errorMessage = error2 instanceof Error ? error2.message : String(error2);
119279
+ const isConversionError = errorMessage.includes("Failed to load image") || errorMessage.includes("convert") || errorMessage.includes("load");
119280
+ if (isConversionError) {
119281
+ const fileExtension2 = file.name.split(".").pop()?.toUpperCase();
119282
+ toast2({
119283
+ title: "Image format not supported",
119284
+ description: `Unable to process ${fileExtension2 || "this image"} format. Please convert your image to JPEG, PNG, GIF, or WebP format before uploading.`,
119285
+ variant: "destructive"
119286
+ });
119287
+ } else {
119288
+ toast2({
119289
+ title: "Error uploading image",
119290
+ description: "Failed to process or upload the image. Please try again with a different image.",
119291
+ variant: "destructive"
119292
+ });
119293
+ }
118929
119294
  } finally {
118930
119295
  setIsUploadingImage(false);
118931
119296
  }
@@ -119067,7 +119432,9 @@ const SMSEditorContent = React__default.memo(
119067
119432
  isUpdating: isUpdatingCommunicationGroup || isUploadingImage,
119068
119433
  hasUnsavedChanges,
119069
119434
  communicationGroupId,
119070
- hasDynamicMergeFieldImage: dynamicMergeFieldImages.length > 0
119435
+ hasDynamicMergeFieldImage: dynamicMergeFieldImages.length > 0,
119436
+ hasAttachedImage: !!imagePreview || (initialImageUrls?.length ?? 0) > 0 || imageBase64 !== null,
119437
+ extraMergeFields: communicationGroup?.extraMergeFields ?? null
119071
119438
  }
119072
119439
  )
119073
119440
  ] }),
@@ -120778,14 +121145,14 @@ const operatorToHumanReadable = (operator, type) => {
120778
121145
  case ConditionOperatorEnumType.NOT_EQUALS:
120779
121146
  return "Not Equals";
120780
121147
  case ConditionOperatorEnumType.GREATER_THAN: {
120781
- if (type === JSONSchemaType.Date) {
120782
- return "Is After Date";
121148
+ if (type === JSONSchemaType.Date || type === JSONSchemaType.DateTime) {
121149
+ return "After";
120783
121150
  }
120784
121151
  return "Greater than";
120785
121152
  }
120786
121153
  case ConditionOperatorEnumType.LESS_THAN: {
120787
- if (type === JSONSchemaType.Date) {
120788
- return "Is Before Date";
121154
+ if (type === JSONSchemaType.Date || type === JSONSchemaType.DateTime) {
121155
+ return "Before";
120789
121156
  }
120790
121157
  return "Less Than";
120791
121158
  }
@@ -120813,6 +121180,164 @@ const buildInFieldToHumanReadable = {
120813
121180
  firstName: "First Name",
120814
121181
  lastName: "Last Name"
120815
121182
  };
121183
+ const ComboboxSelect = ({
121184
+ options,
121185
+ value,
121186
+ onChange: onChange2,
121187
+ placeholder,
121188
+ className = "",
121189
+ disableInput = false,
121190
+ disabled = false,
121191
+ onOpenChange,
121192
+ limitWhenNotSearching,
121193
+ onSearchChange,
121194
+ isLoading = false,
121195
+ shouldFilter = true,
121196
+ showEmptyState = true
121197
+ }) => {
121198
+ const [open, setOpen2] = React.useState(false);
121199
+ const [searchQuery, setSearchQuery] = React.useState("");
121200
+ const triggerRef = React.useRef(null);
121201
+ const [triggerWidth, setTriggerWidth] = React.useState();
121202
+ React.useEffect(() => {
121203
+ if (triggerRef.current && open) {
121204
+ setTriggerWidth(triggerRef.current.offsetWidth);
121205
+ }
121206
+ }, [open]);
121207
+ const handleOpenChange = (newOpen) => {
121208
+ setOpen2(newOpen);
121209
+ if (!newOpen && !onSearchChange) {
121210
+ setSearchQuery("");
121211
+ }
121212
+ onOpenChange?.(newOpen);
121213
+ if (newOpen && value) {
121214
+ requestAnimationFrame(() => {
121215
+ const selected = document.querySelector(
121216
+ `[cmdk-item][data-value="${CSS.escape(value)}"]`
121217
+ );
121218
+ selected?.scrollIntoView({ block: "nearest" });
121219
+ });
121220
+ }
121221
+ };
121222
+ const handleSearchChange = (search2) => {
121223
+ setSearchQuery(search2);
121224
+ onSearchChange?.(search2);
121225
+ };
121226
+ const displayOptions = React.useMemo(() => {
121227
+ if (!shouldFilter) return options;
121228
+ if (!limitWhenNotSearching) return options;
121229
+ const query = searchQuery.trim().toLowerCase();
121230
+ if (!query) {
121231
+ return options.slice(0, limitWhenNotSearching);
121232
+ }
121233
+ const filtered = options.filter((option) => {
121234
+ const searchableText = [
121235
+ option.label,
121236
+ option.description || "",
121237
+ option.value
121238
+ ].join(" ").toLowerCase();
121239
+ return searchableText.includes(query);
121240
+ });
121241
+ return filtered.slice(0, 200);
121242
+ }, [options, searchQuery, limitWhenNotSearching, shouldFilter]);
121243
+ return /* @__PURE__ */ jsxs(
121244
+ Popover,
121245
+ {
121246
+ modal: true,
121247
+ open: disabled ? false : open,
121248
+ onOpenChange: disabled ? void 0 : handleOpenChange,
121249
+ children: [
121250
+ /* @__PURE__ */ jsx(TooltipProvider, { children: /* @__PURE__ */ jsxs(Tooltip, { children: [
121251
+ /* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(
121252
+ Button$1,
121253
+ {
121254
+ ref: triggerRef,
121255
+ "aria-expanded": open,
121256
+ disabled,
121257
+ className: cn$2(
121258
+ "w-full overflow-hidden justify-between",
121259
+ disabled && "bg-gray-50 text-gray-700 cursor-not-allowed",
121260
+ className
121261
+ ),
121262
+ variant: "outline",
121263
+ children: [
121264
+ /* @__PURE__ */ jsx("span", { className: "truncate", children: value ? options.find((option) => option.value === value)?.label || value : placeholder }),
121265
+ /* @__PURE__ */ jsx(ChevronsUpDown, { className: "ml-2 h-4 w-4 flex-shrink-0 opacity-50" })
121266
+ ]
121267
+ }
121268
+ ) }) }),
121269
+ value && options.find((option) => option.value === value)?.label && /* @__PURE__ */ jsx(TooltipContent, { side: "top", children: options.find((option) => option.value === value)?.label })
121270
+ ] }) }),
121271
+ /* @__PURE__ */ jsx(Portal$5, { children: /* @__PURE__ */ jsx(
121272
+ PopoverContent,
121273
+ {
121274
+ align: "start",
121275
+ style: {
121276
+ width: triggerWidth ? `${Math.max(triggerWidth, 300)}px` : "300px",
121277
+ minWidth: "300px"
121278
+ },
121279
+ className: cn$2("p-0", className),
121280
+ children: /* @__PURE__ */ jsxs(Command, { shouldFilter, children: [
121281
+ !disableInput && /* @__PURE__ */ jsx(
121282
+ CommandInput,
121283
+ {
121284
+ placeholder: `${placeholder}...`,
121285
+ onValueChange: handleSearchChange
121286
+ }
121287
+ ),
121288
+ /* @__PURE__ */ jsxs(CommandList, { children: [
121289
+ !isLoading && showEmptyState && /* @__PURE__ */ jsx(CommandEmpty, { children: "No results found." }),
121290
+ /* @__PURE__ */ jsx(CommandGroup, { children: isLoading ? (
121291
+ // Show skeleton loaders while loading
121292
+ Array.from({ length: 5 }).map((_2, index2) => /* @__PURE__ */ jsx(CommandItem, { disabled: true, children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 w-full", children: [
121293
+ /* @__PURE__ */ jsx("div", { className: "h-4 w-4 bg-gray-200 rounded animate-pulse" }),
121294
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1 flex-1", children: [
121295
+ /* @__PURE__ */ jsx("div", { className: "h-4 bg-gray-200 rounded animate-pulse w-3/4" }),
121296
+ /* @__PURE__ */ jsx("div", { className: "h-3 bg-gray-200 rounded animate-pulse w-1/2" })
121297
+ ] })
121298
+ ] }) }, `skeleton-${index2}`))
121299
+ ) : displayOptions.map((option) => /* @__PURE__ */ jsxs(
121300
+ CommandItem,
121301
+ {
121302
+ value: option.value,
121303
+ onSelect: () => {
121304
+ onChange2(option.value === value ? "" : option.value);
121305
+ handleOpenChange(false);
121306
+ },
121307
+ children: [
121308
+ /* @__PURE__ */ jsx(
121309
+ Check,
121310
+ {
121311
+ className: cn$2(
121312
+ "mr-2 h-4 w-4 flex-shrink-0",
121313
+ value === option.value ? "opacity-100" : "opacity-0"
121314
+ )
121315
+ }
121316
+ ),
121317
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col overflow-hidden flex-1 min-w-0", children: [
121318
+ /* @__PURE__ */ jsx("span", { className: "font-medium break-words", children: option.label }),
121319
+ option.description && /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground break-words", children: option.description })
121320
+ ] })
121321
+ ]
121322
+ },
121323
+ option.id || option.value
121324
+ )) })
121325
+ ] })
121326
+ ] })
121327
+ }
121328
+ ) })
121329
+ ]
121330
+ }
121331
+ );
121332
+ };
121333
+ const truncateTextForIcon = (text2, maxWidth = 200, iconWidth = 32) => {
121334
+ if (text2.length <= 20) return text2;
121335
+ const avgCharWidth = 8;
121336
+ const availableWidth = maxWidth - iconWidth - 16;
121337
+ const maxChars = Math.floor(availableWidth / avgCharWidth);
121338
+ if (text2.length <= maxChars) return text2;
121339
+ return text2.substring(0, maxChars - 3) + "...";
121340
+ };
120816
121341
  function composeEventHandlers$1(originalEventHandler, ourEventHandler, { checkForDefaultPrevented = true } = {}) {
120817
121342
  return function handleEvent(event) {
120818
121343
  originalEventHandler?.(event);
@@ -123217,7 +123742,7 @@ const ConditionRow = ({
123217
123742
  const hoverTimeoutRef = useRef(null);
123218
123743
  const { segments } = useListSegments();
123219
123744
  const allUsersSegment = segments?.find(
123220
- (segment2) => segment2.type === BusinessSegmentTypeEnum.ALL_USERS
123745
+ (segment2) => segment2.type === SegmentDefinitionTypeEnum.ALL_USERS
123221
123746
  );
123222
123747
  const totalCount = condition.field === "userId" ? allUsersSegment?.userCount : void 0;
123223
123748
  const getMetadataForField = (field) => {
@@ -123350,8 +123875,8 @@ const ConditionRow = ({
123350
123875
  className: `bg-white rounded-lg border border-gray-200 p-4 transition-all duration-200 ${viewOnly ? "bg-gray-50 border-gray-300" : "hover:border-gray-300 hover:shadow-sm"}`,
123351
123876
  onMouseEnter: !viewOnly ? handleMouseEnter : void 0,
123352
123877
  onMouseLeave: !viewOnly ? handleMouseLeave : void 0,
123353
- children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col sm:flex-row items-stretch gap-3 min-w-0 w-full", children: [
123354
- /* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0 flex items-center gap-2", children: [
123878
+ children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col sm:grid sm:grid-cols-[minmax(120px,3fr)_minmax(100px,2fr)_minmax(100px,3fr)] items-stretch gap-3 min-w-0 w-full", children: [
123879
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex items-center gap-2", children: [
123355
123880
  (metadata2.description || condition.field) && /* @__PURE__ */ jsx(
123356
123881
  InfoTooltip,
123357
123882
  {
@@ -123427,7 +123952,7 @@ const ConditionRow = ({
123427
123952
  }
123428
123953
  )
123429
123954
  ] }),
123430
- /* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0 max-w-xs flex gap-2 items-center", children: [
123955
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex gap-2 items-center", children: [
123431
123956
  (condition.operator === ConditionOperatorEnumType.EQUALS_MONTH_DAY || condition.operator === ConditionOperatorEnumType.EQUALS_MONTH_DAY_YEAR || condition.operator === ConditionOperatorEnumType.BETWEEN_MONTH_DAY || condition.operator === ConditionOperatorEnumType.BETWEEN_MONTH_DAY_YEAR) && /* @__PURE__ */ jsx("div", { className: "flex items-center", children: getInfoTooltip(condition.operator) }),
123432
123957
  /* @__PURE__ */ jsx(
123433
123958
  ComboboxSelect,
@@ -123452,7 +123977,7 @@ const ConditionRow = ({
123452
123977
  }
123453
123978
  )
123454
123979
  ] }),
123455
- /* @__PURE__ */ jsx("div", { className: "flex-1 min-w-0 max-w-full overflow-x-hidden", children: /* @__PURE__ */ jsx(
123980
+ /* @__PURE__ */ jsx("div", { className: "min-w-0 overflow-x-hidden", children: /* @__PURE__ */ jsx(
123456
123981
  ValueInput,
123457
123982
  {
123458
123983
  fieldType,
@@ -123503,7 +124028,8 @@ const SegmentBuilderContent = ({
123503
124028
  businessId,
123504
124029
  viewOnly = false,
123505
124030
  segmentType,
123506
- existingSegmentConditions
124031
+ existingSegmentConditions,
124032
+ onEstimatedTotalChange
123507
124033
  }) => {
123508
124034
  const [searchQuery, setSearchQuery] = React.useState("");
123509
124035
  const [limit, setLimit] = React.useState(100);
@@ -123511,9 +124037,13 @@ const SegmentBuilderContent = ({
123511
124037
  () => JSON.stringify(segment2.conditions),
123512
124038
  [segment2.conditions]
123513
124039
  );
124040
+ const conditionGroupsKey = React.useMemo(
124041
+ () => JSON.stringify(segment2.conditionGroups),
124042
+ [segment2.conditionGroups]
124043
+ );
123514
124044
  React.useEffect(() => {
123515
124045
  setLimit(100);
123516
- }, [searchQuery, conditionsKey]);
124046
+ }, [searchQuery, conditionsKey, conditionGroupsKey]);
123517
124047
  const {
123518
124048
  data: recipientsData,
123519
124049
  isLoading,
@@ -123526,7 +124056,8 @@ const SegmentBuilderContent = ({
123526
124056
  {
123527
124057
  debounceMs: 500,
123528
124058
  search: searchQuery,
123529
- limit
124059
+ limit,
124060
+ conditionGroups: segment2.conditionGroups
123530
124061
  },
123531
124062
  existingSegmentConditions
123532
124063
  );
@@ -123538,6 +124069,9 @@ const SegmentBuilderContent = ({
123538
124069
  })) ?? [];
123539
124070
  const estimatedTotal = recipientsData?.estimatedTotal ?? 0;
123540
124071
  const hasMore = recipientsData?.pagination?.hasNextPage ?? false;
124072
+ React.useEffect(() => {
124073
+ onEstimatedTotalChange?.(estimatedTotal);
124074
+ }, [estimatedTotal, onEstimatedTotalChange]);
123541
124075
  const isLoadingMoreRef = React.useRef(false);
123542
124076
  const handleLoadMore = React.useCallback(() => {
123543
124077
  if (isLoadingMoreRef.current || isLoading || !hasMore) return;
@@ -123547,12 +124081,12 @@ const SegmentBuilderContent = ({
123547
124081
  isLoadingMoreRef.current = false;
123548
124082
  }, 1e3);
123549
124083
  }, [isLoading, hasMore]);
123550
- return /* @__PURE__ */ jsx(BlurDiv, { className: "flex-1 flex flex-col overflow-visible", children: /* @__PURE__ */ jsxs("div", { className: "flex h-full gap-6 overflow-visible", children: [
123551
- /* @__PURE__ */ jsxs("div", { className: "flex-1 flex flex-col overflow-visible", children: [
123552
- /* @__PURE__ */ jsxs("div", { className: "mb-6 grid grid-cols-2 gap-2", children: [
123553
- /* @__PURE__ */ jsxs("div", { className: "grid gap-2", children: [
123554
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-0", children: [
123555
- /* @__PURE__ */ jsx(MinorText, { children: "Name" }),
124084
+ return /* @__PURE__ */ jsxs(BlurDiv, { className: "flex-1 flex flex-col xl:flex-row gap-8 overflow-visible min-h-0", children: [
124085
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 flex flex-col min-w-0 overflow-x-hidden px-1", children: [
124086
+ /* @__PURE__ */ jsxs("div", { className: "mb-8 space-y-5", children: [
124087
+ /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
124088
+ /* @__PURE__ */ jsxs("label", { className: "text-sm font-medium text-neutral-900 flex items-center gap-0", children: [
124089
+ "Name",
123556
124090
  !viewOnly && /* @__PURE__ */ jsx("span", { className: "text-xs text-red-500 ml-1 align-super", children: "*" })
123557
124091
  ] }),
123558
124092
  /* @__PURE__ */ jsx(
@@ -123566,10 +124100,13 @@ const SegmentBuilderContent = ({
123566
124100
  }
123567
124101
  )
123568
124102
  ] }),
123569
- /* @__PURE__ */ jsxs("div", { className: "grid gap-2", children: [
123570
- /* @__PURE__ */ jsx(MinorText, { children: "Description" }),
124103
+ /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
124104
+ /* @__PURE__ */ jsxs("label", { className: "text-sm font-medium text-neutral-900 flex items-center gap-2", children: [
124105
+ "Description",
124106
+ /* @__PURE__ */ jsx("span", { className: "text-xs font-normal text-neutral-400", children: "Optional" })
124107
+ ] }),
123571
124108
  /* @__PURE__ */ jsx(
123572
- Input$1,
124109
+ Textarea,
123573
124110
  {
123574
124111
  placeholder: `${t$2("engage:segment")} description`,
123575
124112
  value: segment2.description,
@@ -123578,11 +124115,13 @@ const SegmentBuilderContent = ({
123578
124115
  description: e4.target.value
123579
124116
  }),
123580
124117
  disabled: viewOnly,
123581
- className: viewOnly ? "bg-gray-50 text-gray-700" : ""
124118
+ className: viewOnly ? "bg-gray-50 text-gray-700 resize-none" : "resize-none",
124119
+ rows: 2
123582
124120
  }
123583
124121
  )
123584
124122
  ] })
123585
124123
  ] }),
124124
+ /* @__PURE__ */ jsx("div", { className: "h-px bg-neutral-200 mb-8" }),
123586
124125
  segmentType === "sql" && /* @__PURE__ */ jsxs("div", { className: "mb-6 p-4 bg-blue-50 border border-blue-200 rounded-lg", children: [
123587
124126
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
123588
124127
  /* @__PURE__ */ jsx("div", { className: "w-2 h-2 bg-blue-500 rounded-full" }),
@@ -123590,7 +124129,11 @@ const SegmentBuilderContent = ({
123590
124129
  ] }),
123591
124130
  /* @__PURE__ */ jsx("p", { className: "text-sm text-blue-600 mt-1", children: "This segment is managed by your admin and cannot be edited here." })
123592
124131
  ] }),
123593
- /* @__PURE__ */ jsx("div", { className: "flex-1 overflow-y-auto overflow-x-hidden pb-8", children: /* @__PURE__ */ jsx("div", { className: "grid overflow-visible", children: /* @__PURE__ */ jsxs(AnimatePresence, { mode: "popLayout", children: [
124132
+ /* @__PURE__ */ jsxs("div", { className: "mb-5", children: [
124133
+ /* @__PURE__ */ jsx("h3", { className: "text-base font-semibold text-neutral-900", children: "Audience Conditions" }),
124134
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-neutral-500 mt-1", children: "Users must match all conditions to be included" })
124135
+ ] }),
124136
+ /* @__PURE__ */ jsx("div", { className: "flex-1 overflow-y-auto overflow-x-hidden pb-8", children: /* @__PURE__ */ jsx("div", { className: "grid overflow-visible gap-1", children: /* @__PURE__ */ jsxs(AnimatePresence, { mode: "popLayout", children: [
123594
124137
  segmentType !== "sql" && segment2.conditions.map((condition, index2) => {
123595
124138
  return /* @__PURE__ */ jsxs(
123596
124139
  motion.div,
@@ -123609,7 +124152,7 @@ const SegmentBuilderContent = ({
123609
124152
  index2 > 0 && /* @__PURE__ */ jsxs(
123610
124153
  motion.div,
123611
124154
  {
123612
- className: "relative flex items-center py-2",
124155
+ className: "relative flex items-center py-3",
123613
124156
  initial: { opacity: 0 },
123614
124157
  animate: { opacity: 1 },
123615
124158
  transition: { delay: 0.1 },
@@ -123617,7 +124160,7 @@ const SegmentBuilderContent = ({
123617
124160
  /* @__PURE__ */ jsx(
123618
124161
  motion.div,
123619
124162
  {
123620
- className: "h-px flex-1 bg-border",
124163
+ className: "h-px flex-1 bg-neutral-200",
123621
124164
  initial: { scaleX: 0 },
123622
124165
  animate: { scaleX: 1 },
123623
124166
  transition: {
@@ -123631,7 +124174,7 @@ const SegmentBuilderContent = ({
123631
124174
  /* @__PURE__ */ jsx(
123632
124175
  motion.span,
123633
124176
  {
123634
- className: "text-muted-foreground text-xs",
124177
+ className: "bg-neutral-100 text-neutral-500 text-xs font-medium rounded-full px-3 py-1 mx-3 border border-neutral-200",
123635
124178
  initial: { opacity: 0 },
123636
124179
  animate: { opacity: 1 },
123637
124180
  transition: { delay: 0.2 },
@@ -123641,7 +124184,7 @@ const SegmentBuilderContent = ({
123641
124184
  /* @__PURE__ */ jsx(
123642
124185
  motion.div,
123643
124186
  {
123644
- className: "h-px flex-1 bg-border",
124187
+ className: "h-px flex-1 bg-neutral-200",
123645
124188
  initial: { scaleX: 0 },
123646
124189
  animate: { scaleX: 1 },
123647
124190
  transition: {
@@ -123684,21 +124227,36 @@ const SegmentBuilderContent = ({
123684
124227
  mass: 0.5
123685
124228
  },
123686
124229
  className: "pt-4",
123687
- children: /* @__PURE__ */ jsxs(Button$1, { variant: "secondary", onClick: addCondition, children: [
123688
- /* @__PURE__ */ jsx(Plus, { className: "h-4 w-4" }),
123689
- "Add Condition"
123690
- ] })
124230
+ children: /* @__PURE__ */ jsxs(
124231
+ "button",
124232
+ {
124233
+ onClick: addCondition,
124234
+ className: "w-full flex items-center justify-center gap-2 border-2 border-dashed border-neutral-300 rounded-lg py-3 text-sm text-neutral-500 hover:border-neutral-400 hover:text-neutral-700 hover:bg-neutral-50 transition-colors",
124235
+ children: [
124236
+ /* @__PURE__ */ jsx(Plus, { className: "h-4 w-4" }),
124237
+ "Add Condition"
124238
+ ]
124239
+ }
124240
+ )
123691
124241
  },
123692
124242
  "add-condition-button"
123693
124243
  )
123694
124244
  ] }) }) })
123695
124245
  ] }),
123696
- /* @__PURE__ */ jsxs("div", { className: "w-96 flex flex-col h-full overflow-hidden", children: [
123697
- /* @__PURE__ */ jsxs("div", { className: "mb-4 flex-shrink-0", children: [
123698
- /* @__PURE__ */ jsx("h3", { className: "text-lg font-semibold text-foreground", children: "Recipients Preview" }),
123699
- /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: isLoading ? "Loading recipients..." : estimatedTotal > 0 ? `${estimatedTotal.toLocaleString()} users match your conditions` : "No users match your conditions" })
124246
+ /* @__PURE__ */ jsx("div", { className: "h-px bg-neutral-200 xl:hidden" }),
124247
+ /* @__PURE__ */ jsx("div", { className: "w-full xl:w-96 flex flex-col min-h-0 xl:h-full overflow-hidden", children: /* @__PURE__ */ jsxs("div", { className: "border border-neutral-200 rounded-lg flex flex-col flex-1 min-h-0 overflow-hidden", children: [
124248
+ /* @__PURE__ */ jsxs("div", { className: "p-4 border-b border-neutral-100 flex-shrink-0", children: [
124249
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 mb-1", children: [
124250
+ /* @__PURE__ */ jsx(Users, { className: "h-4 w-4 text-neutral-500" }),
124251
+ /* @__PURE__ */ jsx("h3", { className: "text-base font-semibold text-neutral-900", children: "Audience Preview" })
124252
+ ] }),
124253
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-neutral-500", children: isLoading ? "Loading recipients..." : estimatedTotal > 0 ? `${estimatedTotal.toLocaleString()} users match your conditions` : "No users match your conditions" }),
124254
+ /* @__PURE__ */ jsxs("div", { className: "mt-2 inline-flex items-center gap-1.5 bg-neutral-100 text-neutral-500 text-xs rounded-md px-2 py-1", children: [
124255
+ /* @__PURE__ */ jsx(Info, { className: "h-3 w-3" }),
124256
+ "Preview based on sample data"
124257
+ ] })
123700
124258
  ] }),
123701
- /* @__PURE__ */ jsx("div", { className: "flex-1 min-h-0 flex flex-col", children: isLoading ? /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center h-full", children: /* @__PURE__ */ jsx("div", { className: "animate-spin h-6 w-6 border-2 border-blue-600 border-t-transparent rounded-full" }) }) : error2 ? /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center h-full text-red-600", children: /* @__PURE__ */ jsx("p", { children: "Error loading recipients" }) }) : /* @__PURE__ */ jsx(
124259
+ /* @__PURE__ */ jsx("div", { className: "flex-1 min-h-0 flex flex-col overflow-hidden", children: isLoading ? /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center h-full p-8", children: /* @__PURE__ */ jsx("div", { className: "animate-spin h-6 w-6 border-2 border-blue-600 border-t-transparent rounded-full" }) }) : error2 ? /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center h-full text-red-600 p-8", children: /* @__PURE__ */ jsx("p", { children: "Error loading recipients" }) }) : /* @__PURE__ */ jsx(
123702
124260
  RecipientsTable,
123703
124261
  {
123704
124262
  recipients,
@@ -123714,8 +124272,8 @@ const SegmentBuilderContent = ({
123714
124272
  isLoading
123715
124273
  }
123716
124274
  ) })
123717
- ] })
123718
- ] }) });
124275
+ ] }) })
124276
+ ] });
123719
124277
  };
123720
124278
  const SegmentBuilderHeader = ({
123721
124279
  segmentId,
@@ -123726,16 +124284,22 @@ const SegmentBuilderHeader = ({
123726
124284
  viewOnly = false
123727
124285
  }) => {
123728
124286
  return /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(DialogHeader$1, { className: "", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
123729
- /* @__PURE__ */ jsx(DialogTitle, { className: "text-3xl font-normal", children: viewOnly ? `View ${t$2("engage:segment")}` : segmentId ? `Edit ${t$2("engage:segment")}` : `Create ${t$2("engage:segment")}` }),
124287
+ /* @__PURE__ */ jsxs("div", { children: [
124288
+ /* @__PURE__ */ jsx(DialogTitle, { className: "text-3xl font-normal", children: viewOnly ? `View ${t$2("engage:segment")}` : segmentId ? `Edit ${t$2("engage:segment")}` : `Create ${t$2("engage:segment")}` }),
124289
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground mt-1", children: "Define conditions to target specific user groups" })
124290
+ ] }),
123730
124291
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
123731
124292
  !viewOnly && promptBuilderStyle === false && textToSegment2 === false && /* @__PURE__ */ jsx(TooltipProvider, { children: /* @__PURE__ */ jsxs(Tooltip, { children: [
123732
- /* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
124293
+ /* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(
123733
124294
  Button$1,
123734
124295
  {
123735
124296
  variant: "outline",
123736
124297
  size: "sm",
123737
124298
  onClick: () => setTextToSegment(true),
123738
- children: /* @__PURE__ */ jsx(Sparkles, { className: "h-4 w-3" })
124299
+ children: [
124300
+ /* @__PURE__ */ jsx(Sparkles, { className: "h-4 w-4" }),
124301
+ "Build with AI"
124302
+ ]
123739
124303
  }
123740
124304
  ) }),
123741
124305
  /* @__PURE__ */ jsx(TooltipContent, { children: /* @__PURE__ */ jsxs("p", { children: [
@@ -124018,12 +124582,18 @@ function SegmentBuilder({
124018
124582
  viewOnly ? false : newSegment ? true : false
124019
124583
  );
124020
124584
  const [showDeleteDialog, setShowDeleteDialog] = React.useState(false);
124585
+ const [estimatedTotal, setEstimatedTotal] = React.useState(0);
124586
+ const handleEstimatedTotalChange = React.useCallback((total2) => {
124587
+ setEstimatedTotal(total2);
124588
+ }, []);
124021
124589
  React.useEffect(() => {
124022
124590
  if (!segmentsConditions) {
124023
124591
  return;
124024
124592
  }
124025
124593
  if (existingSegment) {
124026
- const mappedConditions = existingSegment.conditions.filter(isFieldCondition).map((condition) => ({
124594
+ const conditionsList = existingSegment.conditions;
124595
+ const mappedConditions = conditionsList.filter((c3) => isFieldCondition(c3)).map((condition) => ({
124596
+ type: "property",
124027
124597
  field: condition.field,
124028
124598
  operator: condition.operator,
124029
124599
  value: condition.value
@@ -124035,6 +124605,7 @@ function SegmentBuilder({
124035
124605
  description: existingSegment.description || "",
124036
124606
  logic: "AND",
124037
124607
  conditions: mappedConditions,
124608
+ conditionGroups: existingSegment.conditionGroups,
124038
124609
  type: existingSegment.type,
124039
124610
  createdAt: existingSegment.createdAt
124040
124611
  });
@@ -124051,12 +124622,13 @@ function SegmentBuilder({
124051
124622
  * Use the first fields of segment conditions to create a new segment
124052
124623
  */
124053
124624
  {
124625
+ type: "property",
124054
124626
  field: segmentsConditions.conditions[0].field,
124055
124627
  operator: segmentsConditions.conditions[0].operators[0],
124056
124628
  value: []
124057
124629
  }
124058
124630
  ],
124059
- type: BusinessSegmentTypeEnum.CUSTOM
124631
+ type: SegmentDefinitionTypeEnum.CUSTOM
124060
124632
  }));
124061
124633
  }
124062
124634
  }, [existingSegment, segmentsConditions]);
@@ -124355,6 +124927,7 @@ function SegmentBuilder({
124355
124927
  };
124356
124928
  const addCondition = () => {
124357
124929
  const newCondition = {
124930
+ type: "property",
124358
124931
  field: segmentsConditions.conditions[0].field,
124359
124932
  operator: segmentsConditions.conditions[0].operators[0],
124360
124933
  value: []
@@ -124394,117 +124967,135 @@ function SegmentBuilder({
124394
124967
  )
124395
124968
  },
124396
124969
  "prompt-builder-style"
124397
- ) : /* @__PURE__ */ jsx(BlurDiv, { className: "flex-1 flex flex-col", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-1 flex-col", children: [
124398
- /* @__PURE__ */ jsx("div", { className: "flex flex-1 flex-col px-8 py-2", children: /* @__PURE__ */ jsx("div", { className: "flex flex-1 flex-col gap-4", children: /* @__PURE__ */ jsx(AnimatePresence, { children: !viewOnly && textToSegment2 ? /* @__PURE__ */ jsx(BlurDiv, { className: "flex justify-center min-h-full overflow-auto", children: /* @__PURE__ */ jsx(
124399
- TextToSegment,
124400
- {
124401
- setTextToSegment,
124402
- setSegment: (conditions) => {
124403
- setSegment((prevSegment) => {
124404
- if (!prevSegment) {
124405
- return null;
124406
- }
124407
- return {
124408
- ...prevSegment,
124409
- conditions
124410
- };
124411
- });
124412
- },
124413
- setSegmentName: (name) => {
124414
- setSegment((prevSegment) => {
124415
- if (!prevSegment) {
124416
- return null;
124417
- }
124418
- const newSegment2 = { ...prevSegment, name };
124419
- return newSegment2;
124420
- });
124421
- },
124422
- setSegmentDescription: (description2) => {
124423
- setSegment((prevSegment) => {
124424
- if (!prevSegment) {
124425
- return null;
124426
- }
124427
- const newSegment2 = { ...prevSegment, description: description2 };
124428
- return newSegment2;
124429
- });
124430
- },
124431
- currentSegment: segment2
124432
- }
124433
- ) }) : /* @__PURE__ */ jsx(Fragment$1, { children: /* @__PURE__ */ jsx(
124434
- SegmentBuilderContent,
124435
- {
124436
- segment: segment2,
124437
- setSegment,
124438
- segmentsConditions: {
124439
- conditions: segmentsConditions?.conditions.map((c3) => ({
124440
- ...c3,
124441
- operators: c3.operators
124442
- })) ?? []
124443
- },
124444
- updateCondition,
124445
- duplicateCondition,
124446
- deleteCondition,
124447
- addCondition,
124448
- businessId: business?.id ?? "",
124449
- viewOnly,
124450
- segmentType: existingSegment?.type,
124451
- existingSegmentConditions: existingSegment?.conditions
124452
- }
124453
- ) }) }) }) }),
124454
- /* @__PURE__ */ jsx("div", { className: "border-t px-8 py-4", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
124455
- !viewOnly && textToSegment2 && /* @__PURE__ */ jsxs(
124456
- Button$1,
124457
- {
124458
- variant: "secondary",
124459
- onClick: () => setTextToSegment(false),
124460
- children: [
124461
- /* @__PURE__ */ jsx(Settings2, { className: "h-4 w-4" }),
124462
- "Manual Builder"
124463
- ]
124464
- }
124465
- ),
124466
- /* @__PURE__ */ jsx("div", { className: "flex gap-2 ml-auto", children: viewOnly ? (
124467
- // VIEW-ONLY: Only Close button
124468
- /* @__PURE__ */ jsx(Button$1, { variant: "default", onClick: () => setOpen2(false), children: "Close" })
124469
- ) : (
124470
- // EDIT MODE: Delete (if editing), Cancel, and Save buttons
124471
- /* @__PURE__ */ jsxs(Fragment$1, { children: [
124472
- segmentId && !newSegment && /* @__PURE__ */ jsxs(
124473
- Button$1,
124474
- {
124475
- variant: "destructive",
124476
- onClick: () => setShowDeleteDialog(true),
124477
- disabled: isDeleting,
124478
- children: [
124479
- /* @__PURE__ */ jsx(Trash2, { className: "mr-2 h-4 w-4" }),
124480
- "Delete"
124481
- ]
124482
- }
124483
- ),
124484
- /* @__PURE__ */ jsx(
124485
- Button$1,
124486
- {
124487
- variant: "secondary",
124488
- onClick: () => setOpen2(false),
124489
- children: "Cancel"
124490
- }
124491
- ),
124492
- /* @__PURE__ */ jsx(
124493
- Button$1,
124494
- {
124495
- variant: "default",
124496
- onClick: handleSave,
124497
- disabled: isLoading || isCreating,
124498
- children: isLoading || isCreating ? /* @__PURE__ */ jsxs(Fragment$1, { children: [
124499
- /* @__PURE__ */ jsx(LoaderCircle, { className: "mr-2 h-4 w-4 animate-spin" }),
124500
- segmentId ? "Updating..." : "Creating..."
124501
- ] }) : segmentId ? "Update" : "Create"
124502
- }
124503
- )
124504
- ] })
124505
- ) })
124506
- ] }) })
124507
- ] }) }, "manual-builder-style"),
124970
+ ) : /* @__PURE__ */ jsx(
124971
+ BlurDiv,
124972
+ {
124973
+ className: "flex-1 flex flex-col min-h-0",
124974
+ children: /* @__PURE__ */ jsxs("div", { className: "flex flex-1 flex-col min-h-0", children: [
124975
+ /* @__PURE__ */ jsx("div", { className: "flex flex-1 flex-col px-2 py-2 min-h-0 overflow-y-auto", children: /* @__PURE__ */ jsx("div", { className: "flex flex-1 flex-col gap-4", children: /* @__PURE__ */ jsx(AnimatePresence, { children: !viewOnly && textToSegment2 ? /* @__PURE__ */ jsx(BlurDiv, { className: "flex justify-center min-h-full overflow-hidden", children: /* @__PURE__ */ jsx(
124976
+ TextToSegment,
124977
+ {
124978
+ setTextToSegment,
124979
+ setSegment: (conditions) => {
124980
+ setSegment((prevSegment) => {
124981
+ if (!prevSegment) {
124982
+ return null;
124983
+ }
124984
+ return {
124985
+ ...prevSegment,
124986
+ conditions
124987
+ };
124988
+ });
124989
+ },
124990
+ setSegmentName: (name) => {
124991
+ setSegment((prevSegment) => {
124992
+ if (!prevSegment) {
124993
+ return null;
124994
+ }
124995
+ const newSegment2 = { ...prevSegment, name };
124996
+ return newSegment2;
124997
+ });
124998
+ },
124999
+ setSegmentDescription: (description2) => {
125000
+ setSegment((prevSegment) => {
125001
+ if (!prevSegment) {
125002
+ return null;
125003
+ }
125004
+ const newSegment2 = { ...prevSegment, description: description2 };
125005
+ return newSegment2;
125006
+ });
125007
+ },
125008
+ currentSegment: segment2
125009
+ }
125010
+ ) }) : /* @__PURE__ */ jsx(Fragment$1, { children: /* @__PURE__ */ jsx(
125011
+ SegmentBuilderContent,
125012
+ {
125013
+ segment: segment2,
125014
+ setSegment,
125015
+ segmentsConditions: {
125016
+ conditions: segmentsConditions?.conditions.map((c3) => ({
125017
+ ...c3,
125018
+ operators: c3.operators
125019
+ })) ?? []
125020
+ },
125021
+ updateCondition,
125022
+ duplicateCondition,
125023
+ deleteCondition,
125024
+ addCondition,
125025
+ businessId: business?.id ?? "",
125026
+ viewOnly,
125027
+ segmentType: existingSegment?.type,
125028
+ existingSegmentConditions: existingSegment?.conditions,
125029
+ onEstimatedTotalChange: handleEstimatedTotalChange
125030
+ }
125031
+ ) }) }) }) }),
125032
+ /* @__PURE__ */ jsx("div", { className: "border-t bg-neutral-50/50 px-2 py-4 flex-shrink-0", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
125033
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-4", children: [
125034
+ !viewOnly && textToSegment2 && /* @__PURE__ */ jsxs(
125035
+ Button$1,
125036
+ {
125037
+ variant: "secondary",
125038
+ onClick: () => setTextToSegment(false),
125039
+ children: [
125040
+ /* @__PURE__ */ jsx(Settings2, { className: "h-4 w-4" }),
125041
+ "Manual Builder"
125042
+ ]
125043
+ }
125044
+ ),
125045
+ !textToSegment2 && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-sm text-neutral-500", children: [
125046
+ /* @__PURE__ */ jsx(Users, { className: "h-4 w-4" }),
125047
+ /* @__PURE__ */ jsxs("span", { children: [
125048
+ /* @__PURE__ */ jsx("span", { className: "font-medium text-neutral-700", children: estimatedTotal.toLocaleString() }),
125049
+ " ",
125050
+ "users match this segment"
125051
+ ] })
125052
+ ] })
125053
+ ] }),
125054
+ /* @__PURE__ */ jsx("div", { className: "flex gap-2", children: viewOnly ? (
125055
+ // VIEW-ONLY: Only Close button
125056
+ /* @__PURE__ */ jsx(Button$1, { variant: "default", onClick: () => setOpen2(false), children: "Close" })
125057
+ ) : (
125058
+ // EDIT MODE: Delete (if editing), Cancel, and Save buttons
125059
+ /* @__PURE__ */ jsxs(Fragment$1, { children: [
125060
+ segmentId && !newSegment && /* @__PURE__ */ jsxs(
125061
+ Button$1,
125062
+ {
125063
+ variant: "destructive",
125064
+ onClick: () => setShowDeleteDialog(true),
125065
+ disabled: isDeleting,
125066
+ children: [
125067
+ /* @__PURE__ */ jsx(Trash2, { className: "mr-2 h-4 w-4" }),
125068
+ "Delete"
125069
+ ]
125070
+ }
125071
+ ),
125072
+ /* @__PURE__ */ jsx(
125073
+ Button$1,
125074
+ {
125075
+ variant: "secondary",
125076
+ onClick: () => setOpen2(false),
125077
+ children: "Cancel"
125078
+ }
125079
+ ),
125080
+ /* @__PURE__ */ jsx(
125081
+ Button$1,
125082
+ {
125083
+ variant: "default",
125084
+ onClick: handleSave,
125085
+ disabled: isLoading || isCreating,
125086
+ children: isLoading || isCreating ? /* @__PURE__ */ jsxs(Fragment$1, { children: [
125087
+ /* @__PURE__ */ jsx(LoaderCircle, { className: "mr-2 h-4 w-4 animate-spin" }),
125088
+ segmentId ? "Saving..." : "Creating..."
125089
+ ] }) : segmentId ? "Save" : "Create"
125090
+ }
125091
+ )
125092
+ ] })
125093
+ ) })
125094
+ ] }) })
125095
+ ] })
125096
+ },
125097
+ "manual-builder-style"
125098
+ ),
124508
125099
  /* @__PURE__ */ jsx(Dialog, { open: showDeleteDialog, onOpenChange: setShowDeleteDialog, children: /* @__PURE__ */ jsxs(DialogContent, { className: "sm:max-w-[425px]", children: [
124509
125100
  /* @__PURE__ */ jsxs(DialogHeader$1, { children: [
124510
125101
  /* @__PURE__ */ jsx(DialogTitle, { children: "Delete Segment" }),
@@ -124913,7 +125504,7 @@ const SelectIndividualUsersContent = ({
124913
125504
  const { segments } = useListSegments();
124914
125505
  const allUsersSegment = React__default.useMemo(
124915
125506
  () => segments?.find(
124916
- (segment2) => segment2.type === BusinessSegmentTypeEnum.ALL_USERS
125507
+ (segment2) => segment2.type === SegmentDefinitionTypeEnum.ALL_USERS
124917
125508
  ),
124918
125509
  [segments]
124919
125510
  );
@@ -125474,11 +126065,11 @@ const AutomationAudienceSelectorMain = ({ title: title2 = "Preview Audience" })
125474
126065
  filterChanged
125475
126066
  ]);
125476
126067
  const allUsersSelected = includedSegments.length === 1 && excludedSegments.length === 0 && segments?.find(
125477
- (segment2) => segment2.type === BusinessSegmentTypeEnum.ALL_USERS && segment2.id === includedSegments[0]
126068
+ (segment2) => segment2.type === SegmentDefinitionTypeEnum.ALL_USERS && segment2.id === includedSegments[0]
125478
126069
  ) !== void 0;
125479
126070
  const segmentIdToFetch = includedSegments.length === 1 && excludedSegments.length === 0 && !allUsersSelected ? includedSegments[0] : "";
125480
126071
  const { segment: singleSegment } = useGetSegment(segmentIdToFetch);
125481
- const oneOffSegmentSelected = singleSegment?.type === BusinessSegmentTypeEnum.ONE_OFF;
126072
+ const oneOffSegmentSelected = singleSegment?.type === SegmentDefinitionTypeEnum.ONE_OFF;
125482
126073
  const finalCountResponse = React__default.useMemo(() => {
125483
126074
  if (selectedAudience === AutomationAudienceSelectorType.INDIVIDUAL) {
125484
126075
  if (selectedIndividualUserData.length > 0) {
@@ -125545,22 +126136,24 @@ const AutomationAudienceSelectorMain = ({ title: title2 = "Preview Audience" })
125545
126136
  const initializeState = async () => {
125546
126137
  if (automation2 && !initialStateSet && isLoading === false) {
125547
126138
  if (includedSegments.length === 1 && excludedSegments.length === 0 && segments.find(
125548
- (segment2) => segment2.type === BusinessSegmentTypeEnum.ALL_USERS && segment2.id === includedSegments[0]
126139
+ (segment2) => segment2.type === SegmentDefinitionTypeEnum.ALL_USERS && segment2.id === includedSegments[0]
125549
126140
  ) !== void 0) {
125550
126141
  setSelectedAudience(AutomationAudienceSelectorType.ALL);
125551
126142
  } else if (oneOffSegmentSelected && singleSegment) {
125552
126143
  setSelectedAudience(AutomationAudienceSelectorType.INDIVIDUAL);
125553
126144
  if (singleSegment.conditions) {
125554
126145
  const userIds = [];
125555
- singleSegment.conditions.forEach((condition) => {
125556
- if (condition.field === "userId" && condition.operator === ConditionOperatorEnumType.EQUALS) {
125557
- condition.value.forEach((val) => {
125558
- if (typeof val === "string") {
125559
- userIds.push(val);
125560
- }
125561
- });
126146
+ singleSegment.conditions.forEach(
126147
+ (condition) => {
126148
+ if (isFieldCondition(condition) && condition.field === "userId" && condition.operator === ConditionOperatorEnumType.EQUALS) {
126149
+ condition.value.forEach((val) => {
126150
+ if (typeof val === "string") {
126151
+ userIds.push(val);
126152
+ }
126153
+ });
126154
+ }
125562
126155
  }
125563
- });
126156
+ );
125564
126157
  setSelectedIndividualUserIds(userIds);
125565
126158
  if (userIds.length > 0 && singleSegment.id) {
125566
126159
  try {
@@ -125611,7 +126204,7 @@ const AutomationAudienceSelectorMain = ({ title: title2 = "Preview Audience" })
125611
126204
  setSelectedAudience(value);
125612
126205
  if (value === AutomationAudienceSelectorType.ALL) {
125613
126206
  const allUsersSegment = segments?.find(
125614
- (segment2) => segment2.type === BusinessSegmentTypeEnum.ALL_USERS
126207
+ (segment2) => segment2.type === SegmentDefinitionTypeEnum.ALL_USERS
125615
126208
  );
125616
126209
  if (!allUsersSegment) {
125617
126210
  console.error("All users segment not found");
@@ -125635,15 +126228,17 @@ const AutomationAudienceSelectorMain = ({ title: title2 = "Preview Audience" })
125635
126228
  setExcludedSegments([]);
125636
126229
  if (segment2.conditions) {
125637
126230
  const userIds = [];
125638
- segment2.conditions.forEach((condition) => {
125639
- if (condition.field === "userId" && condition.operator === ConditionOperatorEnumType.EQUALS) {
125640
- condition.value.forEach((val) => {
125641
- if (typeof val === "string") {
125642
- userIds.push(val);
125643
- }
125644
- });
126231
+ segment2.conditions.forEach(
126232
+ (condition) => {
126233
+ if (isFieldCondition(condition) && condition.field === "userId" && condition.operator === ConditionOperatorEnumType.EQUALS) {
126234
+ condition.value.forEach((val) => {
126235
+ if (typeof val === "string") {
126236
+ userIds.push(val);
126237
+ }
126238
+ });
126239
+ }
125645
126240
  }
125646
- });
126241
+ );
125647
126242
  setSelectedIndividualUserIds(userIds);
125648
126243
  if (userIds.length > 0) {
125649
126244
  try {
@@ -125680,9 +126275,10 @@ const AutomationAudienceSelectorMain = ({ title: title2 = "Preview Audience" })
125680
126275
  const newSegment = await createSegmentAsync({
125681
126276
  name: segmentName,
125682
126277
  description: "One-off segment for individual user selection",
125683
- type: BusinessSegmentTypeEnum.ONE_OFF,
126278
+ type: SegmentDefinitionTypeEnum.ONE_OFF,
125684
126279
  conditions: [
125685
126280
  {
126281
+ type: "property",
125686
126282
  field: "userId",
125687
126283
  operator: ConditionOperatorEnumType.EQUALS,
125688
126284
  value: []
@@ -125736,12 +126332,14 @@ const AutomationAudienceSelectorMain = ({ title: title2 = "Preview Audience" })
125736
126332
  params: {
125737
126333
  conditions: userIds.length > 0 ? [
125738
126334
  {
126335
+ type: "property",
125739
126336
  field: "userId",
125740
126337
  operator: ConditionOperatorEnumType.EQUALS,
125741
126338
  value: userIds
125742
126339
  }
125743
126340
  ] : [
125744
126341
  {
126342
+ type: "property",
125745
126343
  field: "userId",
125746
126344
  operator: ConditionOperatorEnumType.EQUALS,
125747
126345
  value: []
@@ -125754,15 +126352,17 @@ const AutomationAudienceSelectorMain = ({ title: title2 = "Preview Audience" })
125754
126352
  segment2 = await createSegmentAsync({
125755
126353
  name: segmentName,
125756
126354
  description: "One-off segment for individual user selection",
125757
- type: BusinessSegmentTypeEnum.ONE_OFF,
126355
+ type: SegmentDefinitionTypeEnum.ONE_OFF,
125758
126356
  conditions: userIds.length > 0 ? [
125759
126357
  {
126358
+ type: "property",
125760
126359
  field: "userId",
125761
126360
  operator: ConditionOperatorEnumType.EQUALS,
125762
126361
  value: userIds
125763
126362
  }
125764
126363
  ] : [
125765
126364
  {
126365
+ type: "property",
125766
126366
  field: "userId",
125767
126367
  operator: ConditionOperatorEnumType.EQUALS,
125768
126368
  value: []
@@ -127013,9 +127613,11 @@ const OneTimeWizardMain = ({ onFinish, getExtraMergeFields, onBeforeSchedule, hi
127013
127613
  await new Promise((resolve) => setTimeout(resolve, 250));
127014
127614
  attempts++;
127015
127615
  }
127616
+ const scheduleSendAt = getScheduleSendAtFromAutomation(automation2);
127016
127617
  const result2 = await onBeforeSchedule({
127017
127618
  estimatedEmailRecipients: estimatedMatchesStats?.estimatedEmails || 0,
127018
- estimatedSmsRecipients: estimatedMatchesStats?.estimatedSms || 0
127619
+ estimatedSmsRecipients: estimatedMatchesStats?.estimatedSms || 0,
127620
+ scheduleSendAt
127019
127621
  });
127020
127622
  if (result2 === true) {
127021
127623
  updateAutomation2(
@@ -128212,6 +128814,7 @@ const ConsolidatedStatsBar = ({
128212
128814
  statistics,
128213
128815
  automationId,
128214
128816
  onLinkClickStatsOpen,
128817
+ includeEmail = true,
128215
128818
  includeSms = false,
128216
128819
  showErrors = false
128217
128820
  }) => {
@@ -128284,7 +128887,7 @@ const ConsolidatedStatsBar = ({
128284
128887
  ] : []
128285
128888
  ];
128286
128889
  return /* @__PURE__ */ jsx("div", { className: "bg-white rounded-xl p-4 border border-border", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col lg:flex-row lg:items-center gap-4 lg:gap-0", children: [
128287
- /* @__PURE__ */ jsxs("div", { className: "lg:flex-[3]", children: [
128890
+ includeEmail && /* @__PURE__ */ jsxs("div", { className: "lg:flex-[3]", children: [
128288
128891
  /* @__PURE__ */ jsx("div", { className: "flex justify-center mb-4 lg:mb-0", children: /* @__PURE__ */ jsx(MinorText, { className: "text-[10px] font-semibold text-gray-500 uppercase tracking-wide", children: "Email" }) }),
128289
128892
  /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center", children: /* @__PURE__ */ jsx("div", { className: "flex items-center gap-2 sm:gap-3 flex-wrap justify-evenly w-full", children: emailStats.map((stat, index2) => /* @__PURE__ */ jsx(
128290
128893
  StatItem,
@@ -128457,6 +129060,7 @@ const LinkClickStatsDialog = ({
128457
129060
  const AutomationStatistics = ({
128458
129061
  automationId,
128459
129062
  includeSales = false,
129063
+ includeEmail = true,
128460
129064
  includeSms = false,
128461
129065
  showErrors = false,
128462
129066
  automation: automation2
@@ -128599,6 +129203,7 @@ const AutomationStatistics = ({
128599
129203
  statistics,
128600
129204
  automationId,
128601
129205
  onLinkClickStatsOpen: () => setIsLinkClickStatsOpen(true),
129206
+ includeEmail,
128602
129207
  includeSms: includeSms && isSmsEnabled,
128603
129208
  showErrors
128604
129209
  },
@@ -129222,9 +129827,9 @@ function SegmentList() {
129222
129827
  isPlaceholderData
129223
129828
  },
129224
129829
  onQueryParametersChange: handleQueryParametersChange,
129225
- getRowClassName: (row) => row.type === BusinessSegmentTypeEnum.ALL_USERS ? "cursor-not-allowed opacity-60" : "",
129830
+ getRowClassName: (row) => row.type === SegmentDefinitionTypeEnum.ALL_USERS ? "cursor-not-allowed opacity-60" : "",
129226
129831
  onRowClick: (row) => {
129227
- if (row.type === BusinessSegmentTypeEnum.ALL_USERS) {
129832
+ if (row.type === SegmentDefinitionTypeEnum.ALL_USERS) {
129228
129833
  toast2({
129229
129834
  title: "Read-only segment",
129230
129835
  description: "This segment cannot be edited.",
@@ -129232,7 +129837,7 @@ function SegmentList() {
129232
129837
  });
129233
129838
  return;
129234
129839
  }
129235
- if (row.type !== BusinessSegmentTypeEnum.CUSTOM) {
129840
+ if (row.type !== SegmentDefinitionTypeEnum.CUSTOM) {
129236
129841
  setSelectedSegment(row.id);
129237
129842
  setCreateDialogOpen(true);
129238
129843
  return;
@@ -129251,7 +129856,7 @@ function SegmentList() {
129251
129856
  setOpen: setCreateDialogOpen,
129252
129857
  segmentId: selectedSegment ?? void 0,
129253
129858
  onSegmentUpdated: onDialogClose,
129254
- viewOnly: selectedSegment ? segments?.find((s4) => s4.id === selectedSegment)?.type !== BusinessSegmentTypeEnum.CUSTOM : false
129859
+ viewOnly: selectedSegment ? segments?.find((s4) => s4.id === selectedSegment)?.type !== SegmentDefinitionTypeEnum.CUSTOM : false
129255
129860
  }
129256
129861
  )
129257
129862
  ] });
@@ -129882,7 +130487,9 @@ const AutomationsEditorHeader = ({ showBackButton, onDuplicationCreated, onBefor
129882
130487
  const navigate = useNavigate();
129883
130488
  const { updateAutomation: businessUpdateAutomation } = useUpdateBusinessAutomation(automation2?.id || "");
129884
130489
  const { toast: toast2 } = useToast();
129885
- const estimatedMatchesStats = useValidationStats();
130490
+ const { data: estimatedRecipientsData } = useGetEstimatedRecipients({
130491
+ automationId: automation2?.id || ""
130492
+ });
129886
130493
  const { communicationGroup } = useCurrentCommunicationGroup();
129887
130494
  const { data: smsApplication } = useGetLatestSmsRegistrationApplication();
129888
130495
  const { channelSenders } = useChannelSender();
@@ -129988,11 +130595,11 @@ const AutomationsEditorHeader = ({ showBackButton, onDuplicationCreated, onBefor
129988
130595
  } else {
129989
130596
  if (onBeforeSchedule && markActive === true) {
129990
130597
  let retries = 0;
129991
- while (!estimatedMatchesStats && retries < 20) {
130598
+ while (!estimatedRecipientsData && retries < 20) {
129992
130599
  await new Promise((resolve) => setTimeout(resolve, 100));
129993
130600
  retries++;
129994
130601
  }
129995
- if (!estimatedMatchesStats) {
130602
+ if (!estimatedRecipientsData) {
129996
130603
  toast2({
129997
130604
  title: "Error while updating the status",
129998
130605
  description: "Please contact your administrator",
@@ -130000,9 +130607,11 @@ const AutomationsEditorHeader = ({ showBackButton, onDuplicationCreated, onBefor
130000
130607
  });
130001
130608
  return;
130002
130609
  }
130610
+ const scheduleSendAt = getScheduleSendAtFromAutomation(automation2);
130003
130611
  const result2 = await onBeforeSchedule({
130004
- estimatedEmailRecipients: estimatedMatchesStats?.emails ?? 0,
130005
- estimatedSmsRecipients: estimatedMatchesStats?.phones ?? 0
130612
+ estimatedEmailRecipients: estimatedRecipientsData?.estimatedEmails ?? 0,
130613
+ estimatedSmsRecipients: estimatedRecipientsData?.estimatedSms ?? 0,
130614
+ scheduleSendAt
130006
130615
  });
130007
130616
  if (result2 !== true) {
130008
130617
  toast2({
@@ -130394,7 +131003,7 @@ const AutomationsEditorHeader = ({ showBackButton, onDuplicationCreated, onBefor
130394
131003
  automationLanguage,
130395
131004
  onBeforeSchedule,
130396
131005
  businessUpdateAutomation,
130397
- estimatedMatchesStats,
131006
+ estimatedRecipientsData,
130398
131007
  queryClient,
130399
131008
  handleUndo
130400
131009
  ]);
@@ -130648,8 +131257,13 @@ const AnimatedTabs = ({
130648
131257
  };
130649
131258
  const AutomationsEditorStatsTab = () => {
130650
131259
  const automation2 = useAutomation();
131260
+ const { state: engageFilterState } = useEngageFilterContext();
131261
+ const dateRange = engageFilterState.dateRange;
131262
+ const { communicationGroup } = useCurrentCommunicationGroup();
130651
131263
  const { isLoading: isStatisticsLoading } = useGetBusinessAutomationStatistics(
130652
- automation2?.id
131264
+ automation2?.id,
131265
+ dateRange?.from,
131266
+ dateRange?.to
130653
131267
  );
130654
131268
  const [cursorForQuery, setCursorForQuery] = useState(
130655
131269
  void 0
@@ -130666,11 +131280,15 @@ const AutomationsEditorStatsTab = () => {
130666
131280
  cursor: cursorForQuery,
130667
131281
  limit: 10,
130668
131282
  automationStatus: automation2?.status,
130669
- automationType: automation2?.triggerType
131283
+ automationType: automation2?.triggerType,
131284
+ startDate: dateRange?.from,
131285
+ endDate: dateRange?.to
130670
131286
  });
130671
131287
  const {
130672
131288
  state: { hideSales, hideSms }
130673
131289
  } = useContext(Context$3);
131290
+ const isEmailChannelEnabled = !!communicationGroup?.emailChannelSenderId;
131291
+ const isSmsChannelEnabled = !!communicationGroup?.smsChannelSenderId;
130674
131292
  const handleQueryParametersChange = useCallback(
130675
131293
  (params) => {
130676
131294
  setCursorForQuery(params.cursor);
@@ -130685,6 +131303,7 @@ const AutomationsEditorStatsTab = () => {
130685
131303
  }
130686
131304
  );
130687
131305
  }
131306
+ const isBroadcast = automation2.triggerType === AutomationTriggerType.ONE_TIME;
130688
131307
  const orderData = orders?.results || [];
130689
131308
  const columns = [
130690
131309
  {
@@ -130751,14 +131370,15 @@ const AutomationsEditorStatsTab = () => {
130751
131370
  }
130752
131371
  ];
130753
131372
  return /* @__PURE__ */ jsxs("div", { className: "h-full p-4 space-y-6", children: [
130754
- /* @__PURE__ */ jsx("div", { className: "flex justify-end", children: /* @__PURE__ */ jsx(EngageDateRangePicker, {}) }),
131373
+ !isBroadcast && /* @__PURE__ */ jsx("div", { className: "flex justify-end", children: /* @__PURE__ */ jsx(EngageDateRangePicker, {}) }),
130755
131374
  /* @__PURE__ */ jsx(
130756
131375
  AutomationStatistics,
130757
131376
  {
130758
131377
  automationId: automation2.id,
130759
131378
  automation: automation2,
130760
131379
  includeSales: !hideSales,
130761
- includeSms: !hideSms,
131380
+ includeEmail: isEmailChannelEnabled,
131381
+ includeSms: !hideSms && isSmsChannelEnabled,
130762
131382
  showErrors: true
130763
131383
  }
130764
131384
  ),
@@ -133466,10 +134086,10 @@ const AutomationAudienceSelector = () => {
133466
134086
  const excludeSegmentIds = automation2.excludeSegmentIds;
133467
134087
  let copyText;
133468
134088
  let showSegmentPills = true;
133469
- if (singleSegment?.type === BusinessSegmentTypeEnum.ALL_USERS) {
134089
+ if (singleSegment?.type === SegmentDefinitionTypeEnum.ALL_USERS) {
133470
134090
  copyText = `Send to all ${t$2("engage:user", { count: 2 })}`;
133471
134091
  showSegmentPills = false;
133472
- } else if (singleSegment?.type === BusinessSegmentTypeEnum.ONE_OFF) {
134092
+ } else if (singleSegment?.type === SegmentDefinitionTypeEnum.ONE_OFF) {
133473
134093
  copyText = `Send to specific ${t$2("engage:user", { count: 2 })}`;
133474
134094
  showSegmentPills = false;
133475
134095
  } else {
@@ -133880,15 +134500,15 @@ const AutomationEditorSubStep = ({
133880
134500
  const channelEnabled = (() => {
133881
134501
  if (!communicationGroup) return false;
133882
134502
  switch (type) {
133883
- case CommunicationSubStepType$1.EMAIL:
134503
+ case CommunicationSubStepType.EMAIL:
133884
134504
  return !!communicationGroup.emailChannelSenderId;
133885
- case CommunicationSubStepType$1.SMS:
134505
+ case CommunicationSubStepType.SMS:
133886
134506
  return !!communicationGroup.smsChannelSenderId;
133887
134507
  }
133888
134508
  })();
133889
134509
  const getIcon = (type2, isSelected2) => {
133890
134510
  switch (type2) {
133891
- case CommunicationSubStepType$1.EMAIL:
134511
+ case CommunicationSubStepType.EMAIL:
133892
134512
  return /* @__PURE__ */ jsx(
133893
134513
  IconDefinitions.EmailIcon,
133894
134514
  {
@@ -133898,7 +134518,7 @@ const AutomationEditorSubStep = ({
133898
134518
  )
133899
134519
  }
133900
134520
  );
133901
- case CommunicationSubStepType$1.SMS:
134521
+ case CommunicationSubStepType.SMS:
133902
134522
  return /* @__PURE__ */ jsx(
133903
134523
  IconDefinitions.SmsIcon,
133904
134524
  {
@@ -133912,16 +134532,16 @@ const AutomationEditorSubStep = ({
133912
134532
  };
133913
134533
  const getSubStepLabel = () => {
133914
134534
  switch (type) {
133915
- case CommunicationSubStepType$1.EMAIL:
134535
+ case CommunicationSubStepType.EMAIL:
133916
134536
  return "Email";
133917
- case CommunicationSubStepType$1.SMS:
134537
+ case CommunicationSubStepType.SMS:
133918
134538
  return "SMS";
133919
134539
  }
133920
134540
  };
133921
134541
  const contentNeeded = (() => {
133922
134542
  if (!communicationGroup) return "Need to select a channel";
133923
134543
  switch (type) {
133924
- case CommunicationSubStepType$1.EMAIL:
134544
+ case CommunicationSubStepType.EMAIL:
133925
134545
  if (!communicationGroup.emailChannelSenderId) {
133926
134546
  return "Please select a email sender";
133927
134547
  }
@@ -133932,7 +134552,7 @@ const AutomationEditorSubStep = ({
133932
134552
  return "Please add a subject to the email";
133933
134553
  }
133934
134554
  return true;
133935
- case CommunicationSubStepType$1.SMS:
134555
+ case CommunicationSubStepType.SMS:
133936
134556
  if (!communicationGroup.smsChannelSenderId) {
133937
134557
  return "Please select a sms sender";
133938
134558
  }
@@ -133983,7 +134603,7 @@ const AutomationEditorSubStep = ({
133983
134603
  children: /* @__PURE__ */ jsx(MinorText, { className: "text-xs", children: getSubStepLabel() })
133984
134604
  }
133985
134605
  ),
133986
- channelEnabled && /* @__PURE__ */ jsx("div", { className: "text-[10px] font-medium text-muted-foreground", children: type === CommunicationSubStepType$1.EMAIL ? isGettingMergeFields ? /* @__PURE__ */ jsx("span", { className: "text-[10px] font-medium text-muted-foreground", children: "..." }) : /* @__PURE__ */ jsx(
134606
+ channelEnabled && /* @__PURE__ */ jsx("div", { className: "text-[10px] font-medium text-muted-foreground", children: type === CommunicationSubStepType.EMAIL ? isGettingMergeFields ? /* @__PURE__ */ jsx("span", { className: "text-[10px] font-medium text-muted-foreground", children: "..." }) : /* @__PURE__ */ jsx(
133987
134607
  MergeFieldRenderer,
133988
134608
  {
133989
134609
  content: communicationGroup?.emailSubject || "No subject set",
@@ -134032,7 +134652,7 @@ const actionTypeToHumanReadable = (actionType, customBlockText) => {
134032
134652
  case ActionType.SEND_COMMUNICATION:
134033
134653
  return customBlockText || "Send Communication";
134034
134654
  case ActionType.WAIT_UNTIL_AT_LEAST_NEXT_AVAILABLE_TIME:
134035
- return "Wait (Skip if Time Has Already Passed Today)";
134655
+ return "Wait (Proceed if Time Has Already Passed Today)";
134036
134656
  case ActionType.WAIT_UNTIL_NEXT_OCCURRENCE:
134037
134657
  return "Wait (Always Wait for Next Occurrence (even if it means waiting until tomorrow))";
134038
134658
  case ActionType.WAIT_FOR_DURATION:
@@ -134322,9 +134942,9 @@ const AutomationFlowMain = ({
134322
134942
  );
134323
134943
  if (selectedAction?.actionData.actionType === ActionType.SEND_COMMUNICATION) {
134324
134944
  if (communicationGroup?.emailChannelSenderId) {
134325
- setSelectedSubStepType2(CommunicationSubStepType$1.EMAIL);
134945
+ setSelectedSubStepType2(CommunicationSubStepType.EMAIL);
134326
134946
  } else {
134327
- setSelectedSubStepType2(CommunicationSubStepType$1.SMS);
134947
+ setSelectedSubStepType2(CommunicationSubStepType.SMS);
134328
134948
  }
134329
134949
  }
134330
134950
  }
@@ -134413,14 +135033,14 @@ const AutomationFlowMain = ({
134413
135033
  /* @__PURE__ */ jsx(
134414
135034
  AutomationEditorSubStep,
134415
135035
  {
134416
- type: CommunicationSubStepType$1.EMAIL,
135036
+ type: CommunicationSubStepType.EMAIL,
134417
135037
  actionId: actionData.actionData.actionMetadata.currentActionId
134418
135038
  }
134419
135039
  ),
134420
135040
  !hideSms && /* @__PURE__ */ jsx(
134421
135041
  AutomationEditorSubStep,
134422
135042
  {
134423
- type: CommunicationSubStepType$1.SMS,
135043
+ type: CommunicationSubStepType.SMS,
134424
135044
  actionId: actionData.actionData.actionMetadata.currentActionId
134425
135045
  }
134426
135046
  )
@@ -134640,9 +135260,9 @@ const useChannelToggle = (type) => {
134640
135260
  const isChannelEnabled = useCallback(() => {
134641
135261
  if (!communicationGroup) return false;
134642
135262
  switch (type) {
134643
- case CommunicationSubStepType$1.EMAIL:
135263
+ case CommunicationSubStepType.EMAIL:
134644
135264
  return !!communicationGroup.emailChannelSenderId;
134645
- case CommunicationSubStepType$1.SMS:
135265
+ case CommunicationSubStepType.SMS:
134646
135266
  return !!communicationGroup.smsChannelSenderId;
134647
135267
  }
134648
135268
  }, [communicationGroup, type]);
@@ -134655,7 +135275,7 @@ const useChannelToggle = (type) => {
134655
135275
  smsChannelSenderId: communicationGroup.smsChannelSenderId
134656
135276
  };
134657
135277
  switch (type) {
134658
- case CommunicationSubStepType$1.EMAIL:
135278
+ case CommunicationSubStepType.EMAIL:
134659
135279
  if (channelEnabled && communicationGroup.emailChannelSenderId) {
134660
135280
  params.emailChannelSenderId = null;
134661
135281
  } else {
@@ -134665,7 +135285,7 @@ const useChannelToggle = (type) => {
134665
135285
  }
134666
135286
  }
134667
135287
  break;
134668
- case CommunicationSubStepType$1.SMS:
135288
+ case CommunicationSubStepType.SMS:
134669
135289
  if (channelEnabled && communicationGroup.smsChannelSenderId) {
134670
135290
  params.smsChannelSenderId = null;
134671
135291
  } else {
@@ -135723,7 +136343,7 @@ const AutomationEditorEmailPreview = ({
135723
136343
  channelEnabled,
135724
136344
  isUpdating: isUpdatingChannel,
135725
136345
  handleToggleChannel
135726
- } = useChannelToggle(CommunicationSubStepType$1.EMAIL);
136346
+ } = useChannelToggle(CommunicationSubStepType.EMAIL);
135727
136347
  const [openPreviewDialog, setOpenPreviewDialog] = useState(false);
135728
136348
  const [showStripoEditor, setShowStripoEditor] = useState(false);
135729
136349
  const [showHelpDialog, setShowHelpDialog] = useState(null);
@@ -136079,7 +136699,7 @@ const AutomationEditorSMSPreview = ({
136079
136699
  channelEnabled,
136080
136700
  isUpdating: isUpdatingChannel,
136081
136701
  handleToggleChannel
136082
- } = useChannelToggle(CommunicationSubStepType.SMS);
136702
+ } = useChannelToggle(CommunicationSubStepType$1.SMS);
136083
136703
  const { updateCommunicationGroup: updateCommunicationGroup2, isUpdating: isUpdatingCommunicationGroup } = useUpdateCommunicationGroup();
136084
136704
  const smsChannelSenders = getSmsChannelSenders({
136085
136705
  channelSenders: channelSenders?.results ?? [],
@@ -136420,8 +137040,8 @@ const AutomationEditorCommunicationPreview = ({
136420
137040
  disablePreviewSubtext
136421
137041
  };
136422
137042
  return /* @__PURE__ */ jsxs("div", { className: "flex flex-col flex-1 bg-muted rounded-md", children: [
136423
- selectedSubStepType === CommunicationSubStepType$1.EMAIL && /* @__PURE__ */ jsx(AutomationEditorEmailPreview, { ...commonProps }),
136424
- selectedSubStepType === CommunicationSubStepType$1.SMS && !hideSms && /* @__PURE__ */ jsx(AutomationEditorSMSPreview, { ...commonProps })
137043
+ selectedSubStepType === CommunicationSubStepType.EMAIL && /* @__PURE__ */ jsx(AutomationEditorEmailPreview, { ...commonProps }),
137044
+ selectedSubStepType === CommunicationSubStepType.SMS && !hideSms && /* @__PURE__ */ jsx(AutomationEditorSMSPreview, { ...commonProps })
136425
137045
  ] });
136426
137046
  };
136427
137047
  const AutomationsEditorMain = () => {
@@ -136577,7 +137197,7 @@ const ViewAutomationMain = ({
136577
137197
  updateCommunicationGroup2
136578
137198
  ]);
136579
137199
  if (!automation2 || !communicationGroup || isLoadingSegments) {
136580
- return /* @__PURE__ */ jsx("div", { className: "flex h-full items-center justify-center", children: /* @__PURE__ */ jsx(
137200
+ return /* @__PURE__ */ jsx("div", { className: "flex flex-1 items-center justify-center", children: /* @__PURE__ */ jsx(
136581
137201
  BasicLoader,
136582
137202
  {
136583
137203
  text: [
@@ -136596,7 +137216,7 @@ const ViewAutomationMain = ({
136596
137216
  fromNameSettingsLink,
136597
137217
  hideSms,
136598
137218
  hideSales,
136599
- children: /* @__PURE__ */ jsxs("div", { className: "h-full flex flex-col gap-4 p-4", children: [
137219
+ children: /* @__PURE__ */ jsxs("div", { className: "flex-1 flex flex-col gap-4 p-4", children: [
136600
137220
  /* @__PURE__ */ jsx(
136601
137221
  AutomationsEditorHeader,
136602
137222
  {
@@ -136616,7 +137236,7 @@ const ViewAutomationContent = ({ ...props2 }) => {
136616
137236
  const effectiveAutomationId = props2.automationId || params?.automationId || searchParams.get("automationId") || "";
136617
137237
  const shouldShowBackButton = searchParams.get("showBackButton") === "true" || props2.showBackButton;
136618
137238
  const shouldHideSms = searchParams.get("hideSms") === "true" || props2.hideSms;
136619
- return /* @__PURE__ */ jsx(Provider, { children: /* @__PURE__ */ jsx(ViewAutomationProvider, { automationId: effectiveAutomationId, children: /* @__PURE__ */ jsx("div", { className: "bg-background h-full min-h-[750px]", children: /* @__PURE__ */ jsx(
137239
+ return /* @__PURE__ */ jsx(Provider, { children: /* @__PURE__ */ jsx(ViewAutomationProvider, { automationId: effectiveAutomationId, children: /* @__PURE__ */ jsx("div", { className: "bg-background flex flex-col h-full min-h-[750px]", children: /* @__PURE__ */ jsx(
136620
137240
  ViewAutomationMain,
136621
137241
  {
136622
137242
  ...props2,