mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-23 00:00:31 +00:00
feat: improvement in Plaid accounts disconnecting
This commit is contained in:
@@ -0,0 +1,9 @@
|
|||||||
|
exports.up = function (knex) {
|
||||||
|
return knex.schema.table('accounts', (table) => {
|
||||||
|
table.boolean('is_syncing_owner').defaultTo(false).after('is_feeds_active');
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.down = function (knex) {
|
||||||
|
table.dropColumn('is_syncing_owner');
|
||||||
|
};
|
||||||
@@ -15,6 +15,7 @@ export interface IAccountDTO {
|
|||||||
export interface IAccountCreateDTO extends IAccountDTO {
|
export interface IAccountCreateDTO extends IAccountDTO {
|
||||||
currencyCode?: string;
|
currencyCode?: string;
|
||||||
plaidAccountId?: string;
|
plaidAccountId?: string;
|
||||||
|
plaidItemId?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IAccountEditDTO extends IAccountDTO {}
|
export interface IAccountEditDTO extends IAccountDTO {}
|
||||||
@@ -38,6 +39,7 @@ export interface IAccount {
|
|||||||
accountParentType: string;
|
accountParentType: string;
|
||||||
bankBalance: string;
|
bankBalance: string;
|
||||||
plaidItemId: number | null
|
plaidItemId: number | null
|
||||||
|
lastFeedsUpdatedAt: Date;
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum AccountNormal {
|
export enum AccountNormal {
|
||||||
|
|||||||
@@ -1,70 +1,12 @@
|
|||||||
import { forEach } from 'lodash';
|
|
||||||
import { Configuration, PlaidApi, PlaidEnvironments } from 'plaid';
|
import { Configuration, PlaidApi, PlaidEnvironments } from 'plaid';
|
||||||
import { createPlaidApiEvent } from './PlaidApiEventsDBSync';
|
|
||||||
import config from '@/config';
|
import config from '@/config';
|
||||||
|
|
||||||
const OPTIONS = { clientApp: 'Plaid-Pattern' };
|
|
||||||
|
|
||||||
// We want to log requests to / responses from the Plaid API (via the Plaid client), as this data
|
|
||||||
// can be useful for troubleshooting.
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Logging function for Plaid client methods that use an access_token as an argument. Associates
|
|
||||||
* the Plaid API event log entry with the item and user the request is for.
|
|
||||||
*
|
|
||||||
* @param {string} clientMethod the name of the Plaid client method called.
|
|
||||||
* @param {Array} clientMethodArgs the arguments passed to the Plaid client method.
|
|
||||||
* @param {Object} response the response from the Plaid client.
|
|
||||||
*/
|
|
||||||
const defaultLogger = async (clientMethod, clientMethodArgs, response) => {
|
|
||||||
const accessToken = clientMethodArgs[0].access_token;
|
|
||||||
// const { id: itemId, user_id: userId } = await retrieveItemByPlaidAccessToken(
|
|
||||||
// accessToken
|
|
||||||
// );
|
|
||||||
// await createPlaidApiEvent(1, 1, clientMethod, clientMethodArgs, response);
|
|
||||||
|
|
||||||
// console.log(response);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Logging function for Plaid client methods that do not use access_token as an argument. These
|
|
||||||
* Plaid API event log entries will not be associated with an item or user.
|
|
||||||
*
|
|
||||||
* @param {string} clientMethod the name of the Plaid client method called.
|
|
||||||
* @param {Array} clientMethodArgs the arguments passed to the Plaid client method.
|
|
||||||
* @param {Object} response the response from the Plaid client.
|
|
||||||
*/
|
|
||||||
const noAccessTokenLogger = async (
|
|
||||||
clientMethod,
|
|
||||||
clientMethodArgs,
|
|
||||||
response
|
|
||||||
) => {
|
|
||||||
// console.log(response);
|
|
||||||
|
|
||||||
// await createPlaidApiEvent(
|
|
||||||
// undefined,
|
|
||||||
// undefined,
|
|
||||||
// clientMethod,
|
|
||||||
// clientMethodArgs,
|
|
||||||
// response
|
|
||||||
// );
|
|
||||||
};
|
|
||||||
|
|
||||||
// Plaid client methods used in this app, mapped to their appropriate logging functions.
|
|
||||||
const clientMethodLoggingFns = {
|
|
||||||
transactionsRefresh: defaultLogger,
|
|
||||||
accountsGet: defaultLogger,
|
|
||||||
institutionsGet: noAccessTokenLogger,
|
|
||||||
institutionsGetById: noAccessTokenLogger,
|
|
||||||
itemPublicTokenExchange: noAccessTokenLogger,
|
|
||||||
itemRemove: defaultLogger,
|
|
||||||
linkTokenCreate: noAccessTokenLogger,
|
|
||||||
transactionsSync: defaultLogger,
|
|
||||||
sandboxItemResetLogin: defaultLogger,
|
|
||||||
};
|
|
||||||
// Wrapper for the Plaid client. This allows us to easily log data for all Plaid client requests.
|
// Wrapper for the Plaid client. This allows us to easily log data for all Plaid client requests.
|
||||||
export class PlaidClientWrapper {
|
export class PlaidClientWrapper {
|
||||||
constructor() {
|
private static instance: PlaidClientWrapper;
|
||||||
|
private client: PlaidApi;
|
||||||
|
|
||||||
|
private constructor() {
|
||||||
// Initialize the Plaid client.
|
// Initialize the Plaid client.
|
||||||
const configuration = new Configuration({
|
const configuration = new Configuration({
|
||||||
basePath: PlaidEnvironments[config.plaid.env],
|
basePath: PlaidEnvironments[config.plaid.env],
|
||||||
@@ -76,26 +18,13 @@ export class PlaidClientWrapper {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
this.client = new PlaidApi(configuration);
|
this.client = new PlaidApi(configuration);
|
||||||
|
|
||||||
// Wrap the Plaid client methods to add a logging function.
|
|
||||||
forEach(clientMethodLoggingFns, (logFn, method) => {
|
|
||||||
this[method] = this.createWrappedClientMethod(method, logFn);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allows us to log API request data for troubleshooting purposes.
|
public static getClient(): PlaidApi {
|
||||||
createWrappedClientMethod(clientMethod, log) {
|
if (!PlaidClientWrapper.instance) {
|
||||||
return async (...args) => {
|
PlaidClientWrapper.instance = new PlaidClientWrapper();
|
||||||
try {
|
|
||||||
const res = await this.client[clientMethod](...args);
|
|
||||||
await log(clientMethod, args, res);
|
|
||||||
return res;
|
|
||||||
} catch (err) {
|
|
||||||
await log(clientMethod, args, err?.response?.data);
|
|
||||||
throw err;
|
|
||||||
}
|
}
|
||||||
};
|
return PlaidClientWrapper.instance.client;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -331,7 +331,7 @@ export default class Account extends mixin(TenantModel, [
|
|||||||
modelClass: PlaidItem.default,
|
modelClass: PlaidItem.default,
|
||||||
join: {
|
join: {
|
||||||
from: 'accounts.plaidItemId',
|
from: 'accounts.plaidItemId',
|
||||||
to: 'plaid_items.id',
|
to: 'plaid_items.plaidItemId',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -13,7 +13,12 @@ export class AccountTransformer extends Transformer {
|
|||||||
* @returns {Array}
|
* @returns {Array}
|
||||||
*/
|
*/
|
||||||
public includeAttributes = (): string[] => {
|
public includeAttributes = (): string[] => {
|
||||||
return ['formattedAmount', 'flattenName', 'bankBalanceFormatted'];
|
return [
|
||||||
|
'formattedAmount',
|
||||||
|
'flattenName',
|
||||||
|
'bankBalanceFormatted',
|
||||||
|
'lastFeedsUpdatedAtFormatted',
|
||||||
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -52,6 +57,15 @@ export class AccountTransformer extends Transformer {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the formatted last feeds update at.
|
||||||
|
* @param {IAccount} account
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
protected lastFeedsUpdatedAtFormatted = (account: IAccount): string => {
|
||||||
|
return this.formatDate(account.lastFeedsUpdatedAt);
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Transformes the accounts collection to flat or nested array.
|
* Transformes the accounts collection to flat or nested array.
|
||||||
* @param {IAccount[]}
|
* @param {IAccount[]}
|
||||||
|
|||||||
@@ -96,6 +96,11 @@ export class CreateAccount {
|
|||||||
...createAccountDTO,
|
...createAccountDTO,
|
||||||
slug: kebabCase(createAccountDTO.name),
|
slug: kebabCase(createAccountDTO.name),
|
||||||
currencyCode: createAccountDTO.currencyCode || baseCurrency,
|
currencyCode: createAccountDTO.currencyCode || baseCurrency,
|
||||||
|
|
||||||
|
// Mark the account is Plaid owner since Plaid item/account is defined on creating.
|
||||||
|
isSyncingOwner: Boolean(
|
||||||
|
createAccountDTO.plaidAccountId || createAccountDTO.plaidItemId
|
||||||
|
),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -117,12 +122,7 @@ export class CreateAccount {
|
|||||||
const tenantMeta = await TenantMetadata.query().findOne({ tenantId });
|
const tenantMeta = await TenantMetadata.query().findOne({ tenantId });
|
||||||
|
|
||||||
// Authorize the account creation.
|
// Authorize the account creation.
|
||||||
await this.authorize(
|
await this.authorize(tenantId, accountDTO, tenantMeta.baseCurrency, params);
|
||||||
tenantId,
|
|
||||||
accountDTO,
|
|
||||||
tenantMeta.baseCurrency,
|
|
||||||
params
|
|
||||||
);
|
|
||||||
// Transformes the DTO to model.
|
// Transformes the DTO to model.
|
||||||
const accountInputModel = this.transformDTOToModel(
|
const accountInputModel = this.transformDTOToModel(
|
||||||
accountDTO,
|
accountDTO,
|
||||||
@@ -157,4 +157,3 @@ export class CreateAccount {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -33,14 +33,15 @@ export class DisconnectBankAccount {
|
|||||||
const account = await Account.query()
|
const account = await Account.query()
|
||||||
.findById(bankAccountId)
|
.findById(bankAccountId)
|
||||||
.whereIn('account_type', [ACCOUNT_TYPE.CASH, ACCOUNT_TYPE.BANK])
|
.whereIn('account_type', [ACCOUNT_TYPE.CASH, ACCOUNT_TYPE.BANK])
|
||||||
|
.withGraphFetched('plaidItem')
|
||||||
.throwIfNotFound();
|
.throwIfNotFound();
|
||||||
|
|
||||||
const oldPlaidItem = await PlaidItem.query().findById(account.plaidItemId);
|
const oldPlaidItem = account.plaidItem;
|
||||||
|
|
||||||
if (!oldPlaidItem) {
|
if (!oldPlaidItem) {
|
||||||
throw new ServiceError(ERRORS.BANK_ACCOUNT_NOT_CONNECTED);
|
throw new ServiceError(ERRORS.BANK_ACCOUNT_NOT_CONNECTED);
|
||||||
}
|
}
|
||||||
const plaidInstance = new PlaidClientWrapper();
|
const plaidInstance = PlaidClientWrapper.getClient();
|
||||||
|
|
||||||
return this.uow.withTransaction(tenantId, async (trx: Knex.Transaction) => {
|
return this.uow.withTransaction(tenantId, async (trx: Knex.Transaction) => {
|
||||||
// Triggers `onBankAccountDisconnecting` event.
|
// Triggers `onBankAccountDisconnecting` event.
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ export class RefreshBankAccountService {
|
|||||||
if (!bankAccount.plaidItem) {
|
if (!bankAccount.plaidItem) {
|
||||||
throw new ServiceError(ERRORS.BANK_ACCOUNT_NOT_CONNECTED);
|
throw new ServiceError(ERRORS.BANK_ACCOUNT_NOT_CONNECTED);
|
||||||
}
|
}
|
||||||
const plaidInstance = new PlaidClientWrapper();
|
const plaidInstance = PlaidClientWrapper.getClient();
|
||||||
|
|
||||||
await plaidInstance.transactionsRefresh({
|
await plaidInstance.transactionsRefresh({
|
||||||
access_token: bankAccount.plaidItem.plaidAccessToken,
|
access_token: bankAccount.plaidItem.plaidAccessToken,
|
||||||
|
|||||||
@@ -35,20 +35,24 @@ export class DisconnectPlaidItemOnAccountDeleted {
|
|||||||
if (!oldAccount.plaidItemId) return;
|
if (!oldAccount.plaidItemId) return;
|
||||||
|
|
||||||
// Retrieves the Plaid item that associated to the deleted account.
|
// Retrieves the Plaid item that associated to the deleted account.
|
||||||
const oldPlaidItem = await PlaidItem.query(trx).findById(
|
const oldPlaidItem = await PlaidItem.query(trx).findOne(
|
||||||
|
'plaidItemId',
|
||||||
oldAccount.plaidItemId
|
oldAccount.plaidItemId
|
||||||
);
|
);
|
||||||
// Unlink the Plaid item from all account before deleting it.
|
// Unlink the Plaid item from all account before deleting it.
|
||||||
await Account.query(trx)
|
await Account.query(trx)
|
||||||
.where('plaidItemId', oldAccount.plaidItemId)
|
.where('plaidItemId', oldAccount.plaidItemId)
|
||||||
.patch({
|
.patch({
|
||||||
|
plaidAccountId: null,
|
||||||
plaidItemId: null,
|
plaidItemId: null,
|
||||||
});
|
});
|
||||||
// Remove the Plaid item from the system.
|
// Remove the Plaid item from the system.
|
||||||
await PlaidItem.query(trx).findById(oldAccount.plaidItemId).delete();
|
await PlaidItem.query(trx)
|
||||||
|
.findOne('plaidItemId', oldAccount.plaidItemId)
|
||||||
|
.delete();
|
||||||
|
|
||||||
if (oldPlaidItem) {
|
if (oldPlaidItem) {
|
||||||
const plaidInstance = new PlaidClientWrapper();
|
const plaidInstance = PlaidClientWrapper.getClient();
|
||||||
|
|
||||||
// Remove the Plaid item.
|
// Remove the Plaid item.
|
||||||
await plaidInstance.itemRemove({
|
await plaidInstance.itemRemove({
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ export class PlaidItemService {
|
|||||||
const { PlaidItem } = this.tenancy.models(tenantId);
|
const { PlaidItem } = this.tenancy.models(tenantId);
|
||||||
const { publicToken, institutionId } = itemDTO;
|
const { publicToken, institutionId } = itemDTO;
|
||||||
|
|
||||||
const plaidInstance = new PlaidClientWrapper();
|
const plaidInstance = PlaidClientWrapper.getClient();
|
||||||
|
|
||||||
// Exchange the public token for a private access token and store with the item.
|
// Exchange the public token for a private access token and store with the item.
|
||||||
const response = await plaidInstance.itemPublicTokenExchange({
|
const response = await plaidInstance.itemPublicTokenExchange({
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ export class PlaidLinkTokenService {
|
|||||||
webhook: config.plaid.linkWebhook,
|
webhook: config.plaid.linkWebhook,
|
||||||
access_token: accessToken,
|
access_token: accessToken,
|
||||||
};
|
};
|
||||||
const plaidInstance = new PlaidClientWrapper();
|
const plaidInstance = PlaidClientWrapper.getClient();
|
||||||
const createResponse = await plaidInstance.linkTokenCreate(linkTokenParams);
|
const createResponse = await plaidInstance.linkTokenCreate(linkTokenParams);
|
||||||
|
|
||||||
return createResponse.data;
|
return createResponse.data;
|
||||||
|
|||||||
@@ -2,6 +2,11 @@ import * as R from 'ramda';
|
|||||||
import { Inject, Service } from 'typedi';
|
import { Inject, Service } from 'typedi';
|
||||||
import bluebird from 'bluebird';
|
import bluebird from 'bluebird';
|
||||||
import { entries, groupBy } from 'lodash';
|
import { entries, groupBy } from 'lodash';
|
||||||
|
import {
|
||||||
|
AccountBase as PlaidAccountBase,
|
||||||
|
Item as PlaidItem,
|
||||||
|
Institution as PlaidInstitution,
|
||||||
|
} from 'plaid';
|
||||||
import { CreateAccount } from '@/services/Accounts/CreateAccount';
|
import { CreateAccount } from '@/services/Accounts/CreateAccount';
|
||||||
import {
|
import {
|
||||||
IAccountCreateDTO,
|
IAccountCreateDTO,
|
||||||
@@ -53,6 +58,7 @@ export class PlaidSyncDb {
|
|||||||
trx?: Knex.Transaction
|
trx?: Knex.Transaction
|
||||||
) {
|
) {
|
||||||
const { Account } = this.tenancy.models(tenantId);
|
const { Account } = this.tenancy.models(tenantId);
|
||||||
|
|
||||||
const plaidAccount = await Account.query().findOne(
|
const plaidAccount = await Account.query().findOne(
|
||||||
'plaidAccountId',
|
'plaidAccountId',
|
||||||
createBankAccountDTO.plaidAccountId
|
createBankAccountDTO.plaidAccountId
|
||||||
@@ -77,13 +83,15 @@ export class PlaidSyncDb {
|
|||||||
*/
|
*/
|
||||||
public async syncBankAccounts(
|
public async syncBankAccounts(
|
||||||
tenantId: number,
|
tenantId: number,
|
||||||
plaidAccounts: PlaidAccount[],
|
plaidAccounts: PlaidAccountBase[],
|
||||||
institution: any,
|
institution: PlaidInstitution,
|
||||||
|
item: PlaidItem,
|
||||||
trx?: Knex.Transaction
|
trx?: Knex.Transaction
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const transformToPlaidAccounts =
|
const transformToPlaidAccounts = transformPlaidAccountToCreateAccount(
|
||||||
transformPlaidAccountToCreateAccount(institution);
|
item,
|
||||||
|
institution
|
||||||
|
);
|
||||||
const accountCreateDTOs = R.map(transformToPlaidAccounts)(plaidAccounts);
|
const accountCreateDTOs = R.map(transformToPlaidAccounts)(plaidAccounts);
|
||||||
|
|
||||||
await bluebird.map(
|
await bluebird.map(
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ export class PlaidUpdateTransactions {
|
|||||||
await this.fetchTransactionUpdates(tenantId, plaidItemId);
|
await this.fetchTransactionUpdates(tenantId, plaidItemId);
|
||||||
|
|
||||||
const request = { access_token: accessToken };
|
const request = { access_token: accessToken };
|
||||||
const plaidInstance = new PlaidClientWrapper();
|
const plaidInstance = PlaidClientWrapper.getClient();
|
||||||
const {
|
const {
|
||||||
data: { accounts, item },
|
data: { accounts, item },
|
||||||
} = await plaidInstance.accountsGet(request);
|
} = await plaidInstance.accountsGet(request);
|
||||||
@@ -66,7 +66,13 @@ export class PlaidUpdateTransactions {
|
|||||||
country_codes: ['US', 'UK'],
|
country_codes: ['US', 'UK'],
|
||||||
});
|
});
|
||||||
// Sync bank accounts.
|
// Sync bank accounts.
|
||||||
await this.plaidSync.syncBankAccounts(tenantId, accounts, institution, trx);
|
await this.plaidSync.syncBankAccounts(
|
||||||
|
tenantId,
|
||||||
|
accounts,
|
||||||
|
institution,
|
||||||
|
item,
|
||||||
|
trx
|
||||||
|
);
|
||||||
// Sync bank account transactions.
|
// Sync bank account transactions.
|
||||||
await this.plaidSync.syncAccountsTransactions(
|
await this.plaidSync.syncAccountsTransactions(
|
||||||
tenantId,
|
tenantId,
|
||||||
@@ -141,7 +147,7 @@ export class PlaidUpdateTransactions {
|
|||||||
cursor: cursor,
|
cursor: cursor,
|
||||||
count: batchSize,
|
count: batchSize,
|
||||||
};
|
};
|
||||||
const plaidInstance = new PlaidClientWrapper();
|
const plaidInstance = PlaidClientWrapper.getClient();
|
||||||
const response = await plaidInstance.transactionsSync(request);
|
const response = await plaidInstance.transactionsSync(request);
|
||||||
const data = response.data;
|
const data = response.data;
|
||||||
// Add this page of results
|
// Add this page of results
|
||||||
|
|||||||
@@ -1,18 +1,28 @@
|
|||||||
import * as R from 'ramda';
|
import * as R from 'ramda';
|
||||||
|
import {
|
||||||
|
Item as PlaidItem,
|
||||||
|
Institution as PlaidInstitution,
|
||||||
|
AccountBase as PlaidAccount,
|
||||||
|
} from 'plaid';
|
||||||
import {
|
import {
|
||||||
CreateUncategorizedTransactionDTO,
|
CreateUncategorizedTransactionDTO,
|
||||||
IAccountCreateDTO,
|
IAccountCreateDTO,
|
||||||
PlaidAccount,
|
|
||||||
PlaidTransaction,
|
PlaidTransaction,
|
||||||
} from '@/interfaces';
|
} from '@/interfaces';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Transformes the Plaid account to create cashflow account DTO.
|
* Transformes the Plaid account to create cashflow account DTO.
|
||||||
* @param {PlaidAccount} plaidAccount
|
* @param {PlaidItem} item -
|
||||||
|
* @param {PlaidInstitution} institution -
|
||||||
|
* @param {PlaidAccount} plaidAccount -
|
||||||
* @returns {IAccountCreateDTO}
|
* @returns {IAccountCreateDTO}
|
||||||
*/
|
*/
|
||||||
export const transformPlaidAccountToCreateAccount = R.curry(
|
export const transformPlaidAccountToCreateAccount = R.curry(
|
||||||
(institution: any, plaidAccount: PlaidAccount): IAccountCreateDTO => {
|
(
|
||||||
|
item: PlaidItem,
|
||||||
|
institution: PlaidInstitution,
|
||||||
|
plaidAccount: PlaidAccount
|
||||||
|
): IAccountCreateDTO => {
|
||||||
return {
|
return {
|
||||||
name: `${institution.name} - ${plaidAccount.name}`,
|
name: `${institution.name} - ${plaidAccount.name}`,
|
||||||
code: '',
|
code: '',
|
||||||
@@ -20,9 +30,10 @@ export const transformPlaidAccountToCreateAccount = R.curry(
|
|||||||
currencyCode: plaidAccount.balances.iso_currency_code,
|
currencyCode: plaidAccount.balances.iso_currency_code,
|
||||||
accountType: 'cash',
|
accountType: 'cash',
|
||||||
active: true,
|
active: true,
|
||||||
plaidAccountId: plaidAccount.account_id,
|
|
||||||
bankBalance: plaidAccount.balances.current,
|
bankBalance: plaidAccount.balances.current,
|
||||||
accountMask: plaidAccount.mask,
|
accountMask: plaidAccount.mask,
|
||||||
|
plaidAccountId: plaidAccount.account_id,
|
||||||
|
plaidItemId: item.item_id,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import {
|
|||||||
DashboardRowsHeightButton,
|
DashboardRowsHeightButton,
|
||||||
FormattedMessage as T,
|
FormattedMessage as T,
|
||||||
AppToaster,
|
AppToaster,
|
||||||
|
If,
|
||||||
} from '@/components';
|
} from '@/components';
|
||||||
|
|
||||||
import { CashFlowMenuItems } from './utils';
|
import { CashFlowMenuItems } from './utils';
|
||||||
@@ -41,6 +42,7 @@ import {
|
|||||||
useDisconnectBankAccount,
|
useDisconnectBankAccount,
|
||||||
useUpdateBankAccount,
|
useUpdateBankAccount,
|
||||||
} from '@/hooks/query/bank-rules';
|
} from '@/hooks/query/bank-rules';
|
||||||
|
import { current } from '@reduxjs/toolkit';
|
||||||
|
|
||||||
function AccountTransactionsActionsBar({
|
function AccountTransactionsActionsBar({
|
||||||
// #withDialogActions
|
// #withDialogActions
|
||||||
@@ -66,6 +68,7 @@ function AccountTransactionsActionsBar({
|
|||||||
const addMoneyOutOptions = useMemo(() => getAddMoneyOutOptions(), []);
|
const addMoneyOutOptions = useMemo(() => getAddMoneyOutOptions(), []);
|
||||||
|
|
||||||
const isFeedsActive = !!currentAccount.is_feeds_active;
|
const isFeedsActive = !!currentAccount.is_feeds_active;
|
||||||
|
const isSyncingOwner = currentAccount.is_syncing_owner;
|
||||||
|
|
||||||
// Handle table row size change.
|
// Handle table row size change.
|
||||||
const handleTableRowSizeChange = (size) => {
|
const handleTableRowSizeChange = (size) => {
|
||||||
@@ -176,6 +179,7 @@ function AccountTransactionsActionsBar({
|
|||||||
/>
|
/>
|
||||||
<NavbarDivider />
|
<NavbarDivider />
|
||||||
|
|
||||||
|
<If condition={isSyncingOwner}>
|
||||||
<Tooltip
|
<Tooltip
|
||||||
content={
|
content={
|
||||||
isFeedsActive
|
isFeedsActive
|
||||||
@@ -191,6 +195,7 @@ function AccountTransactionsActionsBar({
|
|||||||
intent={isFeedsActive ? Intent.SUCCESS : Intent.DANGER}
|
intent={isFeedsActive ? Intent.SUCCESS : Intent.DANGER}
|
||||||
/>
|
/>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
</If>
|
||||||
</NavbarGroup>
|
</NavbarGroup>
|
||||||
|
|
||||||
<NavbarGroup align={Alignment.RIGHT}>
|
<NavbarGroup align={Alignment.RIGHT}>
|
||||||
@@ -203,17 +208,15 @@ function AccountTransactionsActionsBar({
|
|||||||
}}
|
}}
|
||||||
content={
|
content={
|
||||||
<Menu>
|
<Menu>
|
||||||
{isFeedsActive && (
|
<If condition={isSyncingOwner && isFeedsActive}>
|
||||||
<>
|
|
||||||
<MenuItem onClick={handleBankUpdateClick} text={'Update'} />
|
<MenuItem onClick={handleBankUpdateClick} text={'Update'} />
|
||||||
<MenuDivider />
|
<MenuDivider />
|
||||||
</>
|
</If>
|
||||||
)}
|
|
||||||
<MenuItem onClick={handleBankRulesClick} text={'Bank rules'} />
|
<MenuItem onClick={handleBankRulesClick} text={'Bank rules'} />
|
||||||
|
|
||||||
{isFeedsActive && (
|
<If condition={isSyncingOwner && isFeedsActive}>
|
||||||
<MenuItem onClick={handleDisconnectClick} text={'Disconnect'} />
|
<MenuItem onClick={handleDisconnectClick} text={'Disconnect'} />
|
||||||
)}
|
</If>
|
||||||
</Menu>
|
</Menu>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
|||||||
Reference in New Issue
Block a user