@superlogic/spree-pay 0.1.39 → 0.1.42
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/README.md +155 -8
- package/build/index.cjs +690 -146
- package/build/index.css +26 -0
- package/build/index.d.cts +76 -2
- package/build/index.d.ts +76 -2
- package/build/index.js +669 -128
- package/package.json +1 -1
- package/src/styles/globals.css +6 -0
package/build/index.js
CHANGED
|
@@ -3,9 +3,6 @@ import { useCallback as useCallback9, useEffect as useEffect12, useMemo as useMe
|
|
|
3
3
|
import NiceModal9 from "@ebay/nice-modal-react";
|
|
4
4
|
import { SWRConfig } from "swr";
|
|
5
5
|
|
|
6
|
-
// package.json
|
|
7
|
-
var version = "0.1.39";
|
|
8
|
-
|
|
9
6
|
// src/context/SpreePayActionsContext.tsx
|
|
10
7
|
import { createContext, useCallback, useContext, useRef, useState } from "react";
|
|
11
8
|
|
|
@@ -31,8 +28,126 @@ var PaymentType = /* @__PURE__ */ ((PaymentType2) => {
|
|
|
31
28
|
return PaymentType2;
|
|
32
29
|
})(PaymentType || {});
|
|
33
30
|
|
|
31
|
+
// package.json
|
|
32
|
+
var version = "0.1.41";
|
|
33
|
+
|
|
34
|
+
// src/utils/logger.ts
|
|
35
|
+
var LogLevel = /* @__PURE__ */ ((LogLevel2) => {
|
|
36
|
+
LogLevel2[LogLevel2["DEBUG"] = 0] = "DEBUG";
|
|
37
|
+
LogLevel2[LogLevel2["INFO"] = 1] = "INFO";
|
|
38
|
+
LogLevel2[LogLevel2["WARN"] = 2] = "WARN";
|
|
39
|
+
LogLevel2[LogLevel2["ERROR"] = 3] = "ERROR";
|
|
40
|
+
LogLevel2[LogLevel2["NONE"] = 4] = "NONE";
|
|
41
|
+
return LogLevel2;
|
|
42
|
+
})(LogLevel || {});
|
|
43
|
+
var Logger = class _Logger {
|
|
44
|
+
config;
|
|
45
|
+
constructor(config2 = {}) {
|
|
46
|
+
this.config = {
|
|
47
|
+
minLevel: this.getDefaultLogLevel(config2.environment),
|
|
48
|
+
prefix: "[spree-pay]",
|
|
49
|
+
...config2
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Determines default log level based on environment
|
|
54
|
+
* - Production: Only ERROR and version info
|
|
55
|
+
* - Development/Staging: All logs
|
|
56
|
+
*/
|
|
57
|
+
getDefaultLogLevel(environment) {
|
|
58
|
+
if (typeof window === "undefined") return 1 /* INFO */;
|
|
59
|
+
if (environment) {
|
|
60
|
+
return environment === "prod" ? 3 /* ERROR */ : 0 /* DEBUG */;
|
|
61
|
+
}
|
|
62
|
+
return 3 /* ERROR */;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Set the environment and update log level accordingly
|
|
66
|
+
*/
|
|
67
|
+
setEnvironment(environment) {
|
|
68
|
+
this.config.environment = environment;
|
|
69
|
+
this.config.minLevel = this.getDefaultLogLevel(environment);
|
|
70
|
+
}
|
|
71
|
+
shouldLog(level) {
|
|
72
|
+
return level >= this.config.minLevel;
|
|
73
|
+
}
|
|
74
|
+
formatMessage(level, message, context) {
|
|
75
|
+
const levelName = LogLevel[level];
|
|
76
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
77
|
+
const contextStr = context && Object.keys(context).length > 0 ? ` ${JSON.stringify(context)}` : "";
|
|
78
|
+
return `${this.config.prefix} [${levelName}] ${timestamp} - ${message}${contextStr}`;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Log debug information (only in dev/stg)
|
|
82
|
+
*/
|
|
83
|
+
debug(message, context) {
|
|
84
|
+
if (!this.shouldLog(0 /* DEBUG */)) return;
|
|
85
|
+
console.log(this.formatMessage(0 /* DEBUG */, message, context));
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Log informational messages (only in dev/stg)
|
|
89
|
+
*/
|
|
90
|
+
info(message, context) {
|
|
91
|
+
if (!this.shouldLog(1 /* INFO */)) return;
|
|
92
|
+
console.log(this.formatMessage(1 /* INFO */, message, context));
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Log warnings (only in dev/stg)
|
|
96
|
+
*/
|
|
97
|
+
warn(message, context) {
|
|
98
|
+
if (!this.shouldLog(2 /* WARN */)) return;
|
|
99
|
+
console.warn(this.formatMessage(2 /* WARN */, message, context));
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Log errors (shows in all environments)
|
|
103
|
+
*/
|
|
104
|
+
error(message, error, context) {
|
|
105
|
+
if (!this.shouldLog(3 /* ERROR */)) return;
|
|
106
|
+
const errorContext = {
|
|
107
|
+
...context,
|
|
108
|
+
...error instanceof Error ? {
|
|
109
|
+
errorName: error.name,
|
|
110
|
+
errorMessage: error.message,
|
|
111
|
+
errorStack: error.stack
|
|
112
|
+
} : { error }
|
|
113
|
+
};
|
|
114
|
+
console.error(this.formatMessage(3 /* ERROR */, message, errorContext));
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Always logs the version, regardless of environment
|
|
118
|
+
*/
|
|
119
|
+
logVersion() {
|
|
120
|
+
console.log(`${this.config.prefix} v${version} - ${this.config.environment}`);
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Creates a child logger with additional context
|
|
124
|
+
* Useful for component-specific logging
|
|
125
|
+
*/
|
|
126
|
+
child(prefix) {
|
|
127
|
+
return new _Logger({
|
|
128
|
+
...this.config,
|
|
129
|
+
prefix: `${this.config.prefix}:${prefix}`
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Override log level (useful for testing or debugging)
|
|
134
|
+
*/
|
|
135
|
+
setLogLevel(level) {
|
|
136
|
+
this.config.minLevel = level;
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
var logger = new Logger();
|
|
140
|
+
var configureLogger = (config2) => {
|
|
141
|
+
if (config2.environment) {
|
|
142
|
+
logger.setEnvironment(config2.environment);
|
|
143
|
+
}
|
|
144
|
+
const { environment, ...restConfig } = config2;
|
|
145
|
+
Object.assign(logger["config"], restConfig);
|
|
146
|
+
};
|
|
147
|
+
|
|
34
148
|
// src/context/SpreePayActionsContext.tsx
|
|
35
149
|
import { jsx } from "react/jsx-runtime";
|
|
150
|
+
var processLogger = logger.child("process");
|
|
36
151
|
var SpreePayActionsContext = createContext(void 0);
|
|
37
152
|
var SpreePayProvider = ({ children, env }) => {
|
|
38
153
|
const processRef = useRef(null);
|
|
@@ -44,18 +159,43 @@ var SpreePayProvider = ({ children, env }) => {
|
|
|
44
159
|
const register = useCallback((fn) => {
|
|
45
160
|
processRef.current = fn;
|
|
46
161
|
}, []);
|
|
47
|
-
const process = useCallback(
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
162
|
+
const process = useCallback(
|
|
163
|
+
async (data) => {
|
|
164
|
+
if (!processRef.current) {
|
|
165
|
+
const error = new Error("SpreePay process function not registered");
|
|
166
|
+
processLogger.error("Process function not registered", error);
|
|
167
|
+
throw error;
|
|
168
|
+
}
|
|
169
|
+
processLogger.info("Payment process started", {
|
|
170
|
+
hash: data.hash,
|
|
171
|
+
capture: data.capture,
|
|
172
|
+
hasMetadata: Boolean(data.metadata),
|
|
173
|
+
paymentType: selectedPaymentMethod.type
|
|
174
|
+
});
|
|
175
|
+
setInternalProcessing(true);
|
|
176
|
+
try {
|
|
177
|
+
const result = await processRef.current(data);
|
|
178
|
+
processLogger.info("Payment process completed", {
|
|
179
|
+
status: result.status,
|
|
180
|
+
paymentId: result.paymentId,
|
|
181
|
+
paymentType: result.paymentType,
|
|
182
|
+
txHash: result.txHash
|
|
183
|
+
});
|
|
184
|
+
return result;
|
|
185
|
+
} catch (e) {
|
|
186
|
+
processLogger.error("Payment process failed", e instanceof Error ? e : void 0, {
|
|
187
|
+
hash: data.hash,
|
|
188
|
+
paymentType: selectedPaymentMethod.type,
|
|
189
|
+
errorMessage: e instanceof Error ? e.message : String(e)
|
|
190
|
+
});
|
|
191
|
+
if (e instanceof Error) throw e;
|
|
192
|
+
throw new PaymentError("Payment failed", "FAILED" /* FAILED */, e);
|
|
193
|
+
} finally {
|
|
194
|
+
setInternalProcessing(false);
|
|
195
|
+
}
|
|
196
|
+
},
|
|
197
|
+
[selectedPaymentMethod.type]
|
|
198
|
+
);
|
|
59
199
|
const value = {
|
|
60
200
|
// Set default to true for web3 points to backward compatibility
|
|
61
201
|
env: { ...env, useWeb3Points: env.useWeb3Points ?? true },
|
|
@@ -199,7 +339,10 @@ var StaticConfigProvider = ({ children, props }) => {
|
|
|
199
339
|
const envConfig = config[env.environment];
|
|
200
340
|
const isKnownTenant = env.tenantId in envConfig;
|
|
201
341
|
if (!isKnownTenant) {
|
|
202
|
-
|
|
342
|
+
logger.warn(`Unknown tenantId "${env.tenantId}", falling back to "moca"`, {
|
|
343
|
+
tenantId: env.tenantId,
|
|
344
|
+
environment: env.environment
|
|
345
|
+
});
|
|
203
346
|
}
|
|
204
347
|
const appKey = isKnownTenant ? env.tenantId : "moca";
|
|
205
348
|
return envConfig[appKey];
|
|
@@ -548,11 +691,11 @@ var CheckoutButton = ({ isLoggedIn }) => {
|
|
|
548
691
|
),
|
|
549
692
|
/* @__PURE__ */ jsxs5("a", { href: "https://www.spree.finance/", className: "flex items-center justify-center gap-2 hover:underline", children: [
|
|
550
693
|
/* @__PURE__ */ jsx9("p", { children: "Powered by" }),
|
|
551
|
-
/* @__PURE__ */ jsx9("svg", {
|
|
694
|
+
/* @__PURE__ */ jsx9("svg", { xmlns: "http://www.w3.org/2000/svg", fill: "none", className: "h-[30px]", viewBox: "0 0 66 30", children: /* @__PURE__ */ jsx9(
|
|
552
695
|
"path",
|
|
553
696
|
{
|
|
554
697
|
fill: "currentColor",
|
|
555
|
-
d: "M57.79 25.
|
|
698
|
+
d: "M57.79 25.48a5 5 0 0 1-1.55-.25l.55-1.86q.51.15.92.15c.41 0 .51-.1.72-.26q.32-.24.53-.81l.2-.55-3.65-10.3h2.52l2.32 7.62h.1l2.34-7.62h2.53l-4.04 11.31q-.28.81-.75 1.38t-1.14.88-1.6.3Zm-8.84-3.58a4 4 0 0 1-1.73-.35q-.75-.34-1.2-1.02a3 3 0 0 1-.44-1.67 2.4 2.4 0 0 1 1.18-2.3q.53-.35 1.22-.5.69-.19 1.42-.27l1.44-.16q.56-.08.8-.24.27-.15.26-.5v-.04q0-.75-.44-1.15-.45-.4-1.27-.4-.87 0-1.38.37-.51.39-.69.9l-2.22-.31a3.5 3.5 0 0 1 2.35-2.47 6.3 6.3 0 0 1 3.38-.14q.72.16 1.32.56.6.38.96 1.06.37.66.37 1.67v6.75h-2.29v-1.38h-.08a3 3 0 0 1-1.59 1.37q-.58.21-1.37.22m.62-1.75q.72 0 1.24-.28.53-.3.8-.77.3-.46.3-1.03V16.9q-.11.09-.38.17a18 18 0 0 1-1.8.32q-.54.07-.96.23-.42.17-.66.46t-.24.75q0 .66.48 1t1.22.33ZM34.43 21.7V8.23h5.05q1.55 0 2.6.58 1.05.57 1.6 1.59.54 1 .54 2.28 0 1.3-.55 2.3a4 4 0 0 1-1.6 1.59q-1.07.57-2.63.57H36.1v-2h3.01q.9 0 1.49-.32.57-.32.85-.87.3-.55.29-1.27 0-.71-.29-1.26a2 2 0 0 0-.86-.84 3 3 0 0 0-1.49-.31h-2.23v11.41h-2.44ZM14.54.46a14.54 14.54 0 1 1 0 29.08 14.54 14.54 0 0 1 0-29.08M5.59 18.12l-.84 3.35h.83l.84-3.35zm1.66 0-.83 3.35h1.66l.84-3.35zm3.35-9.58c-1.03 0-2.08.84-2.34 1.87l-1.1 4.4c-.26 1.03.37 1.87 1.4 1.87h9.64l-.34 1.44h-8.1l-.85 3.35h9.6c1.04 0 2.1-.85 2.35-1.89l1.05-4.4c.25-1.03-.38-1.85-1.4-1.85h-9.63l.36-1.44h8.13l.84-3.35zm10.44 0-.84 3.35h1.67l.83-3.35zm2.5 0-.84 3.35h.83l.84-3.35z"
|
|
556
699
|
}
|
|
557
700
|
) })
|
|
558
701
|
] })
|
|
@@ -804,49 +947,181 @@ var registerApi = (config2) => {
|
|
|
804
947
|
};
|
|
805
948
|
|
|
806
949
|
// src/services/slapi.ts
|
|
950
|
+
var slapiLogger = logger.child("slapi");
|
|
807
951
|
var SlapiPaymentService = {
|
|
808
|
-
createPayment: ({ capture = false, ...rest }) => {
|
|
809
|
-
|
|
952
|
+
createPayment: async ({ capture = false, ...rest }) => {
|
|
953
|
+
slapiLogger.debug("Creating payment", {
|
|
954
|
+
type: rest.type,
|
|
955
|
+
hash: rest.hash,
|
|
956
|
+
capture
|
|
957
|
+
});
|
|
958
|
+
try {
|
|
959
|
+
const data = await slapiApi.post("/v1/payments", { ...rest, capture });
|
|
960
|
+
slapiLogger.info("Payment created successfully", {
|
|
961
|
+
paymentId: data.id,
|
|
962
|
+
status: data.status,
|
|
963
|
+
txId: data.txId
|
|
964
|
+
});
|
|
965
|
+
return { data };
|
|
966
|
+
} catch (error) {
|
|
967
|
+
slapiLogger.error("Failed to create payment", error, {
|
|
968
|
+
type: rest.type,
|
|
969
|
+
hash: rest.hash
|
|
970
|
+
});
|
|
971
|
+
throw error;
|
|
972
|
+
}
|
|
810
973
|
},
|
|
811
|
-
baseVerify: ({ id, txHash }) => {
|
|
812
|
-
|
|
974
|
+
baseVerify: async ({ id, txHash }) => {
|
|
975
|
+
slapiLogger.debug("Verifying base transaction", { id, txHash });
|
|
976
|
+
try {
|
|
977
|
+
const result = await slapiApi.post(`/v1/base-transactions/transactions/${id}/verify`, {
|
|
978
|
+
txHash
|
|
979
|
+
});
|
|
980
|
+
slapiLogger.info("Base transaction verified", {
|
|
981
|
+
id,
|
|
982
|
+
txHash,
|
|
983
|
+
verified: result.verified
|
|
984
|
+
});
|
|
985
|
+
return result;
|
|
986
|
+
} catch (error) {
|
|
987
|
+
slapiLogger.error("Base transaction verification failed", error, {
|
|
988
|
+
id,
|
|
989
|
+
txHash
|
|
990
|
+
});
|
|
991
|
+
throw error;
|
|
992
|
+
}
|
|
813
993
|
},
|
|
814
|
-
addCard: ({ source, hash }) => {
|
|
815
|
-
|
|
994
|
+
addCard: async ({ source, hash }) => {
|
|
995
|
+
slapiLogger.debug("Adding card", { hash, sourcePrefix: source.substring(0, 10) });
|
|
996
|
+
try {
|
|
997
|
+
const data = await slapiApi.post("/v1/payments/cards", { hash, source });
|
|
998
|
+
slapiLogger.info("Card added successfully", { cardId: data.id, hash });
|
|
999
|
+
return { data };
|
|
1000
|
+
} catch (error) {
|
|
1001
|
+
slapiLogger.error("Failed to add card", error, { hash });
|
|
1002
|
+
throw error;
|
|
1003
|
+
}
|
|
816
1004
|
},
|
|
817
|
-
validate3DS: ({ paymentId }) => {
|
|
818
|
-
|
|
1005
|
+
validate3DS: async ({ paymentId }) => {
|
|
1006
|
+
slapiLogger.debug("Validating 3DS", { paymentId });
|
|
1007
|
+
try {
|
|
1008
|
+
const data = await slapiApi.post("/v1/payments/validate", {
|
|
1009
|
+
paymentId,
|
|
1010
|
+
type: "CREDIT_CARD" /* CREDIT_CARD */
|
|
1011
|
+
});
|
|
1012
|
+
slapiLogger.info("3DS validated successfully", {
|
|
1013
|
+
paymentId,
|
|
1014
|
+
status: data.status
|
|
1015
|
+
});
|
|
1016
|
+
return { data };
|
|
1017
|
+
} catch (error) {
|
|
1018
|
+
slapiLogger.error("3DS validation failed", error, { paymentId });
|
|
1019
|
+
throw error;
|
|
1020
|
+
}
|
|
819
1021
|
},
|
|
820
|
-
validateCDC: ({ paymentId }) => {
|
|
821
|
-
|
|
1022
|
+
validateCDC: async ({ paymentId }) => {
|
|
1023
|
+
slapiLogger.debug("Validating CDC payment", { paymentId });
|
|
1024
|
+
try {
|
|
1025
|
+
const data = await slapiApi.post("/v1/payments/validate", {
|
|
1026
|
+
paymentId,
|
|
1027
|
+
type: "CDC" /* CDC */
|
|
1028
|
+
});
|
|
1029
|
+
slapiLogger.info("CDC payment validated successfully", {
|
|
1030
|
+
paymentId,
|
|
1031
|
+
status: data.status
|
|
1032
|
+
});
|
|
1033
|
+
return { data };
|
|
1034
|
+
} catch (error) {
|
|
1035
|
+
slapiLogger.error("CDC payment validation failed", error, {
|
|
1036
|
+
paymentId
|
|
1037
|
+
});
|
|
1038
|
+
throw error;
|
|
1039
|
+
}
|
|
822
1040
|
},
|
|
823
|
-
validatePoints: ({ paymentId, txHash }) => {
|
|
824
|
-
|
|
1041
|
+
validatePoints: async ({ paymentId, txHash }) => {
|
|
1042
|
+
slapiLogger.debug("Validating points payment", { paymentId, txHash });
|
|
1043
|
+
try {
|
|
1044
|
+
const data = await slapiApi.post("/v1/payments/validate", {
|
|
1045
|
+
txHash,
|
|
1046
|
+
paymentId,
|
|
1047
|
+
type: "POINTS" /* POINTS */
|
|
1048
|
+
});
|
|
1049
|
+
slapiLogger.info("Points payment validated successfully", {
|
|
1050
|
+
paymentId,
|
|
1051
|
+
status: data.status,
|
|
1052
|
+
txHash
|
|
1053
|
+
});
|
|
1054
|
+
return { data };
|
|
1055
|
+
} catch (error) {
|
|
1056
|
+
slapiLogger.error("Points payment validation failed", error, {
|
|
1057
|
+
paymentId,
|
|
1058
|
+
txHash
|
|
1059
|
+
});
|
|
1060
|
+
throw error;
|
|
1061
|
+
}
|
|
825
1062
|
},
|
|
826
|
-
getStatus: (paymentId) => {
|
|
827
|
-
|
|
1063
|
+
getStatus: async (paymentId) => {
|
|
1064
|
+
slapiLogger.debug("Getting payment status", { paymentId });
|
|
1065
|
+
try {
|
|
1066
|
+
const result = await slapiApi.get(`/v1/payments/${paymentId}/status`);
|
|
1067
|
+
slapiLogger.debug("Payment status retrieved", {
|
|
1068
|
+
paymentId,
|
|
1069
|
+
status: result.detail.status
|
|
1070
|
+
});
|
|
1071
|
+
return result;
|
|
1072
|
+
} catch (error) {
|
|
1073
|
+
slapiLogger.error("Failed to get payment status", error, {
|
|
1074
|
+
paymentId
|
|
1075
|
+
});
|
|
1076
|
+
throw error;
|
|
1077
|
+
}
|
|
828
1078
|
}
|
|
829
1079
|
};
|
|
830
1080
|
|
|
831
1081
|
// src/hooks/payments/useCardPayment.ts
|
|
1082
|
+
var cardPaymentLogger = logger.child("card-payment");
|
|
832
1083
|
var useCardPayment = () => {
|
|
833
1084
|
const { selectedPaymentMethod } = useSpreePaymentMethod();
|
|
834
1085
|
const { env } = useSpreePayEnv();
|
|
835
1086
|
const { appProps } = useStaticConfig();
|
|
836
1087
|
const cardPayment = async (params) => {
|
|
837
1088
|
if (selectedPaymentMethod.type !== "CREDIT_CARD" /* CREDIT_CARD */ || !selectedPaymentMethod.method) {
|
|
838
|
-
|
|
1089
|
+
const error = new Error("Unsupported payment method");
|
|
1090
|
+
cardPaymentLogger.error("Invalid payment method for card payment", error, {
|
|
1091
|
+
actualType: selectedPaymentMethod.type,
|
|
1092
|
+
hasMethod: Boolean(selectedPaymentMethod.method)
|
|
1093
|
+
});
|
|
1094
|
+
throw error;
|
|
839
1095
|
}
|
|
840
1096
|
const { hash, capture, metadata } = params;
|
|
1097
|
+
cardPaymentLogger.info("Starting card payment", {
|
|
1098
|
+
hash,
|
|
1099
|
+
capture,
|
|
1100
|
+
hasMetadata: Boolean(metadata)
|
|
1101
|
+
});
|
|
841
1102
|
const card = selectedPaymentMethod.method;
|
|
842
1103
|
let cardId;
|
|
843
1104
|
if ("token" in card) {
|
|
1105
|
+
cardPaymentLogger.debug("Adding new card from token", {
|
|
1106
|
+
lastFour: card.lastFourNumbers,
|
|
1107
|
+
schema: card.schema
|
|
1108
|
+
});
|
|
844
1109
|
const { data: cardResData } = await SlapiPaymentService.addCard({ hash, source: card.token });
|
|
845
1110
|
cardId = cardResData.id;
|
|
1111
|
+
cardPaymentLogger.info("New card added successfully", { cardId });
|
|
846
1112
|
} else {
|
|
847
1113
|
cardId = card.id;
|
|
1114
|
+
cardPaymentLogger.debug("Using existing card", {
|
|
1115
|
+
cardId,
|
|
1116
|
+
lastFour: card.lastFourNumbers
|
|
1117
|
+
});
|
|
848
1118
|
}
|
|
849
1119
|
const transactionFee = getTransactionFee(appProps.amount, appProps.transactionFeePercentage);
|
|
1120
|
+
cardPaymentLogger.debug("Creating payment", {
|
|
1121
|
+
transactionFee,
|
|
1122
|
+
amount: appProps.amount,
|
|
1123
|
+
capture
|
|
1124
|
+
});
|
|
850
1125
|
const { data: paymentResData } = await SlapiPaymentService.createPayment({
|
|
851
1126
|
hash,
|
|
852
1127
|
capture,
|
|
@@ -859,13 +1134,38 @@ var useCardPayment = () => {
|
|
|
859
1134
|
}
|
|
860
1135
|
});
|
|
861
1136
|
let { status } = paymentResData;
|
|
1137
|
+
cardPaymentLogger.info("Payment created", {
|
|
1138
|
+
paymentId: paymentResData.id,
|
|
1139
|
+
status,
|
|
1140
|
+
has3DS: Boolean(paymentResData.redirectUrl)
|
|
1141
|
+
});
|
|
862
1142
|
if (paymentResData.redirectUrl) {
|
|
1143
|
+
cardPaymentLogger.debug("Starting 3DS flow", {
|
|
1144
|
+
paymentId: paymentResData.id
|
|
1145
|
+
});
|
|
863
1146
|
const paymentIntent = await NiceModal2.show(Iframe3ds, { url: paymentResData.redirectUrl });
|
|
864
1147
|
if (paymentIntent) {
|
|
1148
|
+
cardPaymentLogger.debug("3DS completed, validating", {
|
|
1149
|
+
paymentId: paymentResData.id,
|
|
1150
|
+
paymentIntent
|
|
1151
|
+
});
|
|
865
1152
|
const { data: validateData } = await SlapiPaymentService.validate3DS({ paymentId: paymentResData.id });
|
|
866
1153
|
({ status } = validateData);
|
|
1154
|
+
cardPaymentLogger.info("3DS validation completed", {
|
|
1155
|
+
paymentId: paymentResData.id,
|
|
1156
|
+
status
|
|
1157
|
+
});
|
|
1158
|
+
} else {
|
|
1159
|
+
cardPaymentLogger.warn("3DS flow cancelled by user", {
|
|
1160
|
+
paymentId: paymentResData.id
|
|
1161
|
+
});
|
|
867
1162
|
}
|
|
868
1163
|
}
|
|
1164
|
+
cardPaymentLogger.info("Card payment completed", {
|
|
1165
|
+
paymentId: paymentResData.id,
|
|
1166
|
+
status,
|
|
1167
|
+
txId: paymentResData.txId
|
|
1168
|
+
});
|
|
869
1169
|
return {
|
|
870
1170
|
status,
|
|
871
1171
|
paymentType: "CREDIT_CARD" /* CREDIT_CARD */,
|
|
@@ -880,6 +1180,7 @@ var useCardPayment = () => {
|
|
|
880
1180
|
// src/services/AirWalletService.ts
|
|
881
1181
|
import { AirService, BUILD_ENV } from "@mocanetwork/airkit";
|
|
882
1182
|
import { createWalletClient, custom, encodeFunctionData, erc20Abi, parseUnits } from "viem";
|
|
1183
|
+
var airWalletLogger = logger.child("airwallet");
|
|
883
1184
|
var singletonState = null;
|
|
884
1185
|
var initPromise = null;
|
|
885
1186
|
var cachedKey = null;
|
|
@@ -931,16 +1232,19 @@ function peekAirWallet() {
|
|
|
931
1232
|
async function handleSendErc20(params) {
|
|
932
1233
|
const state = singletonState;
|
|
933
1234
|
if (!state?.walletClient) {
|
|
934
|
-
|
|
935
|
-
|
|
1235
|
+
const error = new Error("Air wallet is not initialized");
|
|
1236
|
+
airWalletLogger.error("Wallet not initialized", error);
|
|
1237
|
+
throw error;
|
|
936
1238
|
}
|
|
937
1239
|
if (!params?.recipient) {
|
|
938
|
-
|
|
939
|
-
|
|
1240
|
+
const error = new Error("Recipient address is not set");
|
|
1241
|
+
airWalletLogger.error("Recipient address missing", error, { params });
|
|
1242
|
+
throw error;
|
|
940
1243
|
}
|
|
941
1244
|
if (!params?.token?.address || !params?.token?.decimals) {
|
|
942
|
-
|
|
943
|
-
|
|
1245
|
+
const error = new Error("Token address or decimals not set");
|
|
1246
|
+
airWalletLogger.error("Token configuration invalid", error, { token: params?.token });
|
|
1247
|
+
throw error;
|
|
944
1248
|
}
|
|
945
1249
|
try {
|
|
946
1250
|
const { walletClient } = state;
|
|
@@ -961,9 +1265,17 @@ async function handleSendErc20(params) {
|
|
|
961
1265
|
return { txHash: hash };
|
|
962
1266
|
} catch (error) {
|
|
963
1267
|
if (typeof error === "object" && error !== null && "shortMessage" in error) {
|
|
964
|
-
|
|
1268
|
+
const { shortMessage } = error;
|
|
1269
|
+
airWalletLogger.error("ERC20 transfer failed", error instanceof Error ? error : void 0, {
|
|
1270
|
+
shortMessage,
|
|
1271
|
+
recipient: params.recipient,
|
|
1272
|
+
amount: params.amount
|
|
1273
|
+
});
|
|
965
1274
|
} else {
|
|
966
|
-
|
|
1275
|
+
airWalletLogger.error("Insufficient wallet balance for transaction", error instanceof Error ? error : void 0, {
|
|
1276
|
+
recipient: params.recipient,
|
|
1277
|
+
amount: params.amount
|
|
1278
|
+
});
|
|
967
1279
|
}
|
|
968
1280
|
}
|
|
969
1281
|
}
|
|
@@ -1016,14 +1328,29 @@ async function longPollCardStatus(paymentId) {
|
|
|
1016
1328
|
}
|
|
1017
1329
|
|
|
1018
1330
|
// src/hooks/payments/usePointsPayment.ts
|
|
1331
|
+
var pointsPaymentLogger = logger.child("points-payment");
|
|
1019
1332
|
var usePointsPayment = (mode = "web2") => {
|
|
1020
1333
|
const { selectedPaymentMethod } = useSpreePaymentMethod();
|
|
1021
1334
|
const { spreePayConfig } = useSpreePayConfig();
|
|
1022
1335
|
const pointsPayment = async (params) => {
|
|
1023
1336
|
if (selectedPaymentMethod.type !== "CREDIT_CARD" /* CREDIT_CARD */) {
|
|
1024
|
-
|
|
1337
|
+
const error = new Error("Unsupported payment method");
|
|
1338
|
+
pointsPaymentLogger.error("Invalid payment method for points payment", error, {
|
|
1339
|
+
actualType: selectedPaymentMethod.type
|
|
1340
|
+
});
|
|
1341
|
+
throw error;
|
|
1025
1342
|
}
|
|
1026
1343
|
const { hash, capture, metadata } = params;
|
|
1344
|
+
pointsPaymentLogger.info("Starting points payment", {
|
|
1345
|
+
hash,
|
|
1346
|
+
capture,
|
|
1347
|
+
mode,
|
|
1348
|
+
points: params.points
|
|
1349
|
+
});
|
|
1350
|
+
pointsPaymentLogger.debug("Creating points payment", {
|
|
1351
|
+
mode,
|
|
1352
|
+
captureOverride: mode === "web2" ? true : capture
|
|
1353
|
+
});
|
|
1027
1354
|
const { data: paymentResData } = await SlapiPaymentService.createPayment({
|
|
1028
1355
|
hash,
|
|
1029
1356
|
// capture should be always true for web2 points payments
|
|
@@ -1031,24 +1358,57 @@ var usePointsPayment = (mode = "web2") => {
|
|
|
1031
1358
|
metadata,
|
|
1032
1359
|
type: "POINTS" /* POINTS */
|
|
1033
1360
|
});
|
|
1361
|
+
pointsPaymentLogger.info("Points payment created", {
|
|
1362
|
+
paymentId: paymentResData.id,
|
|
1363
|
+
txId: paymentResData.txId,
|
|
1364
|
+
mode
|
|
1365
|
+
});
|
|
1034
1366
|
if (mode === "web3") {
|
|
1367
|
+
pointsPaymentLogger.debug("Processing web3 points payment");
|
|
1035
1368
|
const wallet = peekAirWallet();
|
|
1036
1369
|
if (!wallet || !spreePayConfig?.pointsChain) {
|
|
1037
|
-
|
|
1370
|
+
const error = new Error("AirWallet not found");
|
|
1371
|
+
pointsPaymentLogger.error("AirWallet not available for web3 points", error, {
|
|
1372
|
+
hasWallet: Boolean(wallet),
|
|
1373
|
+
hasPointsChain: Boolean(spreePayConfig?.pointsChain)
|
|
1374
|
+
});
|
|
1375
|
+
throw error;
|
|
1038
1376
|
}
|
|
1377
|
+
pointsPaymentLogger.debug("Sending ERC20 points transfer", {
|
|
1378
|
+
amount: params.points,
|
|
1379
|
+
recipient: spreePayConfig.pointsChain.recipientAddress
|
|
1380
|
+
});
|
|
1039
1381
|
const transaction = await handleSendErc20({
|
|
1040
1382
|
amount: params.points,
|
|
1041
1383
|
token: spreePayConfig.pointsChain.pointsCoin,
|
|
1042
1384
|
recipient: spreePayConfig.pointsChain.recipientAddress
|
|
1043
1385
|
});
|
|
1044
1386
|
if (!transaction) {
|
|
1045
|
-
|
|
1387
|
+
const error = new Error("Points transaction failed");
|
|
1388
|
+
pointsPaymentLogger.error("Points ERC20 transfer failed", error);
|
|
1389
|
+
throw error;
|
|
1046
1390
|
}
|
|
1391
|
+
pointsPaymentLogger.info("Points transfer completed", {
|
|
1392
|
+
txHash: transaction.txHash,
|
|
1393
|
+
amount: params.points
|
|
1394
|
+
});
|
|
1395
|
+
pointsPaymentLogger.debug("Validating points transaction", {
|
|
1396
|
+
paymentId: paymentResData.id,
|
|
1397
|
+
txHash: transaction.txHash
|
|
1398
|
+
});
|
|
1047
1399
|
await SlapiPaymentService.validatePoints({
|
|
1048
1400
|
paymentId: paymentResData.id,
|
|
1049
1401
|
txHash: transaction.txHash
|
|
1050
1402
|
});
|
|
1403
|
+
pointsPaymentLogger.debug("Polling for points payment status", {
|
|
1404
|
+
paymentId: paymentResData.id
|
|
1405
|
+
});
|
|
1051
1406
|
const pointsStatus2 = await longPollPoints(paymentResData.id);
|
|
1407
|
+
pointsPaymentLogger.info("Web3 points payment completed", {
|
|
1408
|
+
paymentId: paymentResData.id,
|
|
1409
|
+
status: pointsStatus2,
|
|
1410
|
+
txHash: transaction.txHash
|
|
1411
|
+
});
|
|
1052
1412
|
return {
|
|
1053
1413
|
status: pointsStatus2,
|
|
1054
1414
|
txId: paymentResData.txId,
|
|
@@ -1057,7 +1417,14 @@ var usePointsPayment = (mode = "web2") => {
|
|
|
1057
1417
|
paymentType: "POINTS" /* POINTS */
|
|
1058
1418
|
};
|
|
1059
1419
|
}
|
|
1420
|
+
pointsPaymentLogger.debug("Polling for web2 points payment status", {
|
|
1421
|
+
paymentId: paymentResData.id
|
|
1422
|
+
});
|
|
1060
1423
|
const pointsStatus = await longPollPoints(paymentResData.id);
|
|
1424
|
+
pointsPaymentLogger.info("Web2 points payment completed", {
|
|
1425
|
+
paymentId: paymentResData.id,
|
|
1426
|
+
status: pointsStatus
|
|
1427
|
+
});
|
|
1061
1428
|
return {
|
|
1062
1429
|
status: pointsStatus,
|
|
1063
1430
|
txId: paymentResData.txId,
|
|
@@ -1071,6 +1438,7 @@ var usePointsPayment = (mode = "web2") => {
|
|
|
1071
1438
|
|
|
1072
1439
|
// src/hooks/payments/useSplitCardPayments.ts
|
|
1073
1440
|
import NiceModal4 from "@ebay/nice-modal-react";
|
|
1441
|
+
var splitPaymentLogger = logger.child("split-card-payment");
|
|
1074
1442
|
var useSplitCardPayments = (mode = "web2") => {
|
|
1075
1443
|
const { selectedPaymentMethod } = useSpreePaymentMethod();
|
|
1076
1444
|
const { env } = useSpreePayEnv();
|
|
@@ -1081,16 +1449,30 @@ var useSplitCardPayments = (mode = "web2") => {
|
|
|
1081
1449
|
throw new Error("Unsupported payment method");
|
|
1082
1450
|
}
|
|
1083
1451
|
const { hash, capture, metadata, points } = params;
|
|
1452
|
+
splitPaymentLogger.info("Starting split card+points payment", { hash, mode, points, capture });
|
|
1084
1453
|
const card = selectedPaymentMethod.method;
|
|
1085
1454
|
let cardId;
|
|
1086
1455
|
if ("token" in card) {
|
|
1456
|
+
splitPaymentLogger.debug("Adding new card from token", {
|
|
1457
|
+
lastFour: card.lastFourNumbers,
|
|
1458
|
+
schema: card.schema
|
|
1459
|
+
});
|
|
1087
1460
|
const { data: cardResData } = await SlapiPaymentService.addCard({ hash, source: card.token });
|
|
1088
1461
|
cardId = cardResData.id;
|
|
1462
|
+
splitPaymentLogger.debug("Card added successfully", { cardId });
|
|
1089
1463
|
} else {
|
|
1090
1464
|
cardId = card.id;
|
|
1465
|
+
splitPaymentLogger.debug("Using existing card", { cardId });
|
|
1091
1466
|
}
|
|
1092
1467
|
const usdAmount = getSplitAmount(appProps.amount ?? 0, points, spreePayConfig?.pointsConversionRatio);
|
|
1093
1468
|
const transactionFee = getTransactionFee(usdAmount, appProps.transactionFeePercentage);
|
|
1469
|
+
splitPaymentLogger.debug("Calculated split amounts", {
|
|
1470
|
+
totalAmount: appProps.amount,
|
|
1471
|
+
points,
|
|
1472
|
+
usdAmount,
|
|
1473
|
+
transactionFee,
|
|
1474
|
+
conversionRatio: spreePayConfig?.pointsConversionRatio
|
|
1475
|
+
});
|
|
1094
1476
|
const { data: paymentResData } = await SlapiPaymentService.createPayment({
|
|
1095
1477
|
hash,
|
|
1096
1478
|
capture,
|
|
@@ -1105,31 +1487,64 @@ var useSplitCardPayments = (mode = "web2") => {
|
|
|
1105
1487
|
amount: points
|
|
1106
1488
|
}
|
|
1107
1489
|
});
|
|
1490
|
+
splitPaymentLogger.info("Split payment created", {
|
|
1491
|
+
paymentId: paymentResData.id,
|
|
1492
|
+
status: paymentResData.status,
|
|
1493
|
+
has3DS: Boolean(paymentResData.redirectUrl)
|
|
1494
|
+
});
|
|
1108
1495
|
if (paymentResData.redirectUrl) {
|
|
1496
|
+
splitPaymentLogger.debug("Starting 3DS flow for card portion", { paymentId: paymentResData.id });
|
|
1109
1497
|
const paymentIntent = await NiceModal4.show(Iframe3ds, { url: paymentResData.redirectUrl });
|
|
1110
1498
|
if (paymentIntent) {
|
|
1499
|
+
splitPaymentLogger.debug("3DS completed, validating", { paymentId: paymentResData.id });
|
|
1111
1500
|
await SlapiPaymentService.validate3DS({ paymentId: paymentResData.id });
|
|
1501
|
+
} else {
|
|
1502
|
+
splitPaymentLogger.warn("3DS flow canceled or failed", { paymentId: paymentResData.id });
|
|
1112
1503
|
}
|
|
1113
1504
|
}
|
|
1505
|
+
splitPaymentLogger.debug("Polling card payment status", { paymentId: paymentResData.id });
|
|
1114
1506
|
const cardStatus = await longPollCardStatus(paymentResData.id);
|
|
1507
|
+
splitPaymentLogger.info("Card portion completed", { paymentId: paymentResData.id, cardStatus });
|
|
1115
1508
|
if (mode === "web3") {
|
|
1509
|
+
splitPaymentLogger.info("Processing web3 points transfer", { points });
|
|
1116
1510
|
const wallet = peekAirWallet();
|
|
1117
1511
|
if (!wallet || !spreePayConfig?.pointsChain) {
|
|
1512
|
+
splitPaymentLogger.error("AirWallet not initialized for web3 points transfer", void 0, {
|
|
1513
|
+
hasWallet: Boolean(wallet),
|
|
1514
|
+
hasPointsChain: Boolean(spreePayConfig?.pointsChain)
|
|
1515
|
+
});
|
|
1118
1516
|
throw new Error("AirWallet not found");
|
|
1119
1517
|
}
|
|
1518
|
+
splitPaymentLogger.debug("Sending ERC20 points transfer", {
|
|
1519
|
+
amount: params.points,
|
|
1520
|
+
token: spreePayConfig.pointsChain.pointsCoin,
|
|
1521
|
+
recipient: spreePayConfig.pointsChain.recipientAddress
|
|
1522
|
+
});
|
|
1120
1523
|
const transaction = await handleSendErc20({
|
|
1121
1524
|
amount: params.points,
|
|
1122
1525
|
token: spreePayConfig.pointsChain.pointsCoin,
|
|
1123
1526
|
recipient: spreePayConfig.pointsChain.recipientAddress
|
|
1124
1527
|
});
|
|
1125
1528
|
if (!transaction) {
|
|
1529
|
+
splitPaymentLogger.error("Points transaction failed", void 0, { points });
|
|
1126
1530
|
throw new Error("Points transaction failed");
|
|
1127
1531
|
}
|
|
1532
|
+
splitPaymentLogger.info("Points transfer completed", { txHash: transaction.txHash });
|
|
1533
|
+
splitPaymentLogger.debug("Validating points transaction", {
|
|
1534
|
+
paymentId: paymentResData.id,
|
|
1535
|
+
txHash: transaction.txHash
|
|
1536
|
+
});
|
|
1128
1537
|
await SlapiPaymentService.validatePoints({
|
|
1129
1538
|
paymentId: paymentResData.id,
|
|
1130
1539
|
txHash: transaction.txHash
|
|
1131
1540
|
});
|
|
1541
|
+
splitPaymentLogger.debug("Polling points payment status", { paymentId: paymentResData.id });
|
|
1132
1542
|
const pointsStatus = await longPollPoints(paymentResData.id);
|
|
1543
|
+
splitPaymentLogger.info("Web3 split payment completed", {
|
|
1544
|
+
paymentId: paymentResData.id,
|
|
1545
|
+
status: pointsStatus,
|
|
1546
|
+
txHash: transaction.txHash
|
|
1547
|
+
});
|
|
1133
1548
|
return {
|
|
1134
1549
|
paymentType: "SPLIT" /* CREDIT_CARD_SPLIT */,
|
|
1135
1550
|
status: pointsStatus,
|
|
@@ -1138,6 +1553,10 @@ var useSplitCardPayments = (mode = "web2") => {
|
|
|
1138
1553
|
txHash: transaction.txHash
|
|
1139
1554
|
};
|
|
1140
1555
|
}
|
|
1556
|
+
splitPaymentLogger.info("Web2 split payment completed", {
|
|
1557
|
+
paymentId: paymentResData.id,
|
|
1558
|
+
status: cardStatus
|
|
1559
|
+
});
|
|
1141
1560
|
return {
|
|
1142
1561
|
paymentType: "SPLIT" /* CREDIT_CARD_SPLIT */,
|
|
1143
1562
|
status: cardStatus,
|
|
@@ -1218,13 +1637,7 @@ var CardListItem = ({ card, isSelected, onSelect }) => {
|
|
|
1218
1637
|
"cursor-not-allowed opacity-50": isSelected || isRemoveDisabled
|
|
1219
1638
|
// 'cursor-pointer': !isSelected || !isRemoveDisabled,
|
|
1220
1639
|
}),
|
|
1221
|
-
children: /* @__PURE__ */ jsx12("svg", { xmlns: "http://www.w3.org/2000/svg",
|
|
1222
|
-
"path",
|
|
1223
|
-
{
|
|
1224
|
-
fill: "currentColor",
|
|
1225
|
-
d: "M6.35 16.17c-.38 0-.7-.13-.96-.4a1.3 1.3 0 0 1-.39-.95V4.5h-.83v-.83H7.5v-.64h5v.64h3.33v.83H15v10.32c0 .39-.13.7-.39.96a1.3 1.3 0 0 1-.96.39h-7.3ZM14.17 4.5H5.83v10.32c0 .15.05.28.15.37.1.1.22.15.37.15h7.3c.13 0 .25-.06.36-.16.1-.11.16-.23.16-.36V4.5Zm-6 9.17h.84v-7.5h-.84v7.5Zm2.82 0h.84v-7.5h-.84v7.5Z"
|
|
1226
|
-
}
|
|
1227
|
-
) })
|
|
1640
|
+
children: /* @__PURE__ */ jsx12("svg", { xmlns: "http://www.w3.org/2000/svg", fill: "currentColor", className: "size-5", viewBox: "0 0 20 20", children: /* @__PURE__ */ jsx12("path", { d: "M6.35 16.17q-.57 0-.96-.4a1.3 1.3 0 0 1-.39-.95V4.5h-.83v-.83H7.5v-.64h5v.64h3.33v.83H15v10.32q0 .58-.39.96a1.3 1.3 0 0 1-.96.39zM14.17 4.5H5.83v10.32q0 .23.15.37.15.15.37.15h7.3q.2 0 .36-.16.15-.17.16-.36zm-6 9.17h.84v-7.5h-.84zm2.82 0h.84v-7.5h-.84z" }) })
|
|
1228
1641
|
}
|
|
1229
1642
|
)
|
|
1230
1643
|
] })
|
|
@@ -1317,6 +1730,7 @@ function Checkbox({ className, ...props }) {
|
|
|
1317
1730
|
|
|
1318
1731
|
// src/components/CreditCardTab/CreditCard/CreditCardForm.tsx
|
|
1319
1732
|
import { Fragment as Fragment2, jsx as jsx15, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
1733
|
+
var cardFormLogger = logger.child("card-form");
|
|
1320
1734
|
var styleDark = {
|
|
1321
1735
|
base: {
|
|
1322
1736
|
fontSize: "16px",
|
|
@@ -1384,7 +1798,7 @@ var CreditCardForm = ({ cancel, saveCard }) => {
|
|
|
1384
1798
|
}
|
|
1385
1799
|
}
|
|
1386
1800
|
} catch (error) {
|
|
1387
|
-
|
|
1801
|
+
cardFormLogger.error("Failed to create Stripe card token", error);
|
|
1388
1802
|
setCardError("An error occurred while processing your card. Please try again.");
|
|
1389
1803
|
}
|
|
1390
1804
|
};
|
|
@@ -2587,6 +3001,7 @@ var PointsSelector = (props) => {
|
|
|
2587
3001
|
|
|
2588
3002
|
// src/components/CreditCardTab/Points/SplitBlock.tsx
|
|
2589
3003
|
import { jsx as jsx26, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
3004
|
+
var splitBlockLogger = logger.child("split-block");
|
|
2590
3005
|
var SplitBlock = (props) => {
|
|
2591
3006
|
const { onToggle, isSelected, onSelect } = props;
|
|
2592
3007
|
const { balance, isBalanceLoading } = useSlapiBalance();
|
|
@@ -2611,7 +3026,10 @@ var SplitBlock = (props) => {
|
|
|
2611
3026
|
onToggle(false);
|
|
2612
3027
|
}
|
|
2613
3028
|
} catch (e) {
|
|
2614
|
-
|
|
3029
|
+
splitBlockLogger.error("Air Wallet initialization failed", e, {
|
|
3030
|
+
partnerId: pointsChain?.partnerId,
|
|
3031
|
+
environment: env.environment
|
|
3032
|
+
});
|
|
2615
3033
|
}
|
|
2616
3034
|
},
|
|
2617
3035
|
[onToggle, env.environment]
|
|
@@ -2746,6 +3164,7 @@ import { useCallback as useCallback6, useEffect as useEffect8 } from "react";
|
|
|
2746
3164
|
|
|
2747
3165
|
// src/hooks/payments/useCryptoComPayment.ts
|
|
2748
3166
|
import NiceModal5 from "@ebay/nice-modal-react";
|
|
3167
|
+
var cryptoComLogger = logger.child("crypto-com-payment");
|
|
2749
3168
|
var useCryptoComPayment = () => {
|
|
2750
3169
|
const { selectedPaymentMethod } = useSpreePaymentMethod();
|
|
2751
3170
|
const { env } = useSpreePayEnv();
|
|
@@ -2754,6 +3173,7 @@ var useCryptoComPayment = () => {
|
|
|
2754
3173
|
throw new Error("Unsupported payment method");
|
|
2755
3174
|
}
|
|
2756
3175
|
const { hash, metadata } = params;
|
|
3176
|
+
cryptoComLogger.info("Starting Crypto.com Pay payment", { hash });
|
|
2757
3177
|
const { data: paymentResData } = await SlapiPaymentService.createPayment({
|
|
2758
3178
|
hash,
|
|
2759
3179
|
metadata,
|
|
@@ -2763,16 +3183,31 @@ var useCryptoComPayment = () => {
|
|
|
2763
3183
|
cancelUrl: `${typeof window !== "undefined" ? window.location.origin : ""}${env.redirect3dsURI}?payment_intent=canceled`
|
|
2764
3184
|
}
|
|
2765
3185
|
});
|
|
3186
|
+
cryptoComLogger.info("Payment created", {
|
|
3187
|
+
paymentId: paymentResData.id,
|
|
3188
|
+
status: paymentResData.status,
|
|
3189
|
+
hasRedirect: Boolean(paymentResData.redirectUrl)
|
|
3190
|
+
});
|
|
2766
3191
|
let { status } = paymentResData;
|
|
2767
3192
|
if (paymentResData.redirectUrl) {
|
|
3193
|
+
cryptoComLogger.debug("Opening CDC payment redirect", { paymentId: paymentResData.id });
|
|
2768
3194
|
const paymentIntent = await NiceModal5.show(Iframe3ds, { url: paymentResData.redirectUrl });
|
|
3195
|
+
cryptoComLogger.info("CDC payment redirect completed", { paymentIntent });
|
|
2769
3196
|
if (paymentIntent === "success") {
|
|
3197
|
+
cryptoComLogger.debug("Validating CDC payment", { paymentId: paymentResData.id });
|
|
2770
3198
|
const { data: validateData } = await SlapiPaymentService.validateCDC({ paymentId: paymentResData.id });
|
|
2771
3199
|
({ status } = validateData);
|
|
3200
|
+
cryptoComLogger.info("CDC payment validated", { paymentId: paymentResData.id, status });
|
|
2772
3201
|
} else {
|
|
2773
3202
|
status = "FAILED" /* FAILED */;
|
|
3203
|
+
cryptoComLogger.warn("CDC payment canceled or failed", { paymentIntent });
|
|
2774
3204
|
}
|
|
2775
3205
|
}
|
|
3206
|
+
cryptoComLogger.info("Crypto.com Pay payment completed", {
|
|
3207
|
+
paymentId: paymentResData.id,
|
|
3208
|
+
status,
|
|
3209
|
+
txId: paymentResData.txId
|
|
3210
|
+
});
|
|
2776
3211
|
return {
|
|
2777
3212
|
status,
|
|
2778
3213
|
paymentType: "CDC" /* CDC */,
|
|
@@ -2794,7 +3229,7 @@ var Checkout = () => {
|
|
|
2794
3229
|
onClick: appProps.onProcess,
|
|
2795
3230
|
disabled: appProps.isProcessing,
|
|
2796
3231
|
className: "flex flex-col items-center rounded-md bg-[#00307D] p-2 text-(--brand-primary) hover:bg-[#002655] disabled:cursor-not-allowed disabled:bg-[#002655] disabled:text-(--disabled)",
|
|
2797
|
-
children: /* @__PURE__ */ jsxs17("svg", { xmlns: "http://www.w3.org/2000/svg",
|
|
3232
|
+
children: /* @__PURE__ */ jsxs17("svg", { xmlns: "http://www.w3.org/2000/svg", className: "h-7 w-[76px]", fill: "none", viewBox: "0 0 76 28", children: [
|
|
2798
3233
|
/* @__PURE__ */ jsx29(
|
|
2799
3234
|
"path",
|
|
2800
3235
|
{
|
|
@@ -2985,6 +3420,7 @@ var BASE_TOKENS = [
|
|
|
2985
3420
|
|
|
2986
3421
|
// src/hooks/payments/useCryptoPayment.ts
|
|
2987
3422
|
var MAX_UINT256 = BigInt(2) ** BigInt(256) - BigInt(1);
|
|
3423
|
+
var cryptoPaymentLogger = logger.child("crypto-payment");
|
|
2988
3424
|
var useCryptoPayment = () => {
|
|
2989
3425
|
const { data: walletClient } = useWalletClient();
|
|
2990
3426
|
const { spreePayConfig } = useSpreePayConfig();
|
|
@@ -2992,21 +3428,43 @@ var useCryptoPayment = () => {
|
|
|
2992
3428
|
const { selectedPaymentMethod } = useSpreePaymentMethod();
|
|
2993
3429
|
const cryptoPayment = async (params) => {
|
|
2994
3430
|
if (!walletClient) {
|
|
2995
|
-
|
|
3431
|
+
const error = new Error("Wallet not connected");
|
|
3432
|
+
cryptoPaymentLogger.error("Wallet not connected for crypto payment", error);
|
|
3433
|
+
throw error;
|
|
2996
3434
|
}
|
|
2997
3435
|
if (!spreePayConfig) {
|
|
2998
|
-
|
|
3436
|
+
const error = new Error("Spree Pay config not loaded");
|
|
3437
|
+
cryptoPaymentLogger.error("Config not loaded for crypto payment", error);
|
|
3438
|
+
throw error;
|
|
2999
3439
|
}
|
|
3000
3440
|
if (selectedPaymentMethod.type !== "CRYPTO" /* CRYPTO */ || !selectedPaymentMethod.method?.symbol) {
|
|
3001
|
-
|
|
3441
|
+
const error = new Error("Unsupported payment method");
|
|
3442
|
+
cryptoPaymentLogger.error("Invalid payment method for crypto payment", error, {
|
|
3443
|
+
actualType: selectedPaymentMethod.type,
|
|
3444
|
+
hasMethod: Boolean(selectedPaymentMethod.method)
|
|
3445
|
+
});
|
|
3446
|
+
throw error;
|
|
3002
3447
|
}
|
|
3003
3448
|
const { capture, hash, metadata } = params;
|
|
3004
3449
|
const TOKEN = selectedPaymentMethod.method.symbol;
|
|
3450
|
+
cryptoPaymentLogger.info("Starting crypto payment", {
|
|
3451
|
+
hash,
|
|
3452
|
+
capture,
|
|
3453
|
+
token: TOKEN,
|
|
3454
|
+
walletAddress: walletClient.account.address
|
|
3455
|
+
});
|
|
3005
3456
|
if (["MOCA" /* MOCA */, "WETH" /* WETH */, "USDC" /* USDC */, "USDT" /* USDT */].includes(TOKEN)) {
|
|
3006
3457
|
const tokenAddress = selectedPaymentMethod.method.address;
|
|
3007
3458
|
if (!tokenAddress) {
|
|
3008
|
-
|
|
3459
|
+
const error = new Error("Token address not found");
|
|
3460
|
+
cryptoPaymentLogger.error("Token address missing", error, { token: TOKEN });
|
|
3461
|
+
throw error;
|
|
3009
3462
|
}
|
|
3463
|
+
cryptoPaymentLogger.debug("Checking token allowance", {
|
|
3464
|
+
token: TOKEN,
|
|
3465
|
+
tokenAddress,
|
|
3466
|
+
router: spreePayConfig.crypto.oneInchAggregationRouter
|
|
3467
|
+
});
|
|
3010
3468
|
const allowance = await readContract(config2, {
|
|
3011
3469
|
address: tokenAddress,
|
|
3012
3470
|
abi: erc20Abi2,
|
|
@@ -3014,19 +3472,36 @@ var useCryptoPayment = () => {
|
|
|
3014
3472
|
args: [walletClient.account.address, spreePayConfig.crypto.oneInchAggregationRouter]
|
|
3015
3473
|
});
|
|
3016
3474
|
if (allowance <= 0n) {
|
|
3475
|
+
cryptoPaymentLogger.info("Requesting token approval", {
|
|
3476
|
+
token: TOKEN,
|
|
3477
|
+
tokenAddress
|
|
3478
|
+
});
|
|
3017
3479
|
const result = await walletClient.writeContract({
|
|
3018
3480
|
address: tokenAddress,
|
|
3019
3481
|
abi: erc20Abi2,
|
|
3020
3482
|
functionName: "approve",
|
|
3021
3483
|
args: [spreePayConfig.crypto.oneInchAggregationRouter, MAX_UINT256]
|
|
3022
3484
|
});
|
|
3485
|
+
cryptoPaymentLogger.debug("Waiting for approval confirmation", {
|
|
3486
|
+
approvalTxHash: result
|
|
3487
|
+
});
|
|
3023
3488
|
await waitForTransactionReceipt(config2, {
|
|
3024
3489
|
hash: result,
|
|
3025
3490
|
confirmations: 1
|
|
3026
|
-
|
|
3491
|
+
});
|
|
3492
|
+
cryptoPaymentLogger.info("Token approval confirmed", {
|
|
3493
|
+
approvalTxHash: result
|
|
3494
|
+
});
|
|
3495
|
+
} else {
|
|
3496
|
+
cryptoPaymentLogger.debug("Sufficient allowance exists", {
|
|
3497
|
+
allowance: allowance.toString()
|
|
3027
3498
|
});
|
|
3028
3499
|
}
|
|
3029
3500
|
}
|
|
3501
|
+
cryptoPaymentLogger.debug("Creating crypto payment", {
|
|
3502
|
+
token: TOKEN,
|
|
3503
|
+
slippageBps: Math.round(0.5 * 100)
|
|
3504
|
+
});
|
|
3030
3505
|
const paymentRes = await SlapiPaymentService.createPayment({
|
|
3031
3506
|
hash,
|
|
3032
3507
|
capture,
|
|
@@ -3039,19 +3514,42 @@ var useCryptoPayment = () => {
|
|
|
3039
3514
|
slippageBps: Math.round(0.5 * 100)
|
|
3040
3515
|
}
|
|
3041
3516
|
});
|
|
3517
|
+
cryptoPaymentLogger.info("Crypto payment created", {
|
|
3518
|
+
paymentId: paymentRes.data.id,
|
|
3519
|
+
txId: paymentRes.data.txId
|
|
3520
|
+
});
|
|
3042
3521
|
const parsedTX = JSON.parse(paymentRes.data.encodedTx);
|
|
3522
|
+
cryptoPaymentLogger.debug("Sending transaction", {
|
|
3523
|
+
to: parsedTX.to,
|
|
3524
|
+
value: parsedTX.value.toString()
|
|
3525
|
+
});
|
|
3043
3526
|
const txHash = await walletClient.sendTransaction({
|
|
3044
3527
|
account: walletClient.account.address,
|
|
3045
3528
|
to: parsedTX.to,
|
|
3046
3529
|
data: parsedTX.data,
|
|
3047
3530
|
value: parsedTX.value
|
|
3048
3531
|
});
|
|
3532
|
+
cryptoPaymentLogger.info("Transaction sent", {
|
|
3533
|
+
txHash,
|
|
3534
|
+
paymentId: paymentRes.data.id
|
|
3535
|
+
});
|
|
3536
|
+
cryptoPaymentLogger.debug("Verifying transaction on chain", {
|
|
3537
|
+
txId: paymentRes.data.txId,
|
|
3538
|
+
txHash
|
|
3539
|
+
});
|
|
3049
3540
|
const res = await SlapiPaymentService.baseVerify({ id: paymentRes.data.txId, txHash });
|
|
3541
|
+
const finalStatus = res.verified ? "CAPTURED" /* CAPTURED */ : "FAILED" /* FAILED */;
|
|
3542
|
+
cryptoPaymentLogger.info("Crypto payment completed", {
|
|
3543
|
+
paymentId: paymentRes.data.id,
|
|
3544
|
+
txHash,
|
|
3545
|
+
verified: res.verified,
|
|
3546
|
+
status: finalStatus
|
|
3547
|
+
});
|
|
3050
3548
|
return {
|
|
3051
3549
|
txHash,
|
|
3052
3550
|
paymentId: paymentRes.data.id,
|
|
3053
3551
|
txId: paymentRes.data.txId,
|
|
3054
|
-
status:
|
|
3552
|
+
status: finalStatus,
|
|
3055
3553
|
paymentType: "CRYPTO" /* CRYPTO */
|
|
3056
3554
|
};
|
|
3057
3555
|
};
|
|
@@ -3082,48 +3580,45 @@ var ConnectButton = () => {
|
|
|
3082
3580
|
|
|
3083
3581
|
// src/config/symbolLogos.tsx
|
|
3084
3582
|
import { jsx as jsx32, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
3085
|
-
var MOCA_SVG = /* @__PURE__ */ jsxs20("svg", { xmlns: "http://www.w3.org/2000/svg",
|
|
3086
|
-
/* @__PURE__ */ jsx32("circle", { cx: "14", cy: "14", r: "13.5", fill: "#
|
|
3583
|
+
var MOCA_SVG = /* @__PURE__ */ jsxs20("svg", { xmlns: "http://www.w3.org/2000/svg", fill: "none", className: "size-7", viewBox: "0 0 28 28", children: [
|
|
3584
|
+
/* @__PURE__ */ jsx32("circle", { cx: "14", cy: "14", r: "13.5", fill: "#c15f97" }),
|
|
3087
3585
|
/* @__PURE__ */ jsx32(
|
|
3088
3586
|
"path",
|
|
3089
3587
|
{
|
|
3090
3588
|
fill: "#fff",
|
|
3091
|
-
d: "M16.06 6.65c.3 0 .59.16.74.43l6.06 10.5a.85.85 0 1 1-1.47.84L16.06 9.2l-1.51 2.62-.02.03-3.8 6.57a.85.85 0 0 1-1.47-.84l3.57-6.18-1.27-2.2-5.32 9.22a.85.85 0 0 1-1.48-.84l6.07-10.5.06-.1a.85.85 0 0 1 1.4.1l1.52 2.62 1.52-2.62.06-.1c.16-.2.4-.33.67-.
|
|
3589
|
+
d: "M16.06 6.65c.3 0 .59.16.74.43l6.06 10.5a.85.85 0 1 1-1.47.84L16.06 9.2l-1.51 2.62-.02.03-3.8 6.57a.85.85 0 0 1-1.47-.84l3.57-6.18-1.27-2.2-5.32 9.22a.85.85 0 0 1-1.48-.84l6.07-10.5.06-.1a.85.85 0 0 1 1.4.1l1.52 2.62 1.52-2.62.06-.1c.16-.2.4-.33.67-.33"
|
|
3092
3590
|
}
|
|
3093
3591
|
),
|
|
3094
3592
|
/* @__PURE__ */ jsx32("circle", { cx: "16", cy: "14", r: "1.5", fill: "#fff" })
|
|
3095
3593
|
] });
|
|
3096
|
-
var USDC_SVG = /* @__PURE__ */ jsxs20("svg", { xmlns: "http://www.w3.org/2000/svg",
|
|
3097
|
-
/* @__PURE__ */
|
|
3098
|
-
|
|
3099
|
-
|
|
3100
|
-
|
|
3101
|
-
|
|
3102
|
-
|
|
3103
|
-
|
|
3104
|
-
|
|
3105
|
-
|
|
3106
|
-
|
|
3107
|
-
|
|
3108
|
-
|
|
3109
|
-
|
|
3110
|
-
|
|
3111
|
-
|
|
3112
|
-
)
|
|
3113
|
-
] }),
|
|
3114
|
-
/* @__PURE__ */ jsx32("defs", { children: /* @__PURE__ */ jsx32("clipPath", { id: "clip0_528_9163", children: /* @__PURE__ */ jsx32("path", { fill: "#fff", d: "M0 0h28v28H0z" }) }) })
|
|
3594
|
+
var USDC_SVG = /* @__PURE__ */ jsxs20("svg", { xmlns: "http://www.w3.org/2000/svg", className: "size-7", fill: "none", viewBox: "0 0 28 28", children: [
|
|
3595
|
+
/* @__PURE__ */ jsx32("path", { fill: "#2775ca", d: "M14 28c7.76 0 14-6.24 14-14S21.76 0 14 0 0 6.24 0 14s6.24 14 14 14" }),
|
|
3596
|
+
/* @__PURE__ */ jsx32(
|
|
3597
|
+
"path",
|
|
3598
|
+
{
|
|
3599
|
+
fill: "#fff",
|
|
3600
|
+
d: "M17.85 16.22c0-2.04-1.23-2.74-3.68-3.04-1.75-.23-2.1-.7-2.1-1.51 0-.82.59-1.34 1.75-1.34 1.05 0 1.64.35 1.93 1.22.06.18.23.3.4.3h.94a.4.4 0 0 0 .41-.42v-.05a2.91 2.91 0 0 0-2.63-2.4v-1.4c0-.23-.17-.4-.46-.46h-.88c-.23 0-.4.17-.46.46v1.35c-1.75.23-2.86 1.4-2.86 2.85 0 1.93 1.16 2.69 3.61 2.98 1.64.29 2.16.64 2.16 1.57 0 .94-.81 1.58-1.92 1.58-1.52 0-2.04-.64-2.22-1.52-.06-.23-.23-.35-.4-.35h-1a.4.4 0 0 0-.4.41v.06c.23 1.46 1.16 2.5 3.08 2.8v1.4c0 .23.18.4.47.47h.88c.23 0 .4-.18.46-.47v-1.4c1.75-.3 2.92-1.52 2.92-3.1Z"
|
|
3601
|
+
}
|
|
3602
|
+
),
|
|
3603
|
+
/* @__PURE__ */ jsx32(
|
|
3604
|
+
"path",
|
|
3605
|
+
{
|
|
3606
|
+
fill: "#fff",
|
|
3607
|
+
d: "M11.03 22.34a8.69 8.69 0 0 1-5.2-11.2 8.63 8.63 0 0 1 5.2-5.19.6.6 0 0 0 .35-.58v-.82c0-.23-.12-.4-.35-.47-.06 0-.18 0-.24.06a10.48 10.48 0 0 0 0 20.01c.24.12.47 0 .53-.23.06-.06.06-.12.06-.24v-.81c0-.18-.18-.41-.35-.53m6.18-18.2c-.23-.12-.47 0-.53.23-.05.06-.05.12-.05.24v.81c0 .24.17.47.35.59a8.69 8.69 0 0 1 5.19 11.2 8.63 8.63 0 0 1-5.2 5.19c-.23.12-.34.3-.34.58v.82c0 .23.11.4.35.47.05 0 .17 0 .23-.06a10.48 10.48 0 0 0 6.82-13.19 10.58 10.58 0 0 0-6.82-6.88"
|
|
3608
|
+
}
|
|
3609
|
+
)
|
|
3115
3610
|
] });
|
|
3116
|
-
var USDT_SVG = /* @__PURE__ */ jsxs20("svg", { xmlns: "http://www.w3.org/2000/svg",
|
|
3117
|
-
/* @__PURE__ */ jsx32("path", { fill: "#
|
|
3611
|
+
var USDT_SVG = /* @__PURE__ */ jsxs20("svg", { xmlns: "http://www.w3.org/2000/svg", className: "size-7", fill: "none", viewBox: "0 0 28 28", children: [
|
|
3612
|
+
/* @__PURE__ */ jsx32("path", { fill: "#26a17b", d: "M14 28a14 14 0 1 0 0-28 14 14 0 0 0 0 28" }),
|
|
3118
3613
|
/* @__PURE__ */ jsx32(
|
|
3119
3614
|
"path",
|
|
3120
3615
|
{
|
|
3121
3616
|
fill: "#fff",
|
|
3122
|
-
d: "M15.5 15.3v-.01c-.1 0-.6.04-1.72.04-.88 0-1.5-.03-1.73-.04-3.42-.15-5.97-.74-5.97-1.46 0-.7 2.55-1.3 5.97-1.46v2.33a26 26 0 0 0 3.44 0v-2.32c3.42.15 5.96.74 5.96 1.46 0 .7-2.55 1.3-5.96 1.45m0-3.15v-2.08h4.76V6.89H7.3v3.17h4.76v2.08c-3.87.17-6.77.94-6.77 1.
|
|
3617
|
+
d: "M15.5 15.3v-.01c-.1 0-.6.04-1.72.04-.88 0-1.5-.03-1.73-.04-3.42-.15-5.97-.74-5.97-1.46 0-.7 2.55-1.3 5.97-1.46v2.33a26 26 0 0 0 3.44 0v-2.32c3.42.15 5.96.74 5.96 1.46 0 .7-2.55 1.3-5.96 1.45m0-3.15v-2.08h4.76V6.89H7.3v3.17h4.76v2.08c-3.87.17-6.77.94-6.77 1.86s2.9 1.68 6.77 1.86v6.67h3.45v-6.67c3.86-.18 6.76-.94 6.76-1.86s-2.9-1.68-6.76-1.86"
|
|
3123
3618
|
}
|
|
3124
3619
|
)
|
|
3125
3620
|
] });
|
|
3126
|
-
var WETH_SVG = /* @__PURE__ */ jsxs20("svg", { xmlns: "http://www.w3.org/2000/svg", fill: "none",
|
|
3621
|
+
var WETH_SVG = /* @__PURE__ */ jsxs20("svg", { xmlns: "http://www.w3.org/2000/svg", fill: "none", className: "size-7", viewBox: "0 0 24 24", children: [
|
|
3127
3622
|
/* @__PURE__ */ jsxs20("g", { clipPath: "url(#clip0_528_9173)", children: [
|
|
3128
3623
|
/* @__PURE__ */ jsx32(
|
|
3129
3624
|
"path",
|
|
@@ -3421,9 +3916,9 @@ var CryptoSelectModal = NiceModal6.create(() => {
|
|
|
3421
3916
|
/* @__PURE__ */ jsxs22(DialogContent, { showCloseButton: false, className: "max-h-[90vh] gap-0 p-0", children: [
|
|
3422
3917
|
/* @__PURE__ */ jsxs22("div", { className: "flex flex-col gap-4 px-5 py-5 md:px-7", children: [
|
|
3423
3918
|
/* @__PURE__ */ jsxs22("div", { className: "flex items-center justify-between gap-4", children: [
|
|
3424
|
-
/* @__PURE__ */ jsx38("button", { className: "rounded-md hover:bg-(--s-primary-hover)", onClick: modal.remove, children: /* @__PURE__ */ jsx38("svg", { xmlns: "http://www.w3.org/2000/svg",
|
|
3919
|
+
/* @__PURE__ */ jsx38("button", { className: "rounded-md hover:bg-(--s-primary-hover)", onClick: modal.remove, children: /* @__PURE__ */ jsx38("svg", { xmlns: "http://www.w3.org/2000/svg", fill: "none", className: "size-6", viewBox: "0 0 24 25", children: /* @__PURE__ */ jsx38("path", { stroke: "currentColor", d: "m15 6.5-6 6 6 6" }) }) }),
|
|
3425
3920
|
/* @__PURE__ */ jsx38(DialogTitle, { className: "text-2xl font-medium text-(--brand-primary)", children: "Select a token" }),
|
|
3426
|
-
/* @__PURE__ */ jsx38("button", { className: "rounded-md p-1 hover:bg-(--s-primary-hover)", onClick: modal.remove, children: /* @__PURE__ */ jsx38("svg", { xmlns: "http://www.w3.org/2000/svg",
|
|
3921
|
+
/* @__PURE__ */ jsx38("button", { className: "rounded-md p-1 hover:bg-(--s-primary-hover)", onClick: modal.remove, children: /* @__PURE__ */ jsx38("svg", { xmlns: "http://www.w3.org/2000/svg", fill: "none", className: "size-4", viewBox: "0 0 16 17", children: /* @__PURE__ */ jsx38(
|
|
3427
3922
|
"path",
|
|
3428
3923
|
{
|
|
3429
3924
|
fill: "currentColor",
|
|
@@ -3521,7 +4016,7 @@ var SelectCoinButton = () => {
|
|
|
3521
4016
|
className: "flex h-11 w-full overflow-hidden rounded-md bg-(--s-primary) hover:bg-(--s-primary-hover)",
|
|
3522
4017
|
children: /* @__PURE__ */ jsxs23("div", { className: "flex h-full w-full items-center justify-between px-3", children: [
|
|
3523
4018
|
/* @__PURE__ */ jsx39("div", { className: "flex items-center", children: /* @__PURE__ */ jsx39("p", { className: "font-medium text-(--secondary)", children: "Select a token" }) }),
|
|
3524
|
-
/* @__PURE__ */ jsx39("svg", { xmlns: "http://www.w3.org/2000/svg",
|
|
4019
|
+
/* @__PURE__ */ jsx39("svg", { xmlns: "http://www.w3.org/2000/svg", fill: "none", className: "size-4", viewBox: "0 0 16 16", children: /* @__PURE__ */ jsx39("path", { stroke: "currentColor", d: "m6 12.43 4-4-4-4" }) })
|
|
3525
4020
|
] })
|
|
3526
4021
|
}
|
|
3527
4022
|
);
|
|
@@ -3539,7 +4034,7 @@ var SelectedCoin = (props) => {
|
|
|
3539
4034
|
Icon,
|
|
3540
4035
|
!Icon && logoURI && /* @__PURE__ */ jsx40("img", { className: "mr-1 size-8 shrink-0", src: logoURI, alt: `${coin} logo` }),
|
|
3541
4036
|
/* @__PURE__ */ jsx40("p", { className: "font-semibold text-(--brand-primary)", children: coin }),
|
|
3542
|
-
/* @__PURE__ */ jsx40("svg", {
|
|
4037
|
+
/* @__PURE__ */ jsx40("svg", { xmlns: "http://www.w3.org/2000/svg", className: "size-4", fill: "none", viewBox: "0 0 16 16", children: /* @__PURE__ */ jsx40("path", { stroke: "currentColor", d: "m6 12.434 4-4-4-4" }) })
|
|
3543
4038
|
] }),
|
|
3544
4039
|
/* @__PURE__ */ jsxs24("p", { className: "text-xs font-medium text-(--secondary)", children: [
|
|
3545
4040
|
"Wallet balance ",
|
|
@@ -3659,49 +4154,39 @@ var TabButtons = (props) => {
|
|
|
3659
4154
|
return /* @__PURE__ */ jsxs27("div", { className: "flex gap-4", children: [
|
|
3660
4155
|
configIsLoading && /* @__PURE__ */ jsx44("div", { className: "h-[74px] w-[180px] animate-pulse rounded-md bg-(--s-primary)" }),
|
|
3661
4156
|
spreePayConfig?.creditCard.enabled && /* @__PURE__ */ jsxs27(TabButton, { onClick: handleChange("CREDIT_CARD" /* CREDIT_CARD */), isActive: value === "CREDIT_CARD" /* CREDIT_CARD */, children: [
|
|
3662
|
-
/* @__PURE__ */
|
|
3663
|
-
|
|
3664
|
-
|
|
3665
|
-
"
|
|
3666
|
-
|
|
3667
|
-
|
|
3668
|
-
|
|
3669
|
-
}
|
|
3670
|
-
) })
|
|
3671
|
-
] }),
|
|
4157
|
+
/* @__PURE__ */ jsx44("svg", { xmlns: "http://www.w3.org/2000/svg", fill: "none", className: "size-8", viewBox: "0 0 32 32", children: /* @__PURE__ */ jsx44(
|
|
4158
|
+
"path",
|
|
4159
|
+
{
|
|
4160
|
+
fill: "currentColor",
|
|
4161
|
+
d: "M28 8.82v14.36q0 .92-.62 1.54-.6.6-1.53.61H6.15q-.91 0-1.53-.61A2 2 0 0 1 4 23.18V8.82q0-.92.62-1.54.6-.6 1.53-.61h19.7q.91 0 1.53.61.62.62.62 1.54M5.33 11.74h21.34V8.82q0-.31-.26-.56a.8.8 0 0 0-.56-.26H6.15q-.3 0-.56.26a.8.8 0 0 0-.26.56zm0 3.18v8.26q0 .31.26.56t.56.26h19.7q.3 0 .56-.26a.8.8 0 0 0 .26-.56v-8.26z"
|
|
4162
|
+
}
|
|
4163
|
+
) }),
|
|
3672
4164
|
/* @__PURE__ */ jsx44("p", { className: "text-md font-medium", children: "Card" })
|
|
3673
4165
|
] }),
|
|
3674
4166
|
spreePayConfig?.crypto.enabled && /* @__PURE__ */ jsxs27(TabButton, { onClick: handleChange("CRYPTO" /* CRYPTO */), isActive: value === "CRYPTO" /* CRYPTO */, children: [
|
|
3675
|
-
/* @__PURE__ */ jsx44("svg", { xmlns: "http://www.w3.org/2000/svg",
|
|
4167
|
+
/* @__PURE__ */ jsx44("svg", { xmlns: "http://www.w3.org/2000/svg", fill: "none", className: "size-8", viewBox: "0 0 32 32", children: /* @__PURE__ */ jsx44(
|
|
3676
4168
|
"path",
|
|
3677
4169
|
{
|
|
3678
4170
|
fill: "currentColor",
|
|
3679
|
-
|
|
3680
|
-
d: "M21 9.86a8 8 0 0 1 3 5.43l-2.85-.71a5.4 5.4 0 0 0-3.86-3.67 5.3 5.3 0 0 0-6.46 3.8 5.3 5.3 0 0 0 3.91 6.4 5.4 5.4 0 0 0 5.14-1.43l2.85.7a8 8 0 0 1-5.2 3.39L16.72 27l-2.6-.65.64-2.57a8 8 0 0 1-1.3-.32l-.64 2.57-2.6-.65.82-3.24a7.9 7.9 0 0 1-2.8-8.08 7.9 7.9 0 0 1 6.27-5.82L15.32 5l2.6.64-.65 2.58q.67.1 1.3.32l.65-2.57 2.6.64z",
|
|
3681
|
-
clipRule: "evenodd"
|
|
4171
|
+
d: "M21 9.86a8 8 0 0 1 3 5.43l-2.85-.71a5.4 5.4 0 0 0-3.86-3.67 5.3 5.3 0 0 0-6.46 3.8 5.3 5.3 0 0 0 3.91 6.4 5.4 5.4 0 0 0 5.14-1.43l2.85.7a8 8 0 0 1-5.2 3.39L16.72 27l-2.6-.65.64-2.57a8 8 0 0 1-1.3-.32l-.64 2.57-2.6-.65.82-3.24a7.9 7.9 0 0 1-2.8-8.08 7.9 7.9 0 0 1 6.27-5.82L15.32 5l2.6.64-.65 2.58q.67.1 1.3.32l.65-2.57 2.6.64z"
|
|
3682
4172
|
}
|
|
3683
4173
|
) }),
|
|
3684
4174
|
/* @__PURE__ */ jsx44("p", { className: "text-md font-medium", children: "Crypto" })
|
|
3685
4175
|
] }),
|
|
3686
4176
|
spreePayConfig?.cryptoCom.enabled && /* @__PURE__ */ jsxs27(TabButton, { onClick: handleChange("CDC" /* CDC */), isActive: value === "CDC" /* CDC */, children: [
|
|
3687
|
-
/* @__PURE__ */ jsxs27("svg", { xmlns: "http://www.w3.org/2000/svg",
|
|
4177
|
+
/* @__PURE__ */ jsxs27("svg", { xmlns: "http://www.w3.org/2000/svg", fill: "none", className: "h-8 w-11", viewBox: "0 0 44 32", children: [
|
|
3688
4178
|
/* @__PURE__ */ jsx44(
|
|
3689
4179
|
"path",
|
|
3690
4180
|
{
|
|
3691
4181
|
fill: "currentColor",
|
|
3692
|
-
|
|
3693
|
-
d: "M17.6 11v10l-8.8 5L0 21V11l8.8-5zM2.2 16.69l3.15 5.42h1.26l1.5-1.37v-.7L6.56 18.6v-2.32L4.51 15zm8.87-.42v2.32l-1.55 1.46v.69l1.5 1.35h1.24l3.15-5.4-2.32-1.72zm-4.5-1.95.75 1.95-.23 2.17H8.8l1.72-.01-.21-2.17.74-1.94zm-1.25-4-.8 3.48h8.56l-.83-3.47z",
|
|
3694
|
-
clipRule: "evenodd"
|
|
4182
|
+
d: "M17.6 11v10l-8.8 5L0 21V11l8.8-5zM2.2 16.69l3.15 5.42h1.26l1.5-1.37v-.7L6.56 18.6v-2.32L4.51 15zm8.87-.42v2.32l-1.55 1.46v.69l1.5 1.35h1.24l3.15-5.4-2.32-1.72zm-4.5-1.95.75 1.95-.23 2.17H8.8l1.72-.01-.21-2.17.74-1.94zm-1.25-4-.8 3.48h8.56l-.83-3.47z"
|
|
3695
4183
|
}
|
|
3696
4184
|
),
|
|
3697
|
-
/* @__PURE__ */ jsx44("path", { fill: "#009fff", d: "m39.84 18.25 1.94-4.64h1.42l-4.05 9.17H37.7l1.4-3.1-2.64-6.07h1.5z" }),
|
|
3698
4185
|
/* @__PURE__ */ jsx44(
|
|
3699
4186
|
"path",
|
|
3700
4187
|
{
|
|
3701
4188
|
fill: "#009fff",
|
|
3702
|
-
|
|
3703
|
-
d: "M32.91 13.46q.92 0 1.52.34.62.34.91.94t.31 1.37v1.94q0 .37.15.55.15.17.54.2v1.16q-.51 0-.9-.11-.37-.12-.61-.35a2 2 0 0 1-.38-.61 2.6 2.6 0 0 1-2.24 1.22q-.62 0-1.13-.21a2 2 0 0 1-.82-.67q-.3-.44-.3-1.05 0-.73.35-1.16.38-.45.99-.66.63-.21 1.37-.21h1.61q0-.56-.18-.89a1 1 0 0 0-.49-.5q-.3-.15-.71-.16-.54 0-.95.25a1.1 1.1 0 0 0-.5.78h-1.37q.06-.69.46-1.17.41-.5 1.04-.75t1.33-.25m-.14 3.63q-.37 0-.7.1-.33.07-.53.3a.8.8 0 0 0-.2.58q0 .48.35.71t.84.22a1.7 1.7 0 0 0 1.53-.95q.22-.44.22-.93v-.03zM26.34 11q.94 0 1.63.3.69.29 1.08.88.4.57.4 1.43t-.4 1.45-1.1.88q-.7.28-1.61.28h-1.78v3.74H23.2V11zm-1.78 4.07h1.75q.97 0 1.36-.38.4-.4.4-1.08 0-.7-.4-1.07-.4-.4-1.36-.4h-1.75z",
|
|
3704
|
-
clipRule: "evenodd"
|
|
4189
|
+
d: "m39.84 18.25 1.94-4.64h1.42l-4.05 9.17H37.7l1.4-3.1-2.64-6.07h1.5zm-6.93-4.79q.92 0 1.52.34.62.34.91.94t.31 1.37v1.94q0 .37.15.55.15.17.54.2v1.16q-.51 0-.9-.11-.37-.12-.61-.35a2 2 0 0 1-.38-.61 2.6 2.6 0 0 1-2.24 1.22q-.62 0-1.13-.21a2 2 0 0 1-.82-.67q-.3-.44-.3-1.05 0-.73.35-1.16.38-.45.99-.66.63-.21 1.37-.21h1.61q0-.56-.18-.89a1 1 0 0 0-.49-.5q-.3-.15-.71-.16-.54 0-.95.25a1.1 1.1 0 0 0-.5.78h-1.37q.06-.69.46-1.17.41-.5 1.04-.75t1.33-.25m-.14 3.63q-.37 0-.7.1-.33.07-.53.3a.8.8 0 0 0-.2.58q0 .48.35.71t.84.22a1.7 1.7 0 0 0 1.53-.95q.22-.44.22-.93v-.03zM26.34 11q.94 0 1.63.3.69.29 1.08.88.4.57.4 1.43t-.4 1.45-1.1.88q-.7.28-1.61.28h-1.78v3.74H23.2V11zm-1.78 4.07h1.75q.97 0 1.36-.38.4-.4.4-1.08 0-.7-.4-1.07-.4-.4-1.36-.4h-1.75z"
|
|
3705
4190
|
}
|
|
3706
4191
|
)
|
|
3707
4192
|
] }),
|
|
@@ -3731,10 +4216,59 @@ var SpreePayContent = ({ isLoggedIn }) => {
|
|
|
3731
4216
|
] });
|
|
3732
4217
|
};
|
|
3733
4218
|
|
|
4219
|
+
// src/components/ErrorBoundary.tsx
|
|
4220
|
+
import { Component } from "react";
|
|
4221
|
+
import { jsx as jsx46, jsxs as jsxs29 } from "react/jsx-runtime";
|
|
4222
|
+
var ErrorBoundary = class extends Component {
|
|
4223
|
+
constructor(props) {
|
|
4224
|
+
super(props);
|
|
4225
|
+
this.state = { hasError: false, error: null };
|
|
4226
|
+
}
|
|
4227
|
+
static getDerivedStateFromError(error) {
|
|
4228
|
+
return { hasError: true, error };
|
|
4229
|
+
}
|
|
4230
|
+
componentDidCatch(error, errorInfo) {
|
|
4231
|
+
logger.error("Widget error caught by ErrorBoundary", error, {
|
|
4232
|
+
componentStack: errorInfo.componentStack
|
|
4233
|
+
});
|
|
4234
|
+
}
|
|
4235
|
+
render() {
|
|
4236
|
+
if (this.state.hasError) {
|
|
4237
|
+
if (this.props.fallback) {
|
|
4238
|
+
return this.props.fallback;
|
|
4239
|
+
}
|
|
4240
|
+
return /* @__PURE__ */ jsxs29("div", { className: "flex w-full flex-col items-center justify-center rounded-3xl border border-(--b-inverse) bg-(--s-primary) p-8", children: [
|
|
4241
|
+
/* @__PURE__ */ jsx46("div", { className: "mb-4 flex size-12 items-center justify-center rounded-full bg-(--s-secondary)", children: /* @__PURE__ */ jsxs29(
|
|
4242
|
+
"svg",
|
|
4243
|
+
{
|
|
4244
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
4245
|
+
viewBox: "0 0 24 24",
|
|
4246
|
+
fill: "none",
|
|
4247
|
+
stroke: "currentColor",
|
|
4248
|
+
strokeWidth: "2",
|
|
4249
|
+
strokeLinecap: "round",
|
|
4250
|
+
strokeLinejoin: "round",
|
|
4251
|
+
className: "size-10 text-(--warning)",
|
|
4252
|
+
children: [
|
|
4253
|
+
/* @__PURE__ */ jsx46("circle", { cx: "12", cy: "12", r: "10" }),
|
|
4254
|
+
/* @__PURE__ */ jsx46("line", { x1: "12", y1: "8", x2: "12", y2: "12" }),
|
|
4255
|
+
/* @__PURE__ */ jsx46("line", { x1: "12", y1: "16", x2: "12.01", y2: "16" })
|
|
4256
|
+
]
|
|
4257
|
+
}
|
|
4258
|
+
) }),
|
|
4259
|
+
/* @__PURE__ */ jsx46("h3", { className: "mb-2 text-lg font-semibold text-(--primary)", children: "Payment Widget Error" }),
|
|
4260
|
+
/* @__PURE__ */ jsx46("p", { className: "text-center text-sm text-(--secondary)", children: "Something went wrong loading the payment widget. Please refresh the page and try again." })
|
|
4261
|
+
] });
|
|
4262
|
+
}
|
|
4263
|
+
return this.props.children;
|
|
4264
|
+
}
|
|
4265
|
+
};
|
|
4266
|
+
|
|
3734
4267
|
// src/hooks/useKeycloakSSO.ts
|
|
3735
4268
|
import { useCallback as useCallback8, useEffect as useEffect11, useRef as useRef7, useState as useState13 } from "react";
|
|
3736
4269
|
import Keycloak from "keycloak-js";
|
|
3737
4270
|
var refreshAheadSeconds = 60;
|
|
4271
|
+
var keycloakLogger = logger.child("keycloak");
|
|
3738
4272
|
function useKeycloakSSO(config2) {
|
|
3739
4273
|
const { url, realm, clientId, ssoPageURI, enabled } = config2;
|
|
3740
4274
|
const initRef = useRef7(false);
|
|
@@ -3761,8 +4295,11 @@ function useKeycloakSSO(config2) {
|
|
|
3761
4295
|
setAccessToken(kc.token ?? null);
|
|
3762
4296
|
scheduleRefreshRef.current();
|
|
3763
4297
|
}
|
|
3764
|
-
}).catch((
|
|
3765
|
-
|
|
4298
|
+
}).catch((err) => {
|
|
4299
|
+
keycloakLogger.error("Token refresh failed, redirecting to login", err);
|
|
4300
|
+
kc.login().catch((loginErr) => {
|
|
4301
|
+
keycloakLogger.error("Login redirect failed", loginErr);
|
|
4302
|
+
});
|
|
3766
4303
|
});
|
|
3767
4304
|
}, delayMs);
|
|
3768
4305
|
}, []);
|
|
@@ -3781,7 +4318,7 @@ function useKeycloakSSO(config2) {
|
|
|
3781
4318
|
scheduleRefresh();
|
|
3782
4319
|
}
|
|
3783
4320
|
}).catch((err) => {
|
|
3784
|
-
|
|
4321
|
+
keycloakLogger.error("Token expired refresh failed", err);
|
|
3785
4322
|
});
|
|
3786
4323
|
};
|
|
3787
4324
|
kc.init({
|
|
@@ -3789,7 +4326,7 @@ function useKeycloakSSO(config2) {
|
|
|
3789
4326
|
silentCheckSsoRedirectUri: `${window.location.origin}${ssoPageURI}`,
|
|
3790
4327
|
silentCheckSsoFallback: true
|
|
3791
4328
|
}).then((auth) => {
|
|
3792
|
-
|
|
4329
|
+
keycloakLogger.info("SSO initialization successful", { authenticated: auth });
|
|
3793
4330
|
setAccessToken(kc.token ?? null);
|
|
3794
4331
|
if (auth) scheduleRefresh();
|
|
3795
4332
|
}).catch((err) => {
|
|
@@ -3803,7 +4340,7 @@ function useKeycloakSSO(config2) {
|
|
|
3803
4340
|
}
|
|
3804
4341
|
|
|
3805
4342
|
// src/SpreePay.tsx
|
|
3806
|
-
import { jsx as
|
|
4343
|
+
import { jsx as jsx47, jsxs as jsxs30 } from "react/jsx-runtime";
|
|
3807
4344
|
var SpreePayInner = () => {
|
|
3808
4345
|
const [portalEl, setPortalEl] = useState14(null);
|
|
3809
4346
|
const rootRef = useCallback9((node) => {
|
|
@@ -3811,10 +4348,11 @@ var SpreePayInner = () => {
|
|
|
3811
4348
|
const el = node.querySelector(":scope > .sl-spreepay__portal");
|
|
3812
4349
|
setPortalEl(el ?? null);
|
|
3813
4350
|
}, []);
|
|
3814
|
-
useEffect12(() => {
|
|
3815
|
-
console.log(`[spree-pay] v${version}`);
|
|
3816
|
-
}, []);
|
|
3817
4351
|
const { env } = useSpreePayEnv();
|
|
4352
|
+
useEffect12(() => {
|
|
4353
|
+
configureLogger({ environment: env.environment });
|
|
4354
|
+
logger.logVersion();
|
|
4355
|
+
}, [env.environment]);
|
|
3818
4356
|
const { staticConfig, appProps } = useStaticConfig();
|
|
3819
4357
|
const tenantId = env?.tenantId;
|
|
3820
4358
|
const { isChecking, accessToken } = useKeycloakSSO({
|
|
@@ -3838,12 +4376,12 @@ var SpreePayInner = () => {
|
|
|
3838
4376
|
}, [_accessToken, staticConfig, tenantId, unauthenticatedFetcher]);
|
|
3839
4377
|
const getContent = () => {
|
|
3840
4378
|
if (isChecking) {
|
|
3841
|
-
return /* @__PURE__ */
|
|
3842
|
-
/* @__PURE__ */
|
|
3843
|
-
/* @__PURE__ */
|
|
4379
|
+
return /* @__PURE__ */ jsxs30("div", { className: "flex w-full flex-col", children: [
|
|
4380
|
+
/* @__PURE__ */ jsx47("div", { className: "mb-4 h-[315px] animate-pulse rounded-3xl bg-(--s-primary)" }),
|
|
4381
|
+
/* @__PURE__ */ jsx47("div", { className: "h-[135px] animate-pulse rounded-3xl bg-(--s-primary)" })
|
|
3844
4382
|
] });
|
|
3845
4383
|
}
|
|
3846
|
-
return /* @__PURE__ */
|
|
4384
|
+
return /* @__PURE__ */ jsx47(
|
|
3847
4385
|
SWRConfig,
|
|
3848
4386
|
{
|
|
3849
4387
|
value: {
|
|
@@ -3852,17 +4390,17 @@ var SpreePayInner = () => {
|
|
|
3852
4390
|
revalidateOnFocus: false,
|
|
3853
4391
|
revalidateIfStale: false
|
|
3854
4392
|
},
|
|
3855
|
-
children: /* @__PURE__ */
|
|
4393
|
+
children: /* @__PURE__ */ jsx47(PortalContainerProvider, { container: portalEl, children: /* @__PURE__ */ jsx47(NiceModal9.Provider, { children: /* @__PURE__ */ jsx47(SpreePayContent, { isLoggedIn: Boolean(_accessToken) }) }) })
|
|
3856
4394
|
}
|
|
3857
4395
|
);
|
|
3858
4396
|
};
|
|
3859
|
-
return /* @__PURE__ */
|
|
3860
|
-
/* @__PURE__ */
|
|
4397
|
+
return /* @__PURE__ */ jsxs30("div", { ref: rootRef, className: cn("sl-spreepay", appProps.className), children: [
|
|
4398
|
+
/* @__PURE__ */ jsx47("div", { className: "sl-spreepay__portal" }),
|
|
3861
4399
|
getContent()
|
|
3862
4400
|
] });
|
|
3863
4401
|
};
|
|
3864
4402
|
var SpreePay = (props) => {
|
|
3865
|
-
return /* @__PURE__ */
|
|
4403
|
+
return /* @__PURE__ */ jsx47(ErrorBoundary, { children: /* @__PURE__ */ jsx47(StaticConfigProvider, { props, children: /* @__PURE__ */ jsx47(SpreePayInner, {}) }) });
|
|
3866
4404
|
};
|
|
3867
4405
|
|
|
3868
4406
|
// src/hooks/useCapture3DS.ts
|
|
@@ -3875,9 +4413,12 @@ var useCapture3DS = (searchParams) => {
|
|
|
3875
4413
|
}, [searchParams]);
|
|
3876
4414
|
};
|
|
3877
4415
|
export {
|
|
4416
|
+
LogLevel,
|
|
3878
4417
|
PaymentType,
|
|
3879
4418
|
SpreePay,
|
|
3880
4419
|
SpreePayProvider,
|
|
4420
|
+
configureLogger,
|
|
4421
|
+
logger,
|
|
3881
4422
|
useCapture3DS,
|
|
3882
4423
|
useSpreePay
|
|
3883
4424
|
};
|