@wearejh/m2-pwa-adyen 0.39.0 → 0.45.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +96 -0
- package/lib/AdyenProvider.tsx +55 -57
- package/lib/PaymentMethodHandler.tsx +2 -2
- package/lib/adyen.types.ts +5 -7
- package/lib/docs/ADYEN_DOCS.md +107 -0
- package/lib/docs/ADYEN_OVERVIEW.md +138 -0
- package/lib/epics/getAdyenConfig.epic.ts +2 -1
- package/lib/paymentMethods/3DS/ThreeDS2Challenge.tsx +5 -6
- package/lib/paymentMethods/3DS/ThreeDS2Fingerprint.tsx +6 -23
- package/lib/paymentMethods/ApplePay/ApplePay.tsx +6 -18
- package/lib/paymentMethods/Card/Card.tsx +7 -3
- package/lib/paymentMethods/Giftcard/Giftcard.tsx +15 -3
- package/lib/paymentMethods/GooglePay/GooglePay.tsx +7 -19
- package/lib/paymentMethods/Klarna/Klarna.tsx +21 -7
- package/lib/paymentMethods/Klarna/KlarnaOverTime.tsx +25 -11
- package/lib/paymentMethods/Klarna/KlarnaPayNow.tsx +25 -11
- package/lib/paymentMethods/PayPal/PayPal.tsx +7 -5
- package/package.json +9 -9
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,102 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
# [0.45.0](https://github.com/WeareJH/mage-mono/compare/v0.44.0...v0.45.0) (2026-01-08)
|
|
7
|
+
|
|
8
|
+
**Note:** Version bump only for package @wearejh/m2-pwa-adyen
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
# [0.44.0](https://github.com/WeareJH/mage-mono/compare/v0.39.1...v0.44.0) (2026-01-08)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
### Bug Fixes
|
|
18
|
+
|
|
19
|
+
* only use node 12 and regenerate lockfiles ([61356b5](https://github.com/WeareJH/mage-mono/commit/61356b514f6dfc99814f7c108115c4c24bcc0a57))
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
### Features
|
|
23
|
+
|
|
24
|
+
* **WOOD-3014:** Adyen upgrade ([e22eca3](https://github.com/WeareJH/mage-mono/commit/e22eca391e293d0241e031e3769e5a27078af99e))
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
# [0.43.0](https://github.com/WeareJH/mage-mono/compare/v0.39.1...v0.43.0) (2026-01-08)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
### Bug Fixes
|
|
34
|
+
|
|
35
|
+
* only use node 12 and regenerate lockfiles ([61356b5](https://github.com/WeareJH/mage-mono/commit/61356b514f6dfc99814f7c108115c4c24bcc0a57))
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
### Features
|
|
39
|
+
|
|
40
|
+
* **WOOD-3014:** Adyen upgrade ([e22eca3](https://github.com/WeareJH/mage-mono/commit/e22eca391e293d0241e031e3769e5a27078af99e))
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
# [0.42.0](https://github.com/WeareJH/mage-mono/compare/v0.39.1...v0.42.0) (2026-01-08)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
### Bug Fixes
|
|
50
|
+
|
|
51
|
+
* only use node 12 and regenerate lockfiles ([61356b5](https://github.com/WeareJH/mage-mono/commit/61356b514f6dfc99814f7c108115c4c24bcc0a57))
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
### Features
|
|
55
|
+
|
|
56
|
+
* **WOOD-3014:** Adyen upgrade ([e22eca3](https://github.com/WeareJH/mage-mono/commit/e22eca391e293d0241e031e3769e5a27078af99e))
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
# [0.41.0](https://github.com/WeareJH/mage-mono/compare/v0.39.1...v0.41.0) (2026-01-08)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
### Bug Fixes
|
|
66
|
+
|
|
67
|
+
* only use node 12 and regenerate lockfiles ([61356b5](https://github.com/WeareJH/mage-mono/commit/61356b514f6dfc99814f7c108115c4c24bcc0a57))
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
### Features
|
|
71
|
+
|
|
72
|
+
* **WOOD-3014:** Adyen upgrade ([e22eca3](https://github.com/WeareJH/mage-mono/commit/e22eca391e293d0241e031e3769e5a27078af99e))
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
# [0.40.0](https://github.com/WeareJH/mage-mono/compare/v0.39.1...v0.40.0) (2026-01-08)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
### Bug Fixes
|
|
82
|
+
|
|
83
|
+
* only use node 12 and regenerate lockfiles ([61356b5](https://github.com/WeareJH/mage-mono/commit/61356b514f6dfc99814f7c108115c4c24bcc0a57))
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
### Features
|
|
87
|
+
|
|
88
|
+
* **WOOD-3014:** Adyen upgrade ([e22eca3](https://github.com/WeareJH/mage-mono/commit/e22eca391e293d0241e031e3769e5a27078af99e))
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
## [0.39.1](https://github.com/WeareJH/mage-mono/compare/v0.39.0...v0.39.1) (2025-11-12)
|
|
95
|
+
|
|
96
|
+
**Note:** Version bump only for package @wearejh/m2-pwa-adyen
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
|
|
6
102
|
# [0.39.0](https://github.com/WeareJH/mage-mono/compare/v0.38.0...v0.39.0) (2025-11-07)
|
|
7
103
|
|
|
8
104
|
**Note:** Version bump only for package @wearejh/m2-pwa-adyen
|
package/lib/AdyenProvider.tsx
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import React, { createContext, useCallback, useContext, useEffect, useMemo, useState } from 'react';
|
|
2
2
|
import { shallowEqual, useDispatch, useSelector } from 'react-redux';
|
|
3
3
|
import { AppendState as CheckoutState } from '@wearejh/m2-pwa-checkout/lib/checkout.actions';
|
|
4
|
+
import { Core, CoreConfiguration } from '@adyen/adyen-web';
|
|
4
5
|
|
|
5
6
|
import { ActionTypes, AdyenMessage } from './adyen.actions';
|
|
6
7
|
import { initialState as initialStoreState } from './adyen.reducer';
|
|
@@ -134,7 +135,7 @@ export function AdyenProvider(props: AdyenProviderProps) {
|
|
|
134
135
|
const currency = checkoutTotalsState?.base_currency_code ?? 'GBP';
|
|
135
136
|
const price = checkoutTotalsState?.grand_total ?? 0;
|
|
136
137
|
|
|
137
|
-
const adyenCheckoutConfig = useMemo(
|
|
138
|
+
const adyenCheckoutConfig = useMemo<CoreConfiguration>(
|
|
138
139
|
() => ({
|
|
139
140
|
...checkoutConfig,
|
|
140
141
|
amount: {
|
|
@@ -174,39 +175,38 @@ export function AdyenProvider(props: AdyenProviderProps) {
|
|
|
174
175
|
[checkoutConfig, currency, price],
|
|
175
176
|
);
|
|
176
177
|
|
|
177
|
-
/**
|
|
178
|
-
* The Adyen NPM package needs to fetched
|
|
179
|
-
* client-side only, as it doesn't work
|
|
180
|
-
* with server-side rendering.
|
|
181
|
-
*
|
|
182
|
-
* @link https://github.com/Adyen/adyen-web/issues/902
|
|
183
|
-
*/
|
|
184
|
-
// const AdyenCheckout = useMemo(() => {
|
|
185
|
-
// const AdyenCheckout = new (window as any).AdyenCheckout;
|
|
186
|
-
// return AdyenCheckout;
|
|
187
|
-
// }, []);
|
|
188
|
-
|
|
189
178
|
/**
|
|
190
179
|
* `AdyenCheckout` singleton instance.
|
|
180
|
+
* In v6, AdyenCheckout() is async and accessed via window.AdyenWeb
|
|
191
181
|
*
|
|
192
|
-
* @link https://docs.adyen.com/online-payments/
|
|
182
|
+
* @link https://docs.adyen.com/online-payments/upgrade-your-integration/upgrade-to-web-v6/from-v4?tab=component-step1_2
|
|
193
183
|
*/
|
|
194
|
-
const adyenCheckout
|
|
195
|
-
// const hasSettings = Object.keys(checkoutConfig).length > 0;
|
|
184
|
+
const [adyenCheckout, setAdyenCheckout] = useState<AdyenCheckout | undefined>(undefined);
|
|
196
185
|
|
|
197
|
-
|
|
186
|
+
useEffect(() => {
|
|
187
|
+
const initAdyenCheckout = async () => {
|
|
188
|
+
const AdyenCheckout = (window as any).AdyenWeb?.AdyenCheckout as
|
|
189
|
+
| ((props: CoreConfiguration) => Promise<Core>)
|
|
190
|
+
| undefined;
|
|
198
191
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
192
|
+
if (!AdyenCheckout) {
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
dispatch(AdyenMessage(ActionTypes.SetStep, AdyenSteps.CreatingAdyenCheckoutInstance));
|
|
202
197
|
|
|
203
|
-
|
|
198
|
+
try {
|
|
199
|
+
const checkout = await AdyenCheckout(adyenCheckoutConfig);
|
|
204
200
|
|
|
205
|
-
|
|
201
|
+
dispatch(AdyenMessage(ActionTypes.SetStep, AdyenSteps.Ready));
|
|
206
202
|
|
|
207
|
-
|
|
203
|
+
setAdyenCheckout(checkout);
|
|
204
|
+
} catch (error) {
|
|
205
|
+
console.error('Failed to initialize Adyen Checkout:', error);
|
|
206
|
+
}
|
|
207
|
+
};
|
|
208
208
|
|
|
209
|
-
|
|
209
|
+
initAdyenCheckout();
|
|
210
210
|
}, [adyenCheckoutConfig, dispatch]);
|
|
211
211
|
|
|
212
212
|
const paymentFormSubmit = useCallback(() => {
|
|
@@ -233,36 +233,42 @@ export function AdyenProvider(props: AdyenProviderProps) {
|
|
|
233
233
|
|
|
234
234
|
const [availiablePaymentMethods, setAvailiablePaymentMethods] = useState<any[]>([]);
|
|
235
235
|
|
|
236
|
-
const getAvailiablePaymentMethods = useCallback(
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
switch (paymentMethod.type) {
|
|
241
|
-
case PaymentMethodTypes.ApplePay:
|
|
242
|
-
try {
|
|
243
|
-
await adyenCheckout?.create('applepay').isAvailable();
|
|
244
|
-
|
|
245
|
-
return paymentMethod;
|
|
246
|
-
} catch {}
|
|
247
|
-
break;
|
|
236
|
+
const getAvailiablePaymentMethods = useCallback(async () => {
|
|
237
|
+
if (!adyenCheckout) {
|
|
238
|
+
return [];
|
|
239
|
+
}
|
|
248
240
|
|
|
249
|
-
|
|
250
|
-
try {
|
|
251
|
-
await adyenCheckout?.create('paywithgoogle').isAvailable();
|
|
241
|
+
const { ApplePay, GooglePay } = (window as any).AdyenWeb;
|
|
252
242
|
|
|
243
|
+
return Promise.all(
|
|
244
|
+
supportedPaymentMethods.map(async (paymentMethod) => {
|
|
245
|
+
switch (paymentMethod.type) {
|
|
246
|
+
case PaymentMethodTypes.ApplePay:
|
|
247
|
+
try {
|
|
248
|
+
if (ApplePay) {
|
|
249
|
+
await new ApplePay(adyenCheckout).isAvailable();
|
|
250
|
+
return paymentMethod;
|
|
251
|
+
}
|
|
252
|
+
} catch {}
|
|
253
|
+
break;
|
|
254
|
+
|
|
255
|
+
case PaymentMethodTypes.GooglePay:
|
|
256
|
+
try {
|
|
257
|
+
if (GooglePay) {
|
|
258
|
+
await new GooglePay(adyenCheckout).isAvailable();
|
|
253
259
|
return paymentMethod;
|
|
254
|
-
}
|
|
255
|
-
|
|
260
|
+
}
|
|
261
|
+
} catch {}
|
|
262
|
+
break;
|
|
256
263
|
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
264
|
+
default:
|
|
265
|
+
return paymentMethod;
|
|
266
|
+
}
|
|
260
267
|
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
);
|
|
268
|
+
return undefined;
|
|
269
|
+
}),
|
|
270
|
+
);
|
|
271
|
+
}, [adyenCheckout, supportedPaymentMethods]);
|
|
266
272
|
|
|
267
273
|
useEffect(() => {
|
|
268
274
|
getAvailiablePaymentMethods()
|
|
@@ -355,11 +361,3 @@ export function useAdyen() {
|
|
|
355
361
|
// ======
|
|
356
362
|
// Hook End
|
|
357
363
|
// ======
|
|
358
|
-
|
|
359
|
-
// ======
|
|
360
|
-
// Utils Start
|
|
361
|
-
// ======
|
|
362
|
-
|
|
363
|
-
// ======
|
|
364
|
-
// Utils End
|
|
365
|
-
// ======
|
|
@@ -3,7 +3,7 @@ import React, { useMemo } from 'react';
|
|
|
3
3
|
import { GiftCardTypes, PaymentMethodTypes } from './adyen.types';
|
|
4
4
|
import { ApplePay } from './paymentMethods/ApplePay/ApplePay';
|
|
5
5
|
import { Card } from './paymentMethods/Card/Card';
|
|
6
|
-
import {
|
|
6
|
+
import { GooglePay } from './paymentMethods/GooglePay/GooglePay';
|
|
7
7
|
import { Klarna } from './paymentMethods/Klarna/Klarna';
|
|
8
8
|
import { KlarnaOverTime } from './paymentMethods/Klarna/KlarnaOverTime';
|
|
9
9
|
import { KlarnaPayNow } from './paymentMethods/Klarna/KlarnaPayNow';
|
|
@@ -38,7 +38,7 @@ export function PaymentMethodHandler(props: PaymentMethodHandlerProps) {
|
|
|
38
38
|
return <Card />;
|
|
39
39
|
|
|
40
40
|
case PaymentMethodTypes.GooglePay:
|
|
41
|
-
return <
|
|
41
|
+
return <GooglePay />;
|
|
42
42
|
|
|
43
43
|
case PaymentMethodTypes.Klarna:
|
|
44
44
|
return <Klarna />;
|
package/lib/adyen.types.ts
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
import Core from '@adyen/adyen-web
|
|
2
|
-
import type { PaymentMethodsResponse } from '@adyen/adyen-web
|
|
3
|
-
import type { CoreOptions } from '@adyen/adyen-web/dist/types/core/types';
|
|
4
|
-
import type { PaymentAction, PaymentMethod } from '@adyen/adyen-web/dist/types/types';
|
|
1
|
+
import { Core, CoreConfiguration } from '@adyen/adyen-web';
|
|
2
|
+
import type { PaymentAction, PaymentMethodsResponse, RawPaymentMethod } from '@adyen/adyen-web';
|
|
5
3
|
import { DataStatus, Message } from '@wearejh/m2-pwa-engine/lib/types';
|
|
6
4
|
|
|
7
5
|
/**
|
|
@@ -30,7 +28,7 @@ export type AdyenCheckout = Core;
|
|
|
30
28
|
/**
|
|
31
29
|
* Options used to configure the `AdyenCheckout`
|
|
32
30
|
*/
|
|
33
|
-
export type AdyenCheckoutConfig =
|
|
31
|
+
export type AdyenCheckoutConfig = CoreConfiguration;
|
|
34
32
|
|
|
35
33
|
/**
|
|
36
34
|
* The internal Adyen error action.
|
|
@@ -327,7 +325,7 @@ export interface Store {
|
|
|
327
325
|
*/
|
|
328
326
|
selectedPaymentMethod: PaymentMethodTypes;
|
|
329
327
|
|
|
330
|
-
supportedPaymentMethods:
|
|
328
|
+
supportedPaymentMethods: RawPaymentMethod[];
|
|
331
329
|
|
|
332
330
|
status: DataStatus;
|
|
333
331
|
|
|
@@ -353,6 +351,6 @@ export interface MagentoAdyenPaymentMethodsQueryResponse {
|
|
|
353
351
|
paymentMethodsResponse: MagentoAdyenPaymentMethodsResponseObject;
|
|
354
352
|
}
|
|
355
353
|
|
|
356
|
-
export type AdyenPaymentMethod =
|
|
354
|
+
export type AdyenPaymentMethod = RawPaymentMethod & {
|
|
357
355
|
brand?: GiftCardTypes | string;
|
|
358
356
|
};
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# Adyen Docs
|
|
2
|
+
|
|
3
|
+
## AdyenProvider
|
|
4
|
+
|
|
5
|
+
A React context provider that initializes and manages the Adyen checkout instance, payment methods, and payment flow state.
|
|
6
|
+
|
|
7
|
+
### Key Features
|
|
8
|
+
* Adyen Checkout Initialization: Creates singleton AdyenCheckout instance with configuration from Redux store
|
|
9
|
+
* Dynamic Pricing: Automatically converts checkout totals to minor units (e.g., £42.99 → 4299)
|
|
10
|
+
* Payment Method Availability: Filters supported payment methods based on browser/device compatibility (Apple Pay, Google Pay)
|
|
11
|
+
* Auto-reset on Error: Resets form submission state when payment is cancelled or encounters an error
|
|
12
|
+
* Client-side Only: Adyen Web SDK loaded client-side to avoid SSR issues
|
|
13
|
+
|
|
14
|
+
### Context Values
|
|
15
|
+
Provides access to:
|
|
16
|
+
|
|
17
|
+
* adyenCheckout - Adyen checkout instance
|
|
18
|
+
* attemptPayment() - Submit payment with method-specific data
|
|
19
|
+
* checkoutConfig - Adyen configuration with currency and amount
|
|
20
|
+
* orderId - Current order ID
|
|
21
|
+
* step - Current payment flow step (Ready, Error, Cancelled, etc.)
|
|
22
|
+
* supportedPaymentMethods - Filtered list of available payment methods
|
|
23
|
+
* paymentFormSubmit() / paymentFormSubmitted - Form submission state
|
|
24
|
+
* waitForPaymentFormSubmit() - Async form submission handler
|
|
25
|
+
|
|
26
|
+
### State Management
|
|
27
|
+
* Connects to Redux for Adyen state (action, checkoutConfig, orderId, etc.)
|
|
28
|
+
* Connects to Redux for checkout totals (base_currency_code, grand_total)
|
|
29
|
+
* Dispatches step changes during initialization
|
|
30
|
+
|
|
31
|
+
### useAdyen
|
|
32
|
+
Custom hook to access the Adyen context.
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## PaymentMethodHandler
|
|
37
|
+
|
|
38
|
+
A wrapper component that determines which Adyen payment method component should be rendered.
|
|
39
|
+
|
|
40
|
+
### Behavior
|
|
41
|
+
* Uses a switch statement to map payment method types to their corresponding components:
|
|
42
|
+
* ApplePay → <ApplePay />
|
|
43
|
+
* Card → <Card />
|
|
44
|
+
* GooglePay → <GooglePay />
|
|
45
|
+
* Klarna variants → <Klarna />, <KlarnaOverTime />, <KlarnaPayNow />
|
|
46
|
+
* PayPal → <PayPal />
|
|
47
|
+
* Giftcard → <Giftcard brand={brand} /> (requires brand prop)
|
|
48
|
+
|
|
49
|
+
Returns null for unsupported or missing payment methods.
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## Reducer, Actions, and Register
|
|
54
|
+
These three files form the Redux architecture for managing Adyen payment state in the application.
|
|
55
|
+
|
|
56
|
+
### adyen.reducer.ts
|
|
57
|
+
Defines how the Adyen Redux store state changes in response to actions.
|
|
58
|
+
|
|
59
|
+
### adyen.actions.ts
|
|
60
|
+
Defines all possible actions that can be dispatched to modify Adyen state.
|
|
61
|
+
|
|
62
|
+
### adyen.register.ts
|
|
63
|
+
Registers the Adyen module with the Redux store.
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
## Epics
|
|
68
|
+
|
|
69
|
+
The `epics` directory contains Redux-Observable middleware that handles asynchronous side effects for the Adyen payment flow.
|
|
70
|
+
|
|
71
|
+
### Purpose
|
|
72
|
+
Epics listen for specific Redux actions and perform async operations (API calls, redirects, etc.) before dispatching new actions to update the state.
|
|
73
|
+
|
|
74
|
+
### Key Responsibilities
|
|
75
|
+
- **API Communication**: Handles all interactions with Magento and Adyen APIs
|
|
76
|
+
- **Payment Processing**: Manages the complete payment lifecycle from initialization to completion
|
|
77
|
+
- **Error Handling**: Catches and dispatches errors during async operations
|
|
78
|
+
- **State Transitions**: Orchestrates step changes during payment flows (3DS2, redirects, etc.)
|
|
79
|
+
|
|
80
|
+
### Registered Epics
|
|
81
|
+
- `adyenPayment` - Processes final payment results
|
|
82
|
+
- `attemptPayment` - Initiates payment attempts with Magento
|
|
83
|
+
- `getAdyenConfig` - Fetches Adyen configuration and supported methods
|
|
84
|
+
- `getRedirectData` - Handles redirect return flows
|
|
85
|
+
- `paymentDetails` - Submits additional payment details (3DS2, redirect results)
|
|
86
|
+
- `onCancel` / `onError` - Manages payment cancellation and error states
|
|
87
|
+
|
|
88
|
+
These epics work together to handle the complex async flows required for different Adyen payment methods while keeping components focused on rendering UI.
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
## AdyenRedirect
|
|
93
|
+
A React component that handles the redirect flow when users return to the application after completing payment with redirect-based methods (e.g., iDEAL, Klarna, PayPal).
|
|
94
|
+
|
|
95
|
+
### Payment Flow
|
|
96
|
+
* Initialize (AdyenSteps.Init): Component mounts and dispatches GetRedirectData action with the redirect result
|
|
97
|
+
* Process (AdyenSteps.ProcessRedirect): Once order ID is restored from session, dispatches ProcessPaymentDetails action with redirect parameters
|
|
98
|
+
* The getRedirectData and paymentDetails epics handle the actual API communication with Adyen
|
|
99
|
+
|
|
100
|
+
### Key Features
|
|
101
|
+
* Two-stage processing: Waits for order restoration before processing payment details
|
|
102
|
+
* State-driven: Uses step from useAdyen to control flow progression
|
|
103
|
+
* Automatic: Executes on mount without user interaction
|
|
104
|
+
* Empty render: Displays nothing (parent handles loading states)
|
|
105
|
+
|
|
106
|
+
### Use Case
|
|
107
|
+
This component is rendered on the redirect return URL (e.g., /checkout/adyen/return) after users complete payment in a third-party interface and are redirected back to your application.
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
```mermaid
|
|
2
|
+
---
|
|
3
|
+
config:
|
|
4
|
+
theme: redux
|
|
5
|
+
---
|
|
6
|
+
sequenceDiagram
|
|
7
|
+
participant User
|
|
8
|
+
participant PaymentMethodHandler
|
|
9
|
+
participant PaymentComponent as Payment Component<br/>(e.g., ApplePay, Card, PayPal)
|
|
10
|
+
participant AdyenProvider
|
|
11
|
+
participant AdyenCheckout as Adyen Web SDK
|
|
12
|
+
participant Redux
|
|
13
|
+
participant Epic as Redux Epic
|
|
14
|
+
participant MagentoAPI as Magento API
|
|
15
|
+
participant AdyenAPI as Adyen API
|
|
16
|
+
|
|
17
|
+
Note over User,AdyenAPI: 1. INITIALIZATION PHASE
|
|
18
|
+
|
|
19
|
+
User->>PaymentMethodHandler: Navigate to checkout
|
|
20
|
+
PaymentMethodHandler->>Redux: Dispatch GetAdyenConfig
|
|
21
|
+
Redux->>Epic: getAdyenConfig epic triggered
|
|
22
|
+
Epic->>MagentoAPI: Fetch Adyen configuration
|
|
23
|
+
MagentoAPI-->>Epic: Return config + supported methods
|
|
24
|
+
Epic->>Redux: Store config & methods
|
|
25
|
+
|
|
26
|
+
Redux->>AdyenProvider: Subscribe to state changes
|
|
27
|
+
AdyenProvider->>AdyenProvider: Create AdyenCheckout instance
|
|
28
|
+
AdyenProvider->>Redux: Dispatch SetStep(CreatingAdyenCheckoutInstance)
|
|
29
|
+
AdyenProvider->>AdyenCheckout: new AdyenCheckout(config)
|
|
30
|
+
AdyenCheckout-->>AdyenProvider: Return checkout instance
|
|
31
|
+
AdyenProvider->>Redux: Dispatch SetStep(Ready)
|
|
32
|
+
|
|
33
|
+
AdyenProvider->>AdyenProvider: Filter payment methods<br/>(check Apple Pay/Google Pay availability)
|
|
34
|
+
AdyenProvider->>PaymentMethodHandler: Provide supportedPaymentMethods
|
|
35
|
+
|
|
36
|
+
PaymentMethodHandler->>PaymentComponent: Render available methods
|
|
37
|
+
PaymentComponent->>AdyenCheckout: create('applepay'|'card'|etc.)
|
|
38
|
+
AdyenCheckout-->>PaymentComponent: Return component instance
|
|
39
|
+
PaymentComponent->>PaymentComponent: Mount payment UI
|
|
40
|
+
PaymentComponent-->>User: Display payment button/form
|
|
41
|
+
|
|
42
|
+
Note over User,AdyenAPI: 2. PAYMENT ATTEMPT PHASE
|
|
43
|
+
|
|
44
|
+
User->>PaymentComponent: Click Pay button
|
|
45
|
+
PaymentComponent->>PaymentComponent: Validate input
|
|
46
|
+
|
|
47
|
+
alt Apple Pay / Google Pay (Redirect Flow)
|
|
48
|
+
PaymentComponent->>AdyenCheckout: Show Apple Pay sheet
|
|
49
|
+
User->>AdyenCheckout: Authorize payment
|
|
50
|
+
AdyenCheckout-->>PaymentComponent: onAuthorized(data)
|
|
51
|
+
PaymentComponent->>AdyenProvider: paymentFormSubmit()
|
|
52
|
+
AdyenProvider->>Redux: Trigger parent form submit
|
|
53
|
+
PaymentComponent->>AdyenProvider: waitForPaymentFormSubmit()
|
|
54
|
+
AdyenProvider-->>PaymentComponent: Promise resolves
|
|
55
|
+
PaymentComponent->>AdyenProvider: attemptPayment({state, magentoPaymentType})
|
|
56
|
+
else Card / Standard Flow
|
|
57
|
+
PaymentComponent->>PaymentComponent: onSubmit handler
|
|
58
|
+
PaymentComponent->>AdyenProvider: attemptPayment({state, magentoPaymentType})
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
Note over User,AdyenAPI: 3. ORDER CREATION PHASE
|
|
62
|
+
|
|
63
|
+
AdyenProvider->>Redux: Dispatch AttemptPayment action
|
|
64
|
+
Redux->>Epic: attemptPayment epic triggered
|
|
65
|
+
Epic->>MagentoAPI: POST /checkout/payment<br/>(create order with payment data)
|
|
66
|
+
MagentoAPI->>MagentoAPI: Create order
|
|
67
|
+
MagentoAPI->>AdyenAPI: Submit payment to Adyen
|
|
68
|
+
AdyenAPI-->>MagentoAPI: Return payment response
|
|
69
|
+
MagentoAPI-->>Epic: Return { action, orderId, resultCode }
|
|
70
|
+
Epic->>Redux: Store orderId & action
|
|
71
|
+
|
|
72
|
+
Note over User,AdyenAPI: 4. PAYMENT PROCESSING PHASE
|
|
73
|
+
|
|
74
|
+
alt 3DS2 Authentication Required
|
|
75
|
+
Epic->>Redux: Dispatch SetStep(ThreeDS2)
|
|
76
|
+
Redux->>AdyenProvider: step = ThreeDS2
|
|
77
|
+
AdyenProvider->>PaymentComponent: Re-render with action
|
|
78
|
+
PaymentComponent->>AdyenCheckout: createFromAction(action)
|
|
79
|
+
AdyenCheckout-->>User: Display 3DS2 challenge
|
|
80
|
+
User->>AdyenCheckout: Complete authentication
|
|
81
|
+
AdyenCheckout->>PaymentComponent: onAdditionalDetails(data)
|
|
82
|
+
PaymentComponent->>Redux: Dispatch ProcessPaymentDetails
|
|
83
|
+
Redux->>Epic: paymentDetails epic triggered
|
|
84
|
+
Epic->>MagentoAPI: POST /payment-details<br/>(submit 3DS2 result)
|
|
85
|
+
MagentoAPI->>AdyenAPI: Submit details to Adyen
|
|
86
|
+
AdyenAPI-->>MagentoAPI: Return final result
|
|
87
|
+
MagentoAPI-->>Epic: Return resultCode
|
|
88
|
+
Epic->>Redux: Dispatch AdyenPayment(response)
|
|
89
|
+
|
|
90
|
+
else Redirect Payment (Klarna, iDEAL, PayPal)
|
|
91
|
+
Epic->>Redux: Dispatch SetStep(Redirect)
|
|
92
|
+
Redux->>User: Redirect to Adyen/Partner URL
|
|
93
|
+
User->>AdyenAPI: Complete payment externally
|
|
94
|
+
AdyenAPI-->>User: Redirect back with redirectResult
|
|
95
|
+
User->>PaymentMethodHandler: Return to /checkout/adyen/return
|
|
96
|
+
PaymentMethodHandler->>PaymentComponent: Render AdyenRedirect
|
|
97
|
+
PaymentComponent->>Redux: Dispatch GetRedirectData(redirectResult)
|
|
98
|
+
Redux->>Epic: getRedirectData epic triggered
|
|
99
|
+
Epic->>MagentoAPI: Restore order session
|
|
100
|
+
MagentoAPI-->>Epic: Return orderId
|
|
101
|
+
Epic->>Redux: Store orderId
|
|
102
|
+
Redux->>AdyenProvider: step = ProcessRedirect
|
|
103
|
+
AdyenProvider->>PaymentComponent: Re-render
|
|
104
|
+
PaymentComponent->>Redux: Dispatch ProcessPaymentDetails
|
|
105
|
+
Epic->>MagentoAPI: POST /payment-details<br/>(submit redirect result)
|
|
106
|
+
MagentoAPI->>AdyenAPI: Verify payment
|
|
107
|
+
AdyenAPI-->>MagentoAPI: Return final result
|
|
108
|
+
MagentoAPI-->>Epic: Return resultCode
|
|
109
|
+
Epic->>Redux: Dispatch AdyenPayment(response)
|
|
110
|
+
|
|
111
|
+
else Instant Payment (No additional steps)
|
|
112
|
+
Epic->>Redux: Dispatch AdyenPayment(response)
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
Note over User,AdyenAPI: 5. FINALIZATION PHASE
|
|
116
|
+
|
|
117
|
+
Redux->>Epic: adyenPayment epic triggered
|
|
118
|
+
Epic->>Epic: Process resultCode
|
|
119
|
+
|
|
120
|
+
alt Payment Authorized
|
|
121
|
+
Epic->>Redux: Dispatch SetStep(Success)
|
|
122
|
+
Redux->>User: Redirect to success page
|
|
123
|
+
else Payment Refused/Error
|
|
124
|
+
Epic->>Redux: Dispatch SetStep(Error)
|
|
125
|
+
Epic->>Redux: Store error message
|
|
126
|
+
Redux->>AdyenProvider: step = Error
|
|
127
|
+
AdyenProvider->>AdyenProvider: setHasFormSubmitted(false)
|
|
128
|
+
AdyenProvider->>PaymentComponent: Re-render
|
|
129
|
+
PaymentComponent-->>User: Display error message
|
|
130
|
+
PaymentComponent-->>User: Allow retry
|
|
131
|
+
else Payment Cancelled
|
|
132
|
+
Epic->>Redux: Dispatch SetStep(Cancelled)
|
|
133
|
+
Redux->>AdyenProvider: step = Cancelled
|
|
134
|
+
AdyenProvider->>AdyenProvider: setHasFormSubmitted(false)
|
|
135
|
+
AdyenProvider->>PaymentComponent: Re-render
|
|
136
|
+
PaymentComponent-->>User: Allow retry
|
|
137
|
+
end
|
|
138
|
+
```
|
|
@@ -32,7 +32,7 @@ const adyenWebComponentsApiUrl = 'https://checkoutshopper-live.adyen.com/checkou
|
|
|
32
32
|
*
|
|
33
33
|
* @url https://github.com/Adyen/adyen-web
|
|
34
34
|
*/
|
|
35
|
-
const adyenWebComponentsVersion = '
|
|
35
|
+
const adyenWebComponentsVersion = '6.27.1';
|
|
36
36
|
|
|
37
37
|
const CSS_FILE = `${adyenWebComponentsApiUrl}/${adyenWebComponentsVersion}/adyen.css`;
|
|
38
38
|
const JS_FILE = `${adyenWebComponentsApiUrl}/${adyenWebComponentsVersion}/adyen.js`;
|
|
@@ -199,6 +199,7 @@ export function getAdyenConfig(action$: Observable<any>, state$: Observable<any>
|
|
|
199
199
|
}
|
|
200
200
|
|
|
201
201
|
const configuration: AdyenCheckoutConfig = {
|
|
202
|
+
countryCode: shippingAddress?.country_code || 'IE',
|
|
202
203
|
clientKey,
|
|
203
204
|
environment,
|
|
204
205
|
paymentMethodsResponse,
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { SimpleModal } from '@wearejh/m2-pwa-checkout/lib/components/Modal/SimpleModal';
|
|
2
2
|
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
3
3
|
import { useDispatch } from 'react-redux';
|
|
4
|
+
import type { ThreeDS2Challenge as ThreeDS2ChallengeElement, ThreeDS2ChallengeConfiguration } from '@adyen/adyen-web';
|
|
4
5
|
|
|
5
6
|
import { useAdyen } from '../../AdyenProvider';
|
|
6
7
|
import { ActionTypes, AdyenMessage } from '../../adyen.actions';
|
|
@@ -63,7 +64,7 @@ export function ThreeDS2Challenge() {
|
|
|
63
64
|
* from the `adyenCheckout` instance, so are
|
|
64
65
|
* not necessary to redefine here.
|
|
65
66
|
*/
|
|
66
|
-
const adyenChallengeConfig = useMemo(() => {
|
|
67
|
+
const adyenChallengeConfig = useMemo<ThreeDS2ChallengeConfiguration | undefined>(() => {
|
|
67
68
|
if (paymentData && token) {
|
|
68
69
|
return {
|
|
69
70
|
onComplete,
|
|
@@ -92,12 +93,10 @@ export function ThreeDS2Challenge() {
|
|
|
92
93
|
* The submit function which is called automatically
|
|
93
94
|
* when the user has completed the challenge.
|
|
94
95
|
*/
|
|
95
|
-
const adyenChallenge = useMemo(() => {
|
|
96
|
-
|
|
97
|
-
return adyenCheckout.create('threeDS2Challenge', adyenChallengeConfig);
|
|
98
|
-
}
|
|
96
|
+
const adyenChallenge = useMemo<ThreeDS2ChallengeElement>(() => {
|
|
97
|
+
const { ThreeDS2Challenge } = (window as any).AdyenWeb;
|
|
99
98
|
|
|
100
|
-
return
|
|
99
|
+
return new ThreeDS2Challenge(adyenCheckout, adyenChallengeConfig) as ThreeDS2ChallengeElement;
|
|
101
100
|
}, [adyenChallengeConfig, adyenCheckout]);
|
|
102
101
|
|
|
103
102
|
/**
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React, { useCallback, useEffect, useMemo, useRef } from 'react';
|
|
2
2
|
import { useDispatch } from 'react-redux';
|
|
3
|
-
import type ThreeDS2DeviceFingerprint from '@adyen/adyen-web
|
|
3
|
+
import type { ThreeDS2DeviceFingerprint, ThreeDS2DeviceFingerprintConfiguration } from '@adyen/adyen-web';
|
|
4
4
|
|
|
5
5
|
import { useAdyen } from '../../AdyenProvider';
|
|
6
6
|
import { AdyenSteps } from '../../adyen.types';
|
|
@@ -51,7 +51,7 @@ export function ThreeDS2Fingerprint() {
|
|
|
51
51
|
* from the `adyenCheckout` instance, so are
|
|
52
52
|
* not necessary to redefine here.
|
|
53
53
|
*/
|
|
54
|
-
const deviceFingerprintConfig = useMemo(() => {
|
|
54
|
+
const deviceFingerprintConfig = useMemo<ThreeDS2DeviceFingerprintConfiguration | undefined>(() => {
|
|
55
55
|
if (paymentData && token) {
|
|
56
56
|
return {
|
|
57
57
|
onComplete,
|
|
@@ -69,6 +69,7 @@ export function ThreeDS2Fingerprint() {
|
|
|
69
69
|
* newer flow.
|
|
70
70
|
*/
|
|
71
71
|
useOriginalFlow: true,
|
|
72
|
+
showSpinner: true,
|
|
72
73
|
};
|
|
73
74
|
}
|
|
74
75
|
}, [onError, onComplete, paymentData, token]);
|
|
@@ -76,28 +77,10 @@ export function ThreeDS2Fingerprint() {
|
|
|
76
77
|
/**
|
|
77
78
|
* Adyen device fingerprint component instance.
|
|
78
79
|
*/
|
|
79
|
-
const deviceFingerprint = useMemo(() => {
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* The `adyenCheckout` instance needs to be cast
|
|
83
|
-
* as `any`, because the Adyen NPM package types
|
|
84
|
-
* don't accept `onComplete` as a prop, which is
|
|
85
|
-
* in consistent with the API.
|
|
86
|
-
*/
|
|
87
|
-
const adyenCheckoutInstance = adyenCheckout as any;
|
|
80
|
+
const deviceFingerprint = useMemo<ThreeDS2DeviceFingerprint>(() => {
|
|
81
|
+
const { ThreeDS2DeviceFingerprint } = (window as any).AdyenWeb;
|
|
88
82
|
|
|
89
|
-
|
|
90
|
-
'threeDS2DeviceFingerprint',
|
|
91
|
-
deviceFingerprintConfig,
|
|
92
|
-
);
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* Recast the device fingerprint component as
|
|
96
|
-
* `ThreeDS2DeviceFingerprint`, so that
|
|
97
|
-
* its typed.
|
|
98
|
-
*/
|
|
99
|
-
return adyen3DSFingerprint as ThreeDS2DeviceFingerprint;
|
|
100
|
-
}
|
|
83
|
+
return new ThreeDS2DeviceFingerprint(adyenCheckout, deviceFingerprintConfig) as ThreeDS2DeviceFingerprint;
|
|
101
84
|
}, [adyenCheckout, deviceFingerprintConfig]);
|
|
102
85
|
|
|
103
86
|
/**
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import type ApplePayElement from '@adyen/adyen-web
|
|
2
|
-
import type { ApplePayElementProps } from '@adyen/adyen-web/dist/types/components/ApplePay/types';
|
|
1
|
+
import type { ApplePay as ApplePayElement, ApplePayConfiguration } from '@adyen/adyen-web';
|
|
3
2
|
import React, { useCallback, useEffect, useMemo, useRef } from 'react';
|
|
4
3
|
import { useDispatch } from 'react-redux';
|
|
5
4
|
|
|
@@ -90,7 +89,7 @@ export function ApplePay() {
|
|
|
90
89
|
*
|
|
91
90
|
* The Partial type sets all properties to optional.
|
|
92
91
|
*/
|
|
93
|
-
const
|
|
92
|
+
const adyenApplePayConfig = useMemo<ApplePayConfiguration>(
|
|
94
93
|
() => ({
|
|
95
94
|
buttonColor: 'black',
|
|
96
95
|
buttonType: 'buy',
|
|
@@ -105,22 +104,11 @@ export function ApplePay() {
|
|
|
105
104
|
*
|
|
106
105
|
* @link Adyen ApplePay Component Documentation: https://docs.adyen.com/payment-methods/apple-pay/web-component
|
|
107
106
|
*/
|
|
108
|
-
const adyenApplePay = useMemo(() => {
|
|
109
|
-
|
|
110
|
-
* The `adyenCheckout` instance needs to be cast
|
|
111
|
-
* as `any`, because the Apple Pay props require
|
|
112
|
-
* properties which will be automatically inherited
|
|
113
|
-
* from the Adyen checkout instance.
|
|
114
|
-
*/
|
|
115
|
-
const adyenCheckoutInstance = adyenCheckout as any;
|
|
107
|
+
const adyenApplePay = useMemo<ApplePayElement>(() => {
|
|
108
|
+
const { ApplePay } = (window as any).AdyenWeb;
|
|
116
109
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
/**
|
|
120
|
-
* Recast the component so that it's typed.
|
|
121
|
-
*/
|
|
122
|
-
return adyenApplePay as ApplePayElement;
|
|
123
|
-
}, [adyenCheckout, config]);
|
|
110
|
+
return new ApplePay(adyenCheckout, adyenApplePayConfig) as ApplePayElement;
|
|
111
|
+
}, [adyenCheckout, adyenApplePayConfig]);
|
|
124
112
|
|
|
125
113
|
/**
|
|
126
114
|
* Mount the Adyen ApplePay instance, when ready and availiable.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { CardConfiguration, Card as CardElement } from '@adyen/adyen-web';
|
|
2
2
|
import React, { useCallback, useEffect, useMemo, useRef } from 'react';
|
|
3
3
|
import { useDispatch } from 'react-redux';
|
|
4
4
|
|
|
@@ -72,7 +72,7 @@ export function Card() {
|
|
|
72
72
|
*
|
|
73
73
|
* @link Adyen Card Component Documentation - https://docs.adyen.com/payment-methods/cards/web-component#page-introduction
|
|
74
74
|
*/
|
|
75
|
-
const adyenCardConfig:
|
|
75
|
+
const adyenCardConfig: CardConfiguration = useMemo(
|
|
76
76
|
() => ({
|
|
77
77
|
onError,
|
|
78
78
|
onSubmit,
|
|
@@ -85,7 +85,11 @@ export function Card() {
|
|
|
85
85
|
*
|
|
86
86
|
* @link Adyen Card Component Documentation - https://docs.adyen.com/payment-methods/cards/web-component#page-introduction
|
|
87
87
|
*/
|
|
88
|
-
const adyenCard = useMemo(() =>
|
|
88
|
+
const adyenCard = useMemo<CardElement>(() => {
|
|
89
|
+
const { Card } = (window as any).AdyenWeb;
|
|
90
|
+
|
|
91
|
+
return new Card(adyenCheckout, adyenCardConfig).mount('#card') as CardElement;
|
|
92
|
+
}, [adyenCheckout, adyenCardConfig]);
|
|
89
93
|
|
|
90
94
|
/**
|
|
91
95
|
* Mount the Adyen card instance, when ready.
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import React, { useEffect, useRef } from 'react';
|
|
1
|
+
import React, { useEffect, useMemo, useRef } from 'react';
|
|
2
|
+
import type { Redirect as RedirectElement, RedirectConfiguration } from '@adyen/adyen-web';
|
|
2
3
|
|
|
3
4
|
import { useAdyen } from '../../AdyenProvider';
|
|
4
5
|
import { AdyenBrandCodes, AdyenSteps, GiftCardTypes, MagentoPaymentTypes } from '../../adyen.types';
|
|
@@ -71,6 +72,15 @@ export function Giftcard(props: GiftCardProps) {
|
|
|
71
72
|
}
|
|
72
73
|
}, [attemptPayment, paymentFormSubmitted, props.brand]);
|
|
73
74
|
|
|
75
|
+
const redirectConfig = useMemo<RedirectConfiguration | undefined>(() => {
|
|
76
|
+
if (action?.url) {
|
|
77
|
+
return {
|
|
78
|
+
type: 'redirect',
|
|
79
|
+
url: action.url,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
}, [action?.url]);
|
|
83
|
+
|
|
74
84
|
/**
|
|
75
85
|
* Pass Magento's submit reponse to an Adyen Redirect component.
|
|
76
86
|
*
|
|
@@ -80,14 +90,16 @@ export function Giftcard(props: GiftCardProps) {
|
|
|
80
90
|
*/
|
|
81
91
|
useEffect(() => {
|
|
82
92
|
if (action?.url && adyenCheckout && step === AdyenSteps.GiftCardRedirect && redirectContainer.current) {
|
|
83
|
-
const
|
|
93
|
+
const { Redirect } = (window as any).AdyenWeb;
|
|
94
|
+
|
|
95
|
+
const redirect: RedirectElement = new Redirect(adyenCheckout, redirectConfig);
|
|
84
96
|
|
|
85
97
|
if (redirect) {
|
|
86
98
|
redirect.mount(redirectContainer.current);
|
|
87
99
|
redirect?.handleAction(action);
|
|
88
100
|
}
|
|
89
101
|
}
|
|
90
|
-
}, [action, adyenCheckout, step]);
|
|
102
|
+
}, [action, adyenCheckout, redirectConfig, step]);
|
|
91
103
|
|
|
92
104
|
/**
|
|
93
105
|
* Return our component
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import type GooglePay from '@adyen/adyen-web
|
|
2
|
-
import type { GooglePayProps } from '@adyen/adyen-web/dist/types/components/GooglePay/types';
|
|
1
|
+
import type { GooglePay as GooglePayElement, GooglePayConfiguration } from '@adyen/adyen-web';
|
|
3
2
|
import React, { useCallback, useEffect, useMemo, useRef } from 'react';
|
|
4
3
|
import { useDispatch } from 'react-redux';
|
|
5
4
|
|
|
@@ -28,7 +27,7 @@ import { ThreeDS2Fingerprint } from '../3DS/ThreeDS2Fingerprint';
|
|
|
28
27
|
* @link https://docs.adyen.com/payment-methods/google-pay/web-component
|
|
29
28
|
*/
|
|
30
29
|
|
|
31
|
-
export function
|
|
30
|
+
export function GooglePay() {
|
|
32
31
|
const { adyenCheckout, attemptPayment, waitForPaymentFormSubmit, step } = useAdyen();
|
|
33
32
|
|
|
34
33
|
/**
|
|
@@ -93,7 +92,7 @@ export function GooglePayMethod() {
|
|
|
93
92
|
*
|
|
94
93
|
* The Partial type sets all properties to optional.
|
|
95
94
|
*/
|
|
96
|
-
const
|
|
95
|
+
const adyenGooglePayConfig: Partial<GooglePayConfiguration> = useMemo(
|
|
97
96
|
() => ({
|
|
98
97
|
onSubmit,
|
|
99
98
|
buttonSizeMode: 'fill',
|
|
@@ -106,22 +105,11 @@ export function GooglePayMethod() {
|
|
|
106
105
|
*
|
|
107
106
|
* @link Adyen GooglePay Component Documentation: https://docs.adyen.com/payment-methods/google-pay/web-component
|
|
108
107
|
*/
|
|
109
|
-
const adyenGooglePay = useMemo(() => {
|
|
110
|
-
|
|
111
|
-
* The `adyenCheckout` instance needs to be cast
|
|
112
|
-
* as `any`, because the Apple Pay props require
|
|
113
|
-
* properties which will be automatically inherited
|
|
114
|
-
* from the Adyen checkout instance.
|
|
115
|
-
*/
|
|
116
|
-
const adyenCheckoutInstance = adyenCheckout as any;
|
|
108
|
+
const adyenGooglePay = useMemo<GooglePayElement>(() => {
|
|
109
|
+
const { GooglePay } = (window as any).AdyenWeb;
|
|
117
110
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
/**
|
|
121
|
-
* Recast the component so that it's typed.
|
|
122
|
-
*/
|
|
123
|
-
return adyenGooglePay as GooglePay;
|
|
124
|
-
}, [adyenCheckout, config]);
|
|
111
|
+
return new GooglePay(adyenCheckout, adyenGooglePayConfig) as GooglePayElement;
|
|
112
|
+
}, [adyenCheckout, adyenGooglePayConfig]);
|
|
125
113
|
|
|
126
114
|
/**
|
|
127
115
|
* Mount the Adyen GooglePay instance, when ready and availiable.
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
2
2
|
import { useDispatch } from 'react-redux';
|
|
3
|
+
import type { Klarna as KlarnaElement, KlarnaConfiguration } from '@adyen/adyen-web';
|
|
3
4
|
|
|
4
5
|
import { useAdyen } from '../../AdyenProvider';
|
|
5
6
|
import { AdyenBrandCodes, AdyenSteps, MagentoPaymentTypes } from '../../adyen.types';
|
|
@@ -64,8 +65,9 @@ export function Klarna() {
|
|
|
64
65
|
* from the `adyenCheckout` instance, so are
|
|
65
66
|
* not necessary to redefine here.
|
|
66
67
|
*/
|
|
67
|
-
const adyenKlarnaConfig = useMemo(
|
|
68
|
+
const adyenKlarnaConfig = useMemo<KlarnaConfiguration>(
|
|
68
69
|
() => ({
|
|
70
|
+
type: 'klarna',
|
|
69
71
|
onError,
|
|
70
72
|
onSubmit,
|
|
71
73
|
}),
|
|
@@ -77,10 +79,11 @@ export function Klarna() {
|
|
|
77
79
|
*
|
|
78
80
|
* @link Adyen Klarna Component Documentation: https://docs.adyen.com/payment-methods/klarna/web-component
|
|
79
81
|
*/
|
|
80
|
-
const adyenKlarna = useMemo(() =>
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
82
|
+
const adyenKlarna = useMemo<KlarnaElement>(() => {
|
|
83
|
+
const { Klarna } = (window as any).AdyenWeb;
|
|
84
|
+
|
|
85
|
+
return new Klarna(adyenCheckout, adyenKlarnaConfig) as KlarnaElement;
|
|
86
|
+
}, [adyenCheckout, adyenKlarnaConfig]);
|
|
84
87
|
|
|
85
88
|
/**
|
|
86
89
|
* Mount the Adyen Klarna instance, when ready.
|
|
@@ -118,9 +121,20 @@ export function Klarna() {
|
|
|
118
121
|
*/
|
|
119
122
|
useEffect(() => {
|
|
120
123
|
if (action && adyenKlarna && step === AdyenSteps.KlarnaRedirect) {
|
|
121
|
-
|
|
124
|
+
// adyenKlarnaOverTime?.handleAction(action);
|
|
125
|
+
if (
|
|
126
|
+
action.sdkData &&
|
|
127
|
+
typeof action.sdkData === 'object' &&
|
|
128
|
+
'client_token' in action.sdkData &&
|
|
129
|
+
'payment_method_category' in action.sdkData
|
|
130
|
+
) {
|
|
131
|
+
adyenKlarna.handleAction(action as any);
|
|
132
|
+
} else {
|
|
133
|
+
console.error('Invalid Klarna action structure:', action);
|
|
134
|
+
onError({ message: 'Invalid Klarna payment action received' });
|
|
135
|
+
}
|
|
122
136
|
}
|
|
123
|
-
}, [action, adyenKlarna, step]);
|
|
137
|
+
}, [action, adyenKlarna, onError, step]);
|
|
124
138
|
|
|
125
139
|
return (
|
|
126
140
|
<div ref={klarnaContainer}>
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
2
2
|
import { useDispatch } from 'react-redux';
|
|
3
|
+
import type { Klarna as KlarnaElement, KlarnaConfiguration } from '@adyen/adyen-web';
|
|
3
4
|
|
|
4
5
|
import { useAdyen } from '../../AdyenProvider';
|
|
5
6
|
import { AdyenBrandCodes, AdyenSteps, MagentoPaymentTypes } from '../../adyen.types';
|
|
@@ -74,8 +75,9 @@ export function KlarnaOverTime() {
|
|
|
74
75
|
* from the `adyenCheckout` instance, so are
|
|
75
76
|
* not necessary to redefine here.
|
|
76
77
|
*/
|
|
77
|
-
const adyenKlarnaConfig = useMemo(
|
|
78
|
+
const adyenKlarnaConfig = useMemo<KlarnaConfiguration>(
|
|
78
79
|
() => ({
|
|
80
|
+
type: 'klarna_account',
|
|
79
81
|
onError,
|
|
80
82
|
onSubmit,
|
|
81
83
|
}),
|
|
@@ -87,19 +89,20 @@ export function KlarnaOverTime() {
|
|
|
87
89
|
*
|
|
88
90
|
* @link Adyen Klarna Component Documentation: https://docs.adyen.com/payment-methods/klarna/web-component
|
|
89
91
|
*/
|
|
90
|
-
const
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
92
|
+
const adyenKlarnaOverTime = useMemo<KlarnaElement>(() => {
|
|
93
|
+
const { Klarna } = (window as any).AdyenWeb;
|
|
94
|
+
|
|
95
|
+
return new Klarna(adyenCheckout, adyenKlarnaConfig) as KlarnaElement;
|
|
96
|
+
}, [adyenCheckout, adyenKlarnaConfig]);
|
|
94
97
|
|
|
95
98
|
/**
|
|
96
99
|
* Mount the Adyen Klarna instance, when ready.
|
|
97
100
|
*/
|
|
98
101
|
useEffect(() => {
|
|
99
|
-
if (adyenCheckout &&
|
|
100
|
-
|
|
102
|
+
if (adyenCheckout && adyenKlarnaOverTime && klarnaContainer.current) {
|
|
103
|
+
adyenKlarnaOverTime.mount(klarnaContainer.current);
|
|
101
104
|
}
|
|
102
|
-
}, [adyenCheckout,
|
|
105
|
+
}, [adyenCheckout, adyenKlarnaOverTime, klarnaContainer]);
|
|
103
106
|
|
|
104
107
|
/**
|
|
105
108
|
* When the payment form has been submitted,
|
|
@@ -127,10 +130,21 @@ export function KlarnaOverTime() {
|
|
|
127
130
|
* payment, before redirecting the user back to PWA.
|
|
128
131
|
*/
|
|
129
132
|
useEffect(() => {
|
|
130
|
-
if (action &&
|
|
131
|
-
|
|
133
|
+
if (action && adyenKlarnaOverTime && step === AdyenSteps.KlarnaRedirect) {
|
|
134
|
+
// adyenKlarnaOverTime?.handleAction(action);
|
|
135
|
+
if (
|
|
136
|
+
action.sdkData &&
|
|
137
|
+
typeof action.sdkData === 'object' &&
|
|
138
|
+
'client_token' in action.sdkData &&
|
|
139
|
+
'payment_method_category' in action.sdkData
|
|
140
|
+
) {
|
|
141
|
+
adyenKlarnaOverTime.handleAction(action as any);
|
|
142
|
+
} else {
|
|
143
|
+
console.error('Invalid Klarna action structure:', action);
|
|
144
|
+
onError({ message: 'Invalid Klarna payment action received' });
|
|
145
|
+
}
|
|
132
146
|
}
|
|
133
|
-
}, [action,
|
|
147
|
+
}, [action, adyenKlarnaOverTime, onError, step]);
|
|
134
148
|
|
|
135
149
|
return (
|
|
136
150
|
<div ref={klarnaContainer}>
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
2
2
|
import { useDispatch } from 'react-redux';
|
|
3
|
+
import type { Klarna as KlarnaElement, KlarnaConfiguration } from '@adyen/adyen-web';
|
|
3
4
|
|
|
4
5
|
import { useAdyen } from '../../AdyenProvider';
|
|
5
6
|
import { AdyenBrandCodes, AdyenSteps, MagentoPaymentTypes } from '../../adyen.types';
|
|
@@ -64,8 +65,9 @@ export function KlarnaPayNow() {
|
|
|
64
65
|
* from the `adyenCheckout` instance, so are
|
|
65
66
|
* not necessary to redefine here.
|
|
66
67
|
*/
|
|
67
|
-
const adyenKlarnaConfig = useMemo(
|
|
68
|
+
const adyenKlarnaConfig = useMemo<KlarnaConfiguration>(
|
|
68
69
|
() => ({
|
|
70
|
+
type: 'klarna_paynow',
|
|
69
71
|
onError,
|
|
70
72
|
onSubmit,
|
|
71
73
|
}),
|
|
@@ -77,19 +79,20 @@ export function KlarnaPayNow() {
|
|
|
77
79
|
*
|
|
78
80
|
* @link Adyen Klarna Component Documentation: https://docs.adyen.com/payment-methods/klarna/web-component
|
|
79
81
|
*/
|
|
80
|
-
const
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
82
|
+
const adyenKlarnaPayNow = useMemo<KlarnaElement>(() => {
|
|
83
|
+
const { Klarna } = (window as any).AdyenWeb;
|
|
84
|
+
|
|
85
|
+
return new Klarna(adyenCheckout, adyenKlarnaConfig) as KlarnaElement;
|
|
86
|
+
}, [adyenCheckout, adyenKlarnaConfig]);
|
|
84
87
|
|
|
85
88
|
/**
|
|
86
89
|
* Mount the Adyen Klarna instance, when ready.
|
|
87
90
|
*/
|
|
88
91
|
useEffect(() => {
|
|
89
|
-
if (adyenCheckout &&
|
|
90
|
-
|
|
92
|
+
if (adyenCheckout && adyenKlarnaPayNow && klarnaContainer.current) {
|
|
93
|
+
adyenKlarnaPayNow.mount(klarnaContainer.current);
|
|
91
94
|
}
|
|
92
|
-
}, [adyenCheckout,
|
|
95
|
+
}, [adyenCheckout, adyenKlarnaPayNow, klarnaContainer]);
|
|
93
96
|
|
|
94
97
|
/**
|
|
95
98
|
* When the payment form has been submitted,
|
|
@@ -117,10 +120,21 @@ export function KlarnaPayNow() {
|
|
|
117
120
|
* payment, before redirecting the user back to PWA.
|
|
118
121
|
*/
|
|
119
122
|
useEffect(() => {
|
|
120
|
-
if (action &&
|
|
121
|
-
|
|
123
|
+
if (action && adyenKlarnaPayNow && step === AdyenSteps.KlarnaRedirect) {
|
|
124
|
+
// adyenKlarnaOverTime?.handleAction(action);
|
|
125
|
+
if (
|
|
126
|
+
action.sdkData &&
|
|
127
|
+
typeof action.sdkData === 'object' &&
|
|
128
|
+
'client_token' in action.sdkData &&
|
|
129
|
+
'payment_method_category' in action.sdkData
|
|
130
|
+
) {
|
|
131
|
+
adyenKlarnaPayNow.handleAction(action as any);
|
|
132
|
+
} else {
|
|
133
|
+
console.error('Invalid Klarna action structure:', action);
|
|
134
|
+
onError({ message: 'Invalid Klarna payment action received' });
|
|
135
|
+
}
|
|
122
136
|
}
|
|
123
|
-
}, [action,
|
|
137
|
+
}, [action, adyenKlarnaPayNow, onError, step]);
|
|
124
138
|
|
|
125
139
|
return (
|
|
126
140
|
<div ref={klarnaContainer}>
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
2
2
|
import { useDispatch } from 'react-redux';
|
|
3
|
+
import type { PayPal as PayPalElement, PayPalConfiguration } from '@adyen/adyen-web';
|
|
3
4
|
|
|
4
5
|
import { useAdyen } from '../../AdyenProvider';
|
|
5
6
|
import { AdyenSteps, MagentoPaymentTypes } from '../../adyen.types';
|
|
@@ -98,7 +99,7 @@ export function PayPal() {
|
|
|
98
99
|
* from the `adyenCheckout` instance, so are
|
|
99
100
|
* not necessary to redefine here.
|
|
100
101
|
*/
|
|
101
|
-
const adyenPayPalConfig = useMemo(
|
|
102
|
+
const adyenPayPalConfig = useMemo<PayPalConfiguration>(
|
|
102
103
|
() => ({
|
|
103
104
|
onAdditionalDetails,
|
|
104
105
|
onCancel,
|
|
@@ -124,10 +125,11 @@ export function PayPal() {
|
|
|
124
125
|
*
|
|
125
126
|
* @link Adyen PayPal Component Documentation: https://docs.adyen.com/payment-methods/paypal/web-component
|
|
126
127
|
*/
|
|
127
|
-
const adyenPayPal = useMemo(() =>
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
128
|
+
const adyenPayPal = useMemo<PayPalElement>(() => {
|
|
129
|
+
const { PayPal } = (window as any).AdyenWeb;
|
|
130
|
+
|
|
131
|
+
return new PayPal(adyenCheckout, adyenPayPalConfig) as PayPalElement;
|
|
132
|
+
}, [adyenCheckout, adyenPayPalConfig]);
|
|
131
133
|
|
|
132
134
|
/**
|
|
133
135
|
* Mount the Adyen PayPal instance, when ready.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wearejh/m2-pwa-adyen",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.45.0",
|
|
4
4
|
"description": "> TODO: description",
|
|
5
5
|
"author": "Shane Osbourne <shane.osbourne8@gmail.com>",
|
|
6
6
|
"homepage": "",
|
|
@@ -21,14 +21,14 @@
|
|
|
21
21
|
"@reach/dialog": "0.8.2"
|
|
22
22
|
},
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@adyen/adyen-web": "
|
|
25
|
-
"@wearejh/m2-pwa-cart": "^0.
|
|
26
|
-
"@wearejh/m2-pwa-checkout": "^0.
|
|
27
|
-
"@wearejh/m2-pwa-engine": "^0.
|
|
28
|
-
"@wearejh/react-hooks": "^0.
|
|
29
|
-
"@wearejh/rx-form": "^0.
|
|
30
|
-
"@wearejh/swagger-rxjs": "^0.
|
|
24
|
+
"@adyen/adyen-web": "6.27.1",
|
|
25
|
+
"@wearejh/m2-pwa-cart": "^0.45.0",
|
|
26
|
+
"@wearejh/m2-pwa-checkout": "^0.45.0",
|
|
27
|
+
"@wearejh/m2-pwa-engine": "^0.45.0",
|
|
28
|
+
"@wearejh/react-hooks": "^0.45.0",
|
|
29
|
+
"@wearejh/rx-form": "^0.45.0",
|
|
30
|
+
"@wearejh/swagger-rxjs": "^0.45.0",
|
|
31
31
|
"load-js": "^3.0.3"
|
|
32
32
|
},
|
|
33
|
-
"gitHead": "
|
|
33
|
+
"gitHead": "f22c9f8583c85902860ec49590cae76752f8d227"
|
|
34
34
|
}
|