@frak-labs/components 0.0.26 → 1.0.0-beta.61e6fb99

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 (46) hide show
  1. package/cdn/Banner.UBeCtoRQ.js +162 -0
  2. package/cdn/ButtonShare.COa5uY94.js +1 -0
  3. package/cdn/ButtonWallet.BUzysl1S.js +40 -0
  4. package/cdn/OpenInAppButton.Bmzm2fL9.js +1 -0
  5. package/cdn/PostPurchase._st1hB42.js +52 -0
  6. package/cdn/components.js +1 -1
  7. package/cdn/formatReward.B0iBskOJ.js +1 -0
  8. package/cdn/loader.css +0 -14
  9. package/cdn/loader.js +14 -1
  10. package/cdn/sprinkles.css.ts.vanilla.Ct795MMK.js +1175 -0
  11. package/cdn/useGlobalComponents.CLH7id-Y.js +1 -0
  12. package/cdn/useLightDomStyles.DqYouFn3.js +1 -0
  13. package/cdn/usePlacement.Di6eZ4ty.js +58 -0
  14. package/cdn/useReward.DJwgphI1.js +1 -0
  15. package/cdn/useShareModal.UYsKX7L2.js +1 -0
  16. package/dist/GiftIcon-4sr9xXyq.js +1501 -0
  17. package/dist/banner.d.ts +116 -0
  18. package/dist/banner.js +464 -0
  19. package/dist/buttonShare.d.ts +16 -6
  20. package/dist/buttonShare.js +78 -103
  21. package/dist/buttonWallet.d.ts +10 -2
  22. package/dist/buttonWallet.js +79 -40
  23. package/dist/formatReward-Bub6Z6eY.js +33 -0
  24. package/dist/openInApp.d.ts +4 -2
  25. package/dist/openInApp.js +33 -33
  26. package/dist/postPurchase.d.ts +136 -0
  27. package/dist/postPurchase.js +1618 -0
  28. package/dist/useGlobalComponents-Cmfszr7v.js +21 -0
  29. package/dist/useLightDomStyles-C3lcOwY2.js +41 -0
  30. package/dist/usePlacement-V7NrKoub.js +253 -0
  31. package/dist/useReward-DU3_yP8Q.js +65 -0
  32. package/dist/useShareModal-BEVkLrBP.js +54 -0
  33. package/package.json +29 -20
  34. package/cdn/ButtonShare.CqRLxX5u.js +0 -1
  35. package/cdn/ButtonWallet.ToH_g8FC.js +0 -1
  36. package/cdn/OpenInAppButton.BMZnXQLT.js +0 -1
  37. package/cdn/Spinner.DRiAlyyq.js +0 -1
  38. package/cdn/initFrakSdk.CA6zXtGT.js +0 -14
  39. package/cdn/useClientReady.DskSqlAg.js +0 -1
  40. package/dist/Spinner-1CZC_zy6.js +0 -36
  41. package/dist/Spinner-CHZD3tMn.css +0 -1
  42. package/dist/buttonShare.css +0 -1
  43. package/dist/buttonWallet.css +0 -1
  44. package/dist/openInApp.css +0 -1
  45. package/dist/useClientReady-iCtUeDsc.js +0 -197
  46. package/dist/useReward-DAkT-7wT.js +0 -48
@@ -1,17 +1,21 @@
1
- import { n as registerWebComponent, r as getModalBuilderSteps, t as useClientReady } from "./useClientReady-iCtUeDsc.js";
2
- import { t as Spinner } from "./Spinner-1CZC_zy6.js";
3
- import { t as useReward } from "./useReward-DAkT-7wT.js";
4
- import { DebugInfoGatherer, trackEvent } from "@frak-labs/core-sdk";
5
- import { displayEmbeddedWallet } from "@frak-labs/core-sdk/actions";
6
- import { cx } from "class-variance-authority";
1
+ import { a as registerWebComponent, i as useClientReady, s as openEmbeddedWallet, t as usePlacement } from "./usePlacement-V7NrKoub.js";
2
+ import { t as useGlobalComponents } from "./useGlobalComponents-Cmfszr7v.js";
3
+ import { t as useLightDomStyles } from "./useLightDomStyles-C3lcOwY2.js";
4
+ import { t as applyRewardPlaceholder } from "./formatReward-Bub6Z6eY.js";
5
+ import { t as useReward } from "./useReward-DU3_yP8Q.js";
6
+ import { t as useShareModal } from "./useShareModal-BEVkLrBP.js";
7
+ import { trackEvent } from "@frak-labs/core-sdk";
8
+ import { displaySharingPage } from "@frak-labs/core-sdk/actions";
7
9
  import { useCallback, useMemo, useState } from "preact/hooks";
8
10
  import { Fragment, jsx, jsxs } from "preact/jsx-runtime";
9
- import { FrakRpcError, RpcErrorCodes } from "@frak-labs/frame-connector";
10
-
11
- //#region src/components/ButtonShare/ButtonShare.module.css?css_module
12
- const classes = { "buttonShare": "nOB7Uq_buttonShare" };
13
- const _buttonShare0 = classes["buttonShare"];
14
-
11
+ //#region src/utils/sharingPage.ts
12
+ async function openSharingPage(targetInteraction, placement) {
13
+ if (!window.FrakSetup?.client) {
14
+ console.error("Frak client not found");
15
+ return;
16
+ }
17
+ await displaySharingPage(window.FrakSetup.client, { metadata: { ...targetInteraction && { targetInteraction } } }, placement);
18
+ }
15
19
  //#endregion
16
20
  //#region src/hooks/useCopyToClipboard.ts
17
21
  function useCopyToClipboard(options = {}) {
@@ -53,7 +57,6 @@ function useCopyToClipboard(options = {}) {
53
57
  copied
54
58
  };
55
59
  }
56
-
57
60
  //#endregion
58
61
  //#region src/components/ButtonShare/components/ErrorMessage.tsx
59
62
  const styles = {
@@ -129,6 +132,9 @@ function ToggleMessage({ debugInfo }) {
129
132
  */
130
133
  function ErrorMessage({ debugInfo }) {
131
134
  const { copied, copy } = useCopyToClipboard();
135
+ const handleCopy = () => {
136
+ copy(debugInfo ?? "");
137
+ };
132
138
  return /* @__PURE__ */ jsxs("div", {
133
139
  style: styles.errorContainer,
134
140
  children: [
@@ -156,7 +162,7 @@ function ErrorMessage({ debugInfo }) {
156
162
  }),
157
163
  /* @__PURE__ */ jsx("button", {
158
164
  type: "button",
159
- onClick: () => copy(debugInfo ?? ""),
165
+ onClick: handleCopy,
160
166
  style: styles.copyButton,
161
167
  children: copied ? "Informations copiées !" : "Copier les informations de débogage"
162
168
  }),
@@ -164,66 +170,9 @@ function ErrorMessage({ debugInfo }) {
164
170
  ]
165
171
  });
166
172
  }
167
-
168
- //#endregion
169
- //#region src/components/ButtonShare/hooks/useShareModal.ts
170
- /**
171
- * Open the share modal
172
- *
173
- * @description
174
- * This function will open the share modal with the configuration provided in the `window.FrakSetup.modalShareConfig` object.
175
- */
176
- function useShareModal(targetInteraction) {
177
- const [debugInfo, setDebugInfo] = useState(void 0);
178
- const [isError, setIsError] = useState(false);
179
- return {
180
- handleShare: useCallback(async () => {
181
- if (!window.FrakSetup?.client) {
182
- console.error("Frak client not found");
183
- setDebugInfo(DebugInfoGatherer.empty().formatDebugInfo("Frak client not found"));
184
- setIsError(true);
185
- return;
186
- }
187
- const modalBuilderSteps = getModalBuilderSteps();
188
- if (!modalBuilderSteps) throw new Error("modalBuilderSteps not found");
189
- try {
190
- await modalBuilderSteps.sharing(window.FrakSetup?.modalShareConfig ?? {}).display((metadata) => ({
191
- ...metadata,
192
- targetInteraction
193
- }));
194
- } catch (e) {
195
- if (e instanceof FrakRpcError && e.code === RpcErrorCodes.clientAborted) {
196
- console.debug("User aborted the modal");
197
- return;
198
- }
199
- const debugInfo = window.FrakSetup.client.debugInfo.formatDebugInfo(e);
200
- trackEvent(window.FrakSetup.client, "share_modal_error", {
201
- error: e instanceof Object && "message" in e ? e.message : "Unknown error",
202
- debugInfo
203
- });
204
- setDebugInfo(debugInfo);
205
- setIsError(true);
206
- console.error("Error while opening the modal", e);
207
- }
208
- }, [targetInteraction]),
209
- isError,
210
- debugInfo
211
- };
212
- }
213
-
214
173
  //#endregion
215
174
  //#region src/components/ButtonShare/ButtonShare.tsx
216
175
  /**
217
- * Open the embedded wallet modal
218
- *
219
- * @description
220
- * This function will open the wallet modal with the configuration provided in the `window.FrakSetup.modalWalletConfig` object.
221
- */
222
- async function modalEmbeddedWallet() {
223
- if (!window.FrakSetup?.client) throw new Error("Frak client not found");
224
- await displayEmbeddedWallet(window.FrakSetup.client, window.FrakSetup?.modalWalletConfig ?? {});
225
- }
226
- /**
227
176
  * Button to share the current page
228
177
  *
229
178
  * @param args
@@ -264,48 +213,74 @@ async function modalEmbeddedWallet() {
264
213
  * @see {@link @frak-labs/core-sdk!actions.modalBuilder | `modalBuilder()`} for more info about the modal display
265
214
  * @see {@link @frak-labs/core-sdk!actions.getMerchantInformation | `getMerchantInformation()`} for more info about the estimated reward fetching
266
215
  */
267
- function ButtonShare({ text = "Share and earn!", classname = "", useReward: rawUseReward, noRewardText, targetInteraction, showWallet: rawShowWallet }) {
268
- const shouldUseReward = useMemo(() => rawUseReward !== void 0, [rawUseReward]);
269
- const showWallet = useMemo(() => rawShowWallet !== void 0, [rawShowWallet]);
270
- const { isClientReady } = useClientReady();
271
- const { reward } = useReward(shouldUseReward && isClientReady, targetInteraction);
272
- const { handleShare, isError, debugInfo } = useShareModal(targetInteraction);
273
- /**
274
- * Compute the text we will display
275
- */
216
+ function ButtonShare({ placement: placementId, text = "Share and earn!", classname = "", useReward: rawUseReward, noRewardText, targetInteraction, clickAction: rawClickAction, preview }) {
217
+ const isPreview = !!preview;
218
+ const placement = usePlacement(placementId);
219
+ const globalComponents = useGlobalComponents();
220
+ const componentConfig = placement?.components?.buttonShare ?? globalComponents?.buttonShare;
221
+ useLightDomStyles("frak-button-share", placementId, componentConfig?.css);
222
+ const resolvedTargetInteraction = useMemo(() => placement?.targetInteraction !== void 0 ? placement.targetInteraction : targetInteraction, [placement?.targetInteraction, targetInteraction]);
223
+ const resolvedText = componentConfig?.text ?? text;
224
+ const resolvedNoRewardText = componentConfig?.noRewardText ?? noRewardText;
225
+ const shouldUseReward = useMemo(() => componentConfig?.useReward ?? rawUseReward === true, [componentConfig?.useReward, rawUseReward]);
226
+ const resolvedClickAction = useMemo(() => componentConfig?.clickAction ?? rawClickAction ?? "sharing-page", [componentConfig?.clickAction, rawClickAction]);
227
+ const { shouldRender, isHidden, isClientReady } = useClientReady();
228
+ const { reward } = useReward(shouldUseReward && isClientReady, resolvedTargetInteraction);
229
+ const { handleShare, isError, debugInfo } = useShareModal(resolvedTargetInteraction, placementId);
276
230
  const btnText = useMemo(() => {
277
- if (!shouldUseReward) return text;
278
- if (!reward) return noRewardText ?? text.replace("{REWARD}", "");
279
- return text.includes("{REWARD}") ? text.replace("{REWARD}", reward) : `${text} ${reward}`;
231
+ if (!shouldUseReward) return resolvedText;
232
+ if (!reward) return resolvedNoRewardText ?? applyRewardPlaceholder(resolvedText, void 0);
233
+ return resolvedText.includes("{REWARD}") ? applyRewardPlaceholder(resolvedText, reward) : `${resolvedText} ${reward}`;
280
234
  }, [
281
235
  shouldUseReward,
282
- text,
283
- noRewardText,
236
+ resolvedText,
237
+ resolvedNoRewardText,
284
238
  reward
285
239
  ]);
286
- /**
287
- * The action when the button is clicked
288
- */
289
240
  const onClick = useCallback(async () => {
290
- trackEvent(window.FrakSetup.client, "share_button_clicked");
291
- if (showWallet) await modalEmbeddedWallet();
292
- else await handleShare();
293
- }, [showWallet, handleShare]);
294
- return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsxs("button", {
241
+ if (isPreview) return;
242
+ trackEvent(window.FrakSetup.client, "share_button_clicked", {
243
+ placement: placementId,
244
+ target_interaction: resolvedTargetInteraction,
245
+ has_reward: Boolean(reward),
246
+ click_action: resolvedClickAction
247
+ });
248
+ if (resolvedClickAction === "embedded-wallet") openEmbeddedWallet(resolvedTargetInteraction, placementId);
249
+ else if (resolvedClickAction === "share-modal") await handleShare();
250
+ else openSharingPage(resolvedTargetInteraction, placementId);
251
+ }, [
252
+ isPreview,
253
+ resolvedClickAction,
254
+ handleShare,
255
+ resolvedTargetInteraction,
256
+ placementId,
257
+ reward
258
+ ]);
259
+ if (!isPreview && (!shouldRender || isHidden)) return null;
260
+ const buttonClass = [
261
+ "button",
262
+ "button__fadeIn",
263
+ classname
264
+ ].filter(Boolean).join(" ");
265
+ return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("button", {
295
266
  type: "button",
296
- className: cx(classes.buttonShare, classname, "override"),
267
+ disabled: !isPreview && !isClientReady,
268
+ class: buttonClass,
297
269
  onClick,
298
- children: [
299
- !isClientReady && /* @__PURE__ */ jsx(Spinner, {}),
300
- " ",
301
- btnText
302
- ]
270
+ children: btnText
303
271
  }), isError && /* @__PURE__ */ jsx(ErrorMessage, { debugInfo })] });
304
272
  }
305
-
306
273
  //#endregion
307
274
  //#region src/components/ButtonShare/index.ts
308
- registerWebComponent(ButtonShare, "frak-button-share", ["text"], { shadow: false });
309
-
275
+ registerWebComponent(ButtonShare, "frak-button-share", [
276
+ "text",
277
+ "placement",
278
+ "classname",
279
+ "clickAction",
280
+ "useReward",
281
+ "noRewardText",
282
+ "targetInteraction",
283
+ "preview"
284
+ ], { shadow: false });
310
285
  //#endregion
311
- export { ButtonShare };
286
+ export { ButtonShare };
@@ -1,5 +1,5 @@
1
1
  import { InteractionTypeKey } from "@frak-labs/core-sdk";
2
- import * as preact from "preact";
2
+ import * as _$preact from "preact";
3
3
 
4
4
  //#region src/components/ButtonWallet/types.d.ts
5
5
  /**
@@ -7,6 +7,7 @@ import * as preact from "preact";
7
7
  * @inline
8
8
  */
9
9
  type ButtonWalletProps = {
10
+ placement?: string;
10
11
  /**
11
12
  * Classname to apply to the button
12
13
  */
@@ -55,14 +56,21 @@ type ButtonWalletProps = {
55
56
  * <frak-button-wallet use-reward target-interaction="custom.customerMeeting"></frak-button-wallet>
56
57
  * ```
57
58
  *
59
+ * @example
60
+ * Using placement:
61
+ * ```html
62
+ * <frak-button-wallet placement="hero-wallet"></frak-button-wallet>
63
+ * ```
64
+ *
58
65
  * @see {@link @frak-labs/core-sdk!actions.modalBuilder | `modalBuilder()`} for more info about the modal display
59
66
  * @see {@link @frak-labs/core-sdk!actions.getMerchantInformation | `getMerchantInformation()`} for more info about the estimated reward fetching
60
67
  */
61
68
  declare function ButtonWallet({
69
+ placement: placementId,
62
70
  classname,
63
71
  useReward: rawUseReward,
64
72
  targetInteraction
65
- }: ButtonWalletProps): preact.JSX.Element;
73
+ }: ButtonWalletProps): _$preact.JSX.Element | null;
66
74
  //#endregion
67
75
  //#region src/components/ButtonWallet/index.d.ts
68
76
  /**
@@ -1,10 +1,7 @@
1
- import { i as openWalletModal, n as registerWebComponent, t as useClientReady } from "./useClientReady-iCtUeDsc.js";
2
- import { t as useReward } from "./useReward-DAkT-7wT.js";
3
- import { trackEvent } from "@frak-labs/core-sdk";
4
- import { cx } from "class-variance-authority";
1
+ import { a as registerWebComponent, i as useClientReady, n as buildStyleContent, o as openWalletModal, t as usePlacement } from "./usePlacement-V7NrKoub.js";
2
+ import { t as useReward } from "./useReward-DU3_yP8Q.js";
5
3
  import { useEffect, useMemo, useState } from "preact/hooks";
6
- import { jsx, jsxs } from "preact/jsx-runtime";
7
-
4
+ import { Fragment, jsx, jsxs } from "preact/jsx-runtime";
8
5
  //#region src/components/ButtonWallet/assets/GiftIcon.tsx
9
6
  function GiftIcon(props) {
10
7
  return /* @__PURE__ */ jsxs("svg", {
@@ -22,22 +19,48 @@ function GiftIcon(props) {
22
19
  })]
23
20
  });
24
21
  }
25
-
26
- //#endregion
27
- //#region src/components/ButtonWallet/ButtonWallet.module.css?css_module
28
- const classes = {
29
- "reward": "Kl62ia_reward",
30
- "button__left": "Kl62ia_button__left",
31
- "button": "Kl62ia_button",
32
- "button__right": "Kl62ia_button__right"
33
- };
34
- const _reward0 = classes["reward"];
35
- const _button__left0 = classes["button__left"];
36
- const _button0 = classes["button"];
37
- const _button__right0 = classes["button__right"];
38
-
39
22
  //#endregion
40
23
  //#region src/components/ButtonWallet/ButtonWallet.tsx
24
+ const componentCss = `
25
+ .button {
26
+ all: unset;
27
+ position: fixed;
28
+ bottom: 20px;
29
+ z-index: 2000000;
30
+ display: flex;
31
+ justify-content: center;
32
+ align-items: center;
33
+ background-color: #3e557e;
34
+ width: 45px;
35
+ height: 45px;
36
+ border-radius: 50%;
37
+ cursor: pointer;
38
+ text-align: center;
39
+ font-size: 24px;
40
+ }
41
+
42
+ .button__left {
43
+ left: 20px;
44
+ }
45
+
46
+ .button__right {
47
+ right: 20px;
48
+ }
49
+
50
+ .reward {
51
+ position: absolute;
52
+ top: -4px;
53
+ right: 27px;
54
+ padding: 2px 3px;
55
+ border-radius: 5px;
56
+ background: #ff3f3f;
57
+ font-size: 9px;
58
+ color: #fff;
59
+ font-weight: 600;
60
+ white-space: nowrap;
61
+ line-height: 9px;
62
+ }
63
+ `;
41
64
  /**
42
65
  * Button to open wallet modal
43
66
  *
@@ -70,40 +93,56 @@ const _button__right0 = classes["button__right"];
70
93
  * <frak-button-wallet use-reward target-interaction="custom.customerMeeting"></frak-button-wallet>
71
94
  * ```
72
95
  *
96
+ * @example
97
+ * Using placement:
98
+ * ```html
99
+ * <frak-button-wallet placement="hero-wallet"></frak-button-wallet>
100
+ * ```
101
+ *
73
102
  * @see {@link @frak-labs/core-sdk!actions.modalBuilder | `modalBuilder()`} for more info about the modal display
74
103
  * @see {@link @frak-labs/core-sdk!actions.getMerchantInformation | `getMerchantInformation()`} for more info about the estimated reward fetching
75
104
  */
76
- function ButtonWallet({ classname = "", useReward: rawUseReward, targetInteraction }) {
77
- const shouldUseReward = useMemo(() => rawUseReward !== void 0, [rawUseReward]);
78
- const { isClientReady } = useClientReady();
79
- const { reward } = useReward(shouldUseReward && isClientReady, targetInteraction);
105
+ function ButtonWallet({ placement: placementId, classname = "", useReward: rawUseReward, targetInteraction }) {
106
+ const placement = usePlacement(placementId);
107
+ const resolvedTargetInteraction = useMemo(() => placement?.targetInteraction !== void 0 ? placement.targetInteraction : targetInteraction, [placement?.targetInteraction, targetInteraction]);
108
+ const shouldUseReward = useMemo(() => rawUseReward === true, [rawUseReward]);
109
+ const { shouldRender, isHidden, isClientReady } = useClientReady();
110
+ const { reward } = useReward(shouldUseReward && isClientReady, resolvedTargetInteraction);
80
111
  const [position, setPosition] = useState("right");
81
- /**
82
- * Setup the position of the button
83
- */
84
112
  useEffect(() => {
85
- const position = window.FrakSetup?.modalWalletConfig?.metadata?.position;
86
- setPosition(position ?? "right");
87
- }, []);
88
- return /* @__PURE__ */ jsxs("button", {
113
+ const placementPosition = placement?.components?.buttonWallet?.position;
114
+ const configPosition = window.FrakSetup?.modalWalletConfig?.metadata?.position;
115
+ setPosition(placementPosition ?? configPosition ?? "right");
116
+ }, [placement?.components?.buttonWallet?.position]);
117
+ if (!shouldRender || isHidden) return null;
118
+ const buttonClass = [
119
+ "button",
120
+ "button__fadeIn",
121
+ position === "left" ? "button__left" : "button__right",
122
+ classname
123
+ ].filter(Boolean).join(" ");
124
+ return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("style", { children: buildStyleContent(componentCss, placement?.components?.buttonWallet?.css) }), /* @__PURE__ */ jsxs("button", {
89
125
  type: "button",
90
126
  "aria-label": "Open wallet",
91
- class: cx(classes.button, position === "left" ? classes.button__left : classes.button__right, classname, "override"),
127
+ part: "button",
92
128
  disabled: !isClientReady,
129
+ class: buttonClass,
93
130
  onClick: () => {
94
- trackEvent(window.FrakSetup.client, "wallet_button_clicked");
95
- openWalletModal();
131
+ openWalletModal(resolvedTargetInteraction, placementId);
96
132
  },
97
133
  children: [/* @__PURE__ */ jsx(GiftIcon, {}), reward && /* @__PURE__ */ jsx("span", {
98
- className: classes.reward,
134
+ class: "reward",
99
135
  children: reward
100
136
  })]
101
- });
137
+ })] });
102
138
  }
103
-
104
139
  //#endregion
105
140
  //#region src/components/ButtonWallet/index.ts
106
- registerWebComponent(ButtonWallet, "frak-button-wallet", [], { shadow: false });
107
-
141
+ registerWebComponent(ButtonWallet, "frak-button-wallet", [
142
+ "placement",
143
+ "classname",
144
+ "useReward",
145
+ "targetInteraction"
146
+ ], { shadow: true });
108
147
  //#endregion
109
- export { ButtonWallet };
148
+ export { ButtonWallet };
@@ -0,0 +1,33 @@
1
+ import { formatAmount, getCurrencyAmountKey, getSupportedCurrency } from "@frak-labs/core-sdk";
2
+ //#region src/utils/formatReward.ts
3
+ /**
4
+ * Format an {@link EstimatedReward} into a human-readable string.
5
+ *
6
+ * - `fixed` → e.g. `"5 €"`
7
+ * - `percentage` → if `basketAmount` is provided, computes the actual value
8
+ * (e.g. `"10 €"`), otherwise returns `"10 %"`
9
+ * - `tiered` → max tier value, e.g. `"50 €"`
10
+ */
11
+ function formatEstimatedReward(reward, currency, basketAmount) {
12
+ const supportedCurrency = getSupportedCurrency(currency);
13
+ const key = getCurrencyAmountKey(supportedCurrency);
14
+ switch (reward.payoutType) {
15
+ case "fixed": return formatAmount(Math.round(reward.amount[key]), supportedCurrency);
16
+ case "percentage":
17
+ if (basketAmount !== void 0) return formatAmount(Math.round(reward.percent * basketAmount / 100), supportedCurrency);
18
+ return `${reward.percent} %`;
19
+ case "tiered": {
20
+ const max = reward.tiers.reduce((acc, tier) => Math.max(acc, tier.amount[key]), 0);
21
+ return formatAmount(Math.round(max), supportedCurrency);
22
+ }
23
+ }
24
+ }
25
+ /**
26
+ * Replace the `{REWARD}` placeholder in a text string with a reward value.
27
+ * If no reward is provided, returns the text with `{REWARD}` stripped.
28
+ */
29
+ function applyRewardPlaceholder(text, reward) {
30
+ return reward ? text.replace("{REWARD}", reward) : text.replace("{REWARD}", "");
31
+ }
32
+ //#endregion
33
+ export { formatEstimatedReward as n, applyRewardPlaceholder as t };
@@ -1,4 +1,4 @@
1
- import * as preact from "preact";
1
+ import * as _$preact from "preact";
2
2
 
3
3
  //#region src/components/OpenInAppButton/types.d.ts
4
4
  /**
@@ -6,6 +6,7 @@ import * as preact from "preact";
6
6
  * @inline
7
7
  */
8
8
  type OpenInAppButtonProps = {
9
+ placement?: string;
9
10
  /**
10
11
  * Text to display on the button
11
12
  * @defaultValue `"Open in App"`
@@ -45,9 +46,10 @@ type OpenInAppButtonProps = {
45
46
  * ```
46
47
  */
47
48
  declare function OpenInAppButton({
49
+ placement: placementId,
48
50
  text,
49
51
  classname
50
- }: OpenInAppButtonProps): preact.JSX.Element | null;
52
+ }: OpenInAppButtonProps): _$preact.JSX.Element | null;
51
53
  //#endregion
52
54
  //#region src/components/OpenInAppButton/index.d.ts
53
55
  /**
package/dist/openInApp.js CHANGED
@@ -1,10 +1,8 @@
1
- import { n as registerWebComponent, t as useClientReady } from "./useClientReady-iCtUeDsc.js";
2
- import { t as Spinner } from "./Spinner-1CZC_zy6.js";
1
+ import { a as registerWebComponent, i as useClientReady, t as usePlacement } from "./usePlacement-V7NrKoub.js";
2
+ import { t as useLightDomStyles } from "./useLightDomStyles-C3lcOwY2.js";
3
3
  import { DEEP_LINK_SCHEME, trackEvent, triggerDeepLinkWithFallback } from "@frak-labs/core-sdk";
4
- import { cx } from "class-variance-authority";
5
4
  import { useMemo } from "preact/hooks";
6
- import { jsx, jsxs } from "preact/jsx-runtime";
7
-
5
+ import { jsx } from "preact/jsx-runtime";
8
6
  //#region src/utils/isMobile.ts
9
7
  /**
10
8
  * Check if the current device is a mobile device
@@ -21,13 +19,11 @@ function isMobile() {
21
19
  if (/Macintosh/i.test(navigator.userAgent) && navigator.maxTouchPoints > 1) return true;
22
20
  return false;
23
21
  }
24
-
25
22
  //#endregion
26
23
  //#region src/hooks/useIsMobile.ts
27
24
  function useIsMobile() {
28
25
  return { isMobile: useMemo(() => isMobile(), []) };
29
26
  }
30
-
31
27
  //#endregion
32
28
  //#region src/utils/openInApp.ts
33
29
  const DEFAULT_PATH = "wallet";
@@ -37,22 +33,20 @@ const DEFAULT_PATH = "wallet";
37
33
  * Uses visibility-based detection to determine if the app opened.
38
34
  * If the app is not installed (page stays visible after 2.5s),
39
35
  * tracks an "app_not_installed" event.
40
- *
41
- * @param path - Path to open in the app (default: "wallet")
42
36
  */
43
- function openFrakWalletApp(path = DEFAULT_PATH) {
37
+ function openFrakWalletApp(path = DEFAULT_PATH, placement) {
44
38
  const client = window.FrakSetup?.client;
45
- if (client) trackEvent(client, "open_in_app_clicked");
39
+ if (client) trackEvent(client, "open_in_app_clicked", {
40
+ path,
41
+ placement
42
+ });
46
43
  triggerDeepLinkWithFallback(`${DEEP_LINK_SCHEME}${path}`, { onFallback: () => {
47
- if (client) trackEvent(client, "app_not_installed");
44
+ if (client) trackEvent(client, "app_not_installed", {
45
+ path,
46
+ placement
47
+ });
48
48
  } });
49
49
  }
50
-
51
- //#endregion
52
- //#region src/components/OpenInAppButton/OpenInAppButton.module.css?css_module
53
- const classes = { "button": "XYfqGq_button" };
54
- const _button0 = classes["button"];
55
-
56
50
  //#endregion
57
51
  //#region src/components/OpenInAppButton/OpenInAppButton.tsx
58
52
  /**
@@ -81,30 +75,36 @@ const _button0 = classes["button"];
81
75
  * <frak-open-in-app classname="button button-primary"></frak-open-in-app>
82
76
  * ```
83
77
  */
84
- function OpenInAppButton({ text = "Open in App", classname = "" }) {
85
- const { isClientReady } = useClientReady();
78
+ function OpenInAppButton({ placement: placementId, text = "Open in App", classname = "" }) {
79
+ const placement = usePlacement(placementId);
80
+ const { shouldRender, isHidden, isClientReady } = useClientReady();
86
81
  const { isMobile } = useIsMobile();
87
- if (!isMobile) return null;
82
+ useLightDomStyles("frak-open-in-app", placementId, placement?.components?.openInApp?.css);
83
+ const resolvedText = placement?.components?.openInApp?.text ?? text;
84
+ if (!isMobile || !shouldRender || isHidden) return null;
88
85
  const handleClick = () => {
89
- openFrakWalletApp();
86
+ openFrakWalletApp(void 0, placementId);
90
87
  };
91
- return /* @__PURE__ */ jsxs("button", {
88
+ const buttonClass = [
89
+ "button",
90
+ "button__fadeIn",
91
+ classname
92
+ ].filter(Boolean).join(" ");
93
+ return /* @__PURE__ */ jsx("button", {
92
94
  type: "button",
93
95
  "aria-label": "Open in Frak Wallet app",
94
- className: cx(classes.button, classname, "override"),
95
96
  disabled: !isClientReady,
97
+ class: buttonClass,
96
98
  onClick: handleClick,
97
- children: [
98
- !isClientReady && /* @__PURE__ */ jsx(Spinner, {}),
99
- " ",
100
- text
101
- ]
99
+ children: resolvedText
102
100
  });
103
101
  }
104
-
105
102
  //#endregion
106
103
  //#region src/components/OpenInAppButton/index.ts
107
- registerWebComponent(OpenInAppButton, "frak-open-in-app", ["text"], { shadow: false });
108
-
104
+ registerWebComponent(OpenInAppButton, "frak-open-in-app", [
105
+ "text",
106
+ "placement",
107
+ "classname"
108
+ ], { shadow: false });
109
109
  //#endregion
110
- export { OpenInAppButton };
110
+ export { OpenInAppButton };