@easypayment/medusa-paypal-ui 1.0.44 โ 1.0.45
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 +134 -192
- package/package.json +5 -1
package/README.md
CHANGED
|
@@ -1,89 +1,76 @@
|
|
|
1
|
-
|
|
1
|
+
# PayPal for Medusa Frontend UI
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
**PayPal checkout UI for Medusa v2 storefronts โ Smart Buttons, Advanced Card Fields**
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
[](https://www.npmjs.com/package/@easypayment/medusa-paypal-ui)
|
|
6
|
+
[](LICENSE)
|
|
7
|
+
[](https://medusajs.com)
|
|
8
|
+
[](https://nextjs.org)
|
|
6
9
|
|
|
7
|
-
|
|
8
|
-
<a href="https://www.npmjs.com/package/@easypayment/medusa-paypal-ui"><img src="https://img.shields.io/npm/v/@easypayment/medusa-paypal-ui?color=blue&label=npm" alt="npm version" /></a>
|
|
9
|
-
<a href="LICENSE"><img src="https://img.shields.io/badge/License-MIT-green.svg" alt="License: MIT" /></a>
|
|
10
|
-
<a href="https://medusajs.com"><img src="https://img.shields.io/badge/Medusa-v2-9b59b6" alt="Medusa v2" /></a>
|
|
11
|
-
<a href="https://nextjs.org"><img src="https://img.shields.io/badge/Next.js-14%2B-black" alt="Next.js" /></a>
|
|
12
|
-
</p>
|
|
13
|
-
|
|
14
|
-
<p>PayPal Smart Buttons ยท Advanced Card Fields ยท Built-in loading states ยท Admin-controlled settings</p>
|
|
10
|
+
---
|
|
15
11
|
|
|
16
|
-
|
|
12
|
+
## ๐ Table of Contents
|
|
13
|
+
|
|
14
|
+
- [๐ฆ Overview](#-overview)
|
|
15
|
+
- [โ
Requirements](#-requirements)
|
|
16
|
+
- [๐ Installation](#-installation)
|
|
17
|
+
- [๐ Environment Variables](#-environment-variables)
|
|
18
|
+
- [๐ Integration Guide](#-integration-guide)
|
|
19
|
+
- [Step 1 โ Add the import](#step-1--add-the-import)
|
|
20
|
+
- [Step 2 โ Add PayPal helpers and state](#step-2--add-paypal-helpers-and-state)
|
|
21
|
+
- [Step 3 โ Load PayPal config](#step-3--load-paypal-config)
|
|
22
|
+
- [Step 4 โ Update setPaymentMethod](#step-4--update-setpaymentmethod)
|
|
23
|
+
- [Step 5 โ Filter the payment method list](#step-5--filter-the-payment-method-list)
|
|
24
|
+
- [Step 6 โ Inject admin-configured titles](#step-6--inject-admin-configured-titles)
|
|
25
|
+
- [Step 7 โ Render the PayPal UI](#step-7--render-the-paypal-ui)
|
|
26
|
+
- [Step 8 โ Disable the Continue button](#step-8--disable-the-continue-button)
|
|
27
|
+
- [Step 9 โ Fix the summary label](#step-9--fix-the-summary-label)
|
|
28
|
+
- [๐ Complete File](#-complete-file)
|
|
29
|
+
- [๐งช Testing](#-testing)
|
|
30
|
+
- [๐ License](#-license)
|
|
17
31
|
|
|
18
32
|
---
|
|
19
33
|
|
|
20
|
-
## Overview
|
|
34
|
+
## ๐ฆ Overview
|
|
21
35
|
|
|
22
|
-
`@easypayment/medusa-paypal-ui` is
|
|
36
|
+
`@easypayment/medusa-paypal-ui` is the **storefront UI package** that connects your Next.js (App Router) storefront to the `@easypayment/medusa-paypal` backend plugin. It ships the PayPal adapter used inside your checkout payment step โ your storefront adds the adapter, provider filtering, and backend config handling to the existing Medusa payment UI.
|
|
23
37
|
|
|
24
38
|
| Feature | Details |
|
|
25
39
|
|---|---|
|
|
26
|
-
| **PayPal Smart Buttons** | Wallet-based checkout via `pp_paypal_paypal` |
|
|
27
|
-
| **Advanced Card Fields** | Hosted PCI-compliant card inputs via `pp_paypal_card_paypal_card` |
|
|
28
|
-
| **Admin-driven config** | Enable/disable providers and set labels from Medusa Admin |
|
|
29
|
-
| **Built-in UX** | Smart Buttons and Advanced Card UI
|
|
30
|
-
| **Storefront-controlled flow** | Your payment step controls session creation, loading states, and `placeOrder` |
|
|
31
|
-
|
|
32
|
-
---
|
|
33
|
-
|
|
34
|
-
## Table of Contents
|
|
35
|
-
|
|
36
|
-
- [Requirements](#requirements)
|
|
37
|
-
- [Installation](#installation)
|
|
38
|
-
- [Environment Variables](#environment-variables)
|
|
39
|
-
- [Integration Guide](#integration-guide)
|
|
40
|
-
- [Step 1 - Add the import](#step-1---add-the-import)
|
|
41
|
-
- [Step 2 - Add PayPal helpers and state](#step-2---add-paypal-helpers-and-state)
|
|
42
|
-
- [Step 3 - Load config from /store/paypal/config](#step-3---load-config-from-storepaypalconfig)
|
|
43
|
-
- [Step 4 - Update setPaymentMethod](#step-4---update-setpaymentmethod)
|
|
44
|
-
- [Step 5 - Filter the payment method list](#step-5---filter-the-payment-method-list)
|
|
45
|
-
- [Step 6 - Inject admin-configured titles](#step-6---inject-admin-configured-titles)
|
|
46
|
-
- [Step 7 - Render the PayPal UI](#step-7---render-the-paypal-ui)
|
|
47
|
-
- [Step 8 - Disable the Continue button](#step-8---disable-the-continue-button)
|
|
48
|
-
- [Step 9 - Fix the summary label](#step-9---fix-the-summary-label)
|
|
49
|
-
- [Complete File](#complete-file)
|
|
50
|
-
- [Testing](#testing)
|
|
40
|
+
| ๐ต **PayPal Smart Buttons** | Wallet-based checkout via `pp_paypal_paypal` |
|
|
41
|
+
| ๐ณ **Advanced Card Fields** | Hosted PCI-compliant advanced credit card inputs via `pp_paypal_card_paypal_card` |
|
|
42
|
+
| ๐ **Admin-driven config** | Enable/disable providers and set labels from Medusa Admin |
|
|
43
|
+
| โก **Built-in UX** | Smart Buttons and Advanced Card UI rendered by `MedusaNextPayPalAdapter` |
|
|
44
|
+
| ๐ **Storefront-controlled flow** | Your payment step controls session creation, loading states, and `placeOrder` |
|
|
51
45
|
|
|
52
46
|
---
|
|
53
47
|
|
|
54
|
-
## Requirements
|
|
48
|
+
## โ
Requirements
|
|
55
49
|
|
|
56
50
|
- **Node.js** 18+
|
|
57
51
|
- **Next.js** 14+ with App Router
|
|
58
|
-
-
|
|
59
|
-
- A PayPal account connected in Medusa Admin โ Settings โ PayPal โ PayPal Connection
|
|
52
|
+
- **`@easypayment/medusa-paypal`** installed and running on your Medusa server
|
|
53
|
+
- A PayPal account connected in **Medusa Admin โ Settings โ PayPal โ PayPal Connection**
|
|
60
54
|
|
|
61
55
|
---
|
|
62
56
|
|
|
63
|
-
## Installation
|
|
57
|
+
## ๐ Installation
|
|
64
58
|
|
|
65
|
-
|
|
66
|
-
npm install @easypayment/medusa-paypal-ui
|
|
67
|
-
```
|
|
59
|
+
**In your storefront directory**, run:
|
|
68
60
|
|
|
69
61
|
```bash
|
|
70
|
-
|
|
62
|
+
npm install @easypayment/medusa-paypal-ui
|
|
71
63
|
```
|
|
72
64
|
|
|
73
65
|
---
|
|
74
66
|
|
|
75
|
-
## Environment Variables
|
|
67
|
+
## ๐ Environment Variables
|
|
76
68
|
|
|
77
69
|
Add the following to your storefront `.env.local`. Use separate values for development and production.
|
|
78
70
|
|
|
79
71
|
```env
|
|
80
|
-
# Development
|
|
81
72
|
NEXT_PUBLIC_MEDUSA_BACKEND_URL=http://localhost:9000
|
|
82
73
|
NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY=pk_...
|
|
83
|
-
|
|
84
|
-
# Production
|
|
85
|
-
NEXT_PUBLIC_MEDUSA_BACKEND_URL=https://your-medusa-server.com
|
|
86
|
-
NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY=pk_...
|
|
87
74
|
```
|
|
88
75
|
|
|
89
76
|
> **Where to get the publishable key:**
|
|
@@ -91,21 +78,23 @@ NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY=pk_...
|
|
|
91
78
|
|
|
92
79
|
---
|
|
93
80
|
|
|
94
|
-
## Integration Guide
|
|
81
|
+
## ๐ Integration Guide
|
|
95
82
|
|
|
96
|
-
All changes are made to
|
|
83
|
+
All changes in this guide are made to **one single file** in your storefront:
|
|
97
84
|
|
|
98
85
|
```
|
|
99
86
|
src/modules/checkout/components/payment/index.tsx
|
|
100
87
|
```
|
|
101
88
|
|
|
102
|
-
|
|
89
|
+
Open that file and follow each step in order.
|
|
90
|
+
|
|
91
|
+
> **Prefer to copy-paste the whole file?** Skip straight to [Complete File](#-complete-file) and replace the entire contents in one go. The complete file has all 9 steps already applied.
|
|
103
92
|
|
|
104
93
|
---
|
|
105
94
|
|
|
106
|
-
### Step 1
|
|
95
|
+
### Step 1 โ Add the import
|
|
107
96
|
|
|
108
|
-
|
|
97
|
+
**Where:** At the very top of the file, alongside your other imports.
|
|
109
98
|
|
|
110
99
|
```tsx
|
|
111
100
|
import { MedusaNextPayPalAdapter } from "@easypayment/medusa-paypal-ui"
|
|
@@ -113,17 +102,21 @@ import { MedusaNextPayPalAdapter } from "@easypayment/medusa-paypal-ui"
|
|
|
113
102
|
|
|
114
103
|
---
|
|
115
104
|
|
|
116
|
-
### Step 2
|
|
105
|
+
### Step 2 โ Add PayPal helpers and state
|
|
117
106
|
|
|
118
|
-
|
|
107
|
+
**Where:** At the top of the file, outside the component โ add the constants. Inside the `Payment` component, add the `useState` lines alongside your other state declarations.
|
|
119
108
|
|
|
120
109
|
```tsx
|
|
110
|
+
// Outside the component โ add these constants
|
|
121
111
|
const PAYPAL_PROVIDER_ID = "pp_paypal_paypal"
|
|
122
112
|
const PAYPAL_CARD_PROVIDER_ID = "pp_paypal_card_paypal_card"
|
|
123
113
|
const PAYPAL_PROVIDER_IDS = [PAYPAL_PROVIDER_ID, PAYPAL_CARD_PROVIDER_ID]
|
|
124
114
|
|
|
125
115
|
const isPayPal = (id: string) => PAYPAL_PROVIDER_IDS.includes(id)
|
|
116
|
+
```
|
|
126
117
|
|
|
118
|
+
```tsx
|
|
119
|
+
// Inside the Payment component โ add alongside your other useState declarations
|
|
127
120
|
const [paypalEnabled, setPaypalEnabled] = useState(true)
|
|
128
121
|
const [paypalTitle, setPaypalTitle] = useState("PayPal")
|
|
129
122
|
const [cardEnabled, setCardEnabled] = useState(true)
|
|
@@ -133,21 +126,18 @@ const [paypalLoading, setPaypalLoading] = useState(false)
|
|
|
133
126
|
|
|
134
127
|
---
|
|
135
128
|
|
|
136
|
-
### Step 3
|
|
129
|
+
### Step 3 โ Load PayPal config
|
|
130
|
+
|
|
131
|
+
**Where:** Inside the `Payment` component, alongside your other `useEffect` hooks.
|
|
137
132
|
|
|
138
|
-
|
|
133
|
+
This fetches PayPal settings from your backend whenever the payment step is opened, so the UI always reflects the latest admin configuration.
|
|
139
134
|
|
|
140
135
|
```tsx
|
|
141
136
|
useEffect(() => {
|
|
142
|
-
if (!isOpen)
|
|
143
|
-
return
|
|
144
|
-
}
|
|
137
|
+
if (!isOpen) return
|
|
145
138
|
|
|
146
139
|
const backendUrl = process.env.NEXT_PUBLIC_MEDUSA_BACKEND_URL
|
|
147
|
-
|
|
148
|
-
if (!backendUrl) {
|
|
149
|
-
return
|
|
150
|
-
}
|
|
140
|
+
if (!backendUrl) return
|
|
151
141
|
|
|
152
142
|
const key = process.env.NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY
|
|
153
143
|
const controller = new AbortController()
|
|
@@ -165,74 +155,56 @@ useEffect(() => {
|
|
|
165
155
|
return
|
|
166
156
|
}
|
|
167
157
|
|
|
168
|
-
if (!response.ok)
|
|
169
|
-
return
|
|
170
|
-
}
|
|
158
|
+
if (!response.ok) return
|
|
171
159
|
|
|
172
160
|
const config = await response.json()
|
|
173
161
|
|
|
174
|
-
if (typeof config?.paypal_enabled === "boolean")
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
if (typeof config?.paypal_title === "string" && config.paypal_title) {
|
|
179
|
-
setPaypalTitle(config.paypal_title)
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
if (typeof config?.card_enabled === "boolean") {
|
|
183
|
-
setCardEnabled(config.card_enabled)
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
if (typeof config?.card_title === "string" && config.card_title) {
|
|
187
|
-
setCardTitle(config.card_title)
|
|
188
|
-
}
|
|
162
|
+
if (typeof config?.paypal_enabled === "boolean") setPaypalEnabled(config.paypal_enabled)
|
|
163
|
+
if (typeof config?.paypal_title === "string" && config.paypal_title) setPaypalTitle(config.paypal_title)
|
|
164
|
+
if (typeof config?.card_enabled === "boolean") setCardEnabled(config.card_enabled)
|
|
165
|
+
if (typeof config?.card_title === "string" && config.card_title) setCardTitle(config.card_title)
|
|
189
166
|
} catch (err) {
|
|
190
|
-
if ((err as Error).name !== "AbortError")
|
|
191
|
-
setPaypalLoading(false)
|
|
192
|
-
}
|
|
167
|
+
if ((err as Error).name !== "AbortError") setPaypalLoading(false)
|
|
193
168
|
}
|
|
194
169
|
}
|
|
195
170
|
|
|
196
171
|
void loadPayPalConfig()
|
|
197
|
-
|
|
198
172
|
return () => controller.abort()
|
|
199
173
|
}, [isOpen])
|
|
200
174
|
```
|
|
201
175
|
|
|
202
176
|
---
|
|
203
177
|
|
|
204
|
-
### Step 4
|
|
178
|
+
### Step 4 โ Update setPaymentMethod
|
|
179
|
+
|
|
180
|
+
**Where:** Inside the `Payment` component. Find your existing `setPaymentMethod` function and **replace it entirely** with the version below.
|
|
205
181
|
|
|
206
|
-
|
|
182
|
+
The key addition is `paypalLoading` โ it shows a loading indicator while the PayPal payment session is being created in the background.
|
|
207
183
|
|
|
208
184
|
```tsx
|
|
209
185
|
const setPaymentMethod = async (method: string) => {
|
|
210
186
|
setError(null)
|
|
211
187
|
setSelectedPaymentMethod(method)
|
|
212
188
|
|
|
213
|
-
if (!isStripeLike(method) && !isPayPal(method))
|
|
214
|
-
return
|
|
215
|
-
}
|
|
189
|
+
if (!isStripeLike(method) && !isPayPal(method)) return
|
|
216
190
|
|
|
217
|
-
if (isPayPal(method))
|
|
218
|
-
setPaypalLoading(true)
|
|
219
|
-
}
|
|
191
|
+
if (isPayPal(method)) setPaypalLoading(true)
|
|
220
192
|
|
|
221
193
|
try {
|
|
222
194
|
await initiatePaymentSession(cart, { provider_id: method })
|
|
223
195
|
} finally {
|
|
224
|
-
if (isPayPal(method))
|
|
225
|
-
setPaypalLoading(false)
|
|
226
|
-
}
|
|
196
|
+
if (isPayPal(method)) setPaypalLoading(false)
|
|
227
197
|
}
|
|
228
198
|
}
|
|
229
199
|
```
|
|
230
200
|
|
|
231
201
|
---
|
|
232
202
|
|
|
233
|
-
### Step 5
|
|
203
|
+
### Step 5 โ Filter the payment method list
|
|
234
204
|
|
|
235
|
-
|
|
205
|
+
**Where:** Inside the `Payment` component, alongside your other `useMemo` declarations โ add this before the `return` statement.
|
|
206
|
+
|
|
207
|
+
This hides PayPal or Card from the list if they have been disabled in Medusa Admin.
|
|
236
208
|
|
|
237
209
|
```tsx
|
|
238
210
|
const filteredPaymentMethods = useMemo(
|
|
@@ -246,33 +218,33 @@ const filteredPaymentMethods = useMemo(
|
|
|
246
218
|
)
|
|
247
219
|
```
|
|
248
220
|
|
|
249
|
-
Then
|
|
221
|
+
Then in your JSX, find where you render `availablePaymentMethods.map(...)` and **replace** `availablePaymentMethods` with `filteredPaymentMethods`:
|
|
222
|
+
|
|
223
|
+
```tsx
|
|
224
|
+
// Before
|
|
225
|
+
availablePaymentMethods.map((paymentMethod) => ( ... ))
|
|
226
|
+
|
|
227
|
+
// After
|
|
228
|
+
filteredPaymentMethods.map((paymentMethod) => ( ... ))
|
|
229
|
+
```
|
|
250
230
|
|
|
251
231
|
---
|
|
252
232
|
|
|
253
|
-
### Step 6
|
|
233
|
+
### Step 6 โ Inject admin-configured titles
|
|
234
|
+
|
|
235
|
+
**Where:** Inside the `.map()` loop from Step 5, find your `<PaymentContainer>` component and **replace** its `paymentInfoMap` prop with the version below.
|
|
254
236
|
|
|
255
|
-
|
|
237
|
+
This makes the radio button labels show the titles configured in Medusa Admin instead of hardcoded defaults.
|
|
256
238
|
|
|
257
239
|
```tsx
|
|
258
240
|
<PaymentContainer
|
|
259
241
|
paymentInfoMap={{
|
|
260
242
|
...paymentInfoMap,
|
|
261
243
|
...(paymentMethod.id === PAYPAL_PROVIDER_ID
|
|
262
|
-
? {
|
|
263
|
-
[paymentMethod.id]: {
|
|
264
|
-
...(paymentInfoMap[paymentMethod.id] || {}),
|
|
265
|
-
title: paypalTitle,
|
|
266
|
-
},
|
|
267
|
-
}
|
|
244
|
+
? { [paymentMethod.id]: { ...(paymentInfoMap[paymentMethod.id] || {}), title: paypalTitle } }
|
|
268
245
|
: {}),
|
|
269
246
|
...(paymentMethod.id === PAYPAL_CARD_PROVIDER_ID
|
|
270
|
-
? {
|
|
271
|
-
[paymentMethod.id]: {
|
|
272
|
-
...(paymentInfoMap[paymentMethod.id] || {}),
|
|
273
|
-
title: cardTitle,
|
|
274
|
-
},
|
|
275
|
-
}
|
|
247
|
+
? { [paymentMethod.id]: { ...(paymentInfoMap[paymentMethod.id] || {}), title: cardTitle } }
|
|
276
248
|
: {}),
|
|
277
249
|
}}
|
|
278
250
|
paymentProviderId={paymentMethod.id}
|
|
@@ -282,17 +254,19 @@ Inside your `.map()`, pass an overridden `paymentInfoMap` to the `PaymentContain
|
|
|
282
254
|
|
|
283
255
|
---
|
|
284
256
|
|
|
285
|
-
### Step 7
|
|
257
|
+
### Step 7 โ Render the PayPal UI
|
|
258
|
+
|
|
259
|
+
**Where:** In the JSX, immediately after the closing `</RadioGroup>` tag.
|
|
286
260
|
|
|
287
|
-
|
|
261
|
+
The first block shows a loading spinner while the session is being set up. The second block renders the PayPal buttons or card fields once the session is ready.
|
|
288
262
|
|
|
289
263
|
```tsx
|
|
264
|
+
{/* Loading state while PayPal session is being created */}
|
|
290
265
|
{isPayPal(selectedPaymentMethod) && paypalLoading && (
|
|
291
|
-
<div>
|
|
292
|
-
<div>Setting up payment...</div>
|
|
293
|
-
</div>
|
|
266
|
+
<div>Setting up payment...</div>
|
|
294
267
|
)}
|
|
295
268
|
|
|
269
|
+
{/* PayPal buttons or card fields */}
|
|
296
270
|
{isPayPal(selectedPaymentMethod) && !paypalLoading && (
|
|
297
271
|
<MedusaNextPayPalAdapter
|
|
298
272
|
cartId={cart.id}
|
|
@@ -307,17 +281,13 @@ After the closing `</RadioGroup>` tag, render a loading state while the PayPal s
|
|
|
307
281
|
)}
|
|
308
282
|
```
|
|
309
283
|
|
|
310
|
-
> **Critical โ `onSuccess` must call `placeOrder`**
|
|
311
|
-
>
|
|
312
|
-
> `placeOrder` is the Next.js Server Action exported from `@lib/data/cart`. It **must** run server-side โ it is the only mechanism that can clear the httpOnly cart cookie set by the server. Replacing it with a client-side `fetch` to `/store/carts/:id/complete` will complete the order in Medusa but leave the cart cookie intact, breaking the storefront session.
|
|
313
|
-
|
|
314
284
|
---
|
|
315
285
|
|
|
316
|
-
### Step 8
|
|
286
|
+
### Step 8 โ Disable the Continue button
|
|
317
287
|
|
|
318
|
-
|
|
288
|
+
**Where:** In the JSX, find your existing `<Button>` with `data-testid="submit-payment-button"` and **add** `isPayPal(selectedPaymentMethod)` to its `disabled` prop.
|
|
319
289
|
|
|
320
|
-
|
|
290
|
+
PayPal handles its own checkout action, so the "Continue to review" button must be hidden from the flow when PayPal is selected.
|
|
321
291
|
|
|
322
292
|
```tsx
|
|
323
293
|
<Button
|
|
@@ -328,7 +298,7 @@ Add `isPayPal(selectedPaymentMethod)` to your `Button` component's `disabled` pr
|
|
|
328
298
|
disabled={
|
|
329
299
|
(isStripeLike(selectedPaymentMethod) && !cardComplete) ||
|
|
330
300
|
(!selectedPaymentMethod && !paidByGiftcard) ||
|
|
331
|
-
isPayPal(selectedPaymentMethod)
|
|
301
|
+
isPayPal(selectedPaymentMethod) // ๐ add this line
|
|
332
302
|
}
|
|
333
303
|
data-testid="submit-payment-button"
|
|
334
304
|
>
|
|
@@ -340,9 +310,11 @@ Add `isPayPal(selectedPaymentMethod)` to your `Button` component's `disabled` pr
|
|
|
340
310
|
|
|
341
311
|
---
|
|
342
312
|
|
|
343
|
-
### Step 9
|
|
313
|
+
### Step 9 โ Fix the summary label
|
|
344
314
|
|
|
345
|
-
In the collapsed summary view (shown after the customer has
|
|
315
|
+
**Where:** In the collapsed summary view (shown after the customer has completed the payment step). Find the `<Text>` with `data-testid="payment-method-summary"` and **replace its content** with the version below.
|
|
316
|
+
|
|
317
|
+
This shows the admin-configured title instead of a hardcoded or missing label.
|
|
346
318
|
|
|
347
319
|
```tsx
|
|
348
320
|
<Text
|
|
@@ -360,9 +332,9 @@ In the collapsed summary view (shown after the customer has selected a payment m
|
|
|
360
332
|
|
|
361
333
|
---
|
|
362
334
|
|
|
363
|
-
## Complete File
|
|
335
|
+
## ๐ Complete File
|
|
364
336
|
|
|
365
|
-
|
|
337
|
+
If you prefer to copy-paste the entire file at once, replace the full contents of `src/modules/checkout/components/payment/index.tsx` with the following:
|
|
366
338
|
|
|
367
339
|
```tsx
|
|
368
340
|
"use client"
|
|
@@ -420,14 +392,8 @@ const Payment = ({
|
|
|
420
392
|
const filteredPaymentMethods = useMemo(
|
|
421
393
|
() =>
|
|
422
394
|
availablePaymentMethods.filter((paymentMethod) => {
|
|
423
|
-
if (paymentMethod.id === PAYPAL_PROVIDER_ID)
|
|
424
|
-
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
if (paymentMethod.id === PAYPAL_CARD_PROVIDER_ID) {
|
|
428
|
-
return cardEnabled
|
|
429
|
-
}
|
|
430
|
-
|
|
395
|
+
if (paymentMethod.id === PAYPAL_PROVIDER_ID) return paypalEnabled
|
|
396
|
+
if (paymentMethod.id === PAYPAL_CARD_PROVIDER_ID) return cardEnabled
|
|
431
397
|
return true
|
|
432
398
|
}),
|
|
433
399
|
[availablePaymentMethods, cardEnabled, paypalEnabled],
|
|
@@ -437,20 +403,14 @@ const Payment = ({
|
|
|
437
403
|
setError(null)
|
|
438
404
|
setSelectedPaymentMethod(method)
|
|
439
405
|
|
|
440
|
-
if (!isStripeLike(method) && !isPayPal(method))
|
|
441
|
-
return
|
|
442
|
-
}
|
|
406
|
+
if (!isStripeLike(method) && !isPayPal(method)) return
|
|
443
407
|
|
|
444
|
-
if (isPayPal(method))
|
|
445
|
-
setPaypalLoading(true)
|
|
446
|
-
}
|
|
408
|
+
if (isPayPal(method)) setPaypalLoading(true)
|
|
447
409
|
|
|
448
410
|
try {
|
|
449
411
|
await initiatePaymentSession(cart, { provider_id: method })
|
|
450
412
|
} finally {
|
|
451
|
-
if (isPayPal(method))
|
|
452
|
-
setPaypalLoading(false)
|
|
453
|
-
}
|
|
413
|
+
if (isPayPal(method)) setPaypalLoading(false)
|
|
454
414
|
}
|
|
455
415
|
}
|
|
456
416
|
|
|
@@ -508,15 +468,10 @@ const Payment = ({
|
|
|
508
468
|
}, [isOpen])
|
|
509
469
|
|
|
510
470
|
useEffect(() => {
|
|
511
|
-
if (!isOpen)
|
|
512
|
-
return
|
|
513
|
-
}
|
|
471
|
+
if (!isOpen) return
|
|
514
472
|
|
|
515
473
|
const backendUrl = process.env.NEXT_PUBLIC_MEDUSA_BACKEND_URL
|
|
516
|
-
|
|
517
|
-
if (!backendUrl) {
|
|
518
|
-
return
|
|
519
|
-
}
|
|
474
|
+
if (!backendUrl) return
|
|
520
475
|
|
|
521
476
|
const key = process.env.NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY
|
|
522
477
|
const controller = new AbortController()
|
|
@@ -534,36 +489,20 @@ const Payment = ({
|
|
|
534
489
|
return
|
|
535
490
|
}
|
|
536
491
|
|
|
537
|
-
if (!response.ok)
|
|
538
|
-
return
|
|
539
|
-
}
|
|
492
|
+
if (!response.ok) return
|
|
540
493
|
|
|
541
494
|
const config = await response.json()
|
|
542
495
|
|
|
543
|
-
if (typeof config?.paypal_enabled === "boolean")
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
if (typeof config?.paypal_title === "string" && config.paypal_title) {
|
|
548
|
-
setPaypalTitle(config.paypal_title)
|
|
549
|
-
}
|
|
550
|
-
|
|
551
|
-
if (typeof config?.card_enabled === "boolean") {
|
|
552
|
-
setCardEnabled(config.card_enabled)
|
|
553
|
-
}
|
|
554
|
-
|
|
555
|
-
if (typeof config?.card_title === "string" && config.card_title) {
|
|
556
|
-
setCardTitle(config.card_title)
|
|
557
|
-
}
|
|
496
|
+
if (typeof config?.paypal_enabled === "boolean") setPaypalEnabled(config.paypal_enabled)
|
|
497
|
+
if (typeof config?.paypal_title === "string" && config.paypal_title) setPaypalTitle(config.paypal_title)
|
|
498
|
+
if (typeof config?.card_enabled === "boolean") setCardEnabled(config.card_enabled)
|
|
499
|
+
if (typeof config?.card_title === "string" && config.card_title) setCardTitle(config.card_title)
|
|
558
500
|
} catch (err) {
|
|
559
|
-
if ((err as Error).name !== "AbortError")
|
|
560
|
-
setPaypalLoading(false)
|
|
561
|
-
}
|
|
501
|
+
if ((err as Error).name !== "AbortError") setPaypalLoading(false)
|
|
562
502
|
}
|
|
563
503
|
}
|
|
564
504
|
|
|
565
505
|
void loadPayPalConfig()
|
|
566
|
-
|
|
567
506
|
return () => controller.abort()
|
|
568
507
|
}, [isOpen])
|
|
569
508
|
|
|
@@ -684,14 +623,13 @@ const Payment = ({
|
|
|
684
623
|
</div>
|
|
685
624
|
</div>
|
|
686
625
|
)}
|
|
626
|
+
|
|
687
627
|
{isPayPal(selectedPaymentMethod) && !paypalLoading && (
|
|
688
628
|
<MedusaNextPayPalAdapter
|
|
689
629
|
cartId={cart.id}
|
|
690
630
|
selectedProviderId={selectedPaymentMethod}
|
|
691
631
|
baseUrl={process.env.NEXT_PUBLIC_MEDUSA_BACKEND_URL!}
|
|
692
|
-
publishableApiKey={
|
|
693
|
-
process.env.NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY
|
|
694
|
-
}
|
|
632
|
+
publishableApiKey={process.env.NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY}
|
|
695
633
|
onSuccess={async () => {
|
|
696
634
|
await placeOrder(cart.id)
|
|
697
635
|
}}
|
|
@@ -801,18 +739,22 @@ export default Payment
|
|
|
801
739
|
|
|
802
740
|
---
|
|
803
741
|
|
|
804
|
-
## Testing
|
|
742
|
+
## ๐งช Testing
|
|
805
743
|
|
|
806
|
-
Toggle between sandbox and live in Medusa Admin โ
|
|
744
|
+
Toggle between sandbox and live in **Medusa Admin โ Settings โ PayPal โ PayPal Connection โ Environment**.
|
|
807
745
|
|
|
808
|
-
**Sandbox buyer account**
|
|
746
|
+
**Sandbox buyer account** โ log in at [developer.paypal.com](https://developer.paypal.com) โ **Testing โ Sandbox Accounts** to find your auto-generated buyer credentials. Sandbox payments do not charge real money.
|
|
809
747
|
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
**Test card number for Advanced Card fields**
|
|
748
|
+
**Test card for Advanced Card Fields:**
|
|
813
749
|
|
|
814
750
|
```
|
|
815
751
|
Card number 4111 1111 1111 1111
|
|
816
752
|
Expiry Any future date
|
|
817
753
|
CVV Any 3 digits
|
|
818
|
-
```
|
|
754
|
+
```
|
|
755
|
+
|
|
756
|
+
---
|
|
757
|
+
|
|
758
|
+
## ๐ License
|
|
759
|
+
|
|
760
|
+
MIT ยฉ [Easy Payment](https://www.npmjs.com/package/@easypayment/medusa-paypal-ui)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@easypayment/medusa-paypal-ui",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.45",
|
|
4
4
|
"description": "Enterprise Gold PayPal UI module for Medusa v2 storefront (Next.js)",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -46,5 +46,9 @@
|
|
|
46
46
|
"test": "vitest run",
|
|
47
47
|
"test:watch": "vitest",
|
|
48
48
|
"prepublishOnly": "npm run build"
|
|
49
|
+
},
|
|
50
|
+
"repository": {
|
|
51
|
+
"type": "git",
|
|
52
|
+
"url": "https://github.com/easypaymentplugins/medusa-paypal-ui"
|
|
49
53
|
}
|
|
50
54
|
}
|