@akinon/pz-masterpass 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/.prettierrc +13 -0
- package/CHANGELOG.md +7 -0
- package/README.md +122 -0
- package/assets/img/mp_amex.jpg +0 -0
- package/assets/img/mp_mastercard.png +0 -0
- package/assets/img/mp_masterpass-logo.png +0 -0
- package/assets/img/mp_other.png +0 -0
- package/assets/img/mp_troy.png +0 -0
- package/assets/img/mp_visa.png +0 -0
- package/assets/mfs-client.min.js +3 -0
- package/assets/zepto.min.js +2 -0
- package/package.json +18 -0
- package/src/hooks/use-cards.ts +51 -0
- package/src/hooks/use-countdown.ts +28 -0
- package/src/hooks/use-delete-card.tsx +88 -0
- package/src/index.d.ts +3 -0
- package/src/index.ts +17 -0
- package/src/masterpass-provider.tsx +141 -0
- package/src/redux/reducer.ts +126 -0
- package/src/types/index.ts +111 -0
- package/src/utils/check-masterpass.ts +66 -0
- package/src/utils/get-masterpass-cards.ts +32 -0
- package/src/utils/index.ts +177 -0
- package/src/utils/init.ts +17 -0
- package/src/views/card-list/index.tsx +166 -0
- package/src/views/card-registration/index.tsx +250 -0
- package/src/views/countdown-timer/countdown-timer.tsx +43 -0
- package/src/views/delete-confirmation-modal/index.tsx +64 -0
- package/src/views/info-modal/index.tsx +102 -0
- package/src/views/link-modal/index.tsx +135 -0
- package/src/views/otp-modal/index.tsx +148 -0
- package/src/views/otp-modal/otp-form.tsx +86 -0
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { useLocalization } from '@akinon/next/hooks';
|
|
4
|
+
import { useAppDispatch, useAppSelector } from '@akinon/next/redux/hooks';
|
|
5
|
+
import Script from 'next/script';
|
|
6
|
+
import { useEffect } from 'react';
|
|
7
|
+
import { checkMasterpass } from './utils/check-masterpass';
|
|
8
|
+
import { init } from './utils/init';
|
|
9
|
+
import {
|
|
10
|
+
setAccountStatus,
|
|
11
|
+
setCredentials,
|
|
12
|
+
setError,
|
|
13
|
+
setIsDirectPurchase,
|
|
14
|
+
setLanguage,
|
|
15
|
+
setMsisdn,
|
|
16
|
+
setReferenceNo,
|
|
17
|
+
setToken
|
|
18
|
+
} from './redux/reducer';
|
|
19
|
+
import { MasterpassStatus } from './types';
|
|
20
|
+
import { Image, Modal } from '@akinon/next/components';
|
|
21
|
+
import masterpassLogo from '../assets/img/mp_masterpass-logo.png';
|
|
22
|
+
import { checkoutApi } from '@akinon/next/data/client/checkout';
|
|
23
|
+
|
|
24
|
+
interface MasterpassProviderProps {
|
|
25
|
+
children: React.ReactNode;
|
|
26
|
+
translations?: {
|
|
27
|
+
genericErrorMessage?: string;
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const getLanguage = (locale: string) => {
|
|
32
|
+
switch (locale) {
|
|
33
|
+
case 'en':
|
|
34
|
+
return 'eng';
|
|
35
|
+
case 'tr':
|
|
36
|
+
return 'tur';
|
|
37
|
+
default:
|
|
38
|
+
return 'eng';
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export const MasterpassProvider = (props: MasterpassProviderProps) => {
|
|
43
|
+
const { children } = props;
|
|
44
|
+
const { preOrder } = useAppSelector((state) => state.checkout);
|
|
45
|
+
const { otp, error } = useAppSelector((state) => state.masterpass);
|
|
46
|
+
const { locale } = useLocalization();
|
|
47
|
+
const dispatch = useAppDispatch();
|
|
48
|
+
|
|
49
|
+
const prepareState = async () => {
|
|
50
|
+
dispatch(setLanguage(getLanguage(locale)));
|
|
51
|
+
|
|
52
|
+
const data = await init();
|
|
53
|
+
|
|
54
|
+
if (!data) {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
dispatch(setCredentials(data));
|
|
59
|
+
|
|
60
|
+
const { status, response, msisdn, token, referenceNo } =
|
|
61
|
+
await checkMasterpass();
|
|
62
|
+
|
|
63
|
+
if (status !== 200) {
|
|
64
|
+
dispatch(
|
|
65
|
+
setError(
|
|
66
|
+
props.translations?.genericErrorMessage ??
|
|
67
|
+
'An error occurred while initializing Masterpass.'
|
|
68
|
+
)
|
|
69
|
+
);
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const accountStatus = response.accountStatus.substring(
|
|
74
|
+
0,
|
|
75
|
+
6
|
|
76
|
+
) as MasterpassStatus;
|
|
77
|
+
|
|
78
|
+
dispatch(setToken(token));
|
|
79
|
+
dispatch(setMsisdn(msisdn));
|
|
80
|
+
dispatch(setReferenceNo(referenceNo));
|
|
81
|
+
dispatch(setAccountStatus(accountStatus));
|
|
82
|
+
|
|
83
|
+
if (accountStatus === MasterpassStatus.ListCards) {
|
|
84
|
+
dispatch(setIsDirectPurchase(false));
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
useEffect(() => {
|
|
89
|
+
if (preOrder?.payment_option?.payment_type !== 'masterpass') {
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
prepareState();
|
|
94
|
+
}, [preOrder?.payment_option?.payment_type]);
|
|
95
|
+
|
|
96
|
+
useEffect(() => {
|
|
97
|
+
if (!otp.response) {
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (
|
|
102
|
+
otp.response.token &&
|
|
103
|
+
(otp.response.responseCode === '0000' || otp.response.responseCode === '')
|
|
104
|
+
) {
|
|
105
|
+
dispatch(
|
|
106
|
+
checkoutApi.endpoints.completeMasterpassPayment.initiate({
|
|
107
|
+
token: otp.response.token
|
|
108
|
+
}) as any
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
}, [otp.response]);
|
|
112
|
+
|
|
113
|
+
if (preOrder?.payment_option?.payment_type !== 'masterpass') {
|
|
114
|
+
return <>{children}</>;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return (
|
|
118
|
+
<>
|
|
119
|
+
<Script src="/mfs-client.min.js" strategy="afterInteractive" />
|
|
120
|
+
<Script src="/zepto.min.js" strategy="afterInteractive" />
|
|
121
|
+
|
|
122
|
+
<Modal
|
|
123
|
+
portalId="masterpass-error-modal"
|
|
124
|
+
title={
|
|
125
|
+
<Image
|
|
126
|
+
width={140}
|
|
127
|
+
height={25}
|
|
128
|
+
src={masterpassLogo.src}
|
|
129
|
+
alt="Masterpass Logo"
|
|
130
|
+
/>
|
|
131
|
+
}
|
|
132
|
+
open={!!error}
|
|
133
|
+
setOpen={() => dispatch(setError(undefined))}
|
|
134
|
+
>
|
|
135
|
+
<div className="p-6">{error}</div>
|
|
136
|
+
</Modal>
|
|
137
|
+
|
|
138
|
+
{children}
|
|
139
|
+
</>
|
|
140
|
+
);
|
|
141
|
+
};
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { createSlice, PayloadAction } from '@reduxjs/toolkit';
|
|
2
|
+
import {
|
|
3
|
+
MasterpassCredentials,
|
|
4
|
+
MasterpassResponse,
|
|
5
|
+
MasterpassResponseCardType,
|
|
6
|
+
MasterpassStatus
|
|
7
|
+
} from '../types';
|
|
8
|
+
|
|
9
|
+
export interface MasterpassState {
|
|
10
|
+
error?: string;
|
|
11
|
+
token?: string;
|
|
12
|
+
msisdn?: string;
|
|
13
|
+
referenceNo?: string;
|
|
14
|
+
language: string;
|
|
15
|
+
credentials?: MasterpassCredentials;
|
|
16
|
+
accountStatus?: MasterpassStatus;
|
|
17
|
+
cards: MasterpassResponseCardType[];
|
|
18
|
+
selectedCard?: MasterpassResponseCardType;
|
|
19
|
+
isDirectPurchase?: boolean;
|
|
20
|
+
otp: {
|
|
21
|
+
isModalVisible: boolean;
|
|
22
|
+
modalTitle?: string;
|
|
23
|
+
response?: MasterpassResponse;
|
|
24
|
+
};
|
|
25
|
+
deletion: {
|
|
26
|
+
isModalVisible: boolean;
|
|
27
|
+
cardAliasName?: string;
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const initialState: MasterpassState = {
|
|
32
|
+
language: 'eng',
|
|
33
|
+
cards: [],
|
|
34
|
+
otp: {
|
|
35
|
+
isModalVisible: false
|
|
36
|
+
},
|
|
37
|
+
isDirectPurchase: true,
|
|
38
|
+
deletion: {
|
|
39
|
+
isModalVisible: false
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
const rootSlice = createSlice({
|
|
44
|
+
name: 'masterpass',
|
|
45
|
+
initialState,
|
|
46
|
+
reducers: {
|
|
47
|
+
setError: (state, { payload }: PayloadAction<string>) => {
|
|
48
|
+
state.error = payload;
|
|
49
|
+
},
|
|
50
|
+
setToken: (state, { payload }: PayloadAction<string>) => {
|
|
51
|
+
state.token = payload;
|
|
52
|
+
},
|
|
53
|
+
setMsisdn: (state, { payload }: PayloadAction<string>) => {
|
|
54
|
+
state.msisdn = payload;
|
|
55
|
+
},
|
|
56
|
+
setReferenceNo: (state, { payload }: PayloadAction<string>) => {
|
|
57
|
+
state.referenceNo = payload;
|
|
58
|
+
},
|
|
59
|
+
setLanguage: (state, { payload }: PayloadAction<string>) => {
|
|
60
|
+
state.language = payload;
|
|
61
|
+
},
|
|
62
|
+
setCredentials: (
|
|
63
|
+
state,
|
|
64
|
+
{ payload }: PayloadAction<MasterpassCredentials>
|
|
65
|
+
) => {
|
|
66
|
+
state.credentials = payload;
|
|
67
|
+
},
|
|
68
|
+
setAccountStatus: (state, { payload }: PayloadAction<MasterpassStatus>) => {
|
|
69
|
+
state.accountStatus = payload;
|
|
70
|
+
},
|
|
71
|
+
setCards: (
|
|
72
|
+
state,
|
|
73
|
+
{ payload }: PayloadAction<MasterpassResponseCardType[]>
|
|
74
|
+
) => {
|
|
75
|
+
state.cards = payload;
|
|
76
|
+
},
|
|
77
|
+
setSelectedCard: (
|
|
78
|
+
state,
|
|
79
|
+
{ payload }: PayloadAction<MasterpassResponseCardType>
|
|
80
|
+
) => {
|
|
81
|
+
state.selectedCard = payload;
|
|
82
|
+
},
|
|
83
|
+
setIsDirectPurchase: (state, { payload }: PayloadAction<boolean>) => {
|
|
84
|
+
state.isDirectPurchase = payload;
|
|
85
|
+
|
|
86
|
+
if (payload) {
|
|
87
|
+
state.selectedCard = undefined;
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
setOtpModalVisible: (state, { payload }: PayloadAction<boolean>) => {
|
|
91
|
+
state.otp.isModalVisible = payload;
|
|
92
|
+
},
|
|
93
|
+
setOtpModalTitle: (state, { payload }: PayloadAction<string>) => {
|
|
94
|
+
state.otp.modalTitle = payload;
|
|
95
|
+
},
|
|
96
|
+
setOtpResponse: (state, { payload }: PayloadAction<MasterpassResponse>) => {
|
|
97
|
+
state.otp.response = payload;
|
|
98
|
+
},
|
|
99
|
+
setDeletionModalVisible: (state, { payload }: PayloadAction<boolean>) => {
|
|
100
|
+
state.deletion.isModalVisible = payload;
|
|
101
|
+
},
|
|
102
|
+
setDeletionCardAliasName: (state, { payload }: PayloadAction<string>) => {
|
|
103
|
+
state.deletion.cardAliasName = payload;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
export const {
|
|
109
|
+
setError,
|
|
110
|
+
setToken,
|
|
111
|
+
setMsisdn,
|
|
112
|
+
setReferenceNo,
|
|
113
|
+
setLanguage,
|
|
114
|
+
setCredentials,
|
|
115
|
+
setAccountStatus,
|
|
116
|
+
setCards,
|
|
117
|
+
setSelectedCard,
|
|
118
|
+
setIsDirectPurchase,
|
|
119
|
+
setOtpModalVisible,
|
|
120
|
+
setOtpModalTitle,
|
|
121
|
+
setOtpResponse,
|
|
122
|
+
setDeletionModalVisible,
|
|
123
|
+
setDeletionCardAliasName
|
|
124
|
+
} = rootSlice.actions;
|
|
125
|
+
|
|
126
|
+
export default rootSlice.reducer;
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
declare global {
|
|
2
|
+
interface Window {
|
|
3
|
+
// TODO: Add types for MFS
|
|
4
|
+
MFS: {
|
|
5
|
+
addCardToMasterPass: (a: any, b: any) => void;
|
|
6
|
+
checkMasterPass: (a: any, b: MasterpassResponseCallback) => void;
|
|
7
|
+
commit: (a: any) => void;
|
|
8
|
+
completeRegistration: (a: any, b: any, c: any) => void;
|
|
9
|
+
deleteCard: MasterpassAction;
|
|
10
|
+
directPurchase: (a: any, b: any) => void;
|
|
11
|
+
forgotPassword: (a: any, b: any) => void;
|
|
12
|
+
getLastToken: () => string;
|
|
13
|
+
initiateRecurringPayment: (a: any, b: any) => void;
|
|
14
|
+
linkCardToClient: MasterpassAction;
|
|
15
|
+
listCards: (a: any, b: any, c: any) => void;
|
|
16
|
+
parseQrCode: (a: any, b: any) => void;
|
|
17
|
+
purchase: (a: any, b: any) => void;
|
|
18
|
+
purchaseAndRegister: (a: any, b: any) => void;
|
|
19
|
+
register: MasterpassAction;
|
|
20
|
+
resendOtp: (a: any, b: any, c: any) => void;
|
|
21
|
+
setAdditionalParameters: (a: any) => void;
|
|
22
|
+
setAddress: (address: string) => void;
|
|
23
|
+
setClientId: (clientId: string) => void;
|
|
24
|
+
setFingerprint: (a: any) => void;
|
|
25
|
+
setToken: (a: any) => void;
|
|
26
|
+
updateUser: (a: any, b: any) => void;
|
|
27
|
+
validateTransaction: MasterpassAction;
|
|
28
|
+
verifyPin: (a: any, b: any) => void;
|
|
29
|
+
};
|
|
30
|
+
$: any;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export enum MasterpassStatus {
|
|
35
|
+
NoAccount = '000000',
|
|
36
|
+
ListCards = '011100',
|
|
37
|
+
ShowLinkModal = '011000'
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export type MasterpassResponse = {
|
|
41
|
+
responseCode: string;
|
|
42
|
+
responseDescription: string;
|
|
43
|
+
referenceNo?: string;
|
|
44
|
+
token?: string;
|
|
45
|
+
transactionId?: string;
|
|
46
|
+
cardUniqueId?: string;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export type MasterpassResponseCallback<T = MasterpassResponse> = (
|
|
50
|
+
statusCode: number,
|
|
51
|
+
response: T
|
|
52
|
+
) => Promise<void> | void;
|
|
53
|
+
|
|
54
|
+
export type MasterpassAction = (
|
|
55
|
+
a: JQuery<Element>,
|
|
56
|
+
b: MasterpassResponseCallback
|
|
57
|
+
) => Promise<void> | void;
|
|
58
|
+
|
|
59
|
+
export type MasterpassCredentials = {
|
|
60
|
+
client_id: string;
|
|
61
|
+
js: string;
|
|
62
|
+
merchant_id: string;
|
|
63
|
+
osessionid: string;
|
|
64
|
+
s3d_return_url: string;
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
export type MasterpassTokenResponse = {
|
|
68
|
+
msisdn?: string;
|
|
69
|
+
req_ref_no?: string;
|
|
70
|
+
token?: string;
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
export type CheckMasterpassResponse = {
|
|
74
|
+
accountStatus: string;
|
|
75
|
+
amount: string;
|
|
76
|
+
cards: Array<MasterpassResponseCardType>;
|
|
77
|
+
installmentCount: string;
|
|
78
|
+
internalResponseCode: string;
|
|
79
|
+
internalResponseDescription: string;
|
|
80
|
+
newMsisdn: string;
|
|
81
|
+
orderNo: string;
|
|
82
|
+
referenceNo: string;
|
|
83
|
+
responseCode: string;
|
|
84
|
+
responseDescription: string;
|
|
85
|
+
token: string;
|
|
86
|
+
transactionId: string;
|
|
87
|
+
url3D: string;
|
|
88
|
+
url3DError: string;
|
|
89
|
+
url3DSuccess: string;
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
export type MasterpassResponseCardType = {
|
|
93
|
+
BankIca: string;
|
|
94
|
+
CardStatus: string;
|
|
95
|
+
Name: string;
|
|
96
|
+
ProductName: string;
|
|
97
|
+
UniqueId: string;
|
|
98
|
+
Value1: string;
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
export interface RemoveModalProps {
|
|
102
|
+
isOpen: boolean;
|
|
103
|
+
setOpen: (arg: boolean) => void;
|
|
104
|
+
onConfirm: () => void;
|
|
105
|
+
isLoading: boolean;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export interface OtpModalProps {
|
|
109
|
+
title?: string;
|
|
110
|
+
isOpen?: boolean;
|
|
111
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { formCreator } from '.';
|
|
4
|
+
import { CheckMasterpassResponse, MasterpassTokenResponse } from '../types';
|
|
5
|
+
import { buildClientRequestUrl } from '@akinon/next/utils';
|
|
6
|
+
|
|
7
|
+
export const checkMasterpass = () =>
|
|
8
|
+
new Promise<{
|
|
9
|
+
status: number;
|
|
10
|
+
response?: CheckMasterpassResponse;
|
|
11
|
+
msisdn?: string;
|
|
12
|
+
token?: string;
|
|
13
|
+
referenceNo?: string;
|
|
14
|
+
}>(async (resolve) => {
|
|
15
|
+
let data: MasterpassTokenResponse;
|
|
16
|
+
|
|
17
|
+
try {
|
|
18
|
+
const response = await fetch(
|
|
19
|
+
buildClientRequestUrl('/orders/masterpass-token')
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
if (response.status !== 200) {
|
|
23
|
+
resolve({
|
|
24
|
+
status: response.status
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
data = await response.json();
|
|
31
|
+
|
|
32
|
+
const fields = [
|
|
33
|
+
{
|
|
34
|
+
name: 'token',
|
|
35
|
+
value: data.token ?? ''
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
name: 'referenceNo',
|
|
39
|
+
value: data.req_ref_no ?? ''
|
|
40
|
+
},
|
|
41
|
+
{ name: 'userId', value: data.msisdn ?? '' },
|
|
42
|
+
{ name: 'sendSmsLanguage', value: 'eng' },
|
|
43
|
+
{ name: 'sendSms', value: 'N' }
|
|
44
|
+
];
|
|
45
|
+
|
|
46
|
+
const form = formCreator({
|
|
47
|
+
id: 'check-masterpass-form',
|
|
48
|
+
fields
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
window.MFS.checkMasterPass(
|
|
52
|
+
$(form),
|
|
53
|
+
(status: number, response: CheckMasterpassResponse) => {
|
|
54
|
+
resolve({
|
|
55
|
+
status,
|
|
56
|
+
response,
|
|
57
|
+
msisdn: data.msisdn ?? '',
|
|
58
|
+
token: data.token ?? '',
|
|
59
|
+
referenceNo: data.req_ref_no ?? ''
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
);
|
|
63
|
+
} catch (error) {
|
|
64
|
+
console.error(error);
|
|
65
|
+
}
|
|
66
|
+
});
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { CheckMasterpassResponse, MasterpassResponseCardType } from '../types';
|
|
4
|
+
|
|
5
|
+
export const getMasterpassCards = ({
|
|
6
|
+
msisdn,
|
|
7
|
+
token
|
|
8
|
+
}: {
|
|
9
|
+
msisdn: string;
|
|
10
|
+
token: string;
|
|
11
|
+
}) =>
|
|
12
|
+
new Promise<{
|
|
13
|
+
statusCode: number;
|
|
14
|
+
cards: Array<MasterpassResponseCardType>;
|
|
15
|
+
description: string;
|
|
16
|
+
}>((resolve) => {
|
|
17
|
+
try {
|
|
18
|
+
window.MFS?.listCards(
|
|
19
|
+
msisdn,
|
|
20
|
+
token,
|
|
21
|
+
(statusCode: number, response: CheckMasterpassResponse) => {
|
|
22
|
+
resolve({
|
|
23
|
+
statusCode,
|
|
24
|
+
cards: response.cards,
|
|
25
|
+
description: response.responseDescription
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
);
|
|
29
|
+
} catch (error) {
|
|
30
|
+
console.error(error);
|
|
31
|
+
}
|
|
32
|
+
});
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import { CompleteCreditCardParams } from '@akinon/next/data/client/checkout';
|
|
2
|
+
import { MasterpassResponseCardType } from '../types';
|
|
3
|
+
import { getSession } from 'next-auth/react';
|
|
4
|
+
|
|
5
|
+
type Field = {
|
|
6
|
+
name: string;
|
|
7
|
+
value: string;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
interface FromCreator {
|
|
11
|
+
id: string;
|
|
12
|
+
fields: Field[];
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const setMFSParams = ({ amount }: { amount: string }) => {
|
|
16
|
+
window.MFS.setAdditionalParameters({
|
|
17
|
+
order_product_name_arr: ['TEST'],
|
|
18
|
+
order_product_code_arr: ['TST'],
|
|
19
|
+
order_price_arr: [amount],
|
|
20
|
+
order_qty_arr: ['1'],
|
|
21
|
+
order_product_info_arr: ['test']
|
|
22
|
+
});
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export const formCreator = (args: FromCreator) => {
|
|
26
|
+
const { id, fields } = args;
|
|
27
|
+
|
|
28
|
+
const form = document.createElement('form');
|
|
29
|
+
form.setAttribute('method', 'POST');
|
|
30
|
+
form.setAttribute('id', id);
|
|
31
|
+
|
|
32
|
+
fields.forEach((field) => {
|
|
33
|
+
const input = document.createElement('input');
|
|
34
|
+
input.setAttribute('type', 'hidden');
|
|
35
|
+
input.setAttribute('name', field.name);
|
|
36
|
+
input.setAttribute('value', field.value);
|
|
37
|
+
form.appendChild(input);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
return form;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export const getCreditCardType = (number: string) => {
|
|
44
|
+
if (/^5[1-5]/.test(number)) {
|
|
45
|
+
return 'mastercard';
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (/^4/.test(number)) {
|
|
49
|
+
return 'visa';
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (/^3[47]/.test(number)) {
|
|
53
|
+
return 'amex';
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (/^(?:9792|65\d{2}|36|2205)/.test(number)) {
|
|
57
|
+
return 'troy';
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return 'other';
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
export const buildPurchaseForm = async ({
|
|
64
|
+
token,
|
|
65
|
+
orderNo,
|
|
66
|
+
msisdn,
|
|
67
|
+
referenceNo,
|
|
68
|
+
merchantId,
|
|
69
|
+
selectedCard,
|
|
70
|
+
amount
|
|
71
|
+
}: {
|
|
72
|
+
token: string;
|
|
73
|
+
orderNo: string;
|
|
74
|
+
msisdn: string;
|
|
75
|
+
referenceNo: string;
|
|
76
|
+
merchantId: string;
|
|
77
|
+
selectedCard: MasterpassResponseCardType;
|
|
78
|
+
amount: string;
|
|
79
|
+
}) => {
|
|
80
|
+
const session = await getSession();
|
|
81
|
+
|
|
82
|
+
setMFSParams({ amount });
|
|
83
|
+
|
|
84
|
+
const fields = [
|
|
85
|
+
{
|
|
86
|
+
name: 'token',
|
|
87
|
+
value: token
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
name: 'orderNo',
|
|
91
|
+
value: orderNo
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
name: 'referenceNo',
|
|
95
|
+
value: referenceNo
|
|
96
|
+
},
|
|
97
|
+
{ name: 'amount', value: amount },
|
|
98
|
+
{ name: 'userId', value: String(session?.user?.pk ?? '') },
|
|
99
|
+
{ name: 'msisdn', value: msisdn },
|
|
100
|
+
{ name: 'installmentCount', value: '' },
|
|
101
|
+
{ name: 'macroMerchantId', value: merchantId },
|
|
102
|
+
{ name: 'sendSmsLanguage', value: 'eng' },
|
|
103
|
+
{ name: 'sendSms', value: 'N' },
|
|
104
|
+
{ name: 'cardName', value: selectedCard?.Name ?? '' },
|
|
105
|
+
{ name: 'listAccountName', value: selectedCard?.Name ?? '' },
|
|
106
|
+
{ name: 'cardAliasName', value: selectedCard?.Name ?? '' }
|
|
107
|
+
];
|
|
108
|
+
|
|
109
|
+
const form = formCreator({
|
|
110
|
+
id: 'mp-purchase-form',
|
|
111
|
+
fields
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
return form;
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
export const buildDirectPurchaseForm = async (
|
|
118
|
+
{
|
|
119
|
+
token,
|
|
120
|
+
orderNo,
|
|
121
|
+
msisdn,
|
|
122
|
+
referenceNo,
|
|
123
|
+
merchantId,
|
|
124
|
+
amount
|
|
125
|
+
}: {
|
|
126
|
+
token: string;
|
|
127
|
+
orderNo: string;
|
|
128
|
+
msisdn: string;
|
|
129
|
+
referenceNo: string;
|
|
130
|
+
merchantId: string;
|
|
131
|
+
amount: string;
|
|
132
|
+
},
|
|
133
|
+
params?: CompleteCreditCardParams
|
|
134
|
+
) => {
|
|
135
|
+
const session = await getSession();
|
|
136
|
+
|
|
137
|
+
setMFSParams({ amount });
|
|
138
|
+
|
|
139
|
+
const rtaPan = params.card_number;
|
|
140
|
+
const expiryDate =
|
|
141
|
+
params.card_year.slice(-2) + params.card_month.padStart(2, '0');
|
|
142
|
+
const cardHolderName = params.card_holder;
|
|
143
|
+
const cvc = params.card_cvv;
|
|
144
|
+
|
|
145
|
+
const fields = [
|
|
146
|
+
{
|
|
147
|
+
name: 'token',
|
|
148
|
+
value: token
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
name: 'orderNo',
|
|
152
|
+
value: orderNo
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
name: 'referenceNo',
|
|
156
|
+
value: referenceNo
|
|
157
|
+
},
|
|
158
|
+
{ name: 'amount', value: amount },
|
|
159
|
+
{ name: 'userId', value: String(session?.user?.pk ?? '') },
|
|
160
|
+
{ name: 'msisdn', value: msisdn },
|
|
161
|
+
{ name: 'installmentCount', value: '' },
|
|
162
|
+
{ name: 'macroMerchantId', value: merchantId },
|
|
163
|
+
{ name: 'sendSmsLanguage', value: 'eng' },
|
|
164
|
+
{ name: 'sendSms', value: 'N' },
|
|
165
|
+
{ name: 'rtaPan', value: rtaPan },
|
|
166
|
+
{ name: 'expiryDate', value: expiryDate },
|
|
167
|
+
{ name: 'cardHolderName', value: cardHolderName },
|
|
168
|
+
{ name: 'cvc', value: cvc }
|
|
169
|
+
];
|
|
170
|
+
|
|
171
|
+
const form = formCreator({
|
|
172
|
+
id: 'mp-direct-purchase-form',
|
|
173
|
+
fields
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
return form;
|
|
177
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { buildClientRequestUrl } from '@akinon/next/utils';
|
|
2
|
+
import { MasterpassCredentials } from '../types';
|
|
3
|
+
|
|
4
|
+
export const init = () =>
|
|
5
|
+
new Promise<MasterpassCredentials>(async (resolve) => {
|
|
6
|
+
try {
|
|
7
|
+
const response = await fetch(buildClientRequestUrl('/masterpass-js'));
|
|
8
|
+
const data: MasterpassCredentials = await response.json();
|
|
9
|
+
|
|
10
|
+
window.MFS.setClientId(data.client_id);
|
|
11
|
+
window.MFS.setAddress(data.js);
|
|
12
|
+
|
|
13
|
+
resolve(data);
|
|
14
|
+
} catch (error) {
|
|
15
|
+
console.error(error);
|
|
16
|
+
}
|
|
17
|
+
});
|