Untitled
unknown
plain_text
a year ago
13 kB
4
Indexable
import React, { useState, useEffect } from 'react'; import PropTypes from 'prop-types'; import Button from 'components/common/Button'; import { useSearchParams, withRouter } from 'react-router'; import PaymentOptionCard from './components/PaymentOptionCard'; import useBankPayment from './hooks/useBankPayment'; import useCardProcessor from './hooks/useCardProcessor'; import useInvoice from './hooks/useInvoice'; import { useMobile } from 'services/hooks'; import LoadingSpinner from 'components/common/LoadingSpinner'; import PaymentResult from './components/PaymentResult'; import Header from './components/Header'; import FuseModal from 'components/common/FuseModal'; import TermsContent from './components/TermsContent'; import BankInfoContent from './components/BankInfoContent'; import { formatCurrency } from 'services/currency'; import ReviewInvoice from 'components/Invoices/components/CreateInvoice/ReviewInvoice/ReviewInvoice'; import useEtransfer from './hooks/useEtransfer'; import EtransferContent from './components/EtransferContent'; import './styles/payment.scss'; import Modal from 'components/common/Modal'; import { updateInvoiceStatus, executePayment } from 'services/webApi'; import RejectMessageModalBody from './components/RejectMessageModalBody'; import ClearIcon from '@mui/icons-material/Clear'; import RecurringProfile from '../Invoices/components/CreateInvoice/components/RecurringProfile'; import CreditCard from '@mui/icons-material/CreditCard'; import ComponentAccessControl from 'components/AccessControl/ComponentAccessControl'; import initializePaymentModule from '../PaymentWidget/payment-widget'; import { v4 as uuidv4 } from 'uuid'; import { toast, ToastContainer } from 'react-toastify'; import 'react-toastify/dist/ReactToastify.css'; function Payment({ location, router }) { const invoiceToken = location.query.t || ''; const [view, setView] = useState('paymentPending'); const [isRejectModalOpen, setIsRejectModalOpen] = useState(false); const [isSaveRecurringPaymentInfoModal, setIsSaveRecurringPaymentInfoModal] = useState(false); const [isThankYouModalOpen, setIsThankYouModalOpen] = useState(false); const [isRejectionLoading, setIsRejectionLoading] = useState(false); const [uuid, setUuid] = useState(uuidv4()); const { invoice, isLoading: isInvoiceLoading, error } = useInvoice(invoiceToken, setView); const phase = invoice?.tenant?.tenantPhase || 1; const isRecurring = !!invoice?.salesInvoiceDetail?.recurringInvoice; const { error: cardProcessorError, openPayModal, isModalLoading } = useCardProcessor(setView, invoiceToken, isRecurring, invoice?.salesInvoiceDetail?.recurringInvoice?.Id); const { isEtransferModalOpen, setIsEtransferModalOpen, closeEtransferModal, sendEtransferRequest, isEtransferLoading, etransferError, email, emailName, isEtransferDisabled } = useEtransfer(invoice?.billToBranchInfo?.email, invoice?.billToBranchInfo?.partnerName, setView, invoiceToken); const { isPadAgreementOpen, setIsPadAgreementOpen, proceedToAccountFields, isBankInfoOpen, setIsBankInfoOpen, bankInfoFields, setBankInfoField, isBankPaymentLoading, isBankPaymentDisabled, payWithBankAccount, bankPaymentError } = useBankPayment(setView, invoiceToken, invoice); const isMobile = useMobile(); const [message, setMessage] = useState(''); useEffect(() => { if (!invoiceToken) { router.push('/'); } }, [invoiceToken, router]); useEffect(() => { if (invoice && invoice.payableAmount) { const checkDOMReady = () => { if (document.getElementById('divContainer')) { initializePaymentModule(invoice.payableAmount); } else { setTimeout(checkDOMReady, 100); } }; checkDOMReady(); } }, [invoice]); const rejectInvoice = () => { setIsRejectionLoading(true); updateInvoiceStatus(invoiceToken, true, '', message).then(() => { setView('invoiceRejected'); setIsThankYouModalOpen(true); setIsRejectionLoading(false); }).catch(() => { setView('noInvoice'); setIsRejectionLoading(false); }); setIsRejectModalOpen(false); }; const generateNewOrderId = () => { setUuid(uuidv4()); }; const handlePayment = async () => { generateNewOrderId(); const cardNo = localStorage.getItem('creditCard'); const cvv2 = localStorage.getItem('cvc'); const expiry = localStorage.getItem('expDate'); const orderId = uuid; const amount = Math.round(invoice.payableAmount * 100); const currency = 124; const lang = 'EN'; const ecommerceTxnType = 0; if (!cardNo || !cvv2 || !expiry || !amount) { return; } const expiryParts = expiry.split('/'); const formattedExpiry = expiryParts[1] + expiryParts[0]; const paymentRequest = { cardNo: cardNo, cvv2: cvv2, expiry: formattedExpiry, orderId: orderId, amount: amount, currency: currency, lang: lang, ecommerceTxnType: ecommerceTxnType }; try { const response = await executePayment(paymentRequest); console.log('Full Payment Response:', response.data); // Log the entire response // Safely access the result object const result = response.data?.result; if (!result) { throw new Error('Invalid response structure: No result object found'); } console.log('Result:', result); // Log the result object const resultMessage = result?.resultMessage; console.log('Result Message:', resultMessage); // Log the resultMessage if (!resultMessage) { throw new Error('Invalid response structure: No resultMessage found'); } switch (resultMessage) { case 'Approved': toast.success('Invoice paid', { position: toast.POSITION.TOP_RIGHT, }); break; case 'Invalid card number.': toast.error('Invalid card number.', { position: toast.POSITION.TOP_RIGHT, }); break; case 'Not Approved': toast.error('Expiry date or CVV is wrong', { position: toast.POSITION.TOP_RIGHT, }); break; default: toast.error(resultMessage, { position: toast.POSITION.TOP_RIGHT, }); break; } } catch (error) { console.error('Payment failed:', error); toast.error(`Payment failed: ${error.message}`, { position: toast.POSITION.TOP_RIGHT, }); } }; if (isInvoiceLoading) { return <div className='payment--loading'><LoadingSpinner /></div>; } const invoiceStatus = invoice?.salesInvoiceDetail?.trnStatusDefinition?.parameterValue; const isPaymentPending = invoiceStatus === 'Sent' || invoiceStatus === 'Overdue'; const isPaymentOptionsVisible = (!isRecurring && isPaymentPending) || (isRecurring && invoice?.salesInvoiceDetail?.recurringInvoice?.status !== 'Canceled' && isPaymentPending); return ( <div className='payment'> <ToastContainer /> <Modal isOpen={isRejectModalOpen} headerText="Reject Invoice" headerIcon={<ClearIcon />} flavourText={`Please tell ${invoice?.tenant?.companyName} why you are rejecting the invoice`} onPrimaryClick={rejectInvoice} isPrimaryDelete isPrimaryDisabled={message === ''} primaryLabel="Submit" onClose={() => setIsRejectModalOpen(false)}> <RejectMessageModalBody message={message} setMessage={setMessage} /> </Modal> <Modal isOpen={isSaveRecurringPaymentInfoModal} headerText={<div> <CreditCard style={{ fontSize: '2.5rem' }} /> <div> Save Recurring Payment Information</div> </div>} flavourText={<div> By continuing, your payment information will be saved securely and used for future instances of this recurring invoice. <br /><br /> You can revoke this permission at any time by clicking ‘Reject Invoice’ on the invoice preview page or by contacting the Fuse Financial customer who sent you the invoice. <br /><br /> You can read the full terms and conditions here. </div>} onPrimaryClick={async () => { await sendEtransferRequest(); setIsSaveRecurringPaymentInfoModal(false); }} primaryLabel="I Understand" onClose={() => setIsSaveRecurringPaymentInfoModal(false)} /> <Modal isOpen={isThankYouModalOpen} headerText="Thank You!" headerIcon={<ClearIcon />} flavourText={`The Invoice has been rejected and ${invoice?.tenant?.companyName} has been notified.`} onPrimaryClick={() => setIsThankYouModalOpen(false)} isPrimaryDelete primaryLabel="Close" onClose={() => setIsThankYouModalOpen(false)} /> <Header invoice={invoice} isMobile={isMobile} /> <div className='payment__summary'> {view === 'paymentPending' && invoice && <div className='payment__summary__invoice'> <ReviewInvoice companyLogo={invoice.tenant?.companyLogo} invoiceDetails={invoice?.salesInvoiceDetail} /> </div>} <div className='payment__summary__content'> {view === 'paymentPending' ? ( <React.Fragment> <FuseModal shouldShowHeader isForTermsBlocking isOpen={isPadAgreementOpen} onClose={() => setIsPadAgreementOpen(false)} onPrimaryClick={proceedToAccountFields} > <TermsContent /> </FuseModal> <FuseModal shouldShowHeader isOpen={isBankInfoOpen} onClose={() => setIsBankInfoOpen(false)} primaryLabel='Pay From Account' isPrimaryLoading={isBankPaymentLoading} isPrimaryDisabled={isBankPaymentDisabled} onPrimaryClick={payWithBankAccount} error={bankPaymentError} > <BankInfoContent bankInfoObject={bankInfoFields} onInputChange={setBankInfoField} invoiceAmount={formatCurrency(invoice.payableAmount)} invoiceName={invoice.invoiceNumber.toString()} /> </FuseModal> <FuseModal shouldShowHeader isOpen={isEtransferModalOpen} onClose={() => closeEtransferModal()} primaryLabel='Send Request' isPrimaryLoading={isEtransferLoading} isPrimaryDisabled={isEtransferDisabled} onPrimaryClick={() => { if (invoice?.salesInvoiceDetail?.recurringInvoice) { setIsSaveRecurringPaymentInfoModal(true); } else { sendEtransferRequest(); } }} error={etransferError} > <EtransferContent invoiceAmount={formatCurrency(invoice.payableAmount)} invoiceName={invoice.invoiceNumber.toString()} fieldsObject={{ email, emailName }} /> </FuseModal> {isRecurring && isPaymentOptionsVisible && <RecurringProfile isPaymentPage isRecurring={isRecurring} recurringInvoice={invoice.salesInvoiceDetail.recurringInvoice} reviewInvoice />} {isPaymentOptionsVisible && <React.Fragment> <div id='divContainer' /> <div id='hiddenDiv' style={{ display:`none` }} /> <div className='payment__summary__content__reject_pay'> <Button className="pay-btn" variant='text' onClick={() => handlePayment()} isLoading={isRejectionLoading}> Pay Invoice </Button> <Button className="reject-btn" variant='text' onClick={() => setIsRejectModalOpen(true)} isLoading={isRejectionLoading}> Reject Invoice </Button> </div> </React.Fragment>} {cardProcessorError && <div className='payment__summary__content__error'>{cardProcessorError}</div>} </React.Fragment> ) : ( <PaymentResult variant={view} companyName={invoice?.tenant.companyName} invoiceName={invoice?.invoiceNumber.toString()} /> )} </div> </div> </div> ); } Payment.propTypes = { location: PropTypes.object.isRequired, router: PropTypes.object.isRequired }; export default withRouter(Payment);
Editor is loading...
Leave a Comment