@akinon/pz-bkm 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
package/.gitattributes ADDED
@@ -0,0 +1,15 @@
1
+ *.js text eol=lf
2
+ *.jsx text eol=lf
3
+ *.ts text eol=lf
4
+ *.tsx text eol=lf
5
+ *.json text eol=lf
6
+ *.md text eol=lf
7
+
8
+ .eslintignore text eol=lf
9
+ .eslintrc text eol=lf
10
+ .gitignore text eol=lf
11
+ .prettierrc text eol=lf
12
+ .yarnrc text eol=lf
13
+
14
+ * text=auto
15
+
package/.prettierrc ADDED
@@ -0,0 +1,13 @@
1
+ {
2
+ "bracketSameLine": false,
3
+ "tabWidth": 2,
4
+ "singleQuote": true,
5
+ "jsxSingleQuote": false,
6
+ "bracketSpacing": true,
7
+ "semi": true,
8
+ "useTabs": false,
9
+ "arrowParens": "always",
10
+ "endOfLine": "lf",
11
+ "proseWrap": "never",
12
+ "trailingComma": "none"
13
+ }
package/package.json ADDED
@@ -0,0 +1,23 @@
1
+ {
2
+ "name": "@akinon/pz-bkm",
3
+ "version": "1.0.0",
4
+ "license": "MIT",
5
+ "main": "src/index.tsx",
6
+ "peerDependencies": {
7
+ "react": "^18.0.0",
8
+ "react-dom": "^18.0.0"
9
+ },
10
+ "devDependencies": {
11
+ "@types/node": "^18.7.8",
12
+ "@types/react": "^18.0.17",
13
+ "@types/react-dom": "^18.0.6",
14
+ "react": "^18.2.0",
15
+ "react-dom": "^18.2.0",
16
+ "typescript": "5.2.2"
17
+ },
18
+ "dependencies": {
19
+ "@hookform/resolvers": "2.9.0",
20
+ "react-hook-form": "7.31.3",
21
+ "yup": "0.32.11"
22
+ }
23
+ }
package/readme.md ADDED
@@ -0,0 +1,36 @@
1
+ # pz-bkm
2
+
3
+ ### Install the npm package
4
+
5
+ ```bash
6
+ # For latest version
7
+ yarn add git+ssh://git@bitbucket.org:akinonteam/pz-bkm.git
8
+
9
+ # For specific version
10
+ yarn add git+ssh://git@bitbucket.org:akinonteam/pz-bkm.git#eX4mPl3
11
+ ```
12
+
13
+ ### Example Usage
14
+ ##### File Path: src/views/checkout/steps/payment/options/bkm.tsx
15
+
16
+ ```javascript
17
+ import { BKMOption } from 'pz-bkm';
18
+
19
+ export default function BKM() {
20
+ return (
21
+ <BKMOption
22
+ translations={{
23
+ title: 'Pay with BKM Express',
24
+ description: `When paying with BKM Express, you will be redirected to www.bkmexpress.com.tr.`,
25
+ button: 'Pay Now'
26
+ }}
27
+ />
28
+ );
29
+ }
30
+ ```
31
+
32
+ ### Props
33
+ | Property | Type | Description |
34
+ |----------------|-----------|--------------------------------------------------|
35
+ | `translations` | `object` | Object containing translation strings. |
36
+ | `classes` | `object` | Object containing custom CSS class names. |
@@ -0,0 +1,60 @@
1
+ import {
2
+ CheckoutContext as BaseCheckoutContext,
3
+ PreOrder
4
+ } from '@akinon/next/types';
5
+ import { setPaymentStepBusy } from '@akinon/next/redux/reducers/checkout';
6
+ import { api } from '@akinon/next/data/client/api';
7
+ import { buildClientRequestUrl } from '@akinon/next/utils';
8
+
9
+ type CheckoutContext = BaseCheckoutContext & {
10
+ page_context?: {
11
+ transaction_id?: string;
12
+ path?: string;
13
+ token?: string;
14
+ };
15
+ };
16
+
17
+ interface CheckoutResponse {
18
+ pre_order?: PreOrder;
19
+ errors: {
20
+ non_field_errors: string;
21
+ };
22
+ context_list?: CheckoutContext[];
23
+ template_name?: string;
24
+ redirect_url?: string;
25
+ }
26
+
27
+ export const bkmApi = api.injectEndpoints({
28
+ endpoints: (build) => ({
29
+ setBkm: build.mutation<CheckoutResponse, boolean>({
30
+ query: (agreement: boolean) => ({
31
+ url: buildClientRequestUrl('/orders/checkout/?page=BexSelectionPage', {
32
+ useFormData: true
33
+ }),
34
+ method: 'POST',
35
+ body: {
36
+ agreement
37
+ }
38
+ }),
39
+ async onQueryStarted(arg, { dispatch, queryFulfilled }) {
40
+ dispatch(setPaymentStepBusy(true));
41
+ await queryFulfilled;
42
+ dispatch(setPaymentStepBusy(false));
43
+ }
44
+ }),
45
+ completeBkm: build.mutation<CheckoutResponse, void>({
46
+ query: () => ({
47
+ url: buildClientRequestUrl('/orders/checkout/?page=BexCompletePage'),
48
+ method: 'POST'
49
+ }),
50
+ async onQueryStarted(arg, { dispatch, queryFulfilled }) {
51
+ dispatch(setPaymentStepBusy(true));
52
+ await queryFulfilled;
53
+ dispatch(setPaymentStepBusy(false));
54
+ }
55
+ })
56
+ }),
57
+ overrideExisting: false
58
+ });
59
+
60
+ export const { useSetBkmMutation, useCompleteBkmMutation } = bkmApi;
package/src/index.tsx ADDED
@@ -0,0 +1 @@
1
+ export * from './views/bkm-option';
@@ -0,0 +1,147 @@
1
+ import React, { ReactElement, useId } from 'react';
2
+ import Script from 'next/script';
3
+ import * as yup from 'yup';
4
+ import { yupResolver } from '@hookform/resolvers/yup';
5
+ import { SubmitHandler, useForm } from 'react-hook-form';
6
+ import { Button } from '@akinon/next/components';
7
+ import { useCompleteBkmMutation, useSetBkmMutation } from '../endpoints';
8
+ import { twMerge } from 'tailwind-merge';
9
+
10
+ type BKMOptionProps = {
11
+ translations?: {
12
+ title?: string;
13
+ description?: string;
14
+ button?: string;
15
+ required?: string;
16
+ };
17
+ classes?: {
18
+ description?: string;
19
+ button?: string;
20
+ };
21
+ agreementCheckbox?: ReactElement;
22
+ };
23
+
24
+ const formSchema = (requiredText?: string) =>
25
+ yup.object().shape({
26
+ agreement: yup
27
+ .boolean()
28
+ .oneOf([true], requiredText ?? 'This field is required.')
29
+ });
30
+
31
+ const BKMOption = ({
32
+ translations,
33
+ classes,
34
+ agreementCheckbox
35
+ }: BKMOptionProps) => {
36
+ const id = useId();
37
+ const {
38
+ handleSubmit,
39
+ control,
40
+ formState: { errors },
41
+ getValues
42
+ } = useForm({
43
+ resolver: yupResolver(formSchema(translations?.required))
44
+ });
45
+ const [setBkm] = useSetBkmMutation();
46
+ const [completeBkm] = useCompleteBkmMutation();
47
+
48
+ const onSubmit: SubmitHandler<null> = async () => {
49
+ const response = await setBkm(getValues('agreement')).unwrap();
50
+
51
+ const bexContext = response.context_list.find(
52
+ (context) => context.page_name === 'BexBinNumberPage'
53
+ );
54
+
55
+ if (!bexContext) {
56
+ return;
57
+ }
58
+
59
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
60
+ // @ts-ignore
61
+ window.Bex.init(
62
+ {
63
+ id: bexContext.page_context.transaction_id,
64
+ path: bexContext.page_context.path,
65
+ token: bexContext.page_context.token
66
+ },
67
+ 'modal',
68
+ {
69
+ container: `js-bkm-frame-${id}`,
70
+ buttonSize: [500, 500],
71
+ skipButton: true,
72
+ onComplete: async (status) => {
73
+ if (status == 'success') {
74
+ const data = await completeBkm().unwrap();
75
+ const redirectUrl =
76
+ data.context_list?.[0]?.page_context?.redirect_url;
77
+
78
+ if (!redirectUrl) {
79
+ return;
80
+ }
81
+
82
+ window.location.href = redirectUrl;
83
+ }
84
+ }
85
+ }
86
+ );
87
+ };
88
+
89
+ return (
90
+ <>
91
+ <form className="flex flex-col w-full" onSubmit={handleSubmit(onSubmit)}>
92
+ <div className="flex justify-start items-center border-solid border-gray-400 px-4 py-2 sm:px-6 sm:py-3 sm:min-h-15">
93
+ <span className="text-black-800 text-lg font-medium sm:text-2xl">
94
+ {translations?.title ?? 'BKM Express'}
95
+ </span>
96
+ </div>
97
+
98
+ <div className="w-full bg-white">
99
+ <div className="text-black-800 px-4 sm:px-6">
100
+ <p className={twMerge('text-sm w-full mb-2', classes?.description)}>
101
+ {translations?.description ?? (
102
+ <>
103
+ When paying with BKM Express, you will be redirected to
104
+ www.bkmexpress.com.tr. <br />
105
+ You need to log in to the application with the username and
106
+ password you used when signing up to BKM Express. You can
107
+ easily pay by selecting the card you want to make a
108
+ transaction and the payment method from the payment screen
109
+ that appears. After completing your shopping, you will
110
+ automatically return to site.
111
+ </>
112
+ )}
113
+ </p>
114
+ </div>
115
+ </div>
116
+
117
+ <div className="px-4 sm:px-6">
118
+ <div className="flex items-start flex-col border-t border-solid border-gray-400 py-4 space-y-4">
119
+ {agreementCheckbox &&
120
+ React.cloneElement(agreementCheckbox, {
121
+ control: control,
122
+ error: errors.agreement,
123
+ fieldId: 'agreement'
124
+ })}
125
+ <Button
126
+ className={twMerge(
127
+ 'group uppercase mt-4 inline-flex items-center justify-center w-full',
128
+ classes?.button
129
+ )}
130
+ type="submit"
131
+ data-testid="checkout-bank-account-place-order"
132
+ >
133
+ <span>{translations?.button ?? 'Pay with BKM Express'}</span>
134
+ </Button>
135
+ </div>
136
+ </div>
137
+ </form>
138
+ <div
139
+ id={`js-bkm-frame-${id}`}
140
+ className="bkm-frame !flex justify-center items-center !pt-0"
141
+ ></div>
142
+ <Script src="https://js.bkmexpress.com.tr/v1/javascripts/bex.js" defer />
143
+ </>
144
+ );
145
+ };
146
+
147
+ export { BKMOption };