diff --git a/assets/icons/paymenticon.svg b/assets/icons/paymenticon.svg new file mode 100644 index 0000000..7c0d9a0 --- /dev/null +++ b/assets/icons/paymenticon.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/components/Dashboard/Finance/FinanceOverview.jsx b/src/components/Dashboard/Finance/FinanceOverview.jsx index 5df8e4c..0e6be74 100644 --- a/src/components/Dashboard/Finance/FinanceOverview.jsx +++ b/src/components/Dashboard/Finance/FinanceOverview.jsx @@ -13,7 +13,8 @@ const FinanceOverview = () => { const [collapseState, updateCollapseState] = useCollapseState( 'FinanceOverview', { - invoiceStats: true + invoiceStats: true, + paymentStats: true } ) @@ -41,6 +42,7 @@ const FinanceOverview = () => { } className='no-t-padding-collapse' collapseKey='invoiceStats' + canCollapse={false} > { + + updateCollapseState('paymentStats', isActive) + } + className='no-t-padding-collapse' + collapseKey='paymentStats' + canCollapse={false} + > + + + + @@ -58,4 +80,3 @@ const FinanceOverview = () => { } export default FinanceOverview - diff --git a/src/components/Dashboard/Finance/FinanceSidebar.jsx b/src/components/Dashboard/Finance/FinanceSidebar.jsx index 7f763da..1c4e032 100644 --- a/src/components/Dashboard/Finance/FinanceSidebar.jsx +++ b/src/components/Dashboard/Finance/FinanceSidebar.jsx @@ -1,6 +1,7 @@ import { useLocation } from 'react-router-dom' import DashboardSidebar from '../common/DashboardSidebar' import InvoiceIcon from '../../Icons/InvoiceIcon' +import PaymentIcon from '../../Icons/PaymentIcon' import FinanceIcon from '../../Icons/FinanceIcon' const items = [ @@ -16,12 +17,19 @@ const items = [ label: 'Invoices', icon: , path: '/dashboard/finance/invoices' + }, + { + key: 'payments', + label: 'Payments', + icon: , + path: '/dashboard/finance/payments' } ] const routeKeyMap = { '/dashboard/finance/overview': 'overview', - '/dashboard/finance/invoices': 'invoices' + '/dashboard/finance/invoices': 'invoices', + '/dashboard/finance/payments': 'payments' } const FinanceSidebar = (props) => { @@ -43,4 +51,3 @@ const FinanceSidebar = (props) => { } export default FinanceSidebar - diff --git a/src/components/Dashboard/Finance/Invoices/AcknowledgeInvoice.jsx b/src/components/Dashboard/Finance/Invoices/AcknowledgeInvoice.jsx new file mode 100644 index 0000000..362ceb4 --- /dev/null +++ b/src/components/Dashboard/Finance/Invoices/AcknowledgeInvoice.jsx @@ -0,0 +1,47 @@ +import { useState, useContext } from 'react' +import PropTypes from 'prop-types' +import { ApiServerContext } from '../../context/ApiServerContext' +import { message } from 'antd' +import MessageDialogView from '../../common/MessageDialogView.jsx' + +const AcknowledgeInvoice = ({ onOk, objectData }) => { + const [acknowledgeLoading, setAcknowledgeLoading] = useState(false) + const { sendObjectFunction } = useContext(ApiServerContext) + + const handleAcknowledge = async () => { + setAcknowledgeLoading(true) + try { + const result = await sendObjectFunction( + objectData._id, + 'Invoice', + 'acknowledge' + ) + if (result) { + message.success('Invoice acknowledged successfully') + onOk(result) + } + } catch (error) { + console.error('Error acknowledging invoice:', error) + } finally { + setAcknowledgeLoading(false) + } + } + + return ( + + ) +} + +AcknowledgeInvoice.propTypes = { + onOk: PropTypes.func.isRequired, + objectData: PropTypes.object +} + +export default AcknowledgeInvoice + diff --git a/src/components/Dashboard/Finance/Invoices/InvoiceInfo.jsx b/src/components/Dashboard/Finance/Invoices/InvoiceInfo.jsx index c66d4e0..b376e2e 100644 --- a/src/components/Dashboard/Finance/Invoices/InvoiceInfo.jsx +++ b/src/components/Dashboard/Finance/Invoices/InvoiceInfo.jsx @@ -29,6 +29,8 @@ import { import OrderItemIcon from '../../../Icons/OrderItemIcon.jsx' import ShipmentIcon from '../../../Icons/ShipmentIcon.jsx' import PostInvoice from './PostInvoice.jsx' +import AcknowledgeInvoice from './AcknowledgeInvoice.jsx' +import NewPayment from '../Payments/NewPayment.jsx' const log = loglevel.getLogger('InvoiceInfo') log.setLevel(config.logLevel) @@ -42,6 +44,7 @@ const InvoiceInfo = () => { info: true, invoiceOrderItems: true, invoiceShipments: true, + payments: true, notes: true, auditLogs: true }) @@ -55,6 +58,8 @@ const InvoiceInfo = () => { objectData: {} }) const [postInvoiceOpen, setPostInvoiceOpen] = useState(false) + const [acknowledgeInvoiceOpen, setAcknowledgeInvoiceOpen] = useState(false) + const [newPaymentOpen, setNewPaymentOpen] = useState(false) const actions = { reload: () => { @@ -80,6 +85,14 @@ const InvoiceInfo = () => { post: () => { setPostInvoiceOpen(true) return true + }, + acknowledge: () => { + setAcknowledgeInvoiceOpen(true) + return true + }, + newPayment: () => { + setNewPaymentOpen(true) + return true } } @@ -113,6 +126,7 @@ const InvoiceInfo = () => { { key: 'info', label: 'Invoice Information' }, { key: 'invoiceOrderItems', label: 'Invoice Order Items' }, { key: 'invoiceShipments', label: 'Invoice Shipments' }, + { key: 'payments', label: 'Payments' }, { key: 'notes', label: 'Notes' }, { key: 'auditLogs', label: 'Audit Logs' } ]} @@ -205,6 +219,7 @@ const InvoiceInfo = () => { isEditing={isEditing} objectData={objectData} loading={loading} + size='medium' /> { isEditing={isEditing} objectData={objectData} loading={loading} + size='medium' /> )} + } + active={collapseState.payments} + onToggle={(expanded) => updateCollapseState('payments', expanded)} + collapseKey='payments' + > + {objectFormState.loading ? ( + + ) : ( + + )} + } @@ -278,6 +311,46 @@ const InvoiceInfo = () => { objectData={objectFormState.objectData} /> + { + setAcknowledgeInvoiceOpen(false) + }} + width={515} + footer={null} + destroyOnHidden={true} + centered={true} + > + { + setAcknowledgeInvoiceOpen(false) + actions.reload() + }} + objectData={objectFormState.objectData} + /> + + { + setNewPaymentOpen(false) + }} + destroyOnHidden={true} + > + { + setNewPaymentOpen(false) + actions.reload() + }} + reset={newPaymentOpen} + defaultValues={{ + invoice: { ...objectFormState.objectData }, + amount: objectFormState.objectData?.grandTotalAmount + }} + /> + ) } diff --git a/src/components/Dashboard/Finance/Payments.jsx b/src/components/Dashboard/Finance/Payments.jsx new file mode 100644 index 0000000..35fcad9 --- /dev/null +++ b/src/components/Dashboard/Finance/Payments.jsx @@ -0,0 +1,99 @@ +import { useState, useRef } from 'react' +import { Button, Flex, Space, Dropdown, Modal } from 'antd' +import NewPayment from './Payments/NewPayment' +import ObjectTable from '../common/ObjectTable' +import PlusIcon from '../../Icons/PlusIcon' +import ReloadIcon from '../../Icons/ReloadIcon' +import useColumnVisibility from '../hooks/useColumnVisibility' +import GridIcon from '../../Icons/GridIcon' +import ListIcon from '../../Icons/ListIcon' +import useViewMode from '../hooks/useViewMode' +import ColumnViewButton from '../common/ColumnViewButton' + +const Payments = () => { + const [newPaymentOpen, setNewPaymentOpen] = useState(false) + const tableRef = useRef() + + const [viewMode, setViewMode] = useViewMode('payments') + + const [columnVisibility, setColumnVisibility] = + useColumnVisibility('payments') + + const actionItems = { + items: [ + { + label: 'New Payment', + key: 'newPayment', + icon: + }, + { type: 'divider' }, + { + label: 'Reload List', + key: 'reloadList', + icon: + } + ], + onClick: ({ key }) => { + if (key === 'reloadList') { + tableRef.current?.reload() + } else if (key === 'newPayment') { + setNewPaymentOpen(true) + } + } + } + + return ( + <> + + + + + + + + + +