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