@akinon/pz-flow-payment 1.108.0-rc.87 → 1.108.0-rc.9
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 +40 -28
- package/package.json +1 -1
- package/src/views/index.tsx +140 -119
package/CHANGELOG.md
CHANGED
|
@@ -1,13 +1,48 @@
|
|
|
1
1
|
# @akinon/pz-flow-payment
|
|
2
2
|
|
|
3
|
-
## 1.108.0-rc.
|
|
3
|
+
## 1.108.0-rc.9
|
|
4
|
+
|
|
5
|
+
## 1.108.0-rc.8
|
|
6
|
+
|
|
7
|
+
### Minor Changes
|
|
8
|
+
|
|
9
|
+
- f85464e9: ZERO-3640: Fix API call to use hyphenated key for payment ID in FlowPayment component
|
|
10
|
+
|
|
11
|
+
## 1.108.0-rc.7
|
|
12
|
+
|
|
13
|
+
## 1.108.0-rc.6
|
|
14
|
+
|
|
15
|
+
## 1.108.0-rc.5
|
|
4
16
|
|
|
5
17
|
### Minor Changes
|
|
6
18
|
|
|
7
|
-
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
19
|
+
- 31a2d35: ZERO-3640: Refactor checkout API call to include useFormData option; update FlowPayment component for improved error handling and code readability
|
|
20
|
+
|
|
21
|
+
## 1.108.0-rc.4
|
|
22
|
+
|
|
23
|
+
### Minor Changes
|
|
24
|
+
|
|
25
|
+
- d8883ce: ZERO-3640: Refactor wallet completion handling to accept additional parameters; update related API calls
|
|
26
|
+
|
|
27
|
+
## 1.108.0-rc.3
|
|
28
|
+
|
|
29
|
+
### Minor Changes
|
|
30
|
+
|
|
31
|
+
- e00b4a8: ZERO-3640: Refactor wallet selection initialization and error handling; streamline payment session management
|
|
32
|
+
|
|
33
|
+
## 1.108.0-rc.2
|
|
34
|
+
|
|
35
|
+
## 1.108.0-rc.1
|
|
36
|
+
|
|
37
|
+
### Minor Changes
|
|
38
|
+
|
|
39
|
+
- 21d88c1: ZERO-3640: Remove redundant API calls
|
|
40
|
+
|
|
41
|
+
## 1.108.0-rc.0
|
|
42
|
+
|
|
43
|
+
### Minor Changes
|
|
44
|
+
|
|
45
|
+
- ce2e9e20: ZERO-3640: Add error handling and WalletCompletePage request to FlowPayment
|
|
11
46
|
|
|
12
47
|
## 1.107.0
|
|
13
48
|
|
|
@@ -48,29 +83,6 @@
|
|
|
48
83
|
### Minor Changes
|
|
49
84
|
|
|
50
85
|
- 69e4cc5: BRDG-14604: Refactor FlowPayment component to optimize flow initialization and cleanup logic
|
|
51
|
-
- d8be48fb: ZERO-3422: Update fetch method to use dynamic request method in wallet complete redirection middleware
|
|
52
|
-
- 8b1d24eb: ZERO-3422: Update fetch method to use dynamic request method in wallet complete redirection middleware
|
|
53
|
-
|
|
54
|
-
## 1.96.0-rc.60
|
|
55
|
-
|
|
56
|
-
## 1.96.0-rc.59
|
|
57
|
-
|
|
58
|
-
## 1.96.0-rc.58
|
|
59
|
-
|
|
60
|
-
## 1.96.0-rc.57
|
|
61
|
-
|
|
62
|
-
## 1.96.0-rc.56
|
|
63
|
-
|
|
64
|
-
### Minor Changes
|
|
65
|
-
|
|
66
|
-
- 69e4cc5: BRDG-14604: Refactor FlowPayment component to optimize flow initialization and cleanup logic
|
|
67
|
-
|
|
68
|
-
## 1.96.0-rc.55
|
|
69
|
-
|
|
70
|
-
### Minor Changes
|
|
71
|
-
|
|
72
|
-
- d8be48fb: ZERO-3422: Update fetch method to use dynamic request method in wallet complete redirection middleware
|
|
73
|
-
- 8b1d24eb: ZERO-3422: Update fetch method to use dynamic request method in wallet complete redirection middleware
|
|
74
86
|
|
|
75
87
|
## 1.95.0
|
|
76
88
|
|
package/package.json
CHANGED
package/src/views/index.tsx
CHANGED
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
import { checkoutApi } from '@akinon/next/data/client/checkout';
|
|
2
2
|
import { useAppDispatch, useAppSelector } from '@akinon/next/redux/hooks';
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
useSetWalletSelectionPageMutation,
|
|
6
|
-
useSetWalletPaymentPageMutation
|
|
7
|
-
} from '@akinon/next/data/client/checkout';
|
|
3
|
+
import { getCookie } from '@akinon/next/utils';
|
|
4
|
+
import { getUrlPathWithLocale } from '@akinon/next/utils/localization';
|
|
8
5
|
import {
|
|
9
6
|
ComponentOptions,
|
|
10
7
|
CustomTranslations,
|
|
@@ -13,7 +10,23 @@ import {
|
|
|
13
10
|
PaymentSessionResponse
|
|
14
11
|
} from '@checkout.com/checkout-web-components';
|
|
15
12
|
import { RootState } from '@theme/redux/store';
|
|
16
|
-
import { useEffect, useRef, useMemo } from 'react';
|
|
13
|
+
import { useEffect, useRef, useMemo, useState } from 'react';
|
|
14
|
+
|
|
15
|
+
const formatErrorMessage = (errors: any): string => {
|
|
16
|
+
if (typeof errors === 'string') {
|
|
17
|
+
return errors;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (Array.isArray(errors)) {
|
|
21
|
+
return errors.join(', ');
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
if (typeof errors === 'object' && errors !== null) {
|
|
25
|
+
return Object.values(errors).join(', ');
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return 'An error occurred during payment processing';
|
|
29
|
+
};
|
|
17
30
|
|
|
18
31
|
export default function FlowPayment({
|
|
19
32
|
options
|
|
@@ -64,12 +77,9 @@ export default function FlowPayment({
|
|
|
64
77
|
const flowComponentRef = useRef<any>(null);
|
|
65
78
|
const lastAmountRef = useRef<string | null>(null);
|
|
66
79
|
const isInitializingRef = useRef<boolean>(false);
|
|
67
|
-
const
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
const [setPaymentOption] = useSetPaymentOptionMutation();
|
|
71
|
-
const [setWalletSelectionPage] = useSetWalletSelectionPageMutation();
|
|
72
|
-
const [setWalletPaymentPage] = useSetWalletPaymentPageMutation();
|
|
80
|
+
const [errors, setErrors] = useState<any>(null);
|
|
81
|
+
const [walletSelectionReady, setWalletSelectionReady] =
|
|
82
|
+
useState<boolean>(false);
|
|
73
83
|
|
|
74
84
|
// Memoize the amount to track actual changes
|
|
75
85
|
const currentAmount = useMemo(() => {
|
|
@@ -77,100 +87,104 @@ export default function FlowPayment({
|
|
|
77
87
|
}, [preOrder.total_amount]);
|
|
78
88
|
|
|
79
89
|
const initWalletSelection = async () => {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
payment_option: preOrder.payment_option?.pk
|
|
86
|
-
})
|
|
87
|
-
).unwrap();
|
|
90
|
+
const walletSelectionPageResponse = await dispatch(
|
|
91
|
+
checkoutApi.endpoints.setWalletSelectionPage.initiate({
|
|
92
|
+
payment_option: preOrder.payment_option?.pk
|
|
93
|
+
})
|
|
94
|
+
).unwrap();
|
|
88
95
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
96
|
+
const walletPaymentPageContext =
|
|
97
|
+
walletSelectionPageResponse.context_list.find(
|
|
98
|
+
(c) => c.page_name === 'WalletPaymentPage'
|
|
99
|
+
);
|
|
93
100
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
101
|
+
if (!walletPaymentPageContext) {
|
|
102
|
+
setErrors(
|
|
103
|
+
'Payment method not available. Please try a different payment option.'
|
|
104
|
+
);
|
|
105
|
+
setWalletSelectionReady(false);
|
|
106
|
+
return;
|
|
97
107
|
}
|
|
98
|
-
};
|
|
99
108
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
109
|
+
// Initialize wallet payment page to get payment session data
|
|
110
|
+
const walletPaymentPageResponse = await dispatch(
|
|
111
|
+
checkoutApi.endpoints.setWalletPaymentPage.initiate({
|
|
112
|
+
payment_method: 'checkout_flow',
|
|
113
|
+
wallet_method: preOrder.wallet_method
|
|
114
|
+
})
|
|
115
|
+
).unwrap();
|
|
116
|
+
|
|
117
|
+
if (walletPaymentPageResponse.errors) {
|
|
118
|
+
setErrors(walletPaymentPageResponse.errors);
|
|
119
|
+
setWalletSelectionReady(false);
|
|
107
120
|
return;
|
|
108
121
|
}
|
|
109
122
|
|
|
110
|
-
|
|
123
|
+
setWalletSelectionReady(true);
|
|
124
|
+
};
|
|
111
125
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
if (preOrder.payment_option?.pk) {
|
|
115
|
-
const paymentOptionResponse = await setPaymentOption(
|
|
116
|
-
preOrder.payment_option.pk
|
|
117
|
-
).unwrap();
|
|
118
|
-
|
|
119
|
-
// Check if WalletSelectionPage is available in the context list
|
|
120
|
-
const walletSelectionPageContext =
|
|
121
|
-
paymentOptionResponse.context_list?.find(
|
|
122
|
-
(c) => c.page_name === 'WalletSelectionPage'
|
|
123
|
-
);
|
|
124
|
-
|
|
125
|
-
if (!walletSelectionPageContext) {
|
|
126
|
-
console.warn(
|
|
127
|
-
'WalletSelectionPage not found in payment option response context list'
|
|
128
|
-
);
|
|
129
|
-
return;
|
|
130
|
-
}
|
|
131
|
-
}
|
|
126
|
+
const handlePaymentSuccess = async (paymentData: any) => {
|
|
127
|
+
setErrors(null);
|
|
132
128
|
|
|
133
|
-
|
|
134
|
-
const
|
|
135
|
-
|
|
136
|
-
}).unwrap();
|
|
129
|
+
try {
|
|
130
|
+
const ckoPaymentId = paymentData?.id;
|
|
131
|
+
const isSuccess = paymentData?.status === 'Approved';
|
|
137
132
|
|
|
138
|
-
const
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
133
|
+
const paymentCompleteResponse = await dispatch(
|
|
134
|
+
checkoutApi.endpoints.setWalletCompletePage.initiate({
|
|
135
|
+
success: isSuccess,
|
|
136
|
+
'cko-payment-id': ckoPaymentId
|
|
137
|
+
})
|
|
138
|
+
).unwrap();
|
|
142
139
|
|
|
143
|
-
if (
|
|
140
|
+
if (paymentCompleteResponse.errors) {
|
|
141
|
+
setErrors(paymentCompleteResponse.errors);
|
|
144
142
|
return;
|
|
145
143
|
}
|
|
146
144
|
|
|
147
|
-
|
|
148
|
-
|
|
145
|
+
if (
|
|
146
|
+
paymentCompleteResponse.context_list.find(
|
|
147
|
+
(c) => c.page_name === 'ThankYouPage'
|
|
148
|
+
)
|
|
149
|
+
) {
|
|
150
|
+
const redirectUrl = paymentCompleteResponse.context_list.find(
|
|
151
|
+
(c) => c.page_name === 'ThankYouPage'
|
|
152
|
+
)?.page_context.context_data.redirect_url;
|
|
149
153
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
});
|
|
154
|
+
const redirectUrlWithLocale = `${
|
|
155
|
+
window.location.origin
|
|
156
|
+
}${getUrlPathWithLocale(redirectUrl, getCookie('pz-locale') || 'en')}`;
|
|
157
|
+
|
|
158
|
+
window.location.href = redirectUrlWithLocale;
|
|
159
|
+
}
|
|
157
160
|
} catch (error) {
|
|
158
|
-
console.error(
|
|
159
|
-
|
|
160
|
-
error
|
|
161
|
-
);
|
|
162
|
-
} finally {
|
|
163
|
-
isInitializingRef.current = false;
|
|
161
|
+
console.error('Error processing payment completion:', error);
|
|
162
|
+
setErrors(error);
|
|
164
163
|
}
|
|
165
164
|
};
|
|
166
165
|
|
|
166
|
+
const handlePaymentError = async (error: any) => {
|
|
167
|
+
console.error('Payment error occurred:', error);
|
|
168
|
+
setErrors(error);
|
|
169
|
+
};
|
|
170
|
+
|
|
167
171
|
const initFlowPaymentWebComponents = async ({
|
|
168
|
-
publicKey
|
|
169
|
-
paymentSession
|
|
172
|
+
publicKey
|
|
170
173
|
}: {
|
|
171
174
|
publicKey: string;
|
|
172
|
-
paymentSession?: any;
|
|
173
175
|
}) => {
|
|
176
|
+
// Prevent multiple simultaneous initializations
|
|
177
|
+
if (isInitializingRef.current) {
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// Check if amount has actually changed
|
|
182
|
+
if (lastAmountRef.current === currentAmount && flowComponentRef.current) {
|
|
183
|
+
return; // Don't recreate component if amount hasn't changed
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
isInitializingRef.current = true;
|
|
187
|
+
|
|
174
188
|
try {
|
|
175
189
|
// Destroy existing flow component if it exists
|
|
176
190
|
if (flowComponentRef.current) {
|
|
@@ -188,7 +202,18 @@ export default function FlowPayment({
|
|
|
188
202
|
container.innerHTML = '';
|
|
189
203
|
}
|
|
190
204
|
|
|
191
|
-
//
|
|
205
|
+
// FIX: Use existing payment session from preOrder.context_extras
|
|
206
|
+
let paymentSession = preOrder.context_extras;
|
|
207
|
+
|
|
208
|
+
// If we don't have payment session data, we need to wait for it
|
|
209
|
+
if (!paymentSession) {
|
|
210
|
+
console.warn(
|
|
211
|
+
'FlowPayment: Payment session not available yet, component will retry when data is ready'
|
|
212
|
+
);
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// Update the last amount reference after getting fresh data
|
|
192
217
|
lastAmountRef.current = currentAmount;
|
|
193
218
|
|
|
194
219
|
const checkout = await loadCheckoutWebComponents({
|
|
@@ -196,15 +221,21 @@ export default function FlowPayment({
|
|
|
196
221
|
environment: options?.environment || 'production',
|
|
197
222
|
locale: options?.locale || 'en',
|
|
198
223
|
translations: options?.translations,
|
|
199
|
-
paymentSession:
|
|
200
|
-
paymentSession || (preOrder.context_extras as PaymentSessionResponse),
|
|
224
|
+
paymentSession: paymentSession as PaymentSessionResponse,
|
|
201
225
|
appearance: options?.appearance,
|
|
202
226
|
componentOptions: options?.componentOptions
|
|
203
227
|
? { flow: options.componentOptions }
|
|
204
228
|
: undefined
|
|
205
229
|
});
|
|
206
230
|
|
|
207
|
-
const flowComponent = checkout.create('flow'
|
|
231
|
+
const flowComponent = checkout.create('flow', {
|
|
232
|
+
onPaymentCompleted: async (_self, paymentResponse) => {
|
|
233
|
+
handlePaymentSuccess(paymentResponse);
|
|
234
|
+
},
|
|
235
|
+
onError: async (_self, error) => {
|
|
236
|
+
handlePaymentError(error);
|
|
237
|
+
}
|
|
238
|
+
});
|
|
208
239
|
flowComponentRef.current = flowComponent;
|
|
209
240
|
|
|
210
241
|
if (container) {
|
|
@@ -212,6 +243,8 @@ export default function FlowPayment({
|
|
|
212
243
|
}
|
|
213
244
|
} catch (error) {
|
|
214
245
|
console.error('Error initializing flow payment components:', error);
|
|
246
|
+
} finally {
|
|
247
|
+
isInitializingRef.current = false;
|
|
215
248
|
}
|
|
216
249
|
};
|
|
217
250
|
|
|
@@ -219,48 +252,29 @@ export default function FlowPayment({
|
|
|
219
252
|
initWalletSelection();
|
|
220
253
|
}, []);
|
|
221
254
|
|
|
222
|
-
// Initial flow component initialization
|
|
223
255
|
useEffect(() => {
|
|
224
256
|
if (
|
|
225
257
|
!preOrder.wallet_method ||
|
|
226
|
-
!preOrder.token ||
|
|
227
258
|
!walletPaymentData?.data?.public_key ||
|
|
228
|
-
preOrder.wallet_method !== 'checkout_flow'
|
|
259
|
+
preOrder.wallet_method !== 'checkout_flow' ||
|
|
260
|
+
!walletSelectionReady ||
|
|
261
|
+
!preOrder.context_extras
|
|
229
262
|
) {
|
|
230
263
|
return;
|
|
231
264
|
}
|
|
232
265
|
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
publicKey: walletPaymentData.data.public_key
|
|
237
|
-
});
|
|
238
|
-
}
|
|
266
|
+
initFlowPaymentWebComponents({
|
|
267
|
+
publicKey: walletPaymentData.data.public_key
|
|
268
|
+
});
|
|
239
269
|
}, [
|
|
240
270
|
preOrder.wallet_method,
|
|
241
271
|
preOrder.token,
|
|
242
|
-
|
|
272
|
+
currentAmount, // Use memoized amount instead of preOrder.total_amount
|
|
273
|
+
walletPaymentData?.data?.public_key,
|
|
274
|
+
walletSelectionReady,
|
|
275
|
+
preOrder.context_extras // Add payment session dependency
|
|
243
276
|
]);
|
|
244
277
|
|
|
245
|
-
// Handle amount changes by refreshing payment session
|
|
246
|
-
useEffect(() => {
|
|
247
|
-
if (
|
|
248
|
-
!preOrder.wallet_method ||
|
|
249
|
-
!preOrder.token ||
|
|
250
|
-
!walletPaymentData?.data?.public_key ||
|
|
251
|
-
preOrder.wallet_method !== 'checkout_flow'
|
|
252
|
-
) {
|
|
253
|
-
return;
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
// Only refresh if component exists and amount has changed
|
|
257
|
-
if (flowComponentRef.current && lastAmountRef.current !== currentAmount) {
|
|
258
|
-
refreshPaymentSessionAndInitFlow({
|
|
259
|
-
publicKey: walletPaymentData.data.public_key
|
|
260
|
-
});
|
|
261
|
-
}
|
|
262
|
-
}, [currentAmount]);
|
|
263
|
-
|
|
264
278
|
// Cleanup function when component unmounts
|
|
265
279
|
useEffect(() => {
|
|
266
280
|
return () => {
|
|
@@ -271,10 +285,17 @@ export default function FlowPayment({
|
|
|
271
285
|
console.warn('Error destroying flow component on unmount:', error);
|
|
272
286
|
}
|
|
273
287
|
}
|
|
274
|
-
// Reset initialization flag on unmount
|
|
275
|
-
walletPaymentInitialized.current = false;
|
|
276
288
|
};
|
|
277
289
|
}, []);
|
|
278
290
|
|
|
279
|
-
return
|
|
291
|
+
return (
|
|
292
|
+
<div className="flow-payment-container">
|
|
293
|
+
<div id="flow-container"></div>
|
|
294
|
+
{errors && (
|
|
295
|
+
<div className="text-error-100 text-xs mt-5">
|
|
296
|
+
{formatErrorMessage(errors)}
|
|
297
|
+
</div>
|
|
298
|
+
)}
|
|
299
|
+
</div>
|
|
300
|
+
);
|
|
280
301
|
}
|