@easypayment/medusa-paypal-ui 1.2.2 → 1.2.7
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/CHANGELOG.md +23 -1
- package/README.md +85 -52
- package/dist/index.cjs +197 -88
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +197 -88
- package/dist/index.mjs.map +1 -1
- package/dist/order.cjs.map +1 -1
- package/dist/order.mjs.map +1 -1
- package/package.json +1 -1
- package/src/adapters/MedusaNextPayPalAdapter.tsx +196 -195
- package/src/client/http.ts +214 -204
- package/src/client/paypal.ts +91 -88
- package/src/client/types.ts +40 -40
- package/src/components/PayPalAdvancedCard.tsx +646 -611
- package/src/components/PayPalCurrencyNotice.tsx +24 -19
- package/src/components/PayPalPaymentSection.tsx +5 -1
- package/src/components/PayPalProvider.tsx +44 -38
- package/src/components/PayPalSmartButtons.tsx +489 -445
- package/src/hooks/usePayPalConfig.ts +99 -96
- package/src/hooks/usePayPalPaymentMethods.ts +145 -145
- package/src/index.ts +19 -16
- package/src/order.ts +140 -134
- package/src/utils/next-errors.ts +21 -21
- package/src/utils/processing-overlay.ts +96 -96
package/dist/index.mjs
CHANGED
|
@@ -72,7 +72,9 @@ function createHttpClient(opts) {
|
|
|
72
72
|
text = await res.text().catch(() => "");
|
|
73
73
|
} catch (err) {
|
|
74
74
|
if (err instanceof Error && err.name === "AbortError" && !(callerSignal && callerSignal.aborted)) {
|
|
75
|
-
throw new Error(
|
|
75
|
+
throw new Error(
|
|
76
|
+
`[PayPal] Request to ${path} timed out after ${timeoutMs / 1e3}s`
|
|
77
|
+
);
|
|
76
78
|
}
|
|
77
79
|
throw err;
|
|
78
80
|
} finally {
|
|
@@ -99,7 +101,10 @@ function createHttpClient(opts) {
|
|
|
99
101
|
);
|
|
100
102
|
}
|
|
101
103
|
if (!text) {
|
|
102
|
-
throw new HttpError(
|
|
104
|
+
throw new HttpError(
|
|
105
|
+
`[PayPal] Empty response body from ${path} (${res.status})`,
|
|
106
|
+
res.status
|
|
107
|
+
);
|
|
103
108
|
}
|
|
104
109
|
const contentType = res.headers.get("content-type") || "";
|
|
105
110
|
if (!contentType.includes("application/json")) {
|
|
@@ -126,7 +131,9 @@ function createHttpClient(opts) {
|
|
|
126
131
|
if (i >= retries || !transient || aborted) {
|
|
127
132
|
throw err;
|
|
128
133
|
}
|
|
129
|
-
await wait(
|
|
134
|
+
await wait(
|
|
135
|
+
RETRY_BASE_DELAY_MS * Math.pow(2, i) + Math.random() * RETRY_BASE_DELAY_MS
|
|
136
|
+
);
|
|
130
137
|
}
|
|
131
138
|
}
|
|
132
139
|
throw lastError;
|
|
@@ -175,7 +182,10 @@ function createPayPalStoreApi(opts) {
|
|
|
175
182
|
// per-order-id fallback is the correct idempotency scope.
|
|
176
183
|
"Idempotency-Key": generateIdempotencyKey()
|
|
177
184
|
},
|
|
178
|
-
body: JSON.stringify({
|
|
185
|
+
body: JSON.stringify({
|
|
186
|
+
cart_id: cartId,
|
|
187
|
+
is_card_payment: isCardPayment
|
|
188
|
+
})
|
|
179
189
|
});
|
|
180
190
|
},
|
|
181
191
|
captureOrder(cartId, orderId) {
|
|
@@ -221,7 +231,9 @@ function usePayPalConfig({
|
|
|
221
231
|
const hit = _cache.get(key);
|
|
222
232
|
const seedConfig = hit && Date.now() - hit.at < CACHE_TTL ? hit.config : null;
|
|
223
233
|
const [config, setConfig] = useState(seedConfig);
|
|
224
|
-
const [loading, setLoading] = useState(
|
|
234
|
+
const [loading, setLoading] = useState(
|
|
235
|
+
seedConfig === null && enabled
|
|
236
|
+
);
|
|
225
237
|
const [error, setError] = useState(null);
|
|
226
238
|
const fetchIdRef = useRef(0);
|
|
227
239
|
useEffect(() => {
|
|
@@ -252,7 +264,9 @@ function usePayPalConfig({
|
|
|
252
264
|
} catch (e) {
|
|
253
265
|
if (e instanceof Error && e.name === "AbortError") return;
|
|
254
266
|
if (!mounted || id !== fetchIdRef.current) return;
|
|
255
|
-
setError(
|
|
267
|
+
setError(
|
|
268
|
+
e instanceof Error ? e.message : "Failed to load PayPal config"
|
|
269
|
+
);
|
|
256
270
|
} finally {
|
|
257
271
|
if (mounted && id === fetchIdRef.current) setLoading(false);
|
|
258
272
|
}
|
|
@@ -282,7 +296,13 @@ function PayPalProvider(props) {
|
|
|
282
296
|
"disable-funding": disableFunding,
|
|
283
297
|
"data-partner-attribution-id": BN_CODE
|
|
284
298
|
};
|
|
285
|
-
}, [
|
|
299
|
+
}, [
|
|
300
|
+
config.client_id,
|
|
301
|
+
config.currency,
|
|
302
|
+
config.client_token,
|
|
303
|
+
intent,
|
|
304
|
+
disableFunding
|
|
305
|
+
]);
|
|
286
306
|
return /* @__PURE__ */ jsx(
|
|
287
307
|
PayPalScriptProvider,
|
|
288
308
|
{
|
|
@@ -297,10 +317,17 @@ function PayPalProvider(props) {
|
|
|
297
317
|
import { jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
298
318
|
function PayPalCurrencyNotice({ config }) {
|
|
299
319
|
if (config.currency_supported) return null;
|
|
300
|
-
return /* @__PURE__ */ jsxs(
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
320
|
+
return /* @__PURE__ */ jsxs(
|
|
321
|
+
"div",
|
|
322
|
+
{
|
|
323
|
+
role: "alert",
|
|
324
|
+
style: { padding: 12, border: "1px solid #ddd", borderRadius: 10 },
|
|
325
|
+
children: [
|
|
326
|
+
/* @__PURE__ */ jsx2("div", { style: { fontWeight: 600, marginBottom: 6 }, children: "PayPal currency issue" }),
|
|
327
|
+
/* @__PURE__ */ jsx2("ul", { style: { margin: 0, paddingLeft: 18 }, children: (config.currency_errors || []).map((e) => /* @__PURE__ */ jsx2("li", { children: e }, e)) })
|
|
328
|
+
]
|
|
329
|
+
}
|
|
330
|
+
);
|
|
304
331
|
}
|
|
305
332
|
|
|
306
333
|
// src/components/PayPalSmartButtons.tsx
|
|
@@ -476,7 +503,11 @@ function PayPalSmartButtons(props) {
|
|
|
476
503
|
showProcessingOverlay();
|
|
477
504
|
setError(null);
|
|
478
505
|
try {
|
|
479
|
-
const completeResult = await markPaymentComplete(
|
|
506
|
+
const completeResult = await markPaymentComplete(
|
|
507
|
+
baseUrl,
|
|
508
|
+
cartId,
|
|
509
|
+
publishableApiKey
|
|
510
|
+
);
|
|
480
511
|
clearCartCaptured(cartId);
|
|
481
512
|
await onPaid?.({ ...captured, ...completeResult });
|
|
482
513
|
setCompletionPending(false);
|
|
@@ -559,12 +590,34 @@ function PayPalSmartButtons(props) {
|
|
|
559
590
|
)
|
|
560
591
|
] }),
|
|
561
592
|
/* @__PURE__ */ jsxs2("div", { style: { textAlign: "center" }, children: [
|
|
562
|
-
/* @__PURE__ */ jsx3(
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
593
|
+
/* @__PURE__ */ jsx3(
|
|
594
|
+
"div",
|
|
595
|
+
{
|
|
596
|
+
style: {
|
|
597
|
+
fontSize: 18,
|
|
598
|
+
fontWeight: 600,
|
|
599
|
+
color: "#111827",
|
|
600
|
+
letterSpacing: "-0.01em"
|
|
601
|
+
},
|
|
602
|
+
children: "Processing your payment"
|
|
603
|
+
}
|
|
604
|
+
),
|
|
605
|
+
/* @__PURE__ */ jsxs2(
|
|
606
|
+
"div",
|
|
607
|
+
{
|
|
608
|
+
style: {
|
|
609
|
+
fontSize: 14,
|
|
610
|
+
color: "#6b7280",
|
|
611
|
+
marginTop: 6,
|
|
612
|
+
lineHeight: 1.5
|
|
613
|
+
},
|
|
614
|
+
children: [
|
|
615
|
+
"This may take a few moments. Please do not close",
|
|
616
|
+
/* @__PURE__ */ jsx3("br", {}),
|
|
617
|
+
"or refresh this page."
|
|
618
|
+
]
|
|
619
|
+
}
|
|
620
|
+
)
|
|
568
621
|
] }),
|
|
569
622
|
/* @__PURE__ */ jsx3(
|
|
570
623
|
"div",
|
|
@@ -711,68 +764,84 @@ function PayPalSmartButtons(props) {
|
|
|
711
764
|
]
|
|
712
765
|
}
|
|
713
766
|
),
|
|
714
|
-
isResolved && !completionPending && /* @__PURE__ */ jsx3(
|
|
715
|
-
|
|
767
|
+
isResolved && !completionPending && /* @__PURE__ */ jsx3(
|
|
768
|
+
"div",
|
|
716
769
|
{
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
shape: config.button_shape,
|
|
723
|
-
label: config.button_label,
|
|
724
|
-
height: config.button_height
|
|
725
|
-
},
|
|
726
|
-
createOrder: async () => {
|
|
727
|
-
if (processing) throw new Error("Payment already processing");
|
|
728
|
-
if (capturedRef.current) {
|
|
729
|
-
void finalizeCapturedPayment();
|
|
730
|
-
throw new Error("Your payment was already received \u2014 finalizing your order.");
|
|
731
|
-
}
|
|
732
|
-
setError(null);
|
|
733
|
-
setProcessing(true);
|
|
734
|
-
try {
|
|
735
|
-
const r = await api.createOrder(cartId);
|
|
736
|
-
return r.id;
|
|
737
|
-
} catch (e) {
|
|
738
|
-
setProcessing(false);
|
|
739
|
-
throw e;
|
|
740
|
-
}
|
|
770
|
+
style: buttonsReady ? void 0 : {
|
|
771
|
+
position: "absolute",
|
|
772
|
+
left: -9999,
|
|
773
|
+
opacity: 0,
|
|
774
|
+
pointerEvents: "none"
|
|
741
775
|
},
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
776
|
+
children: /* @__PURE__ */ jsx3(
|
|
777
|
+
PayPalButtons,
|
|
778
|
+
{
|
|
779
|
+
forceReRender: [config.currency, config.intent, cartId],
|
|
780
|
+
onInit: handleInit,
|
|
781
|
+
style: {
|
|
782
|
+
layout: "vertical",
|
|
783
|
+
color: config.button_color,
|
|
784
|
+
shape: config.button_shape,
|
|
785
|
+
label: config.button_label,
|
|
786
|
+
height: config.button_height
|
|
787
|
+
},
|
|
788
|
+
createOrder: async () => {
|
|
789
|
+
if (processing) throw new Error("Payment already processing");
|
|
790
|
+
if (capturedRef.current) {
|
|
791
|
+
void finalizeCapturedPayment();
|
|
792
|
+
throw new Error(
|
|
793
|
+
"Your payment was already received \u2014 finalizing your order."
|
|
794
|
+
);
|
|
795
|
+
}
|
|
796
|
+
setError(null);
|
|
797
|
+
setProcessing(true);
|
|
798
|
+
try {
|
|
799
|
+
const r = await api.createOrder(cartId);
|
|
800
|
+
return r.id;
|
|
801
|
+
} catch (e) {
|
|
802
|
+
setProcessing(false);
|
|
803
|
+
throw e;
|
|
804
|
+
}
|
|
805
|
+
},
|
|
806
|
+
onApprove: async (data) => {
|
|
807
|
+
try {
|
|
808
|
+
setProcessing(true);
|
|
809
|
+
showProcessingOverlay();
|
|
810
|
+
setError(null);
|
|
811
|
+
const orderId = String(data?.orderID || "");
|
|
812
|
+
if (!orderId)
|
|
813
|
+
throw new Error(
|
|
814
|
+
"PayPal order ID is missing from approval response"
|
|
815
|
+
);
|
|
816
|
+
const result = await api.captureOrder(cartId, orderId);
|
|
817
|
+
capturedRef.current = result || {};
|
|
818
|
+
markCartCaptured(cartId);
|
|
819
|
+
} catch (e) {
|
|
820
|
+
if (isNextRouterError(e)) return;
|
|
821
|
+
hideProcessingOverlay();
|
|
822
|
+
setProcessing(false);
|
|
823
|
+
const msg = e instanceof Error ? e.message : "Payment capture failed";
|
|
824
|
+
setError(msg);
|
|
825
|
+
onError?.(msg);
|
|
826
|
+
return;
|
|
827
|
+
}
|
|
828
|
+
await finalizeCapturedPayment();
|
|
829
|
+
},
|
|
830
|
+
onCancel: () => {
|
|
831
|
+
hideProcessingOverlay();
|
|
832
|
+
setProcessing(false);
|
|
833
|
+
},
|
|
834
|
+
onError: (err) => {
|
|
835
|
+
hideProcessingOverlay();
|
|
836
|
+
setProcessing(false);
|
|
837
|
+
const msg = err instanceof Error ? err.message : err?.message || "PayPal error";
|
|
838
|
+
setError(msg);
|
|
839
|
+
onError?.(msg);
|
|
840
|
+
}
|
|
760
841
|
}
|
|
761
|
-
|
|
762
|
-
},
|
|
763
|
-
onCancel: () => {
|
|
764
|
-
hideProcessingOverlay();
|
|
765
|
-
setProcessing(false);
|
|
766
|
-
},
|
|
767
|
-
onError: (err) => {
|
|
768
|
-
hideProcessingOverlay();
|
|
769
|
-
setProcessing(false);
|
|
770
|
-
const msg = err instanceof Error ? err.message : err?.message || "PayPal error";
|
|
771
|
-
setError(msg);
|
|
772
|
-
onError?.(msg);
|
|
773
|
-
}
|
|
842
|
+
)
|
|
774
843
|
}
|
|
775
|
-
)
|
|
844
|
+
),
|
|
776
845
|
completionPending && /* @__PURE__ */ jsx3(
|
|
777
846
|
"button",
|
|
778
847
|
{
|
|
@@ -979,7 +1048,11 @@ function PayPalAdvancedCard(props) {
|
|
|
979
1048
|
showProcessingOverlay();
|
|
980
1049
|
setError(null);
|
|
981
1050
|
try {
|
|
982
|
-
const completeResult = await markPaymentComplete(
|
|
1051
|
+
const completeResult = await markPaymentComplete(
|
|
1052
|
+
baseUrl,
|
|
1053
|
+
cartId,
|
|
1054
|
+
publishableApiKey
|
|
1055
|
+
);
|
|
983
1056
|
clearCartCaptured(cartId);
|
|
984
1057
|
await onPaid?.({ ...captured, ...completeResult });
|
|
985
1058
|
setCompletionPending(false);
|
|
@@ -1139,12 +1212,34 @@ function PayPalAdvancedCard(props) {
|
|
|
1139
1212
|
)
|
|
1140
1213
|
] }),
|
|
1141
1214
|
/* @__PURE__ */ jsxs3("div", { style: { textAlign: "center" }, children: [
|
|
1142
|
-
/* @__PURE__ */ jsx4(
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1215
|
+
/* @__PURE__ */ jsx4(
|
|
1216
|
+
"div",
|
|
1217
|
+
{
|
|
1218
|
+
style: {
|
|
1219
|
+
fontSize: 18,
|
|
1220
|
+
fontWeight: 600,
|
|
1221
|
+
color: "#111827",
|
|
1222
|
+
letterSpacing: "-0.01em"
|
|
1223
|
+
},
|
|
1224
|
+
children: "Processing your payment"
|
|
1225
|
+
}
|
|
1226
|
+
),
|
|
1227
|
+
/* @__PURE__ */ jsxs3(
|
|
1228
|
+
"div",
|
|
1229
|
+
{
|
|
1230
|
+
style: {
|
|
1231
|
+
fontSize: 14,
|
|
1232
|
+
color: "#6b7280",
|
|
1233
|
+
marginTop: 6,
|
|
1234
|
+
lineHeight: 1.5
|
|
1235
|
+
},
|
|
1236
|
+
children: [
|
|
1237
|
+
"This may take a few moments. Please do not close",
|
|
1238
|
+
/* @__PURE__ */ jsx4("br", {}),
|
|
1239
|
+
"or refresh this page."
|
|
1240
|
+
]
|
|
1241
|
+
}
|
|
1242
|
+
)
|
|
1148
1243
|
] }),
|
|
1149
1244
|
/* @__PURE__ */ jsx4(
|
|
1150
1245
|
"div",
|
|
@@ -1179,10 +1274,13 @@ function PayPalAdvancedCard(props) {
|
|
|
1179
1274
|
{
|
|
1180
1275
|
style: cardStyle,
|
|
1181
1276
|
createOrder: async () => {
|
|
1182
|
-
if (creatingOrderRef.current)
|
|
1277
|
+
if (creatingOrderRef.current)
|
|
1278
|
+
throw new Error("Payment already processing");
|
|
1183
1279
|
if (capturedRef.current) {
|
|
1184
1280
|
void finalizeCapturedPayment();
|
|
1185
|
-
throw new Error(
|
|
1281
|
+
throw new Error(
|
|
1282
|
+
"Your payment was already received \u2014 finalizing your order."
|
|
1283
|
+
);
|
|
1186
1284
|
}
|
|
1187
1285
|
creatingOrderRef.current = true;
|
|
1188
1286
|
try {
|
|
@@ -1199,7 +1297,10 @@ function PayPalAdvancedCard(props) {
|
|
|
1199
1297
|
setError(null);
|
|
1200
1298
|
showProcessingOverlay();
|
|
1201
1299
|
const orderId = String(data?.orderID || "");
|
|
1202
|
-
if (!orderId)
|
|
1300
|
+
if (!orderId)
|
|
1301
|
+
throw new Error(
|
|
1302
|
+
"PayPal order ID is missing from approval response"
|
|
1303
|
+
);
|
|
1203
1304
|
const result = await api.captureOrder(cartId, orderId);
|
|
1204
1305
|
capturedRef.current = result || {};
|
|
1205
1306
|
markCartCaptured(cartId);
|
|
@@ -1258,7 +1359,13 @@ function PayPalAdvancedCard(props) {
|
|
|
1258
1359
|
/* @__PURE__ */ jsxs3("span", { children: [
|
|
1259
1360
|
"Sandbox mode \u2014 use test card",
|
|
1260
1361
|
" ",
|
|
1261
|
-
/* @__PURE__ */ jsx4(
|
|
1362
|
+
/* @__PURE__ */ jsx4(
|
|
1363
|
+
"strong",
|
|
1364
|
+
{
|
|
1365
|
+
style: { fontFamily: "monospace", letterSpacing: "0.05em" },
|
|
1366
|
+
children: "4111 1111 1111 1111"
|
|
1367
|
+
}
|
|
1368
|
+
),
|
|
1262
1369
|
" ",
|
|
1263
1370
|
"with any future date and any CVV."
|
|
1264
1371
|
] })
|
|
@@ -1660,7 +1767,9 @@ function usePayPalPaymentMethods({
|
|
|
1660
1767
|
const key = cacheKey2(baseUrl, cartId);
|
|
1661
1768
|
const hit = _cache2.get(key);
|
|
1662
1769
|
const seed = hit && Date.now() - hit.at < CACHE_TTL2 ? hit.result : null;
|
|
1663
|
-
const [result, setResult] = useState4(
|
|
1770
|
+
const [result, setResult] = useState4(
|
|
1771
|
+
seed ?? { ...DEFAULT_RESULT, loading: enabled }
|
|
1772
|
+
);
|
|
1664
1773
|
const fetchIdRef = useRef4(0);
|
|
1665
1774
|
useEffect3(() => {
|
|
1666
1775
|
if (!enabled) {
|