@frak-labs/components 1.0.10 → 1.0.11-beta.b456c7f7
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.
- package/cdn/Banner.B5D7REJq.js +167 -0
- package/cdn/ButtonShare.C8i7dA4y.js +1 -0
- package/cdn/ButtonWallet.DwFVkAGJ.js +40 -0
- package/cdn/GiftIcon.DT1i36Fm.js +1 -0
- package/cdn/OpenInAppButton.D1UzTuHx.js +1 -0
- package/cdn/PostPurchase.CuucvS-o.js +89 -0
- package/cdn/components.js +1 -1
- package/cdn/defaults.kWEdCyGS.js +58 -0
- package/cdn/embeddedWallet.CDUxjdX2.js +1 -0
- package/cdn/loader.js +1 -1
- package/cdn/replay-V6FXES7X.CNozpSRg.js +1 -0
- package/cdn/rewards.B6IAemE2.js +1 -0
- package/cdn/useGlobalComponents.BC6Jgzg5.js +1 -0
- package/cdn/useLightDomStyles.imPXuAtf.js +1 -0
- package/cdn/useReward.IXcdcQPk.js +1 -0
- package/dist/{GiftIcon-WEWSJ8kV.js → GiftIcon-BEzYdiux.js} +5 -5
- package/dist/banner.d.ts +1 -1
- package/dist/banner.js +21 -16
- package/dist/buttonShare.d.ts +3 -1
- package/dist/buttonShare.js +11 -9
- package/dist/buttonWallet.js +6 -4
- package/dist/i18n/defaults.d.ts +54 -0
- package/dist/i18n/defaults.js +70 -0
- package/dist/openInApp.d.ts +4 -2
- package/dist/openInApp.js +7 -5
- package/dist/postPurchase.d.ts +1 -1
- package/dist/postPurchase.js +27 -16
- package/dist/rewards-B5VmlrcI.js +145 -0
- package/dist/useGlobalComponents-CZ7Sh2tZ.js +17 -0
- package/dist/{useLightDomStyles-DPKMhggr.js → useLightDomStyles-DphuQhvx.js} +1 -1
- package/dist/{usePlacement-DTN6H6vW.js → usePlacement-4PoDbn2X.js} +54 -12
- package/dist/useReward-DD2mMUN0.js +39 -0
- package/package.json +9 -3
- package/cdn/Banner.De5nN3cX.js +0 -167
- package/cdn/ButtonShare.DHSekTjv.js +0 -1
- package/cdn/ButtonWallet.Cvp_1Tx2.js +0 -40
- package/cdn/GiftIcon.DnSW4dJQ.js +0 -1
- package/cdn/OpenInAppButton.CpO_E-l-.js +0 -1
- package/cdn/PostPurchase.CuO1kjaz.js +0 -89
- package/cdn/embeddedWallet.BS-9u4Be.js +0 -1
- package/cdn/formatReward.DNFkBh_E.js +0 -1
- package/cdn/replay-V6FXES7X.BoL9fAjx.js +0 -1
- package/cdn/useGlobalComponents.pjgSwLk9.js +0 -1
- package/cdn/useLightDomStyles.2RQE6Iby.js +0 -1
- package/cdn/usePlacement.CRfzWKVY.js +0 -58
- package/cdn/useReward.DSMOMYCh.js +0 -1
- package/dist/formatReward-D3CkH7It.js +0 -39
- package/dist/useGlobalComponents-mSs9unyN.js +0 -21
- package/dist/useReward-DSrQsn3r.js +0 -65
|
@@ -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 };
|
package/dist/openInApp.d.ts
CHANGED
|
@@ -6,8 +6,10 @@
|
|
|
6
6
|
type OpenInAppButtonProps = {
|
|
7
7
|
placement?: string;
|
|
8
8
|
/**
|
|
9
|
-
* Text to display on the button
|
|
10
|
-
*
|
|
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"`).
|
|
11
13
|
*/
|
|
12
14
|
text?: string;
|
|
13
15
|
/**
|
package/dist/openInApp.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { t as useLightDomStyles } from "./useLightDomStyles-
|
|
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
|
|
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":
|
|
80
|
+
"aria-label": componentDefaults[lang].openInApp.ariaLabel,
|
|
79
81
|
disabled: !isClientReady,
|
|
80
82
|
class: buttonClass,
|
|
81
83
|
onClick: handleClick,
|
package/dist/postPurchase.d.ts
CHANGED
|
@@ -141,7 +141,7 @@ declare function PostPurchase({
|
|
|
141
141
|
preview,
|
|
142
142
|
previewVariant,
|
|
143
143
|
products,
|
|
144
|
-
imageUrl
|
|
144
|
+
imageUrl: propImageUrl
|
|
145
145
|
}: PostPurchaseProps): import("preact").JSX.Element | null;
|
|
146
146
|
//#endregion
|
|
147
147
|
//#region src/components/PostPurchase/index.d.ts
|
package/dist/postPurchase.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { t as useGlobalComponents } from "./useGlobalComponents-
|
|
3
|
-
import { t as useLightDomStyles } from "./useLightDomStyles-
|
|
4
|
-
import { n as
|
|
5
|
-
import {
|
|
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-B5VmlrcI.js";
|
|
5
|
+
import { componentDefaults } from "./i18n/defaults.js";
|
|
6
|
+
import { i as LogoFrakWithName, n as cssSource$2, t as GiftIcon } from "./GiftIcon-BEzYdiux.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
|
|
121
|
-
|
|
122
|
-
|
|
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" ?
|
|
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
|
|
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 ?
|
|
215
|
-
cta: rewardText ?
|
|
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,
|
|
@@ -289,7 +300,7 @@ function PostPurchase({ customerId, orderId, token, sharingUrl, merchantId, plac
|
|
|
289
300
|
"aria-hidden": "true",
|
|
290
301
|
className: `${icon} button`,
|
|
291
302
|
children: /* @__PURE__ */ jsx("path", {
|
|
292
|
-
d: "M13.
|
|
303
|
+
d: "M13.9 11.14C13.99 11.05 14.15 11.11 14.15 11.24V11.64C14.15 13.05 12.63 14.19 10.75 14.19C8.87 14.19 7.34 13.05 7.34 11.64V11.24C7.34 11.11 7.51 11.05 7.59 11.14C8.35 11.93 9.48 12.43 10.75 12.43C12.01 12.43 13.15 11.93 13.9 11.14ZM1.85 9.65C1.85 9.51 2.01 9.44 2.1 9.54C2.85 10.32 3.99 10.82 5.25 10.82C5.52 10.82 5.79 10.8 6.04 10.76C6.26 10.72 6.47 10.88 6.47 11.1V12.17C6.47 12.32 6.37 12.45 6.22 12.48C5.92 12.55 5.59 12.59 5.25 12.59C3.37 12.59 1.85 11.45 1.85 10.04V9.65ZM10.75 6.21C12.63 6.21 14.15 7.35 14.15 8.75C14.15 10.16 12.63 11.3 10.75 11.3C8.87 11.3 7.34 10.16 7.34 8.75C7.34 7.35 8.87 6.21 10.75 6.21ZM1.85 6.85C1.85 6.71 2.01 6.65 2.1 6.74C2.85 7.53 3.99 8.03 5.25 8.03C5.52 8.03 5.79 8 6.04 7.96C6.26 7.92 6.47 8.09 6.47 8.3V9.37C6.47 9.52 6.37 9.65 6.22 9.69C5.92 9.75 5.59 9.79 5.25 9.79C3.37 9.79 1.85 8.65 1.85 7.24V6.85ZM5.25 1.81C7.13 1.81 8.66 2.95 8.66 4.36C8.66 5.76 7.13 6.9 5.25 6.9C3.37 6.9 1.85 5.76 1.85 4.36C1.85 2.95 3.37 1.81 5.25 1.81Z",
|
|
293
304
|
fill: "currentColor"
|
|
294
305
|
})
|
|
295
306
|
})]
|
|
@@ -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.replaceAll(`{REWARD}`, t) : e.replaceAll(`{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 };
|
|
@@ -3,7 +3,8 @@ import * as coreSdkIndex from "@frak-labs/core-sdk";
|
|
|
3
3
|
import { decompressJsonFromB64, deleteQueryParamCaseInsensitive, getQueryParamCaseInsensitive, sdkConfigStore, setupClient, trackEvent, withCache } from "@frak-labs/core-sdk";
|
|
4
4
|
import * as coreSdkActions from "@frak-labs/core-sdk/actions";
|
|
5
5
|
import { displaySharingPage } from "@frak-labs/core-sdk/actions";
|
|
6
|
-
import {
|
|
6
|
+
import { useCallback, useEffect, useState } from "preact/hooks";
|
|
7
|
+
import { useSyncExternalStore } from "preact/compat";
|
|
7
8
|
//#region src/actions/sharingPage.ts
|
|
8
9
|
async function openSharingPage(targetInteraction, placement, options) {
|
|
9
10
|
if (!window.FrakSetup?.client) {
|
|
@@ -341,6 +342,49 @@ function useClientReady() {
|
|
|
341
342
|
};
|
|
342
343
|
}
|
|
343
344
|
//#endregion
|
|
345
|
+
//#region src/hooks/sdkConfigSubscription.ts
|
|
346
|
+
/**
|
|
347
|
+
* Shared `useSyncExternalStore` plumbing for the SDK config store.
|
|
348
|
+
*
|
|
349
|
+
* The resolved merchant config lives on `window.__frakSdkConfig` and notifies
|
|
350
|
+
* via the `frak:config` CustomEvent (see `@frak-labs/core-sdk` `sdkConfigStore`).
|
|
351
|
+
* A single module-level `subscribe` keeps the reference stable across renders
|
|
352
|
+
* so `useSyncExternalStore` never re-subscribes, and lets every config-driven
|
|
353
|
+
* hook (`useLang`, `usePlacement`, `useGlobalComponents`) share one listener
|
|
354
|
+
* shape instead of each hand-rolling an effect + version counter.
|
|
355
|
+
*/
|
|
356
|
+
/**
|
|
357
|
+
* Subscribe to resolved-config changes. Stable reference (module-level) so
|
|
358
|
+
* `useSyncExternalStore` treats it as a constant store subscription.
|
|
359
|
+
*/
|
|
360
|
+
function subscribeSdkConfig(onStoreChange) {
|
|
361
|
+
if (typeof window === "undefined") return () => {};
|
|
362
|
+
window.addEventListener("frak:config", onStoreChange);
|
|
363
|
+
return () => window.removeEventListener("frak:config", onStoreChange);
|
|
364
|
+
}
|
|
365
|
+
//#endregion
|
|
366
|
+
//#region src/hooks/useLang.ts
|
|
367
|
+
/**
|
|
368
|
+
* Detect a supported language from the browser, defaulting to English.
|
|
369
|
+
* Only `en` / `fr` are recognised — anything else falls back to `en`.
|
|
370
|
+
*/
|
|
371
|
+
function detectBrowserLang() {
|
|
372
|
+
if (typeof navigator === "undefined") return "en";
|
|
373
|
+
return navigator.language?.split("-")[0] === "fr" ? "fr" : "en";
|
|
374
|
+
}
|
|
375
|
+
/**
|
|
376
|
+
* Resolve the active display language for the Web Components.
|
|
377
|
+
*
|
|
378
|
+
* Precedence: resolved SDK/backend config `lang` (driven by `metadata.lang`
|
|
379
|
+
* or the backend `/resolve` response) → browser language → `en`. Backed by
|
|
380
|
+
* `useSyncExternalStore` with a bare-string snapshot, so a `frak:config`
|
|
381
|
+
* dispatch only re-renders the component when the resolved language actually
|
|
382
|
+
* changes (see `@/i18n/defaults`).
|
|
383
|
+
*/
|
|
384
|
+
function useLang() {
|
|
385
|
+
return useSyncExternalStore(subscribeSdkConfig, () => sdkConfigStore.getConfig().lang ?? detectBrowserLang());
|
|
386
|
+
}
|
|
387
|
+
//#endregion
|
|
344
388
|
//#region src/styles/sharedCss.ts
|
|
345
389
|
const sharedCss = `
|
|
346
390
|
:host {
|
|
@@ -409,17 +453,15 @@ const lightDomBaseCss = `
|
|
|
409
453
|
function getPlacement(id) {
|
|
410
454
|
return sdkConfigStore.getConfig().placements?.[id];
|
|
411
455
|
}
|
|
456
|
+
/**
|
|
457
|
+
* Subscribe to a single resolved placement from the SDK config store.
|
|
458
|
+
*
|
|
459
|
+
* Backed by `useSyncExternalStore`: the snapshot is the stored placement
|
|
460
|
+
* object reference (stable between `frak:config` dispatches), so the component
|
|
461
|
+
* only re-renders when that placement actually changes.
|
|
462
|
+
*/
|
|
412
463
|
function usePlacement(placementId) {
|
|
413
|
-
|
|
414
|
-
useEffect(() => {
|
|
415
|
-
const onConfig = (_e) => {
|
|
416
|
-
setConfigVersion((v) => v + 1);
|
|
417
|
-
};
|
|
418
|
-
window.addEventListener("frak:config", onConfig);
|
|
419
|
-
setConfigVersion((v) => v + 1);
|
|
420
|
-
return () => window.removeEventListener("frak:config", onConfig);
|
|
421
|
-
}, []);
|
|
422
|
-
return useMemo(() => placementId ? getPlacement(placementId) : void 0, [placementId, configVersion]);
|
|
464
|
+
return useSyncExternalStore(subscribeSdkConfig, useCallback(() => placementId ? getPlacement(placementId) : void 0, [placementId]));
|
|
423
465
|
}
|
|
424
466
|
//#endregion
|
|
425
|
-
export {
|
|
467
|
+
export { subscribeSdkConfig as a, sanitizeProductList as c, useLang as i, openSharingPage as l, buildStyleContent as n, useClientReady as o, lightDomBaseCss as r, registerWebComponent as s, usePlacement as t };
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { t as E } from "./rewards-B5VmlrcI.js";
|
|
2
|
+
import { getMerchantInformation } from "@frak-labs/core-sdk/actions";
|
|
3
|
+
import { useEffect, useState } from "preact/hooks";
|
|
4
|
+
//#region src/hooks/useReward.ts
|
|
5
|
+
/**
|
|
6
|
+
* Hook to fetch and format the best reward for a given interaction type.
|
|
7
|
+
*
|
|
8
|
+
* Calls `getMerchantInformation`, picks the highest-value reward across all
|
|
9
|
+
* matching live campaigns for the requested `audience` side, and returns it as
|
|
10
|
+
* a formatted string.
|
|
11
|
+
*
|
|
12
|
+
* @param shouldUseReward - Whether to fetch the reward at all
|
|
13
|
+
* @param targetInteraction - Optional filter by interaction type (e.g. "purchase")
|
|
14
|
+
* @param audience - Reward side to display: `"referrer"` (default) or `"referee"`
|
|
15
|
+
* @returns Object containing the formatted reward string, or undefined if unavailable
|
|
16
|
+
*/
|
|
17
|
+
function useReward(shouldUseReward, targetInteraction, audience) {
|
|
18
|
+
const [reward, setReward] = useState(void 0);
|
|
19
|
+
useEffect(() => {
|
|
20
|
+
if (!shouldUseReward) return;
|
|
21
|
+
const client = window.FrakSetup?.client;
|
|
22
|
+
if (!client) return;
|
|
23
|
+
getMerchantInformation(client).then((merchantInfo) => {
|
|
24
|
+
const best = E(merchantInfo.rewards, {
|
|
25
|
+
currency: client.config.metadata?.currency,
|
|
26
|
+
targetInteraction,
|
|
27
|
+
audience
|
|
28
|
+
});
|
|
29
|
+
if (best && best.payoutType !== "percentage") setReward(best.formatted);
|
|
30
|
+
}).catch(() => {});
|
|
31
|
+
}, [
|
|
32
|
+
shouldUseReward,
|
|
33
|
+
targetInteraction,
|
|
34
|
+
audience
|
|
35
|
+
]);
|
|
36
|
+
return { reward };
|
|
37
|
+
}
|
|
38
|
+
//#endregion
|
|
39
|
+
export { useReward as t };
|
package/package.json
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"url": "https://twitter.com/QNivelais"
|
|
12
12
|
}
|
|
13
13
|
],
|
|
14
|
-
"version": "1.0.
|
|
14
|
+
"version": "1.0.11-beta.b456c7f7",
|
|
15
15
|
"description": "Frak Wallet components, helping any person to interact with the Frak wallet.",
|
|
16
16
|
"repository": {
|
|
17
17
|
"url": "https://github.com/frak-id/wallet",
|
|
@@ -66,6 +66,12 @@
|
|
|
66
66
|
"import": "./dist/banner.js",
|
|
67
67
|
"types": "./dist/banner.d.ts"
|
|
68
68
|
},
|
|
69
|
+
"./i18n/defaults": {
|
|
70
|
+
"development": "./src/i18n/defaults.ts",
|
|
71
|
+
"production": "./src/i18n/defaults.ts",
|
|
72
|
+
"import": "./dist/i18n/defaults.js",
|
|
73
|
+
"types": "./dist/i18n/defaults.d.ts"
|
|
74
|
+
},
|
|
69
75
|
"./cdn": {
|
|
70
76
|
"import": "./cdn/components.js"
|
|
71
77
|
},
|
|
@@ -86,8 +92,8 @@
|
|
|
86
92
|
"publish": "echo 'Publishing components...'"
|
|
87
93
|
},
|
|
88
94
|
"dependencies": {
|
|
89
|
-
"@frak-labs/core-sdk": "1.1.
|
|
90
|
-
"@frak-labs/frame-connector": "0.2.0",
|
|
95
|
+
"@frak-labs/core-sdk": "1.1.6-beta.b456c7f7",
|
|
96
|
+
"@frak-labs/frame-connector": "0.2.0-beta.b456c7f7",
|
|
91
97
|
"preact": "^10.29.0",
|
|
92
98
|
"preact-custom-element": "^4.6.0",
|
|
93
99
|
"@frak-labs/design-system": "0.0.0"
|