mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-17 05:10:31 +00:00
feat(webapp): categorize the cashflow uncategorized transactions
This commit is contained in:
@@ -1,13 +1,21 @@
|
||||
// @ts-nocheck
|
||||
import styled from 'styled-components';
|
||||
import { ContentTabs } from '@/components/ContentTabs/ContentTabs';
|
||||
import { useAccountTransactionsContext } from './AccountTransactionsProvider';
|
||||
|
||||
const AccountContentTabs = styled(ContentTabs)`
|
||||
margin: 15px 15px 0 15px;
|
||||
`;
|
||||
|
||||
export function AccountTransactionsFilterTabs() {
|
||||
const { filterTab, setFilterTab } = useAccountTransactionsContext();
|
||||
|
||||
const handleChange = (value) => {
|
||||
setFilterTab(value);
|
||||
};
|
||||
|
||||
return (
|
||||
<AccountContentTabs value={'uncategorized'}>
|
||||
<AccountContentTabs value={filterTab} onChange={handleChange}>
|
||||
<ContentTabs.Tab
|
||||
id={'dashboard'}
|
||||
title={'Dashboard'}
|
||||
|
||||
@@ -1,18 +1,20 @@
|
||||
// @ts-nocheck
|
||||
import React from 'react';
|
||||
import React, { Suspense } from 'react';
|
||||
import styled from 'styled-components';
|
||||
import { Spinner } from '@blueprintjs/core';
|
||||
|
||||
import '@/style/pages/CashFlow/AccountTransactions/List.scss';
|
||||
|
||||
import { DashboardPageContent } from '@/components';
|
||||
|
||||
import AccountTransactionsActionsBar from './AccountTransactionsActionsBar';
|
||||
import AccountTransactionsDataTable from './AccountTransactionsDataTable';
|
||||
import { AccountTransactionsProvider } from './AccountTransactionsProvider';
|
||||
import {
|
||||
AccountTransactionsProvider,
|
||||
useAccountTransactionsContext,
|
||||
} from './AccountTransactionsProvider';
|
||||
import { AccountTransactionsDetailsBar } from './AccountTransactionsDetailsBar';
|
||||
import { AccountTransactionsProgressBar } from './components';
|
||||
import { AccountTransactionsFilterTabs } from './AccountTransactionsFilterTabs';
|
||||
import { AccountTransactionsUncategorizeFilter } from './AccountTransactionsUncategorizeFilter';
|
||||
|
||||
/**
|
||||
* Account transactions list.
|
||||
@@ -27,13 +29,9 @@ function AccountTransactionsList() {
|
||||
<DashboardPageContent>
|
||||
<AccountTransactionsFilterTabs />
|
||||
|
||||
<Box>
|
||||
<AccountTransactionsUncategorizeFilter />
|
||||
|
||||
<CashflowTransactionsTableCard>
|
||||
<AccountTransactionsDataTable />
|
||||
</CashflowTransactionsTableCard>
|
||||
</Box>
|
||||
<Suspense fallback={<Spinner size={30} />}>
|
||||
<AccountTransactionsContent />
|
||||
</Suspense>
|
||||
</DashboardPageContent>
|
||||
</AccountTransactionsProvider>
|
||||
);
|
||||
@@ -41,14 +39,20 @@ function AccountTransactionsList() {
|
||||
|
||||
export default AccountTransactionsList;
|
||||
|
||||
const CashflowTransactionsTableCard = styled.div`
|
||||
border: 2px solid #f0f0f0;
|
||||
border-radius: 10px;
|
||||
padding: 30px 18px;
|
||||
background: #fff;
|
||||
flex: 0 1;
|
||||
`;
|
||||
const AccountsTransactionsAll = React.lazy(
|
||||
() => import('./AccountsTransactionsAll'),
|
||||
);
|
||||
|
||||
const Box = styled.div`
|
||||
margin: 30px 15px;
|
||||
`;
|
||||
const AccountsTransactionsUncategorized = React.lazy(
|
||||
() => import('./AllTransactionsUncategorized'),
|
||||
);
|
||||
|
||||
function AccountTransactionsContent() {
|
||||
const { filterTab } = useAccountTransactionsContext();
|
||||
|
||||
return filterTab === 'uncategorized' ? (
|
||||
<AccountsTransactionsUncategorized />
|
||||
) : (
|
||||
<AccountsTransactionsAll />
|
||||
);
|
||||
}
|
||||
|
||||
@@ -7,7 +7,9 @@ import {
|
||||
useAccountTransactionsInfinity,
|
||||
useCashflowAccounts,
|
||||
useAccount,
|
||||
useAccountUncategorizedTransactionsInfinity,
|
||||
} from '@/hooks/query';
|
||||
import { useAppQueryString } from '@/hooks';
|
||||
|
||||
const AccountTransactionsContext = React.createContext();
|
||||
|
||||
@@ -15,6 +17,10 @@ function flattenInfinityPages(data) {
|
||||
return flatten(map(data.pages, (page) => page.transactions));
|
||||
}
|
||||
|
||||
function flattenInfinityPagesData(data) {
|
||||
return flatten(map(data.pages, (page) => page.data));
|
||||
}
|
||||
|
||||
/**
|
||||
* Account transctions provider.
|
||||
*/
|
||||
@@ -22,6 +28,13 @@ function AccountTransactionsProvider({ query, ...props }) {
|
||||
const { id } = useParams();
|
||||
const accountId = parseInt(id, 10);
|
||||
|
||||
const [locationQuery, setLocationQuery] = useAppQueryString();
|
||||
|
||||
const filterTab = locationQuery?.filter || 'all';
|
||||
const setFilterTab = (value: stirng) => {
|
||||
setLocationQuery({ filter: value });
|
||||
};
|
||||
|
||||
// Fetch cashflow account transactions list
|
||||
const {
|
||||
data: cashflowTransactionsPages,
|
||||
@@ -31,10 +44,32 @@ function AccountTransactionsProvider({ query, ...props }) {
|
||||
fetchNextPage: fetchNextTransactionsPage,
|
||||
isFetchingNextPage,
|
||||
hasNextPage,
|
||||
} = useAccountTransactionsInfinity(accountId, {
|
||||
page_size: 50,
|
||||
account_id: accountId,
|
||||
});
|
||||
} = useAccountTransactionsInfinity(
|
||||
accountId,
|
||||
{
|
||||
page_size: 50,
|
||||
account_id: accountId,
|
||||
},
|
||||
{
|
||||
enabled: filterTab === 'all' || filterTab === 'dashboard',
|
||||
},
|
||||
);
|
||||
|
||||
const {
|
||||
data: uncategorizedTransactionsPage,
|
||||
isFetching: isUncategorizedTransactionFetching,
|
||||
isLoading: isUncategorizedTransactionsLoading,
|
||||
isSuccess: isUncategorizedTransactionsSuccess,
|
||||
fetchNextPage: fetchNextUncategorizedTransactionsPage,
|
||||
} = useAccountUncategorizedTransactionsInfinity(
|
||||
accountId,
|
||||
{
|
||||
page_size: 50,
|
||||
},
|
||||
{
|
||||
enabled: filterTab === 'uncategorized',
|
||||
},
|
||||
);
|
||||
|
||||
// Memorized the cashflow account transactions.
|
||||
const cashflowTransactions = React.useMemo(
|
||||
@@ -45,6 +80,15 @@ function AccountTransactionsProvider({ query, ...props }) {
|
||||
[cashflowTransactionsPages, isCashflowTransactionsSuccess],
|
||||
);
|
||||
|
||||
// Memorized the cashflow account transactions.
|
||||
const uncategorizedTransactions = React.useMemo(
|
||||
() =>
|
||||
isUncategorizedTransactionsSuccess
|
||||
? flattenInfinityPagesData(uncategorizedTransactionsPage)
|
||||
: [],
|
||||
[uncategorizedTransactionsPage, isUncategorizedTransactionsSuccess],
|
||||
);
|
||||
|
||||
// Fetch cashflow accounts.
|
||||
const {
|
||||
data: cashflowAccounts,
|
||||
@@ -78,6 +122,12 @@ function AccountTransactionsProvider({ query, ...props }) {
|
||||
isCashFlowAccountsLoading,
|
||||
isCurrentAccountFetching,
|
||||
isCurrentAccountLoading,
|
||||
|
||||
filterTab,
|
||||
setFilterTab,
|
||||
|
||||
uncategorizedTransactions,
|
||||
isUncategorizedTransactionFetching
|
||||
};
|
||||
|
||||
return (
|
||||
|
||||
@@ -0,0 +1,139 @@
|
||||
// @ts-nocheck
|
||||
import React from 'react';
|
||||
import styled from 'styled-components';
|
||||
|
||||
import {
|
||||
DataTable,
|
||||
TableFastCell,
|
||||
TableSkeletonRows,
|
||||
TableSkeletonHeader,
|
||||
TableVirtualizedListRows,
|
||||
FormattedMessage as T,
|
||||
} from '@/components';
|
||||
import { TABLES } from '@/constants/tables';
|
||||
|
||||
import withSettings from '@/containers/Settings/withSettings';
|
||||
import withAlertsActions from '@/containers/Alert/withAlertActions';
|
||||
import withDrawerActions from '@/containers/Drawer/withDrawerActions';
|
||||
|
||||
import { useMemorizedColumnsWidths } from '@/hooks';
|
||||
import {
|
||||
ActionsMenu,
|
||||
useAccountUncategorizedTransactionsColumns,
|
||||
} from './components';
|
||||
import { useAccountTransactionsContext } from './AccountTransactionsProvider';
|
||||
import { handleCashFlowTransactionType } from './utils';
|
||||
|
||||
import { compose } from '@/utils';
|
||||
|
||||
/**
|
||||
* Account transactions data table.
|
||||
*/
|
||||
function AccountTransactionsDataTable({
|
||||
// #withSettings
|
||||
cashflowTansactionsTableSize,
|
||||
|
||||
// #withAlertsActions
|
||||
openAlert,
|
||||
|
||||
// #withDrawerActions
|
||||
openDrawer,
|
||||
}) {
|
||||
// Retrieve table columns.
|
||||
const columns = useAccountUncategorizedTransactionsColumns();
|
||||
|
||||
// Retrieve list context.
|
||||
const { uncategorizedTransactions, isCashFlowTransactionsLoading } =
|
||||
useAccountTransactionsContext();
|
||||
|
||||
// Local storage memorizing columns widths.
|
||||
const [initialColumnsWidths, , handleColumnResizing] =
|
||||
useMemorizedColumnsWidths(TABLES.CASHFLOW_Transactions);
|
||||
|
||||
// handle delete transaction
|
||||
const handleDeleteTransaction = ({ reference_id }) => {};
|
||||
|
||||
const handleViewDetailCashflowTransaction = (referenceType) => {};
|
||||
|
||||
// Handle cell click.
|
||||
const handleCellClick = (cell, event) => {};
|
||||
|
||||
return (
|
||||
<CashflowTransactionsTable
|
||||
noInitialFetch={true}
|
||||
columns={columns}
|
||||
data={uncategorizedTransactions || []}
|
||||
sticky={true}
|
||||
loading={isCashFlowTransactionsLoading}
|
||||
headerLoading={isCashFlowTransactionsLoading}
|
||||
expandColumnSpace={1}
|
||||
expandToggleColumn={2}
|
||||
selectionColumnWidth={45}
|
||||
TableCellRenderer={TableFastCell}
|
||||
TableLoadingRenderer={TableSkeletonRows}
|
||||
TableRowsRenderer={TableVirtualizedListRows}
|
||||
TableHeaderSkeletonRenderer={TableSkeletonHeader}
|
||||
ContextMenu={ActionsMenu}
|
||||
onCellClick={handleCellClick}
|
||||
// #TableVirtualizedListRows props.
|
||||
vListrowHeight={cashflowTansactionsTableSize == 'small' ? 32 : 40}
|
||||
vListOverscanRowCount={0}
|
||||
initialColumnsWidths={initialColumnsWidths}
|
||||
onColumnResizing={handleColumnResizing}
|
||||
noResults={<T id={'cash_flow.account_transactions.no_results'} />}
|
||||
className="table-constrant"
|
||||
payload={{
|
||||
onViewDetails: handleViewDetailCashflowTransaction,
|
||||
onDelete: handleDeleteTransaction,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export default compose(
|
||||
withSettings(({ cashflowTransactionsSettings }) => ({
|
||||
cashflowTansactionsTableSize: cashflowTransactionsSettings?.tableSize,
|
||||
})),
|
||||
withAlertsActions,
|
||||
withDrawerActions,
|
||||
)(AccountTransactionsDataTable);
|
||||
|
||||
const DashboardConstrantTable = styled(DataTable)`
|
||||
.table {
|
||||
.thead {
|
||||
.th {
|
||||
background: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
.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,31 @@
|
||||
// @ts-nocheck
|
||||
import styled from 'styled-components';
|
||||
|
||||
import '@/style/pages/CashFlow/AccountTransactions/List.scss';
|
||||
|
||||
import AccountTransactionsDataTable from './AccountTransactionsDataTable';
|
||||
import { AccountTransactionsUncategorizeFilter } from './AccountTransactionsUncategorizeFilter';
|
||||
|
||||
const Box = styled.div`
|
||||
margin: 30px 15px;
|
||||
`;
|
||||
|
||||
const CashflowTransactionsTableCard = styled.div`
|
||||
border: 2px solid #f0f0f0;
|
||||
border-radius: 10px;
|
||||
padding: 30px 18px;
|
||||
background: #fff;
|
||||
flex: 0 1;
|
||||
`;
|
||||
|
||||
export default function AccountTransactionsAll() {
|
||||
return (
|
||||
<Box>
|
||||
<AccountTransactionsUncategorizeFilter />
|
||||
|
||||
<CashflowTransactionsTableCard>
|
||||
<AccountTransactionsDataTable />
|
||||
</CashflowTransactionsTableCard>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
// @ts-nocheck
|
||||
import styled from 'styled-components';
|
||||
|
||||
import '@/style/pages/CashFlow/AccountTransactions/List.scss';
|
||||
|
||||
import AccountTransactionsUncategorizedTable from './AccountTransactionsUncategorizedTable';
|
||||
|
||||
const Box = styled.div`
|
||||
margin: 30px 15px;
|
||||
`;
|
||||
|
||||
const CashflowTransactionsTableCard = styled.div`
|
||||
border: 2px solid #f0f0f0;
|
||||
border-radius: 10px;
|
||||
padding: 30px 18px;
|
||||
background: #fff;
|
||||
flex: 0 1;
|
||||
`
|
||||
|
||||
|
||||
export default function AllTransactionsUncategorized() {
|
||||
return (
|
||||
<Box>
|
||||
<CashflowTransactionsTableCard>
|
||||
<AccountTransactionsUncategorizedTable />
|
||||
</CashflowTransactionsTableCard>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
@@ -131,7 +131,75 @@ export function useAccountTransactionsColumns() {
|
||||
* Account transactions progress bar.
|
||||
*/
|
||||
export function AccountTransactionsProgressBar() {
|
||||
const { isCashFlowTransactionsFetching } = useAccountTransactionsContext();
|
||||
const { isCashFlowTransactionsFetching, isUncategorizedTransactionFetching } =
|
||||
useAccountTransactionsContext();
|
||||
|
||||
return isCashFlowTransactionsFetching ? <MaterialProgressBar /> : null;
|
||||
return isCashFlowTransactionsFetching ||
|
||||
isUncategorizedTransactionFetching ? (
|
||||
<MaterialProgressBar />
|
||||
) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve account uncategorized transctions table columns.
|
||||
*/
|
||||
export function useAccountUncategorizedTransactionsColumns() {
|
||||
return React.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: intl.get('reference_no'),
|
||||
accessor: 'reference_number',
|
||||
width: 50,
|
||||
className: 'reference_number',
|
||||
clickable: true,
|
||||
textOverview: true,
|
||||
},
|
||||
{
|
||||
id: 'deposit',
|
||||
Header: intl.get('cash_flow.label.deposit'),
|
||||
accessor: 'formattet_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