feat: bulk categorizing bank transactions

This commit is contained in:
Ahmed Bouhuolia
2024-07-18 17:00:23 +02:00
parent 51471ed000
commit 449390143d
18 changed files with 335 additions and 126 deletions

View File

@@ -9,10 +9,15 @@ import {
PopoverInteractionKind,
Position,
Tooltip,
Checkbox,
} from '@blueprintjs/core';
import { Box, FormatDateCell, Icon, MaterialProgressBar } from '@/components';
import { useAccountTransactionsContext } from './AccountTransactionsProvider';
import { safeCallback } from '@/utils';
import {
useAddTransactionsToCategorizeSelected,
useRemoveTransactionsToCategorizeSelected,
} from '@/hooks/state/banking';
export function ActionsMenu({
payload: { onUncategorize, onUnmatch },
@@ -183,6 +188,20 @@ function statusAccessor(transaction) {
* 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(
() => [
{
@@ -242,6 +261,15 @@ export function useAccountUncategorizedTransactionsColumns() {
align: 'right',
clickable: true,
},
{
id: 'categorize_include',
Header: 'Include',
accessor: (value) => <Checkbox large onChange={handleChange(value)} />,
width: 10,
minWidth: 10,
maxWidth: 10,
align: 'right',
},
],
[],
);

View File

@@ -8,6 +8,8 @@ import {
resetUncategorizedTransactionsSelected,
resetExcludedTransactionsSelected,
setExcludedTransactionsSelected,
resetTransactionsToCategorizeSelected,
setTransactionsToCategorizeSelected,
} from '@/store/banking/banking.reducer';
export interface WithBankingActionsProps {
@@ -23,6 +25,9 @@ export interface WithBankingActionsProps {
setExcludedTransactionsSelected: (ids: Array<string | number>) => void;
resetExcludedTransactionsSelected: () => void;
setTransactionsToCategorizeSelected: (ids: Array<string | number>) => void;
resetTransactionsToCategorizeSelected: () => void;
}
const mapDipatchToProps = (dispatch: any): WithBankingActionsProps => ({
@@ -56,6 +61,11 @@ const mapDipatchToProps = (dispatch: any): WithBankingActionsProps => ({
),
resetExcludedTransactionsSelected: () =>
dispatch(resetExcludedTransactionsSelected()),
setTransactionsToCategorizeSelected: (ids: Array<string | number>) =>
dispatch(setTransactionsToCategorizeSelected({ ids })),
resetTransactionsToCategorizeSelected: () =>
dispatch(resetTransactionsToCategorizeSelected()),
});
export const withBankingActions = connect<

View File

@@ -1,10 +1,15 @@
import { useDispatch, useSelector } from 'react-redux';
import { useCallback, useMemo } from 'react';
import {
getPlaidToken,
setPlaidId,
resetPlaidId,
setTransactionsToCategorizeSelected,
resetTransactionsToCategorizeSelected,
getTransactionsToCategorizeSelected,
addTransactionsToCategorizeSelected,
removeTransactionsToCategorizeSelected,
} from '@/store/banking/banking.reducer';
import { useCallback } from 'react';
import { useDispatch, useSelector } from 'react-redux';
export const useSetBankingPlaidToken = () => {
const dispatch = useDispatch();
@@ -30,3 +35,50 @@ export const useResetBankingPlaidToken = () => {
dispatch(resetPlaidId());
}, [dispatch]);
};
export const useGetTransactionsToCategorizeSelected = () => {
const selectedTransactions = useSelector(getTransactionsToCategorizeSelected);
return useMemo(() => selectedTransactions, [selectedTransactions]);
};
export const useSetTransactionsToCategorizeSelected = () => {
const dispatch = useDispatch();
return useCallback(
(ids: Array<string | number>) => {
return dispatch(setTransactionsToCategorizeSelected({ ids }));
},
[dispatch],
);
};
export const useAddTransactionsToCategorizeSelected = () => {
const dispatch = useDispatch();
return useCallback(
(id: string | number) => {
return dispatch(addTransactionsToCategorizeSelected({ id }));
},
[dispatch],
);
};
export const useRemoveTransactionsToCategorizeSelected = () => {
const dispatch = useDispatch();
return useCallback(
(id: string | number) => {
return dispatch(removeTransactionsToCategorizeSelected({ id }));
},
[dispatch],
);
};
export const useResetTransactionsToCategorizeSelected = () => {
const dispatch = useDispatch();
return useCallback(() => {
dispatch(resetTransactionsToCategorizeSelected());
}, [dispatch]);
};

View File

@@ -1,3 +1,4 @@
import { uniq } from 'lodash';
import { PayloadAction, createSlice } from '@reduxjs/toolkit';
interface StorePlaidState {
@@ -8,6 +9,7 @@ interface StorePlaidState {
uncategorizedTransactionsSelected: Array<number | string>;
excludedTransactionsSelected: Array<number | string>;
transactionsToCategorizeSelected: Array<number | string>;
}
export const PlaidSlice = createSlice({
@@ -22,6 +24,7 @@ export const PlaidSlice = createSlice({
},
uncategorizedTransactionsSelected: [],
excludedTransactionsSelected: [],
transactionsToCategorizeSelected: [],
} as StorePlaidState,
reducers: {
setPlaidId: (state: StorePlaidState, action: PayloadAction<string>) => {
@@ -79,6 +82,37 @@ export const PlaidSlice = createSlice({
resetExcludedTransactionsSelected: (state: StorePlaidState) => {
state.excludedTransactionsSelected = [];
},
setTransactionsToCategorizeSelected: (
state: StorePlaidState,
action: PayloadAction<{ ids: Array<string | number> }>,
) => {
state.transactionsToCategorizeSelected = action.payload.ids;
},
addTransactionsToCategorizeSelected: (
state: StorePlaidState,
action: PayloadAction<{ id: string | number }>,
) => {
state.transactionsToCategorizeSelected = uniq([
...state.transactionsToCategorizeSelected,
action.payload.id,
]);
},
removeTransactionsToCategorizeSelected: (
state: StorePlaidState,
action: PayloadAction<{ id: string | number }>,
) => {
state.transactionsToCategorizeSelected =
state.transactionsToCategorizeSelected.filter(
(t) => t !== action.payload.id,
);
},
resetTransactionsToCategorizeSelected: (state: StorePlaidState) => {
state.transactionsToCategorizeSelected = [];
},
},
});
@@ -93,6 +127,12 @@ export const {
resetUncategorizedTransactionsSelected,
setExcludedTransactionsSelected,
resetExcludedTransactionsSelected,
setTransactionsToCategorizeSelected,
addTransactionsToCategorizeSelected,
removeTransactionsToCategorizeSelected,
resetTransactionsToCategorizeSelected,
} = PlaidSlice.actions;
export const getPlaidToken = (state: any) => state.plaid.plaidToken;
export const getTransactionsToCategorizeSelected = (state: any) =>
state.plaid.transactionsToCategorizeSelected;