@akinon/pz-saved-card 1.67.0 → 1.69.0-rc.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,400 +0,0 @@
1
- 'use client';
2
-
3
- import * as yup from 'yup';
4
- import { cloneElement, ReactElement, useEffect, useState } from 'react';
5
- import { useForm } from 'react-hook-form';
6
- import { useAppDispatch, useAppSelector } from '@akinon/next/redux/hooks';
7
- import {
8
- useSetCompleteSavedCardMutation,
9
- useSetSavedCardMutation
10
- } from '../endpoints';
11
- import { yupResolver } from '@hookform/resolvers/yup';
12
- import Script from 'next/script';
13
- import { resetUcs } from '../redux/reducer';
14
- import { Button, Icon, Image, Input, Select } from '@akinon/next/components';
15
- import SavedCardInstallments from './installments';
16
- import '../types';
17
-
18
- type SavedCardOptionProps = {
19
- texts?: {
20
- title?: string;
21
- button?: string;
22
- installment?: {
23
- title?: string;
24
- payments?: string;
25
- };
26
- label?: {
27
- cardNumber?: string;
28
- expiryDate?: string;
29
- cvv?: string;
30
- };
31
- placeholder?: {
32
- cardNumber?: string;
33
- cardMonth?: string;
34
- cardYear?: string;
35
- cardCvv?: string;
36
- };
37
- errors?: {
38
- required?: string;
39
- cardNumberLength?: string;
40
- cvvLength?: string;
41
- saveCard?: string;
42
- };
43
- };
44
- agreementCheckbox?: ReactElement;
45
- };
46
-
47
- const defaultTranslations: SavedCardOptionProps = {
48
- texts: {
49
- title: 'Pay with Iyzico Saved Card',
50
- button: 'Continue with selected card',
51
- installment: {
52
- title: 'Installment Options'
53
- },
54
- label: {
55
- cardNumber: 'Card Number',
56
- expiryDate: 'Expiration Date',
57
- cvv: 'CVC'
58
- },
59
- placeholder: {
60
- cardMonth: 'Month',
61
- cardYear: 'year'
62
- },
63
- errors: {
64
- required: 'This field is required',
65
- cardNumberLength: 'Card number must be 16 digits long.',
66
- cvvLength: 'CVV must be 3 digits long.',
67
- saveCard:
68
- "Please check the 'Save my card with Iyzico' option to proceed with the payment."
69
- }
70
- }
71
- };
72
-
73
- const formSchema = (translations) => {
74
- return yup.object().shape({
75
- card_number: yup
76
- .string()
77
- .transform((value: string) => value.replace(/_/g, '').replace(/ /g, ''))
78
- .length(
79
- 16,
80
- translations?.cardNumberLength ??
81
- defaultTranslations.texts.errors.cardNumberLength
82
- )
83
- .required(
84
- translations?.required ?? defaultTranslations.texts.errors.required
85
- ),
86
- card_month: yup
87
- .string()
88
- .required(
89
- translations?.required ?? defaultTranslations.texts.errors.required
90
- ),
91
- card_year: yup
92
- .string()
93
- .required(
94
- translations?.required ?? defaultTranslations.texts.errors.required
95
- ),
96
- card_cvv: yup
97
- .string()
98
- .transform((value: string) => value.replace(/_/g, '').replace(/ /g, ''))
99
- .length(
100
- 3,
101
- translations?.cvvLength ?? defaultTranslations.texts.errors.cvvLength
102
- )
103
- .required(
104
- translations?.required ?? defaultTranslations.texts.errors.required
105
- ),
106
- agreement: yup
107
- .boolean()
108
- .oneOf(
109
- [true],
110
- translations?.required ?? defaultTranslations.texts.errors.required
111
- )
112
- });
113
- };
114
-
115
- export function Option(props: SavedCardOptionProps) {
116
- const dispatch = useAppDispatch();
117
- const [formError, setFormError] = useState(null);
118
- const [months, setMonths] = useState([]);
119
- const [years, setYears] = useState([]);
120
- const [installmentOptions, setInstallmentOptions] = useState([]);
121
-
122
- const ucs = useAppSelector((state) => state.saved_card.ucs);
123
- const [setSavedCard] = useSetSavedCardMutation();
124
- const [setCompleteSavedCard] = useSetCompleteSavedCardMutation();
125
-
126
- const {
127
- register,
128
- handleSubmit,
129
- control,
130
- formState: { errors }
131
- } = useForm({
132
- resolver: yupResolver(formSchema(props.texts?.errors))
133
- });
134
-
135
- useEffect(() => {
136
- window.iyziUcsInit?.createTag();
137
-
138
- const months = [
139
- {
140
- label:
141
- props.texts?.placeholder?.cardMonth ??
142
- defaultTranslations.texts.placeholder.cardMonth,
143
- value: ''
144
- }
145
- ];
146
- const years = [
147
- {
148
- label:
149
- props.texts?.placeholder?.cardYear ??
150
- defaultTranslations.texts.placeholder.cardYear,
151
- value: ''
152
- }
153
- ];
154
- const date = new Date();
155
- const currentYear = date.getFullYear();
156
-
157
- for (let i = 1; i <= 12; i++) {
158
- months.push({ label: i.toString(), value: i.toString() });
159
- }
160
-
161
- for (let i = currentYear; i < currentYear + 13; i++) {
162
- years.push({ label: i.toString(), value: i.toString() });
163
- }
164
-
165
- setMonths(months);
166
- setYears(years);
167
- setSavedCard(window.iyziUcsInit.ucsToken).then((res) => {
168
- if (!('data' in res)) {
169
- return;
170
- }
171
-
172
- const installmentContext = res.data?.context_list?.find(
173
- (context) => context.page_name === 'SavedCardInstallmentSelectionPage'
174
- );
175
-
176
- if (installmentContext) {
177
- setInstallmentOptions(installmentContext.page_context.installments);
178
- }
179
- });
180
-
181
- return () => {
182
- dispatch(resetUcs());
183
- };
184
- }, []);
185
-
186
- const onSubmit = async (data) => {
187
- if (!window.iyziUcsInit) {
188
- return;
189
- }
190
-
191
- setFormError({});
192
-
193
- if (window.iyziUcsInit.scriptType === 'CONSUMER_WITH_CARD_EXIST') {
194
- const res = await setCompleteSavedCard({
195
- ucs_token: window.iyziUcsInit.ucsToken,
196
- consumer_token: window.universalCardStorage.consumerToken,
197
- card_token: window.universalCardStorage.cardToken
198
- });
199
-
200
- if ('data' in res && res.data.errors) {
201
- setFormError(res.data.errors);
202
- }
203
- return;
204
- } else {
205
- if (!window.universalCardStorage.registerConsumerCard) {
206
- setFormError({
207
- non_field_errors:
208
- props.texts?.errors?.saveCard ??
209
- defaultTranslations.texts.errors.saveCard
210
- });
211
- return;
212
- }
213
- const res = await setCompleteSavedCard({
214
- agreement: data.agreement,
215
- card_number: data.card_number.replaceAll(' ', ''),
216
- card_month: data.card_month,
217
- card_year: data.card_year,
218
- card_cvv: data.card_cvv,
219
- register_consumer_card: window.universalCardStorage.registerConsumerCard
220
- });
221
-
222
- if ('data' in res && res.data.errors) {
223
- setFormError(res.data.errors);
224
- }
225
- }
226
- };
227
-
228
- const ucsScript = ucs.script && (
229
- <Script
230
- id="saved_card"
231
- strategy="afterInteractive"
232
- dangerouslySetInnerHTML={{ __html: ucs.script }}
233
- />
234
- );
235
-
236
- return (
237
- <>
238
- <form
239
- className="flex flex-row flex-wrap w-full"
240
- onSubmit={handleSubmit(onSubmit)}
241
- >
242
- <div className="w-full flex flex-col xl:w-6/10">
243
- <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">
244
- <span className="text-black-800 text-lg font-medium sm:text-2xl">
245
- {props.texts?.title ?? defaultTranslations.texts.title}
246
- </span>
247
- </div>
248
-
249
- {window.iyziUcsInit?.scriptType === 'UCS_CONSENT' && (
250
- <>
251
- <div className="w-full bg-white">
252
- <div className="px-4 my-2 w-full flex justify-between flex-wrap pb-4 sm:px-6 sm:py-6">
253
- <div className="my-2 w-full flex flex-col sm:px-4">
254
- <div className="text-xs text-gray-800 mb-2 w-full flex justify-between items-center">
255
- <span>
256
- {props.texts?.label?.cardNumber ??
257
- defaultTranslations.texts.label.cardNumber}
258
- </span>
259
- </div>
260
-
261
- <Input
262
- format="#### #### #### ####"
263
- mask="_"
264
- allowEmptyFormatting={true}
265
- control={control}
266
- {...register('card_number')}
267
- error={errors.card_number}
268
- />
269
- </div>
270
-
271
- <div className="w-full my-2 sm:flex">
272
- <div className="sm:w-2/3 sm:px-4">
273
- <label
274
- className="flex w-full text-xs text-start text-black-400 mb-1.5"
275
- htmlFor="card_month"
276
- >
277
- {props.texts?.label?.expiryDate ??
278
- defaultTranslations.texts.label.expiryDate}
279
- </label>
280
-
281
- <div className="flex w-full h-10 space-x-2.5">
282
- <div className="w-2/4">
283
- <Select
284
- className="w-full text-xs border-gray-400 sm:text-sm"
285
- options={months}
286
- {...register('card_month')}
287
- error={errors.card_month}
288
- />
289
- </div>
290
-
291
- <div className="w-2/4">
292
- <Select
293
- className="w-full text-xs border-gray-400 sm:text-sm"
294
- options={years}
295
- {...register('card_year')}
296
- error={errors.card_year}
297
- />
298
- </div>
299
- </div>
300
- </div>
301
- <div className="my-2 sm:w-1/3 sm:px-4 sm:my-0">
302
- <label
303
- className="flex w-full text-xs text-start text-black-400 mb-1.5"
304
- htmlFor="card_cvv"
305
- >
306
- {props.texts?.label?.cvv ??
307
- defaultTranslations.texts.label.cvv}
308
- </label>
309
- <Input
310
- format="###"
311
- mask="_"
312
- control={control}
313
- allowEmptyFormatting={true}
314
- {...register('card_cvv')}
315
- error={errors.card_cvv}
316
- />
317
- <div className="group relative flex items-center justify-start text-gray-600 cursor-pointer mt-2 transition-all hover:text-secondary">
318
- <span className="text-xs underline">
319
- {props.texts?.label?.cvv ??
320
- defaultTranslations.texts.label.cvv}
321
- </span>
322
- <Icon
323
- name="cvc"
324
- size={16}
325
- className="leading-none ml-2"
326
- />
327
- <div className="hidden group-hover:block absolute right-0 bottom-5 w-[11rem] lg:w-[21rem] lg:left-auto lg:right-auto border-2">
328
- <Image
329
- src="/cvv.jpg"
330
- alt="Cvv"
331
- width={385}
332
- height={262}
333
- />
334
- </div>
335
- </div>
336
- </div>
337
- </div>
338
- </div>
339
- </div>
340
- <div id="ucs-permission"></div>
341
- </>
342
- )}
343
- {window.iyziUcsInit?.scriptType !== 'UCS_CONSENT' && (
344
- <div id="ucs-cards"></div>
345
- )}
346
- </div>
347
-
348
- <div className="w-full flex flex-col border-gray-400 border-solid xl:w-4/10 xl:border-l xl:border-t-0">
349
- <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">
350
- <span className="text-black-800 text-lg font-medium sm:text-2xl">
351
- {props.texts?.installment?.title ??
352
- defaultTranslations.texts.installment.title}
353
- </span>
354
- </div>
355
-
356
- <div className="w-full border-solid border-gray-400 bg-white">
357
- <SavedCardInstallments
358
- installmentOptions={installmentOptions}
359
- translations={props.texts?.installment}
360
- error={errors.installment}
361
- />
362
-
363
- <div className="flex flex-col text-xs pb-4 px-4 sm:px-6 sm:pb-6 md:mt-0 mt-4">
364
- {props.agreementCheckbox &&
365
- cloneElement(props.agreementCheckbox, {
366
- control,
367
- error: errors.agreement,
368
- fieldId: 'agreement'
369
- })}
370
- {formError?.non_field_errors && (
371
- <div className="w-full text-xs text-start px-1 mt-3 text-error">
372
- {formError.non_field_errors}
373
- </div>
374
- )}
375
- {formError?.status && (
376
- <div className="w-full text-xs text-start px-1 mt-3 text-error">
377
- {formError.status}
378
- </div>
379
- )}
380
- <Button
381
- className="group uppercase mt-4 inline-flex items-center justify-center"
382
- type="submit"
383
- >
384
- <span>
385
- {props.texts?.button ?? defaultTranslations.texts.button}
386
- </span>
387
- <Icon
388
- name="chevron-end"
389
- size={12}
390
- className="fill-primary-foreground ml-2 h-3 group-hover:fill-primary"
391
- />
392
- </Button>
393
- </div>
394
- </div>
395
- </div>
396
- </form>
397
- {ucsScript}
398
- </>
399
- );
400
- }