@akinon/pz-bkm 1.0.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/.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 };