@embedreach/components 0.3.37 → 0.3.38

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.
@@ -23016,7 +23016,6 @@ const updateBusinessLocations = async (locations) => {
23016
23016
  return response.data;
23017
23017
  };
23018
23018
  const updateBusinessBrandSettings = async (branding) => {
23019
- console.log("branding", branding);
23020
23019
  const response = await baseRequest(BUSINESS_PATH, {
23021
23020
  method: "PATCH",
23022
23021
  body: JSON.stringify({ branding })
@@ -28705,7 +28704,6 @@ const useEngageFormSubmissions = () => {
28705
28704
  };
28706
28705
  const handleBusinessSubmit = async (data, onSuccess) => {
28707
28706
  try {
28708
- console.log("data", data);
28709
28707
  updateBusinessSettings2(data, {
28710
28708
  onSuccess: () => {
28711
28709
  onSuccess?.();
@@ -28727,12 +28725,16 @@ const useEngageFormSubmissions = () => {
28727
28725
  });
28728
28726
  const selectedSender = emailChannelSenders[0];
28729
28727
  if (!selectedSender) return;
28728
+ const replyToEmail = data.replyToEmail?.trim() ? data.replyToEmail : (() => {
28729
+ const domain = selectedSender.fullDomain.split("@")[1] || "";
28730
+ return `no-reply@${domain}`;
28731
+ })();
28730
28732
  updateChannelSender2(
28731
28733
  {
28732
28734
  toUpdate: {
28733
28735
  channelSenderMetadata: {
28734
28736
  ...selectedSender.channelSender.channelSenderMetadata,
28735
- emailReplyTo: data.replyToEmail ?? null,
28737
+ emailReplyTo: replyToEmail,
28736
28738
  emailFromName: data.displayName
28737
28739
  }
28738
28740
  },
@@ -28800,6 +28802,7 @@ const initialState$3 = {
28800
28802
  currentStepIndex: 0,
28801
28803
  steps: allSteps,
28802
28804
  skipSMS: false,
28805
+ skipCompletion: false,
28803
28806
  completedSteps: [],
28804
28807
  visitedSteps: [ENGAGE_STEPS.SPLASH],
28805
28808
  formData: {},
@@ -28850,6 +28853,16 @@ const engageOnboardingReducer = (state, action) => {
28850
28853
  steps: newStepsAfterSMS
28851
28854
  });
28852
28855
  }
28856
+ case "SET_SKIP_COMPLETION": {
28857
+ const newStepsAfterCompletion = allSteps.filter(
28858
+ (step) => step !== ENGAGE_STEPS.COMPLETION || !action.payload
28859
+ );
28860
+ return updateNavigationState({
28861
+ ...state,
28862
+ skipCompletion: action.payload,
28863
+ steps: newStepsAfterCompletion
28864
+ });
28865
+ }
28853
28866
  case "MARK_STEP_COMPLETE":
28854
28867
  return {
28855
28868
  ...state,
@@ -28921,6 +28934,9 @@ const setCurrentStep = (dispatch2) => (step) => {
28921
28934
  const setSkipSMS = (dispatch2) => (skipSMS) => {
28922
28935
  dispatch2({ type: "SET_SKIP_SMS", payload: skipSMS });
28923
28936
  };
28937
+ const setSkipCompletion = (dispatch2) => (skipCompletion) => {
28938
+ dispatch2({ type: "SET_SKIP_COMPLETION", payload: skipCompletion });
28939
+ };
28924
28940
  const markStepComplete = (dispatch2) => (step) => {
28925
28941
  dispatch2({ type: "MARK_STEP_COMPLETE", payload: step });
28926
28942
  };
@@ -32284,7 +32300,8 @@ const EmailChannelForm = ({ onSubmit }) => {
32284
32300
  const { emailFromName, emailReplyTo } = firstSender.channelSender.channelSenderMetadata;
32285
32301
  form.reset({
32286
32302
  displayName: emailFromName || "",
32287
- replyToEmail: emailReplyTo && emailReplyTo.trim() ? emailReplyTo : firstSender.fullDomain
32303
+ replyToEmail: emailReplyTo && emailReplyTo.trim() ? emailReplyTo : ""
32304
+ // Leave blank for new users to encourage them to enter their own email
32288
32305
  });
32289
32306
  }
32290
32307
  }, [emailChannelSenders, form]);
@@ -32303,6 +32320,8 @@ const EmailChannelForm = ({ onSubmit }) => {
32303
32320
  const managedEmailAccount = emailChannelSenders[0];
32304
32321
  const displayName = form.watch("displayName") || "";
32305
32322
  const replyToEmail = form.watch("replyToEmail") || "";
32323
+ const managedEmailDomain = managedEmailAccount.fullDomain.split("@")[1] || "";
32324
+ const noReplyFallback = `no-reply@${managedEmailDomain}`;
32306
32325
  return /* @__PURE__ */ jsx(Form$1, { ...form, children: /* @__PURE__ */ jsxs("form", { onSubmit: handleSubmit, className: "space-y-8 p-8", children: [
32307
32326
  /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
32308
32327
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
@@ -32362,10 +32381,7 @@ const EmailChannelForm = ({ onSubmit }) => {
32362
32381
  ] }),
32363
32382
  /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
32364
32383
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
32365
- /* @__PURE__ */ jsxs(Label$1, { className: "text-sm font-medium text-gray-900", children: [
32366
- "Reply-to Email ",
32367
- /* @__PURE__ */ jsx("span", { className: "text-red-500", children: "*" })
32368
- ] }),
32384
+ /* @__PURE__ */ jsx(Label$1, { className: "text-sm font-medium text-gray-900", children: "Reply-to Email" }),
32369
32385
  /* @__PURE__ */ jsx(
32370
32386
  InfoTooltip,
32371
32387
  {
@@ -32384,10 +32400,14 @@ const EmailChannelForm = ({ onSubmit }) => {
32384
32400
  Input,
32385
32401
  {
32386
32402
  type: "email",
32387
- placeholder: "Enter email address for replies",
32403
+ placeholder: "e.g., support@yourcompany.com",
32388
32404
  ...field
32389
32405
  }
32390
32406
  ) }),
32407
+ /* @__PURE__ */ jsxs("p", { className: "text-sm text-gray-600 mt-2", children: [
32408
+ /* @__PURE__ */ jsx("strong", { children: "Recommended:" }),
32409
+ " Enter an inbox you actively monitor (like support@yourcompany.com) so you can respond to customer replies. If left blank, replies will go to a no-reply address."
32410
+ ] }),
32391
32411
  /* @__PURE__ */ jsx(FormMessage, {})
32392
32412
  ] })
32393
32413
  }
@@ -32423,7 +32443,7 @@ const EmailChannelForm = ({ onSubmit }) => {
32423
32443
  /* @__PURE__ */ jsx("div", { className: "mt-4 p-3 bg-purple-100 rounded-lg", children: /* @__PURE__ */ jsxs("p", { className: "text-sm text-purple-700", children: [
32424
32444
  "Note: When customers reply, their response will go to",
32425
32445
  " ",
32426
- /* @__PURE__ */ jsx("span", { className: "font-semibold text-purple-900", children: replyToEmail || managedEmailAccount.fullDomain })
32446
+ /* @__PURE__ */ jsx("span", { className: "font-semibold text-purple-900", children: replyToEmail || noReplyFallback })
32427
32447
  ] }) })
32428
32448
  ] })
32429
32449
  ] }),
@@ -32538,12 +32558,13 @@ const automationKeys = {
32538
32558
  ...args.limit ? [args.limit] : []
32539
32559
  ],
32540
32560
  businessStatistics: () => [...automationKeys.all, "business", "statistics"],
32541
- recipients: (id2, includeSegments, excludeSegments) => [
32561
+ recipients: (id2, includeSegments, excludeSegments, search2) => [
32542
32562
  ...automationKeys.all,
32543
32563
  id2,
32544
32564
  "recipients",
32545
32565
  JSON.stringify(includeSegments),
32546
- JSON.stringify(excludeSegments)
32566
+ JSON.stringify(excludeSegments),
32567
+ ...search2 ? [search2] : []
32547
32568
  ],
32548
32569
  estimatedRecipients: (id2) => [...automationKeys.all, id2, "estimated-recipients"],
32549
32570
  list: (args) => [
@@ -35409,9 +35430,36 @@ const MergeFieldSettings = ({
35409
35430
  const goToNextStep2 = (isOnboarding ? onboardingContext?.goToNextStep : settingsContext?.navigation?.goToNextStep) || wizardContext?.goToNextStep || (() => {
35410
35431
  });
35411
35432
  const markStepComplete2 = onboardingContext?.markStepComplete;
35433
+ const isLastStep = onboardingContext?.isLastStep ?? false;
35434
+ const handleClose = onboardingContext?.handleClose;
35435
+ const { toggleEngageOnboarding } = useBusiness$1();
35412
35436
  const stepTitle = title2 || ENGAGE_STRINGS.MERGE_FIELDS_TITLE;
35413
35437
  const stepDescription = description2 || "Manage merge fields for personalizing your communications with dynamic content.";
35414
35438
  const formRef = useRef(null);
35439
+ const handleSkip = () => {
35440
+ toggleEngageOnboarding(false);
35441
+ handleClose?.();
35442
+ };
35443
+ const handleCompletion = () => {
35444
+ if (formRef.current) {
35445
+ const mergeFields = formRef.current.getData();
35446
+ const mapping = Object.fromEntries(
35447
+ mergeFields.filter((field) => field.fallbackValue.trim()).map((field) => [
35448
+ field.value.replace(/[{}]/g, ""),
35449
+ // Remove {{}} syntax
35450
+ field.fallbackValue.trim()
35451
+ ])
35452
+ );
35453
+ postBusinessMergeFieldFallbacks2({
35454
+ mergeFieldFallbacks: mapping
35455
+ });
35456
+ if (markStepComplete2) {
35457
+ markStepComplete2(ENGAGE_STEPS.MERGE_FIELDS);
35458
+ }
35459
+ toggleEngageOnboarding(false);
35460
+ handleClose?.();
35461
+ }
35462
+ };
35415
35463
  const handleFormSubmit = () => {
35416
35464
  if (formRef.current) {
35417
35465
  const mergeFields = formRef.current.getData();
@@ -35429,18 +35477,26 @@ const MergeFieldSettings = ({
35429
35477
  if (markStepComplete2) {
35430
35478
  markStepComplete2(ENGAGE_STEPS.MERGE_FIELDS);
35431
35479
  }
35432
- goToNextStep2();
35480
+ if (isLastStep) {
35481
+ handleCompletion();
35482
+ } else {
35483
+ goToNextStep2();
35484
+ }
35433
35485
  }
35434
35486
  }
35435
35487
  };
35488
+ const showCompletionButtons = isOnboarding && isLastStep;
35436
35489
  return /* @__PURE__ */ jsxs(
35437
35490
  WizardFormWrapper,
35438
35491
  {
35439
35492
  title: stepTitle,
35440
35493
  description: stepDescription,
35441
- onBack: goToPreviousStep2,
35494
+ onBack: showCompletionButtons ? void 0 : goToPreviousStep2,
35442
35495
  onNext: handleFormSubmit,
35443
- submitLabel: isOnboarding ? "Next step" : "Save",
35496
+ onSkip: showCompletionButtons ? handleSkip : void 0,
35497
+ submitLabel: showCompletionButtons ? isPosting ? "Saving..." : "Save & Go to dashboard" : isOnboarding ? "Next step" : "Save",
35498
+ canGoNext: !isPosting,
35499
+ skipLabel: showCompletionButtons ? "Skip" : void 0,
35444
35500
  mode: isOnboarding ? "onboarding" : "settings",
35445
35501
  isSubmitting: isPosting,
35446
35502
  children: [
@@ -35580,6 +35636,7 @@ const smsRegistrationApplicationDataSchema = z$2.discriminatedUnion(
35580
35636
  );
35581
35637
  var SmsRegistrationApplicationStatus = /* @__PURE__ */ ((SmsRegistrationApplicationStatus2) => {
35582
35638
  SmsRegistrationApplicationStatus2["PENDING"] = "pending";
35639
+ SmsRegistrationApplicationStatus2["IN_REVIEW"] = "in_review";
35583
35640
  SmsRegistrationApplicationStatus2["APPROVED"] = "approved";
35584
35641
  SmsRegistrationApplicationStatus2["REJECTED"] = "rejected";
35585
35642
  return SmsRegistrationApplicationStatus2;
@@ -35859,7 +35916,7 @@ const SMSSetup = ({
35859
35916
  }
35860
35917
  }
35861
35918
  };
35862
- const isPending = latestSmsRegistrationApplication && latestSmsRegistrationApplication.status === SmsRegistrationApplicationStatus.PENDING;
35919
+ const isInReview = latestSmsRegistrationApplication && (latestSmsRegistrationApplication.status === SmsRegistrationApplicationStatus.IN_REVIEW || latestSmsRegistrationApplication.status === SmsRegistrationApplicationStatus.PENDING);
35863
35920
  return /* @__PURE__ */ jsxs(
35864
35921
  motion.div,
35865
35922
  {
@@ -35880,17 +35937,32 @@ const SMSSetup = ({
35880
35937
  children: /* @__PURE__ */ jsx(IconDefinitions.SmsIcon, {})
35881
35938
  }
35882
35939
  ),
35883
- /* @__PURE__ */ jsx(
35884
- motion.h2,
35885
- {
35886
- variants: itemVariants2,
35887
- className: "text-sm font-medium text-foreground",
35888
- children: "Request your SMS sending number"
35889
- }
35890
- ),
35891
- /* @__PURE__ */ jsxs(motion.div, { variants: itemVariants2, className: "max-w-xl mx-auto", children: [
35892
- /* @__PURE__ */ jsx("p", { className: "text-sm font-normal text-muted-foreground mb-2", children: "Before you can send messages, we need to verify your business info with our SMS provider. Once approved, we'll assign you a phone number to send SMS campaigns." }),
35893
- /* @__PURE__ */ jsx("p", { className: "text-sm font-normal text-muted-foreground", children: "This usually takes 3-7 business days." })
35940
+ isInReview ? /* @__PURE__ */ jsxs(Fragment$1, { children: [
35941
+ /* @__PURE__ */ jsx(
35942
+ motion.h2,
35943
+ {
35944
+ variants: itemVariants2,
35945
+ className: "text-sm font-medium text-foreground",
35946
+ children: "SMS Application Under Review"
35947
+ }
35948
+ ),
35949
+ /* @__PURE__ */ jsxs(motion.div, { variants: itemVariants2, className: "max-w-xl mx-auto", children: [
35950
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-normal text-muted-foreground mb-2", children: "Your SMS application is currently being reviewed by our SMS provider. Once approved, we'll assign you a phone number to send SMS campaigns." }),
35951
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-normal text-muted-foreground", children: "This usually takes 3-7 business days." })
35952
+ ] })
35953
+ ] }) : /* @__PURE__ */ jsxs(Fragment$1, { children: [
35954
+ /* @__PURE__ */ jsx(
35955
+ motion.h2,
35956
+ {
35957
+ variants: itemVariants2,
35958
+ className: "text-sm font-medium text-foreground",
35959
+ children: "Request your SMS sending number"
35960
+ }
35961
+ ),
35962
+ /* @__PURE__ */ jsxs(motion.div, { variants: itemVariants2, className: "max-w-xl mx-auto", children: [
35963
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-normal text-muted-foreground mb-2", children: "Before you can send messages, we need to verify your business info with our SMS provider. Once approved, we'll assign you a phone number to send SMS campaigns." }),
35964
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-normal text-muted-foreground", children: "This usually takes 3-7 business days." })
35965
+ ] })
35894
35966
  ] }),
35895
35967
  /* @__PURE__ */ jsx(AnimatePresence, { mode: "wait", children: showForm ? /* @__PURE__ */ jsx(
35896
35968
  motion.div,
@@ -35911,11 +35983,11 @@ const SMSSetup = ({
35911
35983
  )
35912
35984
  },
35913
35985
  "form"
35914
- ) : isPending ? /* @__PURE__ */ jsxs(
35986
+ ) : isInReview ? /* @__PURE__ */ jsxs(
35915
35987
  motion.div,
35916
35988
  {
35917
35989
  variants: itemVariants2,
35918
- className: "flex items-center gap-2 px-3 py-1.5 bg-orange-50 border border-orange-200 rounded-full",
35990
+ className: "flex items-center gap-2 px-3 py-1.5 bg-amber-50 border border-amber-200 rounded-full",
35919
35991
  children: [
35920
35992
  /* @__PURE__ */ jsx(
35921
35993
  motion.div,
@@ -35929,13 +36001,13 @@ const SMSSetup = ({
35929
36001
  repeat: Number.POSITIVE_INFINITY,
35930
36002
  ease: "easeInOut"
35931
36003
  },
35932
- className: "w-2 h-2 bg-orange-500 rounded-full"
36004
+ className: "w-2 h-2 bg-amber-500 rounded-full"
35933
36005
  }
35934
36006
  ),
35935
- /* @__PURE__ */ jsx("span", { className: "text-sm font-medium text-orange-800", children: "Pending approval" })
36007
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-medium text-amber-800", children: "Pending Review" })
35936
36008
  ]
35937
36009
  },
35938
- "pending"
36010
+ "in-review"
35939
36011
  ) : /* @__PURE__ */ jsx(motion.div, { variants: itemVariants2, children: /* @__PURE__ */ jsx(
35940
36012
  Button$1,
35941
36013
  {
@@ -36023,7 +36095,8 @@ const SMSChannelSettings = ({
36023
36095
  const applicationValid = smsChannelSenders.some(
36024
36096
  (sender) => sender.smsApplication?.status === SmsRegistrationApplicationStatus.APPROVED
36025
36097
  );
36026
- return /* @__PURE__ */ jsx("div", { className: "w-full max-w-4xl mx-auto mt-8", children: validSmsSender ? /* @__PURE__ */ jsxs(
36098
+ const isInReview = smsApplication?.status === SmsRegistrationApplicationStatus.IN_REVIEW || smsApplication?.status === SmsRegistrationApplicationStatus.PENDING;
36099
+ return /* @__PURE__ */ jsx("div", { className: "w-full max-w-4xl mx-auto mt-8", children: isInReview ? /* @__PURE__ */ jsxs(
36027
36100
  motion.div,
36028
36101
  {
36029
36102
  initial: "hidden",
@@ -36033,6 +36106,64 @@ const SMSChannelSettings = ({
36033
36106
  className: cn$2(
36034
36107
  "flex flex-col items-center text-center w-full max-w-[72ch] rounded-xl gap-3 mx-auto bg-background"
36035
36108
  ),
36109
+ children: [
36110
+ /* @__PURE__ */ jsx(
36111
+ motion.div,
36112
+ {
36113
+ variants: itemVariants2,
36114
+ className: "w-16 h-16 rounded-xl flex items-center justify-center bg-amber-50",
36115
+ children: /* @__PURE__ */ jsx(IconDefinitions.SmsIcon, { className: "text-amber-600" })
36116
+ }
36117
+ ),
36118
+ /* @__PURE__ */ jsx(
36119
+ motion.h2,
36120
+ {
36121
+ variants: itemVariants2,
36122
+ className: "text-lg font-medium text-foreground",
36123
+ children: "SMS Application Under Review"
36124
+ }
36125
+ ),
36126
+ /* @__PURE__ */ jsxs(motion.div, { variants: itemVariants2, className: "max-w-xl mx-auto", children: [
36127
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-normal text-muted-foreground mb-2", children: "Your SMS application is currently being reviewed by our SMS provider. Once approved, we'll assign you a phone number to send SMS campaigns." }),
36128
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-normal text-muted-foreground", children: "This usually takes 3-7 business days." })
36129
+ ] }),
36130
+ /* @__PURE__ */ jsx(
36131
+ motion.div,
36132
+ {
36133
+ variants: itemVariants2,
36134
+ className: "flex flex-col items-center w-full gap-4",
36135
+ children: /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center px-4 py-1 rounded-full bg-amber-50 border border-amber-200 text-amber-800 font-medium text-base mb-2", children: [
36136
+ /* @__PURE__ */ jsx(
36137
+ motion.span,
36138
+ {
36139
+ animate: {
36140
+ scale: [1, 1.2, 1],
36141
+ opacity: [1, 0.8, 1]
36142
+ },
36143
+ transition: {
36144
+ duration: 2,
36145
+ repeat: Number.POSITIVE_INFINITY,
36146
+ ease: "easeInOut"
36147
+ },
36148
+ className: "w-2 h-2 bg-amber-500 rounded-full mr-2"
36149
+ }
36150
+ ),
36151
+ "Pending Review"
36152
+ ] })
36153
+ }
36154
+ )
36155
+ ]
36156
+ }
36157
+ ) : validSmsSender ? /* @__PURE__ */ jsxs(
36158
+ motion.div,
36159
+ {
36160
+ initial: "hidden",
36161
+ animate: "visible",
36162
+ exit: "exit",
36163
+ variants: containerVariants,
36164
+ className: cn$2(
36165
+ "flex flex-col items-center text-center w-full max-w-[72ch] rounded-xl gap-3 mx-auto bg-blue-50 border-blue-200 text-blue-900"
36166
+ ),
36036
36167
  children: [
36037
36168
  /* @__PURE__ */ jsx(
36038
36169
  motion.div,
@@ -36071,22 +36202,32 @@ const SMSChannelSettings = ({
36071
36202
  /* @__PURE__ */ jsx("span", { className: "w-2 h-2 bg-blue-500 rounded-full mr-2" }),
36072
36203
  "Ready to send"
36073
36204
  ] }),
36074
- /* @__PURE__ */ jsx("div", { className: "w-full flex flex-col gap-3 max-w-md mx-auto", children: smsChannelSenders.map((sender) => {
36205
+ /* @__PURE__ */ jsx("div", { className: "w-full flex flex-col gap-3 mx-auto", children: smsChannelSenders.map((sender) => {
36075
36206
  const isPending = !!sender.channelSender.channelSenderMetadata.friendlyName?.toLowerCase().includes("pending approval");
36076
36207
  const displayName = sender.channelSender.channelSenderMetadata.friendlyName || sender.channelSender.channelSenderMetadata.from || "Unknown Number";
36077
36208
  return /* @__PURE__ */ jsxs(
36078
36209
  "div",
36079
36210
  {
36080
36211
  className: cn$2(
36081
- "flex items-center justify-between rounded-xl px-4 py-3 border shadow-sm",
36212
+ "flex items-start rounded-xl px-4 py-3 border shadow-sm",
36082
36213
  isPending ? "bg-gray-50 border-gray-200 text-gray-500" : "bg-blue-50 border-blue-200 text-blue-900 font-semibold"
36083
36214
  ),
36084
36215
  children: [
36085
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 min-w-0", children: [
36086
- 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" }),
36087
- /* @__PURE__ */ jsx("span", { className: "truncate", title: displayName, children: displayName })
36216
+ /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-3 flex-1 min-w-0", children: [
36217
+ 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" }),
36218
+ /* @__PURE__ */ jsx(
36219
+ "span",
36220
+ {
36221
+ className: cn$2(
36222
+ "text-sm leading-relaxed",
36223
+ isPending ? "break-words" : "truncate"
36224
+ ),
36225
+ title: displayName,
36226
+ children: displayName
36227
+ }
36228
+ )
36088
36229
  ] }),
36089
- !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", children: sender.channelSender.channelSenderMetadata.from })
36230
+ !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 })
36090
36231
  ]
36091
36232
  },
36092
36233
  sender.channelSender.id
@@ -37040,13 +37181,25 @@ const useAutomationSelection = () => {
37040
37181
  });
37041
37182
  });
37042
37183
  }, [updateAutomationStatesMutation]);
37184
+ const enabledCount = useMemo(() => {
37185
+ return Object.values(selectedAutomations).filter(Boolean).length;
37186
+ }, [selectedAutomations]);
37187
+ const allAutomationsEnabled = useMemo(() => {
37188
+ if (automations.length === 0) return false;
37189
+ return automations.every(
37190
+ (automation2) => selectedAutomations[automation2.id] === true
37191
+ );
37192
+ }, [automations, selectedAutomations]);
37043
37193
  return {
37044
37194
  selectedAutomations,
37045
37195
  handleToggle,
37046
37196
  handleToggleAll,
37047
37197
  saveAutomationStates,
37048
37198
  isSaving: updateAutomationStatesMutation.isPending,
37049
- isLoading
37199
+ isLoading,
37200
+ enabledCount,
37201
+ allAutomationsEnabled,
37202
+ automations
37050
37203
  };
37051
37204
  };
37052
37205
  function composeEventHandlers$3(originalEventHandler, ourEventHandler, { checkForDefaultPrevented = true } = {}) {
@@ -37490,109 +37643,158 @@ const OnboardingAutomationList = ({
37490
37643
  /* @__PURE__ */ jsx("div", { className: "text-sm text-muted-foreground", children: "No automations available yet" })
37491
37644
  ] }) });
37492
37645
  }
37493
- return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
37494
- /* @__PURE__ */ jsx("div", { className: "space-y-3 max-h-[60vh] overflow-y-auto", children: automations?.map((automation2) => {
37495
- const description2 = automation2.description;
37496
- const isEnabled = selectedAutomations[automation2.id] ?? true;
37497
- return /* @__PURE__ */ jsxs(
37498
- "div",
37499
- {
37500
- className: "flex items-start gap-3 p-2 border border-border rounded-lg bg-background hover:bg-muted/30 transition-colors",
37501
- children: [
37502
- /* @__PURE__ */ jsx("div", { className: "flex-1 min-w-0", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 mb-1", children: [
37503
- /* @__PURE__ */ jsx("div", { className: "w-1.5 h-1.5 rounded-full bg-primary flex-shrink-0 mt-1.5" }),
37504
- /* @__PURE__ */ jsxs("div", { className: "flex-1", children: [
37505
- /* @__PURE__ */ jsx("h4", { className: "font-medium text-sm text-foreground", children: automation2.name }),
37506
- description2 && typeof description2 === "string" && /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground mt-0.5 leading-relaxed", children: description2 })
37507
- ] })
37508
- ] }) }),
37509
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 flex-shrink-0", children: [
37510
- /* @__PURE__ */ jsx(
37511
- Label$1,
37512
- {
37513
- htmlFor: `automation-${automation2.id}`,
37514
- className: "text-xs font-medium cursor-pointer",
37515
- children: isEnabled ? "On" : "Off"
37516
- }
37517
- ),
37518
- /* @__PURE__ */ jsx(
37519
- Switch,
37520
- {
37521
- id: `automation-${automation2.id}`,
37522
- checked: isEnabled,
37523
- onCheckedChange: (checked) => onToggle(automation2.id, checked),
37524
- className: "data-[state=checked]:bg-primary"
37525
- }
37526
- )
37527
- ] })
37528
- ]
37529
- },
37530
- automation2.id
37531
- );
37532
- }) }),
37533
- /* @__PURE__ */ jsx("div", { className: "text-center pt-4 border-t border-border", children: /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: "💡 You can change these settings anytime from your automations page" }) })
37534
- ] });
37646
+ return /* @__PURE__ */ jsx("div", { className: "space-y-3 overflow-y-auto flex-1 min-h-0 p-3", children: automations?.map((automation2) => {
37647
+ const description2 = automation2.description;
37648
+ const isEnabled = selectedAutomations[automation2.id] ?? true;
37649
+ return /* @__PURE__ */ jsxs(
37650
+ "div",
37651
+ {
37652
+ className: "flex items-center gap-3 px-3 py-2 border border-border rounded-lg bg-background hover:bg-muted/30 transition-colors",
37653
+ children: [
37654
+ /* @__PURE__ */ jsx("div", { className: "flex-1 min-w-0", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
37655
+ /* @__PURE__ */ jsx("h4", { className: "font-medium text-sm text-foreground", children: automation2.name }),
37656
+ description2 && typeof description2 === "string" && /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground mt-0.5 leading-relaxed", children: description2 })
37657
+ ] }) }),
37658
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 flex-shrink-0", children: [
37659
+ /* @__PURE__ */ jsx(
37660
+ Label$1,
37661
+ {
37662
+ htmlFor: `automation-${automation2.id}`,
37663
+ className: "text-xs font-medium cursor-pointer",
37664
+ children: isEnabled ? "On" : "Off"
37665
+ }
37666
+ ),
37667
+ /* @__PURE__ */ jsx(
37668
+ Switch,
37669
+ {
37670
+ id: `automation-${automation2.id}`,
37671
+ checked: isEnabled,
37672
+ onCheckedChange: (checked) => onToggle(automation2.id, checked)
37673
+ }
37674
+ )
37675
+ ] })
37676
+ ]
37677
+ },
37678
+ automation2.id
37679
+ );
37680
+ }) });
37535
37681
  };
37536
37682
  const CompletionStep = () => {
37537
37683
  const { handleClose, state } = useEngageOnboardingContext();
37538
- const { data: smsApplication } = useGetLatestSmsRegistrationApplication();
37539
37684
  const { toggleEngageOnboarding } = useBusiness$1();
37540
37685
  const {
37541
37686
  selectedAutomations,
37542
37687
  handleToggle,
37543
37688
  saveAutomationStates,
37544
37689
  isSaving,
37545
- isLoading: isLoadingAutomations
37690
+ isLoading: isLoadingAutomations,
37691
+ enabledCount,
37692
+ automations
37546
37693
  } = useAutomationSelection();
37694
+ const { data: smsApplication } = useGetLatestSmsRegistrationApplication();
37547
37695
  const hasSMSSteps = state.steps.includes(ENGAGE_STEPS.SMS) || state.steps.includes(ENGAGE_STEPS.SMS_INTERSTITIAL);
37696
+ const hasAutomations = !isLoadingAutomations && automations.length > 0;
37548
37697
  const handleSkip = () => {
37549
37698
  toggleEngageOnboarding(false);
37550
37699
  handleClose?.();
37551
37700
  };
37552
37701
  const handleCompletion = async () => {
37553
- const success2 = await saveAutomationStates();
37554
- if (success2) {
37555
- toggleEngageOnboarding(false);
37556
- handleClose?.();
37702
+ if (hasAutomations) {
37703
+ const success2 = await saveAutomationStates();
37704
+ if (!success2) {
37705
+ return;
37706
+ }
37557
37707
  }
37708
+ toggleEngageOnboarding(false);
37709
+ handleClose?.();
37558
37710
  };
37559
- return /* @__PURE__ */ jsxs("div", { className: "h-full flex flex-col", children: [
37560
- /* @__PURE__ */ jsx("div", { className: "flex-1 overflow-y-auto p-6", children: /* @__PURE__ */ jsxs("div", { className: "max-w-4xl mx-auto space-y-4", children: [
37561
- /* @__PURE__ */ jsxs("div", { className: "pb-4 border-b border-border", children: [
37562
- /* @__PURE__ */ jsx("h1", { className: "text-lg font-semibold text-foreground mb-1", children: "You're All Set! 🎉" }),
37563
- /* @__PURE__ */ jsxs("p", { className: "text-sm text-muted-foreground", children: [
37564
- "Choose which ",
37565
- t$2("engage:automation", { count: 2 }).toLowerCase(),
37566
- " ",
37567
- "to enable"
37568
- ] })
37711
+ if (isLoadingAutomations) {
37712
+ return /* @__PURE__ */ jsx("div", { className: "h-full flex items-center justify-center", children: /* @__PURE__ */ jsxs("div", { className: "text-center", children: [
37713
+ /* @__PURE__ */ jsx("div", { className: "animate-spin rounded-full h-8 w-8 border-b-2 border-primary mx-auto mb-4" }),
37714
+ /* @__PURE__ */ jsxs("div", { className: "text-sm text-muted-foreground", children: [
37715
+ "Loading your ",
37716
+ t$2("engage:automation", { count: 2 }).toLowerCase(),
37717
+ "..."
37718
+ ] })
37719
+ ] }) });
37720
+ }
37721
+ if (!hasAutomations) {
37722
+ return /* @__PURE__ */ jsxs("div", { className: "h-full flex flex-col overflow-hidden", children: [
37723
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 flex flex-col min-h-0 overflow-hidden", children: [
37724
+ /* @__PURE__ */ jsx("div", { className: "flex-shrink-0 p-6 pb-4", children: /* @__PURE__ */ jsx("div", { className: "max-w-4xl mx-auto space-y-4", children: /* @__PURE__ */ jsxs("div", { className: "pb-4 border-b border-border", children: [
37725
+ /* @__PURE__ */ jsx("h1", { className: "text-lg font-semibold text-foreground mb-1", children: "You're All Set! 🎉" }),
37726
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: "Your Engage setup is complete. You can now start creating broadcasts and automations from your dashboard." })
37727
+ ] }) }) }),
37728
+ /* @__PURE__ */ jsx("div", { className: "flex-1 flex items-center justify-center p-6", children: /* @__PURE__ */ jsxs("div", { className: "max-w-2xl mx-auto text-center", children: [
37729
+ /* @__PURE__ */ jsx("p", { className: "text-2xl font-semibold text-foreground mb-2", children: "Head to your dashboard to start creating broadcasts" }),
37730
+ /* @__PURE__ */ jsx("p", { className: "text-base text-muted-foreground", children: "You're ready to engage with your audience through email and SMS campaigns." })
37731
+ ] }) })
37569
37732
  ] }),
37570
- hasSMSSteps && (!smsApplication?.application || smsApplication.status === SmsRegistrationApplicationStatus.PENDING) && /* @__PURE__ */ jsx("div", { className: "bg-blue-50 border border-blue-200 rounded-lg p-3", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
37571
- /* @__PURE__ */ jsx(
37572
- InfoTooltip,
37573
- {
37574
- title: "You can set up SMS later from the settings menu.",
37575
- size: "small"
37576
- }
37577
- ),
37578
- /* @__PURE__ */ jsx("p", { className: "text-blue-700 text-sm", children: "You can set up SMS later from the settings menu." })
37733
+ /* @__PURE__ */ jsx("div", { className: "border-t border-border py-4 px-6 flex items-center justify-end bg-background gap-4", children: /* @__PURE__ */ jsx(
37734
+ Button$1,
37735
+ {
37736
+ onClick: handleCompletion,
37737
+ className: "flex items-center gap-2 text-sm",
37738
+ children: "Go to dashboard"
37739
+ }
37740
+ ) })
37741
+ ] });
37742
+ }
37743
+ return /* @__PURE__ */ jsxs("div", { className: "h-full flex flex-col overflow-hidden", children: [
37744
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 flex flex-col min-h-0 overflow-hidden", children: [
37745
+ /* @__PURE__ */ jsx("div", { className: "flex-shrink-0 p-6 pb-4", children: /* @__PURE__ */ jsxs("div", { className: "max-w-4xl mx-auto space-y-4", children: [
37746
+ /* @__PURE__ */ jsxs("div", { className: "pb-4 border-b border-border", children: [
37747
+ /* @__PURE__ */ jsx("h1", { className: "text-lg font-semibold text-foreground mb-1", children: "You're All Set! 🎉" }),
37748
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: "These automations will start running automatically. Toggle off any you don't want right now." })
37749
+ ] }),
37750
+ /* @__PURE__ */ jsx("div", { className: "bg-blue-50 border border-blue-200 rounded-lg p-3", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
37751
+ /* @__PURE__ */ jsx(
37752
+ InfoTooltip,
37753
+ {
37754
+ title: "All automations below are ON by default. You can always change these settings later from your automations page.",
37755
+ size: "small"
37756
+ }
37757
+ ),
37758
+ /* @__PURE__ */ jsxs("p", { className: "text-blue-700 text-sm", children: [
37759
+ /* @__PURE__ */ jsx("span", { className: "font-semibold", children: "All automations below are ON by default." }),
37760
+ " ",
37761
+ "You can always change these settings later from your",
37762
+ " ",
37763
+ /* @__PURE__ */ jsx("span", { className: "font-semibold", children: "automations page" }),
37764
+ "."
37765
+ ] })
37766
+ ] }) }),
37767
+ hasSMSSteps && (!smsApplication?.application || smsApplication.status === SmsRegistrationApplicationStatus.PENDING || smsApplication.status === SmsRegistrationApplicationStatus.IN_REVIEW) && /* @__PURE__ */ jsx("div", { className: "bg-blue-50 border border-blue-200 rounded-lg p-3", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
37768
+ /* @__PURE__ */ jsx(
37769
+ InfoTooltip,
37770
+ {
37771
+ title: "You can set up SMS later from the settings menu.",
37772
+ size: "small"
37773
+ }
37774
+ ),
37775
+ /* @__PURE__ */ jsx("p", { className: "text-blue-700 text-sm", children: "You can set up SMS later from the settings menu." })
37776
+ ] }) })
37579
37777
  ] }) }),
37580
- /* @__PURE__ */ jsx("div", { className: "bg-background border border-border rounded-xl p-3 shadow-sm", children: !isLoadingAutomations ? /* @__PURE__ */ jsx(
37778
+ /* @__PURE__ */ jsx("div", { className: "flex-1 flex flex-col min-h-0 pb-4 px-6", children: /* @__PURE__ */ jsx("div", { className: "max-w-4xl mx-auto w-full flex-1 flex flex-col min-h-0", children: /* @__PURE__ */ jsx("div", { className: "bg-background border border-border rounded-xl shadow-sm flex-1 flex flex-col min-h-0", children: /* @__PURE__ */ jsx(
37581
37779
  OnboardingAutomationList,
37582
37780
  {
37583
37781
  selectedAutomations,
37584
37782
  onToggle: handleToggle
37585
37783
  }
37586
- ) : /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center py-12", children: /* @__PURE__ */ jsxs("div", { className: "text-center", children: [
37587
- /* @__PURE__ */ jsx("div", { className: "animate-spin rounded-full h-8 w-8 border-b-2 border-primary mx-auto mb-4" }),
37588
- /* @__PURE__ */ jsxs("div", { className: "text-sm text-muted-foreground", children: [
37589
- "Loading your",
37590
- " ",
37591
- t$2("engage:automation", { count: 2 }).toLowerCase(),
37592
- "..."
37593
- ] })
37594
- ] }) }) })
37595
- ] }) }),
37784
+ ) }) }) })
37785
+ ] }),
37786
+ enabledCount > 0 && /* @__PURE__ */ jsx("div", { className: "px-6 pb-4", children: /* @__PURE__ */ jsx("div", { className: "max-w-4xl mx-auto", children: /* @__PURE__ */ jsx("div", { className: "bg-teal-50 border border-teal-200 rounded-lg p-3", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-center gap-2", children: [
37787
+ /* @__PURE__ */ jsx(Check, { className: "w-4 h-4 text-teal-600" }),
37788
+ /* @__PURE__ */ jsxs("p", { className: "text-sm text-teal-900 font-medium", children: [
37789
+ enabledCount,
37790
+ " ",
37791
+ t$2("engage:automation", {
37792
+ count: enabledCount
37793
+ }).toLowerCase(),
37794
+ " ",
37795
+ "will be activated when you continue"
37796
+ ] })
37797
+ ] }) }) }) }),
37596
37798
  /* @__PURE__ */ jsxs("div", { className: "border-t border-border py-4 px-6 flex items-center justify-end bg-background gap-4", children: [
37597
37799
  /* @__PURE__ */ jsx(
37598
37800
  Button$1,
@@ -37892,12 +38094,14 @@ const EngageOnboarding = () => {
37892
38094
  const hasSMSSteps = state.steps.includes(ENGAGE_STEPS.SMS) || state.steps.includes(ENGAGE_STEPS.SMS_INTERSTITIAL);
37893
38095
  const sidebarSteps = useMemo(() => {
37894
38096
  const stepsToUse = hasSMSSteps ? ONBOARDING_STEP_CONFIGS : filteredSidebarItems;
37895
- return stepsToUse.map((step) => ({
38097
+ return stepsToUse.filter(
38098
+ (step) => state.steps.includes(step.key)
38099
+ ).map((step) => ({
37896
38100
  key: step.key,
37897
38101
  label: step.label,
37898
38102
  isValid: () => state.completedSteps.includes(step.key)
37899
38103
  }));
37900
- }, [hasSMSSteps, filteredSidebarItems, state.completedSteps]);
38104
+ }, [hasSMSSteps, filteredSidebarItems, state.completedSteps, state.steps]);
37901
38105
  const shouldRenderStep = hasSMSSteps || currentStep !== ENGAGE_STEPS.SMS && currentStep !== ENGAGE_STEPS.SMS_INTERSTITIAL;
37902
38106
  return /* @__PURE__ */ jsx(Dialog, { open: state.open, onOpenChange: handleOpenChange, modal: true, children: /* @__PURE__ */ jsxs(
37903
38107
  DialogContent,
@@ -37943,6 +38147,13 @@ const EngageOnboardingProvider = ({
37943
38147
  onClose,
37944
38148
  hideSMS = false
37945
38149
  }) => {
38150
+ const { automations, isLoading: isLoadingAutomations } = useListBusinessAutomations({
38151
+ triggerTypes: [
38152
+ AutomationTriggerType.TRIGGER_BASED,
38153
+ AutomationTriggerType.DATE_BASED
38154
+ ],
38155
+ limit: 50
38156
+ });
37946
38157
  const filteredSteps = hideSMS ? initialState$3.steps.filter(
37947
38158
  (step) => step !== ENGAGE_STEPS.SMS && step !== ENGAGE_STEPS.SMS_INTERSTITIAL
37948
38159
  ) : initialState$3.steps;
@@ -37951,14 +38162,12 @@ const EngageOnboardingProvider = ({
37951
38162
  open,
37952
38163
  steps: filteredSteps
37953
38164
  });
37954
- React__default.useEffect(() => {
37955
- setOpen(dispatch2)(open);
37956
- }, [open]);
37957
38165
  const actions = useMemo(
37958
38166
  () => ({
37959
38167
  setOpen: setOpen(dispatch2),
37960
38168
  setCurrentStep: setCurrentStep(dispatch2),
37961
38169
  setSkipSMS: setSkipSMS(dispatch2),
38170
+ setSkipCompletion: setSkipCompletion(dispatch2),
37962
38171
  markStepComplete: markStepComplete(dispatch2),
37963
38172
  updateFormData: updateFormData(dispatch2),
37964
38173
  resetState: resetState(dispatch2),
@@ -37966,8 +38175,17 @@ const EngageOnboardingProvider = ({
37966
38175
  goToPreviousStep: goToPreviousStep(dispatch2),
37967
38176
  goToStep: goToStep(dispatch2)
37968
38177
  }),
37969
- [dispatch2]
38178
+ // eslint-disable-next-line react-hooks/exhaustive-deps
38179
+ []
37970
38180
  );
38181
+ React__default.useEffect(() => {
38182
+ actions.setOpen(open);
38183
+ }, [open, actions]);
38184
+ useEffect(() => {
38185
+ if (!isLoadingAutomations && automations.length === 0) {
38186
+ actions.setSkipCompletion(true);
38187
+ }
38188
+ }, [isLoadingAutomations, automations.length, actions]);
37971
38189
  const { isFirstStep, isLastStep, canGoNext, canGoPrevious } = state;
37972
38190
  const isStepComplete = useCallback(
37973
38191
  (step) => state.completedSteps.includes(step),
@@ -65628,13 +65846,13 @@ const measure$1 = {
65628
65846
  title_transaction: "Revenue by Source (Transaction Attributed)",
65629
65847
  total_revenue: "Total Revenue",
65630
65848
  click: "Click",
65631
- click_attributed: "Click Date Attributed",
65632
- click_attributed_description: "Counts transactions tracked to clicks made within the selected date range.",
65633
- click_attributed_why_it_matters: "Why it matters: Use this to understand which marketing touchpoints are driving conversions. Transactions are counted based on when the customer's first tracked interaction occurred (ad click, search, site visit), not when they completed their purchase. This helps you see the impact of your marketing efforts at the moment of customer engagement, even if the purchase happens days or weeks later.",
65849
+ click_attributed: "Click Date",
65850
+ click_attributed_description: "Shows ONLY transactions with an associated marketing click/call within the selected date range.",
65851
+ click_attributed_why_it_matters: "Why it matters: \nUse this to understand which marketing touchpoints are driving conversions from when the marketing event occured. Transactions are shown based on when the customer's marketing interaction (ad click, call, google search etc) was tracked, not when they completed their transaction. This helps you see the impact of your marketing efforts at the moment of customer engagement, even if the transaction happens days or weeks later. \n\nExample: \nA customer clicks your ad on Oct 15 but completes their transaction on Nov 3. With Oct 1-31 selected, this transaction appears in your data. With Nov 1-30 selected, it doesn't.",
65634
65852
  transaction: "Transaction",
65635
- transaction_attributed: "Transaction Date Attributed",
65636
- transaction_attributed_description: "Counts transactions created in the selected date range.",
65637
- transaction_attributed_why_it_matters: "Why it matters: Use this to understand actual sales performance during a specific period. Transactions are counted based on when the transaction was completed (transaction date), regardless of when or how the customer first discovered your business. This helps you see all revenue that occurred during the selected timeframe, providing a clear view of business performance by date."
65853
+ transaction_attributed: "Transaction Date",
65854
+ transaction_attributed_description: "Shows all transactions created in the selected date range.",
65855
+ 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."
65638
65856
  }
65639
65857
  }
65640
65858
  }
@@ -66483,13 +66701,13 @@ const measure = {
66483
66701
  title_transaction: "Ingresos por Fuente (Atribución por Transacción)",
66484
66702
  total_revenue: "Ingresos Totales",
66485
66703
  click: "Clic",
66486
- click_attributed: "Fecha de Atribución por Clic",
66487
- click_attributed_description: "Cuenta transacciones rastreadas a clics realizados dentro del rango de fechas seleccionado.",
66488
- click_attributed_why_it_matters: "Why it matters: Use this to understand which marketing touchpoints are driving conversions. Transactions are counted based on when the customer's first tracked interaction occurred (ad click, search, site visit), not when they completed their purchase. This helps you see the impact of your marketing efforts at the moment of customer engagement, even if the purchase happens days or weeks later.",
66704
+ click_attributed: "Fecha de Clic",
66705
+ click_attributed_description: "Muestra SOLO transacciones con un clic/llamada de marketing asociado dentro del rango de fechas seleccionado.",
66706
+ click_attributed_why_it_matters: "Por qué es importante: \nUsa esto para entender qué puntos de contacto de marketing están impulsando conversiones desde cuando ocurrió el evento de marketing. Las transacciones se muestran según cuándo se rastreó la interacción de marketing del cliente (clic en anuncio, llamada, búsqueda en Google, etc.), no cuando completaron su transacción. Esto te ayuda a ver el impacto de tus esfuerzos de marketing en el momento del compromiso del cliente, incluso si la transacción ocurre días o semanas después. \n\nEjemplo: \nUn cliente hace clic en tu anuncio el 15 de octubre pero completa su transacción el 3 de noviembre. Con el 1-31 de octubre seleccionado, esta transacción aparece en tus datos. Con el 1-30 de noviembre seleccionado, no aparece.",
66489
66707
  transaction: "Transacción",
66490
- transaction_attributed: "Fecha de Atribución por Transacción",
66491
- transaction_attributed_description: "Cuenta transacciones creadas en el rango de fechas seleccionado.",
66492
- transaction_attributed_why_it_matters: "Why it matters: Use this to understand actual sales performance during a specific period. Transactions are counted based on when the transaction was completed (transaction date), regardless of when or how the customer first discovered your business. This helps you see all revenue that occurred during the selected timeframe, providing a clear view of business performance by date."
66708
+ transaction_attributed: "Fecha de Transacción",
66709
+ transaction_attributed_description: "Muestra todas las transacciones creadas en el rango de fechas seleccionado.",
66710
+ transaction_attributed_why_it_matters: "Por qué es importante: \nUsa esto para entender el rendimiento real de ventas durante un período específico y de dónde provinieron. Las transacciones se muestran según cuándo se creó la transacción, independientemente de cuándo o cómo el cliente descubrió por primera vez tu negocio. Esto te ayuda a ver todos los ingresos que ocurrieron durante el período de tiempo seleccionado, y con qué esfuerzos de marketing digital están asociados. \n\nEjemplo: \nUn cliente hace clic en tu anuncio el 15 de octubre pero completa su transacción el 3 de noviembre. Con el 1-30 de noviembre seleccionado, esta transacción aparece en tus datos. Con el 1-31 de octubre seleccionado, no aparece."
66493
66711
  }
66494
66712
  }
66495
66713
  }
@@ -67426,13 +67644,13 @@ const defaultTranslations = {
67426
67644
  title_transaction: "Revenue by Source (Transaction Attributed)",
67427
67645
  total_revenue: "Total Revenue",
67428
67646
  click: "Click",
67429
- click_attributed: "Click Date Attributed",
67430
- click_attributed_description: "Counts transactions tracked to clicks made within the selected date range.",
67431
- click_attributed_why_it_matters: "Why it matters: Use this to understand which marketing touchpoints are driving conversions. Transactions are counted based on when the customer's first tracked interaction occurred (ad click, search, site visit), not when they completed their purchase. This helps you see the impact of your marketing efforts at the moment of customer engagement, even if the purchase happens days or weeks later.",
67647
+ click_attributed: "Click Date",
67648
+ click_attributed_description: "Shows ONLY transactions with an associated marketing click/call within the selected date range.",
67649
+ click_attributed_why_it_matters: "Why it matters: \nUse this to understand which marketing touchpoints are driving conversions from when the marketing event occured. Transactions are shown based on when the customer's marketing interaction (ad click, call, google search etc) was tracked, not when they completed their transaction. This helps you see the impact of your marketing efforts at the moment of customer engagement, even if the transaction happens days or weeks later. \n\nExample: \nA customer clicks your ad on Oct 15 but completes their transaction on Nov 3. With Oct 1-31 selected, this transaction appears in your data. With Nov 1-30 selected, it doesn't.",
67432
67650
  transaction: "Transaction",
67433
- transaction_attributed: "Transaction Date Attributed",
67434
- transaction_attributed_description: "Counts transactions created in the selected date range.",
67435
- transaction_attributed_why_it_matters: "Why it matters: Use this to understand actual sales performance during a specific period. Transactions are counted based on when the transaction was completed (transaction date), regardless of when or how the customer first discovered your business. This helps you see all revenue that occurred during the selected timeframe, providing a clear view of business performance by date."
67651
+ transaction_attributed: "Transaction Date",
67652
+ transaction_attributed_description: "Shows all transactions created in the selected date range.",
67653
+ 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."
67436
67654
  }
67437
67655
  }
67438
67656
  }
@@ -69259,26 +69477,21 @@ const parseDate = async (params) => {
69259
69477
  return response.data;
69260
69478
  };
69261
69479
  const previewSegmentRecipients = async (params) => {
69262
- let finalResult = [];
69263
- let cursor = void 0;
69264
- do {
69265
- const paramsWithCursor = {
69266
- ...params,
69267
- cursor
69268
- };
69269
- const iterationResult = await baseRequest(
69270
- `${BUSINESS_AUTOMATION_INTERNAL_PATH}/preview-segment-recipients`,
69271
- {
69272
- method: "POST",
69273
- body: JSON.stringify(paramsWithCursor)
69274
- }
69275
- );
69276
- finalResult = finalResult.concat(iterationResult.data.recipients);
69277
- cursor = iterationResult.data.pagination.cursor;
69278
- } while (cursor !== void 0);
69480
+ const paramsWithLimit = {
69481
+ ...params,
69482
+ limit: params.limit ?? 100
69483
+ };
69484
+ const result = await baseRequest(
69485
+ `${BUSINESS_AUTOMATION_INTERNAL_PATH}/preview-segment-recipients`,
69486
+ {
69487
+ method: "POST",
69488
+ body: JSON.stringify(paramsWithLimit)
69489
+ }
69490
+ );
69279
69491
  return {
69280
- recipients: finalResult,
69281
- estimatedTotal: finalResult.length
69492
+ recipients: result.data.recipients,
69493
+ estimatedTotal: result.data.estimatedTotal,
69494
+ pagination: result.data.pagination
69282
69495
  };
69283
69496
  };
69284
69497
  var JSONSchemaType = /* @__PURE__ */ ((JSONSchemaType2) => {
@@ -69340,6 +69553,7 @@ const useSegment = () => {
69340
69553
  return {
69341
69554
  // Create segment mutation
69342
69555
  createSegment: createMutation.mutate,
69556
+ createSegmentAsync: createMutation.mutateAsync,
69343
69557
  isCreating: createMutation.isPending,
69344
69558
  createError: createMutation.error,
69345
69559
  isCreateSuccess: createMutation.isSuccess,
@@ -69409,6 +69623,55 @@ const useGetCountOfBusinessAutomationRecipients = (args) => {
69409
69623
  }
69410
69624
  };
69411
69625
  };
69626
+ const useGetCountOfBusinessAutomationRecipientsDebounced = (includeSegments, excludeSegments, automationId, options) => {
69627
+ const [debouncedIncludeSegments, setDebouncedIncludeSegments] = useState(includeSegments);
69628
+ const [debouncedExcludeSegments, setDebouncedExcludeSegments] = useState(excludeSegments);
69629
+ const [debouncedSearch, setDebouncedSearch] = useState(options?.search || "");
69630
+ useEffect(() => {
69631
+ const timer = setTimeout(() => {
69632
+ setDebouncedIncludeSegments(includeSegments);
69633
+ setDebouncedExcludeSegments(excludeSegments);
69634
+ }, options?.debounceMs);
69635
+ return () => clearTimeout(timer);
69636
+ }, [includeSegments, excludeSegments, options?.debounceMs]);
69637
+ useEffect(() => {
69638
+ const timer = setTimeout(() => {
69639
+ setDebouncedSearch(options?.search || "");
69640
+ }, 150);
69641
+ return () => clearTimeout(timer);
69642
+ }, [options?.search]);
69643
+ const filter2 = options?.filter ?? "all";
69644
+ const query = useQuery({
69645
+ queryKey: [
69646
+ ...automationKeys.recipients(
69647
+ automationId,
69648
+ debouncedIncludeSegments,
69649
+ debouncedExcludeSegments,
69650
+ debouncedSearch
69651
+ ),
69652
+ filter2,
69653
+ options?.limit ?? 100
69654
+ ],
69655
+ queryFn: () => getCountOfBusinessAutomationRecipients({
69656
+ includeSegments: debouncedIncludeSegments,
69657
+ excludeSegments: debouncedExcludeSegments,
69658
+ automationId,
69659
+ search: debouncedSearch || void 0,
69660
+ limit: options?.limit ?? 100,
69661
+ filter: filter2
69662
+ }),
69663
+ enabled: (options?.enabled ?? true) && !!automationId,
69664
+ staleTime: 0
69665
+ // Always refetch when query key changes (including filter changes)
69666
+ });
69667
+ return {
69668
+ data: query.data,
69669
+ isLoading: query.isLoading,
69670
+ isFetching: query.isFetching,
69671
+ error: query.error,
69672
+ refetch: query.refetch
69673
+ };
69674
+ };
69412
69675
  const useGetSegment = (segmentId) => {
69413
69676
  const segmentQuery = useQuery({
69414
69677
  queryKey: segmentKeys.detail(segmentId),
@@ -69437,6 +69700,27 @@ const useUpdateSegment = (segmentId) => {
69437
69700
  });
69438
69701
  return {
69439
69702
  updateSegment: updateSegmentMutation.mutate,
69703
+ updateSegmentAsync: updateSegmentMutation.mutateAsync,
69704
+ isUpdating: updateSegmentMutation.isPending,
69705
+ updateError: updateSegmentMutation.error,
69706
+ isUpdateSuccess: updateSegmentMutation.isSuccess
69707
+ };
69708
+ };
69709
+ const useUpdateSegmentDynamic = () => {
69710
+ const queryClient = useQueryClient();
69711
+ const updateSegmentMutation = useMutation({
69712
+ mutationFn: ({
69713
+ segmentId,
69714
+ params
69715
+ }) => {
69716
+ return updateSegment(segmentId, params);
69717
+ },
69718
+ onSuccess: () => {
69719
+ queryClient.invalidateQueries({ queryKey: segmentKeys.all });
69720
+ }
69721
+ });
69722
+ return {
69723
+ updateSegmentAsync: updateSegmentMutation.mutateAsync,
69440
69724
  isUpdating: updateSegmentMutation.isPending,
69441
69725
  updateError: updateSegmentMutation.error,
69442
69726
  isUpdateSuccess: updateSegmentMutation.isSuccess
@@ -69476,12 +69760,19 @@ const useParseDate = () => {
69476
69760
  };
69477
69761
  const usePreviewSegmentRecipients = (type, conditions, businessId, options, existingSegmentConditions) => {
69478
69762
  const [debouncedConditions, setDebouncedConditions] = useState(conditions);
69763
+ const [debouncedSearch, setDebouncedSearch] = useState(options?.search || "");
69479
69764
  useEffect(() => {
69480
69765
  const timer = setTimeout(() => {
69481
69766
  setDebouncedConditions(conditions);
69482
69767
  }, options?.debounceMs);
69483
69768
  return () => clearTimeout(timer);
69484
69769
  }, [conditions, options?.debounceMs]);
69770
+ useEffect(() => {
69771
+ const timer = setTimeout(() => {
69772
+ setDebouncedSearch(options?.search || "");
69773
+ }, 600);
69774
+ return () => clearTimeout(timer);
69775
+ }, [options?.search]);
69485
69776
  const areConditionsValid = (conditions2, type2) => {
69486
69777
  if (type2 === BusinessSegmentTypeEnum.SQL) {
69487
69778
  return true;
@@ -69500,24 +69791,38 @@ const usePreviewSegmentRecipients = (type, conditions, businessId, options, exis
69500
69791
  });
69501
69792
  return isValid2;
69502
69793
  };
69794
+ const conditionsKey = JSON.stringify(debouncedConditions);
69795
+ const existingConditionsKey = JSON.stringify(existingSegmentConditions || []);
69503
69796
  const query = useQuery({
69504
69797
  queryKey: [
69505
69798
  "preview-segment-recipients",
69506
69799
  businessId,
69507
- debouncedConditions,
69508
- JSON.stringify(existingSegmentConditions || {})
69800
+ type,
69801
+ conditionsKey,
69802
+ existingConditionsKey,
69803
+ debouncedSearch || "",
69804
+ options?.limit ?? 100
69509
69805
  ],
69510
69806
  queryFn: () => {
69511
69807
  return previewSegmentRecipients({
69512
69808
  businessId,
69513
69809
  // If the segment is a SQL segment, use the existing segment conditions
69514
69810
  conditions: type === BusinessSegmentTypeEnum.SQL && existingSegmentConditions ? existingSegmentConditions : debouncedConditions,
69515
- limit: 1e3
69811
+ limit: options?.limit ?? 100,
69812
+ search: debouncedSearch || void 0
69516
69813
  });
69517
69814
  },
69518
69815
  enabled: (options?.enabled ?? true) && areConditionsValid(debouncedConditions, type),
69519
- staleTime: 3e4
69816
+ staleTime: 3e4,
69520
69817
  // 30 seconds
69818
+ gcTime: 5 * 60 * 1e3,
69819
+ // 5 minutes - keep in cache longer
69820
+ placeholderData: keepPreviousData,
69821
+ // Keep previous data while fetching to prevent re-renders
69822
+ refetchOnWindowFocus: false,
69823
+ // Don't refetch on window focus
69824
+ refetchOnMount: false
69825
+ // Don't refetch on mount if data exists
69521
69826
  });
69522
69827
  return {
69523
69828
  data: query.data,
@@ -69766,21 +70071,23 @@ const BigSelector = ({
69766
70071
  selected,
69767
70072
  disabled = false,
69768
70073
  hideSelectedText = false,
69769
- className = ""
70074
+ className = "",
70075
+ id: id2
69770
70076
  }) => {
69771
70077
  return /* @__PURE__ */ jsxs(
69772
70078
  "button",
69773
70079
  {
70080
+ id: id2,
69774
70081
  onClick,
69775
70082
  className: cn$2(
69776
70083
  className,
69777
- `relative flex flex-col items-center justify-center rounded-lg border-2 p-6 transition-all duration-300 ease-in-out hover:shadow-lg ${selected ? "[border-color:hsl(var(--reach-primary))] shadow-lg" : "border-gray-200 "} ${disabled ? "opacity-50 cursor-not-allowed hover:shadow-none" : "hover:scale-[1.04] scale-[1.02]"} ${!selected && !disabled && "hover:[border-color:hsl(var(--reach-primary))] hover:bg-gray-50"}`
70084
+ `relative flex flex-col items-center justify-center rounded-lg border-2 p-3 sm:p-4 md:p-6 transition-all duration-300 ease-in-out hover:shadow-lg min-w-0 ${selected ? "[border-color:hsl(var(--reach-primary))] shadow-lg" : "border-gray-200 "} ${disabled ? "opacity-50 cursor-not-allowed hover:shadow-none" : "hover:scale-[1.04] scale-[1.02]"} ${!selected && !disabled && "hover:[border-color:hsl(var(--reach-primary))] hover:bg-gray-50"}`
69778
70085
  ),
69779
70086
  children: [
69780
70087
  icon,
69781
- /* @__PURE__ */ jsxs("div", { className: "text-center mt-3 w-full", children: [
69782
- /* @__PURE__ */ jsx("div", { className: "text-sm font-medium text-primary", children: title2 }),
69783
- /* @__PURE__ */ jsx("div", { className: "text-xs text-muted-foreground mt-1 line-clamp-3", children: subtitle })
70088
+ /* @__PURE__ */ jsxs("div", { className: "text-center mt-2 md:mt-3 w-full min-w-0 px-0.5 md:px-1", children: [
70089
+ /* @__PURE__ */ jsx("div", { className: "text-xs sm:text-sm font-medium text-primary break-words line-clamp-2", children: title2 }),
70090
+ /* @__PURE__ */ jsx("div", { className: "text-[10px] sm:text-xs text-muted-foreground mt-0.5 md:mt-1 line-clamp-2 break-words", children: subtitle })
69784
70091
  ] }),
69785
70092
  selected && /* @__PURE__ */ jsxs("div", { className: "absolute top-1 right-1 bg-card rounded-full px-3 py-1 flex items-center gap-1", children: [
69786
70093
  /* @__PURE__ */ jsx(Check, { className: "w-4 h-4 text-card-foreground" }),
@@ -75512,7 +75819,7 @@ function createTextColumn({
75512
75819
  header: () => /* @__PURE__ */ jsx(
75513
75820
  "div",
75514
75821
  {
75515
- className: `flex items-center h-8 px-3 font-medium whitespace-nowrap text-muted-foreground ${meta?.align === "right" ? "justify-end float-right" : meta?.align === "center" ? "justify-center" : "justify-start"} ${headerClassName || ""}`.trim(),
75822
+ className: `flex items-center h-8 px-2 sm:px-3 font-medium whitespace-nowrap text-muted-foreground ${meta?.align === "right" ? "justify-end float-right" : meta?.align === "center" ? "justify-center" : "justify-start"} ${headerClassName || ""}`.trim(),
75516
75823
  children: typeof header2 === "function" ? header2() : /* @__PURE__ */ jsx("span", { children: header2 })
75517
75824
  }
75518
75825
  ),
@@ -75552,7 +75859,7 @@ function createDateColumn({
75552
75859
  header: () => /* @__PURE__ */ jsx(
75553
75860
  "div",
75554
75861
  {
75555
- className: `float-right h-8 flex items-center justify-end px-3 font-medium whitespace-nowrap text-muted-foreground ${headerClassName || ""}`.trim(),
75862
+ className: `float-right h-8 flex items-center justify-end px-2 sm:px-3 font-medium whitespace-nowrap text-muted-foreground ${headerClassName || ""}`.trim(),
75556
75863
  children: typeof header2 === "function" ? header2() : /* @__PURE__ */ jsx("span", { children: header2 })
75557
75864
  }
75558
75865
  ),
@@ -75571,7 +75878,7 @@ function createDateColumn({
75571
75878
  return /* @__PURE__ */ jsx(
75572
75879
  "div",
75573
75880
  {
75574
- className: `font-variant-numeric w-full h-8 flex items-center justify-end pr-4 whitespace-nowrap ${cellClassName || ""} ${meta?.className || ""}`.trim(),
75881
+ className: `font-variant-numeric w-full h-8 flex items-center justify-end pr-2 sm:pr-3 md:pr-4 whitespace-nowrap ${cellClassName || ""} ${meta?.className || ""}`.trim(),
75575
75882
  children: formattedDate
75576
75883
  }
75577
75884
  );
@@ -75606,7 +75913,7 @@ function createNumericColumn({
75606
75913
  header: () => /* @__PURE__ */ jsx(
75607
75914
  "div",
75608
75915
  {
75609
- className: `float-right h-8 flex items-center justify-end px-3 font-medium whitespace-nowrap text-muted-foreground ${headerClassName || ""}`.trim(),
75916
+ className: `float-right h-8 flex items-center justify-end px-2 sm:px-3 font-medium whitespace-nowrap text-muted-foreground ${headerClassName || ""}`.trim(),
75610
75917
  children: typeof header2 === "function" ? header2() : /* @__PURE__ */ jsx("span", { children: header2 })
75611
75918
  }
75612
75919
  ),
@@ -75615,7 +75922,7 @@ function createNumericColumn({
75615
75922
  return /* @__PURE__ */ jsxs(
75616
75923
  "div",
75617
75924
  {
75618
- className: `font-variant-numeric h-8 flex items-center justify-end pr-4 ${cellClassName || ""} ${meta?.className || ""}`.trim(),
75925
+ className: `font-variant-numeric h-8 flex items-center justify-end pr-2 sm:pr-3 md:pr-4 ${cellClassName || ""} ${meta?.className || ""}`.trim(),
75619
75926
  children: [
75620
75927
  prefix,
75621
75928
  value.toLocaleString(void 0, localeStringOptions),
@@ -75637,9 +75944,9 @@ function createIconActionColumn({
75637
75944
  header: header2,
75638
75945
  meta = { align: "center" },
75639
75946
  text: text2,
75640
- size: size2 = 80,
75641
- minSize = 80,
75642
- maxSize = 80,
75947
+ size: size2 = 120,
75948
+ minSize = 100,
75949
+ maxSize = 200,
75643
75950
  enableSorting = false,
75644
75951
  enableHiding = false,
75645
75952
  headerClassName,
@@ -75653,8 +75960,8 @@ function createIconActionColumn({
75653
75960
  header: () => /* @__PURE__ */ jsx(
75654
75961
  "div",
75655
75962
  {
75656
- className: `float-right h-8 flex items-center justify-end px-3 font-medium whitespace-nowrap text-muted-foreground ${headerClassName || ""}`.trim(),
75657
- children: typeof header2 === "function" ? header2() : /* @__PURE__ */ jsx("span", { children: header2 })
75963
+ className: `float-right h-8 flex items-center justify-end px-2 sm:px-3 font-medium whitespace-nowrap text-muted-foreground ${headerClassName || ""}`.trim(),
75964
+ children: typeof header2 === "function" ? header2() : /* @__PURE__ */ jsx("span", { className: "whitespace-nowrap", children: header2 })
75658
75965
  }
75659
75966
  ),
75660
75967
  cell: (info) => {
@@ -75664,7 +75971,7 @@ function createIconActionColumn({
75664
75971
  return /* @__PURE__ */ jsx(
75665
75972
  "div",
75666
75973
  {
75667
- className: `flex items-center h-8 pr-3 ${meta?.align === "right" ? "justify-end" : meta?.align === "center" ? "justify-center" : "justify-start"} ${meta?.className || ""}`.trim(),
75974
+ className: `flex items-center h-8 pr-2 sm:pr-3 min-w-0 ${meta?.align === "right" ? "justify-end" : meta?.align === "center" ? "justify-center" : "justify-start"} ${meta?.className || ""}`.trim(),
75668
75975
  children: /* @__PURE__ */ jsxs(
75669
75976
  Button$1,
75670
75977
  {
@@ -75672,9 +75979,10 @@ function createIconActionColumn({
75672
75979
  size: actionButtonSize,
75673
75980
  disabled: isDisabled,
75674
75981
  onClick: () => onAction(rowOriginal),
75982
+ className: "whitespace-nowrap shrink-0",
75675
75983
  children: [
75676
- /* @__PURE__ */ jsx(IconComponent, { className: "h-4 w-4" }),
75677
- text2 && /* @__PURE__ */ jsx("span", { children: text2 })
75984
+ /* @__PURE__ */ jsx(IconComponent, { className: "h-4 w-4 shrink-0" }),
75985
+ text2 && /* @__PURE__ */ jsx("span", { className: "ml-1.5 shrink-0", children: text2 })
75678
75986
  ]
75679
75987
  }
75680
75988
  )
@@ -82983,9 +83291,9 @@ function createNameColumn(nameAccessor = "name", headerText, showDescription = f
82983
83291
  meta: {
82984
83292
  align: "left",
82985
83293
  displayName: headerText,
82986
- className: "min-w-[240px] w-full"
83294
+ className: "min-w-[200px] sm:min-w-[240px] w-full"
82987
83295
  },
82988
- cellClassName: "pl-3 pr-2",
83296
+ cellClassName: "pl-2 pr-1 sm:pl-3 sm:pr-2",
82989
83297
  cellFormatter: (info) => {
82990
83298
  const value = info.getValue();
82991
83299
  const { original: rowOriginal } = info.row;
@@ -83013,14 +83321,14 @@ function createNameColumn(nameAccessor = "name", headerText, showDescription = f
83013
83321
  [BusinessSegmentTypeEnum.ONE_OFF]: "bg-orange-500"
83014
83322
  };
83015
83323
  const dotColor = type ? typeDotStyles[type] : status ? badgeStyles[status] : "bg-blue-500";
83016
- return /* @__PURE__ */ jsx("div", { className: "w-full flex gap-6 justify-between items-center", children: /* @__PURE__ */ jsxs("div", { className: "flex gap-1 items-center w-full", children: [
83324
+ 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: [
83017
83325
  /* @__PURE__ */ jsx(
83018
83326
  "div",
83019
83327
  {
83020
- className: `w-2 h-2 rounded-full mr-3 flex-shrink-0 ${dotColor}`
83328
+ className: `w-2 h-2 rounded-full mr-1.5 sm:mr-2 md:mr-3 flex-shrink-0 ${dotColor}`
83021
83329
  }
83022
83330
  ),
83023
- /* @__PURE__ */ jsxs("div", { className: "flex-1 flex flex-col gap-0.5", children: [
83331
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 flex flex-col gap-0.5 min-w-0", children: [
83024
83332
  /* @__PURE__ */ jsx("span", { className: "leading-tight font-medium text-sm overflow-hidden text-ellipsis", children: value }),
83025
83333
  showDescription && rowOriginal?.description && /* @__PURE__ */ jsx("div", { className: "relative h-4", children: /* @__PURE__ */ jsx("div", { className: "absolute inset-0 text-muted-foreground text-xs truncate whitespace-nowrap overflow-hidden w-full", children: rowOriginal?.description }) })
83026
83334
  ] })
@@ -83033,15 +83341,19 @@ function createUsersColumn() {
83033
83341
  accessorKey: "user_count",
83034
83342
  header: t$2("engage:user_other"),
83035
83343
  enableSorting: false,
83344
+ size: 120,
83345
+ minSize: 100,
83036
83346
  headerClassName: "justify-end text-right w-full",
83037
83347
  meta: {
83038
83348
  align: "right",
83039
83349
  displayName: t$2("engage:user_other")
83040
83350
  },
83041
- cellClassName: "text-muted-foreground pr-4",
83351
+ cellClassName: "text-muted-foreground pr-2 sm:pr-3 md:pr-4",
83042
83352
  cellFormatter: (info) => {
83043
- const value = info.getValue() ?? 0;
83044
- return `${value.toLocaleString()} ${t$2("engage:user", { count: value }).toLowerCase()}`;
83353
+ const rawValue = info.getValue();
83354
+ const value = typeof rawValue === "string" ? Number(rawValue) : rawValue ?? 0;
83355
+ const numValue = isNaN(value) ? 0 : value;
83356
+ return `${numValue.toLocaleString()} ${t$2("engage:user", { count: numValue }).toLowerCase()}`;
83045
83357
  }
83046
83358
  });
83047
83359
  }
@@ -83050,12 +83362,14 @@ function createTypeColumn() {
83050
83362
  accessorKey: "type",
83051
83363
  header: "Type",
83052
83364
  enableSorting: false,
83365
+ size: 110,
83366
+ minSize: 90,
83053
83367
  headerClassName: "justify-end text-right w-full",
83054
83368
  meta: {
83055
83369
  align: "right",
83056
83370
  displayName: `${t$2("engage:segment")} type`
83057
83371
  },
83058
- cellClassName: "pr-4",
83372
+ cellClassName: "pr-2 sm:pr-3 md:pr-4",
83059
83373
  cellFormatter: (info) => {
83060
83374
  const typeFromCell = info.getValue();
83061
83375
  const displayText = typeFromCell ? typeFromCell === BusinessSegmentTypeEnum.SQL ? "Managed" : typeFromCell.split("_").map((word) => word[0].toUpperCase() + word.slice(1).toLowerCase()).join(" ") : "Unknown";
@@ -83102,6 +83416,7 @@ function createModifiedColumn(dateAccessor = "updated_at") {
83102
83416
  header: "Last Modified",
83103
83417
  formatType: "relative",
83104
83418
  size: 160,
83419
+ minSize: 120,
83105
83420
  enableSorting: false,
83106
83421
  headerClassName: "justify-end text-right w-full",
83107
83422
  meta: {
@@ -83137,7 +83452,7 @@ function createStatusColumn(args) {
83137
83452
  meta: {
83138
83453
  align: "right"
83139
83454
  },
83140
- cellClassName: "pr-4",
83455
+ cellClassName: "pr-2 sm:pr-3 md:pr-4",
83141
83456
  cellFormatter: (info) => {
83142
83457
  const { original: rowOriginal } = info.row;
83143
83458
  const statusValue = rowOriginal.status ?? null;
@@ -83183,7 +83498,7 @@ function createBroadcastActionColumn(args) {
83183
83498
  meta: {
83184
83499
  align: "right"
83185
83500
  },
83186
- cellClassName: "pr-4",
83501
+ cellClassName: "pr-2 sm:pr-3 md:pr-4",
83187
83502
  cellFormatter: (info) => {
83188
83503
  const { original: rowOriginal } = info.row;
83189
83504
  const statusValue = rowOriginal.status ?? null;
@@ -83223,7 +83538,10 @@ function createActionColumn(setSelectedSegment) {
83223
83538
  setSelectedSegment(row.id);
83224
83539
  },
83225
83540
  text: "Edit",
83226
- headerClassName: "w-full",
83541
+ size: 140,
83542
+ minSize: 120,
83543
+ maxSize: 160,
83544
+ headerClassName: "w-full whitespace-nowrap",
83227
83545
  enableHiding: false,
83228
83546
  meta: columnMeta
83229
83547
  });
@@ -83766,6 +84084,7 @@ const ContentBuilderStyleStep = () => {
83766
84084
  /* @__PURE__ */ jsx("div", { id: "wizard-ai-builder-option", className: "min-w-0 w-full h-full", children: /* @__PURE__ */ jsx(
83767
84085
  BigSelector,
83768
84086
  {
84087
+ id: contentBuilderStyle === ContentBuilderStyleEnum.AI ? "wizard-ai-selected" : "wizard-ai-not-selected",
83769
84088
  onClick: () => {
83770
84089
  handleContentBuilderStyleSelect(ContentBuilderStyleEnum.AI);
83771
84090
  },
@@ -83787,6 +84106,7 @@ const ContentBuilderStyleStep = () => {
83787
84106
  children: /* @__PURE__ */ jsx(
83788
84107
  BigSelector,
83789
84108
  {
84109
+ id: contentBuilderStyle === ContentBuilderStyleEnum.MANUAL ? "wizard-manual-selected" : "wizard-manual-not-selected",
83790
84110
  onClick: () => {
83791
84111
  handleContentBuilderStyleSelect(ContentBuilderStyleEnum.MANUAL);
83792
84112
  },
@@ -104054,7 +104374,7 @@ const StripoWrapper = ({
104054
104374
  } = useStripoEditorData();
104055
104375
  const { updateCommunicationGroup: updateCommunicationGroup2 } = useUpdateCommunicationGroup();
104056
104376
  const checkEditorReady = useCallback(() => {
104057
- const isReady = !!(window.StripoEditorApi?.actionsApi && typeof window.StripoEditorApi.actionsApi.save === "function" && typeof window.StripoEditorApi.actionsApi.compileEmail === "function");
104377
+ const isReady = !!(window.StripoEditorApi?.actionsApi && typeof window.StripoEditorApi.actionsApi.save === "function" && typeof window.StripoEditorApi.actionsApi.compileEmail === "function" && typeof window.StripoEditorApi.actionsApi.getTemplateData === "function");
104058
104378
  if (isReady && !isEditorReady) {
104059
104379
  setIsEditorReady(true);
104060
104380
  onEditorReadyChange?.(true);
@@ -104097,21 +104417,38 @@ const StripoWrapper = ({
104097
104417
  }
104098
104418
  try {
104099
104419
  const saveOperation = () => new Promise((resolve, reject) => {
104420
+ let templateData = null;
104421
+ let compiledHtml = null;
104422
+ let saveCompleted = false;
104423
+ const checkAndUpdate = async () => {
104424
+ if (templateData && compiledHtml && saveCompleted) {
104425
+ try {
104426
+ await updateCommunicationGroup2({
104427
+ groupId: template.communicationGroupId,
104428
+ params: {
104429
+ emailHtmlBody: templateData.html,
104430
+ emailCss: templateData.css,
104431
+ emailCompiledHtml: compiledHtml
104432
+ }
104433
+ });
104434
+ setStripoEmailCompiled(true);
104435
+ resolve();
104436
+ } catch (err) {
104437
+ reject(err);
104438
+ }
104439
+ }
104440
+ };
104441
+ const getTemplateDataCallback = function(data) {
104442
+ templateData = data;
104443
+ checkAndUpdate();
104444
+ };
104100
104445
  const compileEmailCallback = async function(error2, html) {
104101
104446
  if (error2) {
104102
104447
  reject(new Error(`Compile failed: ${error2}`));
104103
104448
  return;
104104
104449
  }
104105
- try {
104106
- updateCommunicationGroup2({
104107
- groupId: template.communicationGroupId,
104108
- params: { emailCompiledHtml: html }
104109
- });
104110
- } catch (err) {
104111
- reject(err);
104112
- }
104113
- setStripoEmailCompiled(true);
104114
- resolve();
104450
+ compiledHtml = html;
104451
+ await checkAndUpdate();
104115
104452
  };
104116
104453
  const saveCallback = function(error2) {
104117
104454
  if (error2) {
@@ -104119,7 +104456,12 @@ const StripoWrapper = ({
104119
104456
  return;
104120
104457
  }
104121
104458
  setStripoEmailSaved(true);
104459
+ saveCompleted = true;
104460
+ checkAndUpdate();
104122
104461
  };
104462
+ window.StripoEditorApi.actionsApi.getTemplateData(
104463
+ getTemplateDataCallback
104464
+ );
104123
104465
  window.StripoEditorApi.actionsApi.compileEmail({
104124
104466
  callback: compileEmailCallback,
104125
104467
  minimize: true,
@@ -104703,8 +105045,8 @@ const EditEmailContent = () => {
104703
105045
  children: [
104704
105046
  /* @__PURE__ */ jsx(TitleAndResetButton, { title: "Email Content", type: ChannelType.EMAIL }),
104705
105047
  /* @__PURE__ */ jsx("div", { id: "wizard-email-settings-form", children: /* @__PURE__ */ jsx(EmailSettingsForm, { ...emailSettingsFormProps }) }),
104706
- /* @__PURE__ */ jsxs("div", { className: "flex-1 flex flex-col min-h-0", children: [
104707
- /* @__PURE__ */ jsxs("div", { className: "flex justify-between items-center mb-4", children: [
105048
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 flex flex-col min-h-0 overflow-hidden", children: [
105049
+ /* @__PURE__ */ jsxs("div", { className: "flex justify-between items-center mb-4 flex-shrink-0", children: [
104708
105050
  /* @__PURE__ */ jsx("h3", { className: "font-medium text-lg", children: "Preview" }),
104709
105051
  /* @__PURE__ */ jsx(
104710
105052
  Button$1,
@@ -104719,7 +105061,7 @@ const EditEmailContent = () => {
104719
105061
  }
104720
105062
  )
104721
105063
  ] }),
104722
- /* @__PURE__ */ jsx("div", { className: "w-full", children: memoizedEmailPreview })
105064
+ /* @__PURE__ */ jsx("div", { className: "flex-1 overflow-y-auto min-h-0", children: memoizedEmailPreview })
104723
105065
  ] }),
104724
105066
  /* @__PURE__ */ jsx(
104725
105067
  StripoDialog,
@@ -107695,7 +108037,8 @@ const SendPreviewPopup = ({ automation: automation2, type, setOpenSendPreviewPop
107695
108037
  const [finishedLoading, setFinishedLoading] = useState(false);
107696
108038
  const [selectedPreviewAsRecipientId, setSelectedPreviewAsRecipientId] = useState("");
107697
108039
  const [allUsersForDropdown, setAllUsersForDropdown] = useState();
107698
- const [isLoadingUsers, setIsLoadingUsers] = useState(true);
108040
+ const [isLoadingUsers, setIsLoadingUsers] = useState(false);
108041
+ const [hasAttemptedFetch, setHasAttemptedFetch] = useState(false);
107699
108042
  const { sendTestCommunication: sendTestCommunication2, sendError, isSendSuccess } = useSendTestCommunication();
107700
108043
  const { toast: toast2 } = useToast();
107701
108044
  const { segments } = useListSegments();
@@ -107704,40 +108047,43 @@ const SendPreviewPopup = ({ automation: automation2, type, setOpenSendPreviewPop
107704
108047
  );
107705
108048
  const communicationGroupId = actionDataCommunication?.actionMetadata.communicationGroupId;
107706
108049
  const { communicationGroup, isGetting: isGettingCommunicationGroup } = useGetCommunicationGroup(communicationGroupId ?? void 0);
107707
- useEffect(() => {
107708
- const fetchAllUsers = async () => {
107709
- if (!segments) {
107710
- setIsLoadingUsers(false);
107711
- return;
107712
- }
107713
- if (allUsersForDropdown?.recipients) {
107714
- setIsLoadingUsers(false);
107715
- return;
107716
- }
108050
+ const fetchUsersIfNeeded = React__default.useCallback(async () => {
108051
+ if (hasAttemptedFetch || allUsersForDropdown?.recipients || !segments) {
108052
+ return;
108053
+ }
108054
+ setHasAttemptedFetch(true);
108055
+ setIsLoadingUsers(true);
108056
+ try {
107717
108057
  const allUsersSegment = segments.find(
107718
108058
  (segment2) => segment2.type === BusinessSegmentTypeEnum.ALL_USERS
107719
108059
  );
107720
108060
  if (allUsersSegment) {
107721
- setIsLoadingUsers(true);
107722
- try {
107723
- const allUsersResponse = await getCountOfBusinessAutomationRecipients(
107724
- {
107725
- includeSegments: [allUsersSegment.id],
107726
- excludeSegments: []
107727
- }
107728
- );
107729
- setAllUsersForDropdown(allUsersResponse);
107730
- } catch (error22) {
107731
- console.error("Error fetching all users for dropdown:", error22);
107732
- } finally {
107733
- setIsLoadingUsers(false);
107734
- }
107735
- } else {
107736
- setIsLoadingUsers(false);
108061
+ const allUsersResponse = await getCountOfBusinessAutomationRecipients({
108062
+ includeSegments: [allUsersSegment.id],
108063
+ excludeSegments: []
108064
+ });
108065
+ setAllUsersForDropdown(allUsersResponse);
107737
108066
  }
107738
- };
107739
- fetchAllUsers();
107740
- }, [segments, allUsersForDropdown?.recipients]);
108067
+ } catch (error22) {
108068
+ console.error("Error fetching users for dropdown:", error22);
108069
+ } finally {
108070
+ setIsLoadingUsers(false);
108071
+ }
108072
+ }, [hasAttemptedFetch, allUsersForDropdown?.recipients, segments]);
108073
+ useEffect(() => {
108074
+ if (!allUsersForDropdown?.recipients && segments && !isLoadingUsers && open) {
108075
+ const timer = setTimeout(() => {
108076
+ fetchUsersIfNeeded();
108077
+ }, 100);
108078
+ return () => clearTimeout(timer);
108079
+ }
108080
+ }, [
108081
+ allUsersForDropdown?.recipients,
108082
+ segments,
108083
+ isLoadingUsers,
108084
+ open,
108085
+ fetchUsersIfNeeded
108086
+ ]);
107741
108087
  const filteredRecipients = React__default.useMemo(() => {
107742
108088
  return [...allUsersForDropdown?.recipients ?? []].filter((recipient2) => {
107743
108089
  if (!recipient2.firstName || !recipient2.lastName) return false;
@@ -109245,22 +109591,27 @@ const RecipientsTable = ({
109245
109591
  filter: filter2 = "all",
109246
109592
  audienceMode,
109247
109593
  isSegmentBuilder = false,
109248
- isLoading = false
109594
+ isLoading = false,
109595
+ totalCount,
109596
+ searchQuery = "",
109597
+ onSearchChange,
109598
+ onLoadMore,
109599
+ hasMore = false,
109600
+ isLoadingMore = false
109249
109601
  }) => {
109250
109602
  const [isSearchOpen, setIsSearchOpen] = useState(false);
109251
- const [searchQuery, setSearchQuery] = useState("");
109252
109603
  const [maxHeight, setMaxHeight] = useState(void 0);
109253
109604
  const [displayedCount, setDisplayedCount] = useState(50);
109254
- const [isLoadingMore, setIsLoadingMore] = useState(false);
109605
+ const [isLoadingMoreLocal, setIsLoadingMoreLocal] = useState(false);
109255
109606
  const containerRef = useRef(null);
109256
109607
  const scrollContainerRef = useRef(null);
109608
+ const searchInputRef = useRef(null);
109609
+ const isLoadingMoreRef = useRef(false);
109610
+ const isLoadingMoreState = onLoadMore ? isLoadingMore : isLoadingMoreLocal;
109257
109611
  const filteredRecipients = useMemo(() => {
109258
109612
  return recipients?.filter((recipient) => {
109259
109613
  const hasEmail = !!recipient.email;
109260
109614
  const hasPhone = !!recipient.phone;
109261
- if (!hasEmail && !hasPhone) {
109262
- return false;
109263
- }
109264
109615
  switch (filter2) {
109265
109616
  case "email":
109266
109617
  return hasEmail;
@@ -109272,42 +109623,55 @@ const RecipientsTable = ({
109272
109623
  }
109273
109624
  });
109274
109625
  }, [recipients, filter2]);
109275
- const searchFilteredRecipients = useMemo(() => {
109276
- if (!searchQuery.trim()) return filteredRecipients;
109277
- const query = searchQuery.toLowerCase();
109278
- return filteredRecipients?.filter((recipient) => {
109279
- const displayName = getDisplayName(
109280
- recipient,
109281
- `Unnamed ${t$2("engage:user")}`
109282
- ).toLowerCase();
109283
- const email = recipient.email?.toLowerCase() || "";
109284
- const phone = recipient.phone || "";
109285
- return displayName.includes(query) || email.includes(query) || phone.includes(query);
109286
- });
109287
- }, [filteredRecipients, searchQuery]);
109288
109626
  const displayedRecipients = useMemo(() => {
109289
- return searchFilteredRecipients?.slice(0, displayedCount) || [];
109290
- }, [searchFilteredRecipients, displayedCount]);
109291
- const hasMore = (searchFilteredRecipients?.length || 0) > displayedCount;
109627
+ if (onLoadMore) {
109628
+ return filteredRecipients || [];
109629
+ } else {
109630
+ return filteredRecipients?.slice(0, displayedCount) || [];
109631
+ }
109632
+ }, [filteredRecipients, displayedCount, onLoadMore]);
109633
+ const hasMoreItems = onLoadMore ? hasMore : (filteredRecipients?.length || 0) > displayedCount;
109292
109634
  const loadMore = useCallback(() => {
109293
- if (isLoadingMore || !hasMore) return;
109294
- setIsLoadingMore(true);
109295
- setTimeout(() => {
109296
- setDisplayedCount(
109297
- (prev) => Math.min(prev + ITEMS_PER_LOAD, searchFilteredRecipients?.length || 0)
109298
- );
109299
- setIsLoadingMore(false);
109300
- }, 300);
109301
- }, [isLoadingMore, hasMore, searchFilteredRecipients?.length]);
109635
+ if (isLoadingMoreRef.current) return;
109636
+ if (onLoadMore) {
109637
+ if (!isLoadingMoreState && hasMore && !isLoadingMoreRef.current) {
109638
+ isLoadingMoreRef.current = true;
109639
+ onLoadMore();
109640
+ setTimeout(() => {
109641
+ isLoadingMoreRef.current = false;
109642
+ }, 1e3);
109643
+ }
109644
+ } else {
109645
+ if (isLoadingMoreLocal || !hasMoreItems || isLoadingMoreRef.current)
109646
+ return;
109647
+ isLoadingMoreRef.current = true;
109648
+ setIsLoadingMoreLocal(true);
109649
+ setTimeout(() => {
109650
+ setDisplayedCount(
109651
+ (prev) => Math.min(prev + ITEMS_PER_LOAD, filteredRecipients?.length || 0)
109652
+ );
109653
+ setIsLoadingMoreLocal(false);
109654
+ isLoadingMoreRef.current = false;
109655
+ }, 300);
109656
+ }
109657
+ }, [
109658
+ onLoadMore,
109659
+ isLoadingMoreState,
109660
+ isLoadingMoreLocal,
109661
+ hasMore,
109662
+ hasMoreItems,
109663
+ filteredRecipients?.length
109664
+ ]);
109302
109665
  const handleScroll2 = useCallback(() => {
109303
109666
  const container2 = scrollContainerRef.current;
109304
- if (!container2 || isLoadingMore || !hasMore) return;
109667
+ if (!container2 || isLoadingMoreState || !hasMoreItems || isLoadingMoreRef.current)
109668
+ return;
109305
109669
  const { scrollTop, scrollHeight, clientHeight } = container2;
109306
109670
  const scrollPercentage = (scrollTop + clientHeight) / scrollHeight;
109307
- if (scrollPercentage > 0.8) {
109671
+ if (scrollPercentage > 0.9) {
109308
109672
  loadMore();
109309
109673
  }
109310
- }, [loadMore, isLoadingMore, hasMore]);
109674
+ }, [loadMore, isLoadingMoreState, hasMoreItems]);
109311
109675
  useEffect(() => {
109312
109676
  if (!isSegmentBuilder || !containerRef.current) return;
109313
109677
  const calculateHeight = () => {
@@ -109330,6 +109694,16 @@ const RecipientsTable = ({
109330
109694
  useEffect(() => {
109331
109695
  setDisplayedCount(50);
109332
109696
  }, [searchQuery, filter2]);
109697
+ useEffect(() => {
109698
+ if (isSearchOpen && searchInputRef.current && document.activeElement !== searchInputRef.current) {
109699
+ const timeout = setTimeout(() => {
109700
+ if (searchInputRef.current && document.activeElement !== searchInputRef.current) {
109701
+ searchInputRef.current.focus();
109702
+ }
109703
+ }, 0);
109704
+ return () => clearTimeout(timeout);
109705
+ }
109706
+ }, [isSearchOpen, recipients.length, searchQuery]);
109333
109707
  useEffect(() => {
109334
109708
  const container2 = scrollContainerRef.current;
109335
109709
  if (!container2) return;
@@ -109358,7 +109732,19 @@ const RecipientsTable = ({
109358
109732
  )
109359
109733
  ] })
109360
109734
  ] }),
109361
- /* @__PURE__ */ jsx(AnimatePresence, { children: isSearchOpen && /* @__PURE__ */ jsx(
109735
+ searchQuery.trim() && filteredRecipients.length > 0 ? /* @__PURE__ */ jsx("div", { className: "flex-shrink-0 px-3 py-2 bg-blue-50/50 border-b border-blue-100/50", children: /* @__PURE__ */ jsxs("p", { className: "text-xs text-blue-700", children: [
109736
+ 'Showing all users matching "',
109737
+ searchQuery,
109738
+ '"'
109739
+ ] }) }) : totalCount !== void 0 && totalCount > filteredRecipients.length && filteredRecipients.length > 0 && /* @__PURE__ */ jsx("div", { className: "flex-shrink-0 px-3 py-2 bg-blue-50/50 border-b border-blue-100/50", children: /* @__PURE__ */ jsxs("p", { className: "text-xs text-blue-700", children: [
109740
+ "Showing first ",
109741
+ filteredRecipients.length.toLocaleString(),
109742
+ " of",
109743
+ " ",
109744
+ totalCount.toLocaleString(),
109745
+ " recipients. Use search to find specific recipients."
109746
+ ] }) }),
109747
+ /* @__PURE__ */ jsx(AnimatePresence, { mode: "wait", children: isSearchOpen && /* @__PURE__ */ jsxs(
109362
109748
  motion.div,
109363
109749
  {
109364
109750
  initial: { opacity: 0, height: 0 },
@@ -109366,32 +109752,37 @@ const RecipientsTable = ({
109366
109752
  exit: { opacity: 0, height: 0 },
109367
109753
  transition: { duration: 0.2 },
109368
109754
  className: "flex-shrink-0 bg-white/80 backdrop-blur-sm border-b border-gray-200 px-3 py-3",
109369
- children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
109370
- /* @__PURE__ */ jsx(Search, { className: "w-4 h-4 text-gray-500 flex-shrink-0" }),
109371
- /* @__PURE__ */ jsx(
109372
- "input",
109373
- {
109374
- type: "text",
109375
- placeholder: RECIPIENT_SEARCH_PLACEHOLDER,
109376
- value: searchQuery,
109377
- onChange: (e4) => setSearchQuery(e4.target.value),
109378
- className: "flex-1 bg-transparent border-none outline-none text-sm placeholder:text-gray-400",
109379
- autoFocus: true
109380
- }
109381
- ),
109382
- /* @__PURE__ */ jsx(
109383
- "button",
109384
- {
109385
- onClick: () => {
109386
- setIsSearchOpen(false);
109387
- setSearchQuery("");
109388
- },
109389
- className: "p-1 rounded-md hover:bg-gray-200/50 transition-colors",
109390
- children: /* @__PURE__ */ jsx(X$3, { className: "w-4 h-4 text-gray-500" })
109391
- }
109392
- )
109393
- ] })
109394
- }
109755
+ children: [
109756
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
109757
+ /* @__PURE__ */ jsx(Search, { className: "w-4 h-4 text-gray-500 flex-shrink-0" }),
109758
+ /* @__PURE__ */ jsx(
109759
+ "input",
109760
+ {
109761
+ ref: searchInputRef,
109762
+ type: "text",
109763
+ placeholder: RECIPIENT_SEARCH_PLACEHOLDER,
109764
+ value: searchQuery,
109765
+ onChange: (e4) => onSearchChange?.(e4.target.value),
109766
+ className: "flex-1 bg-transparent border-none outline-none text-sm placeholder:text-gray-400",
109767
+ autoFocus: true
109768
+ }
109769
+ ),
109770
+ /* @__PURE__ */ jsx(
109771
+ "button",
109772
+ {
109773
+ onClick: () => {
109774
+ setIsSearchOpen(false);
109775
+ onSearchChange?.("");
109776
+ },
109777
+ className: "p-1 rounded-md hover:bg-gray-200/50 transition-colors",
109778
+ children: /* @__PURE__ */ jsx(X$3, { className: "w-4 h-4 text-gray-500" })
109779
+ }
109780
+ )
109781
+ ] }),
109782
+ searchQuery.trim() && /* @__PURE__ */ jsx("p", { className: "text-xs text-gray-500 mt-1.5 ml-6", children: "Searching across all recipients" })
109783
+ ]
109784
+ },
109785
+ "search-input"
109395
109786
  ) }),
109396
109787
  /* @__PURE__ */ jsx("div", { ref: scrollContainerRef, className: "flex-1 overflow-y-auto min-h-0", children: /* @__PURE__ */ jsx(AnimatePresence, { mode: "wait", children: isLoading ? /* @__PURE__ */ jsx(
109397
109788
  motion.div,
@@ -109404,7 +109795,7 @@ const RecipientsTable = ({
109404
109795
  children: /* @__PURE__ */ jsx(BasicLoader, { size: "sm", textColor: "text-gray-500" })
109405
109796
  },
109406
109797
  "loading"
109407
- ) : !searchFilteredRecipients?.length ? /* @__PURE__ */ jsx(
109798
+ ) : !filteredRecipients?.length ? /* @__PURE__ */ jsx(
109408
109799
  motion.div,
109409
109800
  {
109410
109801
  initial: { opacity: 0 },
@@ -109485,26 +109876,18 @@ const RecipientsTable = ({
109485
109876
  `recipient-${index2}`
109486
109877
  );
109487
109878
  }),
109488
- hasMore && /* @__PURE__ */ jsx(
109879
+ isLoadingMoreState && displayedRecipients.length > 0 && /* @__PURE__ */ jsx(
109489
109880
  motion.div,
109490
109881
  {
109491
109882
  initial: { opacity: 0 },
109492
109883
  animate: { opacity: 1 },
109884
+ exit: { opacity: 0 },
109493
109885
  transition: { duration: 0.2 },
109494
- className: "flex justify-center py-4",
109495
- children: isLoadingMore ? /* @__PURE__ */ jsx(BasicLoader, { size: "sm", textColor: "text-gray-500" }) : /* @__PURE__ */ jsxs(
109496
- "button",
109497
- {
109498
- onClick: loadMore,
109499
- className: "text-sm text-gray-500 hover:text-gray-700 transition-colors px-3 py-2 rounded-md hover:bg-gray-100/50",
109500
- children: [
109501
- "Load more (",
109502
- searchFilteredRecipients?.length - displayedCount,
109503
- " ",
109504
- "remaining)"
109505
- ]
109506
- }
109507
- )
109886
+ className: "flex justify-center items-center py-6 border-t border-gray-200/50",
109887
+ children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-2", children: [
109888
+ /* @__PURE__ */ jsx(BasicLoader, { size: "sm", textColor: "text-gray-500" }),
109889
+ /* @__PURE__ */ jsx("span", { className: "text-xs text-gray-500", children: "Loading more recipients..." })
109890
+ ] })
109508
109891
  }
109509
109892
  )
109510
109893
  ]
@@ -112197,16 +112580,28 @@ const SegmentBuilderContent = ({
112197
112580
  segmentType,
112198
112581
  existingSegmentConditions
112199
112582
  }) => {
112583
+ const [searchQuery, setSearchQuery] = React.useState("");
112584
+ const [limit, setLimit] = React.useState(100);
112585
+ const conditionsKey = React.useMemo(
112586
+ () => JSON.stringify(segment2.conditions),
112587
+ [segment2.conditions]
112588
+ );
112589
+ React.useEffect(() => {
112590
+ setLimit(100);
112591
+ }, [searchQuery, conditionsKey]);
112200
112592
  const {
112201
112593
  data: recipientsData,
112202
112594
  isLoading,
112595
+ isFetching,
112203
112596
  error: error2
112204
112597
  } = usePreviewSegmentRecipients(
112205
112598
  segment2.type,
112206
112599
  segment2.conditions,
112207
112600
  businessId,
112208
112601
  {
112209
- debounceMs: 500
112602
+ debounceMs: 500,
112603
+ search: searchQuery,
112604
+ limit
112210
112605
  },
112211
112606
  existingSegmentConditions
112212
112607
  );
@@ -112217,6 +112612,16 @@ const SegmentBuilderContent = ({
112217
112612
  phone: recipient.phone
112218
112613
  })) ?? [];
112219
112614
  const estimatedTotal = recipientsData?.estimatedTotal ?? 0;
112615
+ const hasMore = recipientsData?.pagination?.hasNextPage ?? false;
112616
+ const isLoadingMoreRef = React.useRef(false);
112617
+ const handleLoadMore = React.useCallback(() => {
112618
+ if (isLoadingMoreRef.current || isLoading || !hasMore) return;
112619
+ isLoadingMoreRef.current = true;
112620
+ setLimit((prev) => prev + 100);
112621
+ setTimeout(() => {
112622
+ isLoadingMoreRef.current = false;
112623
+ }, 1e3);
112624
+ }, [isLoading, hasMore]);
112220
112625
  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: [
112221
112626
  /* @__PURE__ */ jsxs("div", { className: "flex-1 flex flex-col overflow-visible", children: [
112222
112627
  /* @__PURE__ */ jsxs("div", { className: "mb-6 grid grid-cols-2 gap-2", children: [
@@ -112374,7 +112779,14 @@ const SegmentBuilderContent = ({
112374
112779
  recipients,
112375
112780
  filter: "all",
112376
112781
  audienceMode: AutomationAudienceSelectorType.SEGMENTS,
112377
- isSegmentBuilder: true
112782
+ isSegmentBuilder: true,
112783
+ searchQuery,
112784
+ onSearchChange: setSearchQuery,
112785
+ totalCount: estimatedTotal,
112786
+ onLoadMore: handleLoadMore,
112787
+ hasMore,
112788
+ isLoadingMore: isFetching,
112789
+ isLoading
112378
112790
  }
112379
112791
  ) })
112380
112792
  ] })
@@ -113291,72 +113703,85 @@ const StatCard = ({
113291
113703
  isLoading,
113292
113704
  selected,
113293
113705
  onClick,
113294
- tooltip
113706
+ tooltip,
113707
+ icon: Icon2
113295
113708
  }) => {
113296
113709
  const variantStyles = {
113297
- default: "bg-gray-100/50 text-gray-700",
113298
- blue: "bg-blue-100/50 text-blue-700",
113299
- green: "bg-green-100/50 text-green-700"
113710
+ default: "text-gray-700",
113711
+ blue: "text-blue-700",
113712
+ green: "text-green-700"
113300
113713
  };
113301
- return /* @__PURE__ */ jsxs(
113714
+ const iconStyles = {
113715
+ default: "text-gray-600",
113716
+ blue: "text-blue-600",
113717
+ green: "text-green-600"
113718
+ };
113719
+ return /* @__PURE__ */ jsx(
113302
113720
  motion.div,
113303
113721
  {
113304
- className: `rounded-md border-2 border-muted-foreground/20 px-2 pt-2 pb-3 duration-300 ease-in-out overflow-x-auto max-w-full min-w-0 ${selected ? "scale-[1.02] [border-color:hsl(var(--reach-primary))] shadow-lg" : ""} ${onClick ? "cursor-pointer hover:bg-gray-50/50 transition-colors" : ""}`,
113722
+ className: `rounded-md border-2 border-muted-foreground/20 px-2 sm:px-3 lg:px-4 pt-3 lg:pt-4 pb-3 lg:pb-5 duration-300 ease-in-out overflow-x-auto max-w-full min-w-0 h-full flex flex-col ${selected ? "scale-[1.02] [border-color:hsl(var(--reach-primary))] shadow-lg" : ""} ${onClick ? "cursor-pointer hover:bg-gray-50/50 transition-colors" : ""}`,
113305
113723
  style: {
113306
113724
  containerType: "inline-size"
113307
113725
  },
113308
113726
  "data-card-container": true,
113309
113727
  onClick,
113310
113728
  layout: true,
113311
- children: [
113312
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1 items-start w-full min-w-0", children: [
113313
- /* @__PURE__ */ jsx("div", { className: "flex items-baseline gap-2 w-full min-w-0 @container/num h-8", children: /* @__PURE__ */ jsx(AnimatePresence, { mode: "wait", children: isLoading ? /* @__PURE__ */ jsx(
113314
- motion.div,
113315
- {
113316
- initial: { opacity: 0 },
113317
- animate: { opacity: 1 },
113318
- exit: { opacity: 0 },
113319
- transition: { duration: 0.2 },
113320
- className: "flex items-center gap-2 pl-2 h-full",
113321
- children: /* @__PURE__ */ jsx(BasicLoader, { size: "sm", textColor: "text-gray-500" })
113322
- },
113323
- "loading"
113324
- ) : /* @__PURE__ */ jsxs(
113325
- motion.div,
113326
- {
113327
- initial: { opacity: 0 },
113328
- animate: { opacity: 1 },
113329
- exit: { opacity: 0 },
113330
- transition: { duration: 0.2 },
113331
- className: "flex items-center gap-1 h-full",
113332
- children: [
113333
- /* @__PURE__ */ jsx(
113334
- "span",
113335
- {
113336
- className: "font-semibold pl-2 break-words max-w-full min-w-0 truncate\n text-xl @[250px]/card:text-2xl @[350px]/card:text-3xl @[500px]/card:text-4xl text-primary",
113337
- children: value.toLocaleString()
113338
- }
113339
- ),
113340
- tooltip && /* @__PURE__ */ jsx(InfoTooltip, { title: tooltip }),
113341
- percentage2 !== void 0 && value.toLocaleString().replace(/,/g, "").length < 5 && /* @__PURE__ */ jsxs("span", { className: "text-muted-foreground/50 text-sm hidden @[120px]/num:inline", children: [
113342
- "(",
113343
- percentage2,
113344
- "%)"
113345
- ] })
113346
- ]
113347
- },
113348
- "content"
113349
- ) }) }),
113350
- /* @__PURE__ */ jsx(
113351
- "span",
113729
+ children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col h-full w-full min-w-0", children: [
113730
+ /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-1.5 sm:gap-2 w-full h-[2.5rem] sm:h-[2.75rem] mb-2 sm:mb-3 lg:mb-4", children: [
113731
+ Icon2 ? /* @__PURE__ */ jsx(
113732
+ Icon2,
113352
113733
  {
113353
- className: `px-2 sm:px-2.5 py-1 text-xs font-medium rounded-lg ${variantStyles[variant]}`,
113354
- children: label2
113734
+ className: `w-3.5 h-3.5 sm:w-4 sm:h-4 flex-shrink-0 mt-0.5 ${iconStyles[variant]}`
113355
113735
  }
113356
- )
113736
+ ) : /* @__PURE__ */ jsx("div", { className: "w-3.5 h-3.5 sm:w-4 sm:h-4 flex-shrink-0" }),
113737
+ /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-1.5 flex-1 min-w-0 h-full", children: [
113738
+ /* @__PURE__ */ jsx(
113739
+ "span",
113740
+ {
113741
+ className: `text-[10px] sm:text-xs font-medium leading-tight break-words ${variantStyles[variant]}`,
113742
+ children: label2
113743
+ }
113744
+ ),
113745
+ tooltip && /* @__PURE__ */ jsx("div", { className: "flex-shrink-0 mt-0.5", children: /* @__PURE__ */ jsx(InfoTooltip, { title: tooltip }) })
113746
+ ] })
113357
113747
  ] }),
113358
- /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-fore hidden @[250px]/card:inline mt-1", children: value === 1 ? "contact" : "contacts" })
113359
- ]
113748
+ /* @__PURE__ */ jsx("div", { className: "flex-1 flex items-start w-full", children: /* @__PURE__ */ jsx(AnimatePresence, { mode: "wait", children: isLoading ? /* @__PURE__ */ jsx(
113749
+ motion.div,
113750
+ {
113751
+ initial: { opacity: 0 },
113752
+ animate: { opacity: 1 },
113753
+ exit: { opacity: 0 },
113754
+ transition: { duration: 0.2 },
113755
+ className: "flex items-center",
113756
+ children: /* @__PURE__ */ jsx(BasicLoader, { size: "sm", textColor: "text-gray-500" })
113757
+ },
113758
+ "loading"
113759
+ ) : /* @__PURE__ */ jsxs(
113760
+ motion.div,
113761
+ {
113762
+ initial: { opacity: 0 },
113763
+ animate: { opacity: 1 },
113764
+ exit: { opacity: 0 },
113765
+ transition: { duration: 0.2 },
113766
+ className: "flex flex-col gap-1 w-full",
113767
+ children: [
113768
+ /* @__PURE__ */ jsx(
113769
+ "span",
113770
+ {
113771
+ className: "font-semibold break-words max-w-full min-w-0\n text-lg sm:text-xl @[250px]:text-2xl @[350px]:text-3xl text-primary leading-none",
113772
+ children: value.toLocaleString()
113773
+ }
113774
+ ),
113775
+ percentage2 !== void 0 && /* @__PURE__ */ jsxs("span", { className: "text-muted-foreground/50 text-[10px] leading-none", children: [
113776
+ "(",
113777
+ percentage2,
113778
+ "%)"
113779
+ ] })
113780
+ ]
113781
+ },
113782
+ "content"
113783
+ ) }) })
113784
+ ] })
113360
113785
  }
113361
113786
  );
113362
113787
  };
@@ -113367,17 +113792,44 @@ const EstimatedMatchesView = ({
113367
113792
  isLoading = false
113368
113793
  }) => {
113369
113794
  const stats = React__default.useMemo(() => {
113370
- if (!countResponse?.recipients) return { total: 0, emails: 0, phones: 0 };
113371
- return countResponse.recipients.reduce(
113372
- (acc, user2) => ({
113373
- total: countResponse.count,
113374
- emails: acc.emails + (user2.email ? 1 : 0),
113375
- phones: acc.phones + (user2.phone ? 1 : 0)
113376
- }),
113377
- { total: 0, emails: 0, phones: 0 }
113378
- );
113795
+ if (!countResponse) return { total: 0, emails: 0, phones: 0 };
113796
+ const total2 = countResponse.count || 0;
113797
+ const responseWithCounts = countResponse;
113798
+ if (responseWithCounts.emailCount !== void 0 && responseWithCounts.phoneCount !== void 0) {
113799
+ return {
113800
+ total: total2,
113801
+ emails: responseWithCounts.emailCount,
113802
+ phones: responseWithCounts.phoneCount
113803
+ };
113804
+ }
113805
+ const recipientSample = countResponse.recipients || [];
113806
+ const emails = recipientSample.filter((user2) => user2.email).length;
113807
+ const phones = recipientSample.filter((user2) => user2.phone).length;
113808
+ const sampleSize = recipientSample.length;
113809
+ let estimatedEmails = 0;
113810
+ let estimatedPhones = 0;
113811
+ if (sampleSize > 0 && total2 > 0) {
113812
+ const emailRatio = emails / sampleSize;
113813
+ const phoneRatio = phones / sampleSize;
113814
+ estimatedEmails = Math.round(total2 * emailRatio);
113815
+ estimatedPhones = Math.round(total2 * phoneRatio);
113816
+ } else if (total2 === 0) {
113817
+ estimatedEmails = 0;
113818
+ estimatedPhones = 0;
113819
+ } else {
113820
+ estimatedEmails = 0;
113821
+ estimatedPhones = 0;
113822
+ }
113823
+ return {
113824
+ total: total2,
113825
+ emails: estimatedEmails,
113826
+ phones: estimatedPhones
113827
+ };
113379
113828
  }, [countResponse]);
113380
- const calculatePercentage = (value) => Math.round(value / (stats.total || 1) * 100);
113829
+ const calculatePercentage = (value) => {
113830
+ if (stats.total === 0) return 0;
113831
+ return Math.round(value / stats.total * 100);
113832
+ };
113381
113833
  const showReassuranceBanner = stats.total > Math.max(stats.emails, stats.phones);
113382
113834
  return /* @__PURE__ */ jsxs(Fragment$1, { children: [
113383
113835
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
@@ -113401,7 +113853,7 @@ const EstimatedMatchesView = ({
113401
113853
  }
113402
113854
  )
113403
113855
  ] }) }),
113404
- /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 md:grid-cols-3 md:mb-6 w-full gap-4 mt-3 px-1", children: [
113856
+ /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 lg:mb-6 w-full gap-3 sm:gap-4 mt-3 px-1 items-stretch", children: [
113405
113857
  /* @__PURE__ */ jsx(
113406
113858
  StatCard,
113407
113859
  {
@@ -113418,7 +113870,8 @@ const EstimatedMatchesView = ({
113418
113870
  {
113419
113871
  count: 2
113420
113872
  }
113421
- ).toLocaleLowerCase()} who might have opted out of email or sms.`
113873
+ ).toLocaleLowerCase()} who might have opted out of email or sms.`,
113874
+ icon: IconDefinitions.UsersIcon
113422
113875
  }
113423
113876
  ),
113424
113877
  /* @__PURE__ */ jsx(
@@ -113430,7 +113883,8 @@ const EstimatedMatchesView = ({
113430
113883
  variant: "blue",
113431
113884
  isLoading: isLoading || countResponse === void 0,
113432
113885
  selected: selectedFilter === "email",
113433
- onClick: onFilterChange ? () => onFilterChange("email") : void 0
113886
+ onClick: onFilterChange ? () => onFilterChange("email") : void 0,
113887
+ icon: IconDefinitions.EmailIcon
113434
113888
  }
113435
113889
  ),
113436
113890
  /* @__PURE__ */ jsx(
@@ -113442,7 +113896,8 @@ const EstimatedMatchesView = ({
113442
113896
  variant: "green",
113443
113897
  isLoading: isLoading || countResponse === void 0,
113444
113898
  selected: selectedFilter === "phone",
113445
- onClick: onFilterChange ? () => onFilterChange("phone") : void 0
113899
+ onClick: onFilterChange ? () => onFilterChange("phone") : void 0,
113900
+ icon: IconDefinitions.SmsIcon
113446
113901
  }
113447
113902
  )
113448
113903
  ] })
@@ -113464,11 +113919,11 @@ const AllOrSelectSegmentPicker = ({
113464
113919
  /* @__PURE__ */ jsx(MinorText, { children: "Filter" }),
113465
113920
  !canEditAudience && /* @__PURE__ */ jsx(InfoTooltip, { title: "You cannot edit the audience unless you are in draft mode" })
113466
113921
  ] }),
113467
- /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-3 gap-4 p-1", children: [
113468
- /* @__PURE__ */ jsx("div", { id: "all-users-selector", children: /* @__PURE__ */ jsx(
113922
+ /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 sm:grid-cols-2 xl:grid-cols-3 gap-3 xl:gap-4 px-1", children: [
113923
+ /* @__PURE__ */ jsx("div", { id: "all-users-selector", className: "h-full w-full", children: /* @__PURE__ */ jsx(
113469
113924
  BigSelector,
113470
113925
  {
113471
- className: "h-32",
113926
+ className: "h-full w-full min-h-[6.5rem] xl:min-h-[8rem]",
113472
113927
  onClick: () => handleSelect(AutomationAudienceSelectorType.ALL),
113473
113928
  title: `All ${t$2("engage:user", { count: 2 })}`,
113474
113929
  subtitle: "Send to everyone",
@@ -113478,10 +113933,10 @@ const AllOrSelectSegmentPicker = ({
113478
113933
  hideSelectedText: true
113479
113934
  }
113480
113935
  ) }),
113481
- /* @__PURE__ */ jsx("div", { id: "segments-selector", children: /* @__PURE__ */ jsx(
113936
+ /* @__PURE__ */ jsx("div", { id: "segments-selector", className: "h-full w-full", children: /* @__PURE__ */ jsx(
113482
113937
  BigSelector,
113483
113938
  {
113484
- className: "h-32",
113939
+ className: "h-full w-full min-h-[6.5rem] xl:min-h-[8rem]",
113485
113940
  onClick: () => handleSelect(AutomationAudienceSelectorType.SEGMENTS),
113486
113941
  title: `Select ${t$2("engage:segment", { count: 2 })}`,
113487
113942
  subtitle: `Choose from ${t$2("engage:segment", { count: 2 })}`,
@@ -113491,10 +113946,10 @@ const AllOrSelectSegmentPicker = ({
113491
113946
  hideSelectedText: true
113492
113947
  }
113493
113948
  ) }),
113494
- /* @__PURE__ */ jsx("div", { id: "individual-users-selector", children: /* @__PURE__ */ jsx(
113949
+ /* @__PURE__ */ jsx("div", { id: "individual-users-selector", className: "h-full w-full", children: /* @__PURE__ */ jsx(
113495
113950
  BigSelector,
113496
113951
  {
113497
- className: "h-32",
113952
+ className: "h-full w-full min-h-[6.5rem] xl:min-h-[8rem]",
113498
113953
  onClick: () => handleSelect(AutomationAudienceSelectorType.INDIVIDUAL),
113499
113954
  title: "Select Individual",
113500
113955
  subtitle: `Pick ${t$2("engage:user", { count: 2 }).toLowerCase()} one by one`,
@@ -113510,45 +113965,48 @@ const AllOrSelectSegmentPicker = ({
113510
113965
  const SelectIndividualUsersContent = ({ selectedUserIds, onUserSelectionChange, canEditAudience = true }) => {
113511
113966
  const [tempSelectedUserIds, setTempSelectedUserIds] = useState(selectedUserIds);
113512
113967
  const [allUsersForDropdown, setAllUsersForDropdown] = useState();
113513
- const [isLoadingUsers, setIsLoadingUsers] = useState(true);
113968
+ const [isLoadingUsers, setIsLoadingUsers] = useState(false);
113969
+ const [hasAttemptedFetch, setHasAttemptedFetch] = useState(false);
113514
113970
  const { segments } = useListSegments();
113515
113971
  useEffect(() => {
113516
113972
  setTempSelectedUserIds(selectedUserIds);
113517
113973
  }, [selectedUserIds]);
113518
- useEffect(() => {
113519
- const fetchAllUsers = async () => {
113520
- if (!segments) {
113521
- setIsLoadingUsers(false);
113522
- return;
113523
- }
113524
- if (allUsersForDropdown?.recipients) {
113525
- setIsLoadingUsers(false);
113526
- return;
113527
- }
113974
+ const fetchUsersIfNeeded = React__default.useCallback(async () => {
113975
+ if (hasAttemptedFetch || allUsersForDropdown?.recipients || !segments) {
113976
+ return;
113977
+ }
113978
+ setHasAttemptedFetch(true);
113979
+ setIsLoadingUsers(true);
113980
+ try {
113528
113981
  const allUsersSegment = segments.find(
113529
113982
  (segment2) => segment2.type === BusinessSegmentTypeEnum.ALL_USERS
113530
113983
  );
113531
113984
  if (allUsersSegment) {
113532
- setIsLoadingUsers(true);
113533
- try {
113534
- const allUsersResponse = await getCountOfBusinessAutomationRecipients(
113535
- {
113536
- includeSegments: [allUsersSegment.id],
113537
- excludeSegments: []
113538
- }
113539
- );
113540
- setAllUsersForDropdown(allUsersResponse);
113541
- } catch (error2) {
113542
- console.error("Error fetching all users for dropdown:", error2);
113543
- } finally {
113544
- setIsLoadingUsers(false);
113545
- }
113546
- } else {
113547
- setIsLoadingUsers(false);
113985
+ const allUsersResponse = await getCountOfBusinessAutomationRecipients({
113986
+ includeSegments: [allUsersSegment.id],
113987
+ excludeSegments: []
113988
+ });
113989
+ setAllUsersForDropdown(allUsersResponse);
113548
113990
  }
113549
- };
113550
- fetchAllUsers();
113551
- }, [segments, allUsersForDropdown?.recipients]);
113991
+ } catch (error2) {
113992
+ console.error("Error fetching users for dropdown:", error2);
113993
+ } finally {
113994
+ setIsLoadingUsers(false);
113995
+ }
113996
+ }, [hasAttemptedFetch, allUsersForDropdown?.recipients, segments]);
113997
+ useEffect(() => {
113998
+ if (!allUsersForDropdown?.recipients && segments && !isLoadingUsers) {
113999
+ const timer = setTimeout(() => {
114000
+ fetchUsersIfNeeded();
114001
+ }, 100);
114002
+ return () => clearTimeout(timer);
114003
+ }
114004
+ }, [
114005
+ allUsersForDropdown?.recipients,
114006
+ segments,
114007
+ isLoadingUsers,
114008
+ fetchUsersIfNeeded
114009
+ ]);
113552
114010
  const userOptions = React__default.useMemo(() => {
113553
114011
  if (!allUsersForDropdown?.recipients) return [];
113554
114012
  return allUsersForDropdown.recipients.map((recipient) => {
@@ -113784,29 +114242,127 @@ const AutomationAudienceSelectorMain = ({ title: title2 = "Preview Audience" })
113784
114242
  const [openCreateSegmentDialog, setOpenCreateSegmentDialog] = useState(false);
113785
114243
  const [initialStateSet, setInitialStateSet] = useState(false);
113786
114244
  const [selectedFilter, setSelectedFilter] = useState("all");
114245
+ const [searchQuery, setSearchQuery] = useState("");
114246
+ const [limit, setLimit] = React__default.useState(100);
113787
114247
  const { segments, isLoading } = useListSegments();
113788
114248
  const { updateAutomation: updateAutomation2 } = useUpdateBusinessAutomation(
113789
114249
  automation2?.id ?? ""
113790
114250
  );
113791
- const [countResponse, setCountResponse] = useState(void 0);
113792
- const [isLoadingRecipients, setIsLoadingRecipients] = useState(false);
113793
- const [loadingTimeout, setLoadingTimeout] = useState(null);
113794
- const debouncedSetLoading = useCallback(
113795
- (loading2) => {
113796
- if (loadingTimeout) {
113797
- clearTimeout(loadingTimeout);
113798
- }
113799
- if (loading2) {
113800
- setIsLoadingRecipients(true);
113801
- } else {
113802
- const timeout = setTimeout(() => {
113803
- setIsLoadingRecipients(false);
113804
- }, 100);
113805
- setLoadingTimeout(timeout);
114251
+ const { createSegmentAsync } = useSegment();
114252
+ const { updateSegmentAsync } = useUpdateSegmentDynamic();
114253
+ const countResponse = React__default.useMemo(() => {
114254
+ if (!segments || segments.length === 0) {
114255
+ return void 0;
114256
+ }
114257
+ let totalCount = 0;
114258
+ let emailCount = 0;
114259
+ let phoneCount = 0;
114260
+ includedSegments.forEach((segmentId) => {
114261
+ const segment2 = segments.find((s4) => s4.id === segmentId);
114262
+ if (segment2) {
114263
+ const userCount = Number(segment2.userCount) || 0;
114264
+ const segmentWithCounts = segment2;
114265
+ const email = Number(segmentWithCounts.emailCount) || 0;
114266
+ const phone = Number(segmentWithCounts.phoneCount) || 0;
114267
+ totalCount += userCount;
114268
+ emailCount += email;
114269
+ phoneCount += phone;
114270
+ }
114271
+ });
114272
+ excludedSegments.forEach((segmentId) => {
114273
+ const segment2 = segments.find((s4) => s4.id === segmentId);
114274
+ if (segment2) {
114275
+ const userCount = Number(segment2.userCount) || 0;
114276
+ const segmentWithCounts = segment2;
114277
+ const email = Number(segmentWithCounts.emailCount) || 0;
114278
+ const phone = Number(segmentWithCounts.phoneCount) || 0;
114279
+ totalCount = Math.max(0, totalCount - userCount);
114280
+ emailCount = Math.max(0, emailCount - email);
114281
+ phoneCount = Math.max(0, phoneCount - phone);
113806
114282
  }
113807
- },
113808
- [loadingTimeout]
114283
+ });
114284
+ return {
114285
+ count: totalCount,
114286
+ emailCount,
114287
+ phoneCount,
114288
+ recipients: []
114289
+ };
114290
+ }, [segments, includedSegments, excludedSegments]);
114291
+ React__default.useEffect(() => {
114292
+ setLimit(100);
114293
+ }, [searchQuery, includedSegments, excludedSegments, selectedFilter]);
114294
+ const {
114295
+ data: recipientsData,
114296
+ isLoading: isLoadingRecipients,
114297
+ isFetching: isFetchingRecipients
114298
+ } = useGetCountOfBusinessAutomationRecipientsDebounced(
114299
+ includedSegments,
114300
+ excludedSegments,
114301
+ automation2?.id ?? "",
114302
+ {
114303
+ debounceMs: 500,
114304
+ enabled: !!automation2?.id && initialStateSet && (includedSegments.length > 0 || excludedSegments.length > 0),
114305
+ search: searchQuery,
114306
+ limit,
114307
+ filter: selectedFilter
114308
+ }
114309
+ );
114310
+ const previousRecipientsRef = React__default.useRef([]);
114311
+ const previousFilterRef = React__default.useRef(
114312
+ selectedFilter
113809
114313
  );
114314
+ const [filterChanged, setFilterChanged] = React__default.useState(false);
114315
+ React__default.useEffect(() => {
114316
+ if (previousFilterRef.current !== selectedFilter) {
114317
+ setFilterChanged(true);
114318
+ previousFilterRef.current = selectedFilter;
114319
+ }
114320
+ }, [selectedFilter]);
114321
+ React__default.useEffect(() => {
114322
+ if (recipientsData?.recipients !== void 0) {
114323
+ previousRecipientsRef.current = recipientsData.recipients.map(
114324
+ (recipient) => ({
114325
+ firstName: recipient.firstName ?? "",
114326
+ lastName: recipient.lastName ?? "",
114327
+ email: recipient.email,
114328
+ phone: recipient.phone
114329
+ })
114330
+ );
114331
+ setFilterChanged(false);
114332
+ }
114333
+ }, [recipientsData?.recipients]);
114334
+ const displayRecipients = React__default.useMemo(() => {
114335
+ if (filterChanged) {
114336
+ return [];
114337
+ }
114338
+ if (recipientsData?.recipients !== void 0) {
114339
+ return recipientsData.recipients.map(
114340
+ (recipient) => ({
114341
+ firstName: recipient.firstName ?? "",
114342
+ lastName: recipient.lastName ?? "",
114343
+ email: recipient.email,
114344
+ phone: recipient.phone
114345
+ })
114346
+ );
114347
+ }
114348
+ return previousRecipientsRef.current;
114349
+ }, [recipientsData?.recipients, filterChanged]);
114350
+ const finalCountResponse = React__default.useMemo(() => {
114351
+ if (!countResponse) return void 0;
114352
+ return {
114353
+ // Always use segment-based total count
114354
+ count: countResponse.count,
114355
+ // Always use segment-based email and phone counts (accurate, not limited)
114356
+ emailCount: countResponse.emailCount,
114357
+ phoneCount: countResponse.phoneCount,
114358
+ // Use API recipients for display (filtered by selectedFilter)
114359
+ recipients: recipientsData?.recipients || []
114360
+ };
114361
+ }, [countResponse, recipientsData]);
114362
+ const handleLoadMore = React__default.useCallback(() => {
114363
+ if (isFetchingRecipients || isLoadingRecipients) return;
114364
+ setLimit((prev) => prev + 100);
114365
+ }, [isFetchingRecipients, isLoadingRecipients]);
113810
114366
  const allUsersSelected = includedSegments.length === 1 && excludedSegments.length === 0 && segments?.find(
113811
114367
  (segment2) => segment2.type === BusinessSegmentTypeEnum.ALL_USERS && segment2.id === includedSegments[0]
113812
114368
  ) !== void 0;
@@ -113816,7 +114372,7 @@ const AutomationAudienceSelectorMain = ({ title: title2 = "Preview Audience" })
113816
114372
  useEffect(() => {
113817
114373
  const initializeState = async () => {
113818
114374
  if (automation2 && !initialStateSet && isLoading === false) {
113819
- if (includedSegments.length === 1 && segments.find(
114375
+ if (includedSegments.length === 1 && excludedSegments.length === 0 && segments.find(
113820
114376
  (segment2) => segment2.type === BusinessSegmentTypeEnum.ALL_USERS && segment2.id === includedSegments[0]
113821
114377
  ) !== void 0) {
113822
114378
  setSelectedAudience(AutomationAudienceSelectorType.ALL);
@@ -113838,17 +114394,6 @@ const AutomationAudienceSelectorMain = ({ title: title2 = "Preview Audience" })
113838
114394
  } else {
113839
114395
  setSelectedAudience(AutomationAudienceSelectorType.SEGMENTS);
113840
114396
  }
113841
- debouncedSetLoading(true);
113842
- getCountOfBusinessAutomationRecipients({
113843
- includeSegments: includedSegments,
113844
- excludeSegments: excludedSegments
113845
- }).then((response) => {
113846
- setCountResponse(response);
113847
- debouncedSetLoading(false);
113848
- }).catch((error2) => {
113849
- console.error("Error fetching recipients:", error2);
113850
- debouncedSetLoading(false);
113851
- });
113852
114397
  setInitialStateSet(true);
113853
114398
  }
113854
114399
  };
@@ -113862,8 +114407,7 @@ const AutomationAudienceSelectorMain = ({ title: title2 = "Preview Audience" })
113862
114407
  excludedSegments,
113863
114408
  segments,
113864
114409
  isLoading,
113865
- singleSegment,
113866
- debouncedSetLoading
114410
+ singleSegment
113867
114411
  ]);
113868
114412
  const handleAudienceSelectionChange = async (value) => {
113869
114413
  setSelectedAudience(value);
@@ -113904,7 +114448,7 @@ const AutomationAudienceSelectorMain = ({ title: title2 = "Preview Audience" })
113904
114448
  setSelectedIndividualUserIds(userIds);
113905
114449
  }
113906
114450
  } else {
113907
- const newSegment = await createSegment({
114451
+ const newSegment = await createSegmentAsync({
113908
114452
  name: segmentName,
113909
114453
  description: "One-off segment for individual user selection",
113910
114454
  type: BusinessSegmentTypeEnum.ONE_OFF,
@@ -113928,10 +114472,6 @@ const AutomationAudienceSelectorMain = ({ title: title2 = "Preview Audience" })
113928
114472
  } else if (value === AutomationAudienceSelectorType.SEGMENTS) {
113929
114473
  setIncludedSegments([]);
113930
114474
  setExcludedSegments([]);
113931
- setCountResponse({
113932
- count: 0,
113933
- recipients: []
113934
- });
113935
114475
  }
113936
114476
  };
113937
114477
  const handleAddSegment = (segmentId, type) => {
@@ -113959,24 +114499,27 @@ const AutomationAudienceSelectorMain = ({ title: title2 = "Preview Audience" })
113959
114499
  } catch (error2) {
113960
114500
  }
113961
114501
  if (segment2) {
113962
- const updatedSegment = await updateSegment(segment2.id, {
113963
- conditions: userIds.length > 0 ? [
113964
- {
113965
- field: "userId",
113966
- operator: ConditionOperatorEnumType.EQUALS,
113967
- value: userIds
113968
- }
113969
- ] : [
113970
- {
113971
- field: "userId",
113972
- operator: ConditionOperatorEnumType.EQUALS,
113973
- value: []
113974
- }
113975
- ]
114502
+ const updatedSegment = await updateSegmentAsync({
114503
+ segmentId: segment2.id,
114504
+ params: {
114505
+ conditions: userIds.length > 0 ? [
114506
+ {
114507
+ field: "userId",
114508
+ operator: ConditionOperatorEnumType.EQUALS,
114509
+ value: userIds
114510
+ }
114511
+ ] : [
114512
+ {
114513
+ field: "userId",
114514
+ operator: ConditionOperatorEnumType.EQUALS,
114515
+ value: []
114516
+ }
114517
+ ]
114518
+ }
113976
114519
  });
113977
114520
  segment2 = updatedSegment;
113978
114521
  } else {
113979
- segment2 = await createSegment({
114522
+ segment2 = await createSegmentAsync({
113980
114523
  name: segmentName,
113981
114524
  description: "One-off segment for individual user selection",
113982
114525
  type: BusinessSegmentTypeEnum.ONE_OFF,
@@ -114001,13 +114544,6 @@ const AutomationAudienceSelectorMain = ({ title: title2 = "Preview Audience" })
114001
114544
  excludeSegments: []
114002
114545
  });
114003
114546
  await new Promise((resolve) => setTimeout(resolve, 100));
114004
- debouncedSetLoading(true);
114005
- const countResponse2 = await getCountOfBusinessAutomationRecipients({
114006
- includeSegments: [segment2.id],
114007
- excludeSegments: []
114008
- });
114009
- setCountResponse(countResponse2);
114010
- debouncedSetLoading(false);
114011
114547
  }
114012
114548
  } catch (error2) {
114013
114549
  console.error("Error creating/updating ONE_OFF segment:", error2);
@@ -114015,120 +114551,128 @@ const AutomationAudienceSelectorMain = ({ title: title2 = "Preview Audience" })
114015
114551
  }
114016
114552
  };
114017
114553
  useEffect(() => {
114018
- if (automation2 && initialStateSet) {
114019
- if (selectedAudience === AutomationAudienceSelectorType.INDIVIDUAL && includedSegments.length === 0 && excludedSegments.length === 0) {
114020
- return;
114021
- }
114022
- if (JSON.stringify(includedSegments) !== JSON.stringify(automation2.includeSegmentIds) || JSON.stringify(excludedSegments) !== JSON.stringify(automation2.excludeSegmentIds)) {
114023
- updateAutomation2({
114024
- includeSegments: includedSegments,
114025
- excludeSegments: excludedSegments
114026
- });
114027
- debouncedSetLoading(true);
114028
- getCountOfBusinessAutomationRecipients({
114029
- includeSegments: includedSegments,
114030
- excludeSegments: excludedSegments
114031
- }).then((response) => {
114032
- setCountResponse(response);
114033
- debouncedSetLoading(false);
114034
- }).catch((error2) => {
114035
- console.error("Error fetching recipients:", error2);
114036
- debouncedSetLoading(false);
114037
- });
114038
- }
114554
+ if (!automation2?.id || !initialStateSet) {
114555
+ return;
114556
+ }
114557
+ if (selectedAudience === AutomationAudienceSelectorType.INDIVIDUAL && includedSegments.length === 0 && excludedSegments.length === 0) {
114558
+ return;
114559
+ }
114560
+ const currentIncluded = [...includedSegments].sort().join(",");
114561
+ const currentExcluded = [...excludedSegments].sort().join(",");
114562
+ const savedIncluded = [...automation2.includeSegmentIds || []].sort().join(",");
114563
+ const savedExcluded = [...automation2.excludeSegmentIds || []].sort().join(",");
114564
+ if (currentIncluded !== savedIncluded || currentExcluded !== savedExcluded) {
114565
+ updateAutomation2({
114566
+ includeSegments: includedSegments,
114567
+ excludeSegments: excludedSegments
114568
+ });
114039
114569
  }
114040
114570
  }, [
114041
114571
  includedSegments,
114042
114572
  excludedSegments,
114043
- automation2,
114573
+ automation2?.includeSegmentIds,
114574
+ automation2?.excludeSegmentIds,
114575
+ automation2?.id,
114044
114576
  initialStateSet,
114045
114577
  updateAutomation2,
114046
- selectedAudience,
114047
- debouncedSetLoading
114578
+ selectedAudience
114048
114579
  ]);
114049
114580
  const onSegmentUpdated = (id2) => {
114050
114581
  if (id2) {
114051
114582
  setIncludedSegments((prev) => [...prev, id2]);
114052
114583
  }
114053
114584
  };
114054
- React__default.useEffect(() => {
114055
- return () => {
114056
- if (loadingTimeout) {
114057
- clearTimeout(loadingTimeout);
114058
- }
114059
- };
114060
- }, [loadingTimeout]);
114061
114585
  const canEditAudience = automation2?.status === AutomationStatus.DRAFT;
114062
114586
  return /* @__PURE__ */ jsxs(MainPageWrapper, { title: title2, children: [
114063
- isLoading || !segments || !initialStateSet ? /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(BasicLoader, { text: ["Fetching segments", "Finishing up"] }) }) : /* @__PURE__ */ jsxs("div", { className: "flex gap-6 w-full pb-4 px-4 min-h-0", children: [
114064
- /* @__PURE__ */ jsxs("div", { className: "w-1/2 min-h-0 flex flex-col gap-6", children: [
114065
- /* @__PURE__ */ jsx(
114066
- EstimatedMatchesView,
114067
- {
114068
- countResponse,
114069
- selectedFilter,
114070
- onFilterChange: setSelectedFilter,
114071
- isLoading: isLoadingRecipients
114072
- }
114073
- ),
114074
- /* @__PURE__ */ jsx(
114075
- AllOrSelectSegmentPicker,
114076
- {
114077
- onSelectionChange: handleAudienceSelectionChange,
114078
- defaultValue: selectedAudience,
114079
- canEditAudience
114080
- }
114081
- ),
114082
- /* @__PURE__ */ jsx(AnimatePresence, { children: selectedAudience === AutomationAudienceSelectorType.SEGMENTS && /* @__PURE__ */ jsx(
114083
- motion.div,
114084
- {
114085
- initial: { opacity: 0, height: 0 },
114086
- animate: { opacity: 1, height: "auto" },
114087
- exit: { opacity: 0, height: 0 },
114088
- transition: { duration: 0.3, ease: "easeInOut" },
114089
- className: "w-full",
114090
- children: /* @__PURE__ */ jsx(
114091
- SelectSegmentsContent,
114587
+ isLoading || !segments || !initialStateSet ? /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(BasicLoader, { text: ["Fetching segments", "Finishing up"] }) }) : /* @__PURE__ */ jsxs("div", { className: "flex flex-col md:flex-row gap-4 md:gap-6 w-full pb-4 px-4 min-h-0", children: [
114588
+ /* @__PURE__ */ jsxs(
114589
+ "div",
114590
+ {
114591
+ className: "w-full md:w-1/2 flex flex-col gap-4 md:gap-6 overflow-y-auto",
114592
+ style: { maxHeight: "calc(100vh - 350px)" },
114593
+ children: [
114594
+ /* @__PURE__ */ jsx(
114595
+ EstimatedMatchesView,
114092
114596
  {
114093
- canEditAudience,
114094
- includedSegments,
114095
- excludedSegments,
114096
- handleAddSegment,
114097
- handleRemoveSegment,
114098
- setOpenCreateSegmentDialog,
114099
- segments,
114100
- defaultIsExcludeOpen: excludedSegments.length > 0
114597
+ countResponse: finalCountResponse,
114598
+ selectedFilter,
114599
+ onFilterChange: setSelectedFilter,
114600
+ isLoading
114101
114601
  }
114102
- )
114103
- }
114104
- ) }),
114105
- /* @__PURE__ */ jsx(AnimatePresence, { children: selectedAudience === AutomationAudienceSelectorType.INDIVIDUAL && /* @__PURE__ */ jsx(
114106
- motion.div,
114107
- {
114108
- initial: { opacity: 0, height: 0 },
114109
- animate: { opacity: 1, height: "auto" },
114110
- exit: { opacity: 0, height: 0 },
114111
- transition: { duration: 0.3, ease: "easeInOut" },
114112
- className: "w-full",
114113
- children: /* @__PURE__ */ jsx(
114114
- SelectIndividualUsersContent,
114602
+ ),
114603
+ /* @__PURE__ */ jsx(
114604
+ AllOrSelectSegmentPicker,
114115
114605
  {
114116
- countResponse,
114117
- selectedUserIds: selectedIndividualUserIds,
114118
- onUserSelectionChange: handleIndividualUserSelectionChange,
114606
+ onSelectionChange: handleAudienceSelectionChange,
114607
+ defaultValue: selectedAudience,
114119
114608
  canEditAudience
114120
114609
  }
114121
- )
114122
- }
114123
- ) })
114124
- ] }),
114125
- /* @__PURE__ */ jsx("div", { className: "w-1/2 min-h-0 flex flex-col", children: /* @__PURE__ */ jsx(
114610
+ ),
114611
+ /* @__PURE__ */ jsx(AnimatePresence, { children: selectedAudience === AutomationAudienceSelectorType.SEGMENTS && /* @__PURE__ */ jsx(
114612
+ motion.div,
114613
+ {
114614
+ initial: { opacity: 0, height: 0 },
114615
+ animate: { opacity: 1, height: "auto" },
114616
+ exit: { opacity: 0, height: 0 },
114617
+ transition: { duration: 0.3, ease: "easeInOut" },
114618
+ className: "w-full",
114619
+ children: /* @__PURE__ */ jsx(
114620
+ SelectSegmentsContent,
114621
+ {
114622
+ canEditAudience,
114623
+ includedSegments,
114624
+ excludedSegments,
114625
+ handleAddSegment,
114626
+ handleRemoveSegment,
114627
+ setOpenCreateSegmentDialog,
114628
+ segments,
114629
+ defaultIsExcludeOpen: excludedSegments.length > 0
114630
+ }
114631
+ )
114632
+ }
114633
+ ) }),
114634
+ /* @__PURE__ */ jsx(AnimatePresence, { children: selectedAudience === AutomationAudienceSelectorType.INDIVIDUAL && /* @__PURE__ */ jsx(
114635
+ motion.div,
114636
+ {
114637
+ initial: { opacity: 0, height: 0 },
114638
+ animate: { opacity: 1, height: "auto" },
114639
+ exit: { opacity: 0, height: 0 },
114640
+ transition: { duration: 0.3, ease: "easeInOut" },
114641
+ className: "w-full",
114642
+ children: /* @__PURE__ */ jsx(
114643
+ SelectIndividualUsersContent,
114644
+ {
114645
+ countResponse,
114646
+ selectedUserIds: selectedIndividualUserIds,
114647
+ onUserSelectionChange: handleIndividualUserSelectionChange,
114648
+ canEditAudience
114649
+ }
114650
+ )
114651
+ }
114652
+ ) })
114653
+ ]
114654
+ }
114655
+ ),
114656
+ /* @__PURE__ */ jsx("div", { className: "w-full md:w-1/2 min-h-0 flex flex-col", children: /* @__PURE__ */ jsx(
114126
114657
  RecipientsTable,
114127
114658
  {
114128
- recipients: countResponse?.recipients || [],
114659
+ recipients: displayRecipients,
114129
114660
  filter: selectedFilter,
114130
114661
  audienceMode: selectedAudience,
114131
- isLoading: isLoadingRecipients
114662
+ isLoading: (
114663
+ // Show loading if:
114664
+ // 1. Initial load (no previous recipients)
114665
+ // 2. Filter changed and we're fetching new data
114666
+ isLoadingRecipients && previousRecipientsRef.current.length === 0 || filterChanged && isFetchingRecipients
114667
+ ),
114668
+ totalCount: selectedFilter === "email" ? finalCountResponse?.emailCount : selectedFilter === "phone" ? finalCountResponse?.phoneCount : finalCountResponse?.count,
114669
+ searchQuery,
114670
+ onSearchChange: setSearchQuery,
114671
+ onLoadMore: handleLoadMore,
114672
+ isLoadingMore: (
114673
+ // Only show bottom loading indicator if filter hasn't changed (pagination)
114674
+ isFetchingRecipients && !filterChanged
114675
+ )
114132
114676
  }
114133
114677
  ) })
114134
114678
  ] }),
@@ -117176,7 +117720,12 @@ const EngageMain = () => {
117176
117720
  queryKey: automationKeys.list()
117177
117721
  });
117178
117722
  queryClient.prefetchQuery({
117179
- queryKey: segmentKeys.lists()
117723
+ queryKey: segmentKeys.lists(),
117724
+ queryFn: () => getSegments()
117725
+ });
117726
+ queryClient.prefetchQuery({
117727
+ queryKey: segmentKeys.lists({ limit: 10 }),
117728
+ queryFn: () => getSegments({ limit: 10 })
117180
117729
  });
117181
117730
  }, [queryClient]);
117182
117731
  useEffect(() => {
@@ -121139,9 +121688,21 @@ const BasicsButton = ({
121139
121688
  const SegmentPill = ({
121140
121689
  segmentName,
121141
121690
  segmentId,
121142
- onClick
121691
+ onClick,
121692
+ variant = "default"
121143
121693
  }) => {
121144
121694
  const isClickable = segmentId && onClick;
121695
+ const getVariantStyles = () => {
121696
+ switch (variant) {
121697
+ case "included":
121698
+ return "bg-blue-50 border-blue-200 text-blue-700 hover:bg-blue-100 hover:border-blue-300";
121699
+ case "excluded":
121700
+ return "bg-red-50 border-red-200 text-red-700 hover:bg-red-100 hover:border-red-300";
121701
+ default:
121702
+ return "bg-white border-gray-200 text-gray-700 hover:bg-gray-50 hover:border-gray-300";
121703
+ }
121704
+ };
121705
+ const baseStyles = `inline-flex items-center border rounded-md px-1.5 py-0.5 text-xs font-medium shadow-sm transition-colors ${getVariantStyles()}`;
121145
121706
  if (isClickable) {
121146
121707
  return /* @__PURE__ */ jsx(
121147
121708
  "button",
@@ -121149,12 +121710,12 @@ const SegmentPill = ({
121149
121710
  onClick: () => {
121150
121711
  onClick(segmentId);
121151
121712
  },
121152
- className: "inline-flex items-center bg-white border border-gray-200 rounded-md px-2 py-0.5 text-sm font-medium shadow-sm hover:bg-gray-50 hover:border-gray-300 transition-colors cursor-pointer",
121713
+ className: `${baseStyles} cursor-pointer`,
121153
121714
  children: segmentName
121154
121715
  }
121155
121716
  );
121156
121717
  }
121157
- return /* @__PURE__ */ jsx("span", { className: "inline-flex items-center bg-white border border-gray-200 rounded-md px-2 py-0.5 text-sm font-medium shadow-sm", children: segmentName });
121718
+ return /* @__PURE__ */ jsx("span", { className: baseStyles, children: segmentName });
121158
121719
  };
121159
121720
  const AutomationAudienceSelector = () => {
121160
121721
  const automation2 = useAutomation();
@@ -121175,6 +121736,7 @@ const AutomationAudienceSelector = () => {
121175
121736
  return null;
121176
121737
  }
121177
121738
  const includeSegmentIds = automation2.includeSegmentIds;
121739
+ const excludeSegmentIds = automation2.excludeSegmentIds;
121178
121740
  let copyText;
121179
121741
  let showSegmentPills = true;
121180
121742
  if (singleSegment?.type === BusinessSegmentTypeEnum.ALL_USERS) {
@@ -121207,21 +121769,55 @@ const AutomationAudienceSelector = () => {
121207
121769
  Icon: IconDefinitions.AudienceIcon,
121208
121770
  children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-0.5 flex-1", children: [
121209
121771
  /* @__PURE__ */ jsx(MinorText, { children: "Audience" }),
121210
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
121211
- /* @__PURE__ */ jsx(AutomationFlowLabel, { copyText }),
121212
- showSegmentPills && /* @__PURE__ */ jsx("div", { className: "flex gap-1", children: includeSegmentIds.map((id2) => {
121213
- const segment2 = segments?.find((segment22) => segment22.id === id2);
121214
- if (!segment2) return null;
121215
- return /* @__PURE__ */ jsx(
121216
- SegmentPill,
121772
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
121773
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
121774
+ /* @__PURE__ */ jsx(AutomationFlowLabel, { copyText }),
121775
+ showSegmentPills && /* @__PURE__ */ jsx("div", { className: "flex gap-1", children: includeSegmentIds.map((id2) => {
121776
+ const segment2 = segments?.find(
121777
+ (segment22) => segment22.id === id2
121778
+ );
121779
+ if (!segment2) return null;
121780
+ return /* @__PURE__ */ jsx(
121781
+ SegmentPill,
121782
+ {
121783
+ segmentName: segment2.name,
121784
+ segmentId: id2,
121785
+ onClick: handleSegmentClick,
121786
+ variant: "included"
121787
+ },
121788
+ id2
121789
+ );
121790
+ }) })
121791
+ ] }),
121792
+ excludeSegmentIds && excludeSegmentIds.length > 0 && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
121793
+ /* @__PURE__ */ jsx(
121794
+ AutomationFlowLabel,
121217
121795
  {
121218
- segmentName: segment2.name,
121219
- segmentId: id2,
121220
- onClick: handleSegmentClick
121221
- },
121222
- id2
121223
- );
121224
- }) })
121796
+ copyText: `Excluding ${excludeSegmentIds.length === 1 ? "this" : "these"} ${t$2(
121797
+ "engage:segment",
121798
+ {
121799
+ count: excludeSegmentIds.length
121800
+ }
121801
+ ).toLowerCase()}`
121802
+ }
121803
+ ),
121804
+ /* @__PURE__ */ jsx("div", { className: "flex gap-1", children: excludeSegmentIds.map((id2) => {
121805
+ const segment2 = segments?.find(
121806
+ (segment22) => segment22.id === id2
121807
+ );
121808
+ if (!segment2) return null;
121809
+ return /* @__PURE__ */ jsx(
121810
+ SegmentPill,
121811
+ {
121812
+ segmentName: segment2.name,
121813
+ segmentId: id2,
121814
+ onClick: handleSegmentClick,
121815
+ variant: "excluded"
121816
+ },
121817
+ id2
121818
+ );
121819
+ }) })
121820
+ ] })
121225
121821
  ] })
121226
121822
  ] })
121227
121823
  }
@@ -122114,8 +122710,8 @@ const AutomationsEditorSidebar = ({
122114
122710
  hideSms
122115
122711
  }) => {
122116
122712
  const automation2 = useAutomation();
122117
- const { segments, isLoading } = useListSegments();
122118
- if (!automation2 || isLoading || segments.length === 0) {
122713
+ const { segments } = useListSegments();
122714
+ if (!automation2) {
122119
122715
  return /* @__PURE__ */ jsx("div", { className: "flex h-full items-center justify-center", children: /* @__PURE__ */ jsx(
122120
122716
  BasicLoader,
122121
122717
  {
@@ -123624,6 +124220,7 @@ const ViewAutomationMain = ({
123624
124220
  const { updateCommunicationGroup: updateCommunicationGroup2 } = useUpdateCommunicationGroup();
123625
124221
  const { toast: toast2 } = useToast();
123626
124222
  const { channelSenders } = useChannelSender();
124223
+ const { isLoading: isLoadingSegments } = useListSegments();
123627
124224
  const previousMergeFieldsRef = useRef("");
123628
124225
  const hasInitializedMergeFieldsRef = useRef(false);
123629
124226
  const hasInitializedChannelSendersRef = useRef(false);
@@ -123709,7 +124306,7 @@ const ViewAutomationMain = ({
123709
124306
  channelSenders,
123710
124307
  updateCommunicationGroup2
123711
124308
  ]);
123712
- if (!automation2 || !communicationGroup) {
124309
+ if (!automation2 || !communicationGroup || isLoadingSegments) {
123713
124310
  return /* @__PURE__ */ jsx("div", { className: "flex h-full items-center justify-center", children: /* @__PURE__ */ jsx(
123714
124311
  BasicLoader,
123715
124312
  {