@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 +19 -0
- package/components/index.ts +2 -0
- package/components/link.tsx +52 -0
- package/components/pagination.tsx +194 -0
- package/components/plugin-module.tsx +40 -6
- package/components/selected-payment-option-view.tsx +4 -0
- package/data/client/account.ts +5 -2
- package/data/client/checkout.ts +153 -13
- package/data/urls.ts +6 -2
- package/hooks/index.ts +1 -0
- package/hooks/use-pagination.ts +136 -0
- package/hooks/use-payment-options.ts +1 -0
- package/middlewares/complete-masterpass.ts +159 -0
- package/middlewares/default.ts +105 -93
- package/middlewares/index.ts +3 -1
- package/package.json +2 -2
- package/plugins.d.ts +3 -0
- package/plugins.js +2 -0
- package/redux/reducers/index.ts +6 -2
- package/types/commerce/checkout.ts +1 -0
- package/types/commerce/product.ts +2 -2
- package/utils/get-currency-label.ts +9 -0
- package/utils/get-currency.ts +4 -2
- package/utils/index.ts +1 -0
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
|
package/components/index.ts
CHANGED
|
@@ -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><</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>></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
|
|
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`);
|
package/data/client/account.ts
CHANGED
|
@@ -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(
|
|
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)
|
package/data/client/checkout.ts
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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