@akinon/pz-credit-payment 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. package/.prettierrc +13 -0
  2. package/package.json +20 -0
  3. package/src/index.tsx +162 -0
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,20 @@
1
+ {
2
+ "name": "@akinon/pz-credit-payment",
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": "^4.7.4",
17
+ "react-hook-form": "7.31.3",
18
+ "@hookform/resolvers": "2.9.0"
19
+ }
20
+ }
package/src/index.tsx ADDED
@@ -0,0 +1,162 @@
1
+
2
+ import React from 'react';
3
+ import { yupResolver } from '@hookform/resolvers/yup';
4
+ import { useEffect, useState } from 'react';
5
+ import { SubmitHandler, useForm } from 'react-hook-form';
6
+ import { useAppSelector } from '@akinon/next/redux/hooks';
7
+ import { RootState } from 'redux/store';
8
+ import { Button, Icon, Radio } from '@akinon/next/components';
9
+ import * as yup from 'yup';
10
+ import clsx from 'clsx';
11
+ import { twMerge } from 'tailwind-merge';
12
+ import {
13
+ useSetCreditPaymentOptionMutation,
14
+ useConfirmationCreditPaymentMutation
15
+ } from '@akinon/next/data/client/checkout';
16
+
17
+ interface CreditPaymentTranslationsProps {
18
+ title: string;
19
+ buttonName: string;
20
+ requiredFieldMessage: string;
21
+ }
22
+
23
+ const defaultTranslations = {
24
+ title: 'SHOPPING CREDIT',
25
+ buttonName: 'Place Order',
26
+ requiredFieldMessage: 'This field is required'
27
+ };
28
+
29
+ export interface CreditPaymentProps {
30
+ translations: Record<string, CreditPaymentTranslationsProps>;
31
+ agreementCheckbox: React.ReactElement;
32
+ titleClassName?: string;
33
+ buttonClassName?: string;
34
+ }
35
+
36
+ const creditPaymentFormSchema = (requiredFieldMessage) =>
37
+ yup.object().shape({
38
+ agreement: yup.boolean().oneOf([true], requiredFieldMessage)
39
+ });
40
+
41
+ export const CreditPayment = (
42
+ {
43
+ translations,
44
+ agreementCheckbox,
45
+ titleClassName,
46
+ buttonClassName
47
+ }: CreditPaymentProps
48
+ ) => {
49
+ const _translations = {
50
+ ...defaultTranslations,
51
+ ...translations
52
+ };
53
+
54
+ const {
55
+ handleSubmit,
56
+ control,
57
+ register,
58
+ formState: { errors }
59
+ } = useForm({
60
+ resolver: yupResolver(creditPaymentFormSchema(_translations.requiredFieldMessage))
61
+ });
62
+ const [formError, setFormError] = useState<string | null>(null);
63
+
64
+ const [setCreditPaymentOption] = useSetCreditPaymentOptionMutation();
65
+ const [confirmationCreditPayment] = useConfirmationCreditPaymentMutation();
66
+
67
+ const { creditPaymentOptions, selectedCreditPaymentPk, preOrder } = useAppSelector(
68
+ (state: RootState) => state.checkout
69
+ );
70
+
71
+ const onSubmit: SubmitHandler<any> = async () => {
72
+ const response = await confirmationCreditPayment().unwrap();
73
+
74
+ if(response?.errors?.non_field_errors) {
75
+ setFormError(response?.errors?.non_field_errors);
76
+ return;
77
+ }
78
+ };
79
+
80
+ useEffect(() => {
81
+ if (creditPaymentOptions?.length && !preOrder.credit_payment_option) {
82
+ setCreditPaymentOption(creditPaymentOptions[0].pk);
83
+ }
84
+ }, [creditPaymentOptions, selectedCreditPaymentPk, preOrder.credit_payment_option, setCreditPaymentOption]);
85
+
86
+ return (
87
+ <form className="flex flex-col w-full" onSubmit={handleSubmit(onSubmit)}>
88
+ <div className={clsx(
89
+ twMerge(
90
+ 'flex justify-start items-center border-solid border-gray-400 px-4 py-2 sm:px-6 sm:py-3 sm:min-h-15',
91
+ 'text-black-800 text-lg font-medium sm:text-2xl',
92
+ titleClassName
93
+ )
94
+ )}>
95
+ {_translations.title}
96
+ </div>
97
+
98
+ <div className="border-t border-solid border-gray-400 px-4 sm:px-6">
99
+ {creditPaymentOptions.map((bank) => (
100
+ <div
101
+ key={`bank-account-${bank.pk}`}
102
+ className="w-full border-b border-solid border-gray-400 py-4"
103
+ >
104
+ <label className="w-full flex items-center justify-start">
105
+ <Radio
106
+ type="radio"
107
+ value={bank.pk}
108
+ checked={bank.pk === selectedCreditPaymentPk || preOrder.credit_payment_option?.pk === bank.pk}
109
+ {...register('paymentType')}
110
+ onChange={() => {
111
+ setCreditPaymentOption(bank.pk);
112
+ }}
113
+ data-testid={`checkout-bank-account-${bank.pk}`}
114
+ ></Radio>
115
+
116
+ <span className="w-full flex items-start justify-start flex-col pl-3">
117
+ {bank.name}
118
+ </span>
119
+ </label>
120
+ </div>
121
+ ))}
122
+ </div>
123
+
124
+ <div className="px-4 sm:px-6">
125
+ <div className="flex items-start flex-col py-4 space-y-4">
126
+ {agreementCheckbox &&
127
+ React.cloneElement(agreementCheckbox, {
128
+ control,
129
+ error: errors.agreement,
130
+ fieldId: 'agreement'
131
+ })}
132
+
133
+ {formError && (
134
+ <div className="w-full text-xs text-start px-1 mt-3 text-error">
135
+ {formError}
136
+ </div>
137
+ )}
138
+
139
+ <Button
140
+ type="submit"
141
+ data-testid="checkout-bank-account-place-order"
142
+ className={clsx(
143
+ twMerge(
144
+ 'group uppercase mt-4 inline-flex items-center justify-center w-full',
145
+ buttonClassName
146
+ )
147
+ )}
148
+ >
149
+ <span>{_translations.buttonName}</span>
150
+
151
+ <Icon
152
+ name="chevron-end"
153
+ size={12}
154
+ className="fill-primary-foreground ml-2 h-3 group-hover:fill-primary"
155
+ />
156
+ </Button>
157
+ </div>
158
+ </div>
159
+ </form>
160
+ );
161
+ };
162
+