@frak-labs/components 1.0.8 → 1.0.10-beta.1700e6ec

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.
Files changed (50) hide show
  1. package/cdn/Banner.BpIgsa8e.js +167 -0
  2. package/cdn/ButtonShare.QjU-SB2w.js +1 -0
  3. package/cdn/ButtonWallet.BQWezFCP.js +40 -0
  4. package/cdn/GiftIcon.QppqMfWS.js +1 -0
  5. package/cdn/OpenInAppButton.D1UzTuHx.js +1 -0
  6. package/cdn/PostPurchase.DPgGfAjM.js +89 -0
  7. package/cdn/components.js +1 -1
  8. package/cdn/defaults.kWEdCyGS.js +58 -0
  9. package/cdn/embeddedWallet.CDUxjdX2.js +1 -0
  10. package/cdn/loader.js +1 -1
  11. package/cdn/replay-V6FXES7X.CNozpSRg.js +1 -0
  12. package/cdn/rewards.D4VLYzjp.js +1 -0
  13. package/cdn/useGlobalComponents.BC6Jgzg5.js +1 -0
  14. package/cdn/useLightDomStyles.imPXuAtf.js +1 -0
  15. package/cdn/useReward.Cks8uGHY.js +1 -0
  16. package/dist/{GiftIcon-BIp9FTJs.js → GiftIcon-WEWSJ8kV.js} +1 -1
  17. package/dist/banner.d.ts +2 -3
  18. package/dist/banner.js +75 -76
  19. package/dist/buttonShare.d.ts +4 -3
  20. package/dist/buttonShare.js +11 -9
  21. package/dist/buttonWallet.d.ts +1 -2
  22. package/dist/buttonWallet.js +5 -3
  23. package/dist/i18n/defaults.d.ts +54 -0
  24. package/dist/i18n/defaults.js +70 -0
  25. package/dist/openInApp.d.ts +5 -5
  26. package/dist/openInApp.js +7 -5
  27. package/dist/postPurchase.d.ts +2 -3
  28. package/dist/postPurchase.js +28 -16
  29. package/dist/rewards-CsHE1hVo.js +145 -0
  30. package/dist/useGlobalComponents-CZ7Sh2tZ.js +17 -0
  31. package/dist/{useLightDomStyles-C8giLInY.js → useLightDomStyles-DphuQhvx.js} +1 -1
  32. package/dist/{usePlacement-5kbU3BKj.js → usePlacement-4PoDbn2X.js} +122 -22
  33. package/dist/useReward-Br6GKb9Z.js +39 -0
  34. package/package.json +9 -3
  35. package/cdn/Banner.CcOWT4lZ.js +0 -178
  36. package/cdn/ButtonShare.D9-F0jJJ.js +0 -1
  37. package/cdn/ButtonWallet.B0buPR_z.js +0 -40
  38. package/cdn/GiftIcon.eRNTGQ_r.js +0 -1
  39. package/cdn/OpenInAppButton.Dgb-qhM8.js +0 -1
  40. package/cdn/PostPurchase.BYxnAEyn.js +0 -89
  41. package/cdn/embeddedWallet.BS-9u4Be.js +0 -1
  42. package/cdn/formatReward.B1ZyoceC.js +0 -1
  43. package/cdn/replay-V6FXES7X.BoL9fAjx.js +0 -1
  44. package/cdn/useGlobalComponents.TG9kIYSc.js +0 -1
  45. package/cdn/useLightDomStyles.tjNBKcOr.js +0 -1
  46. package/cdn/usePlacement.BgMXY5CX.js +0 -58
  47. package/cdn/useReward.BtBpuMwt.js +0 -1
  48. package/dist/formatReward-Cf2KpA3x.js +0 -33
  49. package/dist/useGlobalComponents-mSs9unyN.js +0 -21
  50. package/dist/useReward-ClVShg45.js +0 -65
@@ -1,9 +1,10 @@
1
- import { a as registerWebComponent, i as useClientReady, s as openSharingPage, t as usePlacement } from "./usePlacement-5kbU3BKj.js";
1
+ import { i as useLang, l as openSharingPage, o as useClientReady, s as registerWebComponent, t as usePlacement } from "./usePlacement-4PoDbn2X.js";
2
2
  import { t as openEmbeddedWallet } from "./embeddedWallet-By3_p5Xc.js";
3
- import { t as useGlobalComponents } from "./useGlobalComponents-mSs9unyN.js";
4
- import { t as useLightDomStyles } from "./useLightDomStyles-C8giLInY.js";
5
- import { t as applyRewardPlaceholder } from "./formatReward-Cf2KpA3x.js";
6
- import { t as useReward } from "./useReward-ClVShg45.js";
3
+ import { t as useGlobalComponents } from "./useGlobalComponents-CZ7Sh2tZ.js";
4
+ import { t as useLightDomStyles } from "./useLightDomStyles-DphuQhvx.js";
5
+ import { r as b } from "./rewards-CsHE1hVo.js";
6
+ import { t as useReward } from "./useReward-Br6GKb9Z.js";
7
+ import { componentDefaults } from "./i18n/defaults.js";
7
8
  import { trackEvent } from "@frak-labs/core-sdk";
8
9
  import { useCallback, useMemo } from "preact/hooks";
9
10
  import { jsx } from "preact/jsx-runtime";
@@ -52,14 +53,15 @@ import { jsx } from "preact/jsx-runtime";
52
53
  * @see {@link @frak-labs/core-sdk!actions.displaySharingPage | `displaySharingPage()`} for more info about the sharing-page flow
53
54
  * @see {@link @frak-labs/core-sdk!actions.getMerchantInformation | `getMerchantInformation()`} for more info about the estimated reward fetching
54
55
  */
55
- function ButtonShare({ placement: placementId, text = "Share and earn!", classname = "", noRewardText, targetInteraction, clickAction: rawClickAction, preview }) {
56
+ function ButtonShare({ placement: placementId, text, classname = "", noRewardText, targetInteraction, clickAction: rawClickAction, preview }) {
56
57
  const isPreview = !!preview;
58
+ const lang = useLang();
57
59
  const placement = usePlacement(placementId);
58
60
  const globalComponents = useGlobalComponents();
59
61
  const componentConfig = placement?.components?.buttonShare ?? globalComponents?.buttonShare;
60
62
  useLightDomStyles("frak-button-share", placementId, componentConfig?.css);
61
63
  const resolvedTargetInteraction = useMemo(() => placement?.targetInteraction !== void 0 ? placement.targetInteraction : targetInteraction, [placement?.targetInteraction, targetInteraction]);
62
- const resolvedText = componentConfig?.text ?? text;
64
+ const resolvedText = componentConfig?.text ?? text ?? componentDefaults[lang].buttonShare.text;
63
65
  const resolvedNoRewardText = componentConfig?.noRewardText ?? noRewardText;
64
66
  const wantsReward = useMemo(() => resolvedText.includes("{REWARD}"), [resolvedText]);
65
67
  const resolvedClickAction = useMemo(() => componentConfig?.clickAction ?? rawClickAction ?? "sharing-page", [componentConfig?.clickAction, rawClickAction]);
@@ -67,8 +69,8 @@ function ButtonShare({ placement: placementId, text = "Share and earn!", classna
67
69
  const { reward } = useReward(wantsReward && isClientReady, resolvedTargetInteraction);
68
70
  const btnText = useMemo(() => {
69
71
  if (!wantsReward) return resolvedText;
70
- if (reward) return applyRewardPlaceholder(resolvedText, reward);
71
- return resolvedNoRewardText ?? applyRewardPlaceholder(resolvedText, void 0);
72
+ if (reward) return b(resolvedText, reward);
73
+ return resolvedNoRewardText ?? b(resolvedText, void 0);
72
74
  }, [
73
75
  wantsReward,
74
76
  resolvedText,
@@ -1,5 +1,4 @@
1
1
  import { InteractionTypeKey } from "@frak-labs/core-sdk";
2
- import * as _$preact from "preact";
3
2
 
4
3
  //#region src/components/ButtonWallet/types.d.ts
5
4
  /**
@@ -70,7 +69,7 @@ declare function ButtonWallet({
70
69
  classname,
71
70
  useReward: rawUseReward,
72
71
  targetInteraction
73
- }: ButtonWalletProps): _$preact.JSX.Element | null;
72
+ }: ButtonWalletProps): import("preact").JSX.Element | null;
74
73
  //#endregion
75
74
  //#region src/components/ButtonWallet/index.d.ts
76
75
  /**
@@ -1,6 +1,7 @@
1
- import { a as registerWebComponent, i as useClientReady, n as buildStyleContent, t as usePlacement } from "./usePlacement-5kbU3BKj.js";
1
+ import { i as useLang, n as buildStyleContent, o as useClientReady, s as registerWebComponent, t as usePlacement } from "./usePlacement-4PoDbn2X.js";
2
2
  import { t as openEmbeddedWallet } from "./embeddedWallet-By3_p5Xc.js";
3
- import { t as useReward } from "./useReward-ClVShg45.js";
3
+ import { t as useReward } from "./useReward-Br6GKb9Z.js";
4
+ import { componentDefaults } from "./i18n/defaults.js";
4
5
  import { useEffect, useMemo, useState } from "preact/hooks";
5
6
  import { Fragment, jsx, jsxs } from "preact/jsx-runtime";
6
7
  //#region src/components/ButtonWallet/assets/GiftIcon.tsx
@@ -119,6 +120,7 @@ const componentCss = `
119
120
  * @see {@link @frak-labs/core-sdk!actions.getMerchantInformation | `getMerchantInformation()`} for more info about the estimated reward fetching
120
121
  */
121
122
  function ButtonWallet({ placement: placementId, classname = "", useReward: rawUseReward, targetInteraction }) {
123
+ const lang = useLang();
122
124
  const placement = usePlacement(placementId);
123
125
  const resolvedTargetInteraction = useMemo(() => placement?.targetInteraction !== void 0 ? placement.targetInteraction : targetInteraction, [placement?.targetInteraction, targetInteraction]);
124
126
  const shouldUseReward = useMemo(() => rawUseReward === true, [rawUseReward]);
@@ -139,7 +141,7 @@ function ButtonWallet({ placement: placementId, classname = "", useReward: rawUs
139
141
  ].filter(Boolean).join(" ");
140
142
  return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("style", { children: buildStyleContent(componentCss, placement?.components?.buttonWallet?.css) }), /* @__PURE__ */ jsxs("button", {
141
143
  type: "button",
142
- "aria-label": "Open wallet",
144
+ "aria-label": componentDefaults[lang].buttonWallet.ariaLabel,
143
145
  part: "button",
144
146
  disabled: !isClientReady,
145
147
  class: buttonClass,
@@ -0,0 +1,54 @@
1
+ import { Language } from "@frak-labs/core-sdk";
2
+
3
+ //#region src/i18n/defaults.d.ts
4
+ /**
5
+ * Shape of the built-in copy for every SDK Web Component. Declared explicitly
6
+ * so each supported {@link Language} is forced to provide the exact same set
7
+ * of keys (a missing translation is a type error, not a silent fallback).
8
+ */
9
+ type ComponentCopy = {
10
+ buttonShare: {
11
+ text: string;
12
+ };
13
+ postPurchase: {
14
+ refereeText: string;
15
+ refereeNoRewardText: string;
16
+ referrerText: string;
17
+ referrerNoRewardText: string;
18
+ ctaText: string;
19
+ ctaNoRewardText: string;
20
+ };
21
+ openInApp: {
22
+ text: string;
23
+ ariaLabel: string;
24
+ };
25
+ buttonWallet: {
26
+ ariaLabel: string;
27
+ };
28
+ banner: {
29
+ /** Referral title used when an estimated reward is available (carries the `{REWARD}` token). */referralTitleReward: string; /** Referral title used when no reward could be resolved. */
30
+ referralTitle: string;
31
+ referralDescription: string;
32
+ referralCta: string;
33
+ inappTitle: string;
34
+ inappDescription: string;
35
+ inappCta: string;
36
+ dismissLabel: string;
37
+ };
38
+ };
39
+ /**
40
+ * Built-in, per-language default copy for the SDK Web Components.
41
+ *
42
+ * These strings are the last-resort fallback, used only when a merchant
43
+ * provides neither an HTML attribute override nor a backend-config override.
44
+ * They keep the components bilingual out of the box **without** pulling an
45
+ * i18n runtime (e.g. i18next) into the size-critical CDN bundle — resolution
46
+ * is a plain object lookup keyed by the active language (see `useLang`).
47
+ *
48
+ * Adding a new language is a matter of adding one entry here plus extending
49
+ * the `Language` union in `@frak-labs/core-sdk` — no new dependency, no
50
+ * merchant action, no SDK API change.
51
+ */
52
+ declare const componentDefaults: Record<Language, ComponentCopy>;
53
+ //#endregion
54
+ export { componentDefaults };
@@ -0,0 +1,70 @@
1
+ //#region src/i18n/defaults.ts
2
+ /**
3
+ * Built-in, per-language default copy for the SDK Web Components.
4
+ *
5
+ * These strings are the last-resort fallback, used only when a merchant
6
+ * provides neither an HTML attribute override nor a backend-config override.
7
+ * They keep the components bilingual out of the box **without** pulling an
8
+ * i18n runtime (e.g. i18next) into the size-critical CDN bundle — resolution
9
+ * is a plain object lookup keyed by the active language (see `useLang`).
10
+ *
11
+ * Adding a new language is a matter of adding one entry here plus extending
12
+ * the `Language` union in `@frak-labs/core-sdk` — no new dependency, no
13
+ * merchant action, no SDK API change.
14
+ */
15
+ const componentDefaults = {
16
+ en: {
17
+ buttonShare: { text: "Share and earn!" },
18
+ postPurchase: {
19
+ refereeText: "You just earned {REWARD}! Share with friends to earn even more.",
20
+ refereeNoRewardText: "You just earned a reward! Share with friends to earn even more.",
21
+ referrerText: "Earn {REWARD} by sharing this with your friends!",
22
+ referrerNoRewardText: "Share this with your friends and earn rewards!",
23
+ ctaText: "Share & earn {REWARD}",
24
+ ctaNoRewardText: "Share & earn"
25
+ },
26
+ openInApp: {
27
+ text: "Open in App",
28
+ ariaLabel: "Open in Frak Wallet app"
29
+ },
30
+ buttonWallet: { ariaLabel: "Open wallet" },
31
+ banner: {
32
+ referralTitleReward: "Earn {REWARD} on purchases on this site",
33
+ referralTitle: "You've been referred!",
34
+ referralDescription: "Earn rewards after your purchase via the Frak partner app.",
35
+ referralCta: "Got it",
36
+ inappTitle: "Open in your browser",
37
+ inappDescription: "For a better experience and to earn your rewards, open this page in your default browser.",
38
+ inappCta: "Open browser",
39
+ dismissLabel: "Dismiss"
40
+ }
41
+ },
42
+ fr: {
43
+ buttonShare: { text: "Partagez et gagnez !" },
44
+ postPurchase: {
45
+ refereeText: "Vous venez de gagner {REWARD} ! Partagez avec vos amis pour gagner encore plus.",
46
+ refereeNoRewardText: "Vous venez de gagner une récompense ! Partagez avec vos amis pour gagner encore plus.",
47
+ referrerText: "Gagnez {REWARD} en partageant avec vos amis !",
48
+ referrerNoRewardText: "Partagez avec vos amis et gagnez des récompenses !",
49
+ ctaText: "Partagez et gagnez {REWARD}",
50
+ ctaNoRewardText: "Partagez et gagnez"
51
+ },
52
+ openInApp: {
53
+ text: "Ouvrir dans l'app",
54
+ ariaLabel: "Ouvrir dans l'app Frak Wallet"
55
+ },
56
+ buttonWallet: { ariaLabel: "Ouvrir le portefeuille" },
57
+ banner: {
58
+ referralTitleReward: "Gagnez {REWARD} sur vos achats sur ce site",
59
+ referralTitle: "Vous avez été parrainé !",
60
+ referralDescription: "Gagnez des récompenses après votre achat via l'application partenaire Frak.",
61
+ referralCta: "J'ai compris",
62
+ inappTitle: "Ouvrez dans votre navigateur",
63
+ inappDescription: "Pour une meilleure expérience et pour gagner vos récompenses, ouvrez cette page dans votre navigateur par défaut.",
64
+ inappCta: "Ouvrir le navigateur",
65
+ dismissLabel: "Fermer"
66
+ }
67
+ }
68
+ };
69
+ //#endregion
70
+ export { componentDefaults };
@@ -1,5 +1,3 @@
1
- import * as _$preact from "preact";
2
-
3
1
  //#region src/components/OpenInAppButton/types.d.ts
4
2
  /**
5
3
  * The props type for {@link OpenInAppButton}.
@@ -8,8 +6,10 @@ import * as _$preact from "preact";
8
6
  type OpenInAppButtonProps = {
9
7
  placement?: string;
10
8
  /**
11
- * Text to display on the button
12
- * @defaultValue `"Open in App"`
9
+ * Text to display on the button.
10
+ *
11
+ * When omitted, a built-in localized default is used based on the
12
+ * resolved language (`"Open in App"` / `"Ouvrir dans l'app"`).
13
13
  */
14
14
  text?: string;
15
15
  /**
@@ -49,7 +49,7 @@ declare function OpenInAppButton({
49
49
  placement: placementId,
50
50
  text,
51
51
  classname
52
- }: OpenInAppButtonProps): _$preact.JSX.Element | null;
52
+ }: OpenInAppButtonProps): import("preact").JSX.Element | null;
53
53
  //#endregion
54
54
  //#region src/components/OpenInAppButton/index.d.ts
55
55
  /**
package/dist/openInApp.js CHANGED
@@ -1,5 +1,6 @@
1
- import { a as registerWebComponent, i as useClientReady, t as usePlacement } from "./usePlacement-5kbU3BKj.js";
2
- import { t as useLightDomStyles } from "./useLightDomStyles-C8giLInY.js";
1
+ import { i as useLang, o as useClientReady, s as registerWebComponent, t as usePlacement } from "./usePlacement-4PoDbn2X.js";
2
+ import { t as useLightDomStyles } from "./useLightDomStyles-DphuQhvx.js";
3
+ import { componentDefaults } from "./i18n/defaults.js";
3
4
  import { DEEP_LINK_SCHEME, isMobile, trackEvent, triggerDeepLinkWithFallback } from "@frak-labs/core-sdk";
4
5
  import { useMemo } from "preact/hooks";
5
6
  import { jsx } from "preact/jsx-runtime";
@@ -58,12 +59,13 @@ function useIsMobile() {
58
59
  * <frak-open-in-app classname="button button-primary"></frak-open-in-app>
59
60
  * ```
60
61
  */
61
- function OpenInAppButton({ placement: placementId, text = "Open in App", classname = "" }) {
62
+ function OpenInAppButton({ placement: placementId, text, classname = "" }) {
63
+ const lang = useLang();
62
64
  const placement = usePlacement(placementId);
63
65
  const { shouldRender, isHidden, isClientReady } = useClientReady();
64
66
  const { isMobile } = useIsMobile();
65
67
  useLightDomStyles("frak-open-in-app", placementId, placement?.components?.openInApp?.css);
66
- const resolvedText = placement?.components?.openInApp?.text ?? text;
68
+ const resolvedText = placement?.components?.openInApp?.text ?? text ?? componentDefaults[lang].openInApp.text;
67
69
  if (!isMobile || !shouldRender || isHidden) return null;
68
70
  const handleClick = () => {
69
71
  openFrakWalletApp(void 0, placementId);
@@ -75,7 +77,7 @@ function OpenInAppButton({ placement: placementId, text = "Open in App", classna
75
77
  ].filter(Boolean).join(" ");
76
78
  return /* @__PURE__ */ jsx("button", {
77
79
  type: "button",
78
- "aria-label": "Open in Frak Wallet app",
80
+ "aria-label": componentDefaults[lang].openInApp.ariaLabel,
79
81
  disabled: !isClientReady,
80
82
  class: buttonClass,
81
83
  onClick: handleClick,
@@ -1,5 +1,4 @@
1
1
  import { SharingPageProduct } from "@frak-labs/core-sdk";
2
- import * as _$preact from "preact";
3
2
 
4
3
  //#region src/components/PostPurchase/types.d.ts
5
4
  /**
@@ -142,8 +141,8 @@ declare function PostPurchase({
142
141
  preview,
143
142
  previewVariant,
144
143
  products,
145
- imageUrl
146
- }: PostPurchaseProps): _$preact.JSX.Element | null;
144
+ imageUrl: propImageUrl
145
+ }: PostPurchaseProps): import("preact").JSX.Element | null;
147
146
  //#endregion
148
147
  //#region src/components/PostPurchase/index.d.ts
149
148
  /**
@@ -1,8 +1,9 @@
1
- import { a as registerWebComponent, i as useClientReady, o as sanitizeProductList, s as openSharingPage, t as usePlacement } from "./usePlacement-5kbU3BKj.js";
2
- import { t as useGlobalComponents } from "./useGlobalComponents-mSs9unyN.js";
3
- import { t as useLightDomStyles } from "./useLightDomStyles-C8giLInY.js";
4
- import { n as formatEstimatedReward, t as applyRewardPlaceholder } from "./formatReward-Cf2KpA3x.js";
5
- import { i as LogoFrakWithName, n as cssSource$2, t as GiftIcon } from "./GiftIcon-BIp9FTJs.js";
1
+ import { c as sanitizeProductList, i as useLang, l as openSharingPage, o as useClientReady, s as registerWebComponent, t as usePlacement } from "./usePlacement-4PoDbn2X.js";
2
+ import { t as useGlobalComponents } from "./useGlobalComponents-CZ7Sh2tZ.js";
3
+ import { t as useLightDomStyles } from "./useLightDomStyles-DphuQhvx.js";
4
+ import { i as y, n as T, r as b } from "./rewards-CsHE1hVo.js";
5
+ import { componentDefaults } from "./i18n/defaults.js";
6
+ import { i as LogoFrakWithName, n as cssSource$2, t as GiftIcon } from "./GiftIcon-WEWSJ8kV.js";
6
7
  import { trackEvent } from "@frak-labs/core-sdk";
7
8
  import { getMerchantInformation, getUserReferralStatus, trackPurchaseStatus } from "@frak-labs/core-sdk/actions";
8
9
  import { useCallback, useEffect, useMemo, useRef, useState } from "preact/hooks";
@@ -116,13 +117,19 @@ const cssSource = cssSource$1;
116
117
  * Given referral status and merchant info, compute the display variant
117
118
  * and pick the appropriate purchase reward.
118
119
  */
119
- function resolvePostPurchaseContext(referralStatus, merchantInfo) {
120
- const purchaseReward = merchantInfo.rewards.find((r) => r.interactionTypeKey === "purchase" && (r.referrer || r.referee));
121
- if (!purchaseReward) return null;
122
- const variant = referralStatus?.isReferred && purchaseReward.referee ? "referee" : "referrer";
120
+ function resolvePostPurchaseContext(referralStatus, merchantInfo, currency) {
121
+ const audience = referralStatus?.isReferred ? "referee" : "referrer";
122
+ const selected = T(merchantInfo.rewards, {
123
+ targetInteraction: "purchase",
124
+ currency,
125
+ audience
126
+ });
127
+ if (!selected) return null;
128
+ const { campaign } = selected;
129
+ const variant = referralStatus?.isReferred && campaign.referee ? "referee" : "referrer";
123
130
  return {
124
131
  variant,
125
- reward: variant === "referee" ? purchaseReward.referee : purchaseReward.referrer,
132
+ reward: variant === "referee" ? campaign.referee : campaign.referrer,
126
133
  merchantDomain: merchantInfo.onChainMetadata.domain
127
134
  };
128
135
  }
@@ -154,10 +161,11 @@ function resolvePostPurchaseContext(referralStatus, merchantInfo) {
154
161
  * ></frak-post-purchase>
155
162
  * ```
156
163
  */
157
- function PostPurchase({ customerId, orderId, token, sharingUrl, merchantId, placement: placementId, classname = "", variant: forcedVariant, badgeText: propBadgeText, referrerText: propReferrerText, refereeText: propRefereeText, ctaText: propCtaText, preview, previewVariant, products, imageUrl }) {
164
+ function PostPurchase({ customerId, orderId, token, sharingUrl, merchantId, placement: placementId, classname = "", variant: forcedVariant, badgeText: propBadgeText, referrerText: propReferrerText, refereeText: propRefereeText, ctaText: propCtaText, preview, previewVariant, products, imageUrl: propImageUrl }) {
158
165
  const isPreview = !!preview;
159
166
  const { shouldRender, isHidden, isClientReady } = useClientReady();
160
167
  const placement = usePlacement(placementId);
168
+ const lang = useLang();
161
169
  useLightDomStyles("frak-post-purchase", placementId, placement?.components?.postPurchase?.css, cssSource, cssSource$2);
162
170
  const [context, setContext] = useState(null);
163
171
  const [hasFetched, setHasFetched] = useState(false);
@@ -185,7 +193,7 @@ function PostPurchase({ customerId, orderId, token, sharingUrl, merchantId, plac
185
193
  if (!client) return;
186
194
  Promise.all([getUserReferralStatus(client), getMerchantInformation(client)]).then(([referralStatus, merchantInfo]) => {
187
195
  setHasFetched(true);
188
- setContext(resolvePostPurchaseContext(referralStatus, merchantInfo));
196
+ setContext(resolvePostPurchaseContext(referralStatus, merchantInfo, client.config.metadata?.currency));
189
197
  }).catch((e) => {
190
198
  if (e instanceof FrakRpcError && e.code === RpcErrorCodes.configError) {
191
199
  setHasFetched(true);
@@ -204,17 +212,20 @@ function PostPurchase({ customerId, orderId, token, sharingUrl, merchantId, plac
204
212
  const rewardText = useMemo(() => {
205
213
  if (!context?.reward) return void 0;
206
214
  const currency = window.FrakSetup?.client?.config?.metadata?.currency;
207
- return formatEstimatedReward(context.reward, currency);
215
+ return y(context.reward, currency);
208
216
  }, [context?.reward]);
209
217
  const globalComponents = useGlobalComponents();
210
218
  const postPurchaseConfig = placement?.components?.postPurchase ?? globalComponents?.postPurchase;
211
219
  const resolvedBadgeText = propBadgeText ?? postPurchaseConfig?.badgeText;
220
+ const imageUrl = propImageUrl ?? postPurchaseConfig?.imageUrl;
212
221
  const texts = useMemo(() => {
222
+ const defaults = componentDefaults[lang].postPurchase;
213
223
  return {
214
- message: resolvedVariant === "referee" ? rewardText ? applyRewardPlaceholder(propRefereeText ?? postPurchaseConfig?.refereeText ?? "You just earned {REWARD}! Share with friends to earn even more.", rewardText) : propRefereeText ?? postPurchaseConfig?.refereeNoRewardText ?? "You just earned a reward! Share with friends to earn even more." : rewardText ? applyRewardPlaceholder(propReferrerText ?? postPurchaseConfig?.referrerText ?? "Earn {REWARD} by sharing this with your friends!", rewardText) : propReferrerText ?? postPurchaseConfig?.referrerNoRewardText ?? "Share this with your friends and earn rewards!",
215
- cta: rewardText ? applyRewardPlaceholder(propCtaText ?? postPurchaseConfig?.ctaText ?? "Share & earn {REWARD}", rewardText) : propCtaText ?? postPurchaseConfig?.ctaNoRewardText ?? "Share & earn"
224
+ message: resolvedVariant === "referee" ? rewardText ? b(propRefereeText ?? postPurchaseConfig?.refereeText ?? defaults.refereeText, rewardText) : propRefereeText ?? postPurchaseConfig?.refereeNoRewardText ?? defaults.refereeNoRewardText : rewardText ? b(propReferrerText ?? postPurchaseConfig?.referrerText ?? defaults.referrerText, rewardText) : propReferrerText ?? postPurchaseConfig?.referrerNoRewardText ?? defaults.referrerNoRewardText,
225
+ cta: rewardText ? b(propCtaText ?? postPurchaseConfig?.ctaText ?? defaults.ctaText, rewardText) : propCtaText ?? postPurchaseConfig?.ctaNoRewardText ?? defaults.ctaNoRewardText
216
226
  };
217
227
  }, [
228
+ lang,
218
229
  resolvedVariant,
219
230
  rewardText,
220
231
  postPurchaseConfig,
@@ -225,7 +236,8 @@ function PostPurchase({ customerId, orderId, token, sharingUrl, merchantId, plac
225
236
  useEffect(() => {
226
237
  if (!resolvedVariant) return;
227
238
  if (trackedImpressionVariantRef.current === resolvedVariant) return;
228
- if (!isPreview && (!shouldRender || isHidden || !isClientReady)) return;
239
+ if (!isClientReady) return;
240
+ if (!isPreview && (!shouldRender || isHidden)) return;
229
241
  trackEvent(window.FrakSetup?.client, "post_purchase_impression", {
230
242
  placement: placementId,
231
243
  variant: resolvedVariant,
@@ -0,0 +1,145 @@
1
+ //#region ../core/dist/getCurrencyAmountKey-DQcwjJiB.js
2
+ const e = {
3
+ eur: `fr-FR`,
4
+ usd: `en-US`,
5
+ gbp: `en-GB`
6
+ };
7
+ function t(t) {
8
+ return t && t in e ? t : `eur`;
9
+ }
10
+ function n(t) {
11
+ return t ? e[t] ?? e.eur : e.eur;
12
+ }
13
+ function r$1(e, r) {
14
+ let i = n(r), a = t(r);
15
+ return e.toLocaleString(i, {
16
+ style: `currency`,
17
+ currency: a,
18
+ minimumFractionDigits: 0,
19
+ maximumFractionDigits: 2
20
+ });
21
+ }
22
+ function i$1(e) {
23
+ return e ? `${e}Amount` : `eurAmount`;
24
+ }
25
+ //#endregion
26
+ //#region ../core/dist/rewards.js
27
+ function r(e) {
28
+ return Array.isArray(e) ? e : e.conditions;
29
+ }
30
+ function i(e) {
31
+ if (typeof e == `number`) return e;
32
+ if (typeof e == `string` && e.trim() !== ``) {
33
+ let t = Number(e);
34
+ return Number.isFinite(t) ? t : void 0;
35
+ }
36
+ }
37
+ function a(e, t, n) {
38
+ let o = [];
39
+ for (let s of r(e)) {
40
+ if (`logic` in s) {
41
+ o.push(...a(s, t, n));
42
+ continue;
43
+ }
44
+ if (s.field === t && n.has(s.operator)) {
45
+ let e = i(s.value);
46
+ e != null && o.push(e);
47
+ }
48
+ }
49
+ return o;
50
+ }
51
+ const o = new Set([
52
+ `gt`,
53
+ `gte`,
54
+ `between`
55
+ ]), s = new Set([`gt`, `gte`]);
56
+ function c(e) {
57
+ let t = a(e, `purchase.amount`, o);
58
+ return t.length > 0 ? Math.min(...t) : void 0;
59
+ }
60
+ function l(e) {
61
+ let t = a(e, `time.timestamp`, s);
62
+ if (t.length !== 0) return /* @__PURE__ */ new Date(Math.min(...t) * 1e3);
63
+ }
64
+ function h(e, t) {
65
+ switch (e.payoutType) {
66
+ case `fixed`: return e.amount[t];
67
+ case `percentage`: return e.maxAmount?.[t] ?? 0;
68
+ case `tiered`: return e.tiers.reduce((e, n) => `amount` in n ? Math.max(e, n.amount[t]) : e, 0);
69
+ }
70
+ }
71
+ function g(e) {
72
+ return e.payoutType === `percentage` ? e.percent : e.payoutType === `tiered` ? e.tiers.reduce((e, t) => `percent` in t ? Math.max(e, t.percent) : e, 0) : 0;
73
+ }
74
+ function _(e, t) {
75
+ let n = h(e, t);
76
+ return n > 0 ? n : g(e) * 1e-6;
77
+ }
78
+ function v(r, i) {
79
+ let a = t(i), o = i$1(a);
80
+ switch (r.payoutType) {
81
+ case `fixed`: return r$1(Math.round(r.amount[o]), a);
82
+ case `percentage`: return `${r.percent} %`;
83
+ case `tiered`: {
84
+ let t = h(r, o);
85
+ if (t > 0) return r$1(Math.round(t), a);
86
+ let n = g(r);
87
+ return n > 0 ? `${n} %` : r$1(0, a);
88
+ }
89
+ }
90
+ }
91
+ function y(e, r) {
92
+ if (e && !(_(e, i$1(t(r))) <= 0)) return v(e, r);
93
+ }
94
+ function b(e, t) {
95
+ return t ? e.replace(`{REWARD}`, t) : e.replace(`{REWARD}`, ``);
96
+ }
97
+ function x(e, t) {
98
+ return e.expiresAt != null && new Date(e.expiresAt).getTime() <= t;
99
+ }
100
+ function S(e, t) {
101
+ let n = l(e.conditions);
102
+ return n == null || n.getTime() <= t;
103
+ }
104
+ function C(e, t) {
105
+ return t === `referee` ? e.referee : e.referrer;
106
+ }
107
+ function w(e, t, n) {
108
+ let r = C(e, n);
109
+ return r ? _(r, t) : 0;
110
+ }
111
+ function T(e, r = {}) {
112
+ let i = (r.now ?? /* @__PURE__ */ new Date()).getTime(), a = r.audience ?? `referrer`, o = i$1(t(r.currency)), s = (r.targetInteraction ? e.filter((e) => e.interactionTypeKey === r.targetInteraction) : e).filter((e) => !x(e, i)), c = s.filter((e) => S(e, i));
113
+ if (c.length > 0) return {
114
+ campaign: c.reduce((e, t) => w(t, o, a) > w(e, o, a) ? t : e),
115
+ status: `live`
116
+ };
117
+ let u = s.map((e) => ({
118
+ campaign: e,
119
+ startsAt: l(e.conditions)
120
+ })).filter((e) => e.startsAt != null);
121
+ if (u.length === 0) return;
122
+ let d = u.reduce((e, t) => t.startsAt.getTime() < e.startsAt.getTime() ? t : e);
123
+ return {
124
+ campaign: d.campaign,
125
+ status: `upcoming`,
126
+ startsAt: d.startsAt
127
+ };
128
+ }
129
+ function E(t, n = {}) {
130
+ let r = T(t, n);
131
+ if (!r) return;
132
+ let i = C(r.campaign, n.audience ?? `referrer`);
133
+ if (!i) return;
134
+ let a = y(i, n.currency);
135
+ if (!a) return;
136
+ let o = c(r.campaign.conditions), s = o == null ? void 0 : r$1(o, n.currency), l = r.campaign.defaultLockupSeconds, u = l && l > 0 ? Math.round(l / 86400) : void 0;
137
+ return {
138
+ formatted: a,
139
+ payoutType: i.payoutType,
140
+ minPurchaseAmount: s,
141
+ lockupDurationDays: u
142
+ };
143
+ }
144
+ //#endregion
145
+ export { y as i, T as n, b as r, E as t };
@@ -0,0 +1,17 @@
1
+ import { a as subscribeSdkConfig } from "./usePlacement-4PoDbn2X.js";
2
+ import { sdkConfigStore } from "@frak-labs/core-sdk";
3
+ import { useSyncExternalStore } from "preact/compat";
4
+ //#region src/hooks/useGlobalComponents.ts
5
+ /**
6
+ * Subscribe to the global component defaults from the SDK config store.
7
+ * These serve as fallbacks when no placement-level override exists.
8
+ *
9
+ * Backed by `useSyncExternalStore`: the snapshot is the stored `components`
10
+ * object reference (stable between `frak:config` dispatches), so the component
11
+ * only re-renders when the global components actually change.
12
+ */
13
+ function useGlobalComponents() {
14
+ return useSyncExternalStore(subscribeSdkConfig, () => sdkConfigStore.getConfig().components);
15
+ }
16
+ //#endregion
17
+ export { useGlobalComponents as t };
@@ -1,4 +1,4 @@
1
- import { r as lightDomBaseCss } from "./usePlacement-5kbU3BKj.js";
1
+ import { r as lightDomBaseCss } from "./usePlacement-4PoDbn2X.js";
2
2
  import { useEffect } from "preact/hooks";
3
3
  //#region src/styles/styleManager.ts
4
4
  function ensureStyle(id, css) {