@akinon/pz-gpay 2.0.0-beta.10 → 2.0.0-beta.11
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 +6 -0
- package/package.json +1 -1
- package/readme.md +42 -7
- package/src/views/gpay-option.tsx +78 -48
package/CHANGELOG.md
CHANGED
package/package.json
CHANGED
package/readme.md
CHANGED
@@ -28,7 +28,26 @@ const GPay = () => {
|
|
28
28
|
'Click the button below to pay for your order using GarantiPay.',
|
29
29
|
button: 'Pay Now'
|
30
30
|
},
|
31
|
-
|
31
|
+
containerClassName: 'bg-gray-50 rounded-md',
|
32
|
+
titleClassName: 'text-2xl font-bold',
|
33
|
+
descriptionClassName: 'text-sm',
|
34
|
+
buttonClassName: 'bg-primary text-white',
|
35
|
+
customUIRender: ({ handleSubmit, onSubmit, translations }) => (
|
36
|
+
<form onSubmit={handleSubmit(onSubmit)} className="p-6 bg-white">
|
37
|
+
<h2 className="text-xl font-bold mb-2">{translations.title}</h2>
|
38
|
+
<div className="text-sm mb-4">
|
39
|
+
{translations.description.map((item, index) => (
|
40
|
+
<li key={index}>{item}</li>
|
41
|
+
))}
|
42
|
+
</div>
|
43
|
+
<button
|
44
|
+
type="submit"
|
45
|
+
className="w-full h-9 bg-black-300 text-white"
|
46
|
+
>
|
47
|
+
{translations.button}
|
48
|
+
</button>
|
49
|
+
</form>
|
50
|
+
)
|
32
51
|
}}
|
33
52
|
/>
|
34
53
|
);
|
@@ -47,10 +66,26 @@ export default GarantiPayRedirect;
|
|
47
66
|
|
48
67
|
### Props
|
49
68
|
|
50
|
-
| Properties
|
51
|
-
|
|
52
|
-
| translations
|
53
|
-
| containerClassName
|
54
|
-
| titleClassName
|
69
|
+
| Properties | Type | Description |
|
70
|
+
| --- | --- | --- |
|
71
|
+
| translations | object | The translations of the component. |
|
72
|
+
| containerClassName | string | The CSS class to apply to the container. |
|
73
|
+
| titleClassName | string | The CSS class to apply to the title. |
|
55
74
|
| descriptionClassName | string | The CSS class to apply to the description. |
|
56
|
-
| buttonClassName
|
75
|
+
| buttonClassName | string | The CSS class to apply to the button. |
|
76
|
+
| customUIRender | function | Custom render function for the component. Receives form handlers and translations. |
|
77
|
+
|
78
|
+
### Default Translations
|
79
|
+
|
80
|
+
```javascript
|
81
|
+
{
|
82
|
+
title: 'Pay with GarantiPay',
|
83
|
+
description: [
|
84
|
+
'Click on the "GarantiPay" button. Guarantee for payment you will be redirected to the payment page.',
|
85
|
+
'Log in to your account with your username and password on the Garanti Pay page. If you do not have a Garanti Pay membership, create a new membership you can create.',
|
86
|
+
'Complete the payment process by selecting your card and payment type.'
|
87
|
+
],
|
88
|
+
button: 'Pay with GarantiPay',
|
89
|
+
error: 'An error occurred during payment'
|
90
|
+
}
|
91
|
+
```
|
@@ -1,9 +1,16 @@
|
|
1
1
|
'use client';
|
2
2
|
|
3
3
|
import * as yup from 'yup';
|
4
|
-
import { ReactNode, useEffect, useState } from 'react';
|
4
|
+
import { ReactNode, ReactElement, useEffect, useState } from 'react';
|
5
|
+
import {
|
6
|
+
SubmitHandler,
|
7
|
+
useForm,
|
8
|
+
UseFormHandleSubmit,
|
9
|
+
Control,
|
10
|
+
FieldErrors
|
11
|
+
} from 'react-hook-form';
|
5
12
|
import { RootState } from 'redux/store';
|
6
|
-
import {
|
13
|
+
import { yupResolver } from '@hookform/resolvers/yup';
|
7
14
|
import { useAppSelector } from '@akinon/next/redux/hooks';
|
8
15
|
import { useSetPaymentOptionMutation } from '@akinon/next/data/client/checkout';
|
9
16
|
import {
|
@@ -11,39 +18,62 @@ import {
|
|
11
18
|
useSetGPayMethodMutation
|
12
19
|
} from '../endpoints';
|
13
20
|
import { twMerge } from 'tailwind-merge';
|
14
|
-
import { yupResolver } from '@hookform/resolvers/yup';
|
15
21
|
import { Button } from '@akinon/next/components/button';
|
16
22
|
import { getPosError } from '@akinon/next/utils';
|
17
23
|
|
24
|
+
type GPayForm = Record<string, never>;
|
25
|
+
|
18
26
|
const gpayFormSchema = yup.object();
|
19
27
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
}
|
28
|
+
type GPayTranslations = {
|
29
|
+
title: string;
|
30
|
+
description: string[];
|
31
|
+
button: string;
|
32
|
+
error: string;
|
33
|
+
};
|
26
34
|
|
27
|
-
type
|
35
|
+
type GPayOptionProps = {
|
36
|
+
containerClassName?: string;
|
37
|
+
titleClassName?: string;
|
38
|
+
descriptionClassName?: string;
|
39
|
+
buttonClassName?: string;
|
40
|
+
translations?: Partial<GPayTranslations>;
|
41
|
+
customUIRender?: (params: {
|
42
|
+
handleSubmit: UseFormHandleSubmit<GPayForm>;
|
43
|
+
onSubmit: SubmitHandler<GPayForm>;
|
44
|
+
control: Control<GPayForm>;
|
45
|
+
errors: FieldErrors<GPayForm>;
|
46
|
+
translations: GPayTranslations;
|
47
|
+
}) => ReactElement;
|
48
|
+
};
|
28
49
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
50
|
+
const defaultTranslations: GPayTranslations = {
|
51
|
+
title: 'Pay with GarantiPay',
|
52
|
+
description: [
|
53
|
+
'Click on the "Pay with GarantiPay" button. Guarantee for payment you will be redirected to the payment page.',
|
54
|
+
'Log in to your account with your username and password on the Garanti Pay page. If you do not have a Garanti Pay membership, create a new membership you can create.',
|
55
|
+
'Complete the payment process by selecting your card and payment type.'
|
56
|
+
],
|
57
|
+
button: 'Pay with GarantiPay',
|
58
|
+
error: 'An error occurred during payment'
|
35
59
|
};
|
36
60
|
|
37
|
-
export function GPayOption(props:
|
38
|
-
const [formError, setFormError] = useState(null);
|
39
|
-
const [errors, setErrors] = useState([]);
|
61
|
+
export function GPayOption(props: GPayOptionProps) {
|
62
|
+
const [formError, setFormError] = useState<string | null>(null);
|
63
|
+
const [errors, setErrors] = useState<string[]>([]);
|
64
|
+
|
65
|
+
const translations = { ...defaultTranslations, ...props.translations };
|
40
66
|
|
41
67
|
const { preOrder } = useAppSelector((state: RootState) => state.checkout);
|
42
68
|
const isPaymentStepBusy = useAppSelector(
|
43
69
|
(state: RootState) => state.checkout.steps.payment.busy
|
44
70
|
);
|
45
71
|
|
46
|
-
const {
|
72
|
+
const {
|
73
|
+
handleSubmit,
|
74
|
+
control,
|
75
|
+
formState: { errors: formErrors }
|
76
|
+
} = useForm<GPayForm>({
|
47
77
|
resolver: yupResolver(gpayFormSchema)
|
48
78
|
});
|
49
79
|
|
@@ -51,21 +81,19 @@ export function GPayOption(props: GpayOptionProps) {
|
|
51
81
|
const [setGPayMethod] = useSetGPayMethodMutation();
|
52
82
|
const [setCompleteGPay] = useSetCompleteGPayMutation();
|
53
83
|
|
54
|
-
const onSubmit: SubmitHandler<
|
84
|
+
const onSubmit: SubmitHandler<GPayForm> = async () => {
|
55
85
|
if (isPaymentStepBusy) return;
|
56
86
|
|
57
|
-
setFormError(
|
58
|
-
|
87
|
+
setFormError(null);
|
59
88
|
await setGPayMethod();
|
60
89
|
|
61
90
|
const response = await setCompleteGPay().unwrap();
|
62
91
|
|
63
92
|
if (response?.errors?.non_field_errors) {
|
64
|
-
setFormError(response
|
93
|
+
setFormError(response.errors.non_field_errors);
|
65
94
|
}
|
66
95
|
};
|
67
96
|
|
68
|
-
// this is necessary because we need to set the payment_option after the redirect
|
69
97
|
useEffect(() => {
|
70
98
|
const posErrors = getPosError();
|
71
99
|
|
@@ -79,6 +107,16 @@ export function GPayOption(props: GpayOptionProps) {
|
|
79
107
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
80
108
|
}, []);
|
81
109
|
|
110
|
+
if (props.customUIRender) {
|
111
|
+
return props.customUIRender({
|
112
|
+
handleSubmit,
|
113
|
+
onSubmit,
|
114
|
+
control,
|
115
|
+
errors: formErrors,
|
116
|
+
translations
|
117
|
+
});
|
118
|
+
}
|
119
|
+
|
82
120
|
return (
|
83
121
|
<form
|
84
122
|
id="gpay_payment"
|
@@ -86,38 +124,30 @@ export function GPayOption(props: GpayOptionProps) {
|
|
86
124
|
onSubmit={handleSubmit(onSubmit)}
|
87
125
|
>
|
88
126
|
<h1 className={twMerge('text-2xl font-bold', props.titleClassName)}>
|
89
|
-
{
|
127
|
+
{translations.title}
|
90
128
|
</h1>
|
129
|
+
|
91
130
|
<div className={twMerge('text-sm', props.descriptionClassName)}>
|
92
|
-
{
|
93
|
-
|
94
|
-
)
|
95
|
-
<>
|
96
|
-
<li>
|
97
|
-
Click on the “Pay with GarantiPay” button. Guarantee for payment
|
98
|
-
you will be redirected to the payment page.
|
99
|
-
</li>
|
100
|
-
<li>
|
101
|
-
Log in to your account with your username and password on the
|
102
|
-
Garanti Pay page. If you do not have a Garanti Pay membership,
|
103
|
-
create a new membership you can create.
|
104
|
-
</li>
|
105
|
-
<li>
|
106
|
-
Complete the payment process by selecting your card and payment
|
107
|
-
type.
|
108
|
-
</li>
|
109
|
-
</>
|
110
|
-
)}
|
131
|
+
{translations.description.map((item, index) => (
|
132
|
+
<li key={index}>{item}</li>
|
133
|
+
))}
|
111
134
|
</div>
|
112
|
-
|
113
|
-
|
135
|
+
|
136
|
+
<Button
|
137
|
+
data-testid="gpay-payment-button"
|
138
|
+
className={twMerge('w-full mt-3', props.buttonClassName)}
|
139
|
+
type="submit"
|
140
|
+
>
|
141
|
+
{translations.button}
|
114
142
|
</Button>
|
143
|
+
|
115
144
|
{formError && (
|
116
145
|
<div className="w-full text-xs text-start px-1 mt-3 text-error">
|
117
146
|
{formError}
|
118
147
|
</div>
|
119
148
|
)}
|
120
|
-
|
149
|
+
|
150
|
+
{errors.length > 0 && (
|
121
151
|
<div className="w-full text-xs text-start px-1 mt-3 text-error">
|
122
152
|
{errors.map((error) => (
|
123
153
|
<div key={error}>{error}</div>
|