@akinon/pz-bkm 2.0.0-beta.9 → 2.0.1

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,45 +1,150 @@
1
1
  # @akinon/pz-bkm
2
2
 
3
- ## 2.0.0-beta.9
3
+ ## 2.0.1
4
+
5
+ ## 2.0.0
6
+
7
+ ## 2.0.0-beta.27
8
+
9
+ ## 2.0.0-beta.26
10
+
11
+ ## 2.0.0-beta.25
12
+
13
+ ## 2.0.0-beta.24
14
+
15
+ ## 2.0.0-beta.23
16
+
17
+ ## 2.0.0-beta.22
18
+
19
+ ## 2.0.0-beta.21
20
+
21
+ ## 2.0.0-beta.20
22
+
23
+ ## 1.126.0
24
+
25
+ ## 1.125.2
26
+
27
+ ## 1.125.1
28
+
29
+ ## 1.125.0
30
+
31
+ ## 1.124.0
32
+
33
+ ## 1.123.0
34
+
35
+ ## 1.122.0
36
+
37
+ ### Minor Changes
38
+
39
+ - d35e8ac1: ZERO-3402 :Update README.md to enhance props documentation and usage examples for customUIRender
40
+
41
+ ## 1.121.0
42
+
43
+ ## 1.120.0
4
44
 
5
45
  ### Minor Changes
6
46
 
7
- - 0fe7711: ZERO-3387: Upgrade nextjs, eslint-config-next
47
+ - 6ad72e8d: ZERO-4032: Add loading state management for payment submissions across multiple components and add safe guarding
48
+
49
+ ## 1.119.0
50
+
51
+ ## 1.118.0
52
+
53
+ ## 1.117.0
54
+
55
+ ## 1.116.0
56
+
57
+ ## 1.115.0
58
+
59
+ ## 1.114.0
8
60
 
9
- ## 2.0.0-beta.8
61
+ ## 1.113.0
10
62
 
11
- ## 2.0.0-beta.7
63
+ ## 1.112.0
12
64
 
13
- ## 2.0.0-beta.6
65
+ ## 1.111.0
66
+
67
+ ## 1.110.0
68
+
69
+ ## 1.109.0
70
+
71
+ ## 1.108.0
72
+
73
+ ## 1.107.0
74
+
75
+ ## 1.106.0
76
+
77
+ ## 1.105.0
78
+
79
+ ## 1.104.0
80
+
81
+ ## 1.103.0
82
+
83
+ ## 1.102.0
84
+
85
+ ## 1.101.0
86
+
87
+ ## 1.100.0
88
+
89
+ ## 1.99.0
14
90
 
15
91
  ### Minor Changes
16
92
 
17
- - 8f05f9b: ZERO-3250: Beta branch synchronized with Main branch
93
+ - d58538b: ZERO-3638: Enhance RC pipeline: add fetch, merge, and pre-release setup with conditional commit
94
+
95
+ ## 1.98.0
96
+
97
+ ## 1.97.0
18
98
 
19
- ## 2.0.0-beta.5
99
+ ## 1.96.0
20
100
 
21
- ## 2.0.0-beta.4
101
+ ## 1.95.0
22
102
 
23
- ## 2.0.0-beta.3
103
+ ## 1.94.0
24
104
 
25
- ## 2.0.0-beta.2
105
+ ## 1.93.0
106
+
107
+ ## 1.92.0
108
+
109
+ ## 1.91.0
110
+
111
+ ## 1.90.0
26
112
 
27
113
  ### Minor Changes
28
114
 
29
- - a006015: ZERO-3116: Add not-found page and update default middleware.
30
- - 1eeb3d8: ZERO-3116: Add not found page
115
+ - 1044bce: ZERO-3379: Add custom UI rendering support
116
+
117
+ ## 1.89.0
118
+
119
+ ## 1.88.0
120
+
121
+ ## 1.87.0
122
+
123
+ ## 1.86.0
31
124
 
32
- ## 2.0.0-beta.1
125
+ ## 1.85.0
126
+
127
+ ## 1.84.0
33
128
 
34
129
  ### Minor Changes
35
130
 
36
- - ZERO-3091: Upgrade Next.js to v15 and React to v19
131
+ - 624a4eb: ZERO-3276: Update installation instructions across multiple README files to standardize format and improve clarity
132
+
133
+ ## 1.83.0
134
+
135
+ ## 1.82.0
136
+
137
+ ## 1.81.0
138
+
139
+ ## 1.80.0
140
+
141
+ ## 1.79.0
37
142
 
38
- ## 2.0.0-beta.0
143
+ ## 1.78.0
39
144
 
40
- ### Major Changes
145
+ ## 1.77.0
41
146
 
42
- - be6c09d: ZERO-3114: Create beta version.
147
+ ## 1.76.0
43
148
 
44
149
  ## 1.75.0
45
150
 
package/package.json CHANGED
@@ -1,19 +1,19 @@
1
1
  {
2
2
  "name": "@akinon/pz-bkm",
3
- "version": "2.0.0-beta.9",
3
+ "version": "2.0.1",
4
4
  "license": "MIT",
5
5
  "main": "src/index.tsx",
6
6
  "peerDependencies": {
7
- "react": "^19.0.0",
8
- "react-dom": "^19.0.0"
7
+ "react": "^18.0.0 || ^19.0.0",
8
+ "react-dom": "^18.0.0 || ^19.0.0"
9
9
  },
10
10
  "devDependencies": {
11
- "@types/node": "^22.10.2",
12
- "@types/react": "^19.0.2",
13
- "@types/react-dom": "^19.0.2",
14
- "react": "^19.0.0",
15
- "react-dom": "^19.0.0",
16
- "typescript": "^5.7.2"
11
+ "@types/node": "^18.7.8",
12
+ "@types/react": "^18.0.17",
13
+ "@types/react-dom": "^18.0.6",
14
+ "react": "19.2.5",
15
+ "react-dom": "19.2.5",
16
+ "typescript": "5.2.2"
17
17
  },
18
18
  "dependencies": {
19
19
  "@hookform/resolvers": "2.9.0",
package/readme.md CHANGED
@@ -10,9 +10,41 @@ npx @akinon/projectzero@latest --plugins
10
10
 
11
11
  ```
12
12
 
13
- ### Example Usage
13
+ ### Props
14
+
15
+ | Property | Type | Required | Description |
16
+ | --- | --- | --- | --- |
17
+ | `translations` | `object` | Optional | Object containing translation strings. |
18
+ | `classes` | `object` | Optional | Object containing custom CSS class names. |
19
+ | `customUIRender` | `React.ReactNode` | Optional | Custom rendering functions. |
20
+
21
+ ### customUIRender Props
22
+
23
+ | Property | Type | Required | Description |
24
+ | --- | --- | --- | --- |
25
+ | `handleSubmit` | `UseFormHandleSubmit<BKMOptionForm>` | Required | Form submission handler from `react-hook-form`. Wraps the `handleSubmit` method. |
26
+ | `onSubmit` | `SubmitHandler<BKMOptionForm>` | Required | Callback function executed on successful form submission. |
27
+ | `control` | `Control<BKMOptionForm>` | Required | Control object used to register form inputs with `react-hook-form`. |
28
+ | `errors` | `FieldErrors<BKMOptionForm>` | Required | Contains validation errors for form fields. |
29
+ | `translations` | `BKMOptionProps['translations']` | Optional | Optional prop for providing localized strings like title and description. |
30
+ | `bkmFrameId` | `string` | Required | The DOM `id` attribute for the embedded BKM iframe element. |
31
+
32
+ ### Translations Properties
33
+
34
+ | Key | Type | Description |
35
+ | --- | --- | --- |
36
+ | `title` | `string` | The title text displayed at the top of the component. |
37
+ | `description` | `string` | A short description or informative message for the user. |
38
+ | `button` | `string` | Text displayed on the submit button. |
39
+ | `required` | `string` | Validation message shown when a required field is empty. |
40
+
41
+ ### Usage Examples
42
+
43
+ ```bash
44
+ src/views/checkout/steps/payment/options/bkm.tsx
45
+ ```
14
46
 
15
- ##### File Path: src/views/checkout/steps/payment/options/bkm.tsx
47
+ #### Default Usage
16
48
 
17
49
  ```javascript
18
50
  const Bkm = () => {
@@ -33,9 +65,53 @@ const Bkm = () => {
33
65
  export default Bkm;
34
66
  ```
35
67
 
36
- ### Props
68
+ #### Customized Usage with customUIRender
69
+
70
+ ```javascript
71
+ import PluginModule, { Component } from '@akinon/next/components/plugin-module';
72
+
73
+ <PluginModule
74
+ component={Component.BKMExpress}
75
+ props={{
76
+ customUIRender: ({
77
+ handleSubmit,
78
+ onSubmit,
79
+ control,
80
+ errors,
81
+ translations,
82
+ bkmFrameId
83
+ }) => (
84
+ <div className="px-4 py-6">
85
+ <form onSubmit={handleSubmit(onSubmit)}>
86
+ <h2 className="font-semibold text-2xl mb-4">{translations?.title}</h2>
87
+ <p className="text-sm">
88
+ When paying with BKM Express, you will be redirected to
89
+ www.bkmexpress.com.tr. <br />
90
+ You need to log in to the application with the username and password
91
+ you used when signing up to BKM Express. You can easily pay by selecting
92
+ the card you want to make a transaction and the payment method from the
93
+ payment screen that appears. After completing your shopping, you will
94
+ automatically return to site.
95
+ </p>
96
+ <div className="py-4">
97
+ <CheckoutAgreements
98
+ control={control}
99
+ error={errors?.agreement}
100
+ fieldId="agreement"
101
+ />
102
+ </div>
37
103
 
38
- | Property | Type | Description |
39
- | -------------- | -------- | ----------------------------------------- |
40
- | `translations` | `object` | Object containing translation strings. |
41
- | `classes` | `object` | Object containing custom CSS class names. |
104
+ <button className="w-full bg-primary text-white h-9" type="submit">
105
+ Pay with BKM Express
106
+ </button>
107
+ </form>
108
+
109
+ <div
110
+ id={bkmFrameId}
111
+ className="bkm-frame !flex justify-center items-center !pt-0"
112
+ ></div>
113
+ </div>
114
+ )
115
+ }}
116
+ />;
117
+ ```
@@ -1,12 +1,22 @@
1
- import React, { ReactElement, useId } from 'react';
1
+ import React, { ReactElement, useId, useState } from 'react';
2
2
  import Script from 'next/script';
3
3
  import * as yup from 'yup';
4
4
  import { yupResolver } from '@hookform/resolvers/yup';
5
- import { SubmitHandler, useForm } from 'react-hook-form';
5
+ import {
6
+ SubmitHandler,
7
+ useForm,
8
+ UseFormHandleSubmit,
9
+ Control,
10
+ FieldErrors
11
+ } from 'react-hook-form';
6
12
  import { Button } from '@akinon/next/components';
7
13
  import { useCompleteBkmMutation, useSetBkmMutation } from '../endpoints';
8
14
  import { twMerge } from 'tailwind-merge';
9
15
 
16
+ interface BKMOptionForm {
17
+ agreement: boolean;
18
+ }
19
+
10
20
  type BKMOptionProps = {
11
21
  translations?: {
12
22
  title?: string;
@@ -18,6 +28,14 @@ type BKMOptionProps = {
18
28
  description?: string;
19
29
  button?: string;
20
30
  };
31
+ customUIRender?: (params: {
32
+ handleSubmit: UseFormHandleSubmit<BKMOptionForm>;
33
+ onSubmit: SubmitHandler<BKMOptionForm>;
34
+ control: Control<BKMOptionForm>;
35
+ errors: FieldErrors<BKMOptionForm>;
36
+ translations?: BKMOptionProps['translations'];
37
+ bkmFrameId: string;
38
+ }) => ReactElement;
21
39
  agreementCheckbox?: ReactElement;
22
40
  };
23
41
 
@@ -31,61 +49,93 @@ const formSchema = (requiredText?: string) =>
31
49
  const BKMOption = ({
32
50
  translations,
33
51
  classes,
34
- agreementCheckbox
52
+ agreementCheckbox,
53
+ customUIRender
35
54
  }: BKMOptionProps) => {
36
55
  const id = useId();
56
+ const [isProcessing, setIsProcessing] = useState(false);
37
57
  const {
38
58
  handleSubmit,
39
59
  control,
40
- formState: { errors },
60
+ formState: { errors, isSubmitting },
41
61
  getValues
42
- } = useForm({
43
- resolver: yupResolver(formSchema(translations?.required))
62
+ } = useForm<BKMOptionForm>({
63
+ resolver: yupResolver(formSchema(translations?.required)) as any
44
64
  });
45
- const [setBkm] = useSetBkmMutation();
65
+ const [setBkm, { isLoading: isSettingBkm }] = useSetBkmMutation();
46
66
  const [completeBkm] = useCompleteBkmMutation();
47
67
 
48
- const onSubmit: SubmitHandler<null> = async () => {
49
- const response = await setBkm(getValues('agreement')).unwrap();
68
+ const isButtonDisabled = isSubmitting || isSettingBkm || isProcessing;
50
69
 
51
- const bexContext = response.context_list.find(
52
- (context) => context.page_name === 'BexBinNumberPage'
53
- );
70
+ const onSubmit: SubmitHandler<BKMOptionForm> = async () => {
71
+ if (isButtonDisabled) return;
54
72
 
55
- if (!bexContext) {
56
- return;
57
- }
73
+ setIsProcessing(true);
58
74
 
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
- }
75
+ try {
76
+ const response = await setBkm(getValues('agreement')).unwrap();
77
+
78
+ const bexContext = response.context_list.find(
79
+ (context) => context.page_name === 'BexBinNumberPage'
80
+ );
81
+
82
+ if (!bexContext) {
83
+ setIsProcessing(false);
84
+ return;
85
+ }
86
+
87
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
88
+ // @ts-ignore
89
+ window.Bex.init(
90
+ {
91
+ id: bexContext.page_context.transaction_id,
92
+ path: bexContext.page_context.path,
93
+ token: bexContext.page_context.token
94
+ },
95
+ 'modal',
96
+ {
97
+ container: `js-bkm-frame-${id}`,
98
+ buttonSize: [500, 500],
99
+ skipButton: true,
100
+ onComplete: async (status) => {
101
+ if (status == 'success') {
102
+ const data = await completeBkm().unwrap();
103
+ const redirectUrl =
104
+ data.context_list?.[0]?.page_context?.redirect_url;
81
105
 
82
- window.location.href = redirectUrl;
106
+ if (!redirectUrl) {
107
+ return;
108
+ }
109
+
110
+ window.location.href = redirectUrl;
111
+ }
83
112
  }
84
113
  }
85
- }
86
- );
114
+ );
115
+ } catch (error) {
116
+ setIsProcessing(false);
117
+ }
87
118
  };
88
119
 
120
+ if (customUIRender) {
121
+ return (
122
+ <>
123
+ {customUIRender({
124
+ handleSubmit,
125
+ onSubmit,
126
+ control,
127
+ errors,
128
+ translations,
129
+ bkmFrameId: `js-bkm-frame-${id}`
130
+ })}
131
+ <Script
132
+ src="https://js.bkmexpress.com.tr/v1/javascripts/bex.js"
133
+ defer
134
+ />
135
+ </>
136
+ );
137
+ }
138
+
89
139
  return (
90
140
  <>
91
141
  <form className="flex flex-col w-full" onSubmit={handleSubmit(onSubmit)}>
@@ -117,9 +167,8 @@ const BKMOption = ({
117
167
  <div className="px-4 sm:px-6">
118
168
  <div className="flex items-start flex-col border-t border-solid border-gray-400 py-4 space-y-4">
119
169
  {agreementCheckbox &&
120
- React.cloneElement(agreementCheckbox, {
121
- // @ts-ignore
122
- control: control,
170
+ React.cloneElement(agreementCheckbox as any, {
171
+ control: control as any,
123
172
  error: errors.agreement,
124
173
  fieldId: 'agreement'
125
174
  })}
@@ -129,6 +178,7 @@ const BKMOption = ({
129
178
  classes?.button
130
179
  )}
131
180
  type="submit"
181
+ disabled={isButtonDisabled}
132
182
  data-testid="checkout-bank-account-place-order"
133
183
  >
134
184
  <span>{translations?.button ?? 'Pay with BKM Express'}</span>
@@ -138,7 +188,7 @@ const BKMOption = ({
138
188
  </form>
139
189
  <div
140
190
  id={`js-bkm-frame-${id}`}
141
- className="bkm-frame flex! justify-center items-center pt-0!"
191
+ className="bkm-frame !flex justify-center items-center !pt-0"
142
192
  ></div>
143
193
  <Script src="https://js.bkmexpress.com.tr/v1/javascripts/bex.js" defer />
144
194
  </>