'use client'; import * as yup from 'yup'; import { ObjectSchema } from 'yup'; import { yupResolver } from '@hookform/resolvers/yup'; import { useForm } from 'react-hook-form'; import { FormHTMLAttributes, HTMLAttributes, ReactElement, useEffect, useMemo, useState } from 'react'; import { useAppSelector } from '@akinon/next/redux/hooks'; import { useCompleteSavedCardMutation, useSetSavedCardMutation } from '../redux/api'; import { AgreementAndSubmitProps, CardFormSectionProps, ErrorTexts, InstallmentSectionProps, IyzicoSavedCardOptionTexts, IyzicoSavedCardsProps } from '../types'; import { InstallmentSection } from '../components/installment-section'; import { AgreementAndSubmit } from '../components/agreement-and-submit'; import { CardFormSection } from '../components/card-form-section'; import Script from 'next/script'; type IyzicoSavedCardOptionProps = { texts?: IyzicoSavedCardOptionTexts; agreementCheckbox?: ReactElement; customFormSchema?: { 'new-card'?: ObjectSchema; 'existing-card'?: ObjectSchema; }; customRender?: { cardFormSection?: (props: CardFormSectionProps) => ReactElement; savedCardsSection?: (props: IyzicoSavedCardsProps) => ReactElement; installmentSection?: (props: InstallmentSectionProps) => ReactElement; agreementAndSubmit?: (props: AgreementAndSubmitProps) => ReactElement; }; formWrapperClassName?: string; cardSelectionWrapperClassName?: string; installmentWrapperClassName?: string; formProps?: FormHTMLAttributes; cardSelectionWrapperProps?: HTMLAttributes; installmentWrapperProps?: HTMLAttributes; }; const defaultTranslations: IyzicoSavedCardOptionTexts = { title: 'Pay with Iyzico', button: 'Complete Payment', installment: { title: 'Installment Options' }, errors: { required: 'This field is required', cardNumberLength: 'Card number must be 16 digits long.', cvvLength: 'CVV must be 3 digits long.', cardHolderMatches: 'Please enter a valid name', saveCardRequired: 'Please select the Save My Card option' }, label: { cardHolder: 'Cardholder Name', cardNumber: 'Card Number', expiryDate: 'Expiration Date', cvv: 'CVV', saveCardForFuture: 'Save this card for future payments' }, placeholder: { cardHolder: 'Name on Card', cardMonth: 'Month', cardYear: 'Year' }, savedCardsTitle: 'Select from your saved cards:', paymentErrorMessage: 'An error occurred while processing your payment' }; const mergeTranslations = ( customTranslations: IyzicoSavedCardOptionTexts, defaultTranslations: IyzicoSavedCardOptionTexts ) => { return { ...defaultTranslations, ...customTranslations, installment: { ...defaultTranslations.installment, ...customTranslations.installment }, errors: { ...defaultTranslations.errors, ...customTranslations.errors }, label: { ...defaultTranslations.label, ...customTranslations.label }, placeholder: { ...defaultTranslations.placeholder, ...customTranslations.placeholder } }; }; const createFormSchema = ( errors: ErrorTexts, type: 'existing-card' | 'new-card' ) => { const baseSchema = { agreement: yup .boolean() .oneOf([true], errors?.required ?? defaultTranslations.errors.required), register_consumer_card: yup.boolean().default(false) }; if (type === 'new-card') { return yup.object().shape({ ...baseSchema, card_holder: yup .string() .required(errors?.required ?? defaultTranslations.errors.required) .matches( /^[a-zA-ZğüşöçıİĞÜŞÖÇ\s]+$/, errors?.cardHolderMatches ?? defaultTranslations.errors.cardHolderMatches ), card_number: yup .string() .transform((value: string) => value.replace(/_/g, '').replace(/ /g, '')) .length( 16, errors?.cardNumberLength ?? defaultTranslations.errors.cardNumberLength ) .required(errors?.required ?? defaultTranslations.errors.required), card_month: yup .string() .required(errors?.required ?? defaultTranslations.errors.required), card_year: yup .string() .required(errors?.required ?? defaultTranslations.errors.required), card_cvv: yup .string() .transform((value: string) => value.replace(/_/g, '').replace(/ /g, '')) .length(3, errors?.cvvLength ?? defaultTranslations.errors.cvvLength) .required(errors?.required ?? defaultTranslations.errors.required) }); } return yup.object().shape(baseSchema); }; const IyzicoSavedCardOption = ({ texts = defaultTranslations, agreementCheckbox, customFormSchema, customRender, formWrapperClassName = 'flex flex-wrap w-full', cardSelectionWrapperClassName = 'w-full flex flex-col xl:w-6/10', installmentWrapperClassName = 'w-full xl:w-4/10 xl:border-l xl:border-t-0', formProps = {}, cardSelectionWrapperProps = {}, installmentWrapperProps = {} }: IyzicoSavedCardOptionProps) => { const mergedTexts = useMemo( () => mergeTranslations(texts, defaultTranslations), [texts] ); const [completeSavedCard] = useCompleteSavedCardMutation(); const [setSavedCard] = useSetSavedCardMutation(); const installmentOptions = useAppSelector( (state) => state.checkout.installmentOptions ); const ucs = useAppSelector((state) => state.savedCard.ucs); const [type, setType] = useState<'new-card' | 'existing-card'>('new-card'); const [months, setMonths] = useState([]); const [years, setYears] = useState([]); const [formError, setFormError] = useState(null); const getFormSchema = () => { if (customFormSchema?.[type]) { return customFormSchema[type]; } return createFormSchema(mergedTexts.errors, type); }; const { register, handleSubmit, control, formState: { errors, isSubmitting }, setValue: setFormValue } = useForm({ resolver: yupResolver(getFormSchema()) as any }); const onSubmit = async (data) => { if (isSubmitting) return; if (!window.iyziUcsInit) { return; } setFormError(null); try { if (type === 'existing-card') { const res = await completeSavedCard({ agreement: data.agreement, consumer_token: window.universalCardStorage.consumerToken, card_token: window.universalCardStorage.cardToken, register_consumer_card: true }); if ('data' in res && res.data?.errors) { setFormError(res.data.errors); } } else { const res = await completeSavedCard({ agreement: data.agreement, card_holder: data.card_holder, card_number: data.card_number.replaceAll(' ', ''), card_month: data.card_month, card_year: data.card_year, card_cvv: data.card_cvv, register_consumer_card: data.register_consumer_card || false }); if ('data' in res && res.data?.errors) { setFormError(res.data.errors); } } } catch (error) { console.error('Error completing saved card:', error); setFormError({ non_field_errors: mergedTexts.paymentErrorMessage ?? defaultTranslations.paymentErrorMessage }); } }; const ucsScript = ucs?.script && (