mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-16 04:40:32 +00:00
re-structure to monorepo.
This commit is contained in:
@@ -0,0 +1,135 @@
|
||||
// @ts-nocheck
|
||||
import React, { useMemo } from 'react';
|
||||
import {
|
||||
Button,
|
||||
NavbarGroup,
|
||||
Classes,
|
||||
NavbarDivider,
|
||||
Alignment,
|
||||
} from '@blueprintjs/core';
|
||||
import {
|
||||
Icon,
|
||||
DashboardActionsBar,
|
||||
DashboardRowsHeightButton,
|
||||
FormattedMessage as T,
|
||||
} from '@/components';
|
||||
|
||||
import { CashFlowMenuItems } from './utils';
|
||||
import {
|
||||
getAddMoneyOutOptions,
|
||||
getAddMoneyInOptions,
|
||||
} from '@/constants/cashflowOptions';
|
||||
import { useRefreshCashflowTransactionsInfinity } from '@/hooks/query';
|
||||
import { useAccountTransactionsContext } from './AccountTransactionsProvider';
|
||||
|
||||
import withDialogActions from '@/containers/Dialog/withDialogActions';
|
||||
import withSettings from '@/containers/Settings/withSettings';
|
||||
import withSettingsActions from '@/containers/Settings/withSettingsActions';
|
||||
|
||||
import { compose } from '@/utils';
|
||||
|
||||
function AccountTransactionsActionsBar({
|
||||
// #withDialogActions
|
||||
openDialog,
|
||||
|
||||
// #withSettings
|
||||
cashflowTansactionsTableSize,
|
||||
|
||||
// #withSettingsActions
|
||||
addSetting,
|
||||
}) {
|
||||
// Handle table row size change.
|
||||
const handleTableRowSizeChange = (size) => {
|
||||
addSetting('cashflowTransactions', 'tableSize', size);
|
||||
};
|
||||
const { accountId } = useAccountTransactionsContext();
|
||||
|
||||
// Retrieves the money in/out buttons options.
|
||||
const addMoneyInOptions = useMemo(() => getAddMoneyInOptions(), []);
|
||||
const addMoneyOutOptions = useMemo(() => getAddMoneyOutOptions(), []);
|
||||
|
||||
// Handle money in form
|
||||
const handleMoneyInFormTransaction = (account) => {
|
||||
openDialog('money-in', {
|
||||
account_id: accountId,
|
||||
account_type: account.value,
|
||||
account_name: account.name,
|
||||
});
|
||||
};
|
||||
// Handle money out form
|
||||
const handlMoneyOutFormTransaction = (account) => {
|
||||
openDialog('money-out', {
|
||||
account_id: accountId,
|
||||
account_type: account.value,
|
||||
account_name: account.name,
|
||||
});
|
||||
};
|
||||
// Refresh cashflow infinity transactions hook.
|
||||
const { refresh } = useRefreshCashflowTransactionsInfinity();
|
||||
|
||||
// Handle the refresh button click.
|
||||
const handleRefreshBtnClick = () => {
|
||||
refresh();
|
||||
};
|
||||
|
||||
return (
|
||||
<DashboardActionsBar>
|
||||
<NavbarGroup>
|
||||
<CashFlowMenuItems
|
||||
items={addMoneyInOptions}
|
||||
onItemSelect={handleMoneyInFormTransaction}
|
||||
text={<T id={'cash_flow.label.add_money_in'} />}
|
||||
buttonProps={{
|
||||
icon: <Icon icon={'arrow-downward'} iconSize={20} />,
|
||||
}}
|
||||
/>
|
||||
<CashFlowMenuItems
|
||||
items={addMoneyOutOptions}
|
||||
onItemSelect={handlMoneyOutFormTransaction}
|
||||
text={<T id={'cash_flow.label.add_money_out'} />}
|
||||
buttonProps={{
|
||||
icon: <Icon icon={'arrow-upward'} iconSize={20} />,
|
||||
}}
|
||||
/>
|
||||
<NavbarDivider />
|
||||
<Button
|
||||
className={Classes.MINIMAL}
|
||||
icon={<Icon icon="print-16" iconSize={16} />}
|
||||
text={<T id={'print'} />}
|
||||
/>
|
||||
<Button
|
||||
className={Classes.MINIMAL}
|
||||
icon={<Icon icon="file-export-16" iconSize={16} />}
|
||||
text={<T id={'export'} />}
|
||||
/>
|
||||
<Button
|
||||
className={Classes.MINIMAL}
|
||||
icon={<Icon icon="file-import-16" iconSize={16} />}
|
||||
text={<T id={'import'} />}
|
||||
/>
|
||||
<NavbarDivider />
|
||||
<DashboardRowsHeightButton
|
||||
initialValue={cashflowTansactionsTableSize}
|
||||
onChange={handleTableRowSizeChange}
|
||||
/>
|
||||
<NavbarDivider />
|
||||
</NavbarGroup>
|
||||
|
||||
<NavbarGroup align={Alignment.RIGHT}>
|
||||
<Button
|
||||
className={Classes.MINIMAL}
|
||||
icon={<Icon icon="refresh-16" iconSize={14} />}
|
||||
onClick={handleRefreshBtnClick}
|
||||
/>
|
||||
</NavbarGroup>
|
||||
</DashboardActionsBar>
|
||||
);
|
||||
}
|
||||
|
||||
export default compose(
|
||||
withDialogActions,
|
||||
withSettingsActions,
|
||||
withSettings(({ cashflowTransactionsSettings }) => ({
|
||||
cashflowTansactionsTableSize: cashflowTransactionsSettings?.tableSize,
|
||||
})),
|
||||
)(AccountTransactionsActionsBar);
|
||||
@@ -0,0 +1,16 @@
|
||||
// @ts-nocheck
|
||||
import React from 'react';
|
||||
|
||||
const AccountDeleteTransactionAlert = React.lazy(
|
||||
() => import('@/containers/Alerts/CashFlow/AccountDeleteTransactionAlert'),
|
||||
);
|
||||
|
||||
/**
|
||||
* Account transaction alert.
|
||||
*/
|
||||
export default [
|
||||
{
|
||||
name: 'account-transaction-delete',
|
||||
component: AccountDeleteTransactionAlert,
|
||||
},
|
||||
];
|
||||
@@ -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 { useAccountTransactionsColumns, ActionsMenu } 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 = useAccountTransactionsColumns();
|
||||
|
||||
// Retrieve list context.
|
||||
const { cashflowTransactions, isCashFlowTransactionsLoading } =
|
||||
useAccountTransactionsContext();
|
||||
|
||||
// Local storage memorizing columns widths.
|
||||
const [initialColumnsWidths, , handleColumnResizing] =
|
||||
useMemorizedColumnsWidths(TABLES.CASHFLOW_Transactions);
|
||||
|
||||
// handle delete transaction
|
||||
const handleDeleteTransaction = ({ reference_id }) => {
|
||||
openAlert('account-transaction-delete', { referenceId: reference_id });
|
||||
};
|
||||
|
||||
const handleViewDetailCashflowTransaction = (referenceType) => {
|
||||
handleCashFlowTransactionType(referenceType, openDrawer);
|
||||
};
|
||||
|
||||
// Handle cell click.
|
||||
const handleCellClick = (cell, event) => {
|
||||
const referenceType = cell.row.original;
|
||||
handleCashFlowTransactionType(referenceType, openDrawer);
|
||||
};
|
||||
|
||||
return (
|
||||
<CashflowTransactionsTable
|
||||
noInitialFetch={true}
|
||||
columns={columns}
|
||||
data={cashflowTransactions}
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
@@ -0,0 +1,184 @@
|
||||
// @ts-nocheck
|
||||
import React from 'react';
|
||||
import intl from 'react-intl-universal';
|
||||
import styled from 'styled-components';
|
||||
import {
|
||||
Popover,
|
||||
Menu,
|
||||
Position,
|
||||
Button,
|
||||
MenuItem,
|
||||
Classes,
|
||||
} from '@blueprintjs/core';
|
||||
import { Icon } from '@/components';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
import { curry } from 'lodash/fp';
|
||||
|
||||
import { useAccountTransactionsContext } from './AccountTransactionsProvider';
|
||||
|
||||
function AccountSwitchButton() {
|
||||
const { currentAccount } = useAccountTransactionsContext();
|
||||
|
||||
return (
|
||||
<AccountSwitchButtonBase
|
||||
minimal={true}
|
||||
rightIcon={<Icon icon={'arrow-drop-down'} iconSize={24} />}
|
||||
>
|
||||
<AccountSwitchText>{currentAccount.name}</AccountSwitchText>
|
||||
</AccountSwitchButtonBase>
|
||||
);
|
||||
}
|
||||
|
||||
function AccountSwitchItem() {
|
||||
const { push } = useHistory();
|
||||
const { cashflowAccounts, accountId } = useAccountTransactionsContext();
|
||||
|
||||
// Handle item click.
|
||||
const handleItemClick = curry((account, event) => {
|
||||
push(`/cashflow-accounts/${account.id}/transactions`);
|
||||
});
|
||||
|
||||
const items = cashflowAccounts.map((account) => (
|
||||
<AccountSwitchMenuItem
|
||||
name={account.name}
|
||||
balance={account.formatted_amount}
|
||||
onClick={handleItemClick(account)}
|
||||
active={account.id === accountId}
|
||||
/>
|
||||
));
|
||||
|
||||
return (
|
||||
<Popover
|
||||
content={<Menu>{items}</Menu>}
|
||||
position={Position.BOTTOM_LEFT}
|
||||
minimal={true}
|
||||
>
|
||||
<AccountSwitchButton />
|
||||
</Popover>
|
||||
);
|
||||
}
|
||||
|
||||
function AccountBalanceItem() {
|
||||
const { currentAccount } = useAccountTransactionsContext();
|
||||
|
||||
return (
|
||||
<AccountBalanceItemWrap>
|
||||
{intl.get('cash_flow_transaction.balance_in_bigcapital')} {''}
|
||||
<AccountBalanceAmount>
|
||||
{currentAccount.formatted_amount}
|
||||
</AccountBalanceAmount>
|
||||
</AccountBalanceItemWrap>
|
||||
);
|
||||
}
|
||||
|
||||
function AccountTransactionsDetailsBarSkeleton() {
|
||||
return (
|
||||
<React.Fragment>
|
||||
<DetailsBarSkeletonBase className={Classes.SKELETON}>
|
||||
X
|
||||
</DetailsBarSkeletonBase>
|
||||
<DetailsBarSkeletonBase className={Classes.SKELETON}>
|
||||
X
|
||||
</DetailsBarSkeletonBase>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
function AccountTransactionsDetailsContent() {
|
||||
return (
|
||||
<React.Fragment>
|
||||
<AccountSwitchItem />
|
||||
<AccountBalanceItem />
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
export function AccountTransactionsDetailsBar() {
|
||||
const { isCurrentAccountLoading } = useAccountTransactionsContext();
|
||||
|
||||
return (
|
||||
<AccountTransactionDetailsWrap>
|
||||
{isCurrentAccountLoading ? (
|
||||
<AccountTransactionsDetailsBarSkeleton />
|
||||
) : (
|
||||
<AccountTransactionsDetailsContent />
|
||||
)}
|
||||
</AccountTransactionDetailsWrap>
|
||||
);
|
||||
}
|
||||
|
||||
function AccountSwitchMenuItem({
|
||||
name,
|
||||
balance,
|
||||
transactionsNumber,
|
||||
...restProps
|
||||
}) {
|
||||
return (
|
||||
<MenuItem
|
||||
label={balance}
|
||||
text={
|
||||
<React.Fragment>
|
||||
<AccountSwitchItemName>{name}</AccountSwitchItemName>
|
||||
<AccountSwitchItemTranscations>
|
||||
{intl.get('cash_flow_transaction.switch_item', { value: '25' })}
|
||||
</AccountSwitchItemTranscations>
|
||||
|
||||
<AccountSwitchItemUpdatedAt></AccountSwitchItemUpdatedAt>
|
||||
</React.Fragment>
|
||||
}
|
||||
{...restProps}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
const DetailsBarSkeletonBase = styled.div`
|
||||
letter-spacing: 10px;
|
||||
margin-right: 10px;
|
||||
margin-left: 10px;
|
||||
font-size: 8px;
|
||||
width: 140px;
|
||||
`;
|
||||
|
||||
const AccountBalanceItemWrap = styled.div`
|
||||
margin-left: 18px;
|
||||
color: #5f6d86;
|
||||
`;
|
||||
|
||||
const AccountTransactionDetailsWrap = styled.div`
|
||||
display: flex;
|
||||
background: #fff;
|
||||
border-bottom: 1px solid #d2dce2;
|
||||
padding: 0 22px;
|
||||
height: 42px;
|
||||
align-items: center;
|
||||
`;
|
||||
const AccountSwitchText = styled.div`
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
`;
|
||||
|
||||
const AccountBalanceAmount = styled.span`
|
||||
font-weight: 600;
|
||||
display: inline-block;
|
||||
color: rgb(31, 50, 85);
|
||||
margin-left: 10px;
|
||||
`;
|
||||
|
||||
const AccountSwitchItemName = styled.div`
|
||||
font-weight: 600;
|
||||
`;
|
||||
const AccountSwitchItemTranscations = styled.div`
|
||||
font-size: 12px;
|
||||
opacity: 0.7;
|
||||
`;
|
||||
|
||||
const AccountSwitchItemUpdatedAt = styled.div`
|
||||
font-size: 12px;
|
||||
opacity: 0.5;
|
||||
`;
|
||||
|
||||
const AccountSwitchButtonBase = styled(Button)`
|
||||
.bp3-button-text {
|
||||
margin-right: 5px;
|
||||
}
|
||||
`;
|
||||
@@ -0,0 +1,43 @@
|
||||
// @ts-nocheck
|
||||
import React from 'react';
|
||||
import styled from 'styled-components';
|
||||
|
||||
import '@/style/pages/CashFlow/AccountTransactions/List.scss';
|
||||
|
||||
import { DashboardPageContent } from '@/components';
|
||||
|
||||
import AccountTransactionsActionsBar from './AccountTransactionsActionsBar';
|
||||
import AccountTransactionsDataTable from './AccountTransactionsDataTable';
|
||||
import { AccountTransactionsProvider } from './AccountTransactionsProvider';
|
||||
import { AccountTransactionsDetailsBar } from './AccountTransactionsDetailsBar';
|
||||
import { AccountTransactionsProgressBar } from './components';
|
||||
|
||||
/**
|
||||
* Account transactions list.
|
||||
*/
|
||||
function AccountTransactionsList() {
|
||||
return (
|
||||
<AccountTransactionsProvider>
|
||||
<AccountTransactionsActionsBar />
|
||||
<AccountTransactionsDetailsBar />
|
||||
<AccountTransactionsProgressBar />
|
||||
|
||||
<DashboardPageContent>
|
||||
<CashflowTransactionsTableCard>
|
||||
<AccountTransactionsDataTable />
|
||||
</CashflowTransactionsTableCard>
|
||||
</DashboardPageContent>
|
||||
</AccountTransactionsProvider>
|
||||
);
|
||||
}
|
||||
|
||||
export default AccountTransactionsList;
|
||||
|
||||
const CashflowTransactionsTableCard = styled.div`
|
||||
border: 2px solid #f0f0f0;
|
||||
border-radius: 10px;
|
||||
padding: 30px 18px;
|
||||
margin: 30px 15px;
|
||||
background: #fff;
|
||||
flex: 0 1;
|
||||
`;
|
||||
@@ -0,0 +1,97 @@
|
||||
// @ts-nocheck
|
||||
import React from 'react';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { flatten, map } from 'lodash';
|
||||
import { IntersectionObserver, DashboardInsider } from '@/components';
|
||||
import {
|
||||
useAccountTransactionsInfinity,
|
||||
useCashflowAccounts,
|
||||
useAccount,
|
||||
} from '@/hooks/query';
|
||||
|
||||
const AccountTransactionsContext = React.createContext();
|
||||
|
||||
function flattenInfinityPages(data) {
|
||||
return flatten(map(data.pages, (page) => page.transactions));
|
||||
}
|
||||
|
||||
/**
|
||||
* Account transctions provider.
|
||||
*/
|
||||
function AccountTransactionsProvider({ query, ...props }) {
|
||||
const { id } = useParams();
|
||||
const accountId = parseInt(id, 10);
|
||||
|
||||
// Fetch cashflow account transactions list
|
||||
const {
|
||||
data: cashflowTransactionsPages,
|
||||
isFetching: isCashFlowTransactionsFetching,
|
||||
isLoading: isCashFlowTransactionsLoading,
|
||||
isSuccess: isCashflowTransactionsSuccess,
|
||||
fetchNextPage: fetchNextTransactionsPage,
|
||||
isFetchingNextPage,
|
||||
hasNextPage,
|
||||
} = useAccountTransactionsInfinity(accountId, {
|
||||
page_size: 50,
|
||||
account_id: accountId,
|
||||
});
|
||||
|
||||
// Memorized the cashflow account transactions.
|
||||
const cashflowTransactions = React.useMemo(
|
||||
() =>
|
||||
isCashflowTransactionsSuccess
|
||||
? flattenInfinityPages(cashflowTransactionsPages)
|
||||
: [],
|
||||
[cashflowTransactionsPages, isCashflowTransactionsSuccess],
|
||||
);
|
||||
|
||||
// Fetch cashflow accounts.
|
||||
const {
|
||||
data: cashflowAccounts,
|
||||
isFetching: isCashFlowAccountsFetching,
|
||||
isLoading: isCashFlowAccountsLoading,
|
||||
} = useCashflowAccounts(query, { keepPreviousData: true });
|
||||
|
||||
// Retrieve specific account details.
|
||||
const {
|
||||
data: currentAccount,
|
||||
isFetching: isCurrentAccountFetching,
|
||||
isLoading: isCurrentAccountLoading,
|
||||
} = useAccount(accountId, { keepPreviousData: true });
|
||||
|
||||
// Handle the observer ineraction.
|
||||
const handleObserverInteract = React.useCallback(() => {
|
||||
if (!isFetchingNextPage && hasNextPage) {
|
||||
fetchNextTransactionsPage();
|
||||
}
|
||||
}, [isFetchingNextPage, hasNextPage, fetchNextTransactionsPage]);
|
||||
|
||||
// Provider payload.
|
||||
const provider = {
|
||||
accountId,
|
||||
cashflowTransactions,
|
||||
cashflowAccounts,
|
||||
currentAccount,
|
||||
isCashFlowTransactionsFetching,
|
||||
isCashFlowTransactionsLoading,
|
||||
isCashFlowAccountsFetching,
|
||||
isCashFlowAccountsLoading,
|
||||
isCurrentAccountFetching,
|
||||
isCurrentAccountLoading,
|
||||
};
|
||||
|
||||
return (
|
||||
<DashboardInsider name={'account-transactions'}>
|
||||
<AccountTransactionsContext.Provider value={provider} {...props} />
|
||||
<IntersectionObserver
|
||||
onIntersect={handleObserverInteract}
|
||||
enabled={!isFetchingNextPage}
|
||||
/>
|
||||
</DashboardInsider>
|
||||
);
|
||||
}
|
||||
|
||||
const useAccountTransactionsContext = () =>
|
||||
React.useContext(AccountTransactionsContext);
|
||||
|
||||
export { AccountTransactionsProvider, useAccountTransactionsContext };
|
||||
@@ -0,0 +1,137 @@
|
||||
// @ts-nocheck
|
||||
import React from 'react';
|
||||
import intl from 'react-intl-universal';
|
||||
import { Intent, Menu, MenuItem, MenuDivider } from '@blueprintjs/core';
|
||||
import {
|
||||
Can,
|
||||
FormatDateCell,
|
||||
If,
|
||||
Icon,
|
||||
MaterialProgressBar,
|
||||
} from '@/components';
|
||||
import { useAccountTransactionsContext } from './AccountTransactionsProvider';
|
||||
import { TRANSACRIONS_TYPE } from '@/constants/cashflowOptions';
|
||||
import { AbilitySubject, CashflowAction } from '@/constants/abilityOption';
|
||||
import { safeCallback } from '@/utils';
|
||||
|
||||
export function ActionsMenu({
|
||||
payload: { onDelete, onViewDetails },
|
||||
row: { original },
|
||||
}) {
|
||||
return (
|
||||
<Menu>
|
||||
<MenuItem
|
||||
icon={<Icon icon="reader-18" />}
|
||||
text={intl.get('view_details')}
|
||||
onClick={safeCallback(onViewDetails, original)}
|
||||
/>
|
||||
<Can I={CashflowAction.Delete} a={AbilitySubject.Cashflow}>
|
||||
<If condition={TRANSACRIONS_TYPE.includes(original.reference_type)}>
|
||||
<MenuDivider />
|
||||
<MenuItem
|
||||
text={intl.get('delete_transaction')}
|
||||
intent={Intent.DANGER}
|
||||
onClick={safeCallback(onDelete, original)}
|
||||
icon={<Icon icon="trash-16" iconSize={16} />}
|
||||
/>
|
||||
</If>
|
||||
</Can>
|
||||
</Menu>
|
||||
);
|
||||
}
|
||||
/**
|
||||
* Retrieve account transctions table columns.
|
||||
*/
|
||||
export function useAccountTransactionsColumns() {
|
||||
return React.useMemo(
|
||||
() => [
|
||||
{
|
||||
id: 'date',
|
||||
Header: intl.get('date'),
|
||||
accessor: 'date',
|
||||
Cell: FormatDateCell,
|
||||
width: 110,
|
||||
className: 'date',
|
||||
clickable: true,
|
||||
textOverview: true,
|
||||
},
|
||||
{
|
||||
id: 'type',
|
||||
Header: intl.get('type'),
|
||||
accessor: 'formatted_transaction_type',
|
||||
className: 'type',
|
||||
width: 140,
|
||||
textOverview: true,
|
||||
clickable: true,
|
||||
},
|
||||
{
|
||||
id: 'transaction_number',
|
||||
Header: intl.get('transaction_number'),
|
||||
accessor: 'transaction_number',
|
||||
width: 160,
|
||||
className: 'transaction_number',
|
||||
clickable: true,
|
||||
textOverview: true,
|
||||
},
|
||||
{
|
||||
id: 'reference_number',
|
||||
Header: intl.get('reference_no'),
|
||||
accessor: 'reference_number',
|
||||
width: 160,
|
||||
className: 'reference_number',
|
||||
clickable: true,
|
||||
textOverview: true,
|
||||
},
|
||||
{
|
||||
id: 'deposit',
|
||||
Header: intl.get('cash_flow.label.deposit'),
|
||||
accessor: 'formatted_deposit',
|
||||
width: 110,
|
||||
className: 'deposit',
|
||||
textOverview: true,
|
||||
align: 'right',
|
||||
clickable: true,
|
||||
},
|
||||
{
|
||||
id: 'withdrawal',
|
||||
Header: intl.get('cash_flow.label.withdrawal'),
|
||||
accessor: 'formatted_withdrawal',
|
||||
className: 'withdrawal',
|
||||
width: 150,
|
||||
textOverview: true,
|
||||
align: 'right',
|
||||
clickable: true,
|
||||
},
|
||||
{
|
||||
id: 'running_balance',
|
||||
Header: intl.get('cash_flow.label.running_balance'),
|
||||
accessor: 'formatted_running_balance',
|
||||
className: 'running_balance',
|
||||
width: 150,
|
||||
textOverview: true,
|
||||
align: 'right',
|
||||
clickable: true,
|
||||
},
|
||||
{
|
||||
id: 'balance',
|
||||
Header: intl.get('balance'),
|
||||
accessor: 'formatted_balance',
|
||||
className: 'balance',
|
||||
width: 150,
|
||||
textOverview: true,
|
||||
clickable: true,
|
||||
align: 'right',
|
||||
},
|
||||
],
|
||||
[],
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Account transactions progress bar.
|
||||
*/
|
||||
export function AccountTransactionsProgressBar() {
|
||||
const { isCashFlowTransactionsFetching } = useAccountTransactionsContext();
|
||||
|
||||
return isCashFlowTransactionsFetching ? <MaterialProgressBar /> : null;
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
// @ts-nocheck
|
||||
import React from 'react';
|
||||
import {
|
||||
Button,
|
||||
PopoverInteractionKind,
|
||||
MenuItem,
|
||||
Position,
|
||||
} from '@blueprintjs/core';
|
||||
|
||||
import { Select } from '@blueprintjs/select';
|
||||
import { Icon } from '@/components';
|
||||
|
||||
export const CashFlowMenuItems = ({
|
||||
text,
|
||||
items,
|
||||
onItemSelect,
|
||||
buttonProps,
|
||||
}) => {
|
||||
// Menu items renderer.
|
||||
const itemsRenderer = (item, { handleClick, modifiers, query }) => (
|
||||
<MenuItem text={item.name} label={item.label} onClick={handleClick} />
|
||||
);
|
||||
|
||||
const handleCashFlowMenuSelect = (type) => {
|
||||
onItemSelect && onItemSelect(type);
|
||||
};
|
||||
|
||||
return (
|
||||
<Select
|
||||
items={items}
|
||||
itemRenderer={itemsRenderer}
|
||||
onItemSelect={handleCashFlowMenuSelect}
|
||||
popoverProps={{
|
||||
minimal: true,
|
||||
position: Position.BOTTOM_LEFT,
|
||||
interactionKind: PopoverInteractionKind.CLICK,
|
||||
modifiers: {
|
||||
offset: { offset: '0, 4' },
|
||||
},
|
||||
}}
|
||||
filterable={false}
|
||||
>
|
||||
<Button
|
||||
text={text}
|
||||
icon={<Icon icon={'plus-24'} iconSize={20} />}
|
||||
minimal={true}
|
||||
{...buttonProps}
|
||||
/>
|
||||
</Select>
|
||||
);
|
||||
};
|
||||
|
||||
export const handleCashFlowTransactionType = (reference, openDrawer) => {
|
||||
switch (reference.reference_type) {
|
||||
case 'SaleReceipt':
|
||||
return openDrawer('receipt-detail-drawer', {
|
||||
receiptId: reference.reference_id,
|
||||
});
|
||||
case 'Journal':
|
||||
return openDrawer('journal-drawer', {
|
||||
manualJournalId: reference.reference_id,
|
||||
});
|
||||
case 'Expense':
|
||||
return openDrawer('expense-drawer', {
|
||||
expenseId: reference.reference_id,
|
||||
});
|
||||
case 'PaymentReceive':
|
||||
return openDrawer('payment-receive-detail-drawer', {
|
||||
paymentReceiveId: reference.reference_id,
|
||||
});
|
||||
case 'BillPayment':
|
||||
return openDrawer('payment-made-detail-drawer', {
|
||||
paymentMadeId: reference.reference_id,
|
||||
});
|
||||
case 'RefundCreditNote':
|
||||
return openDrawer('refund-credit-detail-drawer', {
|
||||
refundTransactionId: reference.reference_id,
|
||||
});
|
||||
case 'RefundVendorCredit':
|
||||
return openDrawer('refund-vendor-detail-drawer', {
|
||||
refundTransactionId: reference.reference_id,
|
||||
});
|
||||
case 'InventoryAdjustment':
|
||||
return openDrawer('inventory-adjustment-drawer', {
|
||||
inventoryId: reference.reference_id,
|
||||
});
|
||||
|
||||
default:
|
||||
return openDrawer('cashflow-transaction-drawer', {
|
||||
referenceId: reference.reference_id,
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,16 @@
|
||||
// @ts-nocheck
|
||||
import { connect } from 'react-redux';
|
||||
import { getCashflowAccountsTableStateFactory } from '@/store/CashflowAccounts/CashflowAccounts.selectors';
|
||||
|
||||
export default (mapState) => {
|
||||
const getCashflowAccountsTableState = getCashflowAccountsTableStateFactory();
|
||||
|
||||
const mapStateToProps = (state, props) => {
|
||||
const mapped = {
|
||||
cashflowAccountsTableState: getCashflowAccountsTableState(state, props),
|
||||
};
|
||||
return mapState ? mapState(mapped, state, props) : mapped;
|
||||
};
|
||||
|
||||
return connect(mapStateToProps);
|
||||
};
|
||||
@@ -0,0 +1,16 @@
|
||||
// @ts-nocheck
|
||||
import { connect } from 'react-redux';
|
||||
import {
|
||||
setCashflowAccountsTableState,
|
||||
resetCashflowAccountsTableState,
|
||||
} from '@/store/CashflowAccounts/CashflowAccounts.actions';
|
||||
|
||||
const mapActionsToProps = (dispatch) => ({
|
||||
setCashflowAccountsTableState: (queries) =>
|
||||
dispatch(setCashflowAccountsTableState(queries)),
|
||||
|
||||
resetCashflowAccountsTableState: () =>
|
||||
dispatch(resetCashflowAccountsTableState()),
|
||||
});
|
||||
|
||||
export default connect(null, mapActionsToProps);
|
||||
@@ -0,0 +1,122 @@
|
||||
// @ts-nocheck
|
||||
import React from 'react';
|
||||
import {
|
||||
Button,
|
||||
NavbarGroup,
|
||||
Classes,
|
||||
NavbarDivider,
|
||||
Alignment,
|
||||
Switch,
|
||||
} from '@blueprintjs/core';
|
||||
import {
|
||||
DashboardActionsBar,
|
||||
Can,
|
||||
Icon,
|
||||
FormattedMessage as T,
|
||||
} from '@/components';
|
||||
import { useRefreshCashflowAccounts } from '@/hooks/query';
|
||||
import { CashflowAction, AbilitySubject } from '@/constants/abilityOption';
|
||||
|
||||
import withDialogActions from '@/containers/Dialog/withDialogActions';
|
||||
import withCashflowAccountsTableActions from '../AccountTransactions/withCashflowAccountsTableActions';
|
||||
|
||||
import { AccountDialogAction } from '@/containers/Dialogs/AccountDialog/utils';
|
||||
|
||||
import { ACCOUNT_TYPE } from '@/constants';
|
||||
import { DialogsName } from '@/constants/dialogs';
|
||||
|
||||
import { compose } from '@/utils';
|
||||
|
||||
/**
|
||||
* Cash Flow accounts actions bar.
|
||||
*/
|
||||
function CashFlowAccountsActionsBar({
|
||||
// #withDialogActions
|
||||
openDialog,
|
||||
|
||||
// #withCashflowAccountsTableActions
|
||||
setCashflowAccountsTableState,
|
||||
}) {
|
||||
const { refresh } = useRefreshCashflowAccounts();
|
||||
|
||||
// Handle refresh button click.
|
||||
const handleRefreshBtnClick = () => {
|
||||
refresh();
|
||||
};
|
||||
// Handle add bank account.
|
||||
const handleAddBankAccount = () => {
|
||||
openDialog(DialogsName.AccountForm, {
|
||||
action: AccountDialogAction.NewDefinedType,
|
||||
accountType: ACCOUNT_TYPE.CASH,
|
||||
});
|
||||
};
|
||||
// Handle add cash account.
|
||||
const handleAddCashAccount = () => {
|
||||
openDialog(DialogsName.AccountForm, {
|
||||
action: AccountDialogAction.NewDefinedType,
|
||||
accountType: ACCOUNT_TYPE.BANK,
|
||||
});
|
||||
};
|
||||
// Handle inactive switch changing.
|
||||
const handleInactiveSwitchChange = (event) => {
|
||||
const checked = event.target.checked;
|
||||
setCashflowAccountsTableState({ inactiveMode: checked });
|
||||
};
|
||||
|
||||
return (
|
||||
<DashboardActionsBar>
|
||||
<NavbarGroup>
|
||||
<Can I={CashflowAction.Create} a={AbilitySubject.Cashflow}>
|
||||
<Button
|
||||
className={Classes.MINIMAL}
|
||||
icon={<Icon icon={'plus-24'} iconSize={20} />}
|
||||
text={<T id={'cash_flow.label.add_cash_account'} />}
|
||||
onClick={handleAddBankAccount}
|
||||
/>
|
||||
<Button
|
||||
className={Classes.MINIMAL}
|
||||
icon={<Icon icon={'plus-24'} iconSize={20} />}
|
||||
text={<T id={'cash_flow.label.add_bank_account'} />}
|
||||
onClick={handleAddCashAccount}
|
||||
/>
|
||||
<NavbarDivider />
|
||||
</Can>
|
||||
<Button
|
||||
className={Classes.MINIMAL}
|
||||
icon={<Icon icon="print-16" iconSize={16} />}
|
||||
text={<T id={'print'} />}
|
||||
/>
|
||||
<Button
|
||||
className={Classes.MINIMAL}
|
||||
icon={<Icon icon="file-export-16" iconSize={16} />}
|
||||
text={<T id={'export'} />}
|
||||
/>
|
||||
<Button
|
||||
className={Classes.MINIMAL}
|
||||
icon={<Icon icon="file-import-16" iconSize={16} />}
|
||||
text={<T id={'import'} />}
|
||||
/>
|
||||
<NavbarDivider />
|
||||
<Can I={CashflowAction.Edit} a={AbilitySubject.Cashflow}>
|
||||
<Switch
|
||||
labelElement={<T id={'inactive'} />}
|
||||
defaultChecked={false}
|
||||
onChange={handleInactiveSwitchChange}
|
||||
/>
|
||||
</Can>
|
||||
</NavbarGroup>
|
||||
|
||||
<NavbarGroup align={Alignment.RIGHT}>
|
||||
<Button
|
||||
className={Classes.MINIMAL}
|
||||
icon={<Icon icon="refresh-16" iconSize={14} />}
|
||||
onClick={handleRefreshBtnClick}
|
||||
/>
|
||||
</NavbarGroup>
|
||||
</DashboardActionsBar>
|
||||
);
|
||||
}
|
||||
export default compose(
|
||||
withDialogActions,
|
||||
withCashflowAccountsTableActions,
|
||||
)(CashFlowAccountsActionsBar);
|
||||
@@ -0,0 +1,67 @@
|
||||
// @ts-nocheck
|
||||
import React from 'react';
|
||||
|
||||
import { TABLES } from '@/constants/tables';
|
||||
import {
|
||||
DataTable,
|
||||
TableFastCell,
|
||||
TableSkeletonRows,
|
||||
TableSkeletonHeader,
|
||||
} from '@/components';
|
||||
|
||||
import withSettings from '@/containers/Settings/withSettings';
|
||||
|
||||
import { useMemorizedColumnsWidths } from '@/hooks';
|
||||
import { useCashFlowAccountsContext } from './CashFlowAccountsProvider';
|
||||
import { useCashFlowAccountsTableColumns } from './components';
|
||||
import { compose } from '@/utils';
|
||||
|
||||
/**
|
||||
* Cash flow accounts data table.
|
||||
*/
|
||||
function CashFlowAccountsDataTable({
|
||||
// #withSettings
|
||||
cashflowTableSize,
|
||||
}) {
|
||||
// Retrieve list context.
|
||||
const {
|
||||
cashflowAccounts,
|
||||
isCashFlowAccountsFetching,
|
||||
isCashFlowAccountsLoading,
|
||||
} = useCashFlowAccountsContext();
|
||||
|
||||
// Retrieve table columns.
|
||||
const columns = useCashFlowAccountsTableColumns();
|
||||
|
||||
// Local storage memorizing columns widths.
|
||||
const [initialColumnsWidths, , handleColumnResizing] =
|
||||
useMemorizedColumnsWidths(TABLES.CASHFLOW_ACCOUNTS);
|
||||
|
||||
return (
|
||||
<DataTable
|
||||
noInitialFetch={true}
|
||||
columns={columns}
|
||||
data={cashflowAccounts}
|
||||
selectionColumn={false}
|
||||
sticky={true}
|
||||
loading={isCashFlowAccountsLoading}
|
||||
headerLoading={isCashFlowAccountsLoading}
|
||||
progressBarLoading={isCashFlowAccountsFetching}
|
||||
expandColumnSpace={1}
|
||||
expandToggleColumn={2}
|
||||
selectionColumnWidth={45}
|
||||
TableCellRenderer={TableFastCell}
|
||||
TableLoadingRenderer={TableSkeletonRows}
|
||||
TableHeaderSkeletonRenderer={TableSkeletonHeader}
|
||||
initialColumnsWidths={initialColumnsWidths}
|
||||
onColumnResizing={handleColumnResizing}
|
||||
size={cashflowTableSize}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export default compose(
|
||||
withSettings(({ cashflowSettings }) => ({
|
||||
cashflowTableSize: cashflowSettings?.tableSize,
|
||||
})),
|
||||
)(CashFlowAccountsDataTable);
|
||||
@@ -0,0 +1,50 @@
|
||||
// @ts-nocheck
|
||||
import React, { useEffect } from 'react';
|
||||
import { compose } from 'lodash/fp';
|
||||
|
||||
import '@/style/pages/CashFlow/CashFlowAccounts/List.scss';
|
||||
|
||||
import { DashboardPageContent } from '@/components';
|
||||
import { CashFlowAccountsProvider } from './CashFlowAccountsProvider';
|
||||
|
||||
import CashflowAccountsGrid from './CashflowAccountsGrid';
|
||||
import CashFlowAccountsActionsBar from './CashFlowAccountsActionsBar';
|
||||
|
||||
import withCashflowAccounts from '@/containers/CashFlow/AccountTransactions/withCashflowAccounts';
|
||||
import withCashflowAccountsTableActions from '@/containers/CashFlow/AccountTransactions/withCashflowAccountsTableActions';
|
||||
|
||||
/**
|
||||
* Cashflow accounts list.
|
||||
*/
|
||||
function CashFlowAccountsList({
|
||||
// #withCashflowAccounts
|
||||
cashflowAccountsTableState,
|
||||
|
||||
// #withCashflowAccountsTableActions
|
||||
resetCashflowAccountsTableState,
|
||||
}) {
|
||||
// Resets the cashflow accounts table state.
|
||||
useEffect(
|
||||
() => () => {
|
||||
resetCashflowAccountsTableState();
|
||||
},
|
||||
[resetCashflowAccountsTableState],
|
||||
);
|
||||
|
||||
return (
|
||||
<CashFlowAccountsProvider tableState={cashflowAccountsTableState}>
|
||||
<CashFlowAccountsActionsBar />
|
||||
|
||||
<DashboardPageContent>
|
||||
<CashflowAccountsGrid />
|
||||
</DashboardPageContent>
|
||||
</CashFlowAccountsProvider>
|
||||
);
|
||||
}
|
||||
|
||||
export default compose(
|
||||
withCashflowAccounts(({ cashflowAccountsTableState }) => ({
|
||||
cashflowAccountsTableState,
|
||||
})),
|
||||
withCashflowAccountsTableActions,
|
||||
)(CashFlowAccountsList);
|
||||
@@ -0,0 +1,40 @@
|
||||
// @ts-nocheck
|
||||
import React from 'react';
|
||||
import { DashboardInsider } from '@/components/Dashboard';
|
||||
|
||||
import { useCashflowAccounts } from '@/hooks/query';
|
||||
import { transformAccountsStateToQuery } from './utils';
|
||||
|
||||
const CashFlowAccountsContext = React.createContext();
|
||||
|
||||
/**
|
||||
* Cash Flow data provider.
|
||||
*/
|
||||
function CashFlowAccountsProvider({ tableState, ...props }) {
|
||||
const query = transformAccountsStateToQuery(tableState);
|
||||
|
||||
// Fetch cash flow list .
|
||||
const {
|
||||
data: cashflowAccounts,
|
||||
isFetching: isCashFlowAccountsFetching,
|
||||
isLoading: isCashFlowAccountsLoading,
|
||||
} = useCashflowAccounts(query, { keepPreviousData: true });
|
||||
|
||||
// Provider payload.
|
||||
const provider = {
|
||||
cashflowAccounts,
|
||||
isCashFlowAccountsFetching,
|
||||
isCashFlowAccountsLoading,
|
||||
};
|
||||
|
||||
return (
|
||||
<DashboardInsider name={'cashflow-accounts'}>
|
||||
<CashFlowAccountsContext.Provider value={provider} {...props} />
|
||||
</DashboardInsider>
|
||||
);
|
||||
}
|
||||
|
||||
const useCashFlowAccountsContext = () =>
|
||||
React.useContext(CashFlowAccountsContext);
|
||||
|
||||
export { CashFlowAccountsProvider, useCashFlowAccountsContext };
|
||||
@@ -0,0 +1,319 @@
|
||||
// @ts-nocheck
|
||||
import React, { useMemo } from 'react';
|
||||
import intl from 'react-intl-universal';
|
||||
import styled from 'styled-components';
|
||||
import { isNull, isEmpty } from 'lodash';
|
||||
import { compose, curry } from 'lodash/fp';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { ContextMenu2 } from '@blueprintjs/popover2';
|
||||
import { Menu, MenuItem, MenuDivider, Intent } from '@blueprintjs/core';
|
||||
|
||||
import {
|
||||
AccountAction,
|
||||
CashflowAction,
|
||||
AbilitySubject,
|
||||
} from '@/constants/abilityOption';
|
||||
import { DialogsName } from '@/constants/dialogs';
|
||||
import {
|
||||
getAddMoneyInOptions,
|
||||
getAddMoneyOutOptions,
|
||||
} from '@/constants/cashflowOptions';
|
||||
|
||||
import { BankAccountsList, BankAccount, If, Icon, T, Can } from '@/components';
|
||||
import { useCashFlowAccountsContext } from './CashFlowAccountsProvider';
|
||||
|
||||
import withDrawerActions from '@/containers/Drawer/withDrawerActions';
|
||||
import withAlertsActions from '@/containers/Alert/withAlertActions';
|
||||
import withDialogActions from '@/containers/Dialog/withDialogActions';
|
||||
|
||||
import { AccountDialogAction } from '@/containers/Dialogs/AccountDialog/utils';
|
||||
import { safeCallback } from '@/utils';
|
||||
|
||||
const CASHFLOW_SKELETON_N = 4;
|
||||
|
||||
/**
|
||||
* Cashflow accounts skeleton for loading state.
|
||||
*/
|
||||
function CashflowAccountsSkeleton() {
|
||||
return [...Array(CASHFLOW_SKELETON_N)].map((e, i) => (
|
||||
<BankAccount
|
||||
title={'XXXXX'}
|
||||
code={'XXXXX'}
|
||||
balance={'XXXXXX'}
|
||||
cash={'cash'}
|
||||
loading={true}
|
||||
/>
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Cashflow bank account.
|
||||
*/
|
||||
function CashflowBankAccount({
|
||||
// #withAlertsDialog
|
||||
openAlert,
|
||||
|
||||
// #withDial
|
||||
openDialog,
|
||||
|
||||
// #withDrawerActions
|
||||
openDrawer,
|
||||
|
||||
account,
|
||||
}) {
|
||||
// Handle view detail account.
|
||||
const handleViewClick = () => {
|
||||
openDrawer('account-drawer', { accountId: account.id });
|
||||
};
|
||||
// Handle delete action account.
|
||||
const handleDeleteClick = () => {
|
||||
openAlert('account-delete', { accountId: account.id });
|
||||
};
|
||||
// Handle inactivate action account.
|
||||
const handleInactivateClick = () => {
|
||||
openAlert('account-inactivate', { accountId: account.id });
|
||||
};
|
||||
// Handle activate action account.
|
||||
const handleActivateClick = () => {
|
||||
openAlert('account-activate', { accountId: account.id });
|
||||
};
|
||||
// Handle edit account action.
|
||||
const handleEditAccount = () => {
|
||||
openDialog(DialogsName.AccountForm, {
|
||||
action: AccountDialogAction.Edit,
|
||||
id: account.id,
|
||||
});
|
||||
};
|
||||
// Handle money in menu item actions.
|
||||
const handleMoneyInClick = (transactionType) => {
|
||||
openDialog('money-in', {
|
||||
account_type: transactionType,
|
||||
account_id: account.id,
|
||||
});
|
||||
};
|
||||
// Handle money out menu item actions.
|
||||
const handleMoneyOutClick = (transactionType) => {
|
||||
openDialog('money-out', {
|
||||
account_type: transactionType,
|
||||
account_id: account.id,
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<ContextMenu2
|
||||
content={
|
||||
<CashflowAccountContextMenu
|
||||
account={account}
|
||||
onViewClick={handleViewClick}
|
||||
onDeleteClick={handleDeleteClick}
|
||||
onActivateClick={handleActivateClick}
|
||||
onInactivateClick={handleInactivateClick}
|
||||
onEditClick={handleEditAccount}
|
||||
onMoneyInClick={handleMoneyInClick}
|
||||
onMoneyOutClick={handleMoneyOutClick}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<CashflowAccountAnchor
|
||||
to={`/cashflow-accounts/${account.id}/transactions`}
|
||||
>
|
||||
<BankAccount
|
||||
title={account.name}
|
||||
code={account.code}
|
||||
balance={!isNull(account.amount) ? account.formatted_amount : '-'}
|
||||
type={account.account_type}
|
||||
updatedBeforeText={getUpdatedBeforeText(account.createdAt)}
|
||||
/>
|
||||
</CashflowAccountAnchor>
|
||||
</ContextMenu2>
|
||||
);
|
||||
}
|
||||
|
||||
const CashflowBankAccountEnhanced = compose(
|
||||
withAlertsActions,
|
||||
withDrawerActions,
|
||||
withDialogActions,
|
||||
)(CashflowBankAccount);
|
||||
|
||||
function getUpdatedBeforeText(createdAt) {
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Cashflow accounts grid items.
|
||||
*/
|
||||
function CashflowAccountsGridItems({ accounts }) {
|
||||
return accounts.map((account) => (
|
||||
<CashflowBankAccountEnhanced account={account} />
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Cashflow accounts empty state.
|
||||
*/
|
||||
function CashflowAccountsEmptyState() {
|
||||
return (
|
||||
<AccountsEmptyStateBase>
|
||||
<AccountsEmptyStateTitle>
|
||||
<T id={'cash_flow.accounts.no_results'} />
|
||||
</AccountsEmptyStateTitle>
|
||||
</AccountsEmptyStateBase>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cashflow accounts grid.
|
||||
*/
|
||||
export default function CashflowAccountsGrid() {
|
||||
// Retrieve list context.
|
||||
const { cashflowAccounts, isCashFlowAccountsLoading } =
|
||||
useCashFlowAccountsContext();
|
||||
|
||||
return (
|
||||
<CashflowAccountsGridWrap>
|
||||
<BankAccountsList>
|
||||
{isCashFlowAccountsLoading ? (
|
||||
<CashflowAccountsSkeleton />
|
||||
) : isEmpty(cashflowAccounts) ? (
|
||||
<CashflowAccountsEmptyState />
|
||||
) : (
|
||||
<CashflowAccountsGridItems accounts={cashflowAccounts} />
|
||||
)}
|
||||
</BankAccountsList>
|
||||
</CashflowAccountsGridWrap>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cashflow account money out context menu.
|
||||
*/
|
||||
function CashflowAccountMoneyInContextMenu({ onClick }) {
|
||||
const handleItemClick = curry((transactionType, event) => {
|
||||
onClick && onClick(transactionType, event);
|
||||
});
|
||||
// Retreives the add money in button options.
|
||||
const addMoneyInOptions = useMemo(() => getAddMoneyInOptions(), []);
|
||||
|
||||
return addMoneyInOptions.map((option) => (
|
||||
<MenuItem text={option.name} onClick={handleItemClick(option.value)} />
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Cashflow account money in context menu.
|
||||
*/
|
||||
function CashflowAccountMoneyOutContextMenu({ onClick }) {
|
||||
const handleItemClick = curry((transactionType, event) => {
|
||||
onClick && onClick(transactionType, event);
|
||||
});
|
||||
// Retreives the add money out button options.
|
||||
const addMoneyOutOptions = useMemo(() => getAddMoneyOutOptions(), []);
|
||||
|
||||
return addMoneyOutOptions.map((option) => (
|
||||
<MenuItem text={option.name} onClick={handleItemClick(option.value)} />
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Cashflow account context menu.
|
||||
*/
|
||||
function CashflowAccountContextMenu({
|
||||
account,
|
||||
onViewClick,
|
||||
onEditClick,
|
||||
onInactivateClick,
|
||||
onActivateClick,
|
||||
onDeleteClick,
|
||||
onMoneyInClick,
|
||||
onMoneyOutClick,
|
||||
}) {
|
||||
return (
|
||||
<Menu>
|
||||
<MenuItem
|
||||
icon={<Icon icon="reader-18" />}
|
||||
text={intl.get('view_details')}
|
||||
onClick={safeCallback(onViewClick)}
|
||||
/>
|
||||
<Can I={CashflowAction.Create} a={AbilitySubject.Cashflow}>
|
||||
<MenuDivider />
|
||||
<MenuItem
|
||||
text={<T id={'cash_flow_money_in'} />}
|
||||
icon={<Icon icon={'arrow-downward'} iconSize={16} />}
|
||||
>
|
||||
<CashflowAccountMoneyInContextMenu onClick={onMoneyInClick} />
|
||||
</MenuItem>
|
||||
|
||||
<MenuItem
|
||||
text={<T id={'cash_flow_money_out'} />}
|
||||
icon={<Icon icon={'arrow-upward'} iconSize={16} />}
|
||||
>
|
||||
<CashflowAccountMoneyOutContextMenu onClick={onMoneyOutClick} />
|
||||
</MenuItem>
|
||||
</Can>
|
||||
<Can I={CashflowAction.Edit} a={AbilitySubject.Cashflow}>
|
||||
<MenuDivider />
|
||||
|
||||
<MenuItem
|
||||
icon={<Icon icon="pen-18" />}
|
||||
text={intl.get('edit_account')}
|
||||
onClick={safeCallback(onEditClick)}
|
||||
/>
|
||||
</Can>
|
||||
<Can I={AccountAction.Edit} a={AbilitySubject.Account}>
|
||||
<MenuDivider />
|
||||
<If condition={account.active}>
|
||||
<MenuItem
|
||||
text={intl.get('inactivate_account')}
|
||||
icon={<Icon icon="pause-16" iconSize={16} />}
|
||||
onClick={safeCallback(onInactivateClick)}
|
||||
/>
|
||||
</If>
|
||||
<If condition={!account.active}>
|
||||
<MenuItem
|
||||
text={intl.get('activate_account')}
|
||||
icon={<Icon icon="play-16" iconSize={16} />}
|
||||
onClick={safeCallback(onActivateClick)}
|
||||
/>
|
||||
</If>
|
||||
</Can>
|
||||
<Can I={CashflowAction.Delete} a={AbilitySubject.Cashflow}>
|
||||
<MenuDivider />
|
||||
<MenuItem
|
||||
text={intl.get('delete_account')}
|
||||
icon={<Icon icon="trash-16" iconSize={16} />}
|
||||
intent={Intent.DANGER}
|
||||
onClick={safeCallback(onDeleteClick)}
|
||||
/>
|
||||
</Can>
|
||||
</Menu>
|
||||
);
|
||||
}
|
||||
|
||||
const CashflowAccountAnchor = styled(Link)`
|
||||
&,
|
||||
&:hover,
|
||||
&:focus,
|
||||
&:active {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
`;
|
||||
|
||||
const CashflowAccountsGridWrap = styled.div`
|
||||
margin: 30px;
|
||||
`;
|
||||
|
||||
const CashflowBankAccountWrap = styled.div``;
|
||||
|
||||
const AccountsEmptyStateBase = styled.div`
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
margin: 2rem 0;
|
||||
`;
|
||||
const AccountsEmptyStateTitle = styled.h1`
|
||||
font-size: 16px;
|
||||
color: #626b76;
|
||||
opacity: 0.8;
|
||||
line-height: 1.6;
|
||||
font-weight: 500;
|
||||
`;
|
||||
@@ -0,0 +1,93 @@
|
||||
// @ts-nocheck
|
||||
import React from 'react';
|
||||
|
||||
import intl from 'react-intl-universal';
|
||||
import { Intent, Tag } from '@blueprintjs/core';
|
||||
import { isBlank } from '@/utils';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
/**
|
||||
* Account code accessor.
|
||||
*/
|
||||
export const AccountCodeAccessor = (row) =>
|
||||
!isBlank(row.code) ? (
|
||||
<Tag minimal={true} round={true} intent={Intent.NONE}>
|
||||
{row.code}
|
||||
</Tag>
|
||||
) : null;
|
||||
|
||||
/**
|
||||
* Balance cell.
|
||||
*/
|
||||
export const BalanceCell = ({ cell }) => {
|
||||
const account = cell.row.original;
|
||||
|
||||
return account.amount !== null ? (
|
||||
<span>{account.formatted_amount}</span>
|
||||
) : (
|
||||
<span class="placeholder">—</span>
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Account cell.
|
||||
*/
|
||||
const AccountCell = ({ row }) => {
|
||||
const account = row.original;
|
||||
return (
|
||||
<>
|
||||
<div>X</div>
|
||||
<Link to={`/account/${account.id}/transactions`}>{account.name}</Link>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieve Cash flow table columns.
|
||||
*/
|
||||
export function useCashFlowAccountsTableColumns() {
|
||||
return React.useMemo(
|
||||
() => [
|
||||
{
|
||||
id: 'name',
|
||||
Header: intl.get('account_name'),
|
||||
accessor: 'name',
|
||||
Cell: AccountCell,
|
||||
className: 'account_name',
|
||||
width: 200,
|
||||
textOverview: true,
|
||||
},
|
||||
{
|
||||
id: 'code',
|
||||
Header: intl.get('code'),
|
||||
accessor: 'code',
|
||||
className: 'code',
|
||||
width: 80,
|
||||
},
|
||||
{
|
||||
id: 'type',
|
||||
Header: intl.get('type'),
|
||||
accessor: 'account_type_label',
|
||||
className: 'type',
|
||||
width: 140,
|
||||
textOverview: true,
|
||||
},
|
||||
{
|
||||
id: 'currency',
|
||||
Header: intl.get('currency'),
|
||||
accessor: 'currency_code',
|
||||
width: 75,
|
||||
},
|
||||
{
|
||||
id: 'balance',
|
||||
Header: intl.get('balance'),
|
||||
accessor: 'amount',
|
||||
className: 'balance',
|
||||
Cell: BalanceCell,
|
||||
width: 150,
|
||||
align: 'right',
|
||||
},
|
||||
],
|
||||
[],
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
// @ts-nocheck
|
||||
import { transformTableStateToQuery } from '@/utils';
|
||||
|
||||
/**
|
||||
* Transformes the table state to list query.
|
||||
*/
|
||||
export const transformAccountsStateToQuery = (tableState) => {
|
||||
return {
|
||||
...transformTableStateToQuery(tableState),
|
||||
inactive_mode: tableState.inactiveMode,
|
||||
};
|
||||
};
|
||||
Reference in New Issue
Block a user