mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-16 12:50:38 +00:00
feat: pending transactions table
This commit is contained in:
@@ -54,6 +54,12 @@ const AccountUncategorizedTransactions = lazy(() =>
|
||||
).then((module) => ({ default: module.AccountUncategorizedTransactionsAll })),
|
||||
);
|
||||
|
||||
const PendingTransactions = lazy(() =>
|
||||
import('./PendingTransactions/PendingTransactions').then((module) => ({
|
||||
default: module.PendingTransactions,
|
||||
})),
|
||||
);
|
||||
|
||||
/**
|
||||
* Switches between the account transactions tables.
|
||||
* @returns {React.ReactNode}
|
||||
@@ -71,7 +77,7 @@ function AccountTransactionsSwitcher() {
|
||||
default:
|
||||
return <AccountUncategorizedTransactions />;
|
||||
case 'pending':
|
||||
return null;
|
||||
return <PendingTransactions />;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
import React from 'react';
|
||||
import { AccountTransactionsCard } from '../UncategorizedTransactions/AccountTransactionsCard';
|
||||
import { PendingTransactionsBoot } from './PendingTransactionsTableBoot';
|
||||
import { PendingTransactionsDataTable } from './PendingTransactionsTable';
|
||||
|
||||
export function PendingTransactions() {
|
||||
return (
|
||||
<PendingTransactionsBoot>
|
||||
<AccountTransactionsCard>
|
||||
<PendingTransactionsDataTable />
|
||||
</AccountTransactionsCard>
|
||||
</PendingTransactionsBoot>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
// @ts-nocheck
|
||||
import React from 'react';
|
||||
import clsx from 'classnames';
|
||||
import styled from 'styled-components';
|
||||
import {
|
||||
DataTable,
|
||||
TableFastCell,
|
||||
TableSkeletonRows,
|
||||
TableSkeletonHeader,
|
||||
TableVirtualizedListRows,
|
||||
} from '@/components';
|
||||
import withSettings from '@/containers/Settings/withSettings';
|
||||
import { withBankingActions } from '../../withBankingActions';
|
||||
|
||||
import { useAccountTransactionsContext } from '../AccountTransactionsProvider';
|
||||
import { usePendingTransactionsContext } from './PendingTransactionsTableBoot';
|
||||
import { usePendingTransactionsTableColumns } from './_hooks';
|
||||
|
||||
import { compose } from '@/utils';
|
||||
|
||||
/**
|
||||
* Account transactions data table.
|
||||
*/
|
||||
function PendingTransactionsDataTableRoot({
|
||||
// #withSettings
|
||||
cashflowTansactionsTableSize,
|
||||
}) {
|
||||
// Retrieve table columns.
|
||||
const columns = usePendingTransactionsTableColumns();
|
||||
const { scrollableRef } = useAccountTransactionsContext();
|
||||
|
||||
// Retrieve list context.
|
||||
const { pendingTransactions, isPendingTransactionsLoading } =
|
||||
usePendingTransactionsContext();
|
||||
|
||||
return (
|
||||
<CashflowTransactionsTable
|
||||
noInitialFetch={true}
|
||||
columns={columns}
|
||||
data={pendingTransactions || []}
|
||||
sticky={true}
|
||||
loading={isPendingTransactionsLoading}
|
||||
headerLoading={isPendingTransactionsLoading}
|
||||
TableCellRenderer={TableFastCell}
|
||||
TableLoadingRenderer={TableSkeletonRows}
|
||||
TableRowsRenderer={TableVirtualizedListRows}
|
||||
TableHeaderSkeletonRenderer={TableSkeletonHeader}
|
||||
// #TableVirtualizedListRows props.
|
||||
vListrowHeight={cashflowTansactionsTableSize === 'small' ? 32 : 40}
|
||||
vListOverscanRowCount={0}
|
||||
noResults={'There is no pending transactions in the current account.'}
|
||||
windowScrollerProps={{ scrollElement: scrollableRef }}
|
||||
className={clsx('table-constrant')}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export const PendingTransactionsDataTable = compose(
|
||||
withSettings(({ cashflowTransactionsSettings }) => ({
|
||||
cashflowTansactionsTableSize: cashflowTransactionsSettings?.tableSize,
|
||||
})),
|
||||
withBankingActions,
|
||||
)(PendingTransactionsDataTableRoot);
|
||||
|
||||
const DashboardConstrantTable = styled(DataTable)`
|
||||
.table {
|
||||
.thead {
|
||||
.th {
|
||||
background: #fff;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 1px;
|
||||
font-size: 13px;i
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
|
||||
.tbody {
|
||||
.tr:last-child .td {
|
||||
border-bottom: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const CashflowTransactionsTable = styled(DashboardConstrantTable)`
|
||||
.table .tbody {
|
||||
.tbody-inner .tr.no-results {
|
||||
.td {
|
||||
padding: 2rem 0;
|
||||
font-size: 14px;
|
||||
color: #888;
|
||||
font-weight: 400;
|
||||
border-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.tbody-inner {
|
||||
.tr .td:not(:first-child) {
|
||||
border-left: 1px solid #e6e6e6;
|
||||
}
|
||||
|
||||
.td-description {
|
||||
color: #5f6b7c;
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
// @ts-nocheck
|
||||
import React from 'react';
|
||||
import { flatten, map } from 'lodash';
|
||||
import { IntersectionObserver } from '@/components';
|
||||
import { useAccountTransactionsContext } from '../AccountTransactionsProvider';
|
||||
import { usePendingBankTransactionsInfinity } from '@/hooks/query/bank-rules';
|
||||
|
||||
const PendingTransactionsContext = React.createContext();
|
||||
|
||||
function flattenInfinityPagesData(data) {
|
||||
return flatten(map(data.pages, (page) => page.data));
|
||||
}
|
||||
|
||||
/**
|
||||
* Account pending transctions provider.
|
||||
*/
|
||||
function PendingTransactionsBoot({ children }) {
|
||||
const { accountId } = useAccountTransactionsContext();
|
||||
|
||||
// Fetches the pending transactions.
|
||||
const {
|
||||
data: pendingTransactionsPage,
|
||||
isFetching: isPendingTransactionFetching,
|
||||
isLoading: isPendingTransactionsLoading,
|
||||
isSuccess: isPendingTransactionsSuccess,
|
||||
isFetchingNextPage: isPendingTransactionFetchNextPage,
|
||||
fetchNextPage: fetchNextPendingTransactionsPage,
|
||||
hasNextPage: hasPendingTransactionsNextPage,
|
||||
} = usePendingBankTransactionsInfinity({
|
||||
account_id: accountId,
|
||||
page_size: 50,
|
||||
});
|
||||
// Memorized the cashflow account transactions.
|
||||
const pendingTransactions = React.useMemo(
|
||||
() =>
|
||||
isPendingTransactionsSuccess
|
||||
? flattenInfinityPagesData(pendingTransactionsPage)
|
||||
: [],
|
||||
[pendingTransactionsPage, isPendingTransactionsSuccess],
|
||||
);
|
||||
// Handle the observer ineraction.
|
||||
const handleObserverInteract = React.useCallback(() => {
|
||||
if (!isPendingTransactionFetching && hasPendingTransactionsNextPage) {
|
||||
fetchNextPendingTransactionsPage();
|
||||
}
|
||||
}, [
|
||||
isPendingTransactionFetching,
|
||||
hasPendingTransactionsNextPage,
|
||||
fetchNextPendingTransactionsPage,
|
||||
]);
|
||||
// Provider payload.
|
||||
const provider = {
|
||||
pendingTransactions,
|
||||
isPendingTransactionFetching,
|
||||
isPendingTransactionsLoading,
|
||||
};
|
||||
|
||||
return (
|
||||
<PendingTransactionsContext.Provider value={provider}>
|
||||
{children}
|
||||
<IntersectionObserver
|
||||
onIntersect={handleObserverInteract}
|
||||
enabled={!isPendingTransactionFetchNextPage}
|
||||
/>
|
||||
</PendingTransactionsContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
const usePendingTransactionsContext = () =>
|
||||
React.useContext(PendingTransactionsContext);
|
||||
|
||||
export { PendingTransactionsBoot, usePendingTransactionsContext };
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
import { useMemo } from 'react';
|
||||
import intl from 'react-intl-universal';
|
||||
|
||||
/**
|
||||
* Retrieve account pending transctions table columns.
|
||||
*/
|
||||
export function usePendingTransactionsTableColumns() {
|
||||
return useMemo(
|
||||
() => [
|
||||
{
|
||||
id: 'date',
|
||||
Header: intl.get('date'),
|
||||
accessor: 'formatted_date',
|
||||
width: 40,
|
||||
clickable: true,
|
||||
textOverview: true,
|
||||
},
|
||||
{
|
||||
id: 'description',
|
||||
Header: 'Description',
|
||||
accessor: 'description',
|
||||
width: 160,
|
||||
textOverview: true,
|
||||
clickable: true,
|
||||
},
|
||||
{
|
||||
id: 'payee',
|
||||
Header: 'Payee',
|
||||
accessor: 'payee',
|
||||
width: 60,
|
||||
clickable: true,
|
||||
textOverview: true,
|
||||
},
|
||||
{
|
||||
id: 'reference_number',
|
||||
Header: 'Ref.#',
|
||||
accessor: 'reference_no',
|
||||
width: 50,
|
||||
clickable: true,
|
||||
textOverview: true,
|
||||
},
|
||||
{
|
||||
id: 'deposit',
|
||||
Header: intl.get('cash_flow.label.deposit'),
|
||||
accessor: 'formatted_deposit_amount',
|
||||
width: 40,
|
||||
className: 'deposit',
|
||||
textOverview: true,
|
||||
align: 'right',
|
||||
clickable: true,
|
||||
},
|
||||
{
|
||||
id: 'withdrawal',
|
||||
Header: intl.get('cash_flow.label.withdrawal'),
|
||||
accessor: 'formatted_withdrawal_amount',
|
||||
className: 'withdrawal',
|
||||
width: 40,
|
||||
textOverview: true,
|
||||
align: 'right',
|
||||
clickable: true,
|
||||
},
|
||||
],
|
||||
[],
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user