Compare commits

...

12 Commits

Author SHA1 Message Date
a.bouhuolia
36611652da fix(webapp): resource meta of vendors list 2023-05-05 15:41:32 +02:00
a.bouhuolia
06c7ee71b4 fix(webapp): display transactions count in cashflow account 2023-05-05 13:54:45 +02:00
Ahmed Bouhuolia
54d3188666 Merge pull request #116 from bigcapitalhq/BIG-427-fix-sending-invite-email
fix(server): sending invite email
2023-05-05 00:30:24 +02:00
a.bouhuolia
3ceb9adda2 fix(server): sending invite email 2023-05-05 00:28:57 +02:00
Ahmed Bouhuolia
1249415054 Merge pull request #115 from bigcapitalhq/BIG-409-some-flag-icons-are-missing
fix(webapp): some flag icons are missing
2023-05-04 21:32:10 +02:00
Ahmed Bouhuolia
6c96c371c5 Merge pull request #114 from bigcapitalhq/BIG-279-select-specific-accounts-in-general-ledger-does-not-working
`BIG-279` Select specific accounts in general ledger does not working.
2023-05-04 14:29:35 +02:00
a.bouhuolia
6c61a69f10 feat(webapp): handle create item on Accounts select components 2023-05-04 14:24:45 +02:00
a.bouhuolia
981b65349d feat(webapp): allow to create a new account item in accounts list component. 2023-05-03 22:41:54 +02:00
a.bouhuolia
a7d29a31c8 refactor(webapp): all services with new AccountSelect and AccountMultiSelect components. 2023-05-01 00:13:23 +02:00
a.bouhuolia
c1d92b74f0 chore(Select):style the Select button. 2023-04-30 21:13:33 +02:00
a.bouhuolia
6f0f47f38a refactor(webapp): Accounts Select and MultiSelect components 2023-04-30 17:33:15 +02:00
a.bouhuolia
83510cfa70 feat(server): add structure query flat or tree to accounts chart endpoint 2023-04-30 17:24:49 +02:00
54 changed files with 1049 additions and 1103 deletions

View File

@@ -3,7 +3,12 @@ import { check, param, query } from 'express-validator';
import { Service, Inject } from 'typedi'; import { Service, Inject } from 'typedi';
import asyncMiddleware from '@/api/middleware/asyncMiddleware'; import asyncMiddleware from '@/api/middleware/asyncMiddleware';
import BaseController from '@/api/controllers/BaseController'; import BaseController from '@/api/controllers/BaseController';
import { AbilitySubject, AccountAction, IAccountDTO } from '@/interfaces'; import {
AbilitySubject,
AccountAction,
IAccountDTO,
IAccountsStructureType,
} from '@/interfaces';
import { ServiceError } from '@/exceptions'; import { ServiceError } from '@/exceptions';
import DynamicListingService from '@/services/DynamicListing/DynamicListService'; import DynamicListingService from '@/services/DynamicListing/DynamicListService';
import { DATATYPES_LENGTH } from '@/data/DataTypes'; import { DATATYPES_LENGTH } from '@/data/DataTypes';
@@ -172,6 +177,11 @@ export default class AccountsController extends BaseController {
query('inactive_mode').optional().isBoolean().toBoolean(), query('inactive_mode').optional().isBoolean().toBoolean(),
query('search_keyword').optional({ nullable: true }).isString().trim(), query('search_keyword').optional({ nullable: true }).isString().trim(),
query('structure')
.optional()
.isString()
.isIn([IAccountsStructureType.Tree, IAccountsStructureType.Flat]),
]; ];
} }
@@ -341,6 +351,7 @@ export default class AccountsController extends BaseController {
sortOrder: 'desc', sortOrder: 'desc',
columnSortBy: 'created_at', columnSortBy: 'created_at',
inactiveMode: false, inactiveMode: false,
structure: IAccountsStructureType.Tree,
...this.matchedQueryData(req), ...this.matchedQueryData(req),
}; };

View File

@@ -67,6 +67,7 @@ export default class GeneralLedgerReportController extends BaseFinancialReportCo
try { try {
const { data, query, meta } = const { data, query, meta } =
await this.generalLedgetService.generalLedger(tenantId, filter); await this.generalLedgetService.generalLedger(tenantId, filter);
return res.status(200).send({ return res.status(200).send({
meta: this.transfromToResponse(meta), meta: this.transfromToResponse(meta),
data: this.transfromToResponse(data), data: this.transfromToResponse(data),

View File

@@ -4,6 +4,7 @@ import moment from 'moment';
global.__root_dir = path.join(__dirname, '..'); global.__root_dir = path.join(__dirname, '..');
global.__resources_dir = path.join(global.__root_dir, 'resources'); global.__resources_dir = path.join(global.__root_dir, 'resources');
global.__locales_dir = path.join(global.__resources_dir, 'locales'); global.__locales_dir = path.join(global.__resources_dir, 'locales');
global.__views_dir = path.join(global.__root_dir, 'views');
moment.prototype.toMySqlDateTime = function () { moment.prototype.toMySqlDateTime = function () {
return this.format('YYYY-MM-DD HH:mm:ss'); return this.format('YYYY-MM-DD HH:mm:ss');

View File

@@ -79,9 +79,15 @@ export interface IAccountTransaction {
} }
export interface IAccountResponse extends IAccount {} export interface IAccountResponse extends IAccount {}
export enum IAccountsStructureType {
Tree = 'tree',
Flat = 'flat',
}
export interface IAccountsFilter extends IDynamicListFilterDTO { export interface IAccountsFilter extends IDynamicListFilterDTO {
stringifiedFilterRoles?: string; stringifiedFilterRoles?: string;
onlyInactive: boolean; onlyInactive: boolean;
structure?: IAccountsStructureType;
} }
export interface IAccountType { export interface IAccountType {

View File

@@ -1,6 +1,7 @@
import { AnyObject } from '@casl/ability/dist/types/types'; import { AnyObject } from '@casl/ability/dist/types/types';
import { ITenant } from '@/interfaces'; import { ITenant } from '@/interfaces';
import { Model } from 'objection'; import { Model } from 'objection';
import { Tenant } from '@/system/models';
export interface ISystemUser extends Model { export interface ISystemUser extends Model {
id: number; id: number;
@@ -54,20 +55,52 @@ export interface IUserInvite {
export interface IInviteUserService { export interface IInviteUserService {
acceptInvite(token: string, inviteUserInput: IInviteUserInput): Promise<void>; acceptInvite(token: string, inviteUserInput: IInviteUserInput): Promise<void>;
/**
* Re-send user invite.
* @param {number} tenantId -
* @param {string} email -
* @return {Promise<{ invite: IUserInvite }>}
*/
resendInvite( resendInvite(
tenantId: number, tenantId: number,
userId: number, userId: number,
authorizedUser: ISystemUser authorizedUser: ISystemUser
): Promise<{ ): Promise<{
invite: IUserInvite; user: ITenantUser;
}>; }>;
/**
* Sends invite mail to the given email from the given tenant and user.
* @param {number} tenantId -
* @param {string} email -
* @param {IUser} authorizedUser -
* @return {Promise<IUserInvite>}
*/
sendInvite( sendInvite(
tenantId: number, tenantId: number,
email: string, sendInviteDTO: IUserSendInviteDTO,
authorizedUser: ISystemUser authorizedUser: ISystemUser
): Promise<{ ): Promise<{
invite: IUserInvite; invitedUser: ITenantUser;
}>; }>;
}
export interface IAcceptInviteUserService {
/**
* Accept the received invite.
* @param {string} token
* @param {IInviteUserInput} inviteUserInput
* @throws {ServiceErrors}
* @returns {Promise<void>}
*/
acceptInvite(token: string, inviteUserDTO: IInviteUserInput): Promise<void>;
/**
* Validate the given invite token.
* @param {string} token - the given token string.
* @throws {ServiceError}
*/
checkInvite( checkInvite(
token: string token: string
): Promise<{ inviteToken: IUserInvite; orgName: object }>; ): Promise<{ inviteToken: IUserInvite; orgName: object }>;
@@ -121,7 +154,7 @@ export interface IUserInvitedEventPayload {
tenantId: number; tenantId: number;
user: ITenantUser; user: ITenantUser;
} }
export interface IUserInviteTenantSyncedEventPayload{ export interface IUserInviteTenantSyncedEventPayload {
invite: IUserInvite; invite: IUserInvite;
authorizedUser: ISystemUser; authorizedUser: ISystemUser;
tenantId: number; tenantId: number;
@@ -143,10 +176,10 @@ export interface IAcceptInviteEventPayload {
export interface ICheckInviteEventPayload { export interface ICheckInviteEventPayload {
inviteToken: IUserInvite; inviteToken: IUserInvite;
tenant: ITenant tenant: Tenant;
} }
export interface IUserSendInviteDTO { export interface IUserSendInviteDTO {
email: string; email: string;
roleId: number; roleId: number;
} }

View File

@@ -1,5 +1,6 @@
import { Container, Inject } from 'typedi'; import { Container, Inject } from 'typedi';
import InviteUserService from '@/services/InviteUsers/AcceptInviteUser'; import InviteUserService from '@/services/InviteUsers/AcceptInviteUser';
import SendInviteUsersMailMessage from '@/services/InviteUsers/SendInviteUsersMailMessage';
export default class UserInviteMailJob { export default class UserInviteMailJob {
/** /**
@@ -21,24 +22,17 @@ export default class UserInviteMailJob {
*/ */
public async handler(job, done: Function): Promise<void> { public async handler(job, done: Function): Promise<void> {
const { invite, authorizedUser, tenantId } = job.attrs.data; const { invite, authorizedUser, tenantId } = job.attrs.data;
const sendInviteMailMessage = Container.get(SendInviteUsersMailMessage);
const Logger = Container.get('logger');
const inviteUsersService = Container.get(InviteUserService);
Logger.info(`Send invite user mail - started: ${job.attrs.data}`);
try { try {
await inviteUsersService.mailMessages.sendInviteMail( await sendInviteMailMessage.sendInviteMail(
tenantId, tenantId,
authorizedUser, authorizedUser,
invite invite
); );
Logger.info(`Send invite user mail - finished: ${job.attrs.data}`);
done(); done();
} catch (error) { } catch (error) {
Logger.info( console.log(error);
`Send invite user mail - error: ${job.attrs.data}, error: ${error}`
);
done(error); done(error);
} }
} }

View File

@@ -109,7 +109,7 @@ export default class Mail {
* Retrieve view content from the view directory. * Retrieve view content from the view directory.
*/ */
private getViewContent(): string { private getViewContent(): string {
const filePath = path.join(global.__root_dir, `../views/${this.view}`); const filePath = path.join(global.__views_dir, `/${this.view}`);
return fs.readFileSync(filePath, 'utf8'); return fs.readFileSync(filePath, 'utf8');
} }
} }

View File

@@ -2,6 +2,7 @@ import moment from 'moment';
import * as R from 'ramda'; import * as R from 'ramda';
import { includes, isFunction, isObject, isUndefined, omit } from 'lodash'; import { includes, isFunction, isObject, isUndefined, omit } from 'lodash';
import { formatNumber } from 'utils'; import { formatNumber } from 'utils';
import { isArrayLikeObject } from 'lodash/fp';
export class Transformer { export class Transformer {
public context: any; public context: any;
@@ -39,12 +40,33 @@ export class Transformer {
return object; return object;
}; };
/**
*
* @param object
* @returns
*/
protected preCollectionTransform = (object: any) => {
return object;
};
/**
*
* @param object
* @returns
*/
protected postCollectionTransform = (object: any) => {
return object;
};
/** /**
* *
*/ */
public work = (object: any) => { public work = (object: any) => {
if (Array.isArray(object)) { if (Array.isArray(object)) {
return object.map(this.getTransformation); const preTransformed = this.preCollectionTransform(object);
const transformed = preTransformed.map(this.getTransformation);
return this.postCollectionTransform(transformed);
} else if (isObject(object)) { } else if (isObject(object)) {
return this.getTransformation(object); return this.getTransformation(object);
} }

View File

@@ -22,7 +22,7 @@ import SaleInvoiceAutoIncrementSubscriber from '@/subscribers/SaleInvoices/AutoI
import SaleInvoiceConvertFromEstimateSubscriber from '@/subscribers/SaleInvoices/ConvertFromEstimate'; import SaleInvoiceConvertFromEstimateSubscriber from '@/subscribers/SaleInvoices/ConvertFromEstimate';
import PaymentReceiveAutoSerialSubscriber from '@/subscribers/PaymentReceive/AutoSerialIncrement'; import PaymentReceiveAutoSerialSubscriber from '@/subscribers/PaymentReceive/AutoSerialIncrement';
import SyncSystemSendInvite from '@/services/InviteUsers/SyncSystemSendInvite'; import SyncSystemSendInvite from '@/services/InviteUsers/SyncSystemSendInvite';
import InviteSendMainNotification from '@/services/InviteUsers/InviteSendMailNotification'; import InviteSendMainNotification from '@/services/InviteUsers/InviteSendMailNotificationSubscribe';
import SyncTenantAcceptInvite from '@/services/InviteUsers/SyncTenantAcceptInvite'; import SyncTenantAcceptInvite from '@/services/InviteUsers/SyncTenantAcceptInvite';
import SyncTenantUserMutate from '@/services/Users/SyncTenantUserSaved'; import SyncTenantUserMutate from '@/services/Users/SyncTenantUserSaved';
import { SyncTenantUserDelete } from '@/services/Users/SyncTenantUserDeleted'; import { SyncTenantUserDelete } from '@/services/Users/SyncTenantUserDeleted';

View File

@@ -1,6 +1,11 @@
import { IAccount } from '@/interfaces'; import { IAccount, IAccountsStructureType } from '@/interfaces';
import { Transformer } from '@/lib/Transformer/Transformer'; import { Transformer } from '@/lib/Transformer/Transformer';
import { formatNumber } from 'utils'; import {
assocDepthLevelToObjectTree,
flatToNestedArray,
formatNumber,
nestedArrayToFlatten,
} from 'utils';
export class AccountTransformer extends Transformer { export class AccountTransformer extends Transformer {
/** /**
@@ -8,7 +13,23 @@ export class AccountTransformer extends Transformer {
* @returns {Array} * @returns {Array}
*/ */
public includeAttributes = (): string[] => { public includeAttributes = (): string[] => {
return ['formattedAmount']; return ['formattedAmount', 'flattenName'];
};
/**
* Retrieves the flatten name with all dependants accounts names.
* @param {IAccount} account -
* @returns {string}
*/
public flattenName = (account: IAccount): string => {
const parentDependantsIds = this.options.accountsGraph.dependantsOf(
account.id
);
const prefixAccounts = parentDependantsIds.map((dependId) => {
const node = this.options.accountsGraph.getNodeData(dependId);
return `${node.name}: `;
});
return `${prefixAccounts}${account.name}`;
}; };
/** /**
@@ -17,8 +38,28 @@ export class AccountTransformer extends Transformer {
* @returns {string} * @returns {string}
*/ */
protected formattedAmount = (account: IAccount): string => { protected formattedAmount = (account: IAccount): string => {
return formatNumber(account.amount, { return formatNumber(account.amount, { currencyCode: account.currencyCode });
currencyCode: account.currencyCode, };
/**
* Transformes the accounts collection to flat or nested array.
* @param {IAccount[]}
* @returns {IAccount[]}
*/
protected postCollectionTransform = (accounts: IAccount[]) => {
// Transfom the flatten to accounts tree.
const transformed = flatToNestedArray(accounts, {
id: 'id',
parentId: 'parentAccountId',
}); });
// Associate `accountLevel` attr to indicate object depth.
const transformed2 = assocDepthLevelToObjectTree(
transformed,
1,
'accountLevel'
);
return this.options.structure === IAccountsStructureType.Flat
? nestedArrayToFlatten(transformed2)
: transformed2;
}; };
} }

View File

@@ -22,15 +22,19 @@ export class GetAccount {
*/ */
public getAccount = async (tenantId: number, accountId: number) => { public getAccount = async (tenantId: number, accountId: number) => {
const { Account } = this.tenancy.models(tenantId); const { Account } = this.tenancy.models(tenantId);
const { accountRepository } = this.tenancy.repositories(tenantId);
// Find the given account or throw not found error. // Find the given account or throw not found error.
const account = await Account.query().findById(accountId).throwIfNotFound(); const account = await Account.query().findById(accountId).throwIfNotFound();
const accountsGraph = await accountRepository.getDependencyGraph();
// Transformes the account model to POJO. // Transformes the account model to POJO.
const transformed = await this.transformer.transform( const transformed = await this.transformer.transform(
tenantId, tenantId,
account, account,
new AccountTransformer() new AccountTransformer(),
{ accountsGraph }
); );
return this.i18nService.i18nApply( return this.i18nService.i18nApply(
[['accountTypeLabel'], ['accountNormalFormatted']], [['accountTypeLabel'], ['accountNormalFormatted']],

View File

@@ -1,6 +1,11 @@
import { Inject, Service } from 'typedi'; import { Inject, Service } from 'typedi';
import * as R from 'ramda'; import * as R from 'ramda';
import { IAccountsFilter, IAccountResponse, IFilterMeta } from '@/interfaces'; import {
IAccountsFilter,
IAccountResponse,
IFilterMeta,
IAccountsStructureType,
} from '@/interfaces';
import TenancyService from '@/services/Tenancy/TenancyService'; import TenancyService from '@/services/Tenancy/TenancyService';
import DynamicListingService from '@/services/DynamicListing/DynamicListService'; import DynamicListingService from '@/services/DynamicListing/DynamicListService';
import { AccountTransformer } from './AccountTransform'; import { AccountTransformer } from './AccountTransform';
@@ -38,6 +43,7 @@ export class GetAccounts {
filterDTO: IAccountsFilter filterDTO: IAccountsFilter
): Promise<{ accounts: IAccountResponse[]; filterMeta: IFilterMeta }> => { ): Promise<{ accounts: IAccountResponse[]; filterMeta: IFilterMeta }> => {
const { Account } = this.tenancy.models(tenantId); const { Account } = this.tenancy.models(tenantId);
const { accountRepository } = this.tenancy.repositories(tenantId);
// Parses the stringified filter roles. // Parses the stringified filter roles.
const filter = this.parseListFilterDTO(filterDTO); const filter = this.parseListFilterDTO(filterDTO);
@@ -53,17 +59,16 @@ export class GetAccounts {
dynamicList.buildQuery()(builder); dynamicList.buildQuery()(builder);
builder.modify('inactiveMode', filter.inactiveMode); builder.modify('inactiveMode', filter.inactiveMode);
}); });
// Retrievs the formatted accounts collection.
const preTransformedAccounts = await this.transformer.transform( const accountsGraph = await accountRepository.getDependencyGraph();
// Retrieves the transformed accounts collection.
const transformedAccounts = await this.transformer.transform(
tenantId, tenantId,
accounts, accounts,
new AccountTransformer() new AccountTransformer(),
{ accountsGraph, structure: filterDTO.structure }
); );
// Transform accounts to nested array.
const transformedAccounts = flatToNestedArray(preTransformedAccounts, {
id: 'id',
parentId: 'parentAccountId',
});
return { return {
accounts: transformedAccounts, accounts: transformedAccounts,

View File

@@ -5,7 +5,7 @@ import { ICashflowAccountTransactionsQuery, IPaginationMeta } from '@/interfaces
@Service() @Service()
export default class CashflowAccountTransactionsRepo { export default class CashflowAccountTransactionsRepo {
@Inject() @Inject()
tenancy: HasTenancyService; private tenancy: HasTenancyService;
/** /**
* Retrieve the cashflow account transactions. * Retrieve the cashflow account transactions.

View File

@@ -12,9 +12,12 @@ import {
} from '@/interfaces'; } from '@/interfaces';
import { ERRORS } from './constants'; import { ERRORS } from './constants';
import { EventPublisher } from '@/lib/EventPublisher/EventPublisher'; import { EventPublisher } from '@/lib/EventPublisher/EventPublisher';
import { IAcceptInviteUserService } from '@/interfaces';
@Service() @Service()
export default class AcceptInviteUserService { export default class AcceptInviteUserService
implements IAcceptInviteUserService
{
@Inject() @Inject()
private eventPublisher: EventPublisher; private eventPublisher: EventPublisher;

View File

@@ -1,7 +1,4 @@
import { import { IUserInviteTenantSyncedEventPayload } from '@/interfaces';
IUserInvitedEventPayload,
IUserInviteTenantSyncedEventPayload,
} from '@/interfaces';
import events from '@/subscribers/events'; import events from '@/subscribers/events';
import { Inject, Service } from 'typedi'; import { Inject, Service } from 'typedi';

View File

@@ -1,12 +1,12 @@
import path from 'path';
import { ISystemUser } from '@/interfaces'; import { ISystemUser } from '@/interfaces';
import TenancyService from '@/services/Tenancy/TenancyService';
import Mail from '@/lib/Mail'; import Mail from '@/lib/Mail';
import { Service, Container } from 'typedi'; import { Service } from 'typedi';
import config from '@/config';
import { Tenant } from '@/system/models'; import { Tenant } from '@/system/models';
import config from '@/config';
@Service() @Service()
export default class InviteUsersMailMessages { export default class SendInviteUsersMailMessage {
/** /**
* Sends invite mail to the given email. * Sends invite mail to the given email.
* @param user * @param user
@@ -18,7 +18,7 @@ export default class InviteUsersMailMessages {
.findById(tenantId) .findById(tenantId)
.withGraphFetched('metadata'); .withGraphFetched('metadata');
const root = __dirname + '/../../../views/images/bigcapital.png'; const root = path.join(global.__views_dir, '/images/bigcapital.png');
const mail = new Mail() const mail = new Mail()
.setSubject(`${fromUser.firstName} has invited you to join a Bigcapital`) .setSubject(`${fromUser.firstName} has invited you to join a Bigcapital`)

View File

@@ -8,7 +8,7 @@ import { IAcceptInviteEventPayload } from '@/interfaces';
@Service() @Service()
export default class SyncTenantAcceptInvite { export default class SyncTenantAcceptInvite {
@Inject() @Inject()
tenancy: HasTenancyService; private tenancy: HasTenancyService;
/** /**
* Attaches events with handlers. * Attaches events with handlers.

View File

@@ -74,17 +74,15 @@ export default class InviteTenantUserService implements IInviteUserService {
/** /**
* Re-send user invite. * Re-send user invite.
* @param {number} tenantId - * @param {number} tenantId -
* @param {string} email - * @param {string} email -
* @return {Promise<{ invite: IUserInvite }>} * @return {Promise<{ invite: IUserInvite }>}
*/ */
public async resendInvite( public async resendInvite(
tenantId: number, tenantId: number,
userId: number, userId: number,
authorizedUser: ISystemUser authorizedUser: ISystemUser
): Promise<{ ): Promise<{ user: ITenantUser }> {
user: ITenantUser;
}> {
// Retrieve the user by id or throw not found service error. // Retrieve the user by id or throw not found service error.
const user = await this.getUserByIdOrThrowError(tenantId, userId); const user = await this.getUserByIdOrThrowError(tenantId, userId);

View File

@@ -419,6 +419,54 @@ export const parseDate = (date: string) => {
return date ? moment(date).utcOffset(0).format('YYYY-MM-DD') : ''; return date ? moment(date).utcOffset(0).format('YYYY-MM-DD') : '';
}; };
const nestedArrayToFlatten = (
collection,
property = 'children',
parseItem = (a, level) => a,
level = 1
) => {
const parseObject = (obj) =>
parseItem(
{
..._.omit(obj, [property]),
},
level
);
return collection.reduce((items, currentValue, index) => {
let localItems = [...items];
const parsedItem = parseObject(currentValue, level);
localItems.push(parsedItem);
if (Array.isArray(currentValue[property])) {
const flattenArray = nestedArrayToFlatten(
currentValue[property],
property,
parseItem,
level + 1
);
localItems = _.concat(localItems, flattenArray);
}
return localItems;
}, []);
};
const assocDepthLevelToObjectTree = (
objects,
level = 1,
propertyName = 'level'
) => {
for (let i = 0; i < objects.length; i++) {
const object = objects[i];
object[propertyName] = level;
if (object.children) {
assocDepthLevelToObjectTree(object.children, level + 1, propertyName);
}
}
return objects;
};
export { export {
templateRender, templateRender,
accumSum, accumSum,
@@ -449,4 +497,6 @@ export {
dateRangeFromToCollection, dateRangeFromToCollection,
transformToMapKeyValue, transformToMapKeyValue,
mergeObjectsBykey, mergeObjectsBykey,
nestedArrayToFlatten,
assocDepthLevelToObjectTree,
}; };

View File

@@ -1227,9 +1227,9 @@
} }
}, },
"@blueprintjs-formik/select": { "@blueprintjs-formik/select": {
"version": "0.1.5", "version": "0.2.3",
"resolved": "https://registry.npmjs.org/@blueprintjs-formik/select/-/select-0.1.5.tgz", "resolved": "https://registry.npmjs.org/@blueprintjs-formik/select/-/select-0.2.3.tgz",
"integrity": "sha512-EqGbuoiS1VrWpzjd39uVhBAmfVobdpgqalGcpODyGA+XAYoft1UU12yzTzrEOwBZpQKiC12UQwekUPspYBsVKA==", "integrity": "sha512-j/zkX0B9wgtoHgK6Z/rlowB7F7zemrAajBU+d3caCoEYMMqwAI0XA++GytqrIhv5fEGjkZ1hkxS9j8eqX8vtjA==",
"requires": { "requires": {
"lodash.get": "^4.4.2", "lodash.get": "^4.4.2",
"lodash.keyby": "^4.6.0", "lodash.keyby": "^4.6.0",

View File

@@ -5,7 +5,7 @@
"dependencies": { "dependencies": {
"@blueprintjs-formik/core": "^0.2.1", "@blueprintjs-formik/core": "^0.2.1",
"@blueprintjs-formik/datetime": "^0.3.4", "@blueprintjs-formik/datetime": "^0.3.4",
"@blueprintjs-formik/select": "^0.1.4", "@blueprintjs-formik/select": "^0.2.3",
"@blueprintjs/core": "^3.50.2", "@blueprintjs/core": "^3.50.2",
"@blueprintjs/datetime": "^3.23.12", "@blueprintjs/datetime": "^3.23.12",
"@blueprintjs/popover2": "^0.11.1", "@blueprintjs/popover2": "^0.11.1",

View File

@@ -1,74 +0,0 @@
// @ts-nocheck
import React from 'react';
import styled from 'styled-components';
import { MenuItem } from '@blueprintjs/core';
import { FMultiSelect } from '../Forms';
import classNames from 'classnames';
import { Classes } from '@blueprintjs/popover2';
/**
*
* @param {*} query
* @param {*} account
* @param {*} _index
* @param {*} exactMatch
* @returns
*/
const accountItemPredicate = (query, account, _index, exactMatch) => {
const normalizedTitle = account.name.toLowerCase();
const normalizedQuery = query.toLowerCase();
if (exactMatch) {
return normalizedTitle === normalizedQuery;
} else {
return `${account.code}. ${normalizedTitle}`.indexOf(normalizedQuery) >= 0;
}
};
/**
*
* @param {*} account
* @param {*} param1
* @returns
*/
const accountItemRenderer = (
account,
{ handleClick, modifiers, query },
{ isSelected },
) => {
return (
<MenuItem
icon={isSelected ? 'tick' : 'blank'}
text={account.name}
label={account.code}
key={account.id}
onClick={handleClick}
/>
);
};
const accountSelectProps = {
itemPredicate: accountItemPredicate,
itemRenderer: accountItemRenderer,
valueAccessor: (item) => item.id,
labelAccessor: (item) => item.code,
tagRenderer: (item) => item.name,
};
/**
* branches mulit select.
* @param {*} param0
* @returns {JSX.Element}
*/
export function AccountMultiSelect({ accounts, ...rest }) {
return (
<FMultiSelect
items={accounts}
popoverProps={{
minimal: true,
}}
{...accountSelectProps}
{...rest}
/>
);
}

View File

@@ -1,31 +1,97 @@
// @ts-nocheck // @ts-nocheck
import React from 'react'; import React from 'react';
import { MenuItem } from '@blueprintjs/core'; import { MenuItem } from '@blueprintjs/core';
import { MultiSelect } from '../MultiSelectTaggable'; import { FMultiSelect } from '../Forms';
import { accountPredicate } from './_components';
import { MenuItemNestedText } from '../Menu';
import { usePreprocessingAccounts } from './_hooks';
export function AccountsMultiSelect({ ...multiSelectProps }) { // Create new account renderer.
const createNewItemRenderer = (query, active, handleClick) => {
return ( return (
<MultiSelect <MenuItem
itemRenderer={( icon="add"
item, text={intl.get('list.create', { value: `"${query}"` })}
{ active, selected, handleClick, modifiers, query }, active={active}
) => { onClick={handleClick}
return ( />
<MenuItem );
active={active} };
icon={selected ? 'tick' : 'blank'}
text={item.name} /**
label={item.code} * Default account item renderer of the list.
key={item.id} * @returns {JSX.Element}
onClick={handleClick} */
/> const accountRenderer = (
); item,
}} { handleClick, modifiers, query },
{ isSelected },
) => {
if (!modifiers.matchesPredicate) {
return null;
}
return (
<MenuItem
active={modifiers.active}
disabled={modifiers.disabled}
text={<MenuItemNestedText level={item.account_level} text={item.name} />}
key={item.id}
onClick={handleClick}
icon={isSelected ? 'tick' : 'blank'}
/>
);
};
// Create new item from the given query string.
const createNewItemFromQuery = (name) => ({ name });
/**
* Accounts multi-select field binded with Formik form.
* @returns {JSX.Element}
*/
export function AccountsMultiSelect({
items,
allowCreate,
filterByRootTypes,
filterByParentTypes,
filterByTypes,
filterByNormal,
...rest
}) {
// Filters accounts based on filter props.
const filteredAccounts = usePreprocessingAccounts(items, {
filterByParentTypes,
filterByTypes,
filterByNormal,
filterByRootTypes,
});
// Maybe inject new item props to select component.
const maybeCreateNewItemRenderer = allowCreate ? createNewItemRenderer : null;
const maybeCreateNewItemFromQuery = allowCreate
? createNewItemFromQuery
: null;
// Handles the create item click.
const handleCreateItemClick = () => {
openDialog(DialogsName.AccountForm);
};
return (
<FMultiSelect
items={filteredAccounts}
valueAccessor={'id'}
textAccessor={'name'}
labelAccessor={'code'}
tagAccessor={'name'}
popoverProps={{ minimal: true }} popoverProps={{ minimal: true }}
fill={true} itemPredicate={accountPredicate}
tagRenderer={(item) => item.name} itemRenderer={accountRenderer}
resetOnSelect={true} createNewItemRenderer={maybeCreateNewItemRenderer}
{...multiSelectProps} createNewItemFromQuery={maybeCreateNewItemFromQuery}
onCreateItemSelect={handleCreateItemClick}
{...rest}
/> />
); );
} }

View File

@@ -0,0 +1,101 @@
// @ts-nocheck
import React from 'react';
import * as R from 'ramda';
import intl from 'react-intl-universal';
import { MenuItem } from '@blueprintjs/core';
import { MenuItemNestedText, FSelect } from '@/components';
import { accountPredicate } from './_components';
import { DialogsName } from '@/constants/dialogs';
import withDialogActions from '@/containers/Dialog/withDialogActions';
import { usePreprocessingAccounts } from './_hooks';
// Create new account renderer.
const createNewItemRenderer = (query, active, handleClick) => {
return (
<MenuItem
icon="add"
text={intl.get('list.create', { value: `"${query}"` })}
active={active}
onClick={handleClick}
/>
);
};
// Create new item from the given query string.
const createNewItemFromQuery = (name) => ({ name });
/**
* Default account item renderer.
* @returns {JSX.Element}
*/
const accountRenderer = (item, { handleClick, modifiers, query }) => {
if (!modifiers.matchesPredicate) {
return null;
}
return (
<MenuItem
active={modifiers.active}
disabled={modifiers.disabled}
label={item.code}
key={item.id}
text={<MenuItemNestedText level={item.account_level} text={item.name} />}
onClick={handleClick}
/>
);
};
/**
* Accounts select field binded with Formik form.
* @returns {JSX.Element}
*/
function AccountsSelectRoot({
// #withDialogActions
openDialog,
// #ownProps
items,
allowCreate,
filterByParentTypes,
filterByTypes,
filterByNormal,
filterByRootTypes,
...restProps
}) {
// Filters accounts based on filter props.
const filteredAccounts = usePreprocessingAccounts(items, {
filterByParentTypes,
filterByTypes,
filterByNormal,
filterByRootTypes,
});
// Maybe inject new item props to select component.
const maybeCreateNewItemRenderer = allowCreate ? createNewItemRenderer : null;
const maybeCreateNewItemFromQuery = allowCreate
? createNewItemFromQuery
: null;
// Handles the create item click.
const handleCreateItemClick = () => {
openDialog(DialogsName.AccountForm);
};
return (
<FSelect
items={filteredAccounts}
textAccessor={'name'}
labelAccessor={'code'}
valueAccessor={'id'}
popoverProps={{ minimal: true, usePortal: true, inline: false }}
itemPredicate={accountPredicate}
itemRenderer={accountRenderer}
createNewItemRenderer={maybeCreateNewItemRenderer}
createNewItemFromQuery={maybeCreateNewItemFromQuery}
onCreateItemSelect={handleCreateItemClick}
{...restProps}
/>
);
}
export const AccountsSelect = R.compose(withDialogActions)(AccountsSelectRoot);

View File

@@ -1,177 +0,0 @@
// @ts-nocheck
import React, { useCallback, useState, useEffect, useMemo } from 'react';
import intl from 'react-intl-universal';
import classNames from 'classnames';
import { MenuItem, Button } from '@blueprintjs/core';
import { Select } from '@blueprintjs/select';
import * as R from 'ramda';
import { MenuItemNestedText, FormattedMessage as T } from '@/components';
import { nestedArrayToflatten, filterAccountsByQuery } from '@/utils';
import { CLASSES } from '@/constants/classes';
import { DialogsName } from '@/constants/dialogs';
import withDialogActions from '@/containers/Dialog/withDialogActions';
// Create new account renderer.
const createNewItemRenderer = (query, active, handleClick) => {
return (
<MenuItem
icon="add"
text={intl.get('list.create', { value: `"${query}"` })}
active={active}
onClick={handleClick}
/>
);
};
// Create new item from the given query string.
const createNewItemFromQuery = (name) => {
return {
name,
};
};
// Filters accounts items.
const filterAccountsPredicater = (query, account, _index, exactMatch) => {
const normalizedTitle = account.name.toLowerCase();
const normalizedQuery = query.toLowerCase();
if (exactMatch) {
return normalizedTitle === normalizedQuery;
} else {
return `${account.code} ${normalizedTitle}`.indexOf(normalizedQuery) >= 0;
}
};
/**
* Accounts select list.
*/
function AccountsSelectListRoot({
// #withDialogActions
openDialog,
// #ownProps
accounts,
initialAccountId,
selectedAccountId,
defaultSelectText = 'Select account',
onAccountSelected,
disabled = false,
popoverFill = false,
filterByParentTypes,
filterByTypes,
filterByNormal,
filterByRootTypes,
allowCreate,
buttonProps = {},
}) {
const flattenAccounts = useMemo(
() => nestedArrayToflatten(accounts),
[accounts],
);
// Filters accounts based on filter props.
const filteredAccounts = useMemo(() => {
let filteredAccounts = filterAccountsByQuery(flattenAccounts, {
filterByRootTypes,
filterByParentTypes,
filterByTypes,
filterByNormal,
});
return filteredAccounts;
}, [
flattenAccounts,
filterByRootTypes,
filterByParentTypes,
filterByTypes,
filterByNormal,
]);
// Find initial account object to set it as default account in initial render.
const initialAccount = useMemo(
() => filteredAccounts.find((a) => a.id === initialAccountId),
[initialAccountId, filteredAccounts],
);
// Select account item.
const [selectedAccount, setSelectedAccount] = useState(
initialAccount || null,
);
useEffect(() => {
if (typeof selectedAccountId !== 'undefined') {
const account = selectedAccountId
? filteredAccounts.find((a) => a.id === selectedAccountId)
: null;
setSelectedAccount(account);
}
}, [selectedAccountId, filteredAccounts, setSelectedAccount]);
// Account item of select accounts field.
const accountItem = useCallback((item, { handleClick, modifiers, query }) => {
return (
<MenuItem
text={<MenuItemNestedText level={item.level} text={item.name} />}
label={item.code}
key={item.id}
onClick={handleClick}
/>
);
}, []);
// Handle the account item select.
const handleAccountSelect = useCallback(
(account) => {
if (account.id) {
setSelectedAccount({ ...account });
onAccountSelected && onAccountSelected(account);
} else {
openDialog(DialogsName.AccountForm);
}
},
[setSelectedAccount, onAccountSelected, openDialog],
);
// Maybe inject new item props to select component.
const maybeCreateNewItemRenderer = allowCreate ? createNewItemRenderer : null;
const maybeCreateNewItemFromQuery = allowCreate
? createNewItemFromQuery
: null;
return (
<Select
items={filteredAccounts}
noResults={<MenuItem disabled={true} text={<T id={'no_accounts'} />} />}
itemRenderer={accountItem}
itemPredicate={filterAccountsPredicater}
popoverProps={{
minimal: true,
usePortal: !popoverFill,
inline: popoverFill,
}}
filterable={true}
onItemSelect={handleAccountSelect}
disabled={disabled}
className={classNames('form-group--select-list', {
[CLASSES.SELECT_LIST_FILL_POPOVER]: popoverFill,
})}
createNewItemRenderer={maybeCreateNewItemRenderer}
createNewItemFromQuery={maybeCreateNewItemFromQuery}
>
<Button
disabled={disabled}
text={selectedAccount ? selectedAccount.name : defaultSelectText}
{...buttonProps}
/>
</Select>
);
}
export const AccountsSelectList = R.compose(withDialogActions)(
AccountsSelectListRoot,
);

View File

@@ -1,49 +1,15 @@
// @ts-nocheck // @ts-nocheck
import React, { useCallback } from 'react'; import React from 'react';
import classNames from 'classnames'; import { FSelect } from '@/components/Forms';
import { ListSelect } from '@/components';
import { CLASSES } from '@/constants/classes';
export function AccountsTypesSelect({
accountsTypes,
selectedTypeId,
defaultSelectText = 'Select account type',
onTypeSelected,
disabled = false,
popoverFill = false,
...restProps
}) {
// Filters accounts types items.
const filterAccountTypeItems = (query, accountType, _index, exactMatch) => {
const normalizedTitle = accountType.label.toLowerCase();
const normalizedQuery = query.toLowerCase();
if (exactMatch) {
return normalizedTitle === normalizedQuery;
} else {
return normalizedTitle.indexOf(normalizedQuery) >= 0;
}
};
// Handle item selected.
const handleItemSelected = (accountType) => {
onTypeSelected && onTypeSelected(accountType);
};
export function AccountsTypesSelect({ ...props }) {
return ( return (
<ListSelect <FSelect
items={accountsTypes} valueAccessor={'key'}
selectedItemProp={'key'} labelAccessor={'label'}
selectedItem={selectedTypeId} textAccessor={'label'}
textProp={'label'} placeholder={'Select an account...'}
defaultText={defaultSelectText} {...props}
onItemSelect={handleItemSelected}
itemPredicate={filterAccountTypeItems}
disabled={disabled}
className={classNames('form-group--select-list', {
[CLASSES.SELECT_LIST_FILL_POPOVER]: popoverFill,
})}
{...restProps}
/> />
); );
} }

View File

@@ -0,0 +1,14 @@
// @ts-nocheck
import React from 'react';
// Filters accounts items.
export const accountPredicate = (query, account, _index, exactMatch) => {
const normalizedTitle = account.name.toLowerCase();
const normalizedQuery = query.toLowerCase();
if (exactMatch) {
return normalizedTitle === normalizedQuery;
} else {
return `${account.code} ${normalizedTitle}`.indexOf(normalizedQuery) >= 0;
}
};

View File

@@ -0,0 +1,36 @@
import { useMemo } from 'react';
import { filterAccountsByQuery, nestedArrayToflatten } from '@/utils';
interface PreprocessingAccountsOptions {
filterByRootTypes: string[];
filterByParentTypes: string[];
filterByTypes: string[];
filterByNormal: string[];
}
export const usePreprocessingAccounts = (
items: any,
{
filterByRootTypes,
filterByParentTypes,
filterByTypes,
filterByNormal,
}: PreprocessingAccountsOptions,
) => {
return useMemo(() => {
const flattenAccounts = nestedArrayToflatten(items);
const filteredAccounts = filterAccountsByQuery(flattenAccounts, {
filterByRootTypes,
filterByParentTypes,
filterByTypes,
filterByNormal,
});
return filteredAccounts;
}, [
items,
filterByRootTypes,
filterByParentTypes,
filterByTypes,
filterByNormal,
]);
};

View File

@@ -1,5 +1,4 @@
export * from './AccountMultiSelect'; export * from './AccountsSelect';
export * from './AccountsMultiSelect'; export * from './AccountsMultiSelect';
export * from './AccountsSelectList';
export * from './AccountsSuggestField'; export * from './AccountsSuggestField';
export * from './AccountsTypesSelect'; export * from './AccountsTypesSelect';

View File

@@ -77,11 +77,13 @@ export function BankAccount({
</BankAccountHeader> </BankAccountHeader>
<BankAccountMeta> <BankAccountMeta>
<BankAccountMetaLine {false && (
title={intl.get('cash_flow.label_account_transcations')} <BankAccountMetaLine
value={2} title={intl.get('cash_flow.transactions_for_review')}
className={clsx({ [Classes.SKELETON]: loading })} value={'0'}
/> className={clsx({ [Classes.SKELETON]: loading })}
/>
)}
<BankAccountMetaLine <BankAccountMetaLine
title={updatedBeforeText} title={updatedBeforeText}
className={clsx({ [Classes.SKELETON]: loading })} className={clsx({ [Classes.SKELETON]: loading })}

View File

@@ -2,7 +2,6 @@
import React from 'react'; import React from 'react';
import intl from 'react-intl-universal'; import intl from 'react-intl-universal';
import { MenuItem, Button } from '@blueprintjs/core';
import { FSelect } from '../Forms'; import { FSelect } from '../Forms';
/** /**
@@ -28,30 +27,6 @@ const currencyItemPredicate = (query, currency, _index, exactMatch) => {
} }
}; };
/**
* @param {*} currency
* @returns
*/
const currencyItemRenderer = (currency, { handleClick, modifiers, query }) => {
return (
<MenuItem
active={modifiers.active}
disabled={modifiers.disabled}
text={currency.currency_name}
label={currency.currency_code.toString()}
key={currency.id}
onClick={handleClick}
/>
);
};
const currencySelectProps = {
itemPredicate: currencyItemPredicate,
itemRenderer: currencyItemRenderer,
valueAccessor: 'currency_code',
labelAccessor: 'currency_code',
};
/** /**
* *
* @param {*} currencies * @param {*} currencies
@@ -60,18 +35,13 @@ const currencySelectProps = {
export function CurrencySelect({ currencies, ...rest }) { export function CurrencySelect({ currencies, ...rest }) {
return ( return (
<FSelect <FSelect
{...currencySelectProps} itemPredicate={currencyItemPredicate}
valueAccessor={'currency_code'}
textAccessor={'currency_name'}
labelAccessor={'currency_code'}
{...rest} {...rest}
items={currencies} items={currencies}
input={CurrnecySelectButton} placeholder={intl.get('select_currency_code')}
/> />
); );
} }
/**
* @param {*} label
* @returns
*/
function CurrnecySelectButton({ label }) {
return <Button text={label ? label : intl.get('select_currency_code')} />;
}

View File

@@ -1,4 +1,5 @@
// @ts-nocheck // @ts-nocheck
import React from 'react';
import { import {
FormGroup, FormGroup,
InputGroup, InputGroup,
@@ -9,8 +10,9 @@ import {
EditableText, EditableText,
TextArea, TextArea,
} from '@blueprintjs-formik/core'; } from '@blueprintjs-formik/core';
import { Select, MultiSelect } from '@blueprintjs-formik/select'; import { MultiSelect } from '@blueprintjs-formik/select';
import { DateInput } from '@blueprintjs-formik/datetime'; import { DateInput } from '@blueprintjs-formik/datetime';
import { FSelect } from './Select';
export { export {
FormGroup as FFormGroup, FormGroup as FFormGroup,
@@ -19,7 +21,7 @@ export {
Checkbox as FCheckbox, Checkbox as FCheckbox,
RadioGroup as FRadioGroup, RadioGroup as FRadioGroup,
Switch as FSwitch, Switch as FSwitch,
Select as FSelect, FSelect,
MultiSelect as FMultiSelect, MultiSelect as FMultiSelect,
EditableText as FEditableText, EditableText as FEditableText,
TextArea as FTextArea, TextArea as FTextArea,

View File

@@ -0,0 +1,58 @@
// @ts-nocheck
import React from 'react';
import { Button } from '@blueprintjs/core';
import { Select } from '@blueprintjs-formik/select';
import styled from 'styled-components';
import clsx from 'classnames';
export function FSelect({ ...props }) {
const input = ({ activeItem, text, label, value }) => {
return (
<SelectButton
text={text || props.placeholder || 'Select an item ...'}
disabled={props.disabled || false}
{...props.buttonProps}
className={clsx({ 'is-selected': !!text }, props.className)}
/>
);
};
return <Select input={input} {...props} fill={true} />;
}
const SelectButton = styled(Button)`
outline: none;
box-shadow: 0 0 0 transparent;
border: 1px solid #ced4da;
position: relative;
padding-right: 30px;
&:not(.is-selected):not([class*='bp3-intent-']):not(.bp3-minimal) {
color: #5c7080;
}
&:after {
content: '';
display: inline-block;
width: 0;
height: 0;
border-left: 4px solid transparent;
border-right: 4px solid transparent;
border-top: 5px solid #8d8d8d;
position: absolute;
right: 0;
top: 50%;
margin-top: -2px;
margin-right: 12px;
border-radius: 1px;
}
&:not([class*='bp3-intent-']) {
&,
&:hover {
background: #fff;
}
}
.bp3-intent-danger & {
border-color: #db3737;
}
`;

View File

@@ -1,32 +1,29 @@
// @ts-nocheck // @ts-nocheck
import React from 'react'; import React from 'react';
import classNames from 'classnames'; import { Form, useFormikContext } from 'formik';
import { Form, FastField, Field, ErrorMessage, useFormikContext } from 'formik'; import { Button, Classes, FormGroup, Intent } from '@blueprintjs/core';
import {
Button,
Classes,
FormGroup,
InputGroup,
Intent,
TextArea,
Checkbox,
} from '@blueprintjs/core';
import { import {
If, If,
FieldRequiredHint, FieldRequiredHint,
Hint, Hint,
AccountsSelectList, AccountsSelect,
AccountsTypesSelect, AccountsTypesSelect,
CurrencySelect, CurrencySelect,
FormattedMessage as T, FormattedMessage as T,
FFormGroup,
FInputGroup,
FCheckbox,
FTextArea,
} from '@/components'; } from '@/components';
import withAccounts from '@/containers/Accounts/withAccounts'; import withAccounts from '@/containers/Accounts/withAccounts';
import { inputIntent, compose } from '@/utils';
import { useAutofocus } from '@/hooks';
import { FOREIGN_CURRENCY_ACCOUNTS } from '@/constants/accountTypes'; import { FOREIGN_CURRENCY_ACCOUNTS } from '@/constants/accountTypes';
import { useAutofocus } from '@/hooks';
import { useAccountDialogContext } from './AccountDialogProvider'; import { useAccountDialogContext } from './AccountDialogProvider';
import { parentAccountShouldUpdate } from './utils'; import { parentAccountShouldUpdate } from './utils';
import { compose } from '@/utils';
/** /**
* Account form dialogs fields. * Account form dialogs fields.
@@ -36,7 +33,7 @@ function AccountFormDialogFields({
onClose, onClose,
action, action,
}) { }) {
const { values, isSubmitting } = useFormikContext(); const { values, isSubmitting, setFieldValue } = useFormikContext();
const accountNameFieldRef = useAutofocus(); const accountNameFieldRef = useAutofocus();
// Account form context. // Account form context.
@@ -46,146 +43,120 @@ function AccountFormDialogFields({
return ( return (
<Form> <Form>
<div className={Classes.DIALOG_BODY}> <div className={Classes.DIALOG_BODY}>
<Field name={'account_type'}> <FFormGroup
{({ form, field: { value }, meta: { error, touched } }) => ( inline={true}
<FormGroup label={<T id={'account_type'} />}
label={<T id={'account_type'} />} labelInfo={<FieldRequiredHint />}
labelInfo={<FieldRequiredHint />} name={'account_type'}
className={classNames('form-group--account-type', Classes.FILL)} fastField={true}
inline={true}
helperText={<ErrorMessage name="account_type" />}
intent={inputIntent({ error, touched })}
>
<AccountsTypesSelect
accountsTypes={accountsTypes}
selectedTypeId={value}
defaultSelectText={<T id={'select_account_type'} />}
onTypeSelected={(accountType) => {
form.setFieldValue('account_type', accountType.key);
form.setFieldValue('currency_code', '');
}}
disabled={fieldsDisabled.accountType}
popoverProps={{ minimal: true }}
popoverFill={true}
/>
</FormGroup>
)}
</Field>
<FastField name={'name'}>
{({ field, meta: { error, touched } }) => (
<FormGroup
label={<T id={'account_name'} />}
labelInfo={<FieldRequiredHint />}
className={'form-group--account-name'}
intent={inputIntent({ error, touched })}
helperText={<ErrorMessage name="name" />}
inline={true}
>
<InputGroup
medium={true}
inputRef={(ref) => (accountNameFieldRef.current = ref)}
{...field}
/>
</FormGroup>
)}
</FastField>
<FastField name={'code'}>
{({ form, field, meta: { error, touched } }) => (
<FormGroup
label={<T id={'account_code'} />}
className={'form-group--account-code'}
intent={inputIntent({ error, touched })}
helperText={<ErrorMessage name="code" />}
inline={true}
labelInfo={<Hint content={<T id="account_code_hint" />} />}
>
<InputGroup medium={true} {...field} />
</FormGroup>
)}
</FastField>
<Field name={'subaccount'} type={'checkbox'}>
{({ field, meta: { error, touched } }) => (
<FormGroup
label={' '}
className={classNames('form-group--subaccount')}
intent={inputIntent({ error, touched })}
inline={true}
>
<Checkbox
inline={true}
label={<T id={'sub_account'} />}
name={'subaccount'}
{...field}
/>
</FormGroup>
)}
</Field>
<FastField
name={'parent_account_id'}
shouldUpdate={parentAccountShouldUpdate}
> >
{({ <AccountsTypesSelect
form: { values, setFieldValue }, name={'account_type'}
field: { value }, items={accountsTypes}
meta: { error, touched }, onItemSelect={(accountType) => {
}) => ( setFieldValue('account_type', accountType.key);
<FormGroup setFieldValue('currency_code', '');
label={<T id={'parent_account'} />} }}
className={classNames('form-group--parent-account', Classes.FILL)} disabled={fieldsDisabled.accountType}
inline={true} popoverProps={{ minimal: true }}
intent={inputIntent({ error, touched })} fastField={true}
helperText={<ErrorMessage name="parent_account_id" />} fill={true}
> />
<AccountsSelectList </FFormGroup>
accounts={accounts}
onAccountSelected={(account) => { <FFormGroup
setFieldValue('parent_account_id', account.id); name={'name'}
}} label={<T id={'account_name'} />}
defaultSelectText={<T id={'select_parent_account'} />} labelInfo={<FieldRequiredHint />}
selectedAccountId={value} inline={true}
popoverFill={true} fastField={true}
filterByTypes={values.account_type} >
disabled={!values.subaccount} <FInputGroup
/> medium={true}
</FormGroup> inputRef={(ref) => (accountNameFieldRef.current = ref)}
)} name={'name'}
</FastField> fastField={true}
/>
</FFormGroup>
<FFormGroup
label={<T id={'account_code'} />}
name={'code'}
labelInfo={<Hint content={<T id="account_code_hint" />} />}
inline={true}
fastField={true}
>
<FInputGroup medium={true} name={'code'} fastField={true} />
</FFormGroup>
<FFormGroup
label={' '}
name={'subaccount'}
inline={true}
fastField={true}
>
<FCheckbox
inline={true}
label={<T id={'sub_account'} />}
name={'subaccount'}
fastField={true}
/>
</FFormGroup>
{values.subaccount && (
<FFormGroup
name={'parent_account_id'}
shouldUpdate={parentAccountShouldUpdate}
label={<T id={'parent_account'} />}
inline={true}
fastField={true}
>
<AccountsSelect
name={'parent_account_id'}
items={accounts}
shouldUpdate={parentAccountShouldUpdate}
placeholder={<T id={'select_parent_account'} />}
filterByTypes={values.account_type}
buttonProps={{ disabled: !values.subaccount }}
fastField={true}
fill={true}
allowCreate={true}
/>
</FFormGroup>
)}
<If condition={FOREIGN_CURRENCY_ACCOUNTS.includes(values.account_type)}> <If condition={FOREIGN_CURRENCY_ACCOUNTS.includes(values.account_type)}>
{/*------------ Currency -----------*/} {/*------------ Currency -----------*/}
<FastField name={'currency_code'}> <FFormGroup
{({ form, field: { value }, meta: { error, touched } }) => ( label={<T id={'currency'} />}
<FormGroup name={'currency_code'}
label={<T id={'currency'} />} inline={true}
className={classNames('form-group--select-list', Classes.FILL)} fastField={true}
inline={true} >
> <CurrencySelect
<CurrencySelect name={'currency_code'}
name={'currency_code'} currencies={currencies}
currencies={currencies} popoverProps={{ minimal: true }}
popoverProps={{ minimal: true }} fastField={true}
/> fill={true}
</FormGroup> />
)} </FFormGroup>
</FastField>
</If> </If>
<FastField name={'description'}>
{({ field, meta: { error, touched } }) => ( <FFormGroup
<FormGroup label={<T id={'description'} />}
label={<T id={'description'} />} name={'description'}
className={'form-group--description'} inline={true}
intent={inputIntent({ error, touched })} fastField={true}
helperText={<ErrorMessage name={'description'} />} >
inline={true} <FTextArea
> name={'description'}
<TextArea growVertically={true} height={280} {...field} /> growVertically={true}
</FormGroup> height={280}
)} fill={true}
</FastField> fastField={true}
/>
</FFormGroup>
</div> </div>
<div className={Classes.DIALOG_FOOTER}> <div className={Classes.DIALOG_FOOTER}>

View File

@@ -16,7 +16,8 @@ import { customersFieldShouldUpdate, accountsFieldShouldUpdate } from './utils';
import { import {
CurrencySelectList, CurrencySelectList,
CustomerSelectField, CustomerSelectField,
AccountsSelectList, FFormGroup,
AccountsSelect,
FieldRequiredHint, FieldRequiredHint,
Hint, Hint,
} from '@/components'; } from '@/components';
@@ -54,37 +55,26 @@ export default function ExpenseFormHeader() {
)} )}
</FastField> </FastField>
<FastField <FFormGroup
name={'payment_account_id'} name={'payment_account_id'}
accounts={accounts} items={accounts}
label={<T id={'payment_account'} />}
labelInfo={<FieldRequiredHint />}
inline={true}
fastField={true}
shouldUpdate={accountsFieldShouldUpdate} shouldUpdate={accountsFieldShouldUpdate}
> >
{({ form, field: { value }, meta: { error, touched } }) => ( <AccountsSelect
<FormGroup name={'payment_account_id'}
label={<T id={'payment_account'} />} items={accounts}
className={classNames( placeholder={<T id={'select_payment_account'} />}
'form-group--payment_account', filterByParentTypes={[ACCOUNT_PARENT_TYPE.CURRENT_ASSET]}
'form-group--select-list', allowCreate={true}
Classes.FILL, fastField={true}
)} shouldUpdate={accountsFieldShouldUpdate}
labelInfo={<FieldRequiredHint />} fill={true}
intent={inputIntent({ error, touched })} />
helperText={<ErrorMessage name={'payment_account_id'} />} </FFormGroup>
inline={true}
>
<AccountsSelectList
accounts={accounts}
onAccountSelected={(account) => {
form.setFieldValue('payment_account_id', account.id);
}}
defaultSelectText={<T id={'select_payment_account'} />}
selectedAccountId={value}
filterByParentTypes={[ACCOUNT_PARENT_TYPE.CURRENT_ASSET]}
allowCreate={true}
/>
</FormGroup>
)}
</FastField>
<FastField name={'currency_code'}> <FastField name={'currency_code'}>
{({ form, field: { value }, meta: { error, touched } }) => ( {({ form, field: { value }, meta: { error, touched } }) => (

View File

@@ -114,7 +114,7 @@ export const customersFieldShouldUpdate = (newProps, oldProps) => {
*/ */
export const accountsFieldShouldUpdate = (newProps, oldProps) => { export const accountsFieldShouldUpdate = (newProps, oldProps) => {
return ( return (
newProps.accounts !== oldProps.accounts || newProps.items !== oldProps.items ||
defaultFastFieldShouldUpdate(newProps, oldProps) defaultFastFieldShouldUpdate(newProps, oldProps)
); );
}; };

View File

@@ -3,7 +3,7 @@ import React from 'react';
import { Classes } from '@blueprintjs/core'; import { Classes } from '@blueprintjs/core';
import { import {
AccountMultiSelect, AccountsMultiSelect,
Row, Row,
Col, Col,
FormattedMessage as T, FormattedMessage as T,
@@ -54,7 +54,7 @@ function GLHeaderGeneralPaneContent() {
name={'accountsIds'} name={'accountsIds'}
className={Classes.FILL} className={Classes.FILL}
> >
<AccountMultiSelect name="accountsIds" accounts={accounts} /> <AccountsMultiSelect name="accountsIds" items={accounts} />
</FFormGroup> </FFormGroup>
</Col> </Col>
</Row> </Row>

View File

@@ -9,15 +9,15 @@ import {
ControlGroup, ControlGroup,
} from '@blueprintjs/core'; } from '@blueprintjs/core';
import { import {
AccountsSelectList, AccountsSelect,
MoneyInputGroup, MoneyInputGroup,
Col, Col,
Row, Row,
Hint, Hint,
InputPrependText, InputPrependText,
FFormGroup,
} from '@/components'; } from '@/components';
import { FormattedMessage as T } from '@/components'; import { FormattedMessage as T } from '@/components';
import classNames from 'classnames';
import { useItemFormContext } from './ItemFormProvider'; import { useItemFormContext } from './ItemFormProvider';
import withCurrentOrganization from '@/containers/Organization/withCurrentOrganization'; import withCurrentOrganization from '@/containers/Organization/withCurrentOrganization';
@@ -91,42 +91,29 @@ function ItemFormBody({ organization: { base_currency } }) {
</FastField> </FastField>
{/*------------- Selling account ------------- */} {/*------------- Selling account ------------- */}
<FastField <FFormGroup
label={<T id={'account'} />}
name={'sell_account_id'} name={'sell_account_id'}
labelInfo={
<Hint content={<T id={'item.field.sell_account.hint'} />} />
}
inline={true}
items={accounts}
sellable={values.sellable} sellable={values.sellable}
accounts={accounts}
shouldUpdate={sellAccountFieldShouldUpdate} shouldUpdate={sellAccountFieldShouldUpdate}
fastField={true}
> >
{({ form, field: { value }, meta: { error, touched } }) => ( <AccountsSelect
<FormGroup name={'sell_account_id'}
label={<T id={'account'} />} items={accounts}
labelInfo={ placeholder={<T id={'select_account'} />}
<Hint content={<T id={'item.field.sell_account.hint'} />} /> disabled={!values.sellable}
} filterByParentTypes={[ACCOUNT_PARENT_TYPE.INCOME]}
inline={true} fill={true}
intent={inputIntent({ error, touched })} allowCreate={true}
helperText={<ErrorMessage name="sell_account_id" />} fastField={true}
className={classNames( />
'form-group--sell-account', </FFormGroup>
'form-group--select-list',
Classes.FILL,
)}
>
<AccountsSelectList
accounts={accounts}
onAccountSelected={(account) => {
form.setFieldValue('sell_account_id', account.id);
}}
defaultSelectText={<T id={'select_account'} />}
selectedAccountId={value}
disabled={!form.values.sellable}
filterByParentTypes={[ACCOUNT_PARENT_TYPE.INCOME]}
popoverFill={true}
allowCreate={true}
/>
</FormGroup>
)}
</FastField>
<FastField <FastField
name={'sell_description'} name={'sell_description'}
@@ -200,42 +187,31 @@ function ItemFormBody({ organization: { base_currency } }) {
</FastField> </FastField>
{/*------------- Cost account ------------- */} {/*------------- Cost account ------------- */}
<FastField <FFormGroup
name={'cost_account_id'} name={'cost_account_id'}
purchasable={values.purchasable} purchasable={values.purchasable}
accounts={accounts} items={accounts}
shouldUpdate={costAccountFieldShouldUpdate} shouldUpdate={costAccountFieldShouldUpdate}
label={<T id={'account'} />}
labelInfo={
<Hint content={<T id={'item.field.cost_account.hint'} />} />
}
inline={true}
fastField={true}
> >
{({ form, field: { value }, meta: { error, touched } }) => ( <AccountsSelect
<FormGroup name={'cost_account_id'}
label={<T id={'account'} />} items={accounts}
labelInfo={ placeholder={<T id={'select_account'} />}
<Hint content={<T id={'item.field.cost_account.hint'} />} /> filterByParentTypes={[ACCOUNT_PARENT_TYPE.EXPENSE]}
} popoverFill={true}
inline={true} allowCreate={true}
intent={inputIntent({ error, touched })} fastField={true}
helperText={<ErrorMessage name="cost_account_id" />} disabled={!values.purchasable}
className={classNames( purchasable={values.purchasable}
'form-group--cost-account', shouldUpdate={costAccountFieldShouldUpdate}
'form-group--select-list', />
Classes.FILL, </FFormGroup>
)}
>
<AccountsSelectList
accounts={accounts}
onAccountSelected={(account) => {
form.setFieldValue('cost_account_id', account.id);
}}
defaultSelectText={<T id={'select_account'} />}
selectedAccountId={value}
disabled={!form.values.purchasable}
filterByParentTypes={[ACCOUNT_PARENT_TYPE.EXPENSE]}
popoverFill={true}
allowCreate={true}
/>
</FormGroup>
)}
</FastField>
<FastField <FastField
name={'purchase_description'} name={'purchase_description'}

View File

@@ -1,21 +1,18 @@
// @ts-nocheck // @ts-nocheck
import React from 'react'; import React from 'react';
import { FastField, ErrorMessage } from 'formik';
import { FormGroup } from '@blueprintjs/core';
import { CLASSES } from '@/constants/classes';
import { import {
AccountsSelectList, AccountsSelect,
FFormGroup,
FormattedMessage as T, FormattedMessage as T,
Col, Col,
Row, Row,
} from '@/components'; } from '@/components';
import classNames from 'classnames';
import withCurrentOrganization from '@/containers/Organization/withCurrentOrganization';
import withCurrentOrganization from '@/containers/Organization/withCurrentOrganization';
import { accountsFieldShouldUpdate } from './utils'; import { accountsFieldShouldUpdate } from './utils';
import { compose, inputIntent } from '@/utils';
import { ACCOUNT_TYPE } from '@/constants/accountTypes'; import { ACCOUNT_TYPE } from '@/constants/accountTypes';
import { useItemFormContext } from './ItemFormProvider'; import { useItemFormContext } from './ItemFormProvider';
import { compose } from '@/utils';
/** /**
* Item form inventory sections. * Item form inventory sections.
@@ -31,36 +28,24 @@ function ItemFormInventorySection({ organization: { base_currency } }) {
<Row> <Row>
<Col xs={6}> <Col xs={6}>
{/*------------- Inventory account ------------- */} {/*------------- Inventory Account ------------- */}
<FastField <FFormGroup
label={<T id={'inventory_account'} />}
name={'inventory_account_id'} name={'inventory_account_id'}
accounts={accounts} items={accounts}
fastField={true}
shouldUpdate={accountsFieldShouldUpdate} shouldUpdate={accountsFieldShouldUpdate}
inline={true}
> >
{({ form, field: { value }, meta: { touched, error } }) => ( <AccountsSelect
<FormGroup name={'inventory_account_id'}
label={<T id={'inventory_account'} />} items={accounts}
inline={true} placeholder={<T id={'select_account'} />}
intent={inputIntent({ error, touched })} filterByTypes={[ACCOUNT_TYPE.INVENTORY]}
helperText={<ErrorMessage name="inventory_account_id" />} fastField={true}
className={classNames( shouldUpdate={accountsFieldShouldUpdate}
'form-group--item-inventory_account', />
'form-group--select-list', </FFormGroup>
CLASSES.FILL,
)}
>
<AccountsSelectList
accounts={accounts}
onAccountSelected={(account) => {
form.setFieldValue('inventory_account_id', account.id);
}}
defaultSelectText={<T id={'select_account'} />}
selectedAccountId={value}
filterByTypes={[ACCOUNT_TYPE.INVENTORY]}
/>
</FormGroup>
)}
</FastField>
</Col> </Col>
</Row> </Row>
</div> </div>

View File

@@ -119,7 +119,7 @@ export const handleDeleteErrors = (errors) => {
*/ */
export const accountsFieldShouldUpdate = (newProps, oldProps) => { export const accountsFieldShouldUpdate = (newProps, oldProps) => {
return ( return (
newProps.accounts !== oldProps.accounts || newProps.items !== oldProps.items ||
defaultFastFieldShouldUpdate(newProps, oldProps) defaultFastFieldShouldUpdate(newProps, oldProps)
); );
}; };
@@ -149,7 +149,7 @@ export const sellPriceFieldShouldUpdate = (newProps, oldProps) => {
*/ */
export const sellAccountFieldShouldUpdate = (newProps, oldProps) => { export const sellAccountFieldShouldUpdate = (newProps, oldProps) => {
return ( return (
newProps.accounts !== oldProps.accounts || newProps.items !== oldProps.items ||
newProps.sellable !== oldProps.sellable || newProps.sellable !== oldProps.sellable ||
defaultFastFieldShouldUpdate(newProps, oldProps) defaultFastFieldShouldUpdate(newProps, oldProps)
); );

View File

@@ -2,6 +2,7 @@
import React from 'react'; import React from 'react';
import intl from 'react-intl-universal'; import intl from 'react-intl-universal';
import { Form, FastField, useFormikContext } from 'formik'; import { Form, FastField, useFormikContext } from 'formik';
import styled from 'styled-components';
import { import {
FormGroup, FormGroup,
RadioGroup, RadioGroup,
@@ -14,13 +15,13 @@ import { useHistory } from 'react-router-dom';
import { import {
FormattedMessage as T, FormattedMessage as T,
AccountsSelectList, AccountsSelect,
FieldRequiredHint, FieldRequiredHint,
CardFooterActions, CardFooterActions,
FFormGroup,
} from '@/components'; } from '@/components';
import { handleStringChange, inputIntent } from '@/utils'; import { handleStringChange, inputIntent } from '@/utils';
import { ACCOUNT_TYPE } from '@/constants/accountTypes'; import { ACCOUNT_PARENT_TYPE, ACCOUNT_TYPE } from '@/constants/accountTypes';
import { useAccountantFormContext } from './AccountantFormProvider'; import { useAccountantFormContext } from './AccountantFormProvider';
/** /**
@@ -28,6 +29,7 @@ import { useAccountantFormContext } from './AccountantFormProvider';
*/ */
export default function AccountantForm() { export default function AccountantForm() {
const history = useHistory(); const history = useHistory();
const { accounts } = useAccountantFormContext();
const { isSubmitting } = useFormikContext(); const { isSubmitting } = useFormikContext();
@@ -35,8 +37,6 @@ export default function AccountantForm() {
history.go(-1); history.go(-1);
}; };
const { accounts } = useAccountantFormContext();
return ( return (
<Form> <Form>
{/* ----------- Accounts ----------- */} {/* ----------- Accounts ----------- */}
@@ -48,7 +48,7 @@ export default function AccountantForm() {
} }
className={'accounts-checkbox'} className={'accounts-checkbox'}
> >
{/*------------ account code required -----------*/} {/*------------ Account code (required) -----------*/}
<FastField name={'account_code_required'} type={'checkbox'}> <FastField name={'account_code_required'} type={'checkbox'}>
{({ field }) => ( {({ field }) => (
<FormGroup inline={true}> <FormGroup inline={true}>
@@ -65,7 +65,8 @@ export default function AccountantForm() {
</FormGroup> </FormGroup>
)} )}
</FastField> </FastField>
{/*------------ account code unique -----------*/}
{/*------------ Account code (unique) -----------*/}
<FastField name={'account_code_unique'} type={'checkbox'}> <FastField name={'account_code_unique'} type={'checkbox'}>
{({ field }) => ( {({ field }) => (
<FormGroup inline={true}> <FormGroup inline={true}>
@@ -85,6 +86,7 @@ export default function AccountantForm() {
)} )}
</FastField> </FastField>
</FormGroup> </FormGroup>
{/* ----------- Accounting basis ----------- */} {/* ----------- Accounting basis ----------- */}
<FastField name={'accounting_basis'}> <FastField name={'accounting_basis'}>
{({ {({
@@ -116,120 +118,93 @@ export default function AccountantForm() {
</FastField> </FastField>
{/* ----------- Deposit customer account ----------- */} {/* ----------- Deposit customer account ----------- */}
<FastField name={'preferred_deposit_account'}> <AccountantFormGroup
{({ name={'preferred_deposit_account'}
form: { values, setFieldValue }, label={
field: { value }, <strong>
meta: { error, touched }, <T id={'deposit_customer_account'} />
}) => ( </strong>
<FormGroup }
label={ helperText={
<strong> <T
<T id={'deposit_customer_account'} /> id={
</strong> 'select_a_preferred_account_to_deposit_into_it_after_customer_make_payment'
} }
helperText={ />
<T }
id={ labelInfo={<FieldRequiredHint />}
'select_a_preferred_account_to_deposit_into_it_after_customer_make_payment' fastField={true}
} >
/> <AccountsSelect
} name={'preferred_deposit_account'}
labelInfo={<FieldRequiredHint />} items={accounts}
intent={inputIntent({ error, touched })} placeholder={<T id={'select_payment_account'} />}
> filterByTypes={[
<AccountsSelectList ACCOUNT_TYPE.CASH,
accounts={accounts} ACCOUNT_TYPE.BANK,
onAccountSelected={({ id }) => { ACCOUNT_TYPE.OTHER_CURRENT_ASSET,
setFieldValue('preferred_deposit_account', id); ]}
}} fastField={true}
selectedAccountId={value} />
defaultSelectText={<T id={'select_payment_account'} />} </AccountantFormGroup>
filterByTypes={[
ACCOUNT_TYPE.CASH,
ACCOUNT_TYPE.BANK,
ACCOUNT_TYPE.OTHER_CURRENT_ASSET,
]}
/>
</FormGroup>
)}
</FastField>
{/* ----------- Withdrawal vendor account ----------- */} {/* ----------- Withdrawal vendor account ----------- */}
<FastField name={'withdrawal_account'}> <AccountantFormGroup
{({ name={'withdrawal_account'}
form: { values, setFieldValue }, label={
field: { value }, <strong>
meta: { error, touched }, <T id={'withdrawal_vendor_account'} />
}) => ( </strong>
<FormGroup }
label={ helperText={
<strong> <T
<T id={'withdrawal_vendor_account'} /> id={
</strong> 'select_a_preferred_account_to_deposit_into_it_after_customer_make_payment'
} }
helperText={ />
<T }
id={ labelInfo={<FieldRequiredHint />}
'select_a_preferred_account_to_deposit_into_it_after_customer_make_payment' fastField={true}
} >
/> <AccountsSelect
} name={'withdrawal_account'}
labelInfo={<FieldRequiredHint />} items={accounts}
intent={inputIntent({ error, touched })} placeholder={<T id={'select_payment_account'} />}
> filterByTypes={[
<AccountsSelectList ACCOUNT_TYPE.CASH,
accounts={accounts} ACCOUNT_TYPE.BANK,
onAccountSelected={({ id }) => { ACCOUNT_TYPE.OTHER_CURRENT_ASSET,
setFieldValue('withdrawal_account', id); ]}
}} fastField={true}
selectedAccountId={value} />
defaultSelectText={<T id={'select_payment_account'} />} </AccountantFormGroup>
filterByTypes={[
ACCOUNT_TYPE.CASH,
ACCOUNT_TYPE.BANK,
ACCOUNT_TYPE.OTHER_CURRENT_ASSET,
]}
/>
</FormGroup>
)}
</FastField>
{/* ----------- Withdrawal customer account ----------- */} {/* ----------- Withdrawal customer account ----------- */}
<FastField name={'preferred_advance_deposit'}> <AccountantFormGroup
{({ name={'preferred_advance_deposit'}
form: { values, setFieldValue }, label={
field: { value }, <strong>
meta: { error, touched }, <T id={'customer_advance_deposit'} />
}) => ( </strong>
<FormGroup }
label={ helperText={
<strong> <T
<T id={'customer_advance_deposit'} /> id={
</strong> 'select_a_preferred_account_to_deposit_into_it_vendor_advanced_deposits'
} }
helperText={ />
<T }
id={ labelInfo={<FieldRequiredHint />}
'select_a_preferred_account_to_deposit_into_it_vendor_advanced_deposits' fastField={true}
} >
/> <AccountsSelect
} name={'preferred_advance_deposit'}
labelInfo={<FieldRequiredHint />} items={accounts}
intent={inputIntent({ error, touched })} placeholder={<T id={'select_payment_account'} />}
> filterByParentTypes={[ACCOUNT_PARENT_TYPE.CURRENT_ASSET]}
<AccountsSelectList fastField={true}
accounts={accounts} />
onAccountSelected={({ id }) => { </AccountantFormGroup>
setFieldValue('preferred_advance_deposit', id);
}}
selectedAccountId={value}
defaultSelectText={<T id={'select_payment_account'} />}
// filterByParentTypes={[ACCOUNT_PARENT_TYPE.CURRENT_ASSET]}
/>
</FormGroup>
)}
</FastField>
<CardFooterActions> <CardFooterActions>
<Button intent={Intent.PRIMARY} loading={isSubmitting} type="submit"> <Button intent={Intent.PRIMARY} loading={isSubmitting} type="submit">
@@ -242,3 +217,7 @@ export default function AccountantForm() {
</Form> </Form>
); );
} }
const AccountantFormGroup = styled(FFormGroup)`
width: 450px;
`;

View File

@@ -1,15 +1,15 @@
// @ts-nocheck // @ts-nocheck
import React from 'react'; import React from 'react';
import { Form, FastField, useFormikContext } from 'formik'; import { Form, useFormikContext } from 'formik';
import { FormGroup, Button, Intent } from '@blueprintjs/core'; import { FormGroup, Button, Intent } from '@blueprintjs/core';
import { useHistory } from 'react-router-dom'; import { useHistory } from 'react-router-dom';
import { import {
AccountsSelectList, AccountsSelect,
FieldRequiredHint, FieldRequiredHint,
FormattedMessage as T, FormattedMessage as T,
CardFooterActions FFormGroup,
CardFooterActions,
} from '@/components'; } from '@/components';
import { inputIntent } from '@/utils';
import { ACCOUNT_PARENT_TYPE, ACCOUNT_TYPE } from '@/constants/accountTypes'; import { ACCOUNT_PARENT_TYPE, ACCOUNT_TYPE } from '@/constants/accountTypes';
import { useItemPreferencesFormContext } from './ItemPreferencesFormProvider'; import { useItemPreferencesFormContext } from './ItemPreferencesFormProvider';
@@ -29,113 +29,83 @@ export default function ItemForm() {
return ( return (
<Form> <Form>
{/* ----------- preferred sell account ----------- */} {/* ----------- Preferred Sell Account ----------- */}
<FastField name={'preferred_sell_account'}> <FormGroup
{({ name={'preferred_sell_account'}
form: { values, setFieldValue }, label={
field: { value }, <strong>
meta: { error, touched }, <T id={'preferred_sell_account'} />
}) => ( </strong>
<FormGroup }
label={ helperText={
<strong> <T
<T id={'preferred_sell_account'} /> id={
</strong> 'select_a_preferred_account_to_deposit_into_it_after_customer_make_payment'
} }
helperText={ />
<T }
id={ labelInfo={<FieldRequiredHint />}
'select_a_preferred_account_to_deposit_into_it_after_customer_make_payment' fastField={true}
} >
/> <AccountsSelect
} name={'preferred_sell_account'}
labelInfo={<FieldRequiredHint />} items={accounts}
intent={inputIntent({ error, touched })} placeholder={<T id={'select_payment_account'} />}
> filterByParentTypes={[ACCOUNT_PARENT_TYPE.INCOME]}
<AccountsSelectList />
accounts={accounts} </FormGroup>
onAccountSelected={({ id }) => {
setFieldValue('preferred_sell_account', id);
}}
selectedAccountId={value}
defaultSelectText={<T id={'select_payment_account'} />}
filterByParentTypes={[ACCOUNT_PARENT_TYPE.INCOME]}
/>
</FormGroup>
)}
</FastField>
{/* ----------- preferred cost account ----------- */} {/* ----------- Preferred Cost Account ----------- */}
<FastField name={'preferred_cost_account'}> <FFormGroup
{({ name={'preferred_cost_account'}
form: { values, setFieldValue }, label={
field: { value }, <strong>
meta: { error, touched }, <T id={'preferred_cost_account'} />
}) => ( </strong>
<FormGroup }
label={ helperText={
<strong> <T
<T id={'preferred_cost_account'} /> id={
</strong> 'select_a_preferred_account_to_deposit_into_it_after_customer_make_payment'
} }
helperText={ />
<T }
id={ labelInfo={<FieldRequiredHint />}
'select_a_preferred_account_to_deposit_into_it_after_customer_make_payment' fastField={true}
} >
/> <AccountsSelect
} name={'preferred_cost_account'}
labelInfo={<FieldRequiredHint />} items={accounts}
intent={inputIntent({ error, touched })} placeholder={<T id={'select_payment_account'} />}
> filterByParentTypes={[ACCOUNT_PARENT_TYPE.EXPENSE]}
<AccountsSelectList />
accounts={accounts} </FFormGroup>
onAccountSelected={({ id }) => {
setFieldValue('preferred_cost_account', id);
}}
selectedAccountId={value}
defaultSelectText={<T id={'select_payment_account'} />}
filterByParentTypes={[ACCOUNT_PARENT_TYPE.EXPENSE]}
/>
</FormGroup>
)}
</FastField>
{/* ----------- preferred inventory account ----------- */} {/* ----------- Preferred Inventory Account ----------- */}
<FastField name={'preferred_inventory_account'}> <FFormGroup
{({ name={'preferred_inventory_account'}
form: { values, setFieldValue }, label={
field: { value }, <strong>
meta: { error, touched }, <T id={'preferred_inventory_account'} />
}) => ( </strong>
<FormGroup }
label={ helperText={
<strong> <T
<T id={'preferred_inventory_account'} /> id={
</strong> 'select_a_preferred_account_to_deposit_into_it_vendor_advanced_deposits'
} }
helperText={ />
<T }
id={ labelInfo={<FieldRequiredHint />}
'select_a_preferred_account_to_deposit_into_it_vendor_advanced_deposits' fastField={true}
} >
/> <AccountsSelect
} name={'preferred_inventory_account'}
labelInfo={<FieldRequiredHint />} items={accounts}
intent={inputIntent({ error, touched })} placeholder={<T id={'select_payment_account'} />}
> filterByTypes={[ACCOUNT_TYPE.INVENTORY]}
<AccountsSelectList />
accounts={accounts} </FFormGroup>
onAccountSelected={({ id }) => {
setFieldValue('preferred_inventory_account', id);
}}
selectedAccountId={value}
defaultSelectText={<T id={'select_payment_account'} />}
filterByTypes={[ACCOUNT_TYPE.INVENTORY]}
/>
</FormGroup>
)}
</FastField>
<CardFooterActions> <CardFooterActions>
<Button intent={Intent.PRIMARY} loading={isSubmitting} type="submit"> <Button intent={Intent.PRIMARY} loading={isSubmitting} type="submit">

View File

@@ -18,7 +18,7 @@ import { CLASSES } from '@/constants/classes';
import { import {
FFormGroup, FFormGroup,
AccountsSelectList, AccountsSelect,
VendorSelectField, VendorSelectField,
FieldRequiredHint, FieldRequiredHint,
InputPrependText, InputPrependText,
@@ -211,41 +211,30 @@ function PaymentMadeFormHeaderFields({ organization: { base_currency } }) {
</FastField> </FastField>
{/* ------------ Payment account ------------ */} {/* ------------ Payment account ------------ */}
<FastField <FFormGroup
name={'payment_account_id'} name={'payment_account_id'}
accounts={accounts} label={<T id={'payment_account'} />}
labelInfo={<FieldRequiredHint />}
items={accounts}
shouldUpdate={accountsFieldShouldUpdate} shouldUpdate={accountsFieldShouldUpdate}
inline={true}
fastField={true}
> >
{({ form, field: { value }, meta: { error, touched } }) => ( <AccountsSelect
<FormGroup name={'payment_account_id'}
label={<T id={'payment_account'} />} items={accounts}
className={classNames( placeholder={<T id={'select_payment_account'} />}
'form-group--payment_account_id', labelInfo={<FieldRequiredHint />}
'form-group--select-list', filterByTypes={[
Classes.FILL, ACCOUNT_TYPE.CASH,
)} ACCOUNT_TYPE.BANK,
inline={true} ACCOUNT_TYPE.OTHER_CURRENT_ASSET,
labelInfo={<FieldRequiredHint />} ]}
intent={inputIntent({ error, touched })} shouldUpdate={accountsFieldShouldUpdate}
helperText={<ErrorMessage name={'payment_account_id'} />} fastField={true}
> fill={true}
<AccountsSelectList />
accounts={accounts} </FFormGroup>
labelInfo={<FieldRequiredHint />}
onAccountSelected={(account) => {
form.setFieldValue('payment_account_id', account.id);
}}
defaultSelectText={<T id={'select_payment_account'} />}
selectedAccountId={value}
filterByTypes={[
ACCOUNT_TYPE.CASH,
ACCOUNT_TYPE.BANK,
ACCOUNT_TYPE.OTHER_CURRENT_ASSET,
]}
/>
</FormGroup>
)}
</FastField>
{/* ------------ Reference ------------ */} {/* ------------ Reference ------------ */}
<FastField name={'reference'}> <FastField name={'reference'}>

View File

@@ -84,7 +84,7 @@ export const vendorsFieldShouldUpdate = (newProps, oldProps) => {
*/ */
export const accountsFieldShouldUpdate = (newProps, oldProps) => { export const accountsFieldShouldUpdate = (newProps, oldProps) => {
return ( return (
newProps.accounts !== oldProps.accounts || newProps.items !== oldProps.items ||
defaultFastFieldShouldUpdate(newProps, oldProps) defaultFastFieldShouldUpdate(newProps, oldProps)
); );
}; };

View File

@@ -16,21 +16,21 @@ function InvoicesListProvider({ query, tableStateChanged, ...props }) {
const { data: invoicesViews, isLoading: isViewsLoading } = const { data: invoicesViews, isLoading: isViewsLoading } =
useResourceViews('sale_invoices'); useResourceViews('sale_invoices');
// Fetch the accounts resource fields. // Fetch resource fields of the sale invoices.
const { const {
data: resourceMeta, data: resourceMeta,
isLoading: isResourceLoading, isLoading: isResourceLoading,
isFetching: isResourceFetching, isFetching: isResourceFetching,
} = useResourceMeta('sale_invoices'); } = useResourceMeta('sale_invoices');
// Fetch accounts list according to the given custom view id. // Fetch sale invoices of the given query.
const { const {
data: { invoices, pagination, filterMeta }, data: { invoices, pagination, filterMeta },
isFetching: isInvoicesFetching, isFetching: isInvoicesFetching,
isLoading: isInvoicesLoading, isLoading: isInvoicesLoading,
} = useInvoices(query, { keepPreviousData: true }); } = useInvoices(query, { keepPreviousData: true });
// Detarmines the datatable empty status. // Detarmines whether the table should show empty state.
const isEmptyStatus = const isEmptyStatus =
isEmpty(invoices) && !tableStateChanged && !isInvoicesLoading; isEmpty(invoices) && !tableStateChanged && !isInvoicesLoading;

View File

@@ -27,7 +27,7 @@ import {
} from '@/utils'; } from '@/utils';
import { import {
FFormGroup, FFormGroup,
AccountsSelectList, AccountsSelect,
CustomerSelectField, CustomerSelectField,
FieldRequiredHint, FieldRequiredHint,
Icon, Icon,
@@ -285,41 +285,30 @@ function PaymentReceiveHeaderFields({
</FastField> </FastField>
{/* ------------ Deposit account ------------ */} {/* ------------ Deposit account ------------ */}
<FastField <FFormGroup
name={'deposit_account_id'} name={'deposit_account_id'}
accounts={accounts} label={<T id={'deposit_to'} />}
inline={true}
labelInfo={<FieldRequiredHint />}
items={accounts}
shouldUpdate={accountsFieldShouldUpdate} shouldUpdate={accountsFieldShouldUpdate}
fastField={true}
> >
{({ form, field: { value }, meta: { error, touched } }) => ( <AccountsSelect
<FormGroup name={'deposit_account_id'}
label={<T id={'deposit_to'} />} items={accounts}
className={classNames( labelInfo={<FieldRequiredHint />}
'form-group--deposit_account_id', placeholder={<T id={'select_deposit_account'} />}
'form-group--select-list', filterByTypes={[
CLASSES.FILL, ACCOUNT_TYPE.CASH,
)} ACCOUNT_TYPE.BANK,
inline={true} ACCOUNT_TYPE.OTHER_CURRENT_ASSET,
labelInfo={<FieldRequiredHint />} ]}
intent={inputIntent({ error, touched })} shouldUpdate={accountsFieldShouldUpdate}
helperText={<ErrorMessage name={'deposit_account_id'} />} fastField={true}
> fill={true}
<AccountsSelectList />
accounts={accounts} </FFormGroup>
labelInfo={<FieldRequiredHint />}
onAccountSelected={(account) => {
form.setFieldValue('deposit_account_id', account.id);
}}
defaultSelectText={<T id={'select_deposit_account'} />}
selectedAccountId={value}
filterByTypes={[
ACCOUNT_TYPE.CASH,
ACCOUNT_TYPE.BANK,
ACCOUNT_TYPE.OTHER_CURRENT_ASSET,
]}
/>
</FormGroup>
)}
</FastField>
{/* ------------ Reference No. ------------ */} {/* ------------ Reference No. ------------ */}
<FastField name={'reference_no'}> <FastField name={'reference_no'}>

View File

@@ -150,7 +150,7 @@ export const customersFieldShouldUpdate = (newProps, oldProps) => {
*/ */
export const accountsFieldShouldUpdate = (newProps, oldProps) => { export const accountsFieldShouldUpdate = (newProps, oldProps) => {
return ( return (
newProps.accounts !== oldProps.accounts || newProps.items !== oldProps.items ||
defaultFastFieldShouldUpdate(newProps, oldProps) defaultFastFieldShouldUpdate(newProps, oldProps)
); );
}; };

View File

@@ -15,7 +15,7 @@ import { CLASSES } from '@/constants/classes';
import { import {
FFormGroup, FFormGroup,
AccountsSelectList, AccountsSelect,
CustomerSelectField, CustomerSelectField,
FieldRequiredHint, FieldRequiredHint,
Icon, Icon,
@@ -125,38 +125,30 @@ function ReceiptFormHeader({
/> />
{/* ----------- Deposit account ----------- */} {/* ----------- Deposit account ----------- */}
<FastField <FFormGroup
label={<T id={'deposit_account'} />}
inline={true}
labelInfo={<FieldRequiredHint />}
name={'deposit_account_id'} name={'deposit_account_id'}
accounts={accounts} items={accounts}
fastField={true}
shouldUpdate={accountsFieldShouldUpdate} shouldUpdate={accountsFieldShouldUpdate}
> >
{({ form, field: { value }, meta: { error, touched } }) => ( <AccountsSelect
<FormGroup items={accounts}
label={<T id={'deposit_account'} />} name={'deposit_account_id'}
className={classNames('form-group--deposit-account', CLASSES.FILL)} placeholder={<T id={'select_deposit_account'} />}
inline={true} filterByTypes={[
labelInfo={<FieldRequiredHint />} ACCOUNT_TYPE.CASH,
intent={inputIntent({ error, touched })} ACCOUNT_TYPE.BANK,
helperText={<ErrorMessage name={'deposit_account_id'} />} ACCOUNT_TYPE.OTHER_CURRENT_ASSET,
> ]}
<AccountsSelectList allowCreate={true}
accounts={accounts} fill={true}
onAccountSelected={(account) => { fastField={true}
form.setFieldValue('deposit_account_id', account.id); shouldUpdate={accountsFieldShouldUpdate}
}} />
defaultSelectText={<T id={'select_deposit_account'} />} </FFormGroup>
selectedAccountId={value}
popoverFill={true}
filterByTypes={[
ACCOUNT_TYPE.CASH,
ACCOUNT_TYPE.BANK,
ACCOUNT_TYPE.OTHER_CURRENT_ASSET,
]}
allowCreate={true}
/>
</FormGroup>
)}
</FastField>
{/* ----------- Receipt date ----------- */} {/* ----------- Receipt date ----------- */}
<FastField name={'receipt_date'}> <FastField name={'receipt_date'}>

View File

@@ -101,7 +101,7 @@ export const entriesFieldShouldUpdate = (newProps, oldProps) => {
*/ */
export const accountsFieldShouldUpdate = (newProps, oldProps) => { export const accountsFieldShouldUpdate = (newProps, oldProps) => {
return ( return (
newProps.accounts !== oldProps.accounts || newProps.items !== oldProps.items ||
defaultFastFieldShouldUpdate(newProps, oldProps) defaultFastFieldShouldUpdate(newProps, oldProps)
); );
}; };

View File

@@ -20,16 +20,16 @@ function VendorsListProvider({ tableState, tableStateChanged, ...props }) {
isFetching: isVendorsFetching, isFetching: isVendorsFetching,
} = useVendors(tableQuery, { keepPreviousData: true }); } = useVendors(tableQuery, { keepPreviousData: true });
// Fetch customers resource views and fields. // Fetch vendors resource views and fields.
const { data: vendorsViews, isLoading: isVendorsViewsLoading } = const { data: vendorsViews, isLoading: isVendorsViewsLoading } =
useResourceViews('vendors'); useResourceViews('vendors');
// Fetch the customers resource fields. // Fetch the vendors resource fields.
const { const {
data: resourceMeta, data: resourceMeta,
isLoading: isResourceMetaLoading, isLoading: isResourceMetaLoading,
isFetching: isResourceMetaFetching, isFetching: isResourceMetaFetching,
} = useResourceMeta('customers'); } = useResourceMeta('vendors');
// Detarmines the datatable empty status. // Detarmines the datatable empty status.
const isEmptyStatus = const isEmptyStatus =

View File

@@ -8,13 +8,13 @@ import {
} from '@blueprintjs/core'; } from '@blueprintjs/core';
import { DateInput } from '@blueprintjs/datetime'; import { DateInput } from '@blueprintjs/datetime';
import { FastField, Field, ErrorMessage } from 'formik'; import { FastField, Field, ErrorMessage } from 'formik';
import { FormattedMessage as T } from '@/components'; import { FFormGroup, FormattedMessage as T } from '@/components';
import { momentFormatter, compose, tansformDateValue } from '@/utils'; import { momentFormatter, compose, tansformDateValue } from '@/utils';
import classNames from 'classnames'; import classNames from 'classnames';
import { CLASSES } from '@/constants/classes'; import { CLASSES } from '@/constants/classes';
import { import {
AccountsSelectList, AccountsSelect,
FieldRequiredHint, FieldRequiredHint,
Icon, Icon,
InputPrependButton, InputPrependButton,
@@ -91,6 +91,7 @@ function WarehouseTransferFormHeaderFields({
</FormGroup> </FormGroup>
)} )}
</FastField> </FastField>
{/* ----------- Transfer number ----------- */} {/* ----------- Transfer number ----------- */}
<Field name={'transaction_number'}> <Field name={'transaction_number'}>
{({ form, field, meta: { error, touched } }) => ( {({ form, field, meta: { error, touched } }) => (
@@ -130,60 +131,39 @@ function WarehouseTransferFormHeaderFields({
</FormGroup> </FormGroup>
)} )}
</Field> </Field>
{/* ----------- Form Warehouse ----------- */} {/* ----------- Form Warehouse ----------- */}
<FastField name={'from_warehouse_id'} accounts={warehouses}> <FFormGroup
{({ form, field: { value }, meta: { error, touched } }) => ( name={'from_warehouse_id'}
<FormGroup items={warehouses}
label={<T id={'warehouse_transfer.label.from_warehouse'} />} label={<T id={'warehouse_transfer.label.from_warehouse'} />}
className={classNames( inline={true}
'form-group--warehouse-transfer', labelInfo={<FieldRequiredHint />}
CLASSES.FILL, >
)} <AccountsSelect
inline={true} name={'from_warehouse_id'}
labelInfo={<FieldRequiredHint />} items={warehouses}
intent={inputIntent({ error, touched })} placeholder={<T id={'select_warehouse_transfer'} />}
helperText={<ErrorMessage name={'from_warehouse_id'} />} allowCreate={true}
> fill={true}
<AccountsSelectList />
accounts={warehouses} </FFormGroup>
onAccountSelected={(account) => {
form.setFieldValue('from_warehouse_id', account.id);
}}
defaultSelectText={<T id={'select_warehouse_transfer'} />}
selectedAccountId={value}
popoverFill={true}
allowCreate={true}
/>
</FormGroup>
)}
</FastField>
{/* ----------- To Warehouse ----------- */} {/* ----------- To Warehouse ----------- */}
<FastField name={'to_warehouse_id'} accounts={warehouses}> <FFormGroup
{({ form, field: { value }, meta: { error, touched } }) => ( name={'to_warehouse_id'}
<FormGroup label={<T id={'warehouse_transfer.label.to_warehouse'} />}
label={<T id={'warehouse_transfer.label.to_warehouse'} />} inline={true}
className={classNames( labelInfo={<FieldRequiredHint />}
'form-group--warehouse-transfer', >
CLASSES.FILL, <AccountsSelect
)} name={'to_warehouse_id'}
inline={true} items={warehouses}
labelInfo={<FieldRequiredHint />} placeholder={<T id={'select_warehouse_transfer'} />}
intent={inputIntent({ error, touched })} fill={true}
helperText={<ErrorMessage name={'to_warehouse_id'} />} allowCreate={true}
> />
<AccountsSelectList </FFormGroup>
accounts={warehouses}
onAccountSelected={(account) => {
form.setFieldValue('to_warehouse_id', account.id);
}}
defaultSelectText={<T id={'select_warehouse_transfer'} />}
selectedAccountId={value}
popoverFill={true}
allowCreate={true}
/>
</FormGroup>
)}
</FastField>
</div> </div>
); );
} }

View File

@@ -64,7 +64,7 @@
"new_currency": "New Currency", "new_currency": "New Currency",
"currency_name": "Currency Name", "currency_name": "Currency Name",
"currency_code": "Currency Code", "currency_code": "Currency Code",
"select_currency_code": "Select Currency Code", "select_currency_code": "Select Currency Code...",
"edit_exchange_rate": "Edit Exchange Rate", "edit_exchange_rate": "Edit Exchange Rate",
"new_exchange_rate": "New Exchange Rate", "new_exchange_rate": "New Exchange Rate",
"delete_exchange_rate": "Delete Exchange Rate", "delete_exchange_rate": "Delete Exchange Rate",
@@ -242,7 +242,7 @@
"organization": "Organization.", "organization": "Organization.",
"check_your_email_for_a_link_to_reset": "Check your email for a link to reset your password.If it doesnt appear within a few minutes, check your spam folder.", "check_your_email_for_a_link_to_reset": "Check your email for a link to reset your password.If it doesnt appear within a few minutes, check your spam folder.",
"we_couldn_t_find_your_account_with_that_email": "We couldn't find your account with that email.", "we_couldn_t_find_your_account_with_that_email": "We couldn't find your account with that email.",
"select_parent_account": "Select Parent Account", "select_parent_account": "Select Parent Account...",
"the_exchange_rate_has_been_edited_successfully": "The exchange rate has been edited successfully", "the_exchange_rate_has_been_edited_successfully": "The exchange rate has been edited successfully",
"the_exchange_rate_has_been_created_successfully": "The exchange rate has been created successfully", "the_exchange_rate_has_been_created_successfully": "The exchange rate has been created successfully",
"the_user_details_has_been_updated": "The user details has been updated", "the_user_details_has_been_updated": "The user details has been updated",
@@ -540,7 +540,7 @@
"statement": "Statement", "statement": "Statement",
"deposit_account": "Deposit Account", "deposit_account": "Deposit Account",
"send_to_email": "Send to email", "send_to_email": "Send to email",
"select_deposit_account": "Select Deposit Account", "select_deposit_account": "Select Deposit Account...",
"once_delete_this_receipt_you_will_able_to_restore_it": "Once you delete this receipt, you won't be able to restore it later. Are you sure you want to delete this receipt?", "once_delete_this_receipt_you_will_able_to_restore_it": "Once you delete this receipt, you won't be able to restore it later. Are you sure you want to delete this receipt?",
"the_receipt_has_been_created_successfully": "The receipt #{number} has been created successfully.", "the_receipt_has_been_created_successfully": "The receipt #{number} has been created successfully.",
"the_receipt_has_been_edited_successfully": "The receipt #{number} has been edited successfully.", "the_receipt_has_been_edited_successfully": "The receipt #{number} has been edited successfully.",
@@ -609,8 +609,8 @@
"new_payment_made": "New Payment Made", "new_payment_made": "New Payment Made",
"payment_made_list": "Payment Made List", "payment_made_list": "Payment Made List",
"payment_account": "Payment Account", "payment_account": "Payment Account",
"select_vender_account": "Select Vender Account", "select_vender_account": "Select Vender Account...",
"select_payment_account": "Select Payment Account", "select_payment_account": "Select Payment Account...",
"the_payment_made_has_been_edited_successfully": "The payment made has been edited successfully.", "the_payment_made_has_been_edited_successfully": "The payment made has been edited successfully.",
"the_payment_made_has_been_created_successfully": "The payment made has been created successfully.", "the_payment_made_has_been_created_successfully": "The payment made has been created successfully.",
"the_payment_made_has_been_deleted_successfully": "The payment made has been deleted successfully.", "the_payment_made_has_been_deleted_successfully": "The payment made has been deleted successfully.",
@@ -1417,6 +1417,7 @@
"siebar.cashflow": "Cash flow", "siebar.cashflow": "Cash flow",
"siebar.cashflow.label_cash_and_bank_accounts": "Cash & Bank Accounts", "siebar.cashflow.label_cash_and_bank_accounts": "Cash & Bank Accounts",
"cash_flow.label_account_transcations": "Account Transcations", "cash_flow.label_account_transcations": "Account Transcations",
"cash_flow.transactions_for_review": "Transactions for review",
"cash_flow.label.deposit": "Deposit", "cash_flow.label.deposit": "Deposit",
"cash_flow.label.withdrawal": "Withdrawal", "cash_flow.label.withdrawal": "Withdrawal",
"cash_flow.label.running_balance": "Running balance", "cash_flow.label.running_balance": "Running balance",

View File

@@ -52,6 +52,7 @@ body.hide-scrollbar .Pane2 {
} }
.bp3-fill { .bp3-fill {
.bp3-popover-wrapper, .bp3-popover-wrapper,
.bp3-popover-target { .bp3-popover-target {
display: block; display: block;
@@ -68,9 +69,9 @@ body.hide-scrollbar .Pane2 {
margin-right: 6px; margin-right: 6px;
} }
.bp3-select-popover .bp3-menu { .bp3-select-popover .bp3-menu,
.bp3-multi-select-popover .bp3-menu {
max-height: 300px; max-height: 300px;
max-width: 400px;
overflow: auto; overflow: auto;
} }
@@ -103,27 +104,21 @@ body.hide-scrollbar .Pane2 {
background-color: #0066ff; background-color: #0066ff;
} }
.ReactVirtualized__Collection { .ReactVirtualized__Collection {}
}
.ReactVirtualized__Collection__innerScrollContainer { .ReactVirtualized__Collection__innerScrollContainer {}
}
/* Grid default theme */ /* Grid default theme */
.ReactVirtualized__Grid { .ReactVirtualized__Grid {}
}
.ReactVirtualized__Grid__innerScrollContainer { .ReactVirtualized__Grid__innerScrollContainer {}
}
/* Table default theme */ /* Table default theme */
.ReactVirtualized__Table { .ReactVirtualized__Table {}
}
.ReactVirtualized__Table__Grid { .ReactVirtualized__Table__Grid {}
}
.ReactVirtualized__Table__headerRow { .ReactVirtualized__Table__headerRow {
font-weight: 700; font-weight: 700;
@@ -186,8 +181,7 @@ body.hide-scrollbar .Pane2 {
/* List default theme */ /* List default theme */
.ReactVirtualized__List { .ReactVirtualized__List {}
}
.bp3-drawer { .bp3-drawer {
box-shadow: 0 0 0; box-shadow: 0 0 0;
@@ -243,7 +237,7 @@ html[lang^='ar'] {
padding-left: 14px; padding-left: 14px;
padding-right: 14px; padding-right: 14px;
& + .bp3-button { &+.bp3-button {
margin-left: 8px; margin-left: 8px;
} }
} }
@@ -255,7 +249,7 @@ html[lang^='ar'] {
margin: 0; margin: 0;
} }
> .bp3-spinner { >.bp3-spinner {
margin: 20px 0; margin: 20px 0;
} }
} }
@@ -283,6 +277,7 @@ html[lang^='ar'] {
.align-right { .align-right {
text-align: right; text-align: right;
} }
.align-center { .align-center {
text-align: center; text-align: center;
} }
@@ -292,6 +287,6 @@ html[lang^='ar'] {
} }
span.table-tooltip-overview-target{ span.table-tooltip-overview-target {
display: inline; display: inline;
} }