@akinon/pz-flow-payment 1.99.0-snapshot-ZERO-3640-20250919140935 → 1.100.0-rc.71

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 CHANGED
@@ -1,10 +1,18 @@
1
1
  # @akinon/pz-flow-payment
2
2
 
3
- ## 1.99.0-snapshot-ZERO-3640-20250919140935
3
+ ## 1.100.0-rc.71
4
4
 
5
5
  ### Minor Changes
6
6
 
7
- - ce2e9e2: ZERO-3640: Add error handling and WalletCompletePage request to FlowPayment
7
+ - 1b9e9be: BRDG-14604: Refactor FlowPayment component to utilize RTK Query mutations for payment options and wallet selection, enhancing session management and initialization logic
8
+ - d8be48fb: ZERO-3422: Update fetch method to use dynamic request method in wallet complete redirection middleware
9
+ - 8b1d24eb: ZERO-3422: Update fetch method to use dynamic request method in wallet complete redirection middleware
10
+
11
+ ## 1.99.0
12
+
13
+ ### Minor Changes
14
+
15
+ - d58538b: ZERO-3638: Enhance RC pipeline: add fetch, merge, and pre-release setup with conditional commit
8
16
 
9
17
  ## 1.98.0
10
18
 
@@ -19,6 +27,29 @@
19
27
  ### Minor Changes
20
28
 
21
29
  - 69e4cc5: BRDG-14604: Refactor FlowPayment component to optimize flow initialization and cleanup logic
30
+ - d8be48fb: ZERO-3422: Update fetch method to use dynamic request method in wallet complete redirection middleware
31
+ - 8b1d24eb: ZERO-3422: Update fetch method to use dynamic request method in wallet complete redirection middleware
32
+
33
+ ## 1.96.0-rc.60
34
+
35
+ ## 1.96.0-rc.59
36
+
37
+ ## 1.96.0-rc.58
38
+
39
+ ## 1.96.0-rc.57
40
+
41
+ ## 1.96.0-rc.56
42
+
43
+ ### Minor Changes
44
+
45
+ - 69e4cc5: BRDG-14604: Refactor FlowPayment component to optimize flow initialization and cleanup logic
46
+
47
+ ## 1.96.0-rc.55
48
+
49
+ ### Minor Changes
50
+
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
22
53
 
23
54
  ## 1.95.0
24
55
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@akinon/pz-flow-payment",
3
3
  "license": "MIT",
4
- "version": "1.99.0-snapshot-ZERO-3640-20250919140935",
4
+ "version": "1.100.0-rc.71",
5
5
  "main": "src/index.tsx",
6
6
  "dependencies": {
7
7
  "@checkout.com/checkout-web-components": "0.7.0-beta"
@@ -1,7 +1,10 @@
1
1
  import { checkoutApi } from '@akinon/next/data/client/checkout';
2
2
  import { useAppDispatch, useAppSelector } from '@akinon/next/redux/hooks';
3
- import { getCookie } from '@akinon/next/utils';
4
- import { getUrlPathWithLocale } from '@akinon/next/utils/localization';
3
+ import {
4
+ useSetPaymentOptionMutation,
5
+ useSetWalletSelectionPageMutation,
6
+ useSetWalletPaymentPageMutation
7
+ } from '@akinon/next/data/client/checkout';
5
8
  import {
6
9
  ComponentOptions,
7
10
  CustomTranslations,
@@ -9,7 +12,8 @@ import {
9
12
  PartialDesignTokens,
10
13
  PaymentSessionResponse
11
14
  } from '@checkout.com/checkout-web-components';
12
- import { useEffect, useRef, useMemo, useState } from 'react';
15
+ import { RootState } from '@theme/redux/store';
16
+ import { useEffect, useRef, useMemo } from 'react';
13
17
 
14
18
  export default function FlowPayment({
15
19
  options
@@ -17,7 +21,7 @@ export default function FlowPayment({
17
21
  options?: {
18
22
  /**
19
23
  * Environment to use for the payment components.
20
- * Defaults to 'sandbox'.
24
+ * Defaults to 'production'.
21
25
  * If you want to test the payment components, you can set this to 'sandbox'.
22
26
  */
23
27
  environment?: 'sandbox' | 'production';
@@ -54,16 +58,18 @@ export default function FlowPayment({
54
58
  };
55
59
  }) {
56
60
  const { preOrder, walletPaymentData } = useAppSelector(
57
- (state: any) => state.checkout
61
+ (state: RootState) => state.checkout
58
62
  );
59
63
  const dispatch = useAppDispatch();
60
64
  const flowComponentRef = useRef<any>(null);
61
65
  const lastAmountRef = useRef<string | null>(null);
62
66
  const isInitializingRef = useRef<boolean>(false);
63
67
  const walletPaymentInitialized = useRef<boolean>(false);
64
- const [errors, setErrors] = useState<any>(null);
65
68
 
66
- const environment = options?.environment || 'sandbox';
69
+ // RTK Query mutations
70
+ const [setPaymentOption] = useSetPaymentOptionMutation();
71
+ const [setWalletSelectionPage] = useSetWalletSelectionPageMutation();
72
+ const [setWalletPaymentPage] = useSetWalletPaymentPageMutation();
67
73
 
68
74
  // Memoize the amount to track actual changes
69
75
  const currentAmount = useMemo(() => {
@@ -71,88 +77,27 @@ export default function FlowPayment({
71
77
  }, [preOrder.total_amount]);
72
78
 
73
79
  const initWalletSelection = async () => {
74
- const walletSelectionPageResponse = await dispatch(
75
- checkoutApi.endpoints.setWalletSelectionPage.initiate({
76
- payment_option: preOrder.payment_option?.pk
77
- })
78
- ).unwrap();
79
-
80
- const walletPaymentPageContext =
81
- walletSelectionPageResponse.context_list.find(
82
- (c) => c.page_name === 'WalletPaymentPage'
83
- );
84
-
85
- if (!walletPaymentPageContext) {
86
- return;
87
- }
88
-
89
- // FIX: Only call setWalletPaymentPage if not already initialized
90
80
  if (!walletPaymentInitialized.current) {
91
81
  walletPaymentInitialized.current = true;
92
- dispatch(checkoutApi.endpoints.setWalletPaymentPage.initiate({}));
93
- }
94
- };
95
82
 
96
- const handlePaymentSuccess = async (paymentData: any) => {
97
- setErrors(null);
98
-
99
- try {
100
- const walletPaymentPageResponse = await dispatch(
101
- checkoutApi.endpoints.setWalletPaymentPage.initiate({
102
- payment_token: JSON.stringify(paymentData)
83
+ const walletSelectionPageResponse = await dispatch(
84
+ checkoutApi.endpoints.setWalletSelectionPage.initiate({
85
+ payment_option: preOrder.payment_option?.pk
103
86
  })
104
87
  ).unwrap();
105
88
 
106
- if (walletPaymentPageResponse.errors) {
107
- setErrors(walletPaymentPageResponse.errors);
108
- return;
109
- }
110
-
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();
89
+ const walletPaymentPageContext =
90
+ walletSelectionPageResponse.context_list.find(
91
+ (c) => c.page_name === 'WalletPaymentPage'
92
+ );
119
93
 
120
- if (paymentCompleteResponse.errors) {
121
- setErrors(paymentCompleteResponse.errors);
122
- return;
123
- }
124
-
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
- }
94
+ if (walletPaymentPageContext) {
95
+ dispatch(checkoutApi.endpoints.setWalletPaymentPage.initiate({}));
143
96
  }
144
- } catch (error) {
145
- console.error('Error processing payment completion:', error);
146
- setErrors(error);
147
97
  }
148
98
  };
149
99
 
150
- const handlePaymentError = async (error: any) => {
151
- console.error('Payment error occurred:', error);
152
- setErrors(error);
153
- };
154
-
155
- const initFlowPaymentWebComponents = async ({
100
+ const refreshPaymentSessionAndInitFlow = async ({
156
101
  publicKey
157
102
  }: {
158
103
  publicKey: string;
@@ -162,13 +107,70 @@ export default function FlowPayment({
162
107
  return;
163
108
  }
164
109
 
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
110
  isInitializingRef.current = true;
171
111
 
112
+ try {
113
+ // Step 1: Re-set the current payment option to refresh the session with new amount
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
+ }
132
+
133
+ // Step 2: Set wallet selection page
134
+ const walletSelectionResponse = await setWalletSelectionPage({
135
+ payment_option: preOrder.payment_option?.pk
136
+ }).unwrap();
137
+
138
+ const walletPaymentPageContext =
139
+ walletSelectionResponse.context_list?.find(
140
+ (c) => c.page_name === 'WalletPaymentPage'
141
+ );
142
+
143
+ if (!walletPaymentPageContext) {
144
+ return;
145
+ }
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
+ } catch (error) {
158
+ console.error(
159
+ 'Error refreshing payment session and initializing flow:',
160
+ error
161
+ );
162
+ } finally {
163
+ isInitializingRef.current = false;
164
+ }
165
+ };
166
+
167
+ const initFlowPaymentWebComponents = async ({
168
+ publicKey,
169
+ paymentSession
170
+ }: {
171
+ publicKey: string;
172
+ paymentSession?: any;
173
+ }) => {
172
174
  try {
173
175
  // Destroy existing flow component if it exists
174
176
  if (flowComponentRef.current) {
@@ -186,49 +188,23 @@ export default function FlowPayment({
186
188
  container.innerHTML = '';
187
189
  }
188
190
 
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
191
+ // Update the last amount reference
210
192
  lastAmountRef.current = currentAmount;
211
193
 
212
194
  const checkout = await loadCheckoutWebComponents({
213
195
  publicKey,
214
- environment,
196
+ environment: options?.environment || 'production',
215
197
  locale: options?.locale || 'en',
216
198
  translations: options?.translations,
217
- paymentSession: paymentSession as PaymentSessionResponse,
199
+ paymentSession:
200
+ paymentSession || (preOrder.context_extras as PaymentSessionResponse),
218
201
  appearance: options?.appearance,
219
202
  componentOptions: options?.componentOptions
220
203
  ? { flow: options.componentOptions }
221
204
  : undefined
222
205
  });
223
206
 
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
- });
207
+ const flowComponent = checkout.create('flow');
232
208
  flowComponentRef.current = flowComponent;
233
209
 
234
210
  if (container) {
@@ -236,8 +212,6 @@ export default function FlowPayment({
236
212
  }
237
213
  } catch (error) {
238
214
  console.error('Error initializing flow payment components:', error);
239
- } finally {
240
- isInitializingRef.current = false;
241
215
  }
242
216
  };
243
217
 
@@ -245,6 +219,7 @@ export default function FlowPayment({
245
219
  initWalletSelection();
246
220
  }, []);
247
221
 
222
+ // Initial flow component initialization
248
223
  useEffect(() => {
249
224
  if (
250
225
  !preOrder.wallet_method ||
@@ -255,16 +230,37 @@ export default function FlowPayment({
255
230
  return;
256
231
  }
257
232
 
258
- initFlowPaymentWebComponents({
259
- publicKey: walletPaymentData.data.public_key
260
- });
233
+ // Only initialize if component doesn't exist yet (initial mount)
234
+ if (!flowComponentRef.current) {
235
+ initFlowPaymentWebComponents({
236
+ publicKey: walletPaymentData.data.public_key
237
+ });
238
+ }
261
239
  }, [
262
240
  preOrder.wallet_method,
263
241
  preOrder.token,
264
- currentAmount, // Use memoized amount instead of preOrder.total_amount
265
242
  walletPaymentData?.data?.public_key
266
243
  ]);
267
244
 
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
+
268
264
  // Cleanup function when component unmounts
269
265
  useEffect(() => {
270
266
  return () => {
@@ -280,20 +276,5 @@ export default function FlowPayment({
280
276
  };
281
277
  }, []);
282
278
 
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
- );
279
+ return <div id="flow-container" className="flow-payment-container"></div>;
299
280
  }