import { yupResolver } from '@hookform/resolvers/yup'; import clsx from 'clsx'; import { useEffect, useState } from 'react'; import { SubmitHandler, useForm } from 'react-hook-form'; import { useAppSelector } from '@akinon/next/redux/hooks'; import { RootState } from '@theme/redux/store'; import { useCompleteCreditCardPaymentMutation, useSetBinNumberMutation } from '@akinon/next/data/client/checkout'; import { CreditCardForm } from '@theme/types'; import { Button, Icon, Input, Select } from '@theme/components'; import * as yup from 'yup'; import CheckoutAgreements from '../../agreements'; import PaymentHeader from '../../payment-header'; import CreditCardInstallments from './installments'; import { useLocalization } from '@akinon/next/hooks'; import { Image } from '@akinon/next/components/image'; import { getPosError, checkPaymentWillRedirect } from '@akinon/next/utils'; import PluginModule, { Component } from '@akinon/next/components/plugin-module'; import { partAttrs } from '@akinon/pz-theme/src/utils/part-styles'; import { PaymentOption } from '@akinon/next/types'; const creditCardFormSchema = ( t, payment_option: PaymentOption, isMasterpassDirectPurchase?: boolean, isMasterpassCvcRequired?: boolean ) => { if ( payment_option?.payment_type === 'masterpass' && isMasterpassDirectPurchase === false ) { return yup.object().shape({ card_cvv: yup .string() .transform((value: string) => value.replace(/_/g, '').replace(/ /g, '')) .when('*', (_, schema) => { if (isMasterpassCvcRequired) { return schema .length( 3, t('checkout.payment.credit_card.form.error.cvv_length') ) .required(t('checkout.payment.credit_card.form.error.required')); } return schema; }), agreement: yup .boolean() .oneOf([true], t('checkout.payment.credit_card.form.error.required')) }); } return yup.object().shape({ card_holder: yup .string() .required(t('checkout.payment.credit_card.form.error.required')) .matches( /^[a-zA-ZğüşöçıİĞÜŞÖÇ\s]+$/, t('checkout.payment.credit_card.form.error.card_holder_matches') ), card_number: yup .string() .transform((value: string) => value.replace(/_/g, '').replace(/ /g, '')) .length( 16, t('checkout.payment.credit_card.form.error.card_number_length') ) .required(t('checkout.payment.credit_card.form.error.required')), card_month: yup .string() .required(t('checkout.payment.credit_card.form.error.required')), card_year: yup .string() .required(t('checkout.payment.credit_card.form.error.required')), card_cvv: yup .string() .transform((value: string) => value.replace(/_/g, '').replace(/ /g, '')) .length(3, t('checkout.payment.credit_card.form.error.cvv_length')) .required(t('checkout.payment.credit_card.form.error.required')), installment: yup .number() .required(t('checkout.payment.credit_card.form.error.installment')), agreement: yup .boolean() .oneOf([true], t('checkout.payment.credit_card.form.error.required')) }); }; const CheckoutCreditCard = () => { const { installment, payment_option } = useAppSelector( (state: RootState) => state.checkout.preOrder ); const { cardType } = useAppSelector((state: RootState) => state.checkout); const masterpass = useAppSelector((state: RootState) => state.masterpass); const { t } = useLocalization(); const { register, handleSubmit, setValue: setFormValue, trigger: validateInput, control, formState: { errors, isSubmitting }, setError, getValues, clearErrors } = useForm({ resolver: yupResolver( creditCardFormSchema( t, payment_option, masterpass?.isDirectPurchase, masterpass?.cvcRequired ) ) }); const [months, setMonths] = useState([]); const [years, setYears] = useState([]); const [formError, setFormError] = useState(null); const [cardBinNumber, setCardBinNumber] = useState(null); const [isProcessing, setIsProcessing] = useState(false); const [setBinNumber] = useSetBinNumberMutation(); const [completeCreditCardPayment, { isLoading: isCompletingPayment }] = useCompleteCreditCardPaymentMutation(); const isButtonDisabled = isSubmitting || isCompletingPayment || isProcessing; const handleCardNumberChange = (value) => { const binNumber = value.replace(/\D/g, '').substring(0, 6); if (binNumber.length === 6) { if (cardBinNumber !== binNumber) { setBinNumber(binNumber); setCardBinNumber(binNumber); } } else if (cardBinNumber && binNumber.length < 6) { setCardBinNumber(null); } }; const onSubmit: SubmitHandler = async (data) => { if (isButtonDisabled) return; setIsProcessing(true); try { const response = await completeCreditCardPayment(data).unwrap(); setFormError(response?.errors); if (response?.errors || !checkPaymentWillRedirect(response)) { setIsProcessing(false); } } catch (error) { setIsProcessing(false); } }; useEffect(() => { const posErrors = getPosError(); if (posErrors) { setFormError(posErrors); } const months = [ { label: t('checkout.payment.credit_card.form.month.placeholder'), value: '' } ]; const years = [ { label: t('checkout.payment.credit_card.form.year.placeholder'), value: '' } ]; const date = new Date(); const currentYear = date.getFullYear(); for (let i = 1; i <= 12; i++) { months.push({ label: i.toString(), value: i.toString() }); } for (let i = currentYear; i < currentYear + 13; i++) { years.push({ label: i.toString(), value: i.toString() }); } setMonths(months); setYears(years); }, []); // eslint-disable-line react-hooks/exhaustive-deps useEffect(() => { if (installment?.pk) { setFormValue('installment', installment?.pk); validateInput('installment'); } }, [installment?.pk, setFormValue, validateInput]); useEffect(() => { Object.keys(formError ?? {}) .filter((key) => key !== 'non_field_errors') .forEach((item: keyof CreditCardForm) => { setError(item, { type: 'custom', message: formError[item].join(', ') }); }); }, [formError, setError]); return (
{(payment_option?.payment_type === 'credit_card' || (payment_option?.payment_type === 'masterpass' && masterpass?.isDirectPurchase)) && ( <>
{t('checkout.payment.credit_card.description')}
{t( 'checkout.payment.credit_card.form.card_number.placeholder' )} {cardType?.logo && cardBinNumber && ( bankLogo )}
{ const { value } = values; handleCardNumberChange(value); }} {...register('card_number')} error={errors.card_number} data-testid="checkout-credit-card-number" />
{t( 'checkout.payment.credit_card.form.security_code.cvc' )}
{/* TODO: Fix this */} Cvv
)}
{formError?.non_field_errors && (
{formError.non_field_errors}
)} {formError?.status && (
{formError.status}
)}
); }; export default CheckoutCreditCard;