@easypayment/medusa-paypal-ui 1.0.9 → 1.0.11
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 +191 -53
- package/dist/index.cjs +67 -24
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +19 -1
- package/dist/index.d.ts +19 -1
- package/dist/index.mjs +68 -25
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/adapters/MedusaNextPayPalAdapter.tsx +45 -7
- package/src/client/http.ts +10 -0
- package/src/client/types.ts +8 -0
- package/src/components/PayPalProvider.tsx +4 -2
- package/src/components/PayPalSmartButtons.tsx +9 -3
package/README.md
CHANGED
|
@@ -1,53 +1,191 @@
|
|
|
1
|
-
# @easypayment/medusa-paypal-ui —
|
|
2
|
-
|
|
3
|
-
Fixes included:
|
|
4
|
-
- Card Fields: uses `cardFieldsForm.submit()` (typed)
|
|
5
|
-
- Card Fields: `PayPalCardFieldsProvider` includes required `onError`
|
|
6
|
-
- Build: ESM outputs `dist/index.mjs` to match `package.json` exports
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
|
|
1
|
+
# @easypayment/medusa-paypal-ui — v1.0.9
|
|
2
|
+
|
|
3
|
+
Fixes included in this release:
|
|
4
|
+
- Card Fields: uses `cardFieldsForm.submit()` (typed)
|
|
5
|
+
- Card Fields: `PayPalCardFieldsProvider` includes required `onError`
|
|
6
|
+
- Build: ESM outputs `dist/index.mjs` to match `package.json` exports
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## Install
|
|
11
|
+
|
|
12
|
+
In your storefront `package.json`:
|
|
13
|
+
|
|
14
|
+
```json
|
|
15
|
+
{
|
|
16
|
+
"dependencies": {
|
|
17
|
+
"@easypayment/medusa-paypal-ui": "^1.0.9",
|
|
18
|
+
"@paypal/react-paypal-js": "^8.8.0"
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Then:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
npm i
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## Build (monorepo only)
|
|
32
|
+
|
|
33
|
+
If you are working inside a monorepo that includes the package source, build it before running the storefront:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
cd packages/medusa-paypal-ui
|
|
37
|
+
npm run build
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
> The build outputs ESM to `dist/index.mjs`, which matches the `package.json` `exports` field.
|
|
41
|
+
> If you see a module-not-found error at runtime, confirm the build has been run.
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## Use in Medusa Next.js checkout
|
|
46
|
+
|
|
47
|
+
### Recommended: `MedusaNextPayPalAdapter`
|
|
48
|
+
|
|
49
|
+
The adapter handles PayPal authorization and capture. Your storefront is responsible for initiating the payment session and placing the order after a successful payment.
|
|
50
|
+
|
|
51
|
+
```tsx
|
|
52
|
+
import { MedusaNextPayPalAdapter } from "@easypayment/medusa-paypal-ui"
|
|
53
|
+
import { initiatePaymentSession, placeOrder } from "@lib/data/cart"
|
|
54
|
+
|
|
55
|
+
// 1. Call initiatePaymentSession() when the user selects PayPal,
|
|
56
|
+
// then render the adapter:
|
|
57
|
+
|
|
58
|
+
<MedusaNextPayPalAdapter
|
|
59
|
+
cartId={cart.id}
|
|
60
|
+
selectedProviderId={selectedProviderId}
|
|
61
|
+
baseUrl={process.env.NEXT_PUBLIC_MEDUSA_BACKEND_URL!}
|
|
62
|
+
publishableApiKey={process.env.NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY}
|
|
63
|
+
onSuccess={() => placeOrder(cart.id)}
|
|
64
|
+
onError={(msg) => setError(msg)}
|
|
65
|
+
/>
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Props
|
|
69
|
+
|
|
70
|
+
| Prop | Type | Required | Description |
|
|
71
|
+
|---|---|---|---|
|
|
72
|
+
| `cartId` | `string` | ✅ | The active Medusa cart ID |
|
|
73
|
+
| `selectedProviderId` | `string` | ✅ | The provider ID selected by the user |
|
|
74
|
+
| `baseUrl` | `string` | ✅ | Your Medusa backend URL (`NEXT_PUBLIC_MEDUSA_BACKEND_URL`) |
|
|
75
|
+
| `publishableApiKey` | `string` | — | Medusa publishable API key (`NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY`) |
|
|
76
|
+
| `providerIds` | `{ paypal: string, paypalCard: string }` | — | Override default provider IDs (see below) |
|
|
77
|
+
| `onSuccess` | `() => void` | — | Called after successful payment; use to call `placeOrder()` |
|
|
78
|
+
| `onError` | `(msg: string) => void` | — | Called on failure; use to surface the error in your UI |
|
|
79
|
+
|
|
80
|
+
### `onSuccess` vs `onPaid`
|
|
81
|
+
|
|
82
|
+
Earlier examples used `onPaid={() => window.location.reload()}`. The recommended pattern is `onSuccess` with an explicit `placeOrder()` call so the Medusa order is properly recorded before any redirect:
|
|
83
|
+
|
|
84
|
+
```tsx
|
|
85
|
+
// ✅ Recommended
|
|
86
|
+
onSuccess={() => placeOrder(cart.id)}
|
|
87
|
+
onError={(msg) => setError(msg)}
|
|
88
|
+
|
|
89
|
+
// ⚠️ Avoid — skips placeOrder, relies on a page reload
|
|
90
|
+
onPaid={() => window.location.reload()}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
## Important: Provider IDs must match
|
|
96
|
+
|
|
97
|
+
The `providerIds` prop defaults to:
|
|
98
|
+
|
|
99
|
+
```ts
|
|
100
|
+
providerIds={{ paypal: "pp_paypal_paypal", paypalCard: "pp_paypal_card_paypal_card" }}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
These IDs are generated by Medusa from the `id` values you set in `medusa-config.ts`:
|
|
104
|
+
|
|
105
|
+
```ts
|
|
106
|
+
// medusa-config.ts — keep id values as "paypal" and "paypal_card"
|
|
107
|
+
{ resolve: "@easypayment/medusa-paypal/providers/paypal", id: "paypal" }
|
|
108
|
+
{ resolve: "@easypayment/medusa-paypal/providers/paypal_card", id: "paypal_card" }
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
| `medusa-config.ts` id | Generated provider ID |
|
|
112
|
+
|---|---|
|
|
113
|
+
| `"paypal"` | `"pp_paypal_paypal"` |
|
|
114
|
+
| `"paypal_card"` | `"pp_paypal_card_paypal_card"` |
|
|
115
|
+
|
|
116
|
+
If you change the `id` values, pass the resulting IDs explicitly to the adapter:
|
|
117
|
+
|
|
118
|
+
```tsx
|
|
119
|
+
<MedusaNextPayPalAdapter
|
|
120
|
+
...
|
|
121
|
+
providerIds={{ paypal: "pp_custom_paypal", paypalCard: "pp_custom_card" }}
|
|
122
|
+
/>
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Also update the `PAYPAL_IDS` constant in your checkout component to match:
|
|
126
|
+
|
|
127
|
+
```ts
|
|
128
|
+
const PAYPAL_IDS = ["pp_custom_paypal", "pp_custom_card"]
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
---
|
|
132
|
+
|
|
133
|
+
## Integrating with the checkout Payment step
|
|
134
|
+
|
|
135
|
+
The adapter works alongside your existing Stripe / gift-card logic. A minimal integration pattern for `payment/index.tsx`:
|
|
136
|
+
|
|
137
|
+
```tsx
|
|
138
|
+
import { initiatePaymentSession, placeOrder } from "@lib/data/cart"
|
|
139
|
+
import { MedusaNextPayPalAdapter } from "@easypayment/medusa-paypal-ui"
|
|
140
|
+
|
|
141
|
+
const PAYPAL_IDS = ["pp_paypal_paypal", "pp_paypal_card_paypal_card"]
|
|
142
|
+
const isPayPal = (id: string) => PAYPAL_IDS.includes(id)
|
|
143
|
+
|
|
144
|
+
// Inside setPaymentMethod — initiate session immediately on selection
|
|
145
|
+
const setPaymentMethod = async (method: string) => {
|
|
146
|
+
setSelectedPaymentMethod(method)
|
|
147
|
+
if (isStripeLike(method) || isPayPal(method)) {
|
|
148
|
+
await initiatePaymentSession(cart, { provider_id: method })
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// Inside JSX — render adapter when PayPal is selected
|
|
153
|
+
{isPayPal(selectedPaymentMethod) && (
|
|
154
|
+
<MedusaNextPayPalAdapter
|
|
155
|
+
cartId={cart.id}
|
|
156
|
+
selectedProviderId={selectedPaymentMethod}
|
|
157
|
+
baseUrl={process.env.NEXT_PUBLIC_MEDUSA_BACKEND_URL!}
|
|
158
|
+
publishableApiKey={process.env.NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY}
|
|
159
|
+
onSuccess={() => placeOrder(cart.id)}
|
|
160
|
+
onError={(msg) => setError(msg)}
|
|
161
|
+
/>
|
|
162
|
+
)}
|
|
163
|
+
|
|
164
|
+
// Disable the standard Continue button when PayPal is active
|
|
165
|
+
disabled={
|
|
166
|
+
(isStripeLike(selectedPaymentMethod) && !cardComplete) ||
|
|
167
|
+
(!selectedPaymentMethod && !paidByGiftcard) ||
|
|
168
|
+
isPayPal(selectedPaymentMethod)
|
|
169
|
+
}
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
---
|
|
173
|
+
|
|
174
|
+
## Environment Variables
|
|
175
|
+
|
|
176
|
+
Both variables must be set in `.env.local` (or your deployment environment):
|
|
177
|
+
|
|
178
|
+
```bash
|
|
179
|
+
NEXT_PUBLIC_MEDUSA_BACKEND_URL=https://your-medusa-api.example.com
|
|
180
|
+
NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY=pk_xxxxxxxxxxxxxxxxxxxxxxxx
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
> ⚠️ Never place secret keys (`sk_...`) in `NEXT_PUBLIC_` variables — they are bundled into client-side JavaScript.
|
|
184
|
+
|
|
185
|
+
---
|
|
186
|
+
|
|
187
|
+
## Tests
|
|
188
|
+
|
|
189
|
+
```bash
|
|
190
|
+
npm test
|
|
191
|
+
```
|
package/dist/index.cjs
CHANGED
|
@@ -31,6 +31,16 @@ function createHttpClient(opts) {
|
|
|
31
31
|
const res = await fetch(url, { ...init, headers, credentials: "include" });
|
|
32
32
|
const text = await res.text().catch(() => "");
|
|
33
33
|
if (!res.ok) {
|
|
34
|
+
if (res.status === 401) {
|
|
35
|
+
throw new Error(
|
|
36
|
+
"[PayPal] Unauthorized (401) \u2014 check that your publishable API key is correct and set in NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY"
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
if (res.status === 403) {
|
|
40
|
+
throw new Error(
|
|
41
|
+
"[PayPal] Forbidden (403) \u2014 this request is not allowed. Check your CORS and API key settings."
|
|
42
|
+
);
|
|
43
|
+
}
|
|
34
44
|
throw new Error(text || `Request failed (${res.status})`);
|
|
35
45
|
}
|
|
36
46
|
if (!text) return {};
|
|
@@ -114,7 +124,7 @@ function usePayPalConfig({ baseUrl, publishableApiKey, cartId, enabled = true })
|
|
|
114
124
|
return { config, loading, error };
|
|
115
125
|
}
|
|
116
126
|
function PayPalProvider(props) {
|
|
117
|
-
const { config, intent = "capture", children } = props;
|
|
127
|
+
const { config, intent = "capture", disableFunding, children } = props;
|
|
118
128
|
const options = react.useMemo(() => {
|
|
119
129
|
return {
|
|
120
130
|
clientId: config.client_id,
|
|
@@ -122,9 +132,10 @@ function PayPalProvider(props) {
|
|
|
122
132
|
currency: config.currency,
|
|
123
133
|
intent,
|
|
124
134
|
components: config.client_token ? "buttons,card-fields" : "buttons",
|
|
125
|
-
"data-client-token": config.client_token || void 0
|
|
135
|
+
"data-client-token": config.client_token || void 0,
|
|
136
|
+
"disable-funding": disableFunding
|
|
126
137
|
};
|
|
127
|
-
}, [config, intent]);
|
|
138
|
+
}, [config, intent, disableFunding]);
|
|
128
139
|
return /* @__PURE__ */ jsxRuntime.jsx(reactPaypalJs.PayPalScriptProvider, { options, children });
|
|
129
140
|
}
|
|
130
141
|
function PayPalCurrencyNotice({ config }) {
|
|
@@ -146,7 +157,13 @@ function PayPalSmartButtons(props) {
|
|
|
146
157
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
147
158
|
reactPaypalJs.PayPalButtons,
|
|
148
159
|
{
|
|
149
|
-
style: {
|
|
160
|
+
style: {
|
|
161
|
+
layout: "vertical",
|
|
162
|
+
color: config.button_color,
|
|
163
|
+
shape: config.button_shape,
|
|
164
|
+
label: config.button_label,
|
|
165
|
+
height: config.button_height
|
|
166
|
+
},
|
|
150
167
|
createOrder: async () => {
|
|
151
168
|
setError(null);
|
|
152
169
|
const r = await api.createOrder(cartId);
|
|
@@ -159,7 +176,7 @@ function PayPalSmartButtons(props) {
|
|
|
159
176
|
const result = await api.captureOrder(cartId, orderId);
|
|
160
177
|
onPaid?.(result);
|
|
161
178
|
} catch (e) {
|
|
162
|
-
const msg = e
|
|
179
|
+
const msg = e instanceof Error ? e.message : "Payment capture failed";
|
|
163
180
|
setError(msg);
|
|
164
181
|
onError?.(msg);
|
|
165
182
|
}
|
|
@@ -243,7 +260,16 @@ function PayPalAdvancedCard(props) {
|
|
|
243
260
|
var DEFAULT_PAYPAL_PROVIDER_ID = "pp_paypal_paypal";
|
|
244
261
|
var DEFAULT_PAYPAL_CARD_PROVIDER_ID = "pp_paypal_card_paypal_card";
|
|
245
262
|
function MedusaNextPayPalAdapter(props) {
|
|
246
|
-
const {
|
|
263
|
+
const {
|
|
264
|
+
cartId,
|
|
265
|
+
selectedProviderId,
|
|
266
|
+
baseUrl,
|
|
267
|
+
publishableApiKey,
|
|
268
|
+
providerIds,
|
|
269
|
+
onSuccess,
|
|
270
|
+
onError,
|
|
271
|
+
onPaid
|
|
272
|
+
} = props;
|
|
247
273
|
const paypalProviderId = providerIds?.paypal || DEFAULT_PAYPAL_PROVIDER_ID;
|
|
248
274
|
const paypalCardProviderId = providerIds?.paypalCard || DEFAULT_PAYPAL_CARD_PROVIDER_ID;
|
|
249
275
|
const shouldRender = selectedProviderId === paypalProviderId || selectedProviderId === paypalCardProviderId;
|
|
@@ -253,33 +279,50 @@ function MedusaNextPayPalAdapter(props) {
|
|
|
253
279
|
cartId,
|
|
254
280
|
enabled: shouldRender
|
|
255
281
|
});
|
|
282
|
+
const handlePaid = react.useCallback(
|
|
283
|
+
(captureResult) => {
|
|
284
|
+
onPaid?.(captureResult);
|
|
285
|
+
onSuccess?.(cartId);
|
|
286
|
+
},
|
|
287
|
+
[cartId, onPaid, onSuccess]
|
|
288
|
+
);
|
|
256
289
|
if (!shouldRender) return null;
|
|
257
290
|
if (loading) return /* @__PURE__ */ jsxRuntime.jsx("div", { children: "Loading PayPal\u2026" });
|
|
258
291
|
if (error) return /* @__PURE__ */ jsxRuntime.jsx("div", { style: { color: "crimson" }, children: error });
|
|
259
292
|
if (!config) return null;
|
|
293
|
+
if (config.paypal_enabled === false) return null;
|
|
294
|
+
const disableFunding = Array.isArray(config.disable_buttons) ? config.disable_buttons.join(",") : void 0;
|
|
260
295
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "grid", gap: 12 }, children: [
|
|
261
296
|
/* @__PURE__ */ jsxRuntime.jsx(PayPalCurrencyNotice, { config }),
|
|
262
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
263
|
-
|
|
264
|
-
{
|
|
265
|
-
baseUrl,
|
|
266
|
-
publishableApiKey,
|
|
267
|
-
cartId,
|
|
268
|
-
config,
|
|
269
|
-
onPaid,
|
|
270
|
-
onError
|
|
271
|
-
}
|
|
272
|
-
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
273
|
-
PayPalSmartButtons,
|
|
297
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
298
|
+
PayPalProvider,
|
|
274
299
|
{
|
|
275
|
-
baseUrl,
|
|
276
|
-
publishableApiKey,
|
|
277
|
-
cartId,
|
|
278
300
|
config,
|
|
279
|
-
|
|
280
|
-
|
|
301
|
+
intent: config.intent === "authorize" ? "authorize" : "capture",
|
|
302
|
+
disableFunding,
|
|
303
|
+
children: selectedProviderId === paypalCardProviderId ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
304
|
+
PayPalAdvancedCard,
|
|
305
|
+
{
|
|
306
|
+
baseUrl,
|
|
307
|
+
publishableApiKey,
|
|
308
|
+
cartId,
|
|
309
|
+
config,
|
|
310
|
+
onPaid: handlePaid,
|
|
311
|
+
onError
|
|
312
|
+
}
|
|
313
|
+
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
314
|
+
PayPalSmartButtons,
|
|
315
|
+
{
|
|
316
|
+
baseUrl,
|
|
317
|
+
publishableApiKey,
|
|
318
|
+
cartId,
|
|
319
|
+
config,
|
|
320
|
+
onPaid: handlePaid,
|
|
321
|
+
onError
|
|
322
|
+
}
|
|
323
|
+
)
|
|
281
324
|
}
|
|
282
|
-
)
|
|
325
|
+
)
|
|
283
326
|
] });
|
|
284
327
|
}
|
|
285
328
|
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/client/http.ts","../src/client/paypal.ts","../src/hooks/usePayPalConfig.ts","../src/components/PayPalProvider.tsx","../src/components/PayPalCurrencyNotice.tsx","../src/components/PayPalSmartButtons.tsx","../src/components/PayPalAdvancedCard.tsx","../src/adapters/MedusaNextPayPalAdapter.tsx"],"names":["useMemo","useState","useEffect","jsx","PayPalScriptProvider","jsxs","PayPalButtons","usePayPalCardFields","PayPalCardFieldsProvider","PayPalNameField","PayPalNumberField","PayPalExpiryField","PayPalCVVField"],"mappings":"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","file":"index.cjs","sourcesContent":["export type HttpOptions = {\r\n baseUrl: string\r\n publishableApiKey?: string\r\n}\r\n\r\nfunction toHeaderRecord(headers?: RequestInit[\"headers\"]): Record<string, string> {\r\n if (!headers) {\r\n return {}\r\n }\r\n\r\n if (headers instanceof Headers) {\r\n return Object.fromEntries(headers.entries())\r\n }\r\n\r\n if (Array.isArray(headers)) {\r\n return Object.fromEntries(headers)\r\n }\r\n\r\n return { ...headers }\r\n}\r\n\r\nexport function createHttpClient(opts: HttpOptions) {\r\n const base = opts.baseUrl.replace(/\\/+$/, \"\")\r\n\r\n async function request<T>(path: string, init?: RequestInit): Promise<T> {\r\n const url = `${base}${path.startsWith(\"/\") ? \"\" : \"/\"}${path}`\r\n const headers: Record<string, string> = {\r\n Accept: \"application/json\",\r\n ...toHeaderRecord(init?.headers),\r\n }\r\n\r\n if (opts.publishableApiKey) {\r\n headers[\"x-publishable-api-key\"] = opts.publishableApiKey\r\n }\r\n\r\n const res = await fetch(url, { ...init, headers, credentials: \"include\" })\r\n const text = await res.text().catch(() => \"\")\r\n\r\n if (!res.ok) {\r\n throw new Error(text || `Request failed (${res.status})`)\r\n }\r\n if (!text) return {} as T\r\n\r\n const contentType = res.headers.get(\"content-type\") || \"\"\r\n if (!contentType.includes(\"application/json\")) {\r\n console.warn(\"[PayPal] Unexpected non-JSON response:\", contentType, text.slice(0, 200))\r\n return {} as T\r\n }\r\n\r\n try {\r\n return JSON.parse(text) as T\r\n } catch {\r\n console.warn(\"[PayPal] Failed to parse JSON response:\", text.slice(0, 200))\r\n return {} as T\r\n }\r\n }\r\n\r\n return { request }\r\n}\r\n","import type { PayPalConfig, PayPalSettingsResponse } from \"./types\"\r\nimport { createHttpClient, type HttpOptions } from \"./http\"\r\n\r\nexport function createPayPalStoreApi(opts: HttpOptions) {\r\n const http = createHttpClient(opts)\r\n\r\n return {\r\n getConfig(cartId?: string, signal?: AbortSignal) {\r\n const q = cartId ? `?cart_id=${encodeURIComponent(cartId)}` : \"\"\r\n return http.request<PayPalConfig>(`/store/paypal/config${q}`, { signal })\r\n },\r\n\r\n getSettings() {\r\n return http.request<PayPalSettingsResponse>(`/store/paypal/settings`)\r\n },\r\n\r\n createOrder(cartId: string) {\r\n return http.request<{ id: string }>(`/store/paypal/create-order`, {\r\n method: \"POST\",\r\n headers: { \"Content-Type\": \"application/json\" },\r\n body: JSON.stringify({ cart_id: cartId }),\r\n })\r\n },\r\n\r\n captureOrder(cartId: string, orderId: string) {\r\n return http.request<Record<string, unknown>>(`/store/paypal/capture-order`, {\r\n method: \"POST\",\r\n headers: { \"Content-Type\": \"application/json\" },\r\n body: JSON.stringify({ cart_id: cartId, order_id: orderId }),\r\n })\r\n },\r\n }\r\n}\r\n","import { useEffect, useMemo, useState } from \"react\"\r\nimport { createPayPalStoreApi } from \"../client/paypal\"\r\nimport type { PayPalConfig } from \"../client/types\"\r\n\r\ntype Args = {\r\n baseUrl: string\r\n publishableApiKey?: string\r\n cartId?: string\r\n enabled?: boolean\r\n}\r\n\r\nexport function usePayPalConfig({ baseUrl, publishableApiKey, cartId, enabled = true }: Args) {\r\n const api = useMemo(\r\n () => createPayPalStoreApi({ baseUrl, publishableApiKey }),\r\n [baseUrl, publishableApiKey]\r\n )\r\n\r\n const [config, setConfig] = useState<PayPalConfig | null>(null)\r\n const [loading, setLoading] = useState(false)\r\n const [error, setError] = useState<string | null>(null)\r\n\r\n useEffect(() => {\r\n if (!enabled) {\r\n setLoading(false)\r\n setError(null)\r\n setConfig(null)\r\n return\r\n }\r\n\r\n let mounted = true\r\n const controller = new AbortController()\r\n ;(async () => {\r\n try {\r\n setLoading(true)\r\n setError(null)\r\n const cfg = await api.getConfig(cartId, controller.signal)\r\n if (mounted) setConfig(cfg)\r\n } catch (e: any) {\r\n if (e?.name === \"AbortError\") return\r\n if (mounted) setError(e?.message || \"Failed to load PayPal config\")\r\n } finally {\r\n if (mounted) setLoading(false)\r\n }\r\n })()\r\n\r\n return () => {\r\n mounted = false\r\n controller.abort()\r\n }\r\n }, [api, cartId, enabled])\r\n\r\n return { config, loading, error }\r\n}\r\n","\"use client\"\r\n\r\nimport React, { useMemo } from \"react\"\r\nimport { PayPalScriptProvider } from \"@paypal/react-paypal-js\"\r\nimport type { ReactPayPalScriptOptions } from \"@paypal/react-paypal-js\"\r\nimport type { PayPalConfig } from \"../client/types\"\r\n\r\nexport function PayPalProvider(props: {\r\n config: PayPalConfig\r\n intent?: \"capture\" | \"authorize\"\r\n children: React.ReactNode\r\n}) {\r\n const { config, intent = \"capture\", children } = props\r\n\r\n const options = useMemo((): ReactPayPalScriptOptions => {\r\n return {\r\n clientId: config.client_id,\r\n \"client-id\": config.client_id,\r\n currency: config.currency,\r\n intent,\r\n components: config.client_token ? \"buttons,card-fields\" : \"buttons\",\r\n \"data-client-token\": config.client_token || undefined,\r\n }\r\n }, [config, intent])\r\n\r\n return <PayPalScriptProvider options={options}>{children}</PayPalScriptProvider>\r\n}\r\n","\"use client\"\n\nimport React from \"react\"\nimport type { PayPalConfig } from \"../client/types\"\n\nexport function PayPalCurrencyNotice({ config }: { config: PayPalConfig }) {\n if (config.currency_supported) return null\n\n return (\n <div style={{ padding: 12, border: \"1px solid #ddd\", borderRadius: 10 }}>\n <div style={{ fontWeight: 600, marginBottom: 6 }}>PayPal currency issue</div>\n <ul style={{ margin: 0, paddingLeft: 18 }}>\n {(config.currency_errors || []).map((e, i) => (\n <li key={i}>{e}</li>\n ))}\n </ul>\n </div>\n )\n}\n","\"use client\"\r\n\r\nimport React, { useMemo, useState } from \"react\"\r\nimport { PayPalButtons } from \"@paypal/react-paypal-js\"\r\nimport { createPayPalStoreApi } from \"../client/paypal\"\r\nimport type { PayPalConfig } from \"../client/types\"\r\n\r\nexport function PayPalSmartButtons(props: {\r\n baseUrl: string\r\n publishableApiKey?: string\r\n cartId: string\r\n config: PayPalConfig\r\n onPaid?: (result: Record<string, unknown>) => void\r\n onError?: (message: string) => void\r\n}) {\r\n const { baseUrl, publishableApiKey, cartId, config, onPaid, onError } = props\r\n const api = useMemo(\r\n () => createPayPalStoreApi({ baseUrl, publishableApiKey }),\r\n [baseUrl, publishableApiKey]\r\n )\r\n\r\n const [error, setError] = useState<string | null>(null)\r\n\r\n if (!config.currency_supported) return null\r\n\r\n return (\r\n <div>\r\n <PayPalButtons\r\n style={{ layout: \"vertical\" }}\r\n createOrder={async () => {\r\n setError(null)\r\n const r = await api.createOrder(cartId)\r\n return r.id\r\n }}\r\n onApprove={async (data: { orderID?: string }) => {\r\n try {\r\n setError(null)\r\n const orderId = String(data?.orderID || \"\")\r\n const result = await api.captureOrder(cartId, orderId)\r\n onPaid?.(result)\r\n } catch (e: any) {\r\n const msg = e?.message || \"Payment capture failed\"\r\n setError(msg)\r\n onError?.(msg)\r\n }\r\n }}\r\n onError={(err: Error | { message?: string }) => {\r\n const msg = err instanceof Error ? err.message : err?.message || \"PayPal error\"\r\n setError(msg)\r\n onError?.(msg)\r\n }}\r\n />\r\n {error ? <div style={{ marginTop: 10, color: \"crimson\" }}>{error}</div> : null}\r\n </div>\r\n )\r\n}\r\n","\"use client\"\r\n\r\nimport React, { useMemo, useState } from \"react\"\r\nimport {\r\n PayPalCardFieldsProvider,\r\n PayPalNameField,\r\n PayPalNumberField,\r\n PayPalExpiryField,\r\n PayPalCVVField,\r\n usePayPalCardFields,\r\n} from \"@paypal/react-paypal-js\"\r\nimport { createPayPalStoreApi } from \"../client/paypal\"\r\nimport type { PayPalConfig } from \"../client/types\"\r\n\r\nfunction SubmitButton({ disabled, label }: { disabled: boolean; label: string }) {\r\n const { cardFieldsForm } = usePayPalCardFields()\r\n\r\n return (\r\n <button\r\n type=\"button\"\r\n disabled={disabled || !cardFieldsForm}\r\n onClick={() => cardFieldsForm?.submit()}\r\n style={{ padding: \"10px 12px\", borderRadius: 10, border: \"1px solid #ddd\" }}\r\n >\r\n {label}\r\n </button>\r\n )\r\n}\r\n\r\nexport function PayPalAdvancedCard(props: {\r\n baseUrl: string\r\n publishableApiKey?: string\r\n cartId: string\r\n config: PayPalConfig\r\n onPaid?: (result: Record<string, unknown>) => void\r\n onError?: (message: string) => void\r\n}) {\r\n const { baseUrl, publishableApiKey, cartId, config, onPaid, onError } = props\r\n const api = useMemo(\r\n () => createPayPalStoreApi({ baseUrl, publishableApiKey }),\r\n [baseUrl, publishableApiKey]\r\n )\r\n\r\n const [error, setError] = useState<string | null>(null)\r\n const [submitting, setSubmitting] = useState(false)\r\n\r\n if (!config.currency_supported) return null\r\n\r\n if (!config.client_token) {\r\n return (\r\n <div style={{ padding: 12, border: \"1px solid #ddd\", borderRadius: 10 }}>\r\n CardFields unavailable: missing client_token from backend.\r\n </div>\r\n )\r\n }\r\n\r\n return (\r\n <PayPalCardFieldsProvider\r\n createOrder={async () => {\r\n setError(null)\r\n const r = await api.createOrder(cartId)\r\n return r.id\r\n }}\r\n onApprove={async (data: { orderID?: string }) => {\r\n try {\r\n setSubmitting(true)\r\n setError(null)\r\n const orderId = String(data?.orderID || \"\")\r\n const result = await api.captureOrder(cartId, orderId)\r\n onPaid?.(result)\r\n } catch (e: unknown) {\r\n const msg = e instanceof Error ? e.message : \"Card payment failed\"\r\n setError(msg)\r\n onError?.(msg)\r\n } finally {\r\n setSubmitting(false)\r\n }\r\n }}\r\n onError={(e: Error | { message?: string }) => {\r\n const msg = e instanceof Error ? e.message : e?.message || \"CardFields error\"\r\n setError(msg)\r\n onError?.(msg)\r\n }}\r\n >\r\n <div style={{ display: \"grid\", gap: 10 }}>\r\n <PayPalNameField />\r\n <PayPalNumberField />\r\n <div style={{ display: \"grid\", gridTemplateColumns: \"1fr 1fr\", gap: 10 }}>\r\n <PayPalExpiryField />\r\n <PayPalCVVField />\r\n </div>\r\n\r\n <SubmitButton disabled={submitting} label={submitting ? \"Processing...\" : \"Pay by Card\"} />\r\n\r\n {error ? <div style={{ color: \"crimson\" }}>{error}</div> : null}\r\n </div>\r\n </PayPalCardFieldsProvider>\r\n )\r\n}\r\n","\"use client\"\r\n\r\nimport React from \"react\"\r\nimport { PayPalCurrencyNotice } from \"../components/PayPalCurrencyNotice\"\r\nimport { PayPalAdvancedCard } from \"../components/PayPalAdvancedCard\"\r\nimport { PayPalProvider } from \"../components/PayPalProvider\"\r\nimport { PayPalSmartButtons } from \"../components/PayPalSmartButtons\"\r\nimport { usePayPalConfig } from \"../hooks/usePayPalConfig\"\r\n\r\nconst DEFAULT_PAYPAL_PROVIDER_ID = \"pp_paypal_paypal\"\r\nconst DEFAULT_PAYPAL_CARD_PROVIDER_ID = \"pp_paypal_card_paypal_card\"\r\n\r\nexport type MedusaNextPayPalAdapterProps = {\r\n cartId: string\r\n selectedProviderId: string | null | undefined\r\n baseUrl: string\r\n publishableApiKey?: string\r\n providerIds?: {\r\n paypal?: string\r\n paypalCard?: string\r\n }\r\n onPaid?: (result: unknown) => void\r\n onError?: (message: string) => void\r\n}\r\n\r\nexport function MedusaNextPayPalAdapter(props: MedusaNextPayPalAdapterProps) {\r\n const { cartId, selectedProviderId, baseUrl, publishableApiKey, providerIds, onPaid, onError } = props\r\n\r\n const paypalProviderId = providerIds?.paypal || DEFAULT_PAYPAL_PROVIDER_ID\r\n const paypalCardProviderId = providerIds?.paypalCard || DEFAULT_PAYPAL_CARD_PROVIDER_ID\r\n\r\n const shouldRender =\r\n selectedProviderId === paypalProviderId ||\r\n selectedProviderId === paypalCardProviderId\r\n\r\n const { config, loading, error } = usePayPalConfig({\r\n baseUrl,\r\n publishableApiKey,\r\n cartId,\r\n enabled: shouldRender,\r\n })\r\n\r\n if (!shouldRender) return null\r\n if (loading) return <div>Loading PayPal…</div>\r\n if (error) return <div style={{ color: \"crimson\" }}>{error}</div>\r\n if (!config) return null\r\n\r\n return (\r\n <div style={{ display: \"grid\", gap: 12 }}>\r\n <PayPalCurrencyNotice config={config} />\r\n\r\n <PayPalProvider config={config} intent={config.intent === \"authorize\" ? \"authorize\" : \"capture\"}>\r\n {selectedProviderId === paypalCardProviderId ? (\r\n <PayPalAdvancedCard\r\n baseUrl={baseUrl}\r\n publishableApiKey={publishableApiKey}\r\n cartId={cartId}\r\n config={config}\r\n onPaid={onPaid}\r\n onError={onError}\r\n />\r\n ) : (\r\n <PayPalSmartButtons\r\n baseUrl={baseUrl}\r\n publishableApiKey={publishableApiKey}\r\n cartId={cartId}\r\n config={config}\r\n onPaid={onPaid}\r\n onError={onError}\r\n />\r\n )}\r\n </PayPalProvider>\r\n </div>\r\n )\r\n}\r\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/client/http.ts","../src/client/paypal.ts","../src/hooks/usePayPalConfig.ts","../src/components/PayPalProvider.tsx","../src/components/PayPalCurrencyNotice.tsx","../src/components/PayPalSmartButtons.tsx","../src/components/PayPalAdvancedCard.tsx","../src/adapters/MedusaNextPayPalAdapter.tsx"],"names":["useMemo","useState","useEffect","jsx","PayPalScriptProvider","jsxs","PayPalButtons","usePayPalCardFields","PayPalCardFieldsProvider","PayPalNameField","PayPalNumberField","PayPalExpiryField","PayPalCVVField","useCallback"],"mappings":"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","file":"index.cjs","sourcesContent":["export type HttpOptions = {\r\n baseUrl: string\r\n publishableApiKey?: string\r\n}\r\n\r\nfunction toHeaderRecord(headers?: RequestInit[\"headers\"]): Record<string, string> {\r\n if (!headers) {\r\n return {}\r\n }\r\n\r\n if (headers instanceof Headers) {\r\n return Object.fromEntries(headers.entries())\r\n }\r\n\r\n if (Array.isArray(headers)) {\r\n return Object.fromEntries(headers)\r\n }\r\n\r\n return { ...headers }\r\n}\r\n\r\nexport function createHttpClient(opts: HttpOptions) {\r\n const base = opts.baseUrl.replace(/\\/+$/, \"\")\r\n\r\n async function request<T>(path: string, init?: RequestInit): Promise<T> {\r\n const url = `${base}${path.startsWith(\"/\") ? \"\" : \"/\"}${path}`\r\n const headers: Record<string, string> = {\r\n Accept: \"application/json\",\r\n ...toHeaderRecord(init?.headers),\r\n }\r\n\r\n if (opts.publishableApiKey) {\r\n headers[\"x-publishable-api-key\"] = opts.publishableApiKey\r\n }\r\n\r\n const res = await fetch(url, { ...init, headers, credentials: \"include\" })\r\n const text = await res.text().catch(() => \"\")\r\n\r\n if (!res.ok) {\r\n if (res.status === 401) {\r\n throw new Error(\r\n \"[PayPal] Unauthorized (401) — check that your publishable API key is correct and set in NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY\"\r\n )\r\n }\r\n if (res.status === 403) {\r\n throw new Error(\r\n \"[PayPal] Forbidden (403) — this request is not allowed. Check your CORS and API key settings.\"\r\n )\r\n }\r\n throw new Error(text || `Request failed (${res.status})`)\r\n }\r\n if (!text) return {} as T\r\n\r\n const contentType = res.headers.get(\"content-type\") || \"\"\r\n if (!contentType.includes(\"application/json\")) {\r\n console.warn(\"[PayPal] Unexpected non-JSON response:\", contentType, text.slice(0, 200))\r\n return {} as T\r\n }\r\n\r\n try {\r\n return JSON.parse(text) as T\r\n } catch {\r\n console.warn(\"[PayPal] Failed to parse JSON response:\", text.slice(0, 200))\r\n return {} as T\r\n }\r\n }\r\n\r\n return { request }\r\n}\r\n","import type { PayPalConfig, PayPalSettingsResponse } from \"./types\"\r\nimport { createHttpClient, type HttpOptions } from \"./http\"\r\n\r\nexport function createPayPalStoreApi(opts: HttpOptions) {\r\n const http = createHttpClient(opts)\r\n\r\n return {\r\n getConfig(cartId?: string, signal?: AbortSignal) {\r\n const q = cartId ? `?cart_id=${encodeURIComponent(cartId)}` : \"\"\r\n return http.request<PayPalConfig>(`/store/paypal/config${q}`, { signal })\r\n },\r\n\r\n getSettings() {\r\n return http.request<PayPalSettingsResponse>(`/store/paypal/settings`)\r\n },\r\n\r\n createOrder(cartId: string) {\r\n return http.request<{ id: string }>(`/store/paypal/create-order`, {\r\n method: \"POST\",\r\n headers: { \"Content-Type\": \"application/json\" },\r\n body: JSON.stringify({ cart_id: cartId }),\r\n })\r\n },\r\n\r\n captureOrder(cartId: string, orderId: string) {\r\n return http.request<Record<string, unknown>>(`/store/paypal/capture-order`, {\r\n method: \"POST\",\r\n headers: { \"Content-Type\": \"application/json\" },\r\n body: JSON.stringify({ cart_id: cartId, order_id: orderId }),\r\n })\r\n },\r\n }\r\n}\r\n","import { useEffect, useMemo, useState } from \"react\"\r\nimport { createPayPalStoreApi } from \"../client/paypal\"\r\nimport type { PayPalConfig } from \"../client/types\"\r\n\r\ntype Args = {\r\n baseUrl: string\r\n publishableApiKey?: string\r\n cartId?: string\r\n enabled?: boolean\r\n}\r\n\r\nexport function usePayPalConfig({ baseUrl, publishableApiKey, cartId, enabled = true }: Args) {\r\n const api = useMemo(\r\n () => createPayPalStoreApi({ baseUrl, publishableApiKey }),\r\n [baseUrl, publishableApiKey]\r\n )\r\n\r\n const [config, setConfig] = useState<PayPalConfig | null>(null)\r\n const [loading, setLoading] = useState(false)\r\n const [error, setError] = useState<string | null>(null)\r\n\r\n useEffect(() => {\r\n if (!enabled) {\r\n setLoading(false)\r\n setError(null)\r\n setConfig(null)\r\n return\r\n }\r\n\r\n let mounted = true\r\n const controller = new AbortController()\r\n ;(async () => {\r\n try {\r\n setLoading(true)\r\n setError(null)\r\n const cfg = await api.getConfig(cartId, controller.signal)\r\n if (mounted) setConfig(cfg)\r\n } catch (e: any) {\r\n if (e?.name === \"AbortError\") return\r\n if (mounted) setError(e?.message || \"Failed to load PayPal config\")\r\n } finally {\r\n if (mounted) setLoading(false)\r\n }\r\n })()\r\n\r\n return () => {\r\n mounted = false\r\n controller.abort()\r\n }\r\n }, [api, cartId, enabled])\r\n\r\n return { config, loading, error }\r\n}\r\n","\"use client\"\r\n\r\nimport React, { useMemo } from \"react\"\r\nimport { PayPalScriptProvider } from \"@paypal/react-paypal-js\"\r\nimport type { ReactPayPalScriptOptions } from \"@paypal/react-paypal-js\"\r\nimport type { PayPalConfig } from \"../client/types\"\r\n\r\nexport function PayPalProvider(props: {\r\n config: PayPalConfig\r\n intent?: \"capture\" | \"authorize\"\r\n disableFunding?: string\r\n children: React.ReactNode\r\n}) {\r\n const { config, intent = \"capture\", disableFunding, children } = props\r\n\r\n const options = useMemo((): ReactPayPalScriptOptions => {\r\n return {\r\n clientId: config.client_id,\r\n \"client-id\": config.client_id,\r\n currency: config.currency,\r\n intent,\r\n components: config.client_token ? \"buttons,card-fields\" : \"buttons\",\r\n \"data-client-token\": config.client_token || undefined,\r\n \"disable-funding\": disableFunding,\r\n }\r\n }, [config, intent, disableFunding])\r\n\r\n return <PayPalScriptProvider options={options}>{children}</PayPalScriptProvider>\r\n}\r\n","\"use client\"\n\nimport React from \"react\"\nimport type { PayPalConfig } from \"../client/types\"\n\nexport function PayPalCurrencyNotice({ config }: { config: PayPalConfig }) {\n if (config.currency_supported) return null\n\n return (\n <div style={{ padding: 12, border: \"1px solid #ddd\", borderRadius: 10 }}>\n <div style={{ fontWeight: 600, marginBottom: 6 }}>PayPal currency issue</div>\n <ul style={{ margin: 0, paddingLeft: 18 }}>\n {(config.currency_errors || []).map((e, i) => (\n <li key={i}>{e}</li>\n ))}\n </ul>\n </div>\n )\n}\n","\"use client\"\r\n\r\nimport React, { useMemo, useState } from \"react\"\r\nimport { PayPalButtons } from \"@paypal/react-paypal-js\"\r\nimport { createPayPalStoreApi } from \"../client/paypal\"\r\nimport type { PayPalConfig } from \"../client/types\"\r\n\r\nexport function PayPalSmartButtons(props: {\r\n baseUrl: string\r\n publishableApiKey?: string\r\n cartId: string\r\n config: PayPalConfig\r\n onPaid?: (result: Record<string, unknown>) => void\r\n onError?: (message: string) => void\r\n}) {\r\n const { baseUrl, publishableApiKey, cartId, config, onPaid, onError } = props\r\n const api = useMemo(\r\n () => createPayPalStoreApi({ baseUrl, publishableApiKey }),\r\n [baseUrl, publishableApiKey]\r\n )\r\n\r\n const [error, setError] = useState<string | null>(null)\r\n\r\n if (!config.currency_supported) return null\r\n\r\n return (\r\n <div>\r\n <PayPalButtons\r\n style={{\r\n layout: \"vertical\",\r\n color: config.button_color,\r\n shape: config.button_shape,\r\n label: config.button_label,\r\n height: config.button_height,\r\n }}\r\n createOrder={async () => {\r\n setError(null)\r\n const r = await api.createOrder(cartId)\r\n return r.id\r\n }}\r\n onApprove={async (data: { orderID?: string }) => {\r\n try {\r\n setError(null)\r\n const orderId = String(data?.orderID || \"\")\r\n const result = await api.captureOrder(cartId, orderId)\r\n onPaid?.(result)\r\n } catch (e: unknown) {\r\n const msg = e instanceof Error ? e.message : \"Payment capture failed\"\r\n setError(msg)\r\n onError?.(msg)\r\n }\r\n }}\r\n onError={(err: Error | { message?: string }) => {\r\n const msg = err instanceof Error ? err.message : err?.message || \"PayPal error\"\r\n setError(msg)\r\n onError?.(msg)\r\n }}\r\n />\r\n {error ? <div style={{ marginTop: 10, color: \"crimson\" }}>{error}</div> : null}\r\n </div>\r\n )\r\n}\r\n","\"use client\"\r\n\r\nimport React, { useMemo, useState } from \"react\"\r\nimport {\r\n PayPalCardFieldsProvider,\r\n PayPalNameField,\r\n PayPalNumberField,\r\n PayPalExpiryField,\r\n PayPalCVVField,\r\n usePayPalCardFields,\r\n} from \"@paypal/react-paypal-js\"\r\nimport { createPayPalStoreApi } from \"../client/paypal\"\r\nimport type { PayPalConfig } from \"../client/types\"\r\n\r\nfunction SubmitButton({ disabled, label }: { disabled: boolean; label: string }) {\r\n const { cardFieldsForm } = usePayPalCardFields()\r\n\r\n return (\r\n <button\r\n type=\"button\"\r\n disabled={disabled || !cardFieldsForm}\r\n onClick={() => cardFieldsForm?.submit()}\r\n style={{ padding: \"10px 12px\", borderRadius: 10, border: \"1px solid #ddd\" }}\r\n >\r\n {label}\r\n </button>\r\n )\r\n}\r\n\r\nexport function PayPalAdvancedCard(props: {\r\n baseUrl: string\r\n publishableApiKey?: string\r\n cartId: string\r\n config: PayPalConfig\r\n onPaid?: (result: Record<string, unknown>) => void\r\n onError?: (message: string) => void\r\n}) {\r\n const { baseUrl, publishableApiKey, cartId, config, onPaid, onError } = props\r\n const api = useMemo(\r\n () => createPayPalStoreApi({ baseUrl, publishableApiKey }),\r\n [baseUrl, publishableApiKey]\r\n )\r\n\r\n const [error, setError] = useState<string | null>(null)\r\n const [submitting, setSubmitting] = useState(false)\r\n\r\n if (!config.currency_supported) return null\r\n\r\n if (!config.client_token) {\r\n return (\r\n <div style={{ padding: 12, border: \"1px solid #ddd\", borderRadius: 10 }}>\r\n CardFields unavailable: missing client_token from backend.\r\n </div>\r\n )\r\n }\r\n\r\n return (\r\n <PayPalCardFieldsProvider\r\n createOrder={async () => {\r\n setError(null)\r\n const r = await api.createOrder(cartId)\r\n return r.id\r\n }}\r\n onApprove={async (data: { orderID?: string }) => {\r\n try {\r\n setSubmitting(true)\r\n setError(null)\r\n const orderId = String(data?.orderID || \"\")\r\n const result = await api.captureOrder(cartId, orderId)\r\n onPaid?.(result)\r\n } catch (e: unknown) {\r\n const msg = e instanceof Error ? e.message : \"Card payment failed\"\r\n setError(msg)\r\n onError?.(msg)\r\n } finally {\r\n setSubmitting(false)\r\n }\r\n }}\r\n onError={(e: Error | { message?: string }) => {\r\n const msg = e instanceof Error ? e.message : e?.message || \"CardFields error\"\r\n setError(msg)\r\n onError?.(msg)\r\n }}\r\n >\r\n <div style={{ display: \"grid\", gap: 10 }}>\r\n <PayPalNameField />\r\n <PayPalNumberField />\r\n <div style={{ display: \"grid\", gridTemplateColumns: \"1fr 1fr\", gap: 10 }}>\r\n <PayPalExpiryField />\r\n <PayPalCVVField />\r\n </div>\r\n\r\n <SubmitButton disabled={submitting} label={submitting ? \"Processing...\" : \"Pay by Card\"} />\r\n\r\n {error ? <div style={{ color: \"crimson\" }}>{error}</div> : null}\r\n </div>\r\n </PayPalCardFieldsProvider>\r\n )\r\n}\r\n","\"use client\"\r\n\r\nimport React, { useCallback } from \"react\"\r\nimport { PayPalCurrencyNotice } from \"../components/PayPalCurrencyNotice\"\r\nimport { PayPalAdvancedCard } from \"../components/PayPalAdvancedCard\"\r\nimport { PayPalProvider } from \"../components/PayPalProvider\"\r\nimport { PayPalSmartButtons } from \"../components/PayPalSmartButtons\"\r\nimport { usePayPalConfig } from \"../hooks/usePayPalConfig\"\r\n\r\nconst DEFAULT_PAYPAL_PROVIDER_ID = \"pp_paypal_paypal\"\r\nconst DEFAULT_PAYPAL_CARD_PROVIDER_ID = \"pp_paypal_card_paypal_card\"\r\n\r\nexport type MedusaNextPayPalAdapterProps = {\r\n cartId: string\r\n selectedProviderId: string | null | undefined\r\n baseUrl: string\r\n publishableApiKey?: string\r\n providerIds?: {\r\n paypal?: string\r\n paypalCard?: string\r\n }\r\n /**\r\n * Called after PayPal capture succeeds.\r\n * The storefront must call placeOrder(cartId) here — that is the only\r\n * correct way to clear the _medusa_cart_id cookie, because placeOrder\r\n * is a Next.js Server Action that calls removeCartId() server-side.\r\n * A client-side fetch cannot clear an httpOnly cookie set by the server.\r\n */\r\n onSuccess?: (cartId: string) => void\r\n onError?: (message: string) => void\r\n /** @deprecated use onSuccess */\r\n onPaid?: (result: unknown) => void\r\n}\r\n\r\nexport function MedusaNextPayPalAdapter(props: MedusaNextPayPalAdapterProps) {\r\n const {\r\n cartId,\r\n selectedProviderId,\r\n baseUrl,\r\n publishableApiKey,\r\n providerIds,\r\n onSuccess,\r\n onError,\r\n onPaid,\r\n } = props\r\n\r\n const paypalProviderId = providerIds?.paypal || DEFAULT_PAYPAL_PROVIDER_ID\r\n const paypalCardProviderId = providerIds?.paypalCard || DEFAULT_PAYPAL_CARD_PROVIDER_ID\r\n\r\n const shouldRender =\r\n selectedProviderId === paypalProviderId ||\r\n selectedProviderId === paypalCardProviderId\r\n\r\n const { config, loading, error } = usePayPalConfig({\r\n baseUrl,\r\n publishableApiKey,\r\n cartId,\r\n enabled: shouldRender,\r\n })\r\n\r\n // After capture succeeds: call both the legacy onPaid and the new onSuccess.\r\n // Cart completion and cookie clearing must happen in the storefront via\r\n // placeOrder() — we intentionally do NOT call /store/carts/:id/complete here\r\n // because that endpoint does not clear the Next.js server-side cart cookie.\r\n const handlePaid = useCallback(\r\n (captureResult: unknown) => {\r\n onPaid?.(captureResult)\r\n onSuccess?.(cartId)\r\n },\r\n [cartId, onPaid, onSuccess]\r\n )\r\n\r\n if (!shouldRender) return null\r\n if (loading) return <div>Loading PayPal…</div>\r\n if (error) return <div style={{ color: \"crimson\" }}>{error}</div>\r\n if (!config) return null\r\n if (config.paypal_enabled === false) return null\r\n\r\n const disableFunding = Array.isArray(config.disable_buttons)\r\n ? config.disable_buttons.join(\",\")\r\n : undefined\r\n\r\n return (\r\n <div style={{ display: \"grid\", gap: 12 }}>\r\n <PayPalCurrencyNotice config={config} />\r\n <PayPalProvider\r\n config={config}\r\n intent={config.intent === \"authorize\" ? \"authorize\" : \"capture\"}\r\n disableFunding={disableFunding}\r\n >\r\n {selectedProviderId === paypalCardProviderId ? (\r\n <PayPalAdvancedCard\r\n baseUrl={baseUrl}\r\n publishableApiKey={publishableApiKey}\r\n cartId={cartId}\r\n config={config}\r\n onPaid={handlePaid}\r\n onError={onError}\r\n />\r\n ) : (\r\n <PayPalSmartButtons\r\n baseUrl={baseUrl}\r\n publishableApiKey={publishableApiKey}\r\n cartId={cartId}\r\n config={config}\r\n onPaid={handlePaid}\r\n onError={onError}\r\n />\r\n )}\r\n </PayPalProvider>\r\n </div>\r\n )\r\n}\r\n"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -10,6 +10,14 @@ type PayPalConfig = {
|
|
|
10
10
|
supported_currencies: string[];
|
|
11
11
|
client_token?: string;
|
|
12
12
|
intent?: "capture" | "authorize";
|
|
13
|
+
paypal_enabled?: boolean;
|
|
14
|
+
paypal_title?: string;
|
|
15
|
+
button_color?: "gold" | "blue" | "silver" | "black" | "white";
|
|
16
|
+
button_shape?: "rect" | "pill" | "sharp";
|
|
17
|
+
button_width?: string;
|
|
18
|
+
button_height?: number;
|
|
19
|
+
button_label?: "paypal" | "checkout" | "buynow" | "pay" | "installment";
|
|
20
|
+
disable_buttons?: string[];
|
|
13
21
|
};
|
|
14
22
|
type PayPalSettingsResponse = {
|
|
15
23
|
data?: {
|
|
@@ -51,6 +59,7 @@ declare function usePayPalConfig({ baseUrl, publishableApiKey, cartId, enabled }
|
|
|
51
59
|
declare function PayPalProvider(props: {
|
|
52
60
|
config: PayPalConfig;
|
|
53
61
|
intent?: "capture" | "authorize";
|
|
62
|
+
disableFunding?: string;
|
|
54
63
|
children: React.ReactNode;
|
|
55
64
|
}): react_jsx_runtime.JSX.Element;
|
|
56
65
|
|
|
@@ -85,8 +94,17 @@ type MedusaNextPayPalAdapterProps = {
|
|
|
85
94
|
paypal?: string;
|
|
86
95
|
paypalCard?: string;
|
|
87
96
|
};
|
|
88
|
-
|
|
97
|
+
/**
|
|
98
|
+
* Called after PayPal capture succeeds.
|
|
99
|
+
* The storefront must call placeOrder(cartId) here — that is the only
|
|
100
|
+
* correct way to clear the _medusa_cart_id cookie, because placeOrder
|
|
101
|
+
* is a Next.js Server Action that calls removeCartId() server-side.
|
|
102
|
+
* A client-side fetch cannot clear an httpOnly cookie set by the server.
|
|
103
|
+
*/
|
|
104
|
+
onSuccess?: (cartId: string) => void;
|
|
89
105
|
onError?: (message: string) => void;
|
|
106
|
+
/** @deprecated use onSuccess */
|
|
107
|
+
onPaid?: (result: unknown) => void;
|
|
90
108
|
};
|
|
91
109
|
declare function MedusaNextPayPalAdapter(props: MedusaNextPayPalAdapterProps): react_jsx_runtime.JSX.Element | null;
|
|
92
110
|
|
package/dist/index.d.ts
CHANGED
|
@@ -10,6 +10,14 @@ type PayPalConfig = {
|
|
|
10
10
|
supported_currencies: string[];
|
|
11
11
|
client_token?: string;
|
|
12
12
|
intent?: "capture" | "authorize";
|
|
13
|
+
paypal_enabled?: boolean;
|
|
14
|
+
paypal_title?: string;
|
|
15
|
+
button_color?: "gold" | "blue" | "silver" | "black" | "white";
|
|
16
|
+
button_shape?: "rect" | "pill" | "sharp";
|
|
17
|
+
button_width?: string;
|
|
18
|
+
button_height?: number;
|
|
19
|
+
button_label?: "paypal" | "checkout" | "buynow" | "pay" | "installment";
|
|
20
|
+
disable_buttons?: string[];
|
|
13
21
|
};
|
|
14
22
|
type PayPalSettingsResponse = {
|
|
15
23
|
data?: {
|
|
@@ -51,6 +59,7 @@ declare function usePayPalConfig({ baseUrl, publishableApiKey, cartId, enabled }
|
|
|
51
59
|
declare function PayPalProvider(props: {
|
|
52
60
|
config: PayPalConfig;
|
|
53
61
|
intent?: "capture" | "authorize";
|
|
62
|
+
disableFunding?: string;
|
|
54
63
|
children: React.ReactNode;
|
|
55
64
|
}): react_jsx_runtime.JSX.Element;
|
|
56
65
|
|
|
@@ -85,8 +94,17 @@ type MedusaNextPayPalAdapterProps = {
|
|
|
85
94
|
paypal?: string;
|
|
86
95
|
paypalCard?: string;
|
|
87
96
|
};
|
|
88
|
-
|
|
97
|
+
/**
|
|
98
|
+
* Called after PayPal capture succeeds.
|
|
99
|
+
* The storefront must call placeOrder(cartId) here — that is the only
|
|
100
|
+
* correct way to clear the _medusa_cart_id cookie, because placeOrder
|
|
101
|
+
* is a Next.js Server Action that calls removeCartId() server-side.
|
|
102
|
+
* A client-side fetch cannot clear an httpOnly cookie set by the server.
|
|
103
|
+
*/
|
|
104
|
+
onSuccess?: (cartId: string) => void;
|
|
89
105
|
onError?: (message: string) => void;
|
|
106
|
+
/** @deprecated use onSuccess */
|
|
107
|
+
onPaid?: (result: unknown) => void;
|
|
90
108
|
};
|
|
91
109
|
declare function MedusaNextPayPalAdapter(props: MedusaNextPayPalAdapterProps): react_jsx_runtime.JSX.Element | null;
|
|
92
110
|
|
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useMemo, useState, useEffect } from 'react';
|
|
1
|
+
import { useMemo, useState, useEffect, useCallback } from 'react';
|
|
2
2
|
import { PayPalScriptProvider, PayPalButtons, PayPalCardFieldsProvider, PayPalNameField, PayPalNumberField, PayPalExpiryField, PayPalCVVField, usePayPalCardFields } from '@paypal/react-paypal-js';
|
|
3
3
|
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
4
4
|
|
|
@@ -29,6 +29,16 @@ function createHttpClient(opts) {
|
|
|
29
29
|
const res = await fetch(url, { ...init, headers, credentials: "include" });
|
|
30
30
|
const text = await res.text().catch(() => "");
|
|
31
31
|
if (!res.ok) {
|
|
32
|
+
if (res.status === 401) {
|
|
33
|
+
throw new Error(
|
|
34
|
+
"[PayPal] Unauthorized (401) \u2014 check that your publishable API key is correct and set in NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY"
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
if (res.status === 403) {
|
|
38
|
+
throw new Error(
|
|
39
|
+
"[PayPal] Forbidden (403) \u2014 this request is not allowed. Check your CORS and API key settings."
|
|
40
|
+
);
|
|
41
|
+
}
|
|
32
42
|
throw new Error(text || `Request failed (${res.status})`);
|
|
33
43
|
}
|
|
34
44
|
if (!text) return {};
|
|
@@ -112,7 +122,7 @@ function usePayPalConfig({ baseUrl, publishableApiKey, cartId, enabled = true })
|
|
|
112
122
|
return { config, loading, error };
|
|
113
123
|
}
|
|
114
124
|
function PayPalProvider(props) {
|
|
115
|
-
const { config, intent = "capture", children } = props;
|
|
125
|
+
const { config, intent = "capture", disableFunding, children } = props;
|
|
116
126
|
const options = useMemo(() => {
|
|
117
127
|
return {
|
|
118
128
|
clientId: config.client_id,
|
|
@@ -120,9 +130,10 @@ function PayPalProvider(props) {
|
|
|
120
130
|
currency: config.currency,
|
|
121
131
|
intent,
|
|
122
132
|
components: config.client_token ? "buttons,card-fields" : "buttons",
|
|
123
|
-
"data-client-token": config.client_token || void 0
|
|
133
|
+
"data-client-token": config.client_token || void 0,
|
|
134
|
+
"disable-funding": disableFunding
|
|
124
135
|
};
|
|
125
|
-
}, [config, intent]);
|
|
136
|
+
}, [config, intent, disableFunding]);
|
|
126
137
|
return /* @__PURE__ */ jsx(PayPalScriptProvider, { options, children });
|
|
127
138
|
}
|
|
128
139
|
function PayPalCurrencyNotice({ config }) {
|
|
@@ -144,7 +155,13 @@ function PayPalSmartButtons(props) {
|
|
|
144
155
|
/* @__PURE__ */ jsx(
|
|
145
156
|
PayPalButtons,
|
|
146
157
|
{
|
|
147
|
-
style: {
|
|
158
|
+
style: {
|
|
159
|
+
layout: "vertical",
|
|
160
|
+
color: config.button_color,
|
|
161
|
+
shape: config.button_shape,
|
|
162
|
+
label: config.button_label,
|
|
163
|
+
height: config.button_height
|
|
164
|
+
},
|
|
148
165
|
createOrder: async () => {
|
|
149
166
|
setError(null);
|
|
150
167
|
const r = await api.createOrder(cartId);
|
|
@@ -157,7 +174,7 @@ function PayPalSmartButtons(props) {
|
|
|
157
174
|
const result = await api.captureOrder(cartId, orderId);
|
|
158
175
|
onPaid?.(result);
|
|
159
176
|
} catch (e) {
|
|
160
|
-
const msg = e
|
|
177
|
+
const msg = e instanceof Error ? e.message : "Payment capture failed";
|
|
161
178
|
setError(msg);
|
|
162
179
|
onError?.(msg);
|
|
163
180
|
}
|
|
@@ -241,7 +258,16 @@ function PayPalAdvancedCard(props) {
|
|
|
241
258
|
var DEFAULT_PAYPAL_PROVIDER_ID = "pp_paypal_paypal";
|
|
242
259
|
var DEFAULT_PAYPAL_CARD_PROVIDER_ID = "pp_paypal_card_paypal_card";
|
|
243
260
|
function MedusaNextPayPalAdapter(props) {
|
|
244
|
-
const {
|
|
261
|
+
const {
|
|
262
|
+
cartId,
|
|
263
|
+
selectedProviderId,
|
|
264
|
+
baseUrl,
|
|
265
|
+
publishableApiKey,
|
|
266
|
+
providerIds,
|
|
267
|
+
onSuccess,
|
|
268
|
+
onError,
|
|
269
|
+
onPaid
|
|
270
|
+
} = props;
|
|
245
271
|
const paypalProviderId = providerIds?.paypal || DEFAULT_PAYPAL_PROVIDER_ID;
|
|
246
272
|
const paypalCardProviderId = providerIds?.paypalCard || DEFAULT_PAYPAL_CARD_PROVIDER_ID;
|
|
247
273
|
const shouldRender = selectedProviderId === paypalProviderId || selectedProviderId === paypalCardProviderId;
|
|
@@ -251,33 +277,50 @@ function MedusaNextPayPalAdapter(props) {
|
|
|
251
277
|
cartId,
|
|
252
278
|
enabled: shouldRender
|
|
253
279
|
});
|
|
280
|
+
const handlePaid = useCallback(
|
|
281
|
+
(captureResult) => {
|
|
282
|
+
onPaid?.(captureResult);
|
|
283
|
+
onSuccess?.(cartId);
|
|
284
|
+
},
|
|
285
|
+
[cartId, onPaid, onSuccess]
|
|
286
|
+
);
|
|
254
287
|
if (!shouldRender) return null;
|
|
255
288
|
if (loading) return /* @__PURE__ */ jsx("div", { children: "Loading PayPal\u2026" });
|
|
256
289
|
if (error) return /* @__PURE__ */ jsx("div", { style: { color: "crimson" }, children: error });
|
|
257
290
|
if (!config) return null;
|
|
291
|
+
if (config.paypal_enabled === false) return null;
|
|
292
|
+
const disableFunding = Array.isArray(config.disable_buttons) ? config.disable_buttons.join(",") : void 0;
|
|
258
293
|
return /* @__PURE__ */ jsxs("div", { style: { display: "grid", gap: 12 }, children: [
|
|
259
294
|
/* @__PURE__ */ jsx(PayPalCurrencyNotice, { config }),
|
|
260
|
-
/* @__PURE__ */ jsx(
|
|
261
|
-
|
|
262
|
-
{
|
|
263
|
-
baseUrl,
|
|
264
|
-
publishableApiKey,
|
|
265
|
-
cartId,
|
|
266
|
-
config,
|
|
267
|
-
onPaid,
|
|
268
|
-
onError
|
|
269
|
-
}
|
|
270
|
-
) : /* @__PURE__ */ jsx(
|
|
271
|
-
PayPalSmartButtons,
|
|
295
|
+
/* @__PURE__ */ jsx(
|
|
296
|
+
PayPalProvider,
|
|
272
297
|
{
|
|
273
|
-
baseUrl,
|
|
274
|
-
publishableApiKey,
|
|
275
|
-
cartId,
|
|
276
298
|
config,
|
|
277
|
-
|
|
278
|
-
|
|
299
|
+
intent: config.intent === "authorize" ? "authorize" : "capture",
|
|
300
|
+
disableFunding,
|
|
301
|
+
children: selectedProviderId === paypalCardProviderId ? /* @__PURE__ */ jsx(
|
|
302
|
+
PayPalAdvancedCard,
|
|
303
|
+
{
|
|
304
|
+
baseUrl,
|
|
305
|
+
publishableApiKey,
|
|
306
|
+
cartId,
|
|
307
|
+
config,
|
|
308
|
+
onPaid: handlePaid,
|
|
309
|
+
onError
|
|
310
|
+
}
|
|
311
|
+
) : /* @__PURE__ */ jsx(
|
|
312
|
+
PayPalSmartButtons,
|
|
313
|
+
{
|
|
314
|
+
baseUrl,
|
|
315
|
+
publishableApiKey,
|
|
316
|
+
cartId,
|
|
317
|
+
config,
|
|
318
|
+
onPaid: handlePaid,
|
|
319
|
+
onError
|
|
320
|
+
}
|
|
321
|
+
)
|
|
279
322
|
}
|
|
280
|
-
)
|
|
323
|
+
)
|
|
281
324
|
] });
|
|
282
325
|
}
|
|
283
326
|
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/client/http.ts","../src/client/paypal.ts","../src/hooks/usePayPalConfig.ts","../src/components/PayPalProvider.tsx","../src/components/PayPalCurrencyNotice.tsx","../src/components/PayPalSmartButtons.tsx","../src/components/PayPalAdvancedCard.tsx","../src/adapters/MedusaNextPayPalAdapter.tsx"],"names":["useMemo","jsx","useState","jsxs"],"mappings":"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","file":"index.mjs","sourcesContent":["export type HttpOptions = {\r\n baseUrl: string\r\n publishableApiKey?: string\r\n}\r\n\r\nfunction toHeaderRecord(headers?: RequestInit[\"headers\"]): Record<string, string> {\r\n if (!headers) {\r\n return {}\r\n }\r\n\r\n if (headers instanceof Headers) {\r\n return Object.fromEntries(headers.entries())\r\n }\r\n\r\n if (Array.isArray(headers)) {\r\n return Object.fromEntries(headers)\r\n }\r\n\r\n return { ...headers }\r\n}\r\n\r\nexport function createHttpClient(opts: HttpOptions) {\r\n const base = opts.baseUrl.replace(/\\/+$/, \"\")\r\n\r\n async function request<T>(path: string, init?: RequestInit): Promise<T> {\r\n const url = `${base}${path.startsWith(\"/\") ? \"\" : \"/\"}${path}`\r\n const headers: Record<string, string> = {\r\n Accept: \"application/json\",\r\n ...toHeaderRecord(init?.headers),\r\n }\r\n\r\n if (opts.publishableApiKey) {\r\n headers[\"x-publishable-api-key\"] = opts.publishableApiKey\r\n }\r\n\r\n const res = await fetch(url, { ...init, headers, credentials: \"include\" })\r\n const text = await res.text().catch(() => \"\")\r\n\r\n if (!res.ok) {\r\n throw new Error(text || `Request failed (${res.status})`)\r\n }\r\n if (!text) return {} as T\r\n\r\n const contentType = res.headers.get(\"content-type\") || \"\"\r\n if (!contentType.includes(\"application/json\")) {\r\n console.warn(\"[PayPal] Unexpected non-JSON response:\", contentType, text.slice(0, 200))\r\n return {} as T\r\n }\r\n\r\n try {\r\n return JSON.parse(text) as T\r\n } catch {\r\n console.warn(\"[PayPal] Failed to parse JSON response:\", text.slice(0, 200))\r\n return {} as T\r\n }\r\n }\r\n\r\n return { request }\r\n}\r\n","import type { PayPalConfig, PayPalSettingsResponse } from \"./types\"\r\nimport { createHttpClient, type HttpOptions } from \"./http\"\r\n\r\nexport function createPayPalStoreApi(opts: HttpOptions) {\r\n const http = createHttpClient(opts)\r\n\r\n return {\r\n getConfig(cartId?: string, signal?: AbortSignal) {\r\n const q = cartId ? `?cart_id=${encodeURIComponent(cartId)}` : \"\"\r\n return http.request<PayPalConfig>(`/store/paypal/config${q}`, { signal })\r\n },\r\n\r\n getSettings() {\r\n return http.request<PayPalSettingsResponse>(`/store/paypal/settings`)\r\n },\r\n\r\n createOrder(cartId: string) {\r\n return http.request<{ id: string }>(`/store/paypal/create-order`, {\r\n method: \"POST\",\r\n headers: { \"Content-Type\": \"application/json\" },\r\n body: JSON.stringify({ cart_id: cartId }),\r\n })\r\n },\r\n\r\n captureOrder(cartId: string, orderId: string) {\r\n return http.request<Record<string, unknown>>(`/store/paypal/capture-order`, {\r\n method: \"POST\",\r\n headers: { \"Content-Type\": \"application/json\" },\r\n body: JSON.stringify({ cart_id: cartId, order_id: orderId }),\r\n })\r\n },\r\n }\r\n}\r\n","import { useEffect, useMemo, useState } from \"react\"\r\nimport { createPayPalStoreApi } from \"../client/paypal\"\r\nimport type { PayPalConfig } from \"../client/types\"\r\n\r\ntype Args = {\r\n baseUrl: string\r\n publishableApiKey?: string\r\n cartId?: string\r\n enabled?: boolean\r\n}\r\n\r\nexport function usePayPalConfig({ baseUrl, publishableApiKey, cartId, enabled = true }: Args) {\r\n const api = useMemo(\r\n () => createPayPalStoreApi({ baseUrl, publishableApiKey }),\r\n [baseUrl, publishableApiKey]\r\n )\r\n\r\n const [config, setConfig] = useState<PayPalConfig | null>(null)\r\n const [loading, setLoading] = useState(false)\r\n const [error, setError] = useState<string | null>(null)\r\n\r\n useEffect(() => {\r\n if (!enabled) {\r\n setLoading(false)\r\n setError(null)\r\n setConfig(null)\r\n return\r\n }\r\n\r\n let mounted = true\r\n const controller = new AbortController()\r\n ;(async () => {\r\n try {\r\n setLoading(true)\r\n setError(null)\r\n const cfg = await api.getConfig(cartId, controller.signal)\r\n if (mounted) setConfig(cfg)\r\n } catch (e: any) {\r\n if (e?.name === \"AbortError\") return\r\n if (mounted) setError(e?.message || \"Failed to load PayPal config\")\r\n } finally {\r\n if (mounted) setLoading(false)\r\n }\r\n })()\r\n\r\n return () => {\r\n mounted = false\r\n controller.abort()\r\n }\r\n }, [api, cartId, enabled])\r\n\r\n return { config, loading, error }\r\n}\r\n","\"use client\"\r\n\r\nimport React, { useMemo } from \"react\"\r\nimport { PayPalScriptProvider } from \"@paypal/react-paypal-js\"\r\nimport type { ReactPayPalScriptOptions } from \"@paypal/react-paypal-js\"\r\nimport type { PayPalConfig } from \"../client/types\"\r\n\r\nexport function PayPalProvider(props: {\r\n config: PayPalConfig\r\n intent?: \"capture\" | \"authorize\"\r\n children: React.ReactNode\r\n}) {\r\n const { config, intent = \"capture\", children } = props\r\n\r\n const options = useMemo((): ReactPayPalScriptOptions => {\r\n return {\r\n clientId: config.client_id,\r\n \"client-id\": config.client_id,\r\n currency: config.currency,\r\n intent,\r\n components: config.client_token ? \"buttons,card-fields\" : \"buttons\",\r\n \"data-client-token\": config.client_token || undefined,\r\n }\r\n }, [config, intent])\r\n\r\n return <PayPalScriptProvider options={options}>{children}</PayPalScriptProvider>\r\n}\r\n","\"use client\"\n\nimport React from \"react\"\nimport type { PayPalConfig } from \"../client/types\"\n\nexport function PayPalCurrencyNotice({ config }: { config: PayPalConfig }) {\n if (config.currency_supported) return null\n\n return (\n <div style={{ padding: 12, border: \"1px solid #ddd\", borderRadius: 10 }}>\n <div style={{ fontWeight: 600, marginBottom: 6 }}>PayPal currency issue</div>\n <ul style={{ margin: 0, paddingLeft: 18 }}>\n {(config.currency_errors || []).map((e, i) => (\n <li key={i}>{e}</li>\n ))}\n </ul>\n </div>\n )\n}\n","\"use client\"\r\n\r\nimport React, { useMemo, useState } from \"react\"\r\nimport { PayPalButtons } from \"@paypal/react-paypal-js\"\r\nimport { createPayPalStoreApi } from \"../client/paypal\"\r\nimport type { PayPalConfig } from \"../client/types\"\r\n\r\nexport function PayPalSmartButtons(props: {\r\n baseUrl: string\r\n publishableApiKey?: string\r\n cartId: string\r\n config: PayPalConfig\r\n onPaid?: (result: Record<string, unknown>) => void\r\n onError?: (message: string) => void\r\n}) {\r\n const { baseUrl, publishableApiKey, cartId, config, onPaid, onError } = props\r\n const api = useMemo(\r\n () => createPayPalStoreApi({ baseUrl, publishableApiKey }),\r\n [baseUrl, publishableApiKey]\r\n )\r\n\r\n const [error, setError] = useState<string | null>(null)\r\n\r\n if (!config.currency_supported) return null\r\n\r\n return (\r\n <div>\r\n <PayPalButtons\r\n style={{ layout: \"vertical\" }}\r\n createOrder={async () => {\r\n setError(null)\r\n const r = await api.createOrder(cartId)\r\n return r.id\r\n }}\r\n onApprove={async (data: { orderID?: string }) => {\r\n try {\r\n setError(null)\r\n const orderId = String(data?.orderID || \"\")\r\n const result = await api.captureOrder(cartId, orderId)\r\n onPaid?.(result)\r\n } catch (e: any) {\r\n const msg = e?.message || \"Payment capture failed\"\r\n setError(msg)\r\n onError?.(msg)\r\n }\r\n }}\r\n onError={(err: Error | { message?: string }) => {\r\n const msg = err instanceof Error ? err.message : err?.message || \"PayPal error\"\r\n setError(msg)\r\n onError?.(msg)\r\n }}\r\n />\r\n {error ? <div style={{ marginTop: 10, color: \"crimson\" }}>{error}</div> : null}\r\n </div>\r\n )\r\n}\r\n","\"use client\"\r\n\r\nimport React, { useMemo, useState } from \"react\"\r\nimport {\r\n PayPalCardFieldsProvider,\r\n PayPalNameField,\r\n PayPalNumberField,\r\n PayPalExpiryField,\r\n PayPalCVVField,\r\n usePayPalCardFields,\r\n} from \"@paypal/react-paypal-js\"\r\nimport { createPayPalStoreApi } from \"../client/paypal\"\r\nimport type { PayPalConfig } from \"../client/types\"\r\n\r\nfunction SubmitButton({ disabled, label }: { disabled: boolean; label: string }) {\r\n const { cardFieldsForm } = usePayPalCardFields()\r\n\r\n return (\r\n <button\r\n type=\"button\"\r\n disabled={disabled || !cardFieldsForm}\r\n onClick={() => cardFieldsForm?.submit()}\r\n style={{ padding: \"10px 12px\", borderRadius: 10, border: \"1px solid #ddd\" }}\r\n >\r\n {label}\r\n </button>\r\n )\r\n}\r\n\r\nexport function PayPalAdvancedCard(props: {\r\n baseUrl: string\r\n publishableApiKey?: string\r\n cartId: string\r\n config: PayPalConfig\r\n onPaid?: (result: Record<string, unknown>) => void\r\n onError?: (message: string) => void\r\n}) {\r\n const { baseUrl, publishableApiKey, cartId, config, onPaid, onError } = props\r\n const api = useMemo(\r\n () => createPayPalStoreApi({ baseUrl, publishableApiKey }),\r\n [baseUrl, publishableApiKey]\r\n )\r\n\r\n const [error, setError] = useState<string | null>(null)\r\n const [submitting, setSubmitting] = useState(false)\r\n\r\n if (!config.currency_supported) return null\r\n\r\n if (!config.client_token) {\r\n return (\r\n <div style={{ padding: 12, border: \"1px solid #ddd\", borderRadius: 10 }}>\r\n CardFields unavailable: missing client_token from backend.\r\n </div>\r\n )\r\n }\r\n\r\n return (\r\n <PayPalCardFieldsProvider\r\n createOrder={async () => {\r\n setError(null)\r\n const r = await api.createOrder(cartId)\r\n return r.id\r\n }}\r\n onApprove={async (data: { orderID?: string }) => {\r\n try {\r\n setSubmitting(true)\r\n setError(null)\r\n const orderId = String(data?.orderID || \"\")\r\n const result = await api.captureOrder(cartId, orderId)\r\n onPaid?.(result)\r\n } catch (e: unknown) {\r\n const msg = e instanceof Error ? e.message : \"Card payment failed\"\r\n setError(msg)\r\n onError?.(msg)\r\n } finally {\r\n setSubmitting(false)\r\n }\r\n }}\r\n onError={(e: Error | { message?: string }) => {\r\n const msg = e instanceof Error ? e.message : e?.message || \"CardFields error\"\r\n setError(msg)\r\n onError?.(msg)\r\n }}\r\n >\r\n <div style={{ display: \"grid\", gap: 10 }}>\r\n <PayPalNameField />\r\n <PayPalNumberField />\r\n <div style={{ display: \"grid\", gridTemplateColumns: \"1fr 1fr\", gap: 10 }}>\r\n <PayPalExpiryField />\r\n <PayPalCVVField />\r\n </div>\r\n\r\n <SubmitButton disabled={submitting} label={submitting ? \"Processing...\" : \"Pay by Card\"} />\r\n\r\n {error ? <div style={{ color: \"crimson\" }}>{error}</div> : null}\r\n </div>\r\n </PayPalCardFieldsProvider>\r\n )\r\n}\r\n","\"use client\"\r\n\r\nimport React from \"react\"\r\nimport { PayPalCurrencyNotice } from \"../components/PayPalCurrencyNotice\"\r\nimport { PayPalAdvancedCard } from \"../components/PayPalAdvancedCard\"\r\nimport { PayPalProvider } from \"../components/PayPalProvider\"\r\nimport { PayPalSmartButtons } from \"../components/PayPalSmartButtons\"\r\nimport { usePayPalConfig } from \"../hooks/usePayPalConfig\"\r\n\r\nconst DEFAULT_PAYPAL_PROVIDER_ID = \"pp_paypal_paypal\"\r\nconst DEFAULT_PAYPAL_CARD_PROVIDER_ID = \"pp_paypal_card_paypal_card\"\r\n\r\nexport type MedusaNextPayPalAdapterProps = {\r\n cartId: string\r\n selectedProviderId: string | null | undefined\r\n baseUrl: string\r\n publishableApiKey?: string\r\n providerIds?: {\r\n paypal?: string\r\n paypalCard?: string\r\n }\r\n onPaid?: (result: unknown) => void\r\n onError?: (message: string) => void\r\n}\r\n\r\nexport function MedusaNextPayPalAdapter(props: MedusaNextPayPalAdapterProps) {\r\n const { cartId, selectedProviderId, baseUrl, publishableApiKey, providerIds, onPaid, onError } = props\r\n\r\n const paypalProviderId = providerIds?.paypal || DEFAULT_PAYPAL_PROVIDER_ID\r\n const paypalCardProviderId = providerIds?.paypalCard || DEFAULT_PAYPAL_CARD_PROVIDER_ID\r\n\r\n const shouldRender =\r\n selectedProviderId === paypalProviderId ||\r\n selectedProviderId === paypalCardProviderId\r\n\r\n const { config, loading, error } = usePayPalConfig({\r\n baseUrl,\r\n publishableApiKey,\r\n cartId,\r\n enabled: shouldRender,\r\n })\r\n\r\n if (!shouldRender) return null\r\n if (loading) return <div>Loading PayPal…</div>\r\n if (error) return <div style={{ color: \"crimson\" }}>{error}</div>\r\n if (!config) return null\r\n\r\n return (\r\n <div style={{ display: \"grid\", gap: 12 }}>\r\n <PayPalCurrencyNotice config={config} />\r\n\r\n <PayPalProvider config={config} intent={config.intent === \"authorize\" ? \"authorize\" : \"capture\"}>\r\n {selectedProviderId === paypalCardProviderId ? (\r\n <PayPalAdvancedCard\r\n baseUrl={baseUrl}\r\n publishableApiKey={publishableApiKey}\r\n cartId={cartId}\r\n config={config}\r\n onPaid={onPaid}\r\n onError={onError}\r\n />\r\n ) : (\r\n <PayPalSmartButtons\r\n baseUrl={baseUrl}\r\n publishableApiKey={publishableApiKey}\r\n cartId={cartId}\r\n config={config}\r\n onPaid={onPaid}\r\n onError={onError}\r\n />\r\n )}\r\n </PayPalProvider>\r\n </div>\r\n )\r\n}\r\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/client/http.ts","../src/client/paypal.ts","../src/hooks/usePayPalConfig.ts","../src/components/PayPalProvider.tsx","../src/components/PayPalCurrencyNotice.tsx","../src/components/PayPalSmartButtons.tsx","../src/components/PayPalAdvancedCard.tsx","../src/adapters/MedusaNextPayPalAdapter.tsx"],"names":["useMemo","jsx","useState","jsxs"],"mappings":"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","file":"index.mjs","sourcesContent":["export type HttpOptions = {\r\n baseUrl: string\r\n publishableApiKey?: string\r\n}\r\n\r\nfunction toHeaderRecord(headers?: RequestInit[\"headers\"]): Record<string, string> {\r\n if (!headers) {\r\n return {}\r\n }\r\n\r\n if (headers instanceof Headers) {\r\n return Object.fromEntries(headers.entries())\r\n }\r\n\r\n if (Array.isArray(headers)) {\r\n return Object.fromEntries(headers)\r\n }\r\n\r\n return { ...headers }\r\n}\r\n\r\nexport function createHttpClient(opts: HttpOptions) {\r\n const base = opts.baseUrl.replace(/\\/+$/, \"\")\r\n\r\n async function request<T>(path: string, init?: RequestInit): Promise<T> {\r\n const url = `${base}${path.startsWith(\"/\") ? \"\" : \"/\"}${path}`\r\n const headers: Record<string, string> = {\r\n Accept: \"application/json\",\r\n ...toHeaderRecord(init?.headers),\r\n }\r\n\r\n if (opts.publishableApiKey) {\r\n headers[\"x-publishable-api-key\"] = opts.publishableApiKey\r\n }\r\n\r\n const res = await fetch(url, { ...init, headers, credentials: \"include\" })\r\n const text = await res.text().catch(() => \"\")\r\n\r\n if (!res.ok) {\r\n if (res.status === 401) {\r\n throw new Error(\r\n \"[PayPal] Unauthorized (401) — check that your publishable API key is correct and set in NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY\"\r\n )\r\n }\r\n if (res.status === 403) {\r\n throw new Error(\r\n \"[PayPal] Forbidden (403) — this request is not allowed. Check your CORS and API key settings.\"\r\n )\r\n }\r\n throw new Error(text || `Request failed (${res.status})`)\r\n }\r\n if (!text) return {} as T\r\n\r\n const contentType = res.headers.get(\"content-type\") || \"\"\r\n if (!contentType.includes(\"application/json\")) {\r\n console.warn(\"[PayPal] Unexpected non-JSON response:\", contentType, text.slice(0, 200))\r\n return {} as T\r\n }\r\n\r\n try {\r\n return JSON.parse(text) as T\r\n } catch {\r\n console.warn(\"[PayPal] Failed to parse JSON response:\", text.slice(0, 200))\r\n return {} as T\r\n }\r\n }\r\n\r\n return { request }\r\n}\r\n","import type { PayPalConfig, PayPalSettingsResponse } from \"./types\"\r\nimport { createHttpClient, type HttpOptions } from \"./http\"\r\n\r\nexport function createPayPalStoreApi(opts: HttpOptions) {\r\n const http = createHttpClient(opts)\r\n\r\n return {\r\n getConfig(cartId?: string, signal?: AbortSignal) {\r\n const q = cartId ? `?cart_id=${encodeURIComponent(cartId)}` : \"\"\r\n return http.request<PayPalConfig>(`/store/paypal/config${q}`, { signal })\r\n },\r\n\r\n getSettings() {\r\n return http.request<PayPalSettingsResponse>(`/store/paypal/settings`)\r\n },\r\n\r\n createOrder(cartId: string) {\r\n return http.request<{ id: string }>(`/store/paypal/create-order`, {\r\n method: \"POST\",\r\n headers: { \"Content-Type\": \"application/json\" },\r\n body: JSON.stringify({ cart_id: cartId }),\r\n })\r\n },\r\n\r\n captureOrder(cartId: string, orderId: string) {\r\n return http.request<Record<string, unknown>>(`/store/paypal/capture-order`, {\r\n method: \"POST\",\r\n headers: { \"Content-Type\": \"application/json\" },\r\n body: JSON.stringify({ cart_id: cartId, order_id: orderId }),\r\n })\r\n },\r\n }\r\n}\r\n","import { useEffect, useMemo, useState } from \"react\"\r\nimport { createPayPalStoreApi } from \"../client/paypal\"\r\nimport type { PayPalConfig } from \"../client/types\"\r\n\r\ntype Args = {\r\n baseUrl: string\r\n publishableApiKey?: string\r\n cartId?: string\r\n enabled?: boolean\r\n}\r\n\r\nexport function usePayPalConfig({ baseUrl, publishableApiKey, cartId, enabled = true }: Args) {\r\n const api = useMemo(\r\n () => createPayPalStoreApi({ baseUrl, publishableApiKey }),\r\n [baseUrl, publishableApiKey]\r\n )\r\n\r\n const [config, setConfig] = useState<PayPalConfig | null>(null)\r\n const [loading, setLoading] = useState(false)\r\n const [error, setError] = useState<string | null>(null)\r\n\r\n useEffect(() => {\r\n if (!enabled) {\r\n setLoading(false)\r\n setError(null)\r\n setConfig(null)\r\n return\r\n }\r\n\r\n let mounted = true\r\n const controller = new AbortController()\r\n ;(async () => {\r\n try {\r\n setLoading(true)\r\n setError(null)\r\n const cfg = await api.getConfig(cartId, controller.signal)\r\n if (mounted) setConfig(cfg)\r\n } catch (e: any) {\r\n if (e?.name === \"AbortError\") return\r\n if (mounted) setError(e?.message || \"Failed to load PayPal config\")\r\n } finally {\r\n if (mounted) setLoading(false)\r\n }\r\n })()\r\n\r\n return () => {\r\n mounted = false\r\n controller.abort()\r\n }\r\n }, [api, cartId, enabled])\r\n\r\n return { config, loading, error }\r\n}\r\n","\"use client\"\r\n\r\nimport React, { useMemo } from \"react\"\r\nimport { PayPalScriptProvider } from \"@paypal/react-paypal-js\"\r\nimport type { ReactPayPalScriptOptions } from \"@paypal/react-paypal-js\"\r\nimport type { PayPalConfig } from \"../client/types\"\r\n\r\nexport function PayPalProvider(props: {\r\n config: PayPalConfig\r\n intent?: \"capture\" | \"authorize\"\r\n disableFunding?: string\r\n children: React.ReactNode\r\n}) {\r\n const { config, intent = \"capture\", disableFunding, children } = props\r\n\r\n const options = useMemo((): ReactPayPalScriptOptions => {\r\n return {\r\n clientId: config.client_id,\r\n \"client-id\": config.client_id,\r\n currency: config.currency,\r\n intent,\r\n components: config.client_token ? \"buttons,card-fields\" : \"buttons\",\r\n \"data-client-token\": config.client_token || undefined,\r\n \"disable-funding\": disableFunding,\r\n }\r\n }, [config, intent, disableFunding])\r\n\r\n return <PayPalScriptProvider options={options}>{children}</PayPalScriptProvider>\r\n}\r\n","\"use client\"\n\nimport React from \"react\"\nimport type { PayPalConfig } from \"../client/types\"\n\nexport function PayPalCurrencyNotice({ config }: { config: PayPalConfig }) {\n if (config.currency_supported) return null\n\n return (\n <div style={{ padding: 12, border: \"1px solid #ddd\", borderRadius: 10 }}>\n <div style={{ fontWeight: 600, marginBottom: 6 }}>PayPal currency issue</div>\n <ul style={{ margin: 0, paddingLeft: 18 }}>\n {(config.currency_errors || []).map((e, i) => (\n <li key={i}>{e}</li>\n ))}\n </ul>\n </div>\n )\n}\n","\"use client\"\r\n\r\nimport React, { useMemo, useState } from \"react\"\r\nimport { PayPalButtons } from \"@paypal/react-paypal-js\"\r\nimport { createPayPalStoreApi } from \"../client/paypal\"\r\nimport type { PayPalConfig } from \"../client/types\"\r\n\r\nexport function PayPalSmartButtons(props: {\r\n baseUrl: string\r\n publishableApiKey?: string\r\n cartId: string\r\n config: PayPalConfig\r\n onPaid?: (result: Record<string, unknown>) => void\r\n onError?: (message: string) => void\r\n}) {\r\n const { baseUrl, publishableApiKey, cartId, config, onPaid, onError } = props\r\n const api = useMemo(\r\n () => createPayPalStoreApi({ baseUrl, publishableApiKey }),\r\n [baseUrl, publishableApiKey]\r\n )\r\n\r\n const [error, setError] = useState<string | null>(null)\r\n\r\n if (!config.currency_supported) return null\r\n\r\n return (\r\n <div>\r\n <PayPalButtons\r\n style={{\r\n layout: \"vertical\",\r\n color: config.button_color,\r\n shape: config.button_shape,\r\n label: config.button_label,\r\n height: config.button_height,\r\n }}\r\n createOrder={async () => {\r\n setError(null)\r\n const r = await api.createOrder(cartId)\r\n return r.id\r\n }}\r\n onApprove={async (data: { orderID?: string }) => {\r\n try {\r\n setError(null)\r\n const orderId = String(data?.orderID || \"\")\r\n const result = await api.captureOrder(cartId, orderId)\r\n onPaid?.(result)\r\n } catch (e: unknown) {\r\n const msg = e instanceof Error ? e.message : \"Payment capture failed\"\r\n setError(msg)\r\n onError?.(msg)\r\n }\r\n }}\r\n onError={(err: Error | { message?: string }) => {\r\n const msg = err instanceof Error ? err.message : err?.message || \"PayPal error\"\r\n setError(msg)\r\n onError?.(msg)\r\n }}\r\n />\r\n {error ? <div style={{ marginTop: 10, color: \"crimson\" }}>{error}</div> : null}\r\n </div>\r\n )\r\n}\r\n","\"use client\"\r\n\r\nimport React, { useMemo, useState } from \"react\"\r\nimport {\r\n PayPalCardFieldsProvider,\r\n PayPalNameField,\r\n PayPalNumberField,\r\n PayPalExpiryField,\r\n PayPalCVVField,\r\n usePayPalCardFields,\r\n} from \"@paypal/react-paypal-js\"\r\nimport { createPayPalStoreApi } from \"../client/paypal\"\r\nimport type { PayPalConfig } from \"../client/types\"\r\n\r\nfunction SubmitButton({ disabled, label }: { disabled: boolean; label: string }) {\r\n const { cardFieldsForm } = usePayPalCardFields()\r\n\r\n return (\r\n <button\r\n type=\"button\"\r\n disabled={disabled || !cardFieldsForm}\r\n onClick={() => cardFieldsForm?.submit()}\r\n style={{ padding: \"10px 12px\", borderRadius: 10, border: \"1px solid #ddd\" }}\r\n >\r\n {label}\r\n </button>\r\n )\r\n}\r\n\r\nexport function PayPalAdvancedCard(props: {\r\n baseUrl: string\r\n publishableApiKey?: string\r\n cartId: string\r\n config: PayPalConfig\r\n onPaid?: (result: Record<string, unknown>) => void\r\n onError?: (message: string) => void\r\n}) {\r\n const { baseUrl, publishableApiKey, cartId, config, onPaid, onError } = props\r\n const api = useMemo(\r\n () => createPayPalStoreApi({ baseUrl, publishableApiKey }),\r\n [baseUrl, publishableApiKey]\r\n )\r\n\r\n const [error, setError] = useState<string | null>(null)\r\n const [submitting, setSubmitting] = useState(false)\r\n\r\n if (!config.currency_supported) return null\r\n\r\n if (!config.client_token) {\r\n return (\r\n <div style={{ padding: 12, border: \"1px solid #ddd\", borderRadius: 10 }}>\r\n CardFields unavailable: missing client_token from backend.\r\n </div>\r\n )\r\n }\r\n\r\n return (\r\n <PayPalCardFieldsProvider\r\n createOrder={async () => {\r\n setError(null)\r\n const r = await api.createOrder(cartId)\r\n return r.id\r\n }}\r\n onApprove={async (data: { orderID?: string }) => {\r\n try {\r\n setSubmitting(true)\r\n setError(null)\r\n const orderId = String(data?.orderID || \"\")\r\n const result = await api.captureOrder(cartId, orderId)\r\n onPaid?.(result)\r\n } catch (e: unknown) {\r\n const msg = e instanceof Error ? e.message : \"Card payment failed\"\r\n setError(msg)\r\n onError?.(msg)\r\n } finally {\r\n setSubmitting(false)\r\n }\r\n }}\r\n onError={(e: Error | { message?: string }) => {\r\n const msg = e instanceof Error ? e.message : e?.message || \"CardFields error\"\r\n setError(msg)\r\n onError?.(msg)\r\n }}\r\n >\r\n <div style={{ display: \"grid\", gap: 10 }}>\r\n <PayPalNameField />\r\n <PayPalNumberField />\r\n <div style={{ display: \"grid\", gridTemplateColumns: \"1fr 1fr\", gap: 10 }}>\r\n <PayPalExpiryField />\r\n <PayPalCVVField />\r\n </div>\r\n\r\n <SubmitButton disabled={submitting} label={submitting ? \"Processing...\" : \"Pay by Card\"} />\r\n\r\n {error ? <div style={{ color: \"crimson\" }}>{error}</div> : null}\r\n </div>\r\n </PayPalCardFieldsProvider>\r\n )\r\n}\r\n","\"use client\"\r\n\r\nimport React, { useCallback } from \"react\"\r\nimport { PayPalCurrencyNotice } from \"../components/PayPalCurrencyNotice\"\r\nimport { PayPalAdvancedCard } from \"../components/PayPalAdvancedCard\"\r\nimport { PayPalProvider } from \"../components/PayPalProvider\"\r\nimport { PayPalSmartButtons } from \"../components/PayPalSmartButtons\"\r\nimport { usePayPalConfig } from \"../hooks/usePayPalConfig\"\r\n\r\nconst DEFAULT_PAYPAL_PROVIDER_ID = \"pp_paypal_paypal\"\r\nconst DEFAULT_PAYPAL_CARD_PROVIDER_ID = \"pp_paypal_card_paypal_card\"\r\n\r\nexport type MedusaNextPayPalAdapterProps = {\r\n cartId: string\r\n selectedProviderId: string | null | undefined\r\n baseUrl: string\r\n publishableApiKey?: string\r\n providerIds?: {\r\n paypal?: string\r\n paypalCard?: string\r\n }\r\n /**\r\n * Called after PayPal capture succeeds.\r\n * The storefront must call placeOrder(cartId) here — that is the only\r\n * correct way to clear the _medusa_cart_id cookie, because placeOrder\r\n * is a Next.js Server Action that calls removeCartId() server-side.\r\n * A client-side fetch cannot clear an httpOnly cookie set by the server.\r\n */\r\n onSuccess?: (cartId: string) => void\r\n onError?: (message: string) => void\r\n /** @deprecated use onSuccess */\r\n onPaid?: (result: unknown) => void\r\n}\r\n\r\nexport function MedusaNextPayPalAdapter(props: MedusaNextPayPalAdapterProps) {\r\n const {\r\n cartId,\r\n selectedProviderId,\r\n baseUrl,\r\n publishableApiKey,\r\n providerIds,\r\n onSuccess,\r\n onError,\r\n onPaid,\r\n } = props\r\n\r\n const paypalProviderId = providerIds?.paypal || DEFAULT_PAYPAL_PROVIDER_ID\r\n const paypalCardProviderId = providerIds?.paypalCard || DEFAULT_PAYPAL_CARD_PROVIDER_ID\r\n\r\n const shouldRender =\r\n selectedProviderId === paypalProviderId ||\r\n selectedProviderId === paypalCardProviderId\r\n\r\n const { config, loading, error } = usePayPalConfig({\r\n baseUrl,\r\n publishableApiKey,\r\n cartId,\r\n enabled: shouldRender,\r\n })\r\n\r\n // After capture succeeds: call both the legacy onPaid and the new onSuccess.\r\n // Cart completion and cookie clearing must happen in the storefront via\r\n // placeOrder() — we intentionally do NOT call /store/carts/:id/complete here\r\n // because that endpoint does not clear the Next.js server-side cart cookie.\r\n const handlePaid = useCallback(\r\n (captureResult: unknown) => {\r\n onPaid?.(captureResult)\r\n onSuccess?.(cartId)\r\n },\r\n [cartId, onPaid, onSuccess]\r\n )\r\n\r\n if (!shouldRender) return null\r\n if (loading) return <div>Loading PayPal…</div>\r\n if (error) return <div style={{ color: \"crimson\" }}>{error}</div>\r\n if (!config) return null\r\n if (config.paypal_enabled === false) return null\r\n\r\n const disableFunding = Array.isArray(config.disable_buttons)\r\n ? config.disable_buttons.join(\",\")\r\n : undefined\r\n\r\n return (\r\n <div style={{ display: \"grid\", gap: 12 }}>\r\n <PayPalCurrencyNotice config={config} />\r\n <PayPalProvider\r\n config={config}\r\n intent={config.intent === \"authorize\" ? \"authorize\" : \"capture\"}\r\n disableFunding={disableFunding}\r\n >\r\n {selectedProviderId === paypalCardProviderId ? (\r\n <PayPalAdvancedCard\r\n baseUrl={baseUrl}\r\n publishableApiKey={publishableApiKey}\r\n cartId={cartId}\r\n config={config}\r\n onPaid={handlePaid}\r\n onError={onError}\r\n />\r\n ) : (\r\n <PayPalSmartButtons\r\n baseUrl={baseUrl}\r\n publishableApiKey={publishableApiKey}\r\n cartId={cartId}\r\n config={config}\r\n onPaid={handlePaid}\r\n onError={onError}\r\n />\r\n )}\r\n </PayPalProvider>\r\n </div>\r\n )\r\n}\r\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use client"
|
|
2
2
|
|
|
3
|
-
import React from "react"
|
|
3
|
+
import React, { useCallback } from "react"
|
|
4
4
|
import { PayPalCurrencyNotice } from "../components/PayPalCurrencyNotice"
|
|
5
5
|
import { PayPalAdvancedCard } from "../components/PayPalAdvancedCard"
|
|
6
6
|
import { PayPalProvider } from "../components/PayPalProvider"
|
|
@@ -19,12 +19,30 @@ export type MedusaNextPayPalAdapterProps = {
|
|
|
19
19
|
paypal?: string
|
|
20
20
|
paypalCard?: string
|
|
21
21
|
}
|
|
22
|
-
|
|
22
|
+
/**
|
|
23
|
+
* Called after PayPal capture succeeds.
|
|
24
|
+
* The storefront must call placeOrder(cartId) here — that is the only
|
|
25
|
+
* correct way to clear the _medusa_cart_id cookie, because placeOrder
|
|
26
|
+
* is a Next.js Server Action that calls removeCartId() server-side.
|
|
27
|
+
* A client-side fetch cannot clear an httpOnly cookie set by the server.
|
|
28
|
+
*/
|
|
29
|
+
onSuccess?: (cartId: string) => void
|
|
23
30
|
onError?: (message: string) => void
|
|
31
|
+
/** @deprecated use onSuccess */
|
|
32
|
+
onPaid?: (result: unknown) => void
|
|
24
33
|
}
|
|
25
34
|
|
|
26
35
|
export function MedusaNextPayPalAdapter(props: MedusaNextPayPalAdapterProps) {
|
|
27
|
-
const {
|
|
36
|
+
const {
|
|
37
|
+
cartId,
|
|
38
|
+
selectedProviderId,
|
|
39
|
+
baseUrl,
|
|
40
|
+
publishableApiKey,
|
|
41
|
+
providerIds,
|
|
42
|
+
onSuccess,
|
|
43
|
+
onError,
|
|
44
|
+
onPaid,
|
|
45
|
+
} = props
|
|
28
46
|
|
|
29
47
|
const paypalProviderId = providerIds?.paypal || DEFAULT_PAYPAL_PROVIDER_ID
|
|
30
48
|
const paypalCardProviderId = providerIds?.paypalCard || DEFAULT_PAYPAL_CARD_PROVIDER_ID
|
|
@@ -40,23 +58,43 @@ export function MedusaNextPayPalAdapter(props: MedusaNextPayPalAdapterProps) {
|
|
|
40
58
|
enabled: shouldRender,
|
|
41
59
|
})
|
|
42
60
|
|
|
61
|
+
// After capture succeeds: call both the legacy onPaid and the new onSuccess.
|
|
62
|
+
// Cart completion and cookie clearing must happen in the storefront via
|
|
63
|
+
// placeOrder() — we intentionally do NOT call /store/carts/:id/complete here
|
|
64
|
+
// because that endpoint does not clear the Next.js server-side cart cookie.
|
|
65
|
+
const handlePaid = useCallback(
|
|
66
|
+
(captureResult: unknown) => {
|
|
67
|
+
onPaid?.(captureResult)
|
|
68
|
+
onSuccess?.(cartId)
|
|
69
|
+
},
|
|
70
|
+
[cartId, onPaid, onSuccess]
|
|
71
|
+
)
|
|
72
|
+
|
|
43
73
|
if (!shouldRender) return null
|
|
44
74
|
if (loading) return <div>Loading PayPal…</div>
|
|
45
75
|
if (error) return <div style={{ color: "crimson" }}>{error}</div>
|
|
46
76
|
if (!config) return null
|
|
77
|
+
if (config.paypal_enabled === false) return null
|
|
78
|
+
|
|
79
|
+
const disableFunding = Array.isArray(config.disable_buttons)
|
|
80
|
+
? config.disable_buttons.join(",")
|
|
81
|
+
: undefined
|
|
47
82
|
|
|
48
83
|
return (
|
|
49
84
|
<div style={{ display: "grid", gap: 12 }}>
|
|
50
85
|
<PayPalCurrencyNotice config={config} />
|
|
51
|
-
|
|
52
|
-
|
|
86
|
+
<PayPalProvider
|
|
87
|
+
config={config}
|
|
88
|
+
intent={config.intent === "authorize" ? "authorize" : "capture"}
|
|
89
|
+
disableFunding={disableFunding}
|
|
90
|
+
>
|
|
53
91
|
{selectedProviderId === paypalCardProviderId ? (
|
|
54
92
|
<PayPalAdvancedCard
|
|
55
93
|
baseUrl={baseUrl}
|
|
56
94
|
publishableApiKey={publishableApiKey}
|
|
57
95
|
cartId={cartId}
|
|
58
96
|
config={config}
|
|
59
|
-
onPaid={
|
|
97
|
+
onPaid={handlePaid}
|
|
60
98
|
onError={onError}
|
|
61
99
|
/>
|
|
62
100
|
) : (
|
|
@@ -65,7 +103,7 @@ export function MedusaNextPayPalAdapter(props: MedusaNextPayPalAdapterProps) {
|
|
|
65
103
|
publishableApiKey={publishableApiKey}
|
|
66
104
|
cartId={cartId}
|
|
67
105
|
config={config}
|
|
68
|
-
onPaid={
|
|
106
|
+
onPaid={handlePaid}
|
|
69
107
|
onError={onError}
|
|
70
108
|
/>
|
|
71
109
|
)}
|
package/src/client/http.ts
CHANGED
|
@@ -37,6 +37,16 @@ export function createHttpClient(opts: HttpOptions) {
|
|
|
37
37
|
const text = await res.text().catch(() => "")
|
|
38
38
|
|
|
39
39
|
if (!res.ok) {
|
|
40
|
+
if (res.status === 401) {
|
|
41
|
+
throw new Error(
|
|
42
|
+
"[PayPal] Unauthorized (401) — check that your publishable API key is correct and set in NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY"
|
|
43
|
+
)
|
|
44
|
+
}
|
|
45
|
+
if (res.status === 403) {
|
|
46
|
+
throw new Error(
|
|
47
|
+
"[PayPal] Forbidden (403) — this request is not allowed. Check your CORS and API key settings."
|
|
48
|
+
)
|
|
49
|
+
}
|
|
40
50
|
throw new Error(text || `Request failed (${res.status})`)
|
|
41
51
|
}
|
|
42
52
|
if (!text) return {} as T
|
package/src/client/types.ts
CHANGED
|
@@ -7,6 +7,14 @@ export type PayPalConfig = {
|
|
|
7
7
|
supported_currencies: string[]
|
|
8
8
|
client_token?: string
|
|
9
9
|
intent?: "capture" | "authorize"
|
|
10
|
+
paypal_enabled?: boolean
|
|
11
|
+
paypal_title?: string
|
|
12
|
+
button_color?: "gold" | "blue" | "silver" | "black" | "white"
|
|
13
|
+
button_shape?: "rect" | "pill" | "sharp"
|
|
14
|
+
button_width?: string
|
|
15
|
+
button_height?: number
|
|
16
|
+
button_label?: "paypal" | "checkout" | "buynow" | "pay" | "installment"
|
|
17
|
+
disable_buttons?: string[]
|
|
10
18
|
}
|
|
11
19
|
|
|
12
20
|
export type PayPalSettingsResponse = {
|
|
@@ -8,9 +8,10 @@ import type { PayPalConfig } from "../client/types"
|
|
|
8
8
|
export function PayPalProvider(props: {
|
|
9
9
|
config: PayPalConfig
|
|
10
10
|
intent?: "capture" | "authorize"
|
|
11
|
+
disableFunding?: string
|
|
11
12
|
children: React.ReactNode
|
|
12
13
|
}) {
|
|
13
|
-
const { config, intent = "capture", children } = props
|
|
14
|
+
const { config, intent = "capture", disableFunding, children } = props
|
|
14
15
|
|
|
15
16
|
const options = useMemo((): ReactPayPalScriptOptions => {
|
|
16
17
|
return {
|
|
@@ -20,8 +21,9 @@ export function PayPalProvider(props: {
|
|
|
20
21
|
intent,
|
|
21
22
|
components: config.client_token ? "buttons,card-fields" : "buttons",
|
|
22
23
|
"data-client-token": config.client_token || undefined,
|
|
24
|
+
"disable-funding": disableFunding,
|
|
23
25
|
}
|
|
24
|
-
}, [config, intent])
|
|
26
|
+
}, [config, intent, disableFunding])
|
|
25
27
|
|
|
26
28
|
return <PayPalScriptProvider options={options}>{children}</PayPalScriptProvider>
|
|
27
29
|
}
|
|
@@ -26,7 +26,13 @@ export function PayPalSmartButtons(props: {
|
|
|
26
26
|
return (
|
|
27
27
|
<div>
|
|
28
28
|
<PayPalButtons
|
|
29
|
-
style={{
|
|
29
|
+
style={{
|
|
30
|
+
layout: "vertical",
|
|
31
|
+
color: config.button_color,
|
|
32
|
+
shape: config.button_shape,
|
|
33
|
+
label: config.button_label,
|
|
34
|
+
height: config.button_height,
|
|
35
|
+
}}
|
|
30
36
|
createOrder={async () => {
|
|
31
37
|
setError(null)
|
|
32
38
|
const r = await api.createOrder(cartId)
|
|
@@ -38,8 +44,8 @@ export function PayPalSmartButtons(props: {
|
|
|
38
44
|
const orderId = String(data?.orderID || "")
|
|
39
45
|
const result = await api.captureOrder(cartId, orderId)
|
|
40
46
|
onPaid?.(result)
|
|
41
|
-
} catch (e:
|
|
42
|
-
const msg = e
|
|
47
|
+
} catch (e: unknown) {
|
|
48
|
+
const msg = e instanceof Error ? e.message : "Payment capture failed"
|
|
43
49
|
setError(msg)
|
|
44
50
|
onError?.(msg)
|
|
45
51
|
}
|