@frak-labs/components 0.0.26-beta.b38eef2e → 0.0.26-beta.d04602ec
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.BfkMel9Q.js +1 -0
- package/cdn/ButtonShare.BM9Inhmf.js +1 -0
- package/cdn/ButtonWallet.B7UmJcbb.js +40 -0
- package/cdn/OpenInAppButton.B4mrsz6L.js +1 -0
- package/cdn/PostPurchase.BIc0C4Ma.js +1 -0
- package/cdn/components.js +1 -1
- package/cdn/formatReward.C8hlSKRj.js +1 -0
- package/cdn/jsxRuntime.module.5UNmmhNi.js +138 -0
- package/cdn/loader.css +0 -14
- package/cdn/loader.js +66 -1
- package/cdn/useLightDomStyles.D895e4W1.js +1 -0
- package/cdn/useReward.DEU0AF3P.js +1 -0
- package/cdn/useShareModal.CN9_P7Sl.js +1 -0
- package/dist/banner.d.ts +103 -0
- package/dist/banner.js +187 -0
- package/dist/buttonShare.d.ts +7 -5
- package/dist/buttonShare.js +59 -94
- package/dist/buttonWallet.d.ts +9 -1
- package/dist/buttonWallet.js +78 -33
- package/dist/formatReward-6JQldDEC.js +28 -0
- package/dist/openInApp.d.ts +2 -0
- package/dist/openInApp.js +22 -20
- package/dist/postPurchase.d.ts +116 -0
- package/dist/postPurchase.js +146 -0
- package/dist/useLightDomStyles-DukxuNnJ.js +44 -0
- package/dist/usePlacement-BbMuz8_A.js +340 -0
- package/dist/useReward-CI2yRrCj.js +67 -0
- package/dist/useShareModal-DHlayNqk.js +55 -0
- package/package.json +21 -15
- package/cdn/ButtonShare.CSPl5Bi5.js +0 -1
- package/cdn/ButtonWallet.3Hp62hGr.js +0 -1
- package/cdn/OpenInAppButton.BTvukMkp.js +0 -1
- package/cdn/Spinner.DQogVqic.js +0 -1
- package/cdn/initFrakSdk.CMgrZQwQ.js +0 -14
- package/cdn/useClientReady.CKKC4IMk.js +0 -1
- package/dist/Spinner-Btnwk01x.js +0 -36
- package/dist/Spinner-CHZD3tMn.css +0 -1
- package/dist/buttonShare.css +0 -1
- package/dist/buttonWallet.css +0 -1
- package/dist/openInApp.css +0 -1
- package/dist/useClientReady-0vKBG0-p.js +0 -197
- package/dist/useReward-DAkT-7wT.js +0 -48
package/dist/buttonWallet.js
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { t as useReward } from "./useReward-
|
|
1
|
+
import { a as useClientReady, o as registerWebComponent, r as buildStyleContent, s as openWalletModal, t as usePlacement } from "./usePlacement-BbMuz8_A.js";
|
|
2
|
+
import { t as useReward } from "./useReward-CI2yRrCj.js";
|
|
3
3
|
import { trackEvent } from "@frak-labs/core-sdk";
|
|
4
|
-
import { cx } from "class-variance-authority";
|
|
5
4
|
import { useEffect, useMemo, useState } from "preact/hooks";
|
|
6
|
-
import { jsx, jsxs } from "preact/jsx-runtime";
|
|
5
|
+
import { Fragment, jsx, jsxs } from "preact/jsx-runtime";
|
|
7
6
|
|
|
8
7
|
//#region src/components/ButtonWallet/assets/GiftIcon.tsx
|
|
9
8
|
function GiftIcon(props) {
|
|
@@ -23,21 +22,48 @@ function GiftIcon(props) {
|
|
|
23
22
|
});
|
|
24
23
|
}
|
|
25
24
|
|
|
26
|
-
//#endregion
|
|
27
|
-
//#region src/components/ButtonWallet/ButtonWallet.module.css?css_module
|
|
28
|
-
const classes = {
|
|
29
|
-
"button__left": "Kl62ia_button__left",
|
|
30
|
-
"button__right": "Kl62ia_button__right",
|
|
31
|
-
"button": "Kl62ia_button",
|
|
32
|
-
"reward": "Kl62ia_reward"
|
|
33
|
-
};
|
|
34
|
-
const _button__left0 = classes["button__left"];
|
|
35
|
-
const _button__right0 = classes["button__right"];
|
|
36
|
-
const _button0 = classes["button"];
|
|
37
|
-
const _reward0 = classes["reward"];
|
|
38
|
-
|
|
39
25
|
//#endregion
|
|
40
26
|
//#region src/components/ButtonWallet/ButtonWallet.tsx
|
|
27
|
+
const componentCss = `
|
|
28
|
+
.button {
|
|
29
|
+
all: unset;
|
|
30
|
+
position: fixed;
|
|
31
|
+
bottom: 20px;
|
|
32
|
+
z-index: 2000000;
|
|
33
|
+
display: flex;
|
|
34
|
+
justify-content: center;
|
|
35
|
+
align-items: center;
|
|
36
|
+
background-color: #3e557e;
|
|
37
|
+
width: 45px;
|
|
38
|
+
height: 45px;
|
|
39
|
+
border-radius: 50%;
|
|
40
|
+
cursor: pointer;
|
|
41
|
+
text-align: center;
|
|
42
|
+
font-size: 24px;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.button__left {
|
|
46
|
+
left: 20px;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.button__right {
|
|
50
|
+
right: 20px;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.reward {
|
|
54
|
+
position: absolute;
|
|
55
|
+
top: -4px;
|
|
56
|
+
right: 27px;
|
|
57
|
+
padding: 2px 3px;
|
|
58
|
+
border-radius: 5px;
|
|
59
|
+
background: #ff3f3f;
|
|
60
|
+
font-size: 9px;
|
|
61
|
+
color: #fff;
|
|
62
|
+
font-weight: 600;
|
|
63
|
+
white-space: nowrap;
|
|
64
|
+
line-height: 9px;
|
|
65
|
+
}
|
|
66
|
+
`;
|
|
41
67
|
/**
|
|
42
68
|
* Button to open wallet modal
|
|
43
69
|
*
|
|
@@ -70,40 +96,59 @@ const _reward0 = classes["reward"];
|
|
|
70
96
|
* <frak-button-wallet use-reward target-interaction="custom.customerMeeting"></frak-button-wallet>
|
|
71
97
|
* ```
|
|
72
98
|
*
|
|
99
|
+
* @example
|
|
100
|
+
* Using placement:
|
|
101
|
+
* ```html
|
|
102
|
+
* <frak-button-wallet placement="hero-wallet"></frak-button-wallet>
|
|
103
|
+
* ```
|
|
104
|
+
*
|
|
73
105
|
* @see {@link @frak-labs/core-sdk!actions.modalBuilder | `modalBuilder()`} for more info about the modal display
|
|
74
106
|
* @see {@link @frak-labs/core-sdk!actions.getMerchantInformation | `getMerchantInformation()`} for more info about the estimated reward fetching
|
|
75
107
|
*/
|
|
76
|
-
function ButtonWallet({ classname = "", useReward: rawUseReward, targetInteraction }) {
|
|
77
|
-
const
|
|
78
|
-
const
|
|
79
|
-
const
|
|
108
|
+
function ButtonWallet({ placement: placementId, classname = "", useReward: rawUseReward, targetInteraction }) {
|
|
109
|
+
const placement = usePlacement(placementId);
|
|
110
|
+
const resolvedTargetInteraction = useMemo(() => placement?.targetInteraction !== void 0 ? placement.targetInteraction : targetInteraction, [placement?.targetInteraction, targetInteraction]);
|
|
111
|
+
const shouldUseReward = useMemo(() => rawUseReward === true, [rawUseReward]);
|
|
112
|
+
const { shouldRender, isHidden, isClientReady } = useClientReady();
|
|
113
|
+
const { reward } = useReward(shouldUseReward && isClientReady, resolvedTargetInteraction);
|
|
80
114
|
const [position, setPosition] = useState("right");
|
|
81
|
-
/**
|
|
82
|
-
* Setup the position of the button
|
|
83
|
-
*/
|
|
84
115
|
useEffect(() => {
|
|
85
|
-
const
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
116
|
+
const placementPosition = placement?.components?.buttonWallet?.position;
|
|
117
|
+
const configPosition = window.FrakSetup?.modalWalletConfig?.metadata?.position;
|
|
118
|
+
setPosition(placementPosition ?? configPosition ?? "right");
|
|
119
|
+
}, [placement?.components?.buttonWallet?.position]);
|
|
120
|
+
if (!shouldRender || isHidden) return null;
|
|
121
|
+
const buttonClass = [
|
|
122
|
+
"button",
|
|
123
|
+
"button__fadeIn",
|
|
124
|
+
position === "left" ? "button__left" : "button__right",
|
|
125
|
+
classname
|
|
126
|
+
].filter(Boolean).join(" ");
|
|
127
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("style", { children: buildStyleContent(componentCss, placement?.components?.buttonWallet?.css) }), /* @__PURE__ */ jsxs("button", {
|
|
89
128
|
type: "button",
|
|
90
129
|
"aria-label": "Open wallet",
|
|
91
|
-
|
|
130
|
+
part: "button",
|
|
92
131
|
disabled: !isClientReady,
|
|
132
|
+
class: buttonClass,
|
|
93
133
|
onClick: () => {
|
|
94
134
|
trackEvent(window.FrakSetup.client, "wallet_button_clicked");
|
|
95
|
-
openWalletModal();
|
|
135
|
+
openWalletModal(resolvedTargetInteraction, placementId);
|
|
96
136
|
},
|
|
97
137
|
children: [/* @__PURE__ */ jsx(GiftIcon, {}), reward && /* @__PURE__ */ jsx("span", {
|
|
98
|
-
|
|
138
|
+
class: "reward",
|
|
99
139
|
children: reward
|
|
100
140
|
})]
|
|
101
|
-
});
|
|
141
|
+
})] });
|
|
102
142
|
}
|
|
103
143
|
|
|
104
144
|
//#endregion
|
|
105
145
|
//#region src/components/ButtonWallet/index.ts
|
|
106
|
-
registerWebComponent(ButtonWallet, "frak-button-wallet", [
|
|
146
|
+
registerWebComponent(ButtonWallet, "frak-button-wallet", [
|
|
147
|
+
"placement",
|
|
148
|
+
"classname",
|
|
149
|
+
"useReward",
|
|
150
|
+
"targetInteraction"
|
|
151
|
+
], { shadow: true });
|
|
107
152
|
|
|
108
153
|
//#endregion
|
|
109
154
|
export { ButtonWallet };
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { formatAmount, getCurrencyAmountKey, getSupportedCurrency } from "@frak-labs/core-sdk";
|
|
2
|
+
|
|
3
|
+
//#region src/utils/formatReward.ts
|
|
4
|
+
/**
|
|
5
|
+
* Format an {@link EstimatedReward} into a human-readable string.
|
|
6
|
+
*
|
|
7
|
+
* - `fixed` → e.g. `"5 €"`
|
|
8
|
+
* - `percentage` → if `basketAmount` is provided, computes the actual value
|
|
9
|
+
* (e.g. `"10 €"`), otherwise returns `"10 %"`
|
|
10
|
+
* - `tiered` → max tier value, e.g. `"50 €"`
|
|
11
|
+
*/
|
|
12
|
+
function formatEstimatedReward(reward, currency, basketAmount) {
|
|
13
|
+
const supportedCurrency = getSupportedCurrency(currency);
|
|
14
|
+
const key = getCurrencyAmountKey(supportedCurrency);
|
|
15
|
+
switch (reward.payoutType) {
|
|
16
|
+
case "fixed": return formatAmount(Math.round(reward.amount[key]), supportedCurrency);
|
|
17
|
+
case "percentage":
|
|
18
|
+
if (basketAmount !== void 0) return formatAmount(Math.round(reward.percent * basketAmount / 100), supportedCurrency);
|
|
19
|
+
return `${reward.percent} %`;
|
|
20
|
+
case "tiered": {
|
|
21
|
+
const max = reward.tiers.reduce((acc, tier) => Math.max(acc, tier.amount[key]), 0);
|
|
22
|
+
return formatAmount(Math.round(max), supportedCurrency);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
//#endregion
|
|
28
|
+
export { formatEstimatedReward as t };
|
package/dist/openInApp.d.ts
CHANGED
|
@@ -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,6 +46,7 @@ type OpenInAppButtonProps = {
|
|
|
45
46
|
* ```
|
|
46
47
|
*/
|
|
47
48
|
declare function OpenInAppButton({
|
|
49
|
+
placement: placementId,
|
|
48
50
|
text,
|
|
49
51
|
classname
|
|
50
52
|
}: OpenInAppButtonProps): preact.JSX.Element | null;
|
package/dist/openInApp.js
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { t as
|
|
1
|
+
import { a as useClientReady, o as registerWebComponent, t as usePlacement } from "./usePlacement-BbMuz8_A.js";
|
|
2
|
+
import { t as useLightDomStyles } from "./useLightDomStyles-DukxuNnJ.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
|
|
5
|
+
import { jsx } from "preact/jsx-runtime";
|
|
7
6
|
|
|
8
7
|
//#region src/utils/isMobile.ts
|
|
9
8
|
/**
|
|
@@ -48,11 +47,6 @@ function openFrakWalletApp(path = DEFAULT_PATH) {
|
|
|
48
47
|
} });
|
|
49
48
|
}
|
|
50
49
|
|
|
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,38 @@ 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
|
|
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
|
-
|
|
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
86
|
openFrakWalletApp();
|
|
90
87
|
};
|
|
91
|
-
|
|
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
102
|
|
|
105
103
|
//#endregion
|
|
106
104
|
//#region src/components/OpenInAppButton/index.ts
|
|
107
|
-
registerWebComponent(OpenInAppButton, "frak-open-in-app", [
|
|
105
|
+
registerWebComponent(OpenInAppButton, "frak-open-in-app", [
|
|
106
|
+
"text",
|
|
107
|
+
"placement",
|
|
108
|
+
"classname"
|
|
109
|
+
], { shadow: false });
|
|
108
110
|
|
|
109
111
|
//#endregion
|
|
110
112
|
export { OpenInAppButton };
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import * as preact from "preact";
|
|
2
|
+
|
|
3
|
+
//#region src/components/PostPurchase/types.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Props for the {@link PostPurchase} component.
|
|
6
|
+
* @inline
|
|
7
|
+
*/
|
|
8
|
+
type PostPurchaseProps = {
|
|
9
|
+
/**
|
|
10
|
+
* Merchant customer ID for purchase tracking fallback.
|
|
11
|
+
* All three tracking props (`customerId`, `orderId`, `token`) must be
|
|
12
|
+
* present for tracking to fire.
|
|
13
|
+
*/
|
|
14
|
+
customerId?: string;
|
|
15
|
+
/**
|
|
16
|
+
* Merchant order ID for purchase tracking fallback.
|
|
17
|
+
*/
|
|
18
|
+
orderId?: string;
|
|
19
|
+
/**
|
|
20
|
+
* Checkout token for purchase tracking fallback.
|
|
21
|
+
*/
|
|
22
|
+
token?: string;
|
|
23
|
+
/**
|
|
24
|
+
* Base URL to share. Falls back to the merchant domain returned by
|
|
25
|
+
* the backend when omitted.
|
|
26
|
+
*/
|
|
27
|
+
sharingUrl?: string;
|
|
28
|
+
/**
|
|
29
|
+
* Override the merchant ID resolved from the SDK config.
|
|
30
|
+
*/
|
|
31
|
+
merchantId?: string;
|
|
32
|
+
/**
|
|
33
|
+
* Placement ID for backend-driven CSS customization.
|
|
34
|
+
*/
|
|
35
|
+
placement?: string;
|
|
36
|
+
/**
|
|
37
|
+
* CSS class names passed through to the root element (Light DOM).
|
|
38
|
+
*/
|
|
39
|
+
classname?: string;
|
|
40
|
+
/**
|
|
41
|
+
* Force a display variant instead of relying on the backend evaluation.
|
|
42
|
+
*/
|
|
43
|
+
variant?: "referrer" | "referee";
|
|
44
|
+
/**
|
|
45
|
+
* Override the message shown to referrers.
|
|
46
|
+
* Use `{REWARD}` as placeholder for the reward amount.
|
|
47
|
+
*/
|
|
48
|
+
referrerText?: string;
|
|
49
|
+
/**
|
|
50
|
+
* Override the message shown to referees.
|
|
51
|
+
* Use `{REWARD}` as placeholder for the reward amount.
|
|
52
|
+
*/
|
|
53
|
+
refereeText?: string;
|
|
54
|
+
/**
|
|
55
|
+
* Override the CTA button text.
|
|
56
|
+
* Use `{REWARD}` as placeholder for the reward amount.
|
|
57
|
+
*/
|
|
58
|
+
ctaText?: string;
|
|
59
|
+
};
|
|
60
|
+
//#endregion
|
|
61
|
+
//#region src/components/PostPurchase/PostPurchase.d.ts
|
|
62
|
+
/**
|
|
63
|
+
* Post-purchase card component.
|
|
64
|
+
*
|
|
65
|
+
* Renders an inline card on the merchant's thank-you / order-status page
|
|
66
|
+
* that either congratulates a referee or invites a referrer to share.
|
|
67
|
+
*
|
|
68
|
+
* Fetches referral status and merchant information via two independent
|
|
69
|
+
* RPC calls, then computes the display variant locally.
|
|
70
|
+
*
|
|
71
|
+
* @group components
|
|
72
|
+
*
|
|
73
|
+
* @example
|
|
74
|
+
* Minimal — just show the card:
|
|
75
|
+
* ```html
|
|
76
|
+
* <frak-post-purchase></frak-post-purchase>
|
|
77
|
+
* ```
|
|
78
|
+
*
|
|
79
|
+
* @example
|
|
80
|
+
* With purchase tracking fallback and custom sharing URL:
|
|
81
|
+
* ```html
|
|
82
|
+
* <frak-post-purchase
|
|
83
|
+
* customer-id="cust_123"
|
|
84
|
+
* order-id="ord_456"
|
|
85
|
+
* token="checkout_abc"
|
|
86
|
+
* sharing-url="https://merchant.com/product/shoes"
|
|
87
|
+
* ></frak-post-purchase>
|
|
88
|
+
* ```
|
|
89
|
+
*/
|
|
90
|
+
declare function PostPurchase({
|
|
91
|
+
customerId,
|
|
92
|
+
orderId,
|
|
93
|
+
token,
|
|
94
|
+
sharingUrl,
|
|
95
|
+
merchantId,
|
|
96
|
+
placement: placementId,
|
|
97
|
+
classname,
|
|
98
|
+
variant: forcedVariant,
|
|
99
|
+
referrerText: propReferrerText,
|
|
100
|
+
refereeText: propRefereeText,
|
|
101
|
+
ctaText: propCtaText
|
|
102
|
+
}: PostPurchaseProps): preact.JSX.Element | null;
|
|
103
|
+
//#endregion
|
|
104
|
+
//#region src/components/PostPurchase/index.d.ts
|
|
105
|
+
/**
|
|
106
|
+
* Custom element interface for `<frak-post-purchase>`.
|
|
107
|
+
* Combines standard {@link HTMLElement} with {@link PostPurchaseProps}.
|
|
108
|
+
*/
|
|
109
|
+
interface PostPurchaseElement extends HTMLElement, PostPurchaseProps {}
|
|
110
|
+
declare global {
|
|
111
|
+
interface HTMLElementTagNameMap {
|
|
112
|
+
"frak-post-purchase": PostPurchaseElement;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
//#endregion
|
|
116
|
+
export { PostPurchase, PostPurchaseElement };
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { a as useClientReady, o as registerWebComponent, t as usePlacement } from "./usePlacement-BbMuz8_A.js";
|
|
2
|
+
import { t as useLightDomStyles } from "./useLightDomStyles-DukxuNnJ.js";
|
|
3
|
+
import { t as formatEstimatedReward } from "./formatReward-6JQldDEC.js";
|
|
4
|
+
import { t as useShareModal } from "./useShareModal-DHlayNqk.js";
|
|
5
|
+
import { getMerchantInformation, getUserReferralStatus, trackPurchaseStatus } from "@frak-labs/core-sdk/actions";
|
|
6
|
+
import { useEffect, useMemo, useState } from "preact/hooks";
|
|
7
|
+
import { jsx, jsxs } from "preact/jsx-runtime";
|
|
8
|
+
import { FrakRpcError, RpcErrorCodes } from "@frak-labs/frame-connector";
|
|
9
|
+
|
|
10
|
+
//#region src/components/PostPurchase/PostPurchase.tsx
|
|
11
|
+
/**
|
|
12
|
+
* Given referral status and merchant info, compute the display variant
|
|
13
|
+
* and pick the appropriate purchase reward.
|
|
14
|
+
*/
|
|
15
|
+
function resolvePostPurchaseContext(referralStatus, merchantInfo) {
|
|
16
|
+
const purchaseReward = merchantInfo.rewards.find((r) => r.interactionTypeKey === "purchase" && (r.referrer || r.referee));
|
|
17
|
+
if (!purchaseReward) return null;
|
|
18
|
+
const variant = referralStatus?.isReferred && purchaseReward.referee ? "referee" : "referrer";
|
|
19
|
+
return {
|
|
20
|
+
variant,
|
|
21
|
+
reward: variant === "referee" ? purchaseReward.referee : purchaseReward.referrer,
|
|
22
|
+
merchantDomain: merchantInfo.onChainMetadata.domain
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Post-purchase card component.
|
|
27
|
+
*
|
|
28
|
+
* Renders an inline card on the merchant's thank-you / order-status page
|
|
29
|
+
* that either congratulates a referee or invites a referrer to share.
|
|
30
|
+
*
|
|
31
|
+
* Fetches referral status and merchant information via two independent
|
|
32
|
+
* RPC calls, then computes the display variant locally.
|
|
33
|
+
*
|
|
34
|
+
* @group components
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* Minimal — just show the card:
|
|
38
|
+
* ```html
|
|
39
|
+
* <frak-post-purchase></frak-post-purchase>
|
|
40
|
+
* ```
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* With purchase tracking fallback and custom sharing URL:
|
|
44
|
+
* ```html
|
|
45
|
+
* <frak-post-purchase
|
|
46
|
+
* customer-id="cust_123"
|
|
47
|
+
* order-id="ord_456"
|
|
48
|
+
* token="checkout_abc"
|
|
49
|
+
* sharing-url="https://merchant.com/product/shoes"
|
|
50
|
+
* ></frak-post-purchase>
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
53
|
+
function PostPurchase({ customerId, orderId, token, sharingUrl, merchantId, placement: placementId, classname = "", variant: forcedVariant, referrerText: propReferrerText, refereeText: propRefereeText, ctaText: propCtaText }) {
|
|
54
|
+
const { shouldRender, isHidden, isClientReady } = useClientReady();
|
|
55
|
+
const placement = usePlacement(placementId);
|
|
56
|
+
useLightDomStyles("frak-post-purchase", placementId, placement?.components?.postPurchase?.css);
|
|
57
|
+
const [context, setContext] = useState(null);
|
|
58
|
+
const [hasFetched, setHasFetched] = useState(false);
|
|
59
|
+
useEffect(() => {
|
|
60
|
+
if (!isClientReady || !customerId || !orderId || !token) return;
|
|
61
|
+
trackPurchaseStatus({
|
|
62
|
+
customerId,
|
|
63
|
+
orderId,
|
|
64
|
+
token,
|
|
65
|
+
merchantId
|
|
66
|
+
}).catch(() => {});
|
|
67
|
+
}, [
|
|
68
|
+
isClientReady,
|
|
69
|
+
customerId,
|
|
70
|
+
orderId,
|
|
71
|
+
token,
|
|
72
|
+
merchantId
|
|
73
|
+
]);
|
|
74
|
+
useEffect(() => {
|
|
75
|
+
if (!isClientReady || hasFetched) return;
|
|
76
|
+
const client = window.FrakSetup?.client;
|
|
77
|
+
if (!client) return;
|
|
78
|
+
setHasFetched(true);
|
|
79
|
+
Promise.all([getUserReferralStatus(client), getMerchantInformation(client)]).then(([referralStatus, merchantInfo]) => {
|
|
80
|
+
setContext(resolvePostPurchaseContext(referralStatus, merchantInfo));
|
|
81
|
+
}).catch((e) => {
|
|
82
|
+
if (e instanceof FrakRpcError && e.code === RpcErrorCodes.configError) return;
|
|
83
|
+
console.warn("[Frak] Post-purchase context error", e);
|
|
84
|
+
});
|
|
85
|
+
}, [isClientReady, hasFetched]);
|
|
86
|
+
const resolvedVariant = forcedVariant ?? context?.variant;
|
|
87
|
+
const resolvedSharingUrl = sharingUrl ?? context?.merchantDomain;
|
|
88
|
+
const rewardText = useMemo(() => {
|
|
89
|
+
if (!context?.reward) return void 0;
|
|
90
|
+
const currency = window.FrakSetup?.client?.config?.metadata?.currency;
|
|
91
|
+
return formatEstimatedReward(context.reward, currency);
|
|
92
|
+
}, [context?.reward]);
|
|
93
|
+
const postPurchaseConfig = placement?.components?.postPurchase;
|
|
94
|
+
const texts = useMemo(() => {
|
|
95
|
+
const applyReward = (text) => rewardText ? text.replace("{REWARD}", rewardText) : text;
|
|
96
|
+
return {
|
|
97
|
+
message: resolvedVariant === "referee" ? rewardText ? applyReward(propRefereeText ?? postPurchaseConfig?.refereeText ?? "You just earned {REWARD}! Share with friends to earn even more.") : propRefereeText ?? postPurchaseConfig?.refereeNoRewardText ?? "You just earned a reward! Share with friends to earn even more." : rewardText ? applyReward(propReferrerText ?? postPurchaseConfig?.referrerText ?? "Earn {REWARD} by sharing this with your friends!") : propReferrerText ?? postPurchaseConfig?.referrerNoRewardText ?? "Share this with your friends and earn rewards!",
|
|
98
|
+
cta: rewardText ? applyReward(propCtaText ?? postPurchaseConfig?.ctaText ?? "Share & earn {REWARD}") : propCtaText ?? postPurchaseConfig?.ctaNoRewardText ?? "Share & earn"
|
|
99
|
+
};
|
|
100
|
+
}, [
|
|
101
|
+
resolvedVariant,
|
|
102
|
+
rewardText,
|
|
103
|
+
postPurchaseConfig,
|
|
104
|
+
propReferrerText,
|
|
105
|
+
propRefereeText,
|
|
106
|
+
propCtaText
|
|
107
|
+
]);
|
|
108
|
+
const { handleShare } = useShareModal(void 0, placementId, resolvedSharingUrl);
|
|
109
|
+
if (!shouldRender || isHidden) return null;
|
|
110
|
+
if (!context || !resolvedVariant) return null;
|
|
111
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
112
|
+
class: ["post-purchase", classname].filter(Boolean).join(" "),
|
|
113
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
114
|
+
class: "post-purchase__content",
|
|
115
|
+
children: /* @__PURE__ */ jsx("p", {
|
|
116
|
+
class: "post-purchase__message",
|
|
117
|
+
children: texts.message
|
|
118
|
+
})
|
|
119
|
+
}), /* @__PURE__ */ jsx("button", {
|
|
120
|
+
type: "button",
|
|
121
|
+
class: "post-purchase__cta button",
|
|
122
|
+
disabled: !isClientReady,
|
|
123
|
+
onClick: handleShare,
|
|
124
|
+
children: texts.cta
|
|
125
|
+
})]
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
//#endregion
|
|
130
|
+
//#region src/components/PostPurchase/index.ts
|
|
131
|
+
registerWebComponent(PostPurchase, "frak-post-purchase", [
|
|
132
|
+
"customerId",
|
|
133
|
+
"orderId",
|
|
134
|
+
"token",
|
|
135
|
+
"sharingUrl",
|
|
136
|
+
"merchantId",
|
|
137
|
+
"placement",
|
|
138
|
+
"classname",
|
|
139
|
+
"variant",
|
|
140
|
+
"referrerText",
|
|
141
|
+
"refereeText",
|
|
142
|
+
"ctaText"
|
|
143
|
+
], { shadow: false });
|
|
144
|
+
|
|
145
|
+
//#endregion
|
|
146
|
+
export { PostPurchase };
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { i as lightDomBaseCss } from "./usePlacement-BbMuz8_A.js";
|
|
2
|
+
import { useEffect } from "preact/hooks";
|
|
3
|
+
|
|
4
|
+
//#region src/utils/styleManager.ts
|
|
5
|
+
function ensureStyle(id, css) {
|
|
6
|
+
const existing = document.getElementById(id);
|
|
7
|
+
if (existing) {
|
|
8
|
+
if (existing.textContent !== css) existing.textContent = css;
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
const style = document.createElement("style");
|
|
12
|
+
style.id = id;
|
|
13
|
+
style.textContent = css;
|
|
14
|
+
document.head.appendChild(style);
|
|
15
|
+
}
|
|
16
|
+
function injectBase(tag, css) {
|
|
17
|
+
ensureStyle(`frak-base-${tag}`, css);
|
|
18
|
+
}
|
|
19
|
+
function injectPlacement(tag, placementId, scopedCss) {
|
|
20
|
+
ensureStyle(`frak-placement-${tag}-${placementId}`, scopedCss);
|
|
21
|
+
}
|
|
22
|
+
const styleManager = {
|
|
23
|
+
injectBase,
|
|
24
|
+
injectPlacement
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
//#endregion
|
|
28
|
+
//#region src/hooks/useLightDomStyles.ts
|
|
29
|
+
function useLightDomStyles(tag, placementId, placementCss, baseCss) {
|
|
30
|
+
useEffect(() => {
|
|
31
|
+
styleManager.injectBase(tag, baseCss ?? lightDomBaseCss);
|
|
32
|
+
}, [tag]);
|
|
33
|
+
useEffect(() => {
|
|
34
|
+
if (!placementId || !placementCss) return;
|
|
35
|
+
styleManager.injectPlacement(tag, placementId, placementCss);
|
|
36
|
+
}, [
|
|
37
|
+
tag,
|
|
38
|
+
placementId,
|
|
39
|
+
placementCss
|
|
40
|
+
]);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
//#endregion
|
|
44
|
+
export { useLightDomStyles as t };
|