mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-17 05:10:31 +00:00
feat: wip multi-select transactions to categorization and matching
This commit is contained in:
@@ -36,10 +36,14 @@ function AccountTransactionsDataTable({
|
||||
|
||||
// #withBanking
|
||||
openMatchingTransactionAside,
|
||||
enableMultipleCategorization,
|
||||
|
||||
// #withBankingActions
|
||||
setUncategorizedTransactionIdForMatching,
|
||||
setUncategorizedTransactionsSelected,
|
||||
|
||||
addTransactionsToCategorizeSelected,
|
||||
setTransactionsToCategorizeSelected,
|
||||
}) {
|
||||
// Retrieve table columns.
|
||||
const columns = useAccountUncategorizedTransactionsColumns();
|
||||
@@ -57,7 +61,11 @@ function AccountTransactionsDataTable({
|
||||
|
||||
// Handle cell click.
|
||||
const handleCellClick = (cell) => {
|
||||
setUncategorizedTransactionIdForMatching(cell.row.original.id);
|
||||
if (enableMultipleCategorization) {
|
||||
addTransactionsToCategorizeSelected(cell.row.original.id);
|
||||
} else {
|
||||
setTransactionsToCategorizeSelected(cell.row.original.id);
|
||||
}
|
||||
};
|
||||
// Handles categorize button click.
|
||||
const handleCategorizeBtnClick = (transaction) => {
|
||||
@@ -80,12 +88,6 @@ function AccountTransactionsDataTable({
|
||||
});
|
||||
};
|
||||
|
||||
// Handle selected rows change.
|
||||
const handleSelectedRowsChange = (selected) => {
|
||||
const _selectedIds = selected?.map((row) => row.original.id);
|
||||
setUncategorizedTransactionsSelected(_selectedIds);
|
||||
};
|
||||
|
||||
return (
|
||||
<CashflowTransactionsTable
|
||||
noInitialFetch={true}
|
||||
@@ -112,13 +114,12 @@ function AccountTransactionsDataTable({
|
||||
noResults={
|
||||
'There is no uncategorized transactions in the current account.'
|
||||
}
|
||||
onSelectedRowsChange={handleSelectedRowsChange}
|
||||
payload={{
|
||||
onExclude: handleExcludeTransaction,
|
||||
onCategorize: handleCategorizeBtnClick,
|
||||
}}
|
||||
className={clsx('table-constrant', styles.table, {
|
||||
[styles.showCategorizeColumn]: openMatchingTransactionAside,
|
||||
[styles.showCategorizeColumn]: enableMultipleCategorization,
|
||||
})}
|
||||
/>
|
||||
);
|
||||
@@ -129,9 +130,12 @@ export default compose(
|
||||
cashflowTansactionsTableSize: cashflowTransactionsSettings?.tableSize,
|
||||
})),
|
||||
withBankingActions,
|
||||
withBanking(({ openMatchingTransactionAside }) => ({
|
||||
openMatchingTransactionAside,
|
||||
})),
|
||||
withBanking(
|
||||
({ openMatchingTransactionAside, enableMultipleCategorization }) => ({
|
||||
openMatchingTransactionAside,
|
||||
enableMultipleCategorization,
|
||||
}),
|
||||
),
|
||||
)(AccountTransactionsDataTable);
|
||||
|
||||
const DashboardConstrantTable = styled(DataTable)`
|
||||
|
||||
@@ -131,9 +131,9 @@ export function useAccountUncategorizedTransactionsColumns() {
|
||||
className={styles.categorizeCheckbox}
|
||||
/>
|
||||
),
|
||||
width: 10,
|
||||
minWidth: 10,
|
||||
maxWidth: 10,
|
||||
width: 20,
|
||||
minWidth: 20,
|
||||
maxWidth: 20,
|
||||
align: 'right',
|
||||
className: 'categorize_include',
|
||||
},
|
||||
|
||||
@@ -6,10 +6,13 @@ import { useAccounts, useBranches } from '@/hooks/query';
|
||||
import { useFeatureCan } from '@/hooks/state';
|
||||
import { Features } from '@/constants';
|
||||
import { Spinner } from '@blueprintjs/core';
|
||||
import { useGetRecognizedBankTransaction } from '@/hooks/query/bank-rules';
|
||||
import { useCategorizeTransactionTabsBoot } from '@/containers/CashFlow/CategorizeTransactionAside/CategorizeTransactionTabsBoot';
|
||||
import {
|
||||
GetAutofillCategorizeTransaction,
|
||||
useGetAutofillCategorizeTransaction,
|
||||
} from '@/hooks/query/bank-rules';
|
||||
|
||||
interface CategorizeTransactionBootProps {
|
||||
uncategorizedTransactionsIds: Array<number>;
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
@@ -19,8 +22,8 @@ interface CategorizeTransactionBootValue {
|
||||
isBranchesLoading: boolean;
|
||||
isAccountsLoading: boolean;
|
||||
primaryBranch: any;
|
||||
recognizedTranasction: any;
|
||||
isRecognizedTransactionLoading: boolean;
|
||||
autofillCategorizeValues: null | GetAutofillCategorizeTransaction;
|
||||
isAutofillCategorizeValuesLoading: boolean;
|
||||
}
|
||||
|
||||
const CategorizeTransactionBootContext =
|
||||
@@ -32,11 +35,9 @@ const CategorizeTransactionBootContext =
|
||||
* Categorize transcation boot.
|
||||
*/
|
||||
function CategorizeTransactionBoot({
|
||||
uncategorizedTransactionsIds,
|
||||
...props
|
||||
}: CategorizeTransactionBootProps) {
|
||||
const { uncategorizedTransaction, uncategorizedTransactionId } =
|
||||
useCategorizeTransactionTabsBoot();
|
||||
|
||||
// Detarmines whether the feature is enabled.
|
||||
const { featureCan } = useFeatureCan();
|
||||
const isBranchFeatureCan = featureCan(Features.Branches);
|
||||
@@ -49,13 +50,11 @@ function CategorizeTransactionBoot({
|
||||
{},
|
||||
{ enabled: isBranchFeatureCan },
|
||||
);
|
||||
// Fetches the recognized transaction.
|
||||
// Fetches the autofill values of categorize transaction.
|
||||
const {
|
||||
data: recognizedTranasction,
|
||||
isLoading: isRecognizedTransactionLoading,
|
||||
} = useGetRecognizedBankTransaction(uncategorizedTransactionId, {
|
||||
enabled: !!uncategorizedTransaction.is_recognized,
|
||||
});
|
||||
data: autofillCategorizeValues,
|
||||
isLoading: isAutofillCategorizeValuesLoading,
|
||||
} = useGetAutofillCategorizeTransaction(uncategorizedTransactionsIds, {});
|
||||
|
||||
// Retrieves the primary branch.
|
||||
const primaryBranch = useMemo(
|
||||
@@ -69,11 +68,11 @@ function CategorizeTransactionBoot({
|
||||
isBranchesLoading,
|
||||
isAccountsLoading,
|
||||
primaryBranch,
|
||||
recognizedTranasction,
|
||||
isRecognizedTransactionLoading,
|
||||
autofillCategorizeValues,
|
||||
isAutofillCategorizeValuesLoading,
|
||||
};
|
||||
const isLoading =
|
||||
isBranchesLoading || isAccountsLoading || isRecognizedTransactionLoading;
|
||||
isBranchesLoading || isAccountsLoading || isAutofillCategorizeValuesLoading;
|
||||
|
||||
if (isLoading) {
|
||||
<Spinner size={30} />;
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
// @ts-nocheck
|
||||
import styled from 'styled-components';
|
||||
import * as R from 'ramda';
|
||||
import { CategorizeTransactionBoot } from './CategorizeTransactionBoot';
|
||||
import { CategorizeTransactionForm } from './CategorizeTransactionForm';
|
||||
import { useCategorizeTransactionTabsBoot } from '@/containers/CashFlow/CategorizeTransactionAside/CategorizeTransactionTabsBoot';
|
||||
|
||||
export function CategorizeTransactionContent() {
|
||||
const { uncategorizedTransactionId } = useCategorizeTransactionTabsBoot();
|
||||
import { withBanking } from '@/containers/CashFlow/withBanking';
|
||||
|
||||
function CategorizeTransactionContentRoot({
|
||||
transactionsToCategorizeIdsSelected,
|
||||
}) {
|
||||
return (
|
||||
<CategorizeTransactionBoot
|
||||
uncategorizedTransactionId={uncategorizedTransactionId}
|
||||
uncategorizedTransactionsIds={transactionsToCategorizeIdsSelected}
|
||||
>
|
||||
<CategorizeTransactionDrawerBody>
|
||||
<CategorizeTransactionForm />
|
||||
@@ -18,6 +19,12 @@ export function CategorizeTransactionContent() {
|
||||
);
|
||||
}
|
||||
|
||||
export const CategorizeTransactionContent = R.compose(
|
||||
withBanking(({ transactionsToCategorizeIdsSelected }) => ({
|
||||
transactionsToCategorizeIdsSelected,
|
||||
})),
|
||||
)(CategorizeTransactionContentRoot);
|
||||
|
||||
const CategorizeTransactionDrawerBody = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
@@ -22,7 +22,7 @@ function CategorizeTransactionFormRoot({
|
||||
// #withBankingActions
|
||||
closeMatchingTransactionAside,
|
||||
}) {
|
||||
const { uncategorizedTransactionId } = useCategorizeTransactionTabsBoot();
|
||||
const { uncategorizedTransactionIds } = useCategorizeTransactionTabsBoot();
|
||||
const { mutateAsync: categorizeTransaction } = useCategorizeTransaction();
|
||||
|
||||
// Form initial values in create and edit mode.
|
||||
@@ -30,10 +30,10 @@ function CategorizeTransactionFormRoot({
|
||||
|
||||
// Callbacks handles form submit.
|
||||
const handleFormSubmit = (values, { setSubmitting, setErrors }) => {
|
||||
const transformedValues = tranformToRequest(values);
|
||||
const _values = tranformToRequest(values, uncategorizedTransactionIds);
|
||||
|
||||
setSubmitting(true);
|
||||
categorizeTransaction([uncategorizedTransactionId, transformedValues])
|
||||
categorizeTransaction(_values)
|
||||
.then(() => {
|
||||
setSubmitting(false);
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import { Box, FFormGroup, FSelect } from '@/components';
|
||||
import { getAddMoneyInOptions, getAddMoneyOutOptions } from '@/constants';
|
||||
import { useFormikContext } from 'formik';
|
||||
import { useCategorizeTransactionTabsBoot } from '@/containers/CashFlow/CategorizeTransactionAside/CategorizeTransactionTabsBoot';
|
||||
import { useCategorizeTransactionBoot } from './CategorizeTransactionBoot';
|
||||
|
||||
// Retrieves the add money in button options.
|
||||
const MoneyInOptions = getAddMoneyInOptions();
|
||||
@@ -18,16 +19,18 @@ const Title = styled('h3')`
|
||||
`;
|
||||
|
||||
export function CategorizeTransactionFormContent() {
|
||||
const { uncategorizedTransaction } = useCategorizeTransactionTabsBoot();
|
||||
const { autofillCategorizeValues } = useCategorizeTransactionBoot();
|
||||
|
||||
const transactionTypes = uncategorizedTransaction?.is_deposit_transaction
|
||||
const transactionTypes = autofillCategorizeValues?.isDepositTransaction
|
||||
? MoneyInOptions
|
||||
: MoneyOutOptions;
|
||||
|
||||
const formattedAmount = autofillCategorizeValues?.formattedAmount;
|
||||
|
||||
return (
|
||||
<Box style={{ flex: 1, margin: 20 }}>
|
||||
<FormGroup label={'Amount'} inline>
|
||||
<Title>{uncategorizedTransaction.formatted_amount}</Title>
|
||||
<Title>{formattedAmount}</Title>
|
||||
</FormGroup>
|
||||
|
||||
<FFormGroup name={'category'} label={'Category'} fastField inline>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
// @ts-nocheck
|
||||
import * as R from 'ramda';
|
||||
import { transformToForm, transfromToSnakeCase } from '@/utils';
|
||||
import { useCategorizeTransactionTabsBoot } from '@/containers/CashFlow/CategorizeTransactionAside/CategorizeTransactionTabsBoot';
|
||||
import { useCategorizeTransactionBoot } from './CategorizeTransactionBoot';
|
||||
import { GetAutofillCategorizeTransaction } from '@/hooks/query/bank-rules';
|
||||
|
||||
// Default initial form values.
|
||||
export const defaultInitialValues = {
|
||||
@@ -18,48 +18,28 @@ export const defaultInitialValues = {
|
||||
};
|
||||
|
||||
export const transformToCategorizeForm = (
|
||||
uncategorizedTransaction: any,
|
||||
recognizedTransaction?: any,
|
||||
autofillCategorizeTransaction: GetAutofillCategorizeTransaction,
|
||||
) => {
|
||||
let defaultValues = {
|
||||
debitAccountId: uncategorizedTransaction.account_id,
|
||||
transactionType: uncategorizedTransaction.is_deposit_transaction
|
||||
? 'other_income'
|
||||
: 'other_expense',
|
||||
amount: uncategorizedTransaction.amount,
|
||||
date: uncategorizedTransaction.date,
|
||||
};
|
||||
if (recognizedTransaction) {
|
||||
const recognizedDefaults = getRecognizedTransactionDefaultValues(
|
||||
recognizedTransaction,
|
||||
);
|
||||
defaultValues = R.merge(defaultValues, recognizedDefaults);
|
||||
}
|
||||
return transformToForm(defaultValues, defaultInitialValues);
|
||||
return transformToForm(autofillCategorizeTransaction, defaultInitialValues);
|
||||
};
|
||||
|
||||
export const getRecognizedTransactionDefaultValues = (
|
||||
recognizedTransaction: any,
|
||||
export const tranformToRequest = (
|
||||
formValues: Record<string, any>,
|
||||
uncategorizedTransactionIds: Array<number>,
|
||||
) => {
|
||||
return {
|
||||
creditAccountId: recognizedTransaction.assignedAccountId || '',
|
||||
// transactionType: recognizedTransaction.assignCategory,
|
||||
referenceNo: recognizedTransaction.referenceNo || '',
|
||||
uncategorized_transaction_ids: uncategorizedTransactionIds,
|
||||
...transfromToSnakeCase(formValues),
|
||||
};
|
||||
};
|
||||
|
||||
export const tranformToRequest = (formValues: Record<string, any>) => {
|
||||
return transfromToSnakeCase(formValues);
|
||||
};
|
||||
|
||||
/**
|
||||
* Categorize transaction form initial values.
|
||||
* @returns
|
||||
*/
|
||||
export const useCategorizeTransactionFormInitialValues = () => {
|
||||
const { primaryBranch, recognizedTranasction } =
|
||||
const { primaryBranch, autofillCategorizeValues } =
|
||||
useCategorizeTransactionBoot();
|
||||
const { uncategorizedTransaction } = useCategorizeTransactionTabsBoot();
|
||||
|
||||
return {
|
||||
...defaultInitialValues,
|
||||
@@ -68,10 +48,7 @@ export const useCategorizeTransactionFormInitialValues = () => {
|
||||
* values such as `notes` come back from the API as null, so remove those
|
||||
* as well.
|
||||
*/
|
||||
...transformToCategorizeForm(
|
||||
uncategorizedTransaction,
|
||||
recognizedTranasction,
|
||||
),
|
||||
...transformToCategorizeForm(autofillCategorizeValues),
|
||||
|
||||
/** Assign the primary branch id as default value. */
|
||||
branchId: primaryBranch?.id || null,
|
||||
|
||||
@@ -43,9 +43,8 @@ function CategorizeTransactionAsideRoot({
|
||||
|
||||
const handleClose = () => {
|
||||
closeMatchingTransactionAside();
|
||||
};
|
||||
const uncategorizedTransactionId = selectedUncategorizedTransactionId;
|
||||
|
||||
}
|
||||
// Cannot continue if there is no selected transactions.;
|
||||
if (!selectedUncategorizedTransactionId) {
|
||||
return null;
|
||||
}
|
||||
@@ -53,7 +52,7 @@ function CategorizeTransactionAsideRoot({
|
||||
<Aside title={'Categorize Bank Transaction'} onClose={handleClose}>
|
||||
<Aside.Body>
|
||||
<CategorizeTransactionTabsBoot
|
||||
uncategorizedTransactionId={uncategorizedTransactionId}
|
||||
uncategorizedTransactionId={selectedUncategorizedTransactionId}
|
||||
>
|
||||
<CategorizeTransactionTabs />
|
||||
</CategorizeTransactionTabsBoot>
|
||||
@@ -64,7 +63,7 @@ function CategorizeTransactionAsideRoot({
|
||||
|
||||
export const CategorizeTransactionAside = R.compose(
|
||||
withBankingActions,
|
||||
withBanking(({ selectedUncategorizedTransactionId }) => ({
|
||||
selectedUncategorizedTransactionId,
|
||||
withBanking(({ transactionsToCategorizeIdsSelected }) => ({
|
||||
selectedUncategorizedTransactionId: transactionsToCategorizeIdsSelected,
|
||||
})),
|
||||
)(CategorizeTransactionAsideRoot);
|
||||
|
||||
@@ -2,14 +2,10 @@
|
||||
import { Tab, Tabs } from '@blueprintjs/core';
|
||||
import { MatchingBankTransaction } from './MatchingTransaction';
|
||||
import { CategorizeTransactionContent } from '../CategorizeTransaction/drawers/CategorizeTransactionDrawer/CategorizeTransactionContent';
|
||||
import { useCategorizeTransactionTabsBoot } from './CategorizeTransactionTabsBoot';
|
||||
import styles from './CategorizeTransactionTabs.module.scss';
|
||||
|
||||
export function CategorizeTransactionTabs() {
|
||||
const { uncategorizedTransaction } = useCategorizeTransactionTabsBoot();
|
||||
const defaultSelectedTabId = uncategorizedTransaction?.is_recognized
|
||||
? 'categorize'
|
||||
: 'matching';
|
||||
const defaultSelectedTabId = 'categorize';
|
||||
|
||||
return (
|
||||
<Tabs
|
||||
|
||||
@@ -1,16 +1,13 @@
|
||||
// @ts-nocheck
|
||||
import React from 'react';
|
||||
import { Spinner } from '@blueprintjs/core';
|
||||
import { useUncategorizedTransaction } from '@/hooks/query';
|
||||
import React, { useMemo } from 'react';
|
||||
import { castArray, uniq } from 'lodash';
|
||||
|
||||
interface CategorizeTransactionTabsValue {
|
||||
uncategorizedTransactionId: number;
|
||||
isUncategorizedTransactionLoading: boolean;
|
||||
uncategorizedTransaction: any;
|
||||
uncategorizedTransactionIds: Array<number>;
|
||||
}
|
||||
|
||||
interface CategorizeTransactionTabsBootProps {
|
||||
uncategorizedTransactionId: number;
|
||||
uncategorizedTransactionIds: number | Array<number>;
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
@@ -26,28 +23,23 @@ export function CategorizeTransactionTabsBoot({
|
||||
uncategorizedTransactionId,
|
||||
children,
|
||||
}: CategorizeTransactionTabsBootProps) {
|
||||
const {
|
||||
data: uncategorizedTransaction,
|
||||
isLoading: isUncategorizedTransactionLoading,
|
||||
} = useUncategorizedTransaction(uncategorizedTransactionId);
|
||||
const uncategorizedTransactionIds = useMemo(
|
||||
() => uniq(castArray(uncategorizedTransactionId)),
|
||||
[uncategorizedTransactionId],
|
||||
);
|
||||
|
||||
const provider = {
|
||||
uncategorizedTransactionId,
|
||||
uncategorizedTransaction,
|
||||
isUncategorizedTransactionLoading,
|
||||
uncategorizedTransactionIds,
|
||||
};
|
||||
const isLoading = isUncategorizedTransactionLoading;
|
||||
|
||||
// Use a key prop to force re-render of children when uncategorizedTransactionId changes
|
||||
// Use a key prop to force re-render of children when `uncategorizedTransactionIds` changes
|
||||
const childrenPerKey = React.useMemo(() => {
|
||||
return React.Children.map(children, (child) =>
|
||||
React.cloneElement(child, { key: uncategorizedTransactionId }),
|
||||
React.cloneElement(child, {
|
||||
key: uncategorizedTransactionIds?.join(','),
|
||||
}),
|
||||
);
|
||||
}, [children, uncategorizedTransactionId]);
|
||||
}, [children, uncategorizedTransactionIds]);
|
||||
|
||||
if (isLoading) {
|
||||
return <Spinner size={30} />;
|
||||
}
|
||||
return (
|
||||
<CategorizeTransactionTabsBootContext.Provider value={provider}>
|
||||
{childrenPerKey}
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
// @ts-nocheck
|
||||
import { isEmpty } from 'lodash';
|
||||
import * as R from 'ramda';
|
||||
import { useEffect, useState, useMemo } from 'react';
|
||||
import { uniq } from 'lodash';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { AnchorButton, Button, Intent, Tag, Text } from '@blueprintjs/core';
|
||||
import { FastField, FastFieldProps, Formik, useFormikContext } from 'formik';
|
||||
import { AppToaster, Box, FormatNumber, Group, Stack } from '@/components';
|
||||
@@ -45,24 +44,15 @@ function MatchingBankTransactionRoot({
|
||||
// #withBanking
|
||||
transactionsToCategorizeIdsSelected,
|
||||
}) {
|
||||
const { uncategorizedTransactionId } = useCategorizeTransactionTabsBoot();
|
||||
const { uncategorizedTransactionIds } = useCategorizeTransactionTabsBoot();
|
||||
const { mutateAsync: matchTransaction } = useMatchUncategorizedTransaction();
|
||||
|
||||
const selectedTransactionsIds = useMemo(
|
||||
() =>
|
||||
uniq([
|
||||
...transactionsToCategorizeIdsSelected,
|
||||
uncategorizedTransactionId,
|
||||
]),
|
||||
[uncategorizedTransactionId, transactionsToCategorizeIdsSelected],
|
||||
);
|
||||
|
||||
// Handles the form submitting.
|
||||
const handleSubmit = (
|
||||
values: MatchingTransactionFormValues,
|
||||
{ setSubmitting }: FormikHelpers<MatchingTransactionFormValues>,
|
||||
) => {
|
||||
const _values = transformToReq(values);
|
||||
const _values = transformToReq(values, uncategorizedTransactionIds);
|
||||
|
||||
if (_values.matchedTransactions?.length === 0) {
|
||||
AppToaster.show({
|
||||
@@ -72,7 +62,7 @@ function MatchingBankTransactionRoot({
|
||||
return;
|
||||
}
|
||||
setSubmitting(true);
|
||||
matchTransaction({ id: uncategorizedTransactionId, value: _values })
|
||||
matchTransaction(_values)
|
||||
.then(() => {
|
||||
AppToaster.show({
|
||||
intent: Intent.SUCCESS,
|
||||
@@ -91,7 +81,7 @@ function MatchingBankTransactionRoot({
|
||||
message: `The total amount does not equal the uncategorized transaction.`,
|
||||
intent: Intent.DANGER,
|
||||
});
|
||||
|
||||
setSubmitting(false);
|
||||
return;
|
||||
}
|
||||
AppToaster.show({
|
||||
@@ -104,7 +94,7 @@ function MatchingBankTransactionRoot({
|
||||
|
||||
return (
|
||||
<MatchingTransactionBoot
|
||||
uncategorizedTransactionsIds={selectedTransactionsIds}
|
||||
uncategorizedTransactionsIds={uncategorizedTransactionIds}
|
||||
>
|
||||
<Formik initialValues={initialValues} onSubmit={handleSubmit}>
|
||||
<MatchingBankTransactionFormContent />
|
||||
|
||||
@@ -10,6 +10,7 @@ interface MatchingTransactionBootValues {
|
||||
possibleMatches: Array<any>;
|
||||
perfectMatchesCount: number;
|
||||
perfectMatches: Array<any>;
|
||||
totalPending: number;
|
||||
matches: Array<any>;
|
||||
}
|
||||
|
||||
@@ -36,6 +37,7 @@ function MatchingTransactionBoot({
|
||||
const possibleMatches = defaultTo(matchingTransactions?.possibleMatches, []);
|
||||
const perfectMatchesCount = matchingTransactions?.perfectMatches?.length || 0;
|
||||
const perfectMatches = defaultTo(matchingTransactions?.perfectMatches, []);
|
||||
const totalPending = defaultTo(matchingTransactions?.totalPending, 0);
|
||||
|
||||
const matches = R.concat(perfectMatches, possibleMatches);
|
||||
|
||||
@@ -46,6 +48,7 @@ function MatchingTransactionBoot({
|
||||
possibleMatches,
|
||||
perfectMatchesCount,
|
||||
perfectMatches,
|
||||
totalPending,
|
||||
matches,
|
||||
} as MatchingTransactionBootValues;
|
||||
|
||||
|
||||
@@ -4,7 +4,10 @@ import { useMatchingTransactionBoot } from './MatchingTransactionBoot';
|
||||
import { useCategorizeTransactionTabsBoot } from './CategorizeTransactionTabsBoot';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
export const transformToReq = (values: MatchingTransactionFormValues) => {
|
||||
export const transformToReq = (
|
||||
values: MatchingTransactionFormValues,
|
||||
uncategorizedTransactions: Array<number>,
|
||||
) => {
|
||||
const matchedTransactions = Object.entries(values.matched)
|
||||
.filter(([key, value]) => value)
|
||||
.map(([key]) => {
|
||||
@@ -12,14 +15,13 @@ export const transformToReq = (values: MatchingTransactionFormValues) => {
|
||||
|
||||
return { reference_type, reference_id: parseInt(reference_id, 10) };
|
||||
});
|
||||
|
||||
return { matchedTransactions };
|
||||
return { matchedTransactions, uncategorizedTransactions };
|
||||
};
|
||||
|
||||
export const useGetPendingAmountMatched = () => {
|
||||
const { values } = useFormikContext<MatchingTransactionFormValues>();
|
||||
const { perfectMatches, possibleMatches } = useMatchingTransactionBoot();
|
||||
const { uncategorizedTransaction } = useCategorizeTransactionTabsBoot();
|
||||
const { perfectMatches, possibleMatches, totalPending } =
|
||||
useMatchingTransactionBoot();
|
||||
|
||||
return useMemo(() => {
|
||||
const matchedItems = [...perfectMatches, ...possibleMatches].filter(
|
||||
@@ -34,11 +36,10 @@ export const useGetPendingAmountMatched = () => {
|
||||
(item.transactionNormal === 'debit' ? 1 : -1) * parseFloat(item.amount),
|
||||
0,
|
||||
);
|
||||
const amount = uncategorizedTransaction.amount;
|
||||
const pendingAmount = amount - totalMatchedAmount;
|
||||
const pendingAmount = totalPending - totalMatchedAmount;
|
||||
|
||||
return pendingAmount;
|
||||
}, [uncategorizedTransaction, perfectMatches, possibleMatches, values]);
|
||||
}, [totalPending, perfectMatches, possibleMatches, values]);
|
||||
};
|
||||
|
||||
export const useAtleastOneMatchedSelected = () => {
|
||||
|
||||
@@ -18,7 +18,7 @@ export const withBanking = (mapState) => {
|
||||
state.plaid.uncategorizedTransactionsSelected,
|
||||
|
||||
excludedTransactionsIdsSelected: state.plaid.excludedTransactionsSelected,
|
||||
isMultipleCategorization: state.plaid.isMultipleCategorization,
|
||||
enableMultipleCategorization: state.plaid.enableMultipleCategorization,
|
||||
|
||||
transactionsToCategorizeIdsSelected:
|
||||
state.plaid.transactionsToCategorizeSelected,
|
||||
|
||||
@@ -11,6 +11,8 @@ import {
|
||||
resetTransactionsToCategorizeSelected,
|
||||
setTransactionsToCategorizeSelected,
|
||||
enableMultipleCategorization,
|
||||
addTransactionsToCategorizeSelected,
|
||||
removeTransactionsToCategorizeSelected,
|
||||
} from '@/store/banking/banking.reducer';
|
||||
|
||||
export interface WithBankingActionsProps {
|
||||
@@ -28,6 +30,8 @@ export interface WithBankingActionsProps {
|
||||
resetExcludedTransactionsSelected: () => void;
|
||||
|
||||
setTransactionsToCategorizeSelected: (ids: Array<string | number>) => void;
|
||||
addTransactionsToCategorizeSelected: (id: string | number) => void;
|
||||
removeTransactionsToCategorizeSelected: (id: string | number) => void;
|
||||
resetTransactionsToCategorizeSelected: () => void;
|
||||
|
||||
enableMultipleCategorization: (enable: boolean) => void;
|
||||
@@ -88,6 +92,22 @@ const mapDipatchToProps = (dispatch: any): WithBankingActionsProps => ({
|
||||
setTransactionsToCategorizeSelected: (ids: Array<string | number>) =>
|
||||
dispatch(setTransactionsToCategorizeSelected({ ids })),
|
||||
|
||||
/**
|
||||
* Adds selected transactions to categorize.
|
||||
* @param {string | number} id
|
||||
* @returns
|
||||
*/
|
||||
addTransactionsToCategorizeSelected: (id: string | number) =>
|
||||
dispatch(addTransactionsToCategorizeSelected({ id })),
|
||||
|
||||
/**
|
||||
* Removes the selected transactions.
|
||||
* @param {string | number} id
|
||||
* @returns
|
||||
*/
|
||||
removeTransactionsToCategorizeSelected: (id: string | number) =>
|
||||
dispatch(removeTransactionsToCategorizeSelected({ id })),
|
||||
|
||||
/**
|
||||
* Resets the selected transactions to categorize or match.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user