@akinon/pz-flow-payment 1.99.0-rc.69 → 1.99.0-snapshot-ZERO-3640-20250919140314
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 +2 -36
- package/package.json +1 -1
- package/src/views/index.tsx +136 -117
package/CHANGELOG.md
CHANGED
|
@@ -1,21 +1,10 @@
|
|
|
1
1
|
# @akinon/pz-flow-payment
|
|
2
2
|
|
|
3
|
-
## 1.99.0-
|
|
4
|
-
|
|
5
|
-
## 1.99.0-rc.68
|
|
6
|
-
|
|
7
|
-
## 1.99.0-rc.67
|
|
8
|
-
|
|
9
|
-
### Minor Changes
|
|
10
|
-
|
|
11
|
-
- 1b9e9be: BRDG-14604: Refactor FlowPayment component to utilize RTK Query mutations for payment options and wallet selection, enhancing session management and initialization logic
|
|
12
|
-
|
|
13
|
-
## 1.99.0-rc.66
|
|
3
|
+
## 1.99.0-snapshot-ZERO-3640-20250919140314
|
|
14
4
|
|
|
15
5
|
### Minor Changes
|
|
16
6
|
|
|
17
|
-
-
|
|
18
|
-
- 8b1d24eb: ZERO-3422: Update fetch method to use dynamic request method in wallet complete redirection middleware
|
|
7
|
+
- ce2e9e2: ZERO-3640: Add error handling and WalletCompletePage request to FlowPayment
|
|
19
8
|
|
|
20
9
|
## 1.98.0
|
|
21
10
|
|
|
@@ -30,29 +19,6 @@
|
|
|
30
19
|
### Minor Changes
|
|
31
20
|
|
|
32
21
|
- 69e4cc5: BRDG-14604: Refactor FlowPayment component to optimize flow initialization and cleanup logic
|
|
33
|
-
- d8be48fb: ZERO-3422: Update fetch method to use dynamic request method in wallet complete redirection middleware
|
|
34
|
-
- 8b1d24eb: ZERO-3422: Update fetch method to use dynamic request method in wallet complete redirection middleware
|
|
35
|
-
|
|
36
|
-
## 1.96.0-rc.60
|
|
37
|
-
|
|
38
|
-
## 1.96.0-rc.59
|
|
39
|
-
|
|
40
|
-
## 1.96.0-rc.58
|
|
41
|
-
|
|
42
|
-
## 1.96.0-rc.57
|
|
43
|
-
|
|
44
|
-
## 1.96.0-rc.56
|
|
45
|
-
|
|
46
|
-
### Minor Changes
|
|
47
|
-
|
|
48
|
-
- 69e4cc5: BRDG-14604: Refactor FlowPayment component to optimize flow initialization and cleanup logic
|
|
49
|
-
|
|
50
|
-
## 1.96.0-rc.55
|
|
51
|
-
|
|
52
|
-
### Minor Changes
|
|
53
|
-
|
|
54
|
-
- d8be48fb: ZERO-3422: Update fetch method to use dynamic request method in wallet complete redirection middleware
|
|
55
|
-
- 8b1d24eb: ZERO-3422: Update fetch method to use dynamic request method in wallet complete redirection middleware
|
|
56
22
|
|
|
57
23
|
## 1.95.0
|
|
58
24
|
|
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,
|
|
@@ -12,8 +9,7 @@ import {
|
|
|
12
9
|
PartialDesignTokens,
|
|
13
10
|
PaymentSessionResponse
|
|
14
11
|
} from '@checkout.com/checkout-web-components';
|
|
15
|
-
import {
|
|
16
|
-
import { useEffect, useRef, useMemo } from 'react';
|
|
12
|
+
import { useEffect, useRef, useMemo, useState } from 'react';
|
|
17
13
|
|
|
18
14
|
export default function FlowPayment({
|
|
19
15
|
options
|
|
@@ -21,7 +17,7 @@ export default function FlowPayment({
|
|
|
21
17
|
options?: {
|
|
22
18
|
/**
|
|
23
19
|
* Environment to use for the payment components.
|
|
24
|
-
* Defaults to '
|
|
20
|
+
* Defaults to 'sandbox'.
|
|
25
21
|
* If you want to test the payment components, you can set this to 'sandbox'.
|
|
26
22
|
*/
|
|
27
23
|
environment?: 'sandbox' | 'production';
|
|
@@ -58,18 +54,16 @@ export default function FlowPayment({
|
|
|
58
54
|
};
|
|
59
55
|
}) {
|
|
60
56
|
const { preOrder, walletPaymentData } = useAppSelector(
|
|
61
|
-
(state:
|
|
57
|
+
(state: any) => state.checkout
|
|
62
58
|
);
|
|
63
59
|
const dispatch = useAppDispatch();
|
|
64
60
|
const flowComponentRef = useRef<any>(null);
|
|
65
61
|
const lastAmountRef = useRef<string | null>(null);
|
|
66
62
|
const isInitializingRef = useRef<boolean>(false);
|
|
67
63
|
const walletPaymentInitialized = useRef<boolean>(false);
|
|
64
|
+
const [errors, setErrors] = useState<any>(null);
|
|
68
65
|
|
|
69
|
-
|
|
70
|
-
const [setPaymentOption] = useSetPaymentOptionMutation();
|
|
71
|
-
const [setWalletSelectionPage] = useSetWalletSelectionPageMutation();
|
|
72
|
-
const [setWalletPaymentPage] = useSetWalletPaymentPageMutation();
|
|
66
|
+
const environment = options?.environment || 'sandbox';
|
|
73
67
|
|
|
74
68
|
// Memoize the amount to track actual changes
|
|
75
69
|
const currentAmount = useMemo(() => {
|
|
@@ -77,100 +71,104 @@ export default function FlowPayment({
|
|
|
77
71
|
}, [preOrder.total_amount]);
|
|
78
72
|
|
|
79
73
|
const initWalletSelection = async () => {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
payment_option: preOrder.payment_option?.pk
|
|
86
|
-
})
|
|
87
|
-
).unwrap();
|
|
74
|
+
const walletSelectionPageResponse = await dispatch(
|
|
75
|
+
checkoutApi.endpoints.setWalletSelectionPage.initiate({
|
|
76
|
+
payment_option: preOrder.payment_option?.pk
|
|
77
|
+
})
|
|
78
|
+
).unwrap();
|
|
88
79
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
80
|
+
const walletPaymentPageContext =
|
|
81
|
+
walletSelectionPageResponse.context_list.find(
|
|
82
|
+
(c) => c.page_name === 'WalletPaymentPage'
|
|
83
|
+
);
|
|
93
84
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
}
|
|
85
|
+
if (!walletPaymentPageContext) {
|
|
86
|
+
return;
|
|
97
87
|
}
|
|
98
|
-
};
|
|
99
88
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
}) => {
|
|
105
|
-
// Prevent multiple simultaneous initializations
|
|
106
|
-
if (isInitializingRef.current) {
|
|
107
|
-
return;
|
|
89
|
+
// FIX: Only call setWalletPaymentPage if not already initialized
|
|
90
|
+
if (!walletPaymentInitialized.current) {
|
|
91
|
+
walletPaymentInitialized.current = true;
|
|
92
|
+
dispatch(checkoutApi.endpoints.setWalletPaymentPage.initiate({}));
|
|
108
93
|
}
|
|
94
|
+
};
|
|
109
95
|
|
|
110
|
-
|
|
96
|
+
const handlePaymentSuccess = async (paymentData: any) => {
|
|
97
|
+
setErrors(null);
|
|
111
98
|
|
|
112
99
|
try {
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
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
|
-
);
|
|
100
|
+
const walletPaymentPageResponse = await dispatch(
|
|
101
|
+
checkoutApi.endpoints.setWalletPaymentPage.initiate({
|
|
102
|
+
payment_token: JSON.stringify(paymentData)
|
|
103
|
+
})
|
|
104
|
+
).unwrap();
|
|
124
105
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
);
|
|
129
|
-
return;
|
|
130
|
-
}
|
|
106
|
+
if (walletPaymentPageResponse.errors) {
|
|
107
|
+
setErrors(walletPaymentPageResponse.errors);
|
|
108
|
+
return;
|
|
131
109
|
}
|
|
132
110
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
111
|
+
if (
|
|
112
|
+
walletPaymentPageResponse.context_list.find(
|
|
113
|
+
(c) => c.page_name === 'WalletCompletePage'
|
|
114
|
+
)
|
|
115
|
+
) {
|
|
116
|
+
const paymentCompleteResponse = await dispatch(
|
|
117
|
+
checkoutApi.endpoints.setWalletCompletePage.initiate(true)
|
|
118
|
+
).unwrap();
|
|
137
119
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
120
|
+
if (paymentCompleteResponse.errors) {
|
|
121
|
+
setErrors(paymentCompleteResponse.errors);
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
142
124
|
|
|
143
|
-
|
|
144
|
-
|
|
125
|
+
if (
|
|
126
|
+
paymentCompleteResponse.context_list.find(
|
|
127
|
+
(c) => c.page_name === 'ThankYouPage'
|
|
128
|
+
)
|
|
129
|
+
) {
|
|
130
|
+
const redirectUrl = paymentCompleteResponse.context_list.find(
|
|
131
|
+
(c) => c.page_name === 'ThankYouPage'
|
|
132
|
+
)?.page_context.context_data.redirect_url;
|
|
133
|
+
|
|
134
|
+
const redirectUrlWithLocale = `${
|
|
135
|
+
window.location.origin
|
|
136
|
+
}${getUrlPathWithLocale(
|
|
137
|
+
redirectUrl,
|
|
138
|
+
getCookie('pz-locale') || 'en'
|
|
139
|
+
)}`;
|
|
140
|
+
|
|
141
|
+
window.location.href = redirectUrlWithLocale;
|
|
142
|
+
}
|
|
145
143
|
}
|
|
146
|
-
|
|
147
|
-
// Step 3: Set wallet payment page to get updated payment session
|
|
148
|
-
const walletPaymentResponse = await setWalletPaymentPage({}).unwrap();
|
|
149
|
-
|
|
150
|
-
// Step 4: Initialize flow component with fresh payment session
|
|
151
|
-
await initFlowPaymentWebComponents({
|
|
152
|
-
publicKey,
|
|
153
|
-
paymentSession:
|
|
154
|
-
walletPaymentResponse?.pre_order?.context_extras ||
|
|
155
|
-
preOrder.context_extras
|
|
156
|
-
});
|
|
157
144
|
} catch (error) {
|
|
158
|
-
console.error(
|
|
159
|
-
|
|
160
|
-
error
|
|
161
|
-
);
|
|
162
|
-
} finally {
|
|
163
|
-
isInitializingRef.current = false;
|
|
145
|
+
console.error('Error processing payment completion:', error);
|
|
146
|
+
setErrors(error);
|
|
164
147
|
}
|
|
165
148
|
};
|
|
166
149
|
|
|
150
|
+
const handlePaymentError = async (error: any) => {
|
|
151
|
+
console.error('Payment error occurred:', error);
|
|
152
|
+
setErrors(error);
|
|
153
|
+
};
|
|
154
|
+
|
|
167
155
|
const initFlowPaymentWebComponents = async ({
|
|
168
|
-
publicKey
|
|
169
|
-
paymentSession
|
|
156
|
+
publicKey
|
|
170
157
|
}: {
|
|
171
158
|
publicKey: string;
|
|
172
|
-
paymentSession?: any;
|
|
173
159
|
}) => {
|
|
160
|
+
// Prevent multiple simultaneous initializations
|
|
161
|
+
if (isInitializingRef.current) {
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// Check if amount has actually changed
|
|
166
|
+
if (lastAmountRef.current === currentAmount && flowComponentRef.current) {
|
|
167
|
+
return; // Don't recreate component if amount hasn't changed
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
isInitializingRef.current = true;
|
|
171
|
+
|
|
174
172
|
try {
|
|
175
173
|
// Destroy existing flow component if it exists
|
|
176
174
|
if (flowComponentRef.current) {
|
|
@@ -188,23 +186,49 @@ export default function FlowPayment({
|
|
|
188
186
|
container.innerHTML = '';
|
|
189
187
|
}
|
|
190
188
|
|
|
191
|
-
//
|
|
189
|
+
// FIX: Use existing payment session instead of making another API call
|
|
190
|
+
let paymentSession = preOrder.context_extras;
|
|
191
|
+
|
|
192
|
+
// Only get fresh payment data if we don't have a valid session
|
|
193
|
+
if (!paymentSession && lastAmountRef.current !== currentAmount) {
|
|
194
|
+
// Check if another call is already in progress
|
|
195
|
+
if (!walletPaymentInitialized.current) {
|
|
196
|
+
walletPaymentInitialized.current = true;
|
|
197
|
+
const walletPaymentResponse = await dispatch(
|
|
198
|
+
checkoutApi.endpoints.setWalletPaymentPage.initiate({})
|
|
199
|
+
).unwrap();
|
|
200
|
+
paymentSession =
|
|
201
|
+
walletPaymentResponse?.pre_order?.context_extras ||
|
|
202
|
+
preOrder.context_extras;
|
|
203
|
+
} else {
|
|
204
|
+
// Use existing context_extras if another call was already made
|
|
205
|
+
paymentSession = preOrder.context_extras;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// Update the last amount reference after getting fresh data
|
|
192
210
|
lastAmountRef.current = currentAmount;
|
|
193
211
|
|
|
194
212
|
const checkout = await loadCheckoutWebComponents({
|
|
195
213
|
publicKey,
|
|
196
|
-
environment
|
|
214
|
+
environment,
|
|
197
215
|
locale: options?.locale || 'en',
|
|
198
216
|
translations: options?.translations,
|
|
199
|
-
paymentSession:
|
|
200
|
-
paymentSession || (preOrder.context_extras as PaymentSessionResponse),
|
|
217
|
+
paymentSession: paymentSession as PaymentSessionResponse,
|
|
201
218
|
appearance: options?.appearance,
|
|
202
219
|
componentOptions: options?.componentOptions
|
|
203
220
|
? { flow: options.componentOptions }
|
|
204
221
|
: undefined
|
|
205
222
|
});
|
|
206
223
|
|
|
207
|
-
const flowComponent = checkout.create('flow'
|
|
224
|
+
const flowComponent = checkout.create('flow', {
|
|
225
|
+
onPaymentCompleted: async (_self, paymentResponse) => {
|
|
226
|
+
handlePaymentSuccess(paymentResponse);
|
|
227
|
+
},
|
|
228
|
+
onError: async (_self, error) => {
|
|
229
|
+
handlePaymentError(error);
|
|
230
|
+
}
|
|
231
|
+
});
|
|
208
232
|
flowComponentRef.current = flowComponent;
|
|
209
233
|
|
|
210
234
|
if (container) {
|
|
@@ -212,6 +236,8 @@ export default function FlowPayment({
|
|
|
212
236
|
}
|
|
213
237
|
} catch (error) {
|
|
214
238
|
console.error('Error initializing flow payment components:', error);
|
|
239
|
+
} finally {
|
|
240
|
+
isInitializingRef.current = false;
|
|
215
241
|
}
|
|
216
242
|
};
|
|
217
243
|
|
|
@@ -219,7 +245,6 @@ export default function FlowPayment({
|
|
|
219
245
|
initWalletSelection();
|
|
220
246
|
}, []);
|
|
221
247
|
|
|
222
|
-
// Initial flow component initialization
|
|
223
248
|
useEffect(() => {
|
|
224
249
|
if (
|
|
225
250
|
!preOrder.wallet_method ||
|
|
@@ -230,37 +255,16 @@ export default function FlowPayment({
|
|
|
230
255
|
return;
|
|
231
256
|
}
|
|
232
257
|
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
publicKey: walletPaymentData.data.public_key
|
|
237
|
-
});
|
|
238
|
-
}
|
|
258
|
+
initFlowPaymentWebComponents({
|
|
259
|
+
publicKey: walletPaymentData.data.public_key
|
|
260
|
+
});
|
|
239
261
|
}, [
|
|
240
262
|
preOrder.wallet_method,
|
|
241
263
|
preOrder.token,
|
|
264
|
+
currentAmount, // Use memoized amount instead of preOrder.total_amount
|
|
242
265
|
walletPaymentData?.data?.public_key
|
|
243
266
|
]);
|
|
244
267
|
|
|
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
268
|
// Cleanup function when component unmounts
|
|
265
269
|
useEffect(() => {
|
|
266
270
|
return () => {
|
|
@@ -276,5 +280,20 @@ export default function FlowPayment({
|
|
|
276
280
|
};
|
|
277
281
|
}, []);
|
|
278
282
|
|
|
279
|
-
return
|
|
283
|
+
return (
|
|
284
|
+
<div className="flow-payment-container">
|
|
285
|
+
<div id="flow-container"></div>
|
|
286
|
+
{errors && (
|
|
287
|
+
<div className="text-error-100 text-xs mt-5">
|
|
288
|
+
{typeof errors === 'string'
|
|
289
|
+
? errors
|
|
290
|
+
: Array.isArray(errors)
|
|
291
|
+
? errors.join(', ')
|
|
292
|
+
: typeof errors === 'object'
|
|
293
|
+
? Object.values(errors ?? {}).join(', ')
|
|
294
|
+
: 'An error occurred during payment processing'}
|
|
295
|
+
</div>
|
|
296
|
+
)}
|
|
297
|
+
</div>
|
|
298
|
+
);
|
|
280
299
|
}
|