@embedreach/components 0.3.11 → 0.3.13

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.
@@ -12,6 +12,7 @@ const WEBSITE_BRAND_SETTINGS_PATH = `${WEB_PRESENCE_PATH}/brand-settings`;
12
12
  const CHANNEL_SENDER_PATH = "/channel/senders";
13
13
  const CHANNEL_ACCOUNT_PATH = "/channel/accounts";
14
14
  const COMMUNICATION_GROUP_PATH = "/communication-groups";
15
+ const PARTNER_ME_PATH = "/partners/me";
15
16
  const STRIPO_PATH = "/stripo";
16
17
  const SLACK_NOTIFICATION_PATH = "/slack-notifications";
17
18
  const TELEMETRY_PATH = "/telemetry";
@@ -2553,6 +2554,14 @@ let EventEmitter$2 = class EventEmitter {
2553
2554
  }
2554
2555
  };
2555
2556
  const eventEmitter = new EventEmitter$2();
2557
+ const CACHE_INFINITY = {
2558
+ // Never mark data as stale
2559
+ staleTime: Infinity,
2560
+ // Never remove data from cache
2561
+ gcTime: Infinity,
2562
+ // No need to revalidate on window focus for permanent data
2563
+ refetchOnWindowFocus: false
2564
+ };
2556
2565
  const CACHE_STANDARD = {
2557
2566
  // Consider data stale after 5 minutes
2558
2567
  staleTime: 5 * 60 * 1e3,
@@ -28808,6 +28817,40 @@ const DEFAULT_THEME_STYLES = {
28808
28817
  "font-body": 'Inter, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
28809
28818
  "font-heading": '"Plus Jakarta Sans", system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif'
28810
28819
  };
28820
+ const DEFAULT_DARK_THEME_STYLES = {
28821
+ background: "240 6% 10%",
28822
+ // Very dark gray
28823
+ foreground: "0 0% 98%",
28824
+ // Near white
28825
+ card: "240 6% 12%",
28826
+ "card-foreground": "0 0% 98%",
28827
+ popover: "240 6% 12%",
28828
+ "popover-foreground": "0 0% 98%",
28829
+ primary: "210 30% 88%",
28830
+ // Light slate
28831
+ "primary-foreground": "240 6% 10%",
28832
+ secondary: "240 4% 20%",
28833
+ // Muted dark
28834
+ "secondary-foreground": "0 0% 98%",
28835
+ muted: "240 4% 16%",
28836
+ "muted-foreground": "220 10% 65%",
28837
+ accent: "210 15% 24%",
28838
+ "accent-foreground": "0 0% 98%",
28839
+ destructive: "0 62% 54%",
28840
+ // Softer red for dark
28841
+ "destructive-foreground": "0 0% 98%",
28842
+ border: "240 4% 20%",
28843
+ input: "240 4% 20%",
28844
+ ring: "210 30% 88%",
28845
+ "chart-1": "210 50% 70%",
28846
+ "chart-2": "260 50% 75%",
28847
+ "chart-3": "150 50% 65%",
28848
+ "chart-4": "325 50% 75%",
28849
+ "chart-5": "45 80% 75%",
28850
+ radius: "0.625rem",
28851
+ "font-body": 'Inter, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
28852
+ "font-heading": '"Plus Jakarta Sans", system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif'
28853
+ };
28811
28854
  const normalizeColor = (color2) => {
28812
28855
  const div = document.createElement("div");
28813
28856
  div.style.color = color2;
@@ -29196,14 +29239,14 @@ const tailwindToHsl = (tailwindClass) => {
29196
29239
  const [r2, g2, b3] = colorMap[color2][shade];
29197
29240
  return rgbToShadcnHsl(r2, g2, b3);
29198
29241
  };
29199
- const applyThemeStyles = (styles2) => {
29242
+ const applyThemeStyles = (styles2, darkStyles) => {
29200
29243
  const existingStyles = document.getElementById("reach-theme-styles");
29201
29244
  if (existingStyles) {
29202
29245
  existingStyles.remove();
29203
29246
  }
29204
29247
  const styleElement2 = document.createElement("style");
29205
29248
  styleElement2.id = "reach-theme-styles";
29206
- const cssText = `
29249
+ let cssText = `
29207
29250
  [data-reach-root] {
29208
29251
  ${Object.entries(DEFAULT_THEME_STYLES).map(([key, defaultValue]) => {
29209
29252
  const userValue = styles2[key];
@@ -29245,9 +29288,61 @@ const applyThemeStyles = (styles2) => {
29245
29288
  font-family: var(--reach-font-heading);
29246
29289
  }
29247
29290
  `;
29291
+ if (darkStyles) {
29292
+ cssText += `
29293
+ .dark [data-reach-root] {
29294
+ ${Object.entries(DEFAULT_DARK_THEME_STYLES).map(([key, defaultValue]) => {
29295
+ const userValue = darkStyles[key];
29296
+ let finalValue = defaultValue;
29297
+ if (userValue !== void 0) {
29298
+ if (key === "radius" || key === "font-body" || key === "font-heading") {
29299
+ finalValue = userValue;
29300
+ } else if (isValidColor(userValue)) {
29301
+ const isTailwindClass = /^bg-/.test(userValue.trim()) && userValue.trim() !== "bg-inherit" && userValue.trim() !== "bg-current" && userValue.trim() !== "bg-transparent";
29302
+ if (isTailwindClass) {
29303
+ const className = userValue.replace(/['"]/g, "").trim();
29304
+ finalValue = tailwindToHsl(className);
29305
+ } else {
29306
+ try {
29307
+ finalValue = toShadcnFormat(userValue);
29308
+ } catch (e4) {
29309
+ console.warn(
29310
+ `Failed to convert dark color for ${key}, using default`
29311
+ );
29312
+ }
29313
+ }
29314
+ }
29315
+ }
29316
+ return `--reach-${key}: ${finalValue};`;
29317
+ }).join("\n")}
29318
+ }
29319
+
29320
+ .dark [data-reach-root] {
29321
+ font-family: var(--reach-font-body);
29322
+ }
29323
+ .dark [data-reach-root] h1,
29324
+ .dark [data-reach-root] h2,
29325
+ .dark [data-reach-root] h3,
29326
+ .dark [data-reach-root] h4,
29327
+ .dark [data-reach-root] h5,
29328
+ .dark [data-reach-root] h6 {
29329
+ font-family: var(--reach-font-heading);
29330
+ }
29331
+ `;
29332
+ }
29248
29333
  styleElement2.textContent = cssText;
29249
29334
  document.head.appendChild(styleElement2);
29250
29335
  };
29336
+ const mergeThemeStyles = ({
29337
+ partnerThemeConfig,
29338
+ userOverrides
29339
+ } = {}) => {
29340
+ return {
29341
+ ...DEFAULT_THEME_STYLES,
29342
+ ...partnerThemeConfig?.styles || {},
29343
+ ...userOverrides || {}
29344
+ };
29345
+ };
29251
29346
  const themeReducer = (state, action) => {
29252
29347
  switch (action.type) {
29253
29348
  case "set_theme":
@@ -29288,18 +29383,59 @@ const { Context: Context$3, Provider: BaseProvider } = createDataContext(
29288
29383
  error: null
29289
29384
  }
29290
29385
  );
29386
+ const getPartner = async () => {
29387
+ const response = await baseRequest(PARTNER_ME_PATH);
29388
+ return response.data;
29389
+ };
29390
+ const partnerQueryKey = ["partner"];
29391
+ const usePartner = () => {
29392
+ const query = useQuery({
29393
+ queryKey: partnerQueryKey,
29394
+ queryFn: getPartner,
29395
+ ...CACHE_INFINITY
29396
+ });
29397
+ return query;
29398
+ };
29291
29399
  const ThemeInitializer = ({ initialTheme, children }) => {
29292
29400
  const { setTheme: setTheme2, setLoading: setLoading2 } = React__default.useContext(Context$3);
29401
+ const { data: partnerData, isLoading: isPartnerLoading } = usePartner();
29293
29402
  const themeApplied = useRef(false);
29294
29403
  useEffect(() => {
29295
- if (initialTheme && !themeApplied.current) {
29296
- applyThemeStyles(initialTheme.styles);
29297
- setTheme2(initialTheme);
29404
+ if (isPartnerLoading) {
29405
+ return;
29406
+ }
29407
+ if (!themeApplied.current) {
29408
+ const mergedStyles = mergeThemeStyles({
29409
+ partnerThemeConfig: partnerData?.theme_config,
29410
+ userOverrides: initialTheme?.styles
29411
+ });
29412
+ let mergedDarkStyles = void 0;
29413
+ const darkMode = partnerData?.theme_config?.darkMode || initialTheme?.darkMode;
29414
+ if (darkMode) {
29415
+ mergedDarkStyles = mergeThemeStyles({
29416
+ partnerThemeConfig: {
29417
+ styles: {
29418
+ ...DEFAULT_DARK_THEME_STYLES,
29419
+ ...partnerData?.theme_config?.styles || {}
29420
+ }
29421
+ },
29422
+ userOverrides: initialTheme?.styles
29423
+ });
29424
+ document.documentElement.classList.add("dark");
29425
+ } else {
29426
+ document.documentElement.classList.remove("dark");
29427
+ }
29428
+ applyThemeStyles(mergedStyles, mergedDarkStyles);
29429
+ const finalTheme = {
29430
+ styles: mergedStyles,
29431
+ darkMode
29432
+ };
29433
+ setTheme2(finalTheme);
29298
29434
  themeApplied.current = true;
29299
29435
  } else {
29300
29436
  setLoading2(false);
29301
29437
  }
29302
- }, [initialTheme, setTheme2, setLoading2]);
29438
+ }, [initialTheme, partnerData, isPartnerLoading, setTheme2, setLoading2]);
29303
29439
  return /* @__PURE__ */ jsx(Fragment$1, { children });
29304
29440
  };
29305
29441
  const Provider$4 = ({ initialTheme, children }) => {
@@ -32157,6 +32293,8 @@ const measure$1 = {
32157
32293
  missing_website_tracking_banner_title: "Metrics are being processed",
32158
32294
  missing_website_tracking_banner_description: "We're preparing your dashboard and calculating your metrics. To see accurate campaign performance, please ensure tracking is set up on your website. This could take a few hours to a few days to complete but your data will be available soon.",
32159
32295
  missing_website_tracking_banner_action: "Setup Tracking On My Website",
32296
+ update_meta_ads_tracking_banner_title: "Update Your Meta Ads Tracking Parameters",
32297
+ update_meta_ads_tracking_banner_description: "Some of your Meta ads are missing our required tracking parameters for proper attribution. Please update them as soon as possible to ensure accurate attribution.",
32160
32298
  reach_managed_campaign_banner_title: "Campaign Data Processing",
32161
32299
  reach_managed_campaign_banner_description: "Your latest ad campaign data is currently being processed and will be available soon."
32162
32300
  },
@@ -32703,6 +32841,8 @@ const measure = {
32703
32841
  missing_website_tracking_banner_title: "Métricas están siendo procesadas",
32704
32842
  missing_website_tracking_banner_description: "Estamos preparando tu panel y calculando tus métricas. Para ver el rendimiento de tus campañas de manera precisa, por favor asegúrate de que el seguimiento esté configurado en tu sitio web. Esto puede tomar unas horas o unos días para completarse, pero tus datos estarán disponibles pronto.",
32705
32843
  missing_website_tracking_banner_action: "Configurar seguimiento en mi sitio web",
32844
+ update_meta_ads_tracking_banner_title: "Actualizar parámetros de seguimiento de anuncios de Meta",
32845
+ update_meta_ads_tracking_banner_description: "Algunos de tus anuncios de Meta están faltando nuestros parámetros de seguimiento requeridos para una atribución precisa. Por favor, actualízalos lo antes posible para garantizar una atribución precisa.",
32706
32846
  reach_managed_campaign_banner_title: "Datos de campaña procesando",
32707
32847
  reach_managed_campaign_banner_description: "Tus datos de campaña de anuncios están siendo procesados y estarán disponibles pronto."
32708
32848
  },
@@ -33314,6 +33454,8 @@ const defaultTranslations = {
33314
33454
  missing_website_tracking_banner_title: "Metrics are being processed",
33315
33455
  missing_website_tracking_banner_description: "We're preparing your dashboard and calculating your metrics. To see accurate campaign performance, please ensure tracking is set up on your website. This could take a few hours to a few days to complete but your data will be available soon.",
33316
33456
  missing_website_tracking_banner_action: "Setup Tracking On My Website",
33457
+ update_meta_ads_tracking_banner_title: "Update Your Meta Ads Tracking Parameters",
33458
+ update_meta_ads_tracking_banner_description: "Some of your Meta ads are missing our required tracking parameters for proper attribution. Please update them as soon as possible to ensure accurate attribution.",
33317
33459
  reach_managed_campaign_banner_title: "Campaign Data Processing",
33318
33460
  reach_managed_campaign_banner_description: "Your latest ad campaign data is currently being processed and will be available soon."
33319
33461
  },
@@ -48989,20 +49131,29 @@ const useValidationStats = () => {
48989
49131
  const { state } = useViewAutomationContext();
48990
49132
  return state.recipientStats;
48991
49133
  };
48992
- const useRecipientStatsTracking = (automation2) => {
48993
- const { setRecipientStats: setRecipientStats2 } = useViewAutomationContext();
49134
+ const useRecipientStatsTracking = (existingAutomation) => {
49135
+ const { setRecipientStats: setRecipientStats2, state } = useViewAutomationContext();
49136
+ const automation2 = state.automation || existingAutomation;
48994
49137
  const { estimatedMatchesStats } = useRecipientStats$1(automation2);
48995
49138
  useEffect(() => {
48996
49139
  if (estimatedMatchesStats) {
48997
49140
  setRecipientStats2(estimatedMatchesStats);
48998
49141
  }
48999
- }, [estimatedMatchesStats, setRecipientStats2]);
49142
+ }, [estimatedMatchesStats, setRecipientStats2, automation2]);
49000
49143
  };
49001
49144
  const ViewAutomationProvider = ({
49002
49145
  automationId,
49146
+ existingAutomation,
49003
49147
  children
49004
49148
  }) => {
49005
- return /* @__PURE__ */ jsx(Provider$2, { children: /* @__PURE__ */ jsx(ViewAutomationContent$1, { automationId, children }) });
49149
+ return /* @__PURE__ */ jsx(Provider$2, { children: /* @__PURE__ */ jsx(
49150
+ ViewAutomationContent$1,
49151
+ {
49152
+ automationId,
49153
+ existingAutomation,
49154
+ children
49155
+ }
49156
+ ) });
49006
49157
  };
49007
49158
  const ViewAutomationContent$1 = ({ automationId, existingAutomation, children }) => {
49008
49159
  useAutomationFetching(automationId);
@@ -91447,7 +91598,7 @@ const getEmailChannelSendersWithChannelAccounts = (args) => {
91447
91598
  (account) => account.id === sender.channelAccountId
91448
91599
  );
91449
91600
  if (!channelAccount) return [];
91450
- if (channelAccount.channelAccountMetadata.type === ChannelAccountTypeEnum.REACH_MANAGED) {
91601
+ if (channelAccount.channelAccountMetadata.type === ChannelAccountTypeEnum.REACH_MANAGED || channelAccount.channelAccountMetadata.type === ChannelAccountTypeEnum.REACH_MANAGED_SES) {
91451
91602
  return [
91452
91603
  {
91453
91604
  channelSenderId: sender.id,
@@ -106785,7 +106936,7 @@ const getAutomationSteps = ({
106785
106936
  ];
106786
106937
  };
106787
106938
  const useRecipientStats = (automation2) => {
106788
- const { data: estimatedMatches } = useGetCountOfBusinessAutomationRecipients({
106939
+ const { data: estimatedMatches, isLoading } = useGetCountOfBusinessAutomationRecipients({
106789
106940
  automationId: automation2?.id ?? "",
106790
106941
  includeSegments: automation2?.includeSegmentIds ?? [],
106791
106942
  excludeSegments: automation2?.excludeSegmentIds ?? []
@@ -106802,7 +106953,8 @@ const useRecipientStats = (automation2) => {
106802
106953
  }, [estimatedMatches?.recipients]);
106803
106954
  return {
106804
106955
  estimatedMatches,
106805
- estimatedMatchesStats
106956
+ estimatedMatchesStats,
106957
+ isLoading
106806
106958
  };
106807
106959
  };
106808
106960
  const DEFAULT_LOGO_URL = "https://assets.embedreach.com/defaults/logo-placeholder-128.png";
@@ -107012,7 +107164,7 @@ const OneTimeWizardMain = ({ onFinish, getExtraMergeFields, onBeforeSchedule })
107012
107164
  const { updateAutomation: updateAutomation2 } = useUpdateBusinessAutomation(
107013
107165
  automation2?.id || ""
107014
107166
  );
107015
- const { estimatedMatchesStats } = useRecipientStats(automation2 ?? void 0);
107167
+ const { estimatedMatchesStats, isLoading: isLoadingRecipientStats } = useRecipientStats(automation2 ?? void 0);
107016
107168
  const {
107017
107169
  state: { selectedChannels }
107018
107170
  } = useContext(Context);
@@ -107101,6 +107253,11 @@ const OneTimeWizardMain = ({ onFinish, getExtraMergeFields, onBeforeSchedule })
107101
107253
  }
107102
107254
  if (onBeforeSchedule) {
107103
107255
  try {
107256
+ let attempts = 0;
107257
+ while (isLoadingRecipientStats && attempts < 10) {
107258
+ await new Promise((resolve) => setTimeout(resolve, 250));
107259
+ attempts++;
107260
+ }
107104
107261
  const result = await onBeforeSchedule({
107105
107262
  estimatedEmailRecipients: estimatedMatchesStats?.emails || 0,
107106
107263
  estimatedSmsRecipients: estimatedMatchesStats?.phones || 0
@@ -107597,7 +107754,8 @@ function CreateAutomationDialog({
107597
107754
  replyToSettingsText,
107598
107755
  replyToSettingsLink,
107599
107756
  fromNameSettingsText,
107600
- fromNameSettingsLink
107757
+ fromNameSettingsLink,
107758
+ onBeforeSchedule
107601
107759
  }) {
107602
107760
  const onCloseInner = (createdAutomation) => {
107603
107761
  onClose?.(createdAutomation);
@@ -107637,7 +107795,8 @@ function CreateAutomationDialog({
107637
107795
  automationType,
107638
107796
  currentStep,
107639
107797
  setCurrentStep,
107640
- getExtraMergeFields
107798
+ getExtraMergeFields,
107799
+ onBeforeSchedule
107641
107800
  }
107642
107801
  )
107643
107802
  ]
@@ -22811,7 +22811,19 @@ const handlers = [
22811
22811
  message: "Success (Sandbox)",
22812
22812
  data: null
22813
22813
  });
22814
- })
22814
+ }),
22815
+ http.get(
22816
+ `${HOSTNAME}/api/ad-platform-tracking/meta/check-for-existing?ad_account_id=sandbox-m-act-789`,
22817
+ async () => {
22818
+ return HttpResponse.json({
22819
+ success: true,
22820
+ message: "Success (Sandbox)",
22821
+ data: {
22822
+ ads_with_tracking: []
22823
+ }
22824
+ });
22825
+ }
22826
+ )
22815
22827
  ];
22816
22828
  const worker = setupWorker(...handlers);
22817
22829
  const MAX_RETRIES = 3;
package/dist/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { default as default_2 } from 'react';
2
2
  import { JSX as JSX_2 } from 'react/jsx-runtime';
3
+ import { ThemeConfig } from '@reach/shared-types/theme';
3
4
 
4
5
  export declare enum AutomationTriggerType {
5
6
  ONE_TIME = "one_time",
@@ -7,7 +8,7 @@ export declare enum AutomationTriggerType {
7
8
  DATE_BASED = "date_based"
8
9
  }
9
10
 
10
- export declare function CreateAutomationDialog({ open, setOpen, onClose, automationType, getExtraMergeFields, replyToSettingsText, replyToSettingsLink, fromNameSettingsText, fromNameSettingsLink, }: CreateAutomationDialogProps): JSX_2.Element;
11
+ export declare function CreateAutomationDialog({ open, setOpen, onClose, automationType, getExtraMergeFields, replyToSettingsText, replyToSettingsLink, fromNameSettingsText, fromNameSettingsLink, onBeforeSchedule, }: CreateAutomationDialogProps): JSX_2.Element;
11
12
 
12
13
  declare interface CreateAutomationDialogProps extends CreateAutomationModalProps {
13
14
  /**
@@ -247,53 +248,7 @@ declare type StaticMergeField = ReachMergeFieldBase & {
247
248
  templateName: string;
248
249
  };
249
250
 
250
- /**
251
- * Theme initialization options that can be passed to ReachProvider
252
- */
253
- export declare interface ThemeConfig {
254
- /** Optional overrides for theme styles */
255
- styles: Partial<ThemeStyles>;
256
- /** Dark mode toggle */
257
- darkMode?: boolean;
258
- }
259
-
260
- /**
261
- * Theme styles incorporating shadcn variables
262
- *
263
- * Matches what we say in our dev docs here:
264
- * https://docs.embedreach.com/sdk/customization
265
- *
266
- * @interface ThemeStyles
267
- */
268
- declare interface ThemeStyles {
269
- background?: string;
270
- foreground?: string;
271
- card?: string;
272
- 'card-foreground'?: string;
273
- popover?: string;
274
- 'popover-foreground'?: string;
275
- primary?: string;
276
- 'primary-foreground'?: string;
277
- secondary?: string;
278
- 'secondary-foreground'?: string;
279
- muted?: string;
280
- 'muted-foreground'?: string;
281
- accent?: string;
282
- 'accent-foreground'?: string;
283
- destructive?: string;
284
- 'destructive-foreground'?: string;
285
- border?: string;
286
- input?: string;
287
- ring?: string;
288
- 'chart-1'?: string;
289
- 'chart-2'?: string;
290
- 'chart-3'?: string;
291
- 'chart-4'?: string;
292
- 'chart-5'?: string;
293
- radius?: string;
294
- 'font-body'?: string;
295
- 'font-heading'?: string;
296
- }
251
+ export { ThemeConfig }
297
252
 
298
253
  export declare const ViewAutomationModal: default_2.FC<ViewAutomationProps & {
299
254
  inRouter?: boolean;