diff --git a/client/src/containers/FinancialStatements/VendorsTransactions/VendorsTransactions.js b/client/src/containers/FinancialStatements/VendorsTransactions/VendorsTransactions.js new file mode 100644 index 000000000..74ed07d60 --- /dev/null +++ b/client/src/containers/FinancialStatements/VendorsTransactions/VendorsTransactions.js @@ -0,0 +1,88 @@ +import React, { useEffect, useState } from 'react'; +import moment from 'moment'; +import 'style/pages/FinancialStatements/ContactsTransactions.scss'; + +import { FinancialStatement } from 'components'; +import DashboardPageContent from 'components/Dashboard/DashboardPageContent'; + +import VendorsTransactionsHeader from './VendorsTransactionsHeader'; +import VendorsTransactionsActionsBar from './VendorsTransactionsActionsBar'; +import VendorsTransactionsTable from './VendorsTransactionsTable'; + +import withVendorsTransactionsActions from './withVendorsTransactionsActions'; +import withSettings from 'containers/Settings/withSettings'; + +import { VendorsTransactionsProvider } from './VendorsTransactionsProvider'; +import { VendorsTransactionsLoadingBar } from './components'; + +import { compose } from 'utils'; + +/** + * Vendors transactions. + */ +function VendorsTransactions({ + // #withPreferences + organizationName, + + //#withVendorsTransactionsActions + toggleVendorsTransactionsFilterDrawer, +}) { + // filter + const [filter, setFilter] = useState({ + fromDate: moment().startOf('year').format('YYYY-MM-DD'), + toDate: moment().endOf('year').format('YYYY-MM-DD'), + }); + + const handleFilterSubmit = (filter) => { + const _filter = { + ...filter, + fromDate: moment(filter.fromDate).format('YYYY-MM-DD'), + toDate: moment(filter.toDate).format('YYYY-MM-DD'), + }; + setFilter({ ..._filter }); + }; + + // Handle number format submit. + const handleNumberFormatSubmit = (values) => { + setFilter({ + ...filter, + numberFormat: values, + }); + }; + + useEffect( + () => () => { + toggleVendorsTransactionsFilterDrawer(false); + }, + [toggleVendorsTransactionsFilterDrawer], + ); + + return ( + + + + + +
+ +
+ +
+
+
+
+
+ ); +} +export default compose( + withSettings(({ organizationSettings }) => ({ + organizationName: organizationSettings.name, + })), + withVendorsTransactionsActions, +)(VendorsTransactions); diff --git a/client/src/containers/FinancialStatements/VendorsTransactions/VendorsTransactionsActionsBar.js b/client/src/containers/FinancialStatements/VendorsTransactions/VendorsTransactionsActionsBar.js new file mode 100644 index 000000000..92b4a2dfc --- /dev/null +++ b/client/src/containers/FinancialStatements/VendorsTransactions/VendorsTransactionsActionsBar.js @@ -0,0 +1,134 @@ +import React from 'react'; +import { + NavbarGroup, + Button, + Classes, + NavbarDivider, + Popover, + PopoverInteractionKind, + Position, +} from '@blueprintjs/core'; +import { FormattedMessage as T } from 'react-intl'; +import classNames from 'classnames'; + +import Icon from 'components/Icon'; +import DashboardActionsBar from 'components/Dashboard/DashboardActionsBar'; +import NumberFormatDropdown from 'components/NumberFormatDropdown'; + +import { useVendorsTranscationsContext } from './VendorsTransactionsProvider'; +import withVendorsTransaction from './withVendorsTransaction'; +import withVendorsTransactionsActions from './withVendorsTransactionsActions'; + +import { compose, saveInvoke } from 'utils'; + +/** + * vendors transcations actions bar. + */ +function VendorsTransactionsActionsBar({ + // #ownProps + numberFormat, + onNumberFormatSubmit, + + //#withVendorsTransaction + isFilterDrawerOpen, + + //#withVendorsTransactionsActions + toggleVendorsTransactionsFilterDrawer, +}) { + const { + isVendorsTransactionsLoading, + refetch, + } = useVendorsTranscationsContext(); + + // Handle filter toggle click. + const handleFilterToggleClick = () => { + toggleVendorsTransactionsFilterDrawer(); + }; + + // Handle recalculate the report button. + const handleRecalcReport = () => { + refetch(); + }; + + // Handle number format form submit. + const handleNumberFormatSubmit = (values) => { + saveInvoke(onNumberFormatSubmit, values); + }; + + return ( + + + + + + + + + ); +} +export default compose( + withVendorsTransactionsActions, + withVendorsTransaction(({ vendorsTransactionsDrawerFilter }) => ({ + isFilterDrawerOpen: vendorsTransactionsDrawerFilter, + })), +)(VendorsTransactionsHeader); diff --git a/client/src/containers/FinancialStatements/VendorsTransactions/VendorsTransactionsHeaderGeneralPanel.js b/client/src/containers/FinancialStatements/VendorsTransactions/VendorsTransactionsHeaderGeneralPanel.js new file mode 100644 index 000000000..49c1beea2 --- /dev/null +++ b/client/src/containers/FinancialStatements/VendorsTransactions/VendorsTransactionsHeaderGeneralPanel.js @@ -0,0 +1,13 @@ +import React from 'react'; +import FinancialStatementDateRange from 'containers/FinancialStatements/FinancialStatementDateRange'; + +/** + * Vendors transactions header - General panel. + */ +export default function VendorsTransactionsHeaderGeneralPanel() { + return ( +
+ +
+ ); +} diff --git a/client/src/containers/FinancialStatements/VendorsTransactions/VendorsTransactionsProvider.js b/client/src/containers/FinancialStatements/VendorsTransactions/VendorsTransactionsProvider.js new file mode 100644 index 000000000..c024e43a1 --- /dev/null +++ b/client/src/containers/FinancialStatements/VendorsTransactions/VendorsTransactionsProvider.js @@ -0,0 +1,37 @@ +import React, { createContext, useContext, useMemo } from 'react'; +import FinancialReportPage from '../FinancialReportPage'; +import { useVendorsTranscationsReport } from 'hooks/query'; + + +const VendorsTransactionsContext = createContext(); + +/** + * Vendors transcations provider. + */ +function VendorsTransactionsProvider({ filter, ...props }) { + const { + data: vendorsTransactions, + isFetching: isVendorsTransactionFetching, + isLoading: isVendorsTransactionsLoading, + refetch, + } = useVendorsTranscationsReport(); + + const provider = { + vendorsTransactions, + isVendorsTransactionsLoading, + isVendorsTransactionFetching, + refetch, + filter, + }; + + return ( + + + + ); +} + +const useVendorsTranscationsContext = () => + useContext(VendorsTransactionsContext); + +export { VendorsTransactionsProvider, useVendorsTranscationsContext }; diff --git a/client/src/containers/FinancialStatements/VendorsTransactions/VendorsTransactionsTable.js b/client/src/containers/FinancialStatements/VendorsTransactions/VendorsTransactionsTable.js new file mode 100644 index 000000000..b554f3aae --- /dev/null +++ b/client/src/containers/FinancialStatements/VendorsTransactions/VendorsTransactionsTable.js @@ -0,0 +1,60 @@ +import React, { useMemo, useCallback } from 'react'; +import { useIntl } from 'react-intl'; +import classNames from 'classnames'; + +import FinancialSheet from 'components/FinancialSheet'; +import DataTable from 'components/DataTable'; +import { useVendorsTransactionsColumns } from './components'; +import { useVendorsTranscationsContext } from './VendorsTransactionsProvider'; + +import { defaultExpanderReducer, getColumnWidth } from 'utils'; + +/** + * Vendors transcations table. + */ + +export default function VendorsTransactionsTable({ + // #ownProps + companyName, +}) { + const { formatMessage } = useIntl(); + + const { + vendorsTransactions: { tableRows }, + isVendorsTransactionsLoading, + filter, + } = useVendorsTranscationsContext(); + + const columns = useVendorsTransactionsColumns(); + + const expandedRows = useMemo(() => defaultExpanderReducer(tableRows, 5), [ + tableRows, + ]); + + const rowClassNames = (row) => { + return [`row-type--${row.original.rowTypes}`]; + }; + + return ( + + + + ); +} diff --git a/client/src/containers/FinancialStatements/VendorsTransactions/components.js b/client/src/containers/FinancialStatements/VendorsTransactions/components.js new file mode 100644 index 000000000..5c97cf4cd --- /dev/null +++ b/client/src/containers/FinancialStatements/VendorsTransactions/components.js @@ -0,0 +1,99 @@ +import React from 'react'; +import { formatMessage } from 'services/intl'; +import { If } from 'components'; +import { useVendorsTranscationsContext } from './VendorsTransactionsProvider'; +import FinancialLoadingBar from '../FinancialLoadingBar'; +import { defaultExpanderReducer, getColumnWidth, getForceWidth } from 'utils'; +import { CellTextSpan } from 'components/Datatable/Cells'; + +/** + * Retrieve vendors transcations columns. + */ +export const useVendorsTransactionsColumns = () => { + const { + vendorsTransactions: { tableRows }, + } = useVendorsTranscationsContext(); + + return React.useMemo( + () => [ + { + Header: formatMessage({ id: 'vendor_name' }), + accessor: ({ cells }) => { + return ( + + {cells[0].value} + + ); + }, + className: 'vendor_name', + textOverview: true, + // width: 240, + }, + { + Header: formatMessage({ id: 'account_name' }), + accessor: 'cells[1].value', + className: 'name', + textOverview: true, + width: 180, + }, + { + Header: formatMessage({ id: 'reference_type' }), + accessor: 'cells[2].value', + textOverview: true, + width: 180, + }, + { + Header: formatMessage({ id: 'transaction_type' }), + accessor: 'cells[3].value', + textOverview: true, + width: 180, + }, + { + Header: formatMessage({ id: 'credit' }), + accessor: 'cells[4].value', + className: 'credit', + textOverview: true, + width: getColumnWidth(tableRows, 'credit', { + minWidth: 140, + magicSpacing: 10, + }), + }, + { + Header: formatMessage({ id: 'debit' }), + accessor: 'cells[5].value', + className: 'debit', + textOverview: true, + width: getColumnWidth(tableRows, 'debit', { + minWidth: 140, + magicSpacing: 10, + }), + }, + { + Header: formatMessage({ id: 'running_balance' }), + accessor: 'cells[6].value', + className: 'running_balance', + textOverview: true, + width: getColumnWidth(tableRows, 'running_balance', { + minWidth: 140, + magicSpacing: 10, + }), + }, + ], + [tableRows, formatMessage], + ); +}; + +/** + * vendors transcations loading bar. + */ +export function VendorsTransactionsLoadingBar() { + const { isVendorsTransactionsLoading } = useVendorsTranscationsContext(); + return ( + + + + ); +} diff --git a/client/src/containers/FinancialStatements/VendorsTransactions/withVendorsTransaction.js b/client/src/containers/FinancialStatements/VendorsTransactions/withVendorsTransaction.js new file mode 100644 index 000000000..1331f8842 --- /dev/null +++ b/client/src/containers/FinancialStatements/VendorsTransactions/withVendorsTransaction.js @@ -0,0 +1,15 @@ +import { connect } from 'react-redux'; +import { getVendorsTransactionsFilterDrawer } from 'store/financialStatement/financialStatements.selectors'; + +export default (mapState) => { + const mapStateToProps = (state, props) => { + const mapped = { + vendorsTransactionsDrawerFilter: getVendorsTransactionsFilterDrawer( + state, + props, + ), + }; + return mapState ? mapState(mapped, state, props) : mapped; + }; + return connect(mapStateToProps); +}; diff --git a/client/src/containers/FinancialStatements/VendorsTransactions/withVendorsTransactionsActions.js b/client/src/containers/FinancialStatements/VendorsTransactions/withVendorsTransactionsActions.js new file mode 100644 index 000000000..7239c6f01 --- /dev/null +++ b/client/src/containers/FinancialStatements/VendorsTransactions/withVendorsTransactionsActions.js @@ -0,0 +1,9 @@ +import { connect } from 'react-redux'; +import { toggleVendorsTransactionsFilterDrawer } from 'store/financialStatement/financialStatements.actions'; + +const mapActionsToProps = (dispatch) => ({ + toggleVendorsTransactionsFilterDrawer: (toggle) => + dispatch(toggleVendorsTransactionsFilterDrawer(toggle)), +}); + +export default connect(null, mapActionsToProps); diff --git a/client/src/style/pages/FinancialStatements/ContactsTransactions.scss b/client/src/style/pages/FinancialStatements/ContactsTransactions.scss new file mode 100644 index 000000000..aa8591eba --- /dev/null +++ b/client/src/style/pages/FinancialStatements/ContactsTransactions.scss @@ -0,0 +1,75 @@ +.financial-sheet { + &--customer-transactions, + &--vendor-transactions { + .financial-sheet__table { + .tbody, + .thead { + .tr .td, + .tr .th { + &.credit, + &.debit, + &.running_balance { + text-align: right; + } + } + } + .tbody { + .tr .td { + padding-top: 0.2rem; + padding-bottom: 0.2rem; + border-top-color: transparent; + border-bottom-color: transparent; + + &.customer_name, + &.vendor_name { + > div { + display: flex; + } + span.force-width { + position: relative; + } + } + } + .tr:not(.no-results) .td { + // border-left: 1px solid #ececec; + } + + .tr.row-type { + &--CUSTOMER, + &--VENDOR { + .td { + &.customer_name, + &.vendor_name { + font-weight: 500; + } + &.name { + border-left-color: transparent; + } + } + &:not(:first-child).is-expanded .td { + border-top: 1px solid #ddd; + } + } + &--OPENING_BALANCE, + // &--TRANSACTION, + &--CLOSING_BALANCE { + font-weight: 500; + } + &--CUSTOMER:last-child { + .td { + border-bottom: 1px solid #ddd; + } + } + } + } + } + } +} + +.financial-statement--transactions { + .financial-header-drawer { + .bp3-drawer { + max-height: 350px; + } + } +}