'use client'; import * as yup from 'yup'; import { yupResolver } from '@hookform/resolvers/yup'; import { useForm } from 'react-hook-form'; import React, { ReactElement, useMemo, useState } from 'react'; import { useAppDispatch, useAppSelector } from '@akinon/next/redux/hooks'; import { checkPaymentWillRedirect } from '@akinon/next/utils'; import { useCompleteSavedCardMutation, useSetSavedCardMutation } from '../redux/api'; import amex from '../../assets/img/amex.jpg'; import mastercard from '../../assets/img/mastercard.png'; import other from '../../assets/img/other.png'; import troy from '../../assets/img/troy.png'; import visa from '../../assets/img/visa.png'; import { DeleteConfirmationModal } from '../components/delete-confirmation-modal'; import { AgreementAndSubmitProps, CardSelectionSectionProps, ErrorTexts, InstallmentSectionProps, SavedCardOptionTexts } from '../types'; import { CardSelectionSection } from '../components/card-selection-section'; import { InstallmentSection } from '../components/installment-section'; import { AgreementAndSubmit } from '../components/agreement-and-submit'; export const cardImages = { amex, mastercard, troy, visa, other }; type SavedCardOptionProps = { texts?: SavedCardOptionTexts; agreementCheckbox?: ReactElement; customRender?: { cardSelectionSection?: (props: CardSelectionSectionProps) => ReactElement; installmentSection?: (props: InstallmentSectionProps) => ReactElement; agreementAndSubmit?: (props: AgreementAndSubmitProps) => ReactElement; }; formWrapperClassName?: string; cardSelectionWrapperClassName?: string; installmentWrapperClassName?: string; formProps?: React.FormHTMLAttributes; cardSelectionWrapperProps?: React.HTMLAttributes; installmentWrapperProps?: React.HTMLAttributes; }; const defaultTranslations: SavedCardOptionTexts = { title: 'Pay with Saved Card', button: 'Continue with selected card', installment: { title: 'Installment Options' }, errors: { required: 'This field is required' } }; const mergeTranslations = ( customTranslations: SavedCardOptionTexts, defaultTranslations: SavedCardOptionTexts ) => { return { ...defaultTranslations, ...customTranslations, installment: { ...defaultTranslations.installment, ...customTranslations.installment }, errors: { ...defaultTranslations.errors, ...customTranslations.errors }, deletePopup: { ...defaultTranslations.deletePopup, ...customTranslations.deletePopup } }; }; const createFormSchema = (errors: ErrorTexts) => yup.object().shape({ card: yup .string() .required(errors?.required ?? defaultTranslations.errors.required) .typeError(errors?.required ?? defaultTranslations.errors.required), agreement: yup .boolean() .oneOf([true], errors?.required ?? defaultTranslations.errors.required) }); const SavedCardOption = ({ texts = defaultTranslations, agreementCheckbox, 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 = {} }: SavedCardOptionProps) => { const mergedTexts = useMemo( () => mergeTranslations(texts, defaultTranslations), [texts] ); const dispatch = useAppDispatch(); const [isProcessing, setIsProcessing] = useState(false); const [completeSavedCard, { isLoading: isCompleting }] = useCompleteSavedCardMutation(); const [setSavedCard] = useSetSavedCardMutation(); const installmentOptions = useAppSelector( (state) => state.checkout.installmentOptions ); const cards = useAppSelector((state) => state.savedCard.cards); const { register, handleSubmit, control, formState: { errors, isSubmitting }, setValue, watch } = useForm({ resolver: yupResolver(createFormSchema(mergedTexts.errors)) as any }); const selectedCardToken = watch('card'); const selectedCard = useMemo( () => cards?.find((card) => card.token === selectedCardToken), [cards, selectedCardToken] ); const isButtonDisabled = isSubmitting || isCompleting || isProcessing; const handleCardSelection = async (card) => { await setSavedCard({ card }).unwrap(); setValue('card', card.token, { shouldValidate: true }); }; const onSubmit = async () => { if (isButtonDisabled) return; setIsProcessing(true); try { const response = await completeSavedCard({ agreement: true }).unwrap(); if (response?.errors || !checkPaymentWillRedirect(response)) { setIsProcessing(false); } } catch (error) { setIsProcessing(false); console.error('Error completing saved card:', error); } }; return ( <>
{customRender?.cardSelectionSection ? ( customRender.cardSelectionSection({ title: mergedTexts.title, cards, selectedCard, onSelect: handleCardSelection, register, errors, dispatch }) ) : ( )}
{customRender?.installmentSection ? ( customRender.installmentSection({ title: mergedTexts.installment?.title, installmentOptions, translations: mergedTexts.installment, errors: errors.installment }) ) : ( )} {customRender?.agreementAndSubmit ? ( customRender.agreementAndSubmit({ agreementCheckbox, control, errors, buttonText: mergedTexts.button, isSubmitting: isButtonDisabled }) ) : ( )}
); }; export default SavedCardOption;