mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-20 14:50:32 +00:00
feat: bulk categorize and match bank transactions
This commit is contained in:
@@ -12,6 +12,8 @@ import {
|
|||||||
PopoverInteractionKind,
|
PopoverInteractionKind,
|
||||||
Position,
|
Position,
|
||||||
Intent,
|
Intent,
|
||||||
|
Switch,
|
||||||
|
Tooltip,
|
||||||
} from '@blueprintjs/core';
|
} from '@blueprintjs/core';
|
||||||
import { useHistory } from 'react-router-dom';
|
import { useHistory } from 'react-router-dom';
|
||||||
import {
|
import {
|
||||||
@@ -39,9 +41,9 @@ import { withBanking } from '../withBanking';
|
|||||||
import { isEmpty } from 'lodash';
|
import { isEmpty } from 'lodash';
|
||||||
import {
|
import {
|
||||||
useExcludeUncategorizedTransactions,
|
useExcludeUncategorizedTransactions,
|
||||||
useUnexcludeUncategorizedTransaction,
|
|
||||||
useUnexcludeUncategorizedTransactions,
|
useUnexcludeUncategorizedTransactions,
|
||||||
} from '@/hooks/query/bank-rules';
|
} from '@/hooks/query/bank-rules';
|
||||||
|
import { withBankingActions } from '../withBankingActions';
|
||||||
|
|
||||||
function AccountTransactionsActionsBar({
|
function AccountTransactionsActionsBar({
|
||||||
// #withDialogActions
|
// #withDialogActions
|
||||||
@@ -56,6 +58,9 @@ function AccountTransactionsActionsBar({
|
|||||||
// #withBanking
|
// #withBanking
|
||||||
uncategorizedTransationsIdsSelected,
|
uncategorizedTransationsIdsSelected,
|
||||||
excludedTransactionsIdsSelected,
|
excludedTransactionsIdsSelected,
|
||||||
|
|
||||||
|
// #withBankingActions
|
||||||
|
enableMultipleCategorization,
|
||||||
}) {
|
}) {
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
const { accountId } = useAccountTransactionsContext();
|
const { accountId } = useAccountTransactionsContext();
|
||||||
@@ -148,6 +153,10 @@ function AccountTransactionsActionsBar({
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleMultipleCategorizingSwitch = (event) => {
|
||||||
|
enableMultipleCategorization(event.currentTarget.checked);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DashboardActionsBar>
|
<DashboardActionsBar>
|
||||||
<NavbarGroup>
|
<NavbarGroup>
|
||||||
@@ -201,7 +210,6 @@ function AccountTransactionsActionsBar({
|
|||||||
disable={isExcludingLoading}
|
disable={isExcludingLoading}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{!isEmpty(excludedTransactionsIdsSelected) && (
|
{!isEmpty(excludedTransactionsIdsSelected) && (
|
||||||
<Button
|
<Button
|
||||||
icon={<Icon icon="disable" iconSize={16} />}
|
icon={<Icon icon="disable" iconSize={16} />}
|
||||||
@@ -215,6 +223,20 @@ function AccountTransactionsActionsBar({
|
|||||||
</NavbarGroup>
|
</NavbarGroup>
|
||||||
|
|
||||||
<NavbarGroup align={Alignment.RIGHT}>
|
<NavbarGroup align={Alignment.RIGHT}>
|
||||||
|
<Tooltip
|
||||||
|
content={
|
||||||
|
'Enables to categorize or matching multiple bank transactions into one transaction.'
|
||||||
|
}
|
||||||
|
position={Position.BOTTOM}
|
||||||
|
minimal
|
||||||
|
>
|
||||||
|
<Switch
|
||||||
|
label={'Multi Select'}
|
||||||
|
inline
|
||||||
|
onChange={handleMultipleCategorizingSwitch}
|
||||||
|
/>
|
||||||
|
</Tooltip>
|
||||||
|
<NavbarDivider />
|
||||||
<Popover
|
<Popover
|
||||||
minimal={true}
|
minimal={true}
|
||||||
interactionKind={PopoverInteractionKind.CLICK}
|
interactionKind={PopoverInteractionKind.CLICK}
|
||||||
@@ -256,4 +278,5 @@ export default compose(
|
|||||||
excludedTransactionsIdsSelected,
|
excludedTransactionsIdsSelected,
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
|
withBankingActions,
|
||||||
)(AccountTransactionsActionsBar);
|
)(AccountTransactionsActionsBar);
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
|
||||||
|
|
||||||
|
.table :global .td.categorize_include,
|
||||||
|
.table :global .th.categorize_include {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table.showCategorizeColumn :global .td.categorize_include,
|
||||||
|
.table.showCategorizeColumn :global .th.categorize_include {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.categorizeCheckbox:global(.bp4-checkbox) :global .bp4-control-indicator {
|
||||||
|
border-radius: 20px;
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
// @ts-nocheck
|
// @ts-nocheck
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import clsx from 'classnames';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
import { Intent } from '@blueprintjs/core';
|
import { Intent } from '@blueprintjs/core';
|
||||||
import {
|
import {
|
||||||
@@ -12,17 +13,19 @@ import {
|
|||||||
AppToaster,
|
AppToaster,
|
||||||
} from '@/components';
|
} from '@/components';
|
||||||
import { TABLES } from '@/constants/tables';
|
import { TABLES } from '@/constants/tables';
|
||||||
import { ActionsMenu } from './UncategorizedTransactions/components';
|
import { ActionsMenu } from './components';
|
||||||
|
|
||||||
import withSettings from '@/containers/Settings/withSettings';
|
import withSettings from '@/containers/Settings/withSettings';
|
||||||
import { withBankingActions } from '../withBankingActions';
|
import { withBankingActions } from '../../withBankingActions';
|
||||||
|
|
||||||
import { useMemorizedColumnsWidths } from '@/hooks';
|
import { useMemorizedColumnsWidths } from '@/hooks';
|
||||||
import { useAccountUncategorizedTransactionsColumns } from './components';
|
import { useAccountUncategorizedTransactionsContext } from '../AllTransactionsUncategorizedBoot';
|
||||||
import { useAccountUncategorizedTransactionsContext } from './AllTransactionsUncategorizedBoot';
|
|
||||||
import { useExcludeUncategorizedTransaction } from '@/hooks/query/bank-rules';
|
import { useExcludeUncategorizedTransaction } from '@/hooks/query/bank-rules';
|
||||||
|
import { useAccountUncategorizedTransactionsColumns } from './hooks';
|
||||||
|
|
||||||
import { compose } from '@/utils';
|
import { compose } from '@/utils';
|
||||||
|
import { withBanking } from '../../withBanking';
|
||||||
|
import styles from './AccountTransactionsUncategorizedTable.module.scss';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Account transactions data table.
|
* Account transactions data table.
|
||||||
@@ -31,6 +34,9 @@ function AccountTransactionsDataTable({
|
|||||||
// #withSettings
|
// #withSettings
|
||||||
cashflowTansactionsTableSize,
|
cashflowTansactionsTableSize,
|
||||||
|
|
||||||
|
// #withBanking
|
||||||
|
openMatchingTransactionAside,
|
||||||
|
|
||||||
// #withBankingActions
|
// #withBankingActions
|
||||||
setUncategorizedTransactionIdForMatching,
|
setUncategorizedTransactionIdForMatching,
|
||||||
setUncategorizedTransactionsSelected,
|
setUncategorizedTransactionsSelected,
|
||||||
@@ -66,7 +72,7 @@ function AccountTransactionsDataTable({
|
|||||||
message: 'The bank transaction has been excluded successfully.',
|
message: 'The bank transaction has been excluded successfully.',
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch(() => {
|
||||||
AppToaster.show({
|
AppToaster.show({
|
||||||
intent: Intent.DANGER,
|
intent: Intent.DANGER,
|
||||||
message: 'Something went wrong.',
|
message: 'Something went wrong.',
|
||||||
@@ -106,12 +112,14 @@ function AccountTransactionsDataTable({
|
|||||||
noResults={
|
noResults={
|
||||||
'There is no uncategorized transactions in the current account.'
|
'There is no uncategorized transactions in the current account.'
|
||||||
}
|
}
|
||||||
className="table-constrant"
|
|
||||||
onSelectedRowsChange={handleSelectedRowsChange}
|
onSelectedRowsChange={handleSelectedRowsChange}
|
||||||
payload={{
|
payload={{
|
||||||
onExclude: handleExcludeTransaction,
|
onExclude: handleExcludeTransaction,
|
||||||
onCategorize: handleCategorizeBtnClick,
|
onCategorize: handleCategorizeBtnClick,
|
||||||
}}
|
}}
|
||||||
|
className={clsx('table-constrant', styles.table, {
|
||||||
|
[styles.showCategorizeColumn]: openMatchingTransactionAside,
|
||||||
|
})}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -121,6 +129,9 @@ export default compose(
|
|||||||
cashflowTansactionsTableSize: cashflowTransactionsSettings?.tableSize,
|
cashflowTansactionsTableSize: cashflowTransactionsSettings?.tableSize,
|
||||||
})),
|
})),
|
||||||
withBankingActions,
|
withBankingActions,
|
||||||
|
withBanking(({ openMatchingTransactionAside }) => ({
|
||||||
|
openMatchingTransactionAside,
|
||||||
|
})),
|
||||||
)(AccountTransactionsDataTable);
|
)(AccountTransactionsDataTable);
|
||||||
|
|
||||||
const DashboardConstrantTable = styled(DataTable)`
|
const DashboardConstrantTable = styled(DataTable)`
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import * as R from 'ramda';
|
import * as R from 'ramda';
|
||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
import AccountTransactionsUncategorizedTable from '../AccountTransactionsUncategorizedTable';
|
import AccountTransactionsUncategorizedTable from './AccountTransactionsUncategorizedTable';
|
||||||
import { AccountUncategorizedTransactionsBoot } from '../AllTransactionsUncategorizedBoot';
|
import { AccountUncategorizedTransactionsBoot } from '../AllTransactionsUncategorizedBoot';
|
||||||
import { AccountTransactionsCard } from './AccountTransactionsCard';
|
import { AccountTransactionsCard } from './AccountTransactionsCard';
|
||||||
import {
|
import {
|
||||||
|
|||||||
@@ -0,0 +1,143 @@
|
|||||||
|
// @ts-nocheck
|
||||||
|
import React from 'react';
|
||||||
|
import intl from 'react-intl-universal';
|
||||||
|
import {
|
||||||
|
Checkbox,
|
||||||
|
Intent,
|
||||||
|
PopoverInteractionKind,
|
||||||
|
Position,
|
||||||
|
Tag,
|
||||||
|
Tooltip,
|
||||||
|
} from '@blueprintjs/core';
|
||||||
|
import {
|
||||||
|
useAddTransactionsToCategorizeSelected,
|
||||||
|
useRemoveTransactionsToCategorizeSelected,
|
||||||
|
} from '@/hooks/state/banking';
|
||||||
|
import { Box, Icon } from '@/components';
|
||||||
|
import styles from './AccountTransactionsUncategorizedTable.module.scss';
|
||||||
|
|
||||||
|
function statusAccessor(transaction) {
|
||||||
|
return transaction.is_recognized ? (
|
||||||
|
<Tooltip
|
||||||
|
// compact
|
||||||
|
interactionKind={PopoverInteractionKind.HOVER}
|
||||||
|
position={Position.RIGHT}
|
||||||
|
content={
|
||||||
|
<Box>
|
||||||
|
<span>{transaction.assigned_category_formatted}</span>
|
||||||
|
<Icon
|
||||||
|
icon={'arrowRight'}
|
||||||
|
color={'#8F99A8'}
|
||||||
|
iconSize={12}
|
||||||
|
style={{ marginLeft: 8, marginRight: 8 }}
|
||||||
|
/>
|
||||||
|
<span>{transaction.assigned_account_name}</span>
|
||||||
|
</Box>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Box>
|
||||||
|
<Tag intent={Intent.SUCCESS} interactive>
|
||||||
|
Recognized
|
||||||
|
</Tag>
|
||||||
|
</Box>
|
||||||
|
</Tooltip>
|
||||||
|
) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve account uncategorized transctions table columns.
|
||||||
|
*/
|
||||||
|
export function useAccountUncategorizedTransactionsColumns() {
|
||||||
|
const addTransactionsToCategorizeSelected =
|
||||||
|
useAddTransactionsToCategorizeSelected();
|
||||||
|
|
||||||
|
const removeTransactionsToCategorizeSelected =
|
||||||
|
useRemoveTransactionsToCategorizeSelected();
|
||||||
|
|
||||||
|
const handleChange = (value) => (event) => {
|
||||||
|
if (event.currentTarget.checked) {
|
||||||
|
addTransactionsToCategorizeSelected(value.id);
|
||||||
|
} else {
|
||||||
|
removeTransactionsToCategorizeSelected(value.id);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
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: 'Ref.#',
|
||||||
|
accessor: 'reference_no',
|
||||||
|
width: 50,
|
||||||
|
clickable: true,
|
||||||
|
textOverview: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'status',
|
||||||
|
Header: 'Status',
|
||||||
|
accessor: statusAccessor,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
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,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'categorize_include',
|
||||||
|
Header: '',
|
||||||
|
accessor: (value) => (
|
||||||
|
<Checkbox
|
||||||
|
large
|
||||||
|
onChange={handleChange(value)}
|
||||||
|
className={styles.categorizeCheckbox}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
width: 10,
|
||||||
|
minWidth: 10,
|
||||||
|
maxWidth: 10,
|
||||||
|
align: 'right',
|
||||||
|
className: 'categorize_include',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
[],
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -9,15 +9,10 @@ import {
|
|||||||
PopoverInteractionKind,
|
PopoverInteractionKind,
|
||||||
Position,
|
Position,
|
||||||
Tooltip,
|
Tooltip,
|
||||||
Checkbox,
|
|
||||||
} from '@blueprintjs/core';
|
} from '@blueprintjs/core';
|
||||||
import { Box, FormatDateCell, Icon, MaterialProgressBar } from '@/components';
|
import { Box, FormatDateCell, Icon, MaterialProgressBar } from '@/components';
|
||||||
import { useAccountTransactionsContext } from './AccountTransactionsProvider';
|
import { useAccountTransactionsContext } from './AccountTransactionsProvider';
|
||||||
import { safeCallback } from '@/utils';
|
import { safeCallback } from '@/utils';
|
||||||
import {
|
|
||||||
useAddTransactionsToCategorizeSelected,
|
|
||||||
useRemoveTransactionsToCategorizeSelected,
|
|
||||||
} from '@/hooks/state/banking';
|
|
||||||
|
|
||||||
export function ActionsMenu({
|
export function ActionsMenu({
|
||||||
payload: { onUncategorize, onUnmatch },
|
payload: { onUncategorize, onUnmatch },
|
||||||
@@ -155,122 +150,3 @@ export function AccountTransactionsProgressBar() {
|
|||||||
<MaterialProgressBar />
|
<MaterialProgressBar />
|
||||||
) : null;
|
) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function statusAccessor(transaction) {
|
|
||||||
return transaction.is_recognized ? (
|
|
||||||
<Tooltip
|
|
||||||
compact
|
|
||||||
interactionKind={PopoverInteractionKind.HOVER}
|
|
||||||
position={Position.RIGHT}
|
|
||||||
content={
|
|
||||||
<Box>
|
|
||||||
<span>{transaction.assigned_category_formatted}</span>
|
|
||||||
<Icon
|
|
||||||
icon={'arrowRight'}
|
|
||||||
color={'#8F99A8'}
|
|
||||||
iconSize={12}
|
|
||||||
style={{ marginLeft: 8, marginRight: 8 }}
|
|
||||||
/>
|
|
||||||
<span>{transaction.assigned_account_name}</span>
|
|
||||||
</Box>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<Box>
|
|
||||||
<Tag intent={Intent.SUCCESS} interactive>
|
|
||||||
Recognized
|
|
||||||
</Tag>
|
|
||||||
</Box>
|
|
||||||
</Tooltip>
|
|
||||||
) : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieve account uncategorized transctions table columns.
|
|
||||||
*/
|
|
||||||
export function useAccountUncategorizedTransactionsColumns() {
|
|
||||||
const addTransactionsToCategorizeSelected =
|
|
||||||
useAddTransactionsToCategorizeSelected();
|
|
||||||
|
|
||||||
const removeTransactionsToCategorizeSelected =
|
|
||||||
useRemoveTransactionsToCategorizeSelected();
|
|
||||||
|
|
||||||
const handleChange = (value) => (event) => {
|
|
||||||
if (event.currentTarget.checked) {
|
|
||||||
addTransactionsToCategorizeSelected(value.id);
|
|
||||||
} else {
|
|
||||||
removeTransactionsToCategorizeSelected(value.id);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
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: 'Ref.#',
|
|
||||||
accessor: 'reference_no',
|
|
||||||
width: 50,
|
|
||||||
clickable: true,
|
|
||||||
textOverview: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'status',
|
|
||||||
Header: 'Status',
|
|
||||||
accessor: statusAccessor,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
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,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'categorize_include',
|
|
||||||
Header: 'Include',
|
|
||||||
accessor: (value) => <Checkbox large onChange={handleChange(value)} />,
|
|
||||||
width: 10,
|
|
||||||
minWidth: 10,
|
|
||||||
maxWidth: 10,
|
|
||||||
align: 'right',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
[],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ export const withBanking = (mapState) => {
|
|||||||
state.plaid.uncategorizedTransactionsSelected,
|
state.plaid.uncategorizedTransactionsSelected,
|
||||||
|
|
||||||
excludedTransactionsIdsSelected: state.plaid.excludedTransactionsSelected,
|
excludedTransactionsIdsSelected: state.plaid.excludedTransactionsSelected,
|
||||||
|
isMultipleCategorization: state.plaid.isMultipleCategorization,
|
||||||
};
|
};
|
||||||
return mapState ? mapState(mapped, state, props) : mapped;
|
return mapState ? mapState(mapped, state, props) : mapped;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import {
|
|||||||
setExcludedTransactionsSelected,
|
setExcludedTransactionsSelected,
|
||||||
resetTransactionsToCategorizeSelected,
|
resetTransactionsToCategorizeSelected,
|
||||||
setTransactionsToCategorizeSelected,
|
setTransactionsToCategorizeSelected,
|
||||||
|
enableMultipleCategorization,
|
||||||
} from '@/store/banking/banking.reducer';
|
} from '@/store/banking/banking.reducer';
|
||||||
|
|
||||||
export interface WithBankingActionsProps {
|
export interface WithBankingActionsProps {
|
||||||
@@ -28,6 +29,8 @@ export interface WithBankingActionsProps {
|
|||||||
|
|
||||||
setTransactionsToCategorizeSelected: (ids: Array<string | number>) => void;
|
setTransactionsToCategorizeSelected: (ids: Array<string | number>) => void;
|
||||||
resetTransactionsToCategorizeSelected: () => void;
|
resetTransactionsToCategorizeSelected: () => void;
|
||||||
|
|
||||||
|
enableMultipleCategorization: (enable: boolean) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const mapDipatchToProps = (dispatch: any): WithBankingActionsProps => ({
|
const mapDipatchToProps = (dispatch: any): WithBankingActionsProps => ({
|
||||||
@@ -66,6 +69,9 @@ const mapDipatchToProps = (dispatch: any): WithBankingActionsProps => ({
|
|||||||
dispatch(setTransactionsToCategorizeSelected({ ids })),
|
dispatch(setTransactionsToCategorizeSelected({ ids })),
|
||||||
resetTransactionsToCategorizeSelected: () =>
|
resetTransactionsToCategorizeSelected: () =>
|
||||||
dispatch(resetTransactionsToCategorizeSelected()),
|
dispatch(resetTransactionsToCategorizeSelected()),
|
||||||
|
|
||||||
|
enableMultipleCategorization: (enable) =>
|
||||||
|
dispatch(enableMultipleCategorization({ enable })),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const withBankingActions = connect<
|
export const withBankingActions = connect<
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import {
|
|||||||
getTransactionsToCategorizeSelected,
|
getTransactionsToCategorizeSelected,
|
||||||
addTransactionsToCategorizeSelected,
|
addTransactionsToCategorizeSelected,
|
||||||
removeTransactionsToCategorizeSelected,
|
removeTransactionsToCategorizeSelected,
|
||||||
|
getOpenMatchingTransactionAside,
|
||||||
} from '@/store/banking/banking.reducer';
|
} from '@/store/banking/banking.reducer';
|
||||||
|
|
||||||
export const useSetBankingPlaidToken = () => {
|
export const useSetBankingPlaidToken = () => {
|
||||||
@@ -82,3 +83,14 @@ export const useResetTransactionsToCategorizeSelected = () => {
|
|||||||
dispatch(resetTransactionsToCategorizeSelected());
|
dispatch(resetTransactionsToCategorizeSelected());
|
||||||
}, [dispatch]);
|
}, [dispatch]);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const useGetOpenMatchingTransactionAside = () => {
|
||||||
|
const openMatchingTransactionAside = useSelector(
|
||||||
|
getOpenMatchingTransactionAside,
|
||||||
|
);
|
||||||
|
|
||||||
|
return useMemo(
|
||||||
|
() => openMatchingTransactionAside,
|
||||||
|
[openMatchingTransactionAside],
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ interface StorePlaidState {
|
|||||||
uncategorizedTransactionsSelected: Array<number | string>;
|
uncategorizedTransactionsSelected: Array<number | string>;
|
||||||
excludedTransactionsSelected: Array<number | string>;
|
excludedTransactionsSelected: Array<number | string>;
|
||||||
transactionsToCategorizeSelected: Array<number | string>;
|
transactionsToCategorizeSelected: Array<number | string>;
|
||||||
|
|
||||||
|
enableMultipleCategorization: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const PlaidSlice = createSlice({
|
export const PlaidSlice = createSlice({
|
||||||
@@ -25,6 +27,7 @@ export const PlaidSlice = createSlice({
|
|||||||
uncategorizedTransactionsSelected: [],
|
uncategorizedTransactionsSelected: [],
|
||||||
excludedTransactionsSelected: [],
|
excludedTransactionsSelected: [],
|
||||||
transactionsToCategorizeSelected: [],
|
transactionsToCategorizeSelected: [],
|
||||||
|
enableMultipleCategorization: false,
|
||||||
} as StorePlaidState,
|
} as StorePlaidState,
|
||||||
reducers: {
|
reducers: {
|
||||||
setPlaidId: (state: StorePlaidState, action: PayloadAction<string>) => {
|
setPlaidId: (state: StorePlaidState, action: PayloadAction<string>) => {
|
||||||
@@ -113,6 +116,13 @@ export const PlaidSlice = createSlice({
|
|||||||
resetTransactionsToCategorizeSelected: (state: StorePlaidState) => {
|
resetTransactionsToCategorizeSelected: (state: StorePlaidState) => {
|
||||||
state.transactionsToCategorizeSelected = [];
|
state.transactionsToCategorizeSelected = [];
|
||||||
},
|
},
|
||||||
|
|
||||||
|
enableMultipleCategorization: (
|
||||||
|
state: StorePlaidState,
|
||||||
|
action: PayloadAction<{ enable: boolean }>,
|
||||||
|
) => {
|
||||||
|
state.enableMultipleCategorization = action.payload.enable;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -131,8 +141,15 @@ export const {
|
|||||||
addTransactionsToCategorizeSelected,
|
addTransactionsToCategorizeSelected,
|
||||||
removeTransactionsToCategorizeSelected,
|
removeTransactionsToCategorizeSelected,
|
||||||
resetTransactionsToCategorizeSelected,
|
resetTransactionsToCategorizeSelected,
|
||||||
|
enableMultipleCategorization,
|
||||||
} = PlaidSlice.actions;
|
} = PlaidSlice.actions;
|
||||||
|
|
||||||
export const getPlaidToken = (state: any) => state.plaid.plaidToken;
|
export const getPlaidToken = (state: any) => state.plaid.plaidToken;
|
||||||
export const getTransactionsToCategorizeSelected = (state: any) =>
|
export const getTransactionsToCategorizeSelected = (state: any) =>
|
||||||
state.plaid.transactionsToCategorizeSelected;
|
state.plaid.transactionsToCategorizeSelected;
|
||||||
|
|
||||||
|
export const getOpenMatchingTransactionAside = (state: any) =>
|
||||||
|
state.plaid.openMatchingTransactionAside;
|
||||||
|
|
||||||
|
export const isMultipleCategorization = (state: any) =>
|
||||||
|
state.plaid.enableMultipleCategorization;
|
||||||
|
|||||||
@@ -124,7 +124,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.bp4-control.bp4-checkbox .bp4-control-indicator {
|
.bp4-control.bp4-checkbox:not(.bp4-large) .bp4-control-indicator {
|
||||||
cursor: auto;
|
cursor: auto;
|
||||||
|
|
||||||
&,
|
&,
|
||||||
|
|||||||
Reference in New Issue
Block a user