@akinon/pz-bkm 2.0.0-beta.2 → 2.0.0-beta.20

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,18 +1,126 @@
1
1
  # @akinon/pz-bkm
2
2
 
3
- ## 2.0.0-beta.2
3
+ ## 2.0.0-beta.20
4
4
 
5
- ## 2.0.0-beta.1
5
+ ## 1.125.0
6
+
7
+ ## 1.124.0
8
+
9
+ ## 1.123.0
10
+
11
+ ## 1.122.0
12
+
13
+ ### Minor Changes
14
+
15
+ - d35e8ac1: ZERO-3402 :Update README.md to enhance props documentation and usage examples for customUIRender
16
+
17
+ ## 1.121.0
18
+
19
+ ## 1.120.0
20
+
21
+ ### Minor Changes
22
+
23
+ - 6ad72e8d: ZERO-4032: Add loading state management for payment submissions across multiple components and add safe guarding
24
+
25
+ ## 1.119.0
26
+
27
+ ## 1.118.0
28
+
29
+ ## 1.117.0
30
+
31
+ ## 1.116.0
32
+
33
+ ## 1.115.0
34
+
35
+ ## 1.114.0
36
+
37
+ ## 1.113.0
38
+
39
+ ## 1.112.0
40
+
41
+ ## 1.111.0
42
+
43
+ ## 1.110.0
44
+
45
+ ## 1.109.0
46
+
47
+ ## 1.108.0
48
+
49
+ ## 1.107.0
50
+
51
+ ## 1.106.0
52
+
53
+ ## 1.105.0
54
+
55
+ ## 1.104.0
56
+
57
+ ## 1.103.0
58
+
59
+ ## 1.102.0
60
+
61
+ ## 1.101.0
62
+
63
+ ## 1.100.0
64
+
65
+ ## 1.99.0
66
+
67
+ ### Minor Changes
68
+
69
+ - d58538b: ZERO-3638: Enhance RC pipeline: add fetch, merge, and pre-release setup with conditional commit
70
+
71
+ ## 1.98.0
72
+
73
+ ## 1.97.0
74
+
75
+ ## 1.96.0
76
+
77
+ ## 1.95.0
78
+
79
+ ## 1.94.0
80
+
81
+ ## 1.93.0
82
+
83
+ ## 1.92.0
84
+
85
+ ## 1.91.0
86
+
87
+ ## 1.90.0
6
88
 
7
89
  ### Minor Changes
8
90
 
9
- - ZERO-3091: Upgrade Next.js to v15 and React to v19
91
+ - 1044bce: ZERO-3379: Add custom UI rendering support
92
+
93
+ ## 1.89.0
94
+
95
+ ## 1.88.0
96
+
97
+ ## 1.87.0
98
+
99
+ ## 1.86.0
100
+
101
+ ## 1.85.0
102
+
103
+ ## 1.84.0
104
+
105
+ ### Minor Changes
106
+
107
+ - 624a4eb: ZERO-3276: Update installation instructions across multiple README files to standardize format and improve clarity
108
+
109
+ ## 1.83.0
110
+
111
+ ## 1.82.0
112
+
113
+ ## 1.81.0
114
+
115
+ ## 1.80.0
116
+
117
+ ## 1.79.0
10
118
 
11
- ## 2.0.0-beta.0
119
+ ## 1.78.0
12
120
 
13
- ### Major Changes
121
+ ## 1.77.0
14
122
 
15
- - be6c09d: ZERO-3114: Create beta version.
123
+ ## 1.76.0
16
124
 
17
125
  ## 1.75.0
18
126
 
package/package.json CHANGED
@@ -1,19 +1,19 @@
1
1
  {
2
2
  "name": "@akinon/pz-bkm",
3
- "version": "2.0.0-beta.2",
3
+ "version": "2.0.0-beta.20",
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.4",
15
+ "react-dom": "^19.2.4",
16
+ "typescript": "5.2.2"
17
17
  },
18
18
  "dependencies": {
19
19
  "@hookform/resolvers": "2.9.0",
package/readme.md CHANGED
@@ -1,17 +1,50 @@
1
1
  # @akinon/pz-bkm
2
2
 
3
- ### Install the npm package
3
+ ## Installation method
4
+
5
+ You can use the following command to install the extension with the latest plugins:
4
6
 
5
7
  ```bash
6
- # For latest version
7
- yarn add @akinon/pz-bkm
8
8
 
9
- # Preferred installation method
10
9
  npx @akinon/projectzero@latest --plugins
10
+
11
+ ```
12
+
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
11
45
  ```
12
46
 
13
- ### Example Usage
14
- ##### File Path: src/views/checkout/steps/payment/options/bkm.tsx
47
+ #### Default Usage
15
48
 
16
49
  ```javascript
17
50
  const Bkm = () => {
@@ -32,8 +65,53 @@ const Bkm = () => {
32
65
  export default Bkm;
33
66
  ```
34
67
 
35
- ### Props
36
- | Property | Type | Description |
37
- |----------------|-----------|--------------------------------------------------|
38
- | `translations` | `object` | Object containing translation strings. |
39
- | `classes` | `object` | Object containing custom CSS class names. |
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>
103
+
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>