@superlogic/spree-pay 0.1.21 → 0.1.23
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/build/index.cjs +189 -108
- package/build/index.css +16 -0
- package/build/index.d.cts +4 -4
- package/build/index.d.ts +4 -4
- package/build/index.js +189 -108
- package/package.json +1 -1
package/build/index.cjs
CHANGED
|
@@ -62,7 +62,7 @@ var PaymentError = class extends Error {
|
|
|
62
62
|
var PaymentType = /* @__PURE__ */ ((PaymentType2) => {
|
|
63
63
|
PaymentType2["CREDIT_CARD"] = "CREDIT_CARD";
|
|
64
64
|
PaymentType2["CRYPTO"] = "CRYPTO";
|
|
65
|
-
PaymentType2["
|
|
65
|
+
PaymentType2["CREDIT_CARD_SPLIT"] = "SPLIT";
|
|
66
66
|
PaymentType2["POINTS"] = "POINTS";
|
|
67
67
|
return PaymentType2;
|
|
68
68
|
})(PaymentType || {});
|
|
@@ -141,48 +141,36 @@ var CONFIG = {
|
|
|
141
141
|
bookit: {
|
|
142
142
|
slapiUrl: "https://slapi.dev.superlogic.com",
|
|
143
143
|
keycloakUrl: "https://auth.dev.join.bookit.com",
|
|
144
|
-
keycloakClientId: "oneof-next"
|
|
145
|
-
pointsConversionRatio: 100,
|
|
146
|
-
pointsTitle: "AIR SP"
|
|
144
|
+
keycloakClientId: "oneof-next"
|
|
147
145
|
},
|
|
148
146
|
moca: {
|
|
149
147
|
slapiUrl: "https://slapi.dev.air.shop",
|
|
150
148
|
keycloakUrl: "https://login.dev.air.shop",
|
|
151
|
-
keycloakClientId: "oneof-next"
|
|
152
|
-
pointsConversionRatio: 100,
|
|
153
|
-
pointsTitle: "AIR SP"
|
|
149
|
+
keycloakClientId: "oneof-next"
|
|
154
150
|
}
|
|
155
151
|
},
|
|
156
152
|
stg: {
|
|
157
153
|
bookit: {
|
|
158
154
|
slapiUrl: "https://slapi.stg.superlogic.com",
|
|
159
155
|
keycloakUrl: "https://auth.stg.join.bookit.com",
|
|
160
|
-
keycloakClientId: "oneof-next"
|
|
161
|
-
pointsConversionRatio: 100,
|
|
162
|
-
pointsTitle: "AIR SP"
|
|
156
|
+
keycloakClientId: "oneof-next"
|
|
163
157
|
},
|
|
164
158
|
moca: {
|
|
165
159
|
slapiUrl: "https://slapi.stg.air.shop",
|
|
166
160
|
keycloakUrl: "https://login.stg.air.shop",
|
|
167
|
-
keycloakClientId: "oneof-next"
|
|
168
|
-
pointsConversionRatio: 100,
|
|
169
|
-
pointsTitle: "AIR SP"
|
|
161
|
+
keycloakClientId: "oneof-next"
|
|
170
162
|
}
|
|
171
163
|
},
|
|
172
164
|
prod: {
|
|
173
165
|
bookit: {
|
|
174
166
|
slapiUrl: "https://slapi.superlogic.com",
|
|
175
167
|
keycloakUrl: "https://auth.join.bookit.com",
|
|
176
|
-
keycloakClientId: "oneof-next"
|
|
177
|
-
pointsConversionRatio: 100,
|
|
178
|
-
pointsTitle: "AIR SP"
|
|
168
|
+
keycloakClientId: "oneof-next"
|
|
179
169
|
},
|
|
180
170
|
moca: {
|
|
181
171
|
slapiUrl: "https://slapi.air.shop",
|
|
182
172
|
keycloakUrl: "https://login.air.shop",
|
|
183
|
-
keycloakClientId: "oneof-next"
|
|
184
|
-
pointsConversionRatio: 100,
|
|
185
|
-
pointsTitle: "AIR SP"
|
|
173
|
+
keycloakClientId: "oneof-next"
|
|
186
174
|
}
|
|
187
175
|
}
|
|
188
176
|
};
|
|
@@ -210,7 +198,20 @@ var useStaticConfig = () => {
|
|
|
210
198
|
var import_swr = __toESM(require("swr"), 1);
|
|
211
199
|
var useSpreePayConfig = () => {
|
|
212
200
|
const { data, isLoading } = (0, import_swr.default)("/v1/tenants/configs/spree-pay");
|
|
213
|
-
return {
|
|
201
|
+
return {
|
|
202
|
+
spreePayConfig: data ? {
|
|
203
|
+
...data,
|
|
204
|
+
rainbowProjectId: data.rainbowProjectId ?? "3fdcd5ff50cb84917cd05e40146975d8",
|
|
205
|
+
rainbowAppName: data.rainbowAppName ?? "AIR Shop",
|
|
206
|
+
pointsTitle: data.pointsTitle ?? "AIR SP",
|
|
207
|
+
pointsConversionRatio: data.pointsConversionRatio ?? 100,
|
|
208
|
+
crypto: {
|
|
209
|
+
...data.crypto,
|
|
210
|
+
oneInchAggregationRouter: data.crypto?.oneInchAggregationRouter || "0x111111125421ca6dc452d289314280a0f8842a65"
|
|
211
|
+
}
|
|
212
|
+
} : null,
|
|
213
|
+
configIsLoading: isLoading
|
|
214
|
+
};
|
|
214
215
|
};
|
|
215
216
|
|
|
216
217
|
// src/lib/utils.ts
|
|
@@ -277,7 +278,7 @@ var formatUSD = (amount, currency = "USD") => {
|
|
|
277
278
|
}).format(amount);
|
|
278
279
|
return formattedAmount;
|
|
279
280
|
};
|
|
280
|
-
var formatPoints = (amount, pointsTitle = "
|
|
281
|
+
var formatPoints = (amount, pointsTitle = "") => {
|
|
281
282
|
const formattedAmount = new Intl.NumberFormat("en-US", {
|
|
282
283
|
notation: "compact",
|
|
283
284
|
style: "decimal",
|
|
@@ -297,7 +298,7 @@ var formatCoin = (amount, currency = "USDC") => {
|
|
|
297
298
|
|
|
298
299
|
// src/utils/split.ts
|
|
299
300
|
var getSplitAmount = (amount, splitTokens, pointsConversionRatio) => {
|
|
300
|
-
if (!Number.isFinite(amount) || !Number.isFinite(splitTokens) || !Number.isFinite(pointsConversionRatio)) {
|
|
301
|
+
if (!Number.isFinite(amount) || !Number.isFinite(splitTokens) || !pointsConversionRatio || !Number.isFinite(pointsConversionRatio)) {
|
|
301
302
|
return amount;
|
|
302
303
|
}
|
|
303
304
|
if (pointsConversionRatio <= 0) return amount;
|
|
@@ -319,13 +320,13 @@ var getTransactionFee = (amount = 0, transactionFeePercentage) => {
|
|
|
319
320
|
// src/components/CheckoutButton.tsx
|
|
320
321
|
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
321
322
|
var CheckoutButton = ({ isLoggedIn }) => {
|
|
322
|
-
const {
|
|
323
|
+
const { appProps } = useStaticConfig();
|
|
323
324
|
const { amount, onProcess, isProcessing, transactionFeePercentage } = appProps;
|
|
324
325
|
const { spreePayConfig } = useSpreePayConfig();
|
|
325
|
-
const { pointsTitle, pointsConversionRatio } = staticConfig;
|
|
326
326
|
const { selectedPaymentMethod, isInternalProcessing } = useSpreePaymentMethod();
|
|
327
327
|
const { splitAmount, type, method } = selectedPaymentMethod;
|
|
328
|
-
const
|
|
328
|
+
const usdAmount = getSplitAmount(amount ?? 0, splitAmount ?? 0, spreePayConfig?.pointsConversionRatio);
|
|
329
|
+
const isDisabled = !amount || !method && usdAmount !== 0 || !!isProcessing || isInternalProcessing || !isLoggedIn;
|
|
329
330
|
const isCC = type === "CREDIT_CARD" /* CREDIT_CARD */;
|
|
330
331
|
const isCrypto = type === "CRYPTO" /* CRYPTO */;
|
|
331
332
|
const getCheckoutContent = () => {
|
|
@@ -333,15 +334,14 @@ var CheckoutButton = ({ isLoggedIn }) => {
|
|
|
333
334
|
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Spinner, { className: "inline", size: "sm" });
|
|
334
335
|
}
|
|
335
336
|
if (isCC && amount) {
|
|
336
|
-
const usdAmount = getSplitAmount(amount, splitAmount ?? 0, pointsConversionRatio);
|
|
337
337
|
if (splitAmount && usdAmount) {
|
|
338
|
-
return `Pay ${formatUSD(usdAmount + getTransactionFee(usdAmount, transactionFeePercentage))} + ${formatPoints(splitAmount, pointsTitle)}`;
|
|
338
|
+
return `Pay ${formatUSD(usdAmount + getTransactionFee(usdAmount, transactionFeePercentage))} + ${formatPoints(splitAmount, spreePayConfig?.pointsTitle)}`;
|
|
339
339
|
}
|
|
340
340
|
if (usdAmount) {
|
|
341
341
|
return `Pay ${formatUSD(usdAmount + getTransactionFee(usdAmount, transactionFeePercentage))}`;
|
|
342
342
|
}
|
|
343
343
|
if (splitAmount) {
|
|
344
|
-
return `Pay ${formatPoints(splitAmount, pointsTitle)}`;
|
|
344
|
+
return `Pay ${formatPoints(splitAmount, spreePayConfig?.pointsTitle)}`;
|
|
345
345
|
}
|
|
346
346
|
return "Checkout";
|
|
347
347
|
}
|
|
@@ -394,7 +394,7 @@ var SpreeLegal = () => {
|
|
|
394
394
|
// src/components/CreditCardTab/CreditCardTab.tsx
|
|
395
395
|
var import_react13 = require("react");
|
|
396
396
|
|
|
397
|
-
// src/hooks/useCardPayment.ts
|
|
397
|
+
// src/hooks/payments/useCardPayment.ts
|
|
398
398
|
var import_nice_modal_react2 = __toESM(require("@ebay/nice-modal-react"), 1);
|
|
399
399
|
|
|
400
400
|
// src/modals/Iframe3ds.tsx
|
|
@@ -629,17 +629,8 @@ var registerApi = (config) => {
|
|
|
629
629
|
|
|
630
630
|
// src/services/slapi.ts
|
|
631
631
|
var SlapiPaymentService = {
|
|
632
|
-
createPayment: (
|
|
633
|
-
|
|
634
|
-
let reqParams;
|
|
635
|
-
if (type === "CRYPTO" /* CRYPTO */) {
|
|
636
|
-
reqParams = { type, hash, crypto: params.crypto };
|
|
637
|
-
} else if (type === "CREDIT_CARD" /* CREDIT_CARD */ && params.points && params.points.amount > 0) {
|
|
638
|
-
reqParams = { type: "SPLIT" /* SPLIT */, hash, card: params.card, points: params.points };
|
|
639
|
-
} else {
|
|
640
|
-
reqParams = { type, hash, card: params.card };
|
|
641
|
-
}
|
|
642
|
-
return slapiApi.post("/v1/payments", { ...reqParams, capture, metadata }).then((data) => ({ data }));
|
|
632
|
+
createPayment: ({ capture = false, ...rest }) => {
|
|
633
|
+
return slapiApi.post("/v1/payments", { ...rest, capture }).then((data) => ({ data }));
|
|
643
634
|
},
|
|
644
635
|
baseVerify: ({ id, txHash }) => {
|
|
645
636
|
return slapiApi.post(`/v1/base-transactions/transactions/${id}/verify`, { txHash });
|
|
@@ -658,7 +649,7 @@ var SlapiPaymentService = {
|
|
|
658
649
|
}
|
|
659
650
|
};
|
|
660
651
|
|
|
661
|
-
// src/hooks/useCardPayment.ts
|
|
652
|
+
// src/hooks/payments/useCardPayment.ts
|
|
662
653
|
var useCardPayment = () => {
|
|
663
654
|
const { selectedPaymentMethod } = useSpreePaymentMethod();
|
|
664
655
|
const { env } = useSpreePayEnv();
|
|
@@ -707,20 +698,6 @@ var useCardPayment = () => {
|
|
|
707
698
|
return { cardPayment };
|
|
708
699
|
};
|
|
709
700
|
|
|
710
|
-
// src/hooks/useCards.ts
|
|
711
|
-
var import_swr2 = __toESM(require("swr"), 1);
|
|
712
|
-
var useCards = () => {
|
|
713
|
-
const { data, isLoading, mutate } = (0, import_swr2.default)(`/v1/payments/cards`);
|
|
714
|
-
return {
|
|
715
|
-
cards: data?.data.filter((c) => c.active) || [],
|
|
716
|
-
cardsIsLoading: isLoading,
|
|
717
|
-
mutateCards: mutate
|
|
718
|
-
};
|
|
719
|
-
};
|
|
720
|
-
|
|
721
|
-
// src/hooks/useSplitCardPayments.ts
|
|
722
|
-
var import_nice_modal_react3 = __toESM(require("@ebay/nice-modal-react"), 1);
|
|
723
|
-
|
|
724
701
|
// src/services/AirWalletService.ts
|
|
725
702
|
var import_airkit = require("@mocanetwork/airkit");
|
|
726
703
|
var import_viem = require("viem");
|
|
@@ -812,7 +789,8 @@ async function handleSendErc20(params) {
|
|
|
812
789
|
}
|
|
813
790
|
}
|
|
814
791
|
|
|
815
|
-
// src/hooks/
|
|
792
|
+
// src/hooks/payments/utils.ts
|
|
793
|
+
var import_nice_modal_react3 = __toESM(require("@ebay/nice-modal-react"), 1);
|
|
816
794
|
var REFRESH_INTERVAL = 3 * 1e3;
|
|
817
795
|
var MAX_RETRIES = 10;
|
|
818
796
|
async function longPollPoints(paymentId) {
|
|
@@ -853,10 +831,55 @@ async function longPollCardStatus(paymentId) {
|
|
|
853
831
|
}
|
|
854
832
|
throw new Error("Payment polling timed out");
|
|
855
833
|
}
|
|
834
|
+
|
|
835
|
+
// src/hooks/payments/usePointsPayment.ts
|
|
836
|
+
var usePointsPayment = () => {
|
|
837
|
+
const { selectedPaymentMethod } = useSpreePaymentMethod();
|
|
838
|
+
const { spreePayConfig } = useSpreePayConfig();
|
|
839
|
+
const pointsPayment = async (params) => {
|
|
840
|
+
if (selectedPaymentMethod.type !== "CREDIT_CARD" /* CREDIT_CARD */) {
|
|
841
|
+
throw new Error("Unsupported payment method");
|
|
842
|
+
}
|
|
843
|
+
const { hash, capture, metadata } = params;
|
|
844
|
+
const { data: paymentResData } = await SlapiPaymentService.createPayment({
|
|
845
|
+
hash,
|
|
846
|
+
capture,
|
|
847
|
+
metadata,
|
|
848
|
+
type: "POINTS" /* POINTS */
|
|
849
|
+
});
|
|
850
|
+
const wallet = peekAirWallet();
|
|
851
|
+
if (!wallet || !spreePayConfig?.pointsChain) {
|
|
852
|
+
throw new Error("AirWallet not found");
|
|
853
|
+
}
|
|
854
|
+
const transaction = await handleSendErc20({
|
|
855
|
+
amount: params.points,
|
|
856
|
+
token: spreePayConfig.pointsChain.pointsCoin,
|
|
857
|
+
recipient: spreePayConfig.pointsChain.recipientAddress
|
|
858
|
+
});
|
|
859
|
+
if (!transaction) {
|
|
860
|
+
throw new Error("Points transaction failed");
|
|
861
|
+
}
|
|
862
|
+
await SlapiPaymentService.validatePoints({
|
|
863
|
+
paymentId: paymentResData.id,
|
|
864
|
+
txHash: transaction.txHash
|
|
865
|
+
});
|
|
866
|
+
const pointsStatus = await longPollPoints(paymentResData.id);
|
|
867
|
+
return {
|
|
868
|
+
status: pointsStatus,
|
|
869
|
+
txId: paymentResData.txId,
|
|
870
|
+
txHash: transaction.txHash,
|
|
871
|
+
paymentId: paymentResData.id,
|
|
872
|
+
paymentType: "POINTS" /* POINTS */
|
|
873
|
+
};
|
|
874
|
+
};
|
|
875
|
+
return { pointsPayment };
|
|
876
|
+
};
|
|
877
|
+
|
|
878
|
+
// src/hooks/payments/useSplitCardPayments.ts
|
|
856
879
|
var useSplitCardPayments = () => {
|
|
857
880
|
const { selectedPaymentMethod } = useSpreePaymentMethod();
|
|
858
881
|
const { env } = useSpreePayEnv();
|
|
859
|
-
const { appProps
|
|
882
|
+
const { appProps } = useStaticConfig();
|
|
860
883
|
const { spreePayConfig } = useSpreePayConfig();
|
|
861
884
|
const splitPayment = async (params) => {
|
|
862
885
|
if (selectedPaymentMethod.type !== "CREDIT_CARD" /* CREDIT_CARD */ || !selectedPaymentMethod.method || !params.points) {
|
|
@@ -871,13 +894,13 @@ var useSplitCardPayments = () => {
|
|
|
871
894
|
} else {
|
|
872
895
|
cardId = card.id;
|
|
873
896
|
}
|
|
874
|
-
const usdAmount = getSplitAmount(appProps.amount ?? 0, points,
|
|
897
|
+
const usdAmount = getSplitAmount(appProps.amount ?? 0, points, spreePayConfig?.pointsConversionRatio);
|
|
875
898
|
const transactionFee = getTransactionFee(usdAmount, appProps.transactionFeePercentage);
|
|
876
899
|
const { data: paymentResData } = await SlapiPaymentService.createPayment({
|
|
877
900
|
hash,
|
|
878
901
|
capture,
|
|
879
902
|
metadata,
|
|
880
|
-
type: "
|
|
903
|
+
type: "SPLIT" /* CREDIT_CARD_SPLIT */,
|
|
881
904
|
card: {
|
|
882
905
|
cardId,
|
|
883
906
|
transactionFee,
|
|
@@ -906,7 +929,7 @@ var useSplitCardPayments = () => {
|
|
|
906
929
|
});
|
|
907
930
|
const pointsStatus = await longPollPoints(paymentResData.id);
|
|
908
931
|
return {
|
|
909
|
-
paymentType: "SPLIT" /*
|
|
932
|
+
paymentType: "SPLIT" /* CREDIT_CARD_SPLIT */,
|
|
910
933
|
status: pointsStatus,
|
|
911
934
|
paymentId: paymentResData.id,
|
|
912
935
|
txId: paymentResData.txId,
|
|
@@ -916,6 +939,17 @@ var useSplitCardPayments = () => {
|
|
|
916
939
|
return { splitPayment };
|
|
917
940
|
};
|
|
918
941
|
|
|
942
|
+
// src/hooks/useCards.ts
|
|
943
|
+
var import_swr2 = __toESM(require("swr"), 1);
|
|
944
|
+
var useCards = () => {
|
|
945
|
+
const { data, isLoading, mutate } = (0, import_swr2.default)(`/v1/payments/cards`);
|
|
946
|
+
return {
|
|
947
|
+
cards: data?.data.filter((c) => c.active) || [],
|
|
948
|
+
cardsIsLoading: isLoading,
|
|
949
|
+
mutateCards: mutate
|
|
950
|
+
};
|
|
951
|
+
};
|
|
952
|
+
|
|
919
953
|
// src/components/CreditCardTab/CreditCard/CreditCard.tsx
|
|
920
954
|
var import_react6 = require("react");
|
|
921
955
|
var import_react_stripe_js2 = require("@stripe/react-stripe-js");
|
|
@@ -1269,24 +1303,35 @@ function Switch({ className, ...props }) {
|
|
|
1269
1303
|
// src/components/common/PointsSwitch.tsx
|
|
1270
1304
|
var import_jsx_runtime15 = require("react/jsx-runtime");
|
|
1271
1305
|
var PointsSwitch = (props) => {
|
|
1272
|
-
const { disabled = false, value, onChange } = props;
|
|
1273
|
-
const {
|
|
1274
|
-
const { pointsConversionRatio, pointsTitle } = staticConfig;
|
|
1306
|
+
const { disabled = false, value, onChange, message } = props;
|
|
1307
|
+
const { spreePayConfig } = useSpreePayConfig();
|
|
1275
1308
|
const { balance } = useSlapiBalance();
|
|
1276
1309
|
const id = (0, import_react7.useId)();
|
|
1277
|
-
return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex
|
|
1278
|
-
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex items-center gap-3", children: [
|
|
1279
|
-
/* @__PURE__ */ (0, import_jsx_runtime15.
|
|
1280
|
-
|
|
1281
|
-
"
|
|
1282
|
-
|
|
1283
|
-
|
|
1310
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex flex-col gap-6", children: [
|
|
1311
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex items-center justify-between gap-3", children: [
|
|
1312
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex items-center gap-3", children: [
|
|
1313
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Switch, { checked: value, onCheckedChange: onChange, disabled, id }),
|
|
1314
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(Label, { className: "text-md items-baseline leading-[1.3] font-semibold text-black md:text-xl", htmlFor: id, children: [
|
|
1315
|
+
"Use Points ",
|
|
1316
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "text-xs font-medium", children: "Optional" })
|
|
1317
|
+
] })
|
|
1318
|
+
] }),
|
|
1319
|
+
balance?.availablePoints ? /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("p", { className: "flex-1 text-right text-sm font-medium text-black", children: [
|
|
1320
|
+
formatPoints(balance.availablePoints, spreePayConfig?.pointsTitle),
|
|
1321
|
+
" ",
|
|
1322
|
+
!!spreePayConfig?.pointsConversionRatio && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "text-black/50", children: formatUSD(balance.availablePoints / spreePayConfig.pointsConversionRatio) })
|
|
1323
|
+
] }) : null
|
|
1284
1324
|
] }),
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1325
|
+
message && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex items-start gap-1 rounded-sm border-1 border-[#006FD533] bg-[#006FD50D] p-1.5", children: [
|
|
1326
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("svg", { className: "size-5 shrink-0", xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 20 20", children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
1327
|
+
"path",
|
|
1328
|
+
{
|
|
1329
|
+
fill: "#000",
|
|
1330
|
+
d: "M9.6 13.8h.8V9.2h-.8zM10 8q.2 0 .4-.2l.1-.3-.1-.4L10 7l-.4.1-.1.4.1.3zm0 9.5a7 7 0 0 1-5.3-2.2 8 8 0 0 1-1.6-8.2 8 8 0 0 1 4-4q1.4-.6 2.9-.6a7 7 0 0 1 5.3 2.2 8 8 0 0 1 1.6 8.2 8 8 0 0 1-4 4q-1.4.6-2.9.6m0-.8q2.8 0 4.7-2 2-1.9 2-4.7t-2-4.7a6 6 0 0 0-4.7-2q-2.8 0-4.7 2a6 6 0 0 0-2 4.7q0 2.8 2 4.7 1.9 2 4.7 2"
|
|
1331
|
+
}
|
|
1332
|
+
) }),
|
|
1333
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("p", { className: "text-xs font-medium text-black", children: message })
|
|
1334
|
+
] })
|
|
1290
1335
|
] });
|
|
1291
1336
|
};
|
|
1292
1337
|
|
|
@@ -2290,12 +2335,14 @@ var PointsSelector = (props) => {
|
|
|
2290
2335
|
const { isDisabled, isSelected, onSelect, children } = props;
|
|
2291
2336
|
const { balance } = useSlapiBalance();
|
|
2292
2337
|
const { selectedPaymentMethod, setSelectedPaymentMethod } = useSpreePaymentMethod();
|
|
2293
|
-
const { appProps
|
|
2338
|
+
const { appProps } = useStaticConfig();
|
|
2339
|
+
const { spreePayConfig } = useSpreePayConfig();
|
|
2340
|
+
const { pointsConversionRatio } = spreePayConfig || {};
|
|
2294
2341
|
const min = 0;
|
|
2295
|
-
const max = Math.min((appProps.amount ?? 0) *
|
|
2342
|
+
const max = Math.min((appProps.amount ?? 0) * (pointsConversionRatio ?? 0), balance?.availablePoints ?? 0);
|
|
2296
2343
|
const step = 10;
|
|
2297
2344
|
const [splitTokens, setSplitTokens] = (0, import_react10.useState)(0);
|
|
2298
|
-
const
|
|
2345
|
+
const usdAmount = getSplitAmount(appProps.amount ?? 0, splitTokens, pointsConversionRatio);
|
|
2299
2346
|
const handleCommit = (value) => {
|
|
2300
2347
|
setSelectedPaymentMethod({ ...selectedPaymentMethod, splitAmount: value });
|
|
2301
2348
|
};
|
|
@@ -2323,7 +2370,15 @@ var PointsSelector = (props) => {
|
|
|
2323
2370
|
] }),
|
|
2324
2371
|
isSelected && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "px-3 pt-6 pb-2 md:px-4", children: /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "flex justify-between gap-3", children: [
|
|
2325
2372
|
/* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "flex max-w-[100px] flex-col gap-1", children: [
|
|
2326
|
-
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
2373
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
2374
|
+
Input,
|
|
2375
|
+
{
|
|
2376
|
+
readOnly: true,
|
|
2377
|
+
value: Math.round(splitTokens),
|
|
2378
|
+
className: "bg-white text-center font-medium",
|
|
2379
|
+
onClick: (e) => e.stopPropagation()
|
|
2380
|
+
}
|
|
2381
|
+
),
|
|
2327
2382
|
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("p", { className: "text-left text-xs leading-[20px] text-black/45", children: "Points" })
|
|
2328
2383
|
] }),
|
|
2329
2384
|
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "flex w-full items-center pb-6", children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
@@ -2332,6 +2387,7 @@ var PointsSelector = (props) => {
|
|
|
2332
2387
|
value: [splitTokens],
|
|
2333
2388
|
onValueCommit: ([v]) => handleCommit(v),
|
|
2334
2389
|
onValueChange: ([v]) => setSplitTokens(v),
|
|
2390
|
+
onPointerDown: (e) => e.stopPropagation(),
|
|
2335
2391
|
min,
|
|
2336
2392
|
max,
|
|
2337
2393
|
step
|
|
@@ -2342,8 +2398,9 @@ var PointsSelector = (props) => {
|
|
|
2342
2398
|
Input,
|
|
2343
2399
|
{
|
|
2344
2400
|
readOnly: true,
|
|
2345
|
-
value: formatUSD(
|
|
2346
|
-
className: "bg-white text-center font-medium"
|
|
2401
|
+
value: formatUSD(usdAmount + getTransactionFee(usdAmount, appProps.transactionFeePercentage)),
|
|
2402
|
+
className: "bg-white text-center font-medium",
|
|
2403
|
+
onClick: (e) => e.stopPropagation()
|
|
2347
2404
|
}
|
|
2348
2405
|
),
|
|
2349
2406
|
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("p", { className: "text-left text-xs leading-[20px] text-black/45", children: "Card" })
|
|
@@ -2362,8 +2419,7 @@ var SplitBlock = (props) => {
|
|
|
2362
2419
|
const { spreePayConfig } = useSpreePayConfig();
|
|
2363
2420
|
const [address, setAddress] = (0, import_react11.useState)(null);
|
|
2364
2421
|
const [walletReady, setWalletReady] = (0, import_react11.useState)(false);
|
|
2365
|
-
const {
|
|
2366
|
-
const { pointsConversionRatio, pointsTitle } = staticConfig;
|
|
2422
|
+
const { pointsConversionRatio, pointsTitle } = spreePayConfig || {};
|
|
2367
2423
|
const initWallet = (0, import_react11.useCallback)(
|
|
2368
2424
|
async (pointsChain) => {
|
|
2369
2425
|
if (!pointsChain) return;
|
|
@@ -2394,7 +2450,7 @@ var SplitBlock = (props) => {
|
|
|
2394
2450
|
" ",
|
|
2395
2451
|
formatPoints(balance.availablePoints, pointsTitle),
|
|
2396
2452
|
" ",
|
|
2397
|
-
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { className: "text-black/50", children: formatUSD(balance.availablePoints / pointsConversionRatio) })
|
|
2453
|
+
pointsConversionRatio && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { className: "text-black/50", children: formatUSD(balance.availablePoints / pointsConversionRatio) })
|
|
2398
2454
|
] }) : null }),
|
|
2399
2455
|
isBalanceLoading ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "h-4 w-6 animate-pulse bg-gray-200" }) : !balance?.availablePoints && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("p", { className: "text-sm font-medium text-black", children: "No points available" }),
|
|
2400
2456
|
address && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "text-sm font-medium text-black", children: address.length > 8 ? `${address.slice(0, 4)}...${address.slice(-4)}` : address })
|
|
@@ -2416,7 +2472,15 @@ var Points = () => {
|
|
|
2416
2472
|
}
|
|
2417
2473
|
};
|
|
2418
2474
|
return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(import_jsx_runtime26.Fragment, { children: [
|
|
2419
|
-
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
2475
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
2476
|
+
PointsSwitch,
|
|
2477
|
+
{
|
|
2478
|
+
value: usePoints,
|
|
2479
|
+
onChange: handleTogglePoints,
|
|
2480
|
+
message: spreePayConfig?.creditCard.pointsInfoMessage,
|
|
2481
|
+
disabled: !spreePayConfig?.creditCard.enabled || !spreePayConfig?.creditCard.points
|
|
2482
|
+
}
|
|
2483
|
+
),
|
|
2420
2484
|
usePoints && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
2421
2485
|
SplitBlock,
|
|
2422
2486
|
{
|
|
@@ -2432,26 +2496,30 @@ var Points = () => {
|
|
|
2432
2496
|
var import_jsx_runtime27 = require("react/jsx-runtime");
|
|
2433
2497
|
var CreditCardTab = () => {
|
|
2434
2498
|
const { selectedPaymentMethod, setSelectedPaymentMethod } = useSpreePaymentMethod();
|
|
2499
|
+
const { appProps } = useStaticConfig();
|
|
2500
|
+
const { spreePayConfig } = useSpreePayConfig();
|
|
2435
2501
|
const { register } = useSpreePayRegister();
|
|
2436
2502
|
const { mutateCards } = useCards();
|
|
2437
2503
|
const { cardPayment } = useCardPayment();
|
|
2438
2504
|
const { splitPayment } = useSplitCardPayments();
|
|
2505
|
+
const { pointsPayment } = usePointsPayment();
|
|
2439
2506
|
const handlePay = (0, import_react13.useCallback)(
|
|
2440
2507
|
async (data) => {
|
|
2441
2508
|
try {
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
}
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
}
|
|
2452
|
-
return Promise.reject(new PaymentError("Card payment failed", res.status));
|
|
2509
|
+
let res = null;
|
|
2510
|
+
const pointsAmount = selectedPaymentMethod.splitAmount ?? 0;
|
|
2511
|
+
const usdAmount = getSplitAmount(appProps.amount ?? 0, pointsAmount, spreePayConfig?.pointsConversionRatio);
|
|
2512
|
+
if (usdAmount && pointsAmount) {
|
|
2513
|
+
res = await splitPayment({ ...data, points: pointsAmount });
|
|
2514
|
+
} else if (!usdAmount && pointsAmount) {
|
|
2515
|
+
res = await pointsPayment({ ...data, points: pointsAmount });
|
|
2516
|
+
} else {
|
|
2517
|
+
res = await cardPayment(data);
|
|
2453
2518
|
}
|
|
2454
|
-
|
|
2519
|
+
if (["AUTHORIZED" /* AUTHORIZED */, "CAPTURED" /* CAPTURED */].includes(res.status)) {
|
|
2520
|
+
return Promise.resolve(res);
|
|
2521
|
+
}
|
|
2522
|
+
return Promise.reject(new PaymentError("Card payment failed", res.status));
|
|
2455
2523
|
} catch (_) {
|
|
2456
2524
|
return Promise.reject(new PaymentError("Payment failed", "FAILED" /* FAILED */));
|
|
2457
2525
|
} finally {
|
|
@@ -2459,7 +2527,16 @@ var CreditCardTab = () => {
|
|
|
2459
2527
|
mutateCards();
|
|
2460
2528
|
}
|
|
2461
2529
|
},
|
|
2462
|
-
[
|
|
2530
|
+
[
|
|
2531
|
+
mutateCards,
|
|
2532
|
+
selectedPaymentMethod,
|
|
2533
|
+
pointsPayment,
|
|
2534
|
+
appProps.amount,
|
|
2535
|
+
setSelectedPaymentMethod,
|
|
2536
|
+
cardPayment,
|
|
2537
|
+
splitPayment,
|
|
2538
|
+
spreePayConfig
|
|
2539
|
+
]
|
|
2463
2540
|
);
|
|
2464
2541
|
(0, import_react13.useEffect)(() => {
|
|
2465
2542
|
register(handlePay);
|
|
@@ -2534,7 +2611,7 @@ async function waitForTransactionReceipt(config, parameters) {
|
|
|
2534
2611
|
// ../../node_modules/@wagmi/core/dist/esm/exports/index.js
|
|
2535
2612
|
var import_viem3 = require("viem");
|
|
2536
2613
|
|
|
2537
|
-
// src/hooks/useCryptoPayment.ts
|
|
2614
|
+
// src/hooks/payments/useCryptoPayment.ts
|
|
2538
2615
|
var import_viem4 = require("viem");
|
|
2539
2616
|
var import_wagmi = require("wagmi");
|
|
2540
2617
|
|
|
@@ -2575,17 +2652,20 @@ var BASE_TOKENS = [
|
|
|
2575
2652
|
}
|
|
2576
2653
|
];
|
|
2577
2654
|
|
|
2578
|
-
// src/hooks/useCryptoPayment.ts
|
|
2655
|
+
// src/hooks/payments/useCryptoPayment.ts
|
|
2579
2656
|
var MAX_UINT256 = BigInt(2) ** BigInt(256) - BigInt(1);
|
|
2580
|
-
var ONE_INCH_AGGREGATION_ROUTER_V6 = "0x111111125421ca6dc452d289314280a0f8842a65";
|
|
2581
2657
|
var useCryptoPayment = () => {
|
|
2582
2658
|
const { data: walletClient } = (0, import_wagmi.useWalletClient)();
|
|
2659
|
+
const { spreePayConfig } = useSpreePayConfig();
|
|
2583
2660
|
const config = (0, import_wagmi.useConfig)();
|
|
2584
2661
|
const { selectedPaymentMethod } = useSpreePaymentMethod();
|
|
2585
2662
|
const cryptoPayment = async (params) => {
|
|
2586
2663
|
if (!walletClient) {
|
|
2587
2664
|
throw new Error("Wallet not connected");
|
|
2588
2665
|
}
|
|
2666
|
+
if (!spreePayConfig) {
|
|
2667
|
+
throw new Error("Spree Pay config not loaded");
|
|
2668
|
+
}
|
|
2589
2669
|
if (selectedPaymentMethod.type !== "CRYPTO" /* CRYPTO */ || !selectedPaymentMethod.method?.symbol) {
|
|
2590
2670
|
throw new Error("Unsupported payment method");
|
|
2591
2671
|
}
|
|
@@ -2600,14 +2680,14 @@ var useCryptoPayment = () => {
|
|
|
2600
2680
|
address: tokenAddress,
|
|
2601
2681
|
abi: import_viem4.erc20Abi,
|
|
2602
2682
|
functionName: "allowance",
|
|
2603
|
-
args: [walletClient.account.address,
|
|
2683
|
+
args: [walletClient.account.address, spreePayConfig.crypto.oneInchAggregationRouter]
|
|
2604
2684
|
});
|
|
2605
2685
|
if (allowance <= 0n) {
|
|
2606
2686
|
const result = await walletClient.writeContract({
|
|
2607
2687
|
address: tokenAddress,
|
|
2608
2688
|
abi: import_viem4.erc20Abi,
|
|
2609
2689
|
functionName: "approve",
|
|
2610
|
-
args: [
|
|
2690
|
+
args: [spreePayConfig.crypto.oneInchAggregationRouter, MAX_UINT256]
|
|
2611
2691
|
});
|
|
2612
2692
|
await waitForTransactionReceipt(config, {
|
|
2613
2693
|
hash: result,
|
|
@@ -2625,7 +2705,7 @@ var useCryptoPayment = () => {
|
|
|
2625
2705
|
token: TOKEN,
|
|
2626
2706
|
publicKey: walletClient.account.address,
|
|
2627
2707
|
slippageType: "fixed",
|
|
2628
|
-
slippageBps: 0.5 * 100
|
|
2708
|
+
slippageBps: Math.round(0.5 * 100)
|
|
2629
2709
|
}
|
|
2630
2710
|
});
|
|
2631
2711
|
const parsedTX = JSON.parse(paymentRes.data.encodedTx);
|
|
@@ -3172,8 +3252,8 @@ var CryptoWrapper = () => {
|
|
|
3172
3252
|
const config = (0, import_react16.useMemo)(() => {
|
|
3173
3253
|
if (!spreePayConfig) return null;
|
|
3174
3254
|
return (0, import_rainbowkit2.getDefaultConfig)({
|
|
3175
|
-
appName: spreePayConfig.rainbowAppName
|
|
3176
|
-
projectId: spreePayConfig.rainbowProjectId
|
|
3255
|
+
appName: spreePayConfig.rainbowAppName,
|
|
3256
|
+
projectId: spreePayConfig.rainbowProjectId,
|
|
3177
3257
|
chains: [import_chains.base],
|
|
3178
3258
|
ssr: true
|
|
3179
3259
|
});
|
|
@@ -3185,9 +3265,10 @@ var CryptoWrapper = () => {
|
|
|
3185
3265
|
// src/components/CryptoTab/CryptoTab.tsx
|
|
3186
3266
|
var import_jsx_runtime39 = require("react/jsx-runtime");
|
|
3187
3267
|
var CryptoTab = () => {
|
|
3268
|
+
const { spreePayConfig } = useSpreePayConfig();
|
|
3188
3269
|
return /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { children: [
|
|
3189
3270
|
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)("div", { className: "border-b-1 border-black/7 px-5 py-5 md:px-7 md:py-5", children: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(CryptoWrapper, {}) }),
|
|
3190
|
-
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)("div", { className: "px-5 py-5 md:px-7 md:py-6", children: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(PointsSwitch, { disabled: true }) })
|
|
3271
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)("div", { className: "px-5 py-5 md:px-7 md:py-6", children: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(PointsSwitch, { disabled: true, message: spreePayConfig?.crypto.pointsInfoMessage }) })
|
|
3191
3272
|
] });
|
|
3192
3273
|
};
|
|
3193
3274
|
|
|
@@ -3239,7 +3320,7 @@ var TabButtons = (props) => {
|
|
|
3239
3320
|
/* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(
|
|
3240
3321
|
TabButton,
|
|
3241
3322
|
{
|
|
3242
|
-
isDisabled: !spreePayConfig?.
|
|
3323
|
+
isDisabled: !spreePayConfig?.crypto.enabled,
|
|
3243
3324
|
onClick: handleChange("CRYPTO" /* CRYPTO */),
|
|
3244
3325
|
isActive: value === "CRYPTO" /* CRYPTO */,
|
|
3245
3326
|
children: [
|
package/build/index.css
CHANGED
|
@@ -344,6 +344,10 @@
|
|
|
344
344
|
width: calc(var(--spacing) * 4);
|
|
345
345
|
height: calc(var(--spacing) * 4);
|
|
346
346
|
}
|
|
347
|
+
.sl-spreepay .size-5 {
|
|
348
|
+
width: calc(var(--spacing) * 5);
|
|
349
|
+
height: calc(var(--spacing) * 5);
|
|
350
|
+
}
|
|
347
351
|
.sl-spreepay .size-6 {
|
|
348
352
|
width: calc(var(--spacing) * 6);
|
|
349
353
|
height: calc(var(--spacing) * 6);
|
|
@@ -507,6 +511,9 @@
|
|
|
507
511
|
.sl-spreepay .items-center {
|
|
508
512
|
align-items: center;
|
|
509
513
|
}
|
|
514
|
+
.sl-spreepay .items-start {
|
|
515
|
+
align-items: flex-start;
|
|
516
|
+
}
|
|
510
517
|
.sl-spreepay .justify-between {
|
|
511
518
|
justify-content: space-between;
|
|
512
519
|
}
|
|
@@ -591,6 +598,9 @@
|
|
|
591
598
|
border-left-style: var(--tw-border-style) !important;
|
|
592
599
|
border-left-width: 0px !important;
|
|
593
600
|
}
|
|
601
|
+
.sl-spreepay .border-\[\#006FD533\] {
|
|
602
|
+
border-color: #006FD533;
|
|
603
|
+
}
|
|
594
604
|
.sl-spreepay .border-\[\#F5F7FA\] {
|
|
595
605
|
border-color: #F5F7FA;
|
|
596
606
|
}
|
|
@@ -630,6 +640,9 @@
|
|
|
630
640
|
.sl-spreepay .border-transparent {
|
|
631
641
|
border-color: transparent;
|
|
632
642
|
}
|
|
643
|
+
.sl-spreepay .bg-\[\#006FD50D\] {
|
|
644
|
+
background-color: #006FD50D;
|
|
645
|
+
}
|
|
633
646
|
.sl-spreepay .bg-\[\#F5F7FA\] {
|
|
634
647
|
background-color: #F5F7FA;
|
|
635
648
|
}
|
|
@@ -699,6 +712,9 @@
|
|
|
699
712
|
.sl-spreepay .p-1 {
|
|
700
713
|
padding: calc(var(--spacing) * 1);
|
|
701
714
|
}
|
|
715
|
+
.sl-spreepay .p-1\.5 {
|
|
716
|
+
padding: calc(var(--spacing) * 1.5);
|
|
717
|
+
}
|
|
702
718
|
.sl-spreepay .p-6 {
|
|
703
719
|
padding: calc(var(--spacing) * 6);
|
|
704
720
|
}
|
package/build/index.d.cts
CHANGED
|
@@ -50,7 +50,7 @@ type Card = {
|
|
|
50
50
|
active: boolean;
|
|
51
51
|
addressZipCheck: string;
|
|
52
52
|
cardId: string;
|
|
53
|
-
createdAt: Date;
|
|
53
|
+
createdAt: string | Date;
|
|
54
54
|
default: boolean;
|
|
55
55
|
expireMonth: string;
|
|
56
56
|
expireYear: string;
|
|
@@ -62,7 +62,7 @@ type Card = {
|
|
|
62
62
|
name: string;
|
|
63
63
|
paymentProvider: string;
|
|
64
64
|
schema: string | undefined;
|
|
65
|
-
updatedAt: Date;
|
|
65
|
+
updatedAt: string | Date;
|
|
66
66
|
userId: string;
|
|
67
67
|
zipCode: string;
|
|
68
68
|
};
|
|
@@ -84,10 +84,10 @@ type SelectedPaymentMethod = CardPaymentMethod | CryptoPaymentMethod;
|
|
|
84
84
|
declare enum PaymentType {
|
|
85
85
|
CREDIT_CARD = "CREDIT_CARD",
|
|
86
86
|
CRYPTO = "CRYPTO",
|
|
87
|
-
|
|
87
|
+
CREDIT_CARD_SPLIT = "SPLIT",
|
|
88
88
|
POINTS = "POINTS"
|
|
89
89
|
}
|
|
90
|
-
declare
|
|
90
|
+
declare enum SlapiPaymentStatus {
|
|
91
91
|
NOT_INITIALIZED = "NOT_INITIALIZED",// back-end only
|
|
92
92
|
PENDING = "PENDING",// back-end only
|
|
93
93
|
AUTHORIZED = "AUTHORIZED",// success
|
package/build/index.d.ts
CHANGED
|
@@ -50,7 +50,7 @@ type Card = {
|
|
|
50
50
|
active: boolean;
|
|
51
51
|
addressZipCheck: string;
|
|
52
52
|
cardId: string;
|
|
53
|
-
createdAt: Date;
|
|
53
|
+
createdAt: string | Date;
|
|
54
54
|
default: boolean;
|
|
55
55
|
expireMonth: string;
|
|
56
56
|
expireYear: string;
|
|
@@ -62,7 +62,7 @@ type Card = {
|
|
|
62
62
|
name: string;
|
|
63
63
|
paymentProvider: string;
|
|
64
64
|
schema: string | undefined;
|
|
65
|
-
updatedAt: Date;
|
|
65
|
+
updatedAt: string | Date;
|
|
66
66
|
userId: string;
|
|
67
67
|
zipCode: string;
|
|
68
68
|
};
|
|
@@ -84,10 +84,10 @@ type SelectedPaymentMethod = CardPaymentMethod | CryptoPaymentMethod;
|
|
|
84
84
|
declare enum PaymentType {
|
|
85
85
|
CREDIT_CARD = "CREDIT_CARD",
|
|
86
86
|
CRYPTO = "CRYPTO",
|
|
87
|
-
|
|
87
|
+
CREDIT_CARD_SPLIT = "SPLIT",
|
|
88
88
|
POINTS = "POINTS"
|
|
89
89
|
}
|
|
90
|
-
declare
|
|
90
|
+
declare enum SlapiPaymentStatus {
|
|
91
91
|
NOT_INITIALIZED = "NOT_INITIALIZED",// back-end only
|
|
92
92
|
PENDING = "PENDING",// back-end only
|
|
93
93
|
AUTHORIZED = "AUTHORIZED",// success
|
package/build/index.js
CHANGED
|
@@ -22,7 +22,7 @@ var PaymentError = class extends Error {
|
|
|
22
22
|
var PaymentType = /* @__PURE__ */ ((PaymentType2) => {
|
|
23
23
|
PaymentType2["CREDIT_CARD"] = "CREDIT_CARD";
|
|
24
24
|
PaymentType2["CRYPTO"] = "CRYPTO";
|
|
25
|
-
PaymentType2["
|
|
25
|
+
PaymentType2["CREDIT_CARD_SPLIT"] = "SPLIT";
|
|
26
26
|
PaymentType2["POINTS"] = "POINTS";
|
|
27
27
|
return PaymentType2;
|
|
28
28
|
})(PaymentType || {});
|
|
@@ -101,48 +101,36 @@ var CONFIG = {
|
|
|
101
101
|
bookit: {
|
|
102
102
|
slapiUrl: "https://slapi.dev.superlogic.com",
|
|
103
103
|
keycloakUrl: "https://auth.dev.join.bookit.com",
|
|
104
|
-
keycloakClientId: "oneof-next"
|
|
105
|
-
pointsConversionRatio: 100,
|
|
106
|
-
pointsTitle: "AIR SP"
|
|
104
|
+
keycloakClientId: "oneof-next"
|
|
107
105
|
},
|
|
108
106
|
moca: {
|
|
109
107
|
slapiUrl: "https://slapi.dev.air.shop",
|
|
110
108
|
keycloakUrl: "https://login.dev.air.shop",
|
|
111
|
-
keycloakClientId: "oneof-next"
|
|
112
|
-
pointsConversionRatio: 100,
|
|
113
|
-
pointsTitle: "AIR SP"
|
|
109
|
+
keycloakClientId: "oneof-next"
|
|
114
110
|
}
|
|
115
111
|
},
|
|
116
112
|
stg: {
|
|
117
113
|
bookit: {
|
|
118
114
|
slapiUrl: "https://slapi.stg.superlogic.com",
|
|
119
115
|
keycloakUrl: "https://auth.stg.join.bookit.com",
|
|
120
|
-
keycloakClientId: "oneof-next"
|
|
121
|
-
pointsConversionRatio: 100,
|
|
122
|
-
pointsTitle: "AIR SP"
|
|
116
|
+
keycloakClientId: "oneof-next"
|
|
123
117
|
},
|
|
124
118
|
moca: {
|
|
125
119
|
slapiUrl: "https://slapi.stg.air.shop",
|
|
126
120
|
keycloakUrl: "https://login.stg.air.shop",
|
|
127
|
-
keycloakClientId: "oneof-next"
|
|
128
|
-
pointsConversionRatio: 100,
|
|
129
|
-
pointsTitle: "AIR SP"
|
|
121
|
+
keycloakClientId: "oneof-next"
|
|
130
122
|
}
|
|
131
123
|
},
|
|
132
124
|
prod: {
|
|
133
125
|
bookit: {
|
|
134
126
|
slapiUrl: "https://slapi.superlogic.com",
|
|
135
127
|
keycloakUrl: "https://auth.join.bookit.com",
|
|
136
|
-
keycloakClientId: "oneof-next"
|
|
137
|
-
pointsConversionRatio: 100,
|
|
138
|
-
pointsTitle: "AIR SP"
|
|
128
|
+
keycloakClientId: "oneof-next"
|
|
139
129
|
},
|
|
140
130
|
moca: {
|
|
141
131
|
slapiUrl: "https://slapi.air.shop",
|
|
142
132
|
keycloakUrl: "https://login.air.shop",
|
|
143
|
-
keycloakClientId: "oneof-next"
|
|
144
|
-
pointsConversionRatio: 100,
|
|
145
|
-
pointsTitle: "AIR SP"
|
|
133
|
+
keycloakClientId: "oneof-next"
|
|
146
134
|
}
|
|
147
135
|
}
|
|
148
136
|
};
|
|
@@ -170,7 +158,20 @@ var useStaticConfig = () => {
|
|
|
170
158
|
import useSWR from "swr";
|
|
171
159
|
var useSpreePayConfig = () => {
|
|
172
160
|
const { data, isLoading } = useSWR("/v1/tenants/configs/spree-pay");
|
|
173
|
-
return {
|
|
161
|
+
return {
|
|
162
|
+
spreePayConfig: data ? {
|
|
163
|
+
...data,
|
|
164
|
+
rainbowProjectId: data.rainbowProjectId ?? "3fdcd5ff50cb84917cd05e40146975d8",
|
|
165
|
+
rainbowAppName: data.rainbowAppName ?? "AIR Shop",
|
|
166
|
+
pointsTitle: data.pointsTitle ?? "AIR SP",
|
|
167
|
+
pointsConversionRatio: data.pointsConversionRatio ?? 100,
|
|
168
|
+
crypto: {
|
|
169
|
+
...data.crypto,
|
|
170
|
+
oneInchAggregationRouter: data.crypto?.oneInchAggregationRouter || "0x111111125421ca6dc452d289314280a0f8842a65"
|
|
171
|
+
}
|
|
172
|
+
} : null,
|
|
173
|
+
configIsLoading: isLoading
|
|
174
|
+
};
|
|
174
175
|
};
|
|
175
176
|
|
|
176
177
|
// src/lib/utils.ts
|
|
@@ -237,7 +238,7 @@ var formatUSD = (amount, currency = "USD") => {
|
|
|
237
238
|
}).format(amount);
|
|
238
239
|
return formattedAmount;
|
|
239
240
|
};
|
|
240
|
-
var formatPoints = (amount, pointsTitle = "
|
|
241
|
+
var formatPoints = (amount, pointsTitle = "") => {
|
|
241
242
|
const formattedAmount = new Intl.NumberFormat("en-US", {
|
|
242
243
|
notation: "compact",
|
|
243
244
|
style: "decimal",
|
|
@@ -257,7 +258,7 @@ var formatCoin = (amount, currency = "USDC") => {
|
|
|
257
258
|
|
|
258
259
|
// src/utils/split.ts
|
|
259
260
|
var getSplitAmount = (amount, splitTokens, pointsConversionRatio) => {
|
|
260
|
-
if (!Number.isFinite(amount) || !Number.isFinite(splitTokens) || !Number.isFinite(pointsConversionRatio)) {
|
|
261
|
+
if (!Number.isFinite(amount) || !Number.isFinite(splitTokens) || !pointsConversionRatio || !Number.isFinite(pointsConversionRatio)) {
|
|
261
262
|
return amount;
|
|
262
263
|
}
|
|
263
264
|
if (pointsConversionRatio <= 0) return amount;
|
|
@@ -279,13 +280,13 @@ var getTransactionFee = (amount = 0, transactionFeePercentage) => {
|
|
|
279
280
|
// src/components/CheckoutButton.tsx
|
|
280
281
|
import { jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
281
282
|
var CheckoutButton = ({ isLoggedIn }) => {
|
|
282
|
-
const {
|
|
283
|
+
const { appProps } = useStaticConfig();
|
|
283
284
|
const { amount, onProcess, isProcessing, transactionFeePercentage } = appProps;
|
|
284
285
|
const { spreePayConfig } = useSpreePayConfig();
|
|
285
|
-
const { pointsTitle, pointsConversionRatio } = staticConfig;
|
|
286
286
|
const { selectedPaymentMethod, isInternalProcessing } = useSpreePaymentMethod();
|
|
287
287
|
const { splitAmount, type, method } = selectedPaymentMethod;
|
|
288
|
-
const
|
|
288
|
+
const usdAmount = getSplitAmount(amount ?? 0, splitAmount ?? 0, spreePayConfig?.pointsConversionRatio);
|
|
289
|
+
const isDisabled = !amount || !method && usdAmount !== 0 || !!isProcessing || isInternalProcessing || !isLoggedIn;
|
|
289
290
|
const isCC = type === "CREDIT_CARD" /* CREDIT_CARD */;
|
|
290
291
|
const isCrypto = type === "CRYPTO" /* CRYPTO */;
|
|
291
292
|
const getCheckoutContent = () => {
|
|
@@ -293,15 +294,14 @@ var CheckoutButton = ({ isLoggedIn }) => {
|
|
|
293
294
|
return /* @__PURE__ */ jsx4(Spinner, { className: "inline", size: "sm" });
|
|
294
295
|
}
|
|
295
296
|
if (isCC && amount) {
|
|
296
|
-
const usdAmount = getSplitAmount(amount, splitAmount ?? 0, pointsConversionRatio);
|
|
297
297
|
if (splitAmount && usdAmount) {
|
|
298
|
-
return `Pay ${formatUSD(usdAmount + getTransactionFee(usdAmount, transactionFeePercentage))} + ${formatPoints(splitAmount, pointsTitle)}`;
|
|
298
|
+
return `Pay ${formatUSD(usdAmount + getTransactionFee(usdAmount, transactionFeePercentage))} + ${formatPoints(splitAmount, spreePayConfig?.pointsTitle)}`;
|
|
299
299
|
}
|
|
300
300
|
if (usdAmount) {
|
|
301
301
|
return `Pay ${formatUSD(usdAmount + getTransactionFee(usdAmount, transactionFeePercentage))}`;
|
|
302
302
|
}
|
|
303
303
|
if (splitAmount) {
|
|
304
|
-
return `Pay ${formatPoints(splitAmount, pointsTitle)}`;
|
|
304
|
+
return `Pay ${formatPoints(splitAmount, spreePayConfig?.pointsTitle)}`;
|
|
305
305
|
}
|
|
306
306
|
return "Checkout";
|
|
307
307
|
}
|
|
@@ -354,7 +354,7 @@ var SpreeLegal = () => {
|
|
|
354
354
|
// src/components/CreditCardTab/CreditCardTab.tsx
|
|
355
355
|
import { useCallback as useCallback5, useEffect as useEffect7 } from "react";
|
|
356
356
|
|
|
357
|
-
// src/hooks/useCardPayment.ts
|
|
357
|
+
// src/hooks/payments/useCardPayment.ts
|
|
358
358
|
import NiceModal2 from "@ebay/nice-modal-react";
|
|
359
359
|
|
|
360
360
|
// src/modals/Iframe3ds.tsx
|
|
@@ -589,17 +589,8 @@ var registerApi = (config) => {
|
|
|
589
589
|
|
|
590
590
|
// src/services/slapi.ts
|
|
591
591
|
var SlapiPaymentService = {
|
|
592
|
-
createPayment: (
|
|
593
|
-
|
|
594
|
-
let reqParams;
|
|
595
|
-
if (type === "CRYPTO" /* CRYPTO */) {
|
|
596
|
-
reqParams = { type, hash, crypto: params.crypto };
|
|
597
|
-
} else if (type === "CREDIT_CARD" /* CREDIT_CARD */ && params.points && params.points.amount > 0) {
|
|
598
|
-
reqParams = { type: "SPLIT" /* SPLIT */, hash, card: params.card, points: params.points };
|
|
599
|
-
} else {
|
|
600
|
-
reqParams = { type, hash, card: params.card };
|
|
601
|
-
}
|
|
602
|
-
return slapiApi.post("/v1/payments", { ...reqParams, capture, metadata }).then((data) => ({ data }));
|
|
592
|
+
createPayment: ({ capture = false, ...rest }) => {
|
|
593
|
+
return slapiApi.post("/v1/payments", { ...rest, capture }).then((data) => ({ data }));
|
|
603
594
|
},
|
|
604
595
|
baseVerify: ({ id, txHash }) => {
|
|
605
596
|
return slapiApi.post(`/v1/base-transactions/transactions/${id}/verify`, { txHash });
|
|
@@ -618,7 +609,7 @@ var SlapiPaymentService = {
|
|
|
618
609
|
}
|
|
619
610
|
};
|
|
620
611
|
|
|
621
|
-
// src/hooks/useCardPayment.ts
|
|
612
|
+
// src/hooks/payments/useCardPayment.ts
|
|
622
613
|
var useCardPayment = () => {
|
|
623
614
|
const { selectedPaymentMethod } = useSpreePaymentMethod();
|
|
624
615
|
const { env } = useSpreePayEnv();
|
|
@@ -667,20 +658,6 @@ var useCardPayment = () => {
|
|
|
667
658
|
return { cardPayment };
|
|
668
659
|
};
|
|
669
660
|
|
|
670
|
-
// src/hooks/useCards.ts
|
|
671
|
-
import useSWR2 from "swr";
|
|
672
|
-
var useCards = () => {
|
|
673
|
-
const { data, isLoading, mutate } = useSWR2(`/v1/payments/cards`);
|
|
674
|
-
return {
|
|
675
|
-
cards: data?.data.filter((c) => c.active) || [],
|
|
676
|
-
cardsIsLoading: isLoading,
|
|
677
|
-
mutateCards: mutate
|
|
678
|
-
};
|
|
679
|
-
};
|
|
680
|
-
|
|
681
|
-
// src/hooks/useSplitCardPayments.ts
|
|
682
|
-
import NiceModal3 from "@ebay/nice-modal-react";
|
|
683
|
-
|
|
684
661
|
// src/services/AirWalletService.ts
|
|
685
662
|
import { AirService, BUILD_ENV } from "@mocanetwork/airkit";
|
|
686
663
|
import { createWalletClient, custom, encodeFunctionData, erc20Abi, parseUnits } from "viem";
|
|
@@ -772,7 +749,8 @@ async function handleSendErc20(params) {
|
|
|
772
749
|
}
|
|
773
750
|
}
|
|
774
751
|
|
|
775
|
-
// src/hooks/
|
|
752
|
+
// src/hooks/payments/utils.ts
|
|
753
|
+
import NiceModal3 from "@ebay/nice-modal-react";
|
|
776
754
|
var REFRESH_INTERVAL = 3 * 1e3;
|
|
777
755
|
var MAX_RETRIES = 10;
|
|
778
756
|
async function longPollPoints(paymentId) {
|
|
@@ -813,10 +791,55 @@ async function longPollCardStatus(paymentId) {
|
|
|
813
791
|
}
|
|
814
792
|
throw new Error("Payment polling timed out");
|
|
815
793
|
}
|
|
794
|
+
|
|
795
|
+
// src/hooks/payments/usePointsPayment.ts
|
|
796
|
+
var usePointsPayment = () => {
|
|
797
|
+
const { selectedPaymentMethod } = useSpreePaymentMethod();
|
|
798
|
+
const { spreePayConfig } = useSpreePayConfig();
|
|
799
|
+
const pointsPayment = async (params) => {
|
|
800
|
+
if (selectedPaymentMethod.type !== "CREDIT_CARD" /* CREDIT_CARD */) {
|
|
801
|
+
throw new Error("Unsupported payment method");
|
|
802
|
+
}
|
|
803
|
+
const { hash, capture, metadata } = params;
|
|
804
|
+
const { data: paymentResData } = await SlapiPaymentService.createPayment({
|
|
805
|
+
hash,
|
|
806
|
+
capture,
|
|
807
|
+
metadata,
|
|
808
|
+
type: "POINTS" /* POINTS */
|
|
809
|
+
});
|
|
810
|
+
const wallet = peekAirWallet();
|
|
811
|
+
if (!wallet || !spreePayConfig?.pointsChain) {
|
|
812
|
+
throw new Error("AirWallet not found");
|
|
813
|
+
}
|
|
814
|
+
const transaction = await handleSendErc20({
|
|
815
|
+
amount: params.points,
|
|
816
|
+
token: spreePayConfig.pointsChain.pointsCoin,
|
|
817
|
+
recipient: spreePayConfig.pointsChain.recipientAddress
|
|
818
|
+
});
|
|
819
|
+
if (!transaction) {
|
|
820
|
+
throw new Error("Points transaction failed");
|
|
821
|
+
}
|
|
822
|
+
await SlapiPaymentService.validatePoints({
|
|
823
|
+
paymentId: paymentResData.id,
|
|
824
|
+
txHash: transaction.txHash
|
|
825
|
+
});
|
|
826
|
+
const pointsStatus = await longPollPoints(paymentResData.id);
|
|
827
|
+
return {
|
|
828
|
+
status: pointsStatus,
|
|
829
|
+
txId: paymentResData.txId,
|
|
830
|
+
txHash: transaction.txHash,
|
|
831
|
+
paymentId: paymentResData.id,
|
|
832
|
+
paymentType: "POINTS" /* POINTS */
|
|
833
|
+
};
|
|
834
|
+
};
|
|
835
|
+
return { pointsPayment };
|
|
836
|
+
};
|
|
837
|
+
|
|
838
|
+
// src/hooks/payments/useSplitCardPayments.ts
|
|
816
839
|
var useSplitCardPayments = () => {
|
|
817
840
|
const { selectedPaymentMethod } = useSpreePaymentMethod();
|
|
818
841
|
const { env } = useSpreePayEnv();
|
|
819
|
-
const { appProps
|
|
842
|
+
const { appProps } = useStaticConfig();
|
|
820
843
|
const { spreePayConfig } = useSpreePayConfig();
|
|
821
844
|
const splitPayment = async (params) => {
|
|
822
845
|
if (selectedPaymentMethod.type !== "CREDIT_CARD" /* CREDIT_CARD */ || !selectedPaymentMethod.method || !params.points) {
|
|
@@ -831,13 +854,13 @@ var useSplitCardPayments = () => {
|
|
|
831
854
|
} else {
|
|
832
855
|
cardId = card.id;
|
|
833
856
|
}
|
|
834
|
-
const usdAmount = getSplitAmount(appProps.amount ?? 0, points,
|
|
857
|
+
const usdAmount = getSplitAmount(appProps.amount ?? 0, points, spreePayConfig?.pointsConversionRatio);
|
|
835
858
|
const transactionFee = getTransactionFee(usdAmount, appProps.transactionFeePercentage);
|
|
836
859
|
const { data: paymentResData } = await SlapiPaymentService.createPayment({
|
|
837
860
|
hash,
|
|
838
861
|
capture,
|
|
839
862
|
metadata,
|
|
840
|
-
type: "
|
|
863
|
+
type: "SPLIT" /* CREDIT_CARD_SPLIT */,
|
|
841
864
|
card: {
|
|
842
865
|
cardId,
|
|
843
866
|
transactionFee,
|
|
@@ -866,7 +889,7 @@ var useSplitCardPayments = () => {
|
|
|
866
889
|
});
|
|
867
890
|
const pointsStatus = await longPollPoints(paymentResData.id);
|
|
868
891
|
return {
|
|
869
|
-
paymentType: "SPLIT" /*
|
|
892
|
+
paymentType: "SPLIT" /* CREDIT_CARD_SPLIT */,
|
|
870
893
|
status: pointsStatus,
|
|
871
894
|
paymentId: paymentResData.id,
|
|
872
895
|
txId: paymentResData.txId,
|
|
@@ -876,6 +899,17 @@ var useSplitCardPayments = () => {
|
|
|
876
899
|
return { splitPayment };
|
|
877
900
|
};
|
|
878
901
|
|
|
902
|
+
// src/hooks/useCards.ts
|
|
903
|
+
import useSWR2 from "swr";
|
|
904
|
+
var useCards = () => {
|
|
905
|
+
const { data, isLoading, mutate } = useSWR2(`/v1/payments/cards`);
|
|
906
|
+
return {
|
|
907
|
+
cards: data?.data.filter((c) => c.active) || [],
|
|
908
|
+
cardsIsLoading: isLoading,
|
|
909
|
+
mutateCards: mutate
|
|
910
|
+
};
|
|
911
|
+
};
|
|
912
|
+
|
|
879
913
|
// src/components/CreditCardTab/CreditCard/CreditCard.tsx
|
|
880
914
|
import { useMemo as useMemo2, useState as useState4 } from "react";
|
|
881
915
|
import { Elements } from "@stripe/react-stripe-js";
|
|
@@ -1229,24 +1263,35 @@ function Switch({ className, ...props }) {
|
|
|
1229
1263
|
// src/components/common/PointsSwitch.tsx
|
|
1230
1264
|
import { jsx as jsx15, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
1231
1265
|
var PointsSwitch = (props) => {
|
|
1232
|
-
const { disabled = false, value, onChange } = props;
|
|
1233
|
-
const {
|
|
1234
|
-
const { pointsConversionRatio, pointsTitle } = staticConfig;
|
|
1266
|
+
const { disabled = false, value, onChange, message } = props;
|
|
1267
|
+
const { spreePayConfig } = useSpreePayConfig();
|
|
1235
1268
|
const { balance } = useSlapiBalance();
|
|
1236
1269
|
const id = useId2();
|
|
1237
|
-
return /* @__PURE__ */ jsxs9("div", { className: "flex
|
|
1238
|
-
/* @__PURE__ */ jsxs9("div", { className: "flex items-center gap-3", children: [
|
|
1239
|
-
/* @__PURE__ */
|
|
1240
|
-
|
|
1241
|
-
"
|
|
1242
|
-
|
|
1243
|
-
|
|
1270
|
+
return /* @__PURE__ */ jsxs9("div", { className: "flex flex-col gap-6", children: [
|
|
1271
|
+
/* @__PURE__ */ jsxs9("div", { className: "flex items-center justify-between gap-3", children: [
|
|
1272
|
+
/* @__PURE__ */ jsxs9("div", { className: "flex items-center gap-3", children: [
|
|
1273
|
+
/* @__PURE__ */ jsx15(Switch, { checked: value, onCheckedChange: onChange, disabled, id }),
|
|
1274
|
+
/* @__PURE__ */ jsxs9(Label, { className: "text-md items-baseline leading-[1.3] font-semibold text-black md:text-xl", htmlFor: id, children: [
|
|
1275
|
+
"Use Points ",
|
|
1276
|
+
/* @__PURE__ */ jsx15("span", { className: "text-xs font-medium", children: "Optional" })
|
|
1277
|
+
] })
|
|
1278
|
+
] }),
|
|
1279
|
+
balance?.availablePoints ? /* @__PURE__ */ jsxs9("p", { className: "flex-1 text-right text-sm font-medium text-black", children: [
|
|
1280
|
+
formatPoints(balance.availablePoints, spreePayConfig?.pointsTitle),
|
|
1281
|
+
" ",
|
|
1282
|
+
!!spreePayConfig?.pointsConversionRatio && /* @__PURE__ */ jsx15("span", { className: "text-black/50", children: formatUSD(balance.availablePoints / spreePayConfig.pointsConversionRatio) })
|
|
1283
|
+
] }) : null
|
|
1244
1284
|
] }),
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1285
|
+
message && /* @__PURE__ */ jsxs9("div", { className: "flex items-start gap-1 rounded-sm border-1 border-[#006FD533] bg-[#006FD50D] p-1.5", children: [
|
|
1286
|
+
/* @__PURE__ */ jsx15("svg", { className: "size-5 shrink-0", xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 20 20", children: /* @__PURE__ */ jsx15(
|
|
1287
|
+
"path",
|
|
1288
|
+
{
|
|
1289
|
+
fill: "#000",
|
|
1290
|
+
d: "M9.6 13.8h.8V9.2h-.8zM10 8q.2 0 .4-.2l.1-.3-.1-.4L10 7l-.4.1-.1.4.1.3zm0 9.5a7 7 0 0 1-5.3-2.2 8 8 0 0 1-1.6-8.2 8 8 0 0 1 4-4q1.4-.6 2.9-.6a7 7 0 0 1 5.3 2.2 8 8 0 0 1 1.6 8.2 8 8 0 0 1-4 4q-1.4.6-2.9.6m0-.8q2.8 0 4.7-2 2-1.9 2-4.7t-2-4.7a6 6 0 0 0-4.7-2q-2.8 0-4.7 2a6 6 0 0 0-2 4.7q0 2.8 2 4.7 1.9 2 4.7 2"
|
|
1291
|
+
}
|
|
1292
|
+
) }),
|
|
1293
|
+
/* @__PURE__ */ jsx15("p", { className: "text-xs font-medium text-black", children: message })
|
|
1294
|
+
] })
|
|
1250
1295
|
] });
|
|
1251
1296
|
};
|
|
1252
1297
|
|
|
@@ -2250,12 +2295,14 @@ var PointsSelector = (props) => {
|
|
|
2250
2295
|
const { isDisabled, isSelected, onSelect, children } = props;
|
|
2251
2296
|
const { balance } = useSlapiBalance();
|
|
2252
2297
|
const { selectedPaymentMethod, setSelectedPaymentMethod } = useSpreePaymentMethod();
|
|
2253
|
-
const { appProps
|
|
2298
|
+
const { appProps } = useStaticConfig();
|
|
2299
|
+
const { spreePayConfig } = useSpreePayConfig();
|
|
2300
|
+
const { pointsConversionRatio } = spreePayConfig || {};
|
|
2254
2301
|
const min = 0;
|
|
2255
|
-
const max = Math.min((appProps.amount ?? 0) *
|
|
2302
|
+
const max = Math.min((appProps.amount ?? 0) * (pointsConversionRatio ?? 0), balance?.availablePoints ?? 0);
|
|
2256
2303
|
const step = 10;
|
|
2257
2304
|
const [splitTokens, setSplitTokens] = useState8(0);
|
|
2258
|
-
const
|
|
2305
|
+
const usdAmount = getSplitAmount(appProps.amount ?? 0, splitTokens, pointsConversionRatio);
|
|
2259
2306
|
const handleCommit = (value) => {
|
|
2260
2307
|
setSelectedPaymentMethod({ ...selectedPaymentMethod, splitAmount: value });
|
|
2261
2308
|
};
|
|
@@ -2283,7 +2330,15 @@ var PointsSelector = (props) => {
|
|
|
2283
2330
|
] }),
|
|
2284
2331
|
isSelected && /* @__PURE__ */ jsx24("div", { className: "px-3 pt-6 pb-2 md:px-4", children: /* @__PURE__ */ jsxs12("div", { className: "flex justify-between gap-3", children: [
|
|
2285
2332
|
/* @__PURE__ */ jsxs12("div", { className: "flex max-w-[100px] flex-col gap-1", children: [
|
|
2286
|
-
/* @__PURE__ */ jsx24(
|
|
2333
|
+
/* @__PURE__ */ jsx24(
|
|
2334
|
+
Input,
|
|
2335
|
+
{
|
|
2336
|
+
readOnly: true,
|
|
2337
|
+
value: Math.round(splitTokens),
|
|
2338
|
+
className: "bg-white text-center font-medium",
|
|
2339
|
+
onClick: (e) => e.stopPropagation()
|
|
2340
|
+
}
|
|
2341
|
+
),
|
|
2287
2342
|
/* @__PURE__ */ jsx24("p", { className: "text-left text-xs leading-[20px] text-black/45", children: "Points" })
|
|
2288
2343
|
] }),
|
|
2289
2344
|
/* @__PURE__ */ jsx24("div", { className: "flex w-full items-center pb-6", children: /* @__PURE__ */ jsx24(
|
|
@@ -2292,6 +2347,7 @@ var PointsSelector = (props) => {
|
|
|
2292
2347
|
value: [splitTokens],
|
|
2293
2348
|
onValueCommit: ([v]) => handleCommit(v),
|
|
2294
2349
|
onValueChange: ([v]) => setSplitTokens(v),
|
|
2350
|
+
onPointerDown: (e) => e.stopPropagation(),
|
|
2295
2351
|
min,
|
|
2296
2352
|
max,
|
|
2297
2353
|
step
|
|
@@ -2302,8 +2358,9 @@ var PointsSelector = (props) => {
|
|
|
2302
2358
|
Input,
|
|
2303
2359
|
{
|
|
2304
2360
|
readOnly: true,
|
|
2305
|
-
value: formatUSD(
|
|
2306
|
-
className: "bg-white text-center font-medium"
|
|
2361
|
+
value: formatUSD(usdAmount + getTransactionFee(usdAmount, appProps.transactionFeePercentage)),
|
|
2362
|
+
className: "bg-white text-center font-medium",
|
|
2363
|
+
onClick: (e) => e.stopPropagation()
|
|
2307
2364
|
}
|
|
2308
2365
|
),
|
|
2309
2366
|
/* @__PURE__ */ jsx24("p", { className: "text-left text-xs leading-[20px] text-black/45", children: "Card" })
|
|
@@ -2322,8 +2379,7 @@ var SplitBlock = (props) => {
|
|
|
2322
2379
|
const { spreePayConfig } = useSpreePayConfig();
|
|
2323
2380
|
const [address, setAddress] = useState9(null);
|
|
2324
2381
|
const [walletReady, setWalletReady] = useState9(false);
|
|
2325
|
-
const {
|
|
2326
|
-
const { pointsConversionRatio, pointsTitle } = staticConfig;
|
|
2382
|
+
const { pointsConversionRatio, pointsTitle } = spreePayConfig || {};
|
|
2327
2383
|
const initWallet = useCallback4(
|
|
2328
2384
|
async (pointsChain) => {
|
|
2329
2385
|
if (!pointsChain) return;
|
|
@@ -2354,7 +2410,7 @@ var SplitBlock = (props) => {
|
|
|
2354
2410
|
" ",
|
|
2355
2411
|
formatPoints(balance.availablePoints, pointsTitle),
|
|
2356
2412
|
" ",
|
|
2357
|
-
/* @__PURE__ */ jsx25("span", { className: "text-black/50", children: formatUSD(balance.availablePoints / pointsConversionRatio) })
|
|
2413
|
+
pointsConversionRatio && /* @__PURE__ */ jsx25("span", { className: "text-black/50", children: formatUSD(balance.availablePoints / pointsConversionRatio) })
|
|
2358
2414
|
] }) : null }),
|
|
2359
2415
|
isBalanceLoading ? /* @__PURE__ */ jsx25("div", { className: "h-4 w-6 animate-pulse bg-gray-200" }) : !balance?.availablePoints && /* @__PURE__ */ jsx25("p", { className: "text-sm font-medium text-black", children: "No points available" }),
|
|
2360
2416
|
address && /* @__PURE__ */ jsx25("div", { className: "text-sm font-medium text-black", children: address.length > 8 ? `${address.slice(0, 4)}...${address.slice(-4)}` : address })
|
|
@@ -2376,7 +2432,15 @@ var Points = () => {
|
|
|
2376
2432
|
}
|
|
2377
2433
|
};
|
|
2378
2434
|
return /* @__PURE__ */ jsxs14(Fragment3, { children: [
|
|
2379
|
-
/* @__PURE__ */ jsx26(
|
|
2435
|
+
/* @__PURE__ */ jsx26(
|
|
2436
|
+
PointsSwitch,
|
|
2437
|
+
{
|
|
2438
|
+
value: usePoints,
|
|
2439
|
+
onChange: handleTogglePoints,
|
|
2440
|
+
message: spreePayConfig?.creditCard.pointsInfoMessage,
|
|
2441
|
+
disabled: !spreePayConfig?.creditCard.enabled || !spreePayConfig?.creditCard.points
|
|
2442
|
+
}
|
|
2443
|
+
),
|
|
2380
2444
|
usePoints && /* @__PURE__ */ jsx26(
|
|
2381
2445
|
SplitBlock,
|
|
2382
2446
|
{
|
|
@@ -2392,26 +2456,30 @@ var Points = () => {
|
|
|
2392
2456
|
import { jsx as jsx27, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
2393
2457
|
var CreditCardTab = () => {
|
|
2394
2458
|
const { selectedPaymentMethod, setSelectedPaymentMethod } = useSpreePaymentMethod();
|
|
2459
|
+
const { appProps } = useStaticConfig();
|
|
2460
|
+
const { spreePayConfig } = useSpreePayConfig();
|
|
2395
2461
|
const { register } = useSpreePayRegister();
|
|
2396
2462
|
const { mutateCards } = useCards();
|
|
2397
2463
|
const { cardPayment } = useCardPayment();
|
|
2398
2464
|
const { splitPayment } = useSplitCardPayments();
|
|
2465
|
+
const { pointsPayment } = usePointsPayment();
|
|
2399
2466
|
const handlePay = useCallback5(
|
|
2400
2467
|
async (data) => {
|
|
2401
2468
|
try {
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
|
|
2406
|
-
|
|
2407
|
-
|
|
2408
|
-
}
|
|
2409
|
-
|
|
2410
|
-
|
|
2411
|
-
}
|
|
2412
|
-
return Promise.reject(new PaymentError("Card payment failed", res.status));
|
|
2469
|
+
let res = null;
|
|
2470
|
+
const pointsAmount = selectedPaymentMethod.splitAmount ?? 0;
|
|
2471
|
+
const usdAmount = getSplitAmount(appProps.amount ?? 0, pointsAmount, spreePayConfig?.pointsConversionRatio);
|
|
2472
|
+
if (usdAmount && pointsAmount) {
|
|
2473
|
+
res = await splitPayment({ ...data, points: pointsAmount });
|
|
2474
|
+
} else if (!usdAmount && pointsAmount) {
|
|
2475
|
+
res = await pointsPayment({ ...data, points: pointsAmount });
|
|
2476
|
+
} else {
|
|
2477
|
+
res = await cardPayment(data);
|
|
2413
2478
|
}
|
|
2414
|
-
|
|
2479
|
+
if (["AUTHORIZED" /* AUTHORIZED */, "CAPTURED" /* CAPTURED */].includes(res.status)) {
|
|
2480
|
+
return Promise.resolve(res);
|
|
2481
|
+
}
|
|
2482
|
+
return Promise.reject(new PaymentError("Card payment failed", res.status));
|
|
2415
2483
|
} catch (_) {
|
|
2416
2484
|
return Promise.reject(new PaymentError("Payment failed", "FAILED" /* FAILED */));
|
|
2417
2485
|
} finally {
|
|
@@ -2419,7 +2487,16 @@ var CreditCardTab = () => {
|
|
|
2419
2487
|
mutateCards();
|
|
2420
2488
|
}
|
|
2421
2489
|
},
|
|
2422
|
-
[
|
|
2490
|
+
[
|
|
2491
|
+
mutateCards,
|
|
2492
|
+
selectedPaymentMethod,
|
|
2493
|
+
pointsPayment,
|
|
2494
|
+
appProps.amount,
|
|
2495
|
+
setSelectedPaymentMethod,
|
|
2496
|
+
cardPayment,
|
|
2497
|
+
splitPayment,
|
|
2498
|
+
spreePayConfig
|
|
2499
|
+
]
|
|
2423
2500
|
);
|
|
2424
2501
|
useEffect7(() => {
|
|
2425
2502
|
register(handlePay);
|
|
@@ -2494,7 +2571,7 @@ async function waitForTransactionReceipt(config, parameters) {
|
|
|
2494
2571
|
// ../../node_modules/@wagmi/core/dist/esm/exports/index.js
|
|
2495
2572
|
import { custom as custom2, http, webSocket } from "viem";
|
|
2496
2573
|
|
|
2497
|
-
// src/hooks/useCryptoPayment.ts
|
|
2574
|
+
// src/hooks/payments/useCryptoPayment.ts
|
|
2498
2575
|
import { erc20Abi as erc20Abi2 } from "viem";
|
|
2499
2576
|
import { useConfig, useWalletClient } from "wagmi";
|
|
2500
2577
|
|
|
@@ -2535,17 +2612,20 @@ var BASE_TOKENS = [
|
|
|
2535
2612
|
}
|
|
2536
2613
|
];
|
|
2537
2614
|
|
|
2538
|
-
// src/hooks/useCryptoPayment.ts
|
|
2615
|
+
// src/hooks/payments/useCryptoPayment.ts
|
|
2539
2616
|
var MAX_UINT256 = BigInt(2) ** BigInt(256) - BigInt(1);
|
|
2540
|
-
var ONE_INCH_AGGREGATION_ROUTER_V6 = "0x111111125421ca6dc452d289314280a0f8842a65";
|
|
2541
2617
|
var useCryptoPayment = () => {
|
|
2542
2618
|
const { data: walletClient } = useWalletClient();
|
|
2619
|
+
const { spreePayConfig } = useSpreePayConfig();
|
|
2543
2620
|
const config = useConfig();
|
|
2544
2621
|
const { selectedPaymentMethod } = useSpreePaymentMethod();
|
|
2545
2622
|
const cryptoPayment = async (params) => {
|
|
2546
2623
|
if (!walletClient) {
|
|
2547
2624
|
throw new Error("Wallet not connected");
|
|
2548
2625
|
}
|
|
2626
|
+
if (!spreePayConfig) {
|
|
2627
|
+
throw new Error("Spree Pay config not loaded");
|
|
2628
|
+
}
|
|
2549
2629
|
if (selectedPaymentMethod.type !== "CRYPTO" /* CRYPTO */ || !selectedPaymentMethod.method?.symbol) {
|
|
2550
2630
|
throw new Error("Unsupported payment method");
|
|
2551
2631
|
}
|
|
@@ -2560,14 +2640,14 @@ var useCryptoPayment = () => {
|
|
|
2560
2640
|
address: tokenAddress,
|
|
2561
2641
|
abi: erc20Abi2,
|
|
2562
2642
|
functionName: "allowance",
|
|
2563
|
-
args: [walletClient.account.address,
|
|
2643
|
+
args: [walletClient.account.address, spreePayConfig.crypto.oneInchAggregationRouter]
|
|
2564
2644
|
});
|
|
2565
2645
|
if (allowance <= 0n) {
|
|
2566
2646
|
const result = await walletClient.writeContract({
|
|
2567
2647
|
address: tokenAddress,
|
|
2568
2648
|
abi: erc20Abi2,
|
|
2569
2649
|
functionName: "approve",
|
|
2570
|
-
args: [
|
|
2650
|
+
args: [spreePayConfig.crypto.oneInchAggregationRouter, MAX_UINT256]
|
|
2571
2651
|
});
|
|
2572
2652
|
await waitForTransactionReceipt(config, {
|
|
2573
2653
|
hash: result,
|
|
@@ -2585,7 +2665,7 @@ var useCryptoPayment = () => {
|
|
|
2585
2665
|
token: TOKEN,
|
|
2586
2666
|
publicKey: walletClient.account.address,
|
|
2587
2667
|
slippageType: "fixed",
|
|
2588
|
-
slippageBps: 0.5 * 100
|
|
2668
|
+
slippageBps: Math.round(0.5 * 100)
|
|
2589
2669
|
}
|
|
2590
2670
|
});
|
|
2591
2671
|
const parsedTX = JSON.parse(paymentRes.data.encodedTx);
|
|
@@ -3132,8 +3212,8 @@ var CryptoWrapper = () => {
|
|
|
3132
3212
|
const config = useMemo9(() => {
|
|
3133
3213
|
if (!spreePayConfig) return null;
|
|
3134
3214
|
return getDefaultConfig({
|
|
3135
|
-
appName: spreePayConfig.rainbowAppName
|
|
3136
|
-
projectId: spreePayConfig.rainbowProjectId
|
|
3215
|
+
appName: spreePayConfig.rainbowAppName,
|
|
3216
|
+
projectId: spreePayConfig.rainbowProjectId,
|
|
3137
3217
|
chains: [base],
|
|
3138
3218
|
ssr: true
|
|
3139
3219
|
});
|
|
@@ -3145,9 +3225,10 @@ var CryptoWrapper = () => {
|
|
|
3145
3225
|
// src/components/CryptoTab/CryptoTab.tsx
|
|
3146
3226
|
import { jsx as jsx39, jsxs as jsxs23 } from "react/jsx-runtime";
|
|
3147
3227
|
var CryptoTab = () => {
|
|
3228
|
+
const { spreePayConfig } = useSpreePayConfig();
|
|
3148
3229
|
return /* @__PURE__ */ jsxs23("div", { children: [
|
|
3149
3230
|
/* @__PURE__ */ jsx39("div", { className: "border-b-1 border-black/7 px-5 py-5 md:px-7 md:py-5", children: /* @__PURE__ */ jsx39(CryptoWrapper, {}) }),
|
|
3150
|
-
/* @__PURE__ */ jsx39("div", { className: "px-5 py-5 md:px-7 md:py-6", children: /* @__PURE__ */ jsx39(PointsSwitch, { disabled: true }) })
|
|
3231
|
+
/* @__PURE__ */ jsx39("div", { className: "px-5 py-5 md:px-7 md:py-6", children: /* @__PURE__ */ jsx39(PointsSwitch, { disabled: true, message: spreePayConfig?.crypto.pointsInfoMessage }) })
|
|
3151
3232
|
] });
|
|
3152
3233
|
};
|
|
3153
3234
|
|
|
@@ -3199,7 +3280,7 @@ var TabButtons = (props) => {
|
|
|
3199
3280
|
/* @__PURE__ */ jsxs24(
|
|
3200
3281
|
TabButton,
|
|
3201
3282
|
{
|
|
3202
|
-
isDisabled: !spreePayConfig?.
|
|
3283
|
+
isDisabled: !spreePayConfig?.crypto.enabled,
|
|
3203
3284
|
onClick: handleChange("CRYPTO" /* CRYPTO */),
|
|
3204
3285
|
isActive: value === "CRYPTO" /* CRYPTO */,
|
|
3205
3286
|
children: [
|