@akinon/next 1.17.1 → 1.19.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 CHANGED
@@ -1,5 +1,24 @@
1
1
  # @akinon/next
2
2
 
3
+ ## 1.19.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 846e3200: ZERO-2287: Add pz-masterpass plugin
8
+
9
+ ## 1.18.0
10
+
11
+ ### Minor Changes
12
+
13
+ - db017b2c: ZERO-2271: Fix showing currency code instead of label
14
+ - db017b2c: ZERO-2389: Show card logo in credit card form
15
+ - db017b2c: ZERO-2387: Add sorting by date in orders page
16
+ - db017b2c: ZERO-2377: Add B2B plugin
17
+
18
+ ### Patch Changes
19
+
20
+ - db017b2c: ZERO-2417: Update basket_offers type in Product interface
21
+
3
22
  ## 1.17.1
4
23
 
5
24
  ## 1.17.0
@@ -16,3 +16,5 @@ export * from './radio';
16
16
  export * from './react-portal';
17
17
  export * from './selected-payment-option-view';
18
18
  export * from './trans';
19
+ export * from './link';
20
+ export * from './pagination';
@@ -0,0 +1,52 @@
1
+ 'use client';
2
+
3
+ import { useLocalization } from '@akinon/next/hooks';
4
+ import { LocaleUrlStrategy } from '@akinon/next/localization';
5
+ import { urlLocaleMatcherRegex } from '@akinon/next/utils';
6
+ import NextLink, { LinkProps as NextLinkProps } from 'next/link';
7
+ import { useEffect, useState } from 'react';
8
+
9
+ interface LinkProps extends NextLinkProps {
10
+ children: React.ReactNode;
11
+ className?: string;
12
+ target?: '_blank' | '_self' | '_parent' | '_top';
13
+ }
14
+
15
+ export const Link = ({
16
+ children,
17
+ target,
18
+ className,
19
+ href,
20
+ ...rest
21
+ }: LinkProps) => {
22
+ const { locale, defaultLocaleValue, localeUrlStrategy } = useLocalization();
23
+ const [formattedHref, setFormattedHref] = useState(href ?? '#');
24
+
25
+ useEffect(() => {
26
+ if (typeof href !== 'string') return;
27
+ if (href.startsWith('http')) return;
28
+
29
+ const pathnameWithoutLocale = href.replace(urlLocaleMatcherRegex, '');
30
+ const hrefWithLocale = `/${locale}${pathnameWithoutLocale}`;
31
+
32
+ if (localeUrlStrategy === LocaleUrlStrategy.ShowAllLocales) {
33
+ setFormattedHref(hrefWithLocale);
34
+ } else if (
35
+ localeUrlStrategy === LocaleUrlStrategy.HideDefaultLocale &&
36
+ locale !== defaultLocaleValue
37
+ ) {
38
+ setFormattedHref(hrefWithLocale);
39
+ }
40
+ }, [href, defaultLocaleValue, locale, localeUrlStrategy]);
41
+
42
+ return (
43
+ <NextLink
44
+ href={formattedHref}
45
+ target={target}
46
+ className={className}
47
+ {...rest}
48
+ >
49
+ {children}
50
+ </NextLink>
51
+ );
52
+ };
@@ -0,0 +1,194 @@
1
+ 'use client';
2
+
3
+ import { MouseEvent, useCallback, useEffect, useState } from 'react';
4
+ import { PaginationProps } from '@theme/components/types';
5
+ import { twMerge } from 'tailwind-merge';
6
+ import clsx from 'clsx';
7
+
8
+ import usePagination from '@akinon/next/hooks/use-pagination';
9
+ import { useLocalization } from '@akinon/next/hooks';
10
+ import { useRouter } from '@akinon/next/hooks';
11
+ import { Link } from './link';
12
+
13
+ export const Pagination = (props: PaginationProps) => {
14
+ const { t } = useLocalization();
15
+ const router = useRouter();
16
+ const {
17
+ total,
18
+ limit,
19
+ currentPage,
20
+ numberOfPages,
21
+ containerClassName,
22
+ prevClassName,
23
+ pageClassName,
24
+ nextClassName,
25
+ threshold = 1,
26
+ render
27
+ } = props;
28
+
29
+ const pagination = usePagination(total, limit, currentPage, numberOfPages);
30
+ const {
31
+ total: paginationTotal,
32
+ limit: paginationLimit,
33
+ page,
34
+ pageList,
35
+ prev,
36
+ next,
37
+ setTotal,
38
+ setLimit
39
+ } = pagination;
40
+
41
+ const [paginationItems, setPaginationItems] = useState([]);
42
+ const showNext = currentPage * paginationLimit < total;
43
+
44
+ const createListItems = useCallback(() => {
45
+ setPaginationItems([]);
46
+ const delta = 2;
47
+ const startPage = Math.max(Number(page) - delta, 1);
48
+ const endPage = Math.min(Number(page) + delta, numberOfPages);
49
+
50
+ setPaginationItems((prev) => [
51
+ ...prev,
52
+ {
53
+ page: pageList[0].page,
54
+ url: pageList[0].url
55
+ }
56
+ ]);
57
+
58
+ if (delta < startPage) {
59
+ setPaginationItems((prev) => [...prev, { page: '...', url: '#' }]);
60
+ }
61
+
62
+ for (let i = startPage; i <= endPage; i++) {
63
+ if (i === 1) continue;
64
+
65
+ setPaginationItems((prev) => [
66
+ ...prev,
67
+ {
68
+ page: pageList[i - 1]?.page,
69
+ url: pageList[i - 1]?.url
70
+ }
71
+ ]);
72
+ }
73
+
74
+ if (endPage < numberOfPages - threshold) {
75
+ setPaginationItems((prev) => [...prev, { page: '...', url: '#' }]);
76
+ }
77
+
78
+ if (page < numberOfPages - delta) {
79
+ setPaginationItems((prev) => [
80
+ ...prev,
81
+ {
82
+ page: pageList[pageList.length - threshold].page,
83
+ url: pageList[pageList.length - threshold].url
84
+ }
85
+ ]);
86
+ }
87
+ }, [numberOfPages, page, pageList, threshold]);
88
+
89
+ const handleClick = (e: MouseEvent<HTMLAnchorElement>, url: string) => {
90
+ e.preventDefault();
91
+
92
+ const newUrl = new URL(url, window.location.origin);
93
+ const page = newUrl.searchParams.get('page');
94
+
95
+ if (page === '1') {
96
+ newUrl.searchParams.delete('page');
97
+ }
98
+
99
+ router.push(newUrl.pathname + newUrl.search, undefined);
100
+ };
101
+
102
+ useEffect(() => {
103
+ createListItems();
104
+ }, [createListItems, page]);
105
+
106
+ useEffect(() => {
107
+ if (total && total !== paginationTotal) {
108
+ setTotal(total);
109
+ }
110
+ }, [total, paginationTotal, setTotal]);
111
+
112
+ useEffect(() => {
113
+ if (limit && limit !== paginationLimit) {
114
+ setLimit(limit);
115
+ }
116
+ }, [limit, paginationLimit, setLimit]);
117
+
118
+ if (render) {
119
+ return <>{render(pagination)}</>;
120
+ }
121
+
122
+ return (
123
+ <ul
124
+ className={twMerge(
125
+ 'flex mt-8 mb-4 justify-center items-center',
126
+ containerClassName
127
+ )}
128
+ >
129
+ {prev && (
130
+ <li>
131
+ <Link
132
+ onClick={(e) => handleClick(e, prev)}
133
+ href={prev}
134
+ className={twMerge(
135
+ 'flex cursor-pointer text-sm px-2',
136
+ prevClassName
137
+ )}
138
+ >
139
+ <span>&lt;</span>
140
+ <span className="hidden lg:inline-block ms-4">
141
+ {t('category.pagination.previous')}
142
+ </span>
143
+ </Link>
144
+ </li>
145
+ )}
146
+
147
+ {paginationItems &&
148
+ paginationItems?.map((item, i) => (
149
+ <li key={i}>
150
+ {item?.url != '#' ? (
151
+ <Link
152
+ onClick={(e) => handleClick(e, item.url)}
153
+ href={item.url}
154
+ className={twMerge(
155
+ clsx(
156
+ 'text-xs px-2 cursor-pointer',
157
+ { 'pointer-events-none': item.url === null },
158
+ Number(page) === Number(item?.page)
159
+ ? 'font-semibold text-black-800'
160
+ : 'text-gray-400'
161
+ ),
162
+ pageClassName
163
+ )}
164
+ >
165
+ {item?.page}
166
+ </Link>
167
+ ) : (
168
+ <span className="cursor-default text-xs flex items-center justify-center">
169
+ {item?.page}
170
+ </span>
171
+ )}
172
+ </li>
173
+ ))}
174
+
175
+ {showNext && (
176
+ <li>
177
+ <Link
178
+ onClick={(e) => handleClick(e, next)}
179
+ href={next}
180
+ className={twMerge(
181
+ 'flex cursor-pointer text-xs px-2',
182
+ nextClassName
183
+ )}
184
+ >
185
+ <span className="hidden lg:inline-block me-4">
186
+ {t('category.pagination.next')}
187
+ </span>
188
+ <span>&gt;</span>
189
+ </Link>
190
+ </li>
191
+ )}
192
+ </ul>
193
+ );
194
+ };
@@ -1,3 +1,5 @@
1
+ 'use client';
2
+
1
3
  import dynamic from 'next/dynamic';
2
4
  import plugins from 'plugins';
3
5
  import logger from '../utils/log';
@@ -12,7 +14,9 @@ enum Plugin {
12
14
  GPay = 'pz-gpay',
13
15
  Otp = 'pz-otp',
14
16
  BKMExpress = 'pz-bkm',
15
- CreditPayment = 'pz-credit-payment'
17
+ CreditPayment = 'pz-credit-payment',
18
+ Masterpass = 'pz-masterpass',
19
+ B2B = 'pz-b2b'
16
20
  }
17
21
 
18
22
  export enum Component {
@@ -24,7 +28,15 @@ export enum Component {
24
28
  GPay = 'GPayOption',
25
29
  Otp = 'Otp',
26
30
  BKMExpress = 'BKMOption',
27
- CreditPayment = 'CreditPayment'
31
+ CreditPayment = 'CreditPayment',
32
+ MasterpassProvider = 'MasterpassProvider',
33
+ MasterpassCardList = 'MasterpassCardList',
34
+ MasterpassCardRegistration = 'MasterpassCardRegistration',
35
+ MasterpassDeleteConfirmationModal = 'MasterpassDeleteConfirmationModal',
36
+ MasterpassOtpModal = 'MasterpassOtpModal',
37
+ MasterpassLinkModal = 'MasterpassLinkModal',
38
+ MyQuotationsB2B = 'AccountMyQuotations',
39
+ BasketB2B = 'BasketB2b'
28
40
  }
29
41
 
30
42
  const PluginComponents = new Map([
@@ -36,7 +48,19 @@ const PluginComponents = new Map([
36
48
  [Plugin.GPay, [Component.GPay]],
37
49
  [Plugin.Otp, [Component.Otp]],
38
50
  [Plugin.BKMExpress, [Component.BKMExpress]],
39
- [Plugin.CreditPayment, [Component.CreditPayment]]
51
+ [Plugin.CreditPayment, [Component.CreditPayment]],
52
+ [
53
+ Plugin.Masterpass,
54
+ [
55
+ Component.MasterpassCardList,
56
+ Component.MasterpassProvider,
57
+ Component.MasterpassCardRegistration,
58
+ Component.MasterpassDeleteConfirmationModal,
59
+ Component.MasterpassOtpModal,
60
+ Component.MasterpassLinkModal
61
+ ]
62
+ ],
63
+ [Plugin.B2B, [Component.MyQuotationsB2B, Component.BasketB2B]]
40
64
  ]);
41
65
 
42
66
  const getPlugin = (component: Component) => {
@@ -49,10 +73,12 @@ const getPlugin = (component: Component) => {
49
73
 
50
74
  export default function PluginModule({
51
75
  component,
52
- props
76
+ props,
77
+ children
53
78
  }: {
54
79
  component: Component;
55
80
  props?: any;
81
+ children?: React.ReactNode;
56
82
  }) {
57
83
  const plugin = getPlugin(component);
58
84
 
@@ -81,6 +107,10 @@ export default function PluginModule({
81
107
  promise = import(`${'@akinon/pz-bkm'}`);
82
108
  } else if (plugin === Plugin.CreditPayment) {
83
109
  promise = import(`${'@akinon/pz-credit-payment'}`);
110
+ } else if (plugin === Plugin.Masterpass) {
111
+ promise = import(`${'@akinon/pz-masterpass'}`);
112
+ } else if (plugin === Plugin.B2B) {
113
+ promise = import(`${'@akinon/pz-b2b'}`);
84
114
  }
85
115
  } catch (error) {
86
116
  logger.error(error);
@@ -92,11 +122,15 @@ export default function PluginModule({
92
122
  },
93
123
  { ssr: false }
94
124
  ),
95
- [plugin]
125
+ [plugin, component]
96
126
  );
97
127
 
98
128
  if (!(plugins as string[]).includes(plugin)) {
99
- return null;
129
+ return <>{children}</>;
130
+ }
131
+
132
+ if (children) {
133
+ return <Component {...props}>{children}</Component>;
100
134
  }
101
135
 
102
136
  return <Component {...props} />;
@@ -50,6 +50,10 @@ export default function SelectedPaymentOptionView() {
50
50
  );
51
51
  } else if (payment_option.payment_type === 'loyalty_money') {
52
52
  promise = import(`views/checkout/steps/payment/options/loyalty`);
53
+ } else if (payment_option.payment_type === 'masterpass') {
54
+ promise = import(
55
+ `views/checkout/steps/payment/options/credit-card`
56
+ );
53
57
  }
54
58
  // else if (payment_option.payment_type === 'credit_payment') {
55
59
  // promise = import(`views/checkout/steps/payment/options/credit-payment`);
@@ -20,6 +20,7 @@ interface GetOrdersParams {
20
20
  limit?: number;
21
21
  page?: number;
22
22
  createdDate?: string;
23
+ endDate?: string;
23
24
  }
24
25
 
25
26
  export interface GetQuotationsResponse {
@@ -105,8 +106,10 @@ const accountApi = api.injectEndpoints({
105
106
  query: (id) => buildClientRequestUrl(account.orderId(id))
106
107
  }),
107
108
  getOrders: builder.query<GetOrdersResponse, GetOrdersParams>({
108
- query: ({ page, limit, createdDate } = {}) =>
109
- buildClientRequestUrl(account.getOrders({ page, limit, createdDate }))
109
+ query: ({ page, limit, createdDate, endDate } = {}) =>
110
+ buildClientRequestUrl(
111
+ account.getOrders({ page, limit, createdDate, endDate })
112
+ )
110
113
  }),
111
114
  getQuotations: builder.query<GetQuotationsResponse, void>({
112
115
  query: () => buildClientRequestUrl(account.getQuotations)
@@ -4,7 +4,8 @@ import {
4
4
  setPaymentStepBusy,
5
5
  setSelectedBankAccountPk,
6
6
  setSelectedCreditPaymentPk,
7
- setShippingStepBusy
7
+ setShippingStepBusy,
8
+ setCardType
8
9
  } from '../../redux/reducers/checkout';
9
10
  import {
10
11
  CheckoutContext,
@@ -15,7 +16,17 @@ import {
15
16
  import { buildClientRequestUrl } from '../../utils';
16
17
  import { api } from './api';
17
18
  import { checkout } from '../urls';
18
- import { store } from 'redux/store';
19
+ import { AppDispatch, AppStore, store } from 'redux/store';
20
+ import settings from '@theme/settings';
21
+ import { showMobile3dIframe } from '../../utils/mobile-3d-iframe';
22
+ import {
23
+ setError,
24
+ setOtpModalVisible
25
+ } from '@akinon/pz-masterpass/src/redux/reducer';
26
+ import {
27
+ buildDirectPurchaseForm,
28
+ buildPurchaseForm
29
+ } from '@akinon/pz-masterpass/src/utils';
19
30
 
20
31
  interface CheckoutResponse {
21
32
  pre_order?: PreOrder;
@@ -37,7 +48,7 @@ interface SetRetailStoreParams {
37
48
  billingAddressPk: number;
38
49
  }
39
50
 
40
- interface CompleteCreditCardParams {
51
+ export interface CompleteCreditCardParams {
41
52
  card_holder: string;
42
53
  card_cvv: string;
43
54
  card_number: string;
@@ -65,6 +76,83 @@ export interface PayOnDeliveryParams {
65
76
  paymentType: string;
66
77
  }
67
78
 
79
+ const completeMasterpassPayment = async (
80
+ params: CompleteCreditCardParams,
81
+ dispatch: AppDispatch,
82
+ context: CheckoutContext,
83
+ reduxStore: AppStore
84
+ ) => {
85
+ const state = reduxStore.getState();
86
+ const { token, order_no } = context.page_context;
87
+ const { endpoints: apiEndpoints } = checkoutApi;
88
+ const { preOrder } = state.checkout ?? {};
89
+
90
+ const { isDirectPurchase, referenceNo, credentials, msisdn, selectedCard } =
91
+ state.masterpass ?? {};
92
+
93
+ const commonFormValues = {
94
+ token,
95
+ orderNo: order_no,
96
+ referenceNo,
97
+ merchantId: credentials?.merchant_id ?? null,
98
+ msisdn,
99
+ amount: preOrder?.unpaid_amount?.replace('.', '') ?? ''
100
+ };
101
+
102
+ const form = isDirectPurchase
103
+ ? await buildDirectPurchaseForm(commonFormValues, params)
104
+ : await buildPurchaseForm({ ...commonFormValues, selectedCard });
105
+
106
+ window.MFS?.[
107
+ state.masterpass.isDirectPurchase ? 'directPurchase' : 'purchase'
108
+ ]($(form), async (statusCode, response) => {
109
+ if (response.responseCode == '5009') {
110
+ // TODO: Handle Digital Loan
111
+ }
112
+
113
+ if (response.responseCode == '5010') {
114
+ const { isMobileApp } = state.root;
115
+ const returnUrl = state.masterpass.credentials?.s3d_return_url;
116
+ const url =
117
+ response.url3D + '&returnUrl=' + encodeURIComponent(returnUrl);
118
+ const urlObj = new URL(url, window.location.origin);
119
+ urlObj.searchParams.set('t', new Date().getTime().toString());
120
+
121
+ if (
122
+ (isMobileApp ||
123
+ /iPad|iPhone|iPod|Android/i.test(navigator.userAgent)) &&
124
+ !settings.checkout?.iframeExcludedPaymentOptions?.includes(
125
+ preOrder?.payment_option?.slug
126
+ )
127
+ ) {
128
+ showMobile3dIframe(urlObj.toString());
129
+ } else {
130
+ window.location.href = urlObj.toString();
131
+ }
132
+
133
+ return;
134
+ }
135
+
136
+ if (response.responseCode == '5001') {
137
+ dispatch(setOtpModalVisible(true));
138
+ return;
139
+ }
140
+
141
+ if (
142
+ response.token &&
143
+ (response.responseCode == '0000' || response.responseCode == '')
144
+ ) {
145
+ dispatch(
146
+ apiEndpoints.completeMasterpassPayment.initiate({ token }) as any
147
+ );
148
+ }
149
+
150
+ if (response.responseDescription.length) {
151
+ dispatch(setError(response.responseDescription));
152
+ }
153
+ });
154
+ };
155
+
68
156
  export const checkoutApi = api.injectEndpoints({
69
157
  endpoints: (build) => ({
70
158
  fetchCheckout: build.query<CheckoutResponse, void>({
@@ -100,19 +188,69 @@ export const checkoutApi = api.injectEndpoints({
100
188
  card_month,
101
189
  card_year,
102
190
  use_three_d = true
103
- }) => ({
104
- url: buildClientRequestUrl(checkout.completeCreditCardPayment, {
191
+ }) => {
192
+ const paymentOption =
193
+ store.getState().checkout?.preOrder?.payment_option;
194
+
195
+ if (paymentOption?.payment_type === 'masterpass') {
196
+ return {
197
+ url: buildClientRequestUrl(checkout.getMasterpassOrderNo, {
198
+ useFormData: true
199
+ }),
200
+ method: 'POST'
201
+ };
202
+ }
203
+
204
+ return {
205
+ url: buildClientRequestUrl(checkout.completeCreditCardPayment, {
206
+ useFormData: true
207
+ }),
208
+ method: 'POST',
209
+ body: {
210
+ agreement: '1',
211
+ use_three_d: use_three_d ? '1' : '0',
212
+ card_cvv,
213
+ card_holder,
214
+ card_month,
215
+ card_number,
216
+ card_year
217
+ }
218
+ };
219
+ },
220
+ async onQueryStarted(args, { dispatch, queryFulfilled }) {
221
+ dispatch(setPaymentStepBusy(true));
222
+ const { data } = await queryFulfilled;
223
+ const reduxStore = (await import('redux/store')).store;
224
+ const completePaymentContext = data?.context_list?.find(
225
+ (context) => context?.page_name === 'MasterpassCompletePage'
226
+ );
227
+
228
+ if (completePaymentContext) {
229
+ await completeMasterpassPayment(
230
+ args,
231
+ dispatch,
232
+ completePaymentContext,
233
+ reduxStore
234
+ );
235
+ }
236
+
237
+ dispatch(setPaymentStepBusy(false));
238
+ },
239
+ invalidatesTags: ['Basket']
240
+ }),
241
+ completeMasterpassPayment: build.mutation<
242
+ CheckoutResponse,
243
+ {
244
+ token: string;
245
+ }
246
+ >({
247
+ query: ({ token }) => ({
248
+ url: buildClientRequestUrl(checkout.completeMasterpassPayment, {
105
249
  useFormData: true
106
250
  }),
107
251
  method: 'POST',
108
252
  body: {
109
- agreement: '1',
110
- use_three_d: use_three_d ? '1' : '0',
111
- card_cvv,
112
- card_holder,
113
- card_month,
114
- card_number,
115
- card_year
253
+ token
116
254
  }
117
255
  }),
118
256
  async onQueryStarted(arg, { dispatch, queryFulfilled }) {
@@ -231,6 +369,7 @@ export const checkoutApi = api.injectEndpoints({
231
369
  dispatch(setInstallmentOptions([]));
232
370
  dispatch(setBankAccounts([]));
233
371
  dispatch(setSelectedBankAccountPk(null));
372
+ dispatch(setCardType(null));
234
373
  await queryFulfilled;
235
374
  dispatch(setPaymentStepBusy(false));
236
375
  }
@@ -256,6 +395,7 @@ export const checkoutApi = api.injectEndpoints({
256
395
  },
257
396
  async onQueryStarted(arg, { dispatch, queryFulfilled }) {
258
397
  dispatch(setPaymentStepBusy(true));
398
+ dispatch(setCardType(arg));
259
399
  await queryFulfilled;
260
400
  dispatch(setPaymentStepBusy(false));
261
401
  }
@@ -325,7 +465,7 @@ export const checkoutApi = api.injectEndpoints({
325
465
  }),
326
466
  method: 'POST',
327
467
  body: {
328
- agreement: true,
468
+ agreement: true
329
469
  }
330
470
  }),
331
471
  async onQueryStarted(arg, { dispatch, queryFulfilled }) {
package/data/urls.ts CHANGED
@@ -16,15 +16,17 @@ export const account = {
16
16
  getOrders: ({
17
17
  page,
18
18
  limit,
19
- createdDate
19
+ createdDate,
20
+ endDate
20
21
  }: {
21
22
  page?: number;
22
23
  limit?: number;
23
24
  createdDate?: string;
25
+ endDate?: string;
24
26
  }) =>
25
27
  `/users/orders/?page=${page || 1}&limit=${limit || 12} ${
26
28
  createdDate ? `&created_date__gte=${createdDate}` : ''
27
- }`,
29
+ } ${endDate ? `&created_date__lte=${endDate}` : ''}`,
28
30
  getQuotations: '/b2b/my-quotations',
29
31
  sendContact: '/users/contact-us',
30
32
  passwordReset: (slug: string) => `/users/reset/${slug}`,
@@ -77,6 +79,8 @@ export const checkout = {
77
79
  setPaymentOption: '/orders/checkout/?page=PaymentOptionSelectionPage',
78
80
  setBinNumber: '/orders/checkout/?page=BinNumberPage',
79
81
  setMasterpassBinNumber: '/orders/checkout/?page=MasterpassBinNumberPage',
82
+ getMasterpassOrderNo: '/orders/checkout/?page=MasterpassOrderNoPage',
83
+ completeMasterpassPayment: '/orders/checkout/?page=MasterpassCompletePage',
80
84
  setInstallmentOption: '/orders/checkout/?page=InstallmentSelectionPage',
81
85
  setMasterPassInstallmentOption:
82
86
  '/orders/checkout/?page=MasterpassInstallmentPage',
package/hooks/index.ts CHANGED
@@ -8,3 +8,4 @@ export * from './use-media-query';
8
8
  export * from './use-on-click-outside';
9
9
  export * from './use-mobile-iframe-handler';
10
10
  export * from './use-payment-options';
11
+ export * from './use-pagination';