Untitled
unknown
plain_text
a year ago
13 kB
9
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