Compare commits

..

1 Commits

Author SHA1 Message Date
Ahmed Bouhuolia
7ad1d3677c fix(webapp): Payment made details drawer does not show up 2023-06-14 13:13:32 +02:00
225 changed files with 3794 additions and 2542 deletions

View File

@@ -29,7 +29,7 @@ TENANT_DB_NAME_PERFIX=bigcapital_tenant_
# TENANT_DB_CHARSET= # TENANT_DB_CHARSET=
# Application # Application
BASE_URL=http://example.com BASE_URL=https://bigcapital.ly
JWT_SECRET=b0JDZW56RnV6aEthb0RGPXVEcUI JWT_SECRET=b0JDZW56RnV6aEthb0RGPXVEcUI
# Jobs MongoDB # Jobs MongoDB

View File

@@ -2,30 +2,6 @@
All notable changes to Bigcapital server-side will be in this file. All notable changes to Bigcapital server-side will be in this file.
# [0.9.8] - 19-06-2023
`bigcapitalhq/webapp`
* add: Inventory Adjustment option to the item drawer by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/158
* fix: use all drawers names from common enum object by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/157
* fix: adjustment type options do not show up by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/159
* fix: change the remove line text to be red to intent as a danger action by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/162
* fix: rename sidebar localization keys names to be keyword path by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/161
* fix: manual journal placeholder text by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/160
* fix: warehouses select component by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/168
`bigcapitalhq/server`
* fix: sending emails on reset password and registration by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/167
## [0.9.7] - 14-06-2023
`@bigcapital/webapp`
* fix: change the footer links of onboarding pages by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/139
`@bigcapital/server`
* fix: expense transaction journal entries by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/155
## [0.9.6] - 12-06-2023 ## [0.9.6] - 12-06-2023
`@bigcapital/webapp` `@bigcapital/webapp`

View File

@@ -92,7 +92,6 @@ export default class AuthenticationController extends BaseController {
check('password') check('password')
.exists() .exists()
.isString() .isString()
.isLength({ min: 6 })
.trim() .trim()
.escape() .escape()
.isLength({ max: DATATYPES_LENGTH.STRING }), .isLength({ max: DATATYPES_LENGTH.STRING }),
@@ -107,7 +106,7 @@ export default class AuthenticationController extends BaseController {
return [ return [
check('password') check('password')
.exists() .exists()
.isLength({ min: 6 }) .isLength({ min: 5 })
.custom((value, { req }) => { .custom((value, { req }) => {
if (value !== req.body.confirm_password) { if (value !== req.body.confirm_password) {
throw new Error("Passwords don't match"); throw new Error("Passwords don't match");

View File

@@ -95,15 +95,16 @@ module.exports = {
* JWT secret. * JWT secret.
*/ */
jwtSecret: process.env.JWT_SECRET, jwtSecret: process.env.JWT_SECRET,
resetPasswordSeconds: 600,
/** /**
* *
*/ */
resetPasswordSeconds: 600, customerSuccess: {
email: 'success@bigcapital.ly',
phoneNumber: '(218) 92 791 8381',
},
/**
* Application base URL.
*/
baseURL: process.env.BASE_URL, baseURL: process.env.BASE_URL,
/** /**
@@ -136,6 +137,16 @@ module.exports = {
}, },
}, },
/**
* Users registeration configuration.
*/
registration: {
countries: {
whitelist: ['LY'],
blacklist: [],
},
},
/** /**
* Sign-up restrictions * Sign-up restrictions
*/ */
@@ -156,6 +167,8 @@ module.exports = {
browserWSEndpoint: process.env.BROWSER_WS_ENDPOINT, browserWSEndpoint: process.env.BROWSER_WS_ENDPOINT,
}, },
protocol: '',
hostname: '',
scheduleComputeItemCost: 'in 5 seconds', scheduleComputeItemCost: 'in 5 seconds',
/** /**

View File

@@ -41,8 +41,6 @@ export interface ILedgerEntry {
index: number; index: number;
indexGroup?: number; indexGroup?: number;
note?: string;
userId?: number; userId?: number;
itemId?: number; itemId?: number;
branchId?: number; branchId?: number;

View File

@@ -1,7 +1,7 @@
import { Container } from 'typedi'; import { Container, Inject } from 'typedi';
import AuthenticationMailMesssages from '@/services/Authentication/AuthenticationMailMessages'; import AuthenticationService from '@/services/Authentication/AuthApplication';
export default class ResetPasswordEmailJob { export default class WelcomeEmailJob {
/** /**
* Constructor method. * Constructor method.
* @param {Agenda} agenda * @param {Agenda} agenda
@@ -10,7 +10,7 @@ export default class ResetPasswordEmailJob {
agenda.define( agenda.define(
'reset-password-mail', 'reset-password-mail',
{ priority: 'high' }, { priority: 'high' },
this.handler.bind(this) this.handler.bind(this),
); );
} }
@@ -22,13 +22,17 @@ export default class ResetPasswordEmailJob {
public async handler(job, done: Function): Promise<void> { public async handler(job, done: Function): Promise<void> {
const { data } = job.attrs; const { data } = job.attrs;
const { user, token } = data; const { user, token } = data;
const authService = Container.get(AuthenticationMailMesssages); const Logger = Container.get('logger');
const authService = Container.get(AuthenticationService);
Logger.info(`[send_reset_password] started.`, { data });
try { try {
await authService.sendResetPasswordMessage(user, token); await authService.mailMessages.sendResetPasswordMessage(user, token);
done(); Logger.info(`[send_reset_password] finished.`, { data });
done()
} catch (error) { } catch (error) {
console.log(error); Logger.error(`[send_reset_password] error.`, { data, error });
done(error); done(error);
} }
} }

View File

@@ -0,0 +1,22 @@
import { Container } from 'typedi';
export default class SmsNotification {
constructor(agenda) {
agenda.define('sms-notification', { priority: 'high' }, this.handler);
}
/**
*
* @param {Job}job
*/
async handler(job) {
const { message, to } = job.attrs.data;
const smsClient = Container.get('SMSClient');
try {
await smsClient.sendMessage(to, message);
} catch (error) {
done(e);
}
}
}

View File

@@ -0,0 +1,35 @@
import { Container, Inject } from 'typedi';
import AuthenticationService from '@/services/Authentication/AuthApplication';
export default class WelcomeSMSJob {
/**
* Constructor method.
* @param {Agenda} agenda
*/
constructor(agenda) {
agenda.define('welcome-sms', { priority: 'high' }, this.handler);
}
/**
* Handle send welcome mail job.
* @param {Job} job
* @param {Function} done
*/
public async handler(job, done: Function): Promise<void> {
const { tenant, user } = job.attrs.data;
const Logger = Container.get('logger');
const authService = Container.get(AuthenticationService);
Logger.info(`[welcome_sms] started: ${job.attrs.data}`);
try {
await authService.smsMessages.sendWelcomeMessage(tenant, user);
Logger.info(`[welcome_sms] finished`, { tenant, user });
done();
} catch (error) {
Logger.info(`[welcome_sms] error`, { error, tenant, user });
done(error);
}
}
}

View File

@@ -0,0 +1,39 @@
import { Container } from 'typedi';
import AuthenticationService from '@/services/Authentication/AuthApplication';
export default class WelcomeEmailJob {
/**
* Constructor method.
* @param {Agenda} agenda -
*/
constructor(agenda) {
// Welcome mail and SMS message.
agenda.define(
'welcome-email',
{ priority: 'high' },
this.handler.bind(this),
);
}
/**
* Handle send welcome mail job.
* @param {Job} job
* @param {Function} done
*/
public async handler(job, done: Function): Promise<void> {
const { organizationId, user } = job.attrs.data;
const Logger: any = Container.get('logger');
const authService = Container.get(AuthenticationService);
Logger.info(`[welcome_mail] started: ${job.attrs.data}`);
try {
await authService.mailMessages.sendWelcomeMessage(user, organizationId);
Logger.info(`[welcome_mail] finished: ${job.attrs.data}`);
done();
} catch (error) {
Logger.error(`[welcome_mail] error: ${job.attrs.data}, error: ${error}`);
done(error);
}
}
}

View File

@@ -31,6 +31,7 @@ import OrgBuildSmsNotificationSubscriber from '@/subscribers/Organization/BuildS
import PurgeUserAbilityCache from '@/services/Users/PurgeUserAbilityCache'; import PurgeUserAbilityCache from '@/services/Users/PurgeUserAbilityCache';
import ResetLoginThrottleSubscriber from '@/subscribers/Authentication/ResetLoginThrottle'; import ResetLoginThrottleSubscriber from '@/subscribers/Authentication/ResetLoginThrottle';
import AuthenticationSubscriber from '@/subscribers/Authentication/SendResetPasswordMail'; import AuthenticationSubscriber from '@/subscribers/Authentication/SendResetPasswordMail';
import AuthSendWelcomeMailSubscriber from '@/subscribers/Authentication/SendWelcomeMail';
import PurgeAuthorizedUserOnceRoleMutate from '@/services/Roles/PurgeAuthorizedUser'; import PurgeAuthorizedUserOnceRoleMutate from '@/services/Roles/PurgeAuthorizedUser';
import SendSmsNotificationToCustomer from '@/subscribers/SaleInvoices/SendSmsNotificationToCustomer'; import SendSmsNotificationToCustomer from '@/subscribers/SaleInvoices/SendSmsNotificationToCustomer';
import SendSmsNotificationSaleReceipt from '@/subscribers/SaleReceipt/SendSmsNotificationToCustomer'; import SendSmsNotificationSaleReceipt from '@/subscribers/SaleReceipt/SendSmsNotificationToCustomer';
@@ -119,6 +120,7 @@ export const susbcribers = () => {
PurgeUserAbilityCache, PurgeUserAbilityCache,
ResetLoginThrottleSubscriber, ResetLoginThrottleSubscriber,
AuthenticationSubscriber, AuthenticationSubscriber,
AuthSendWelcomeMailSubscriber,
PurgeAuthorizedUserOnceRoleMutate, PurgeAuthorizedUserOnceRoleMutate,
SendSmsNotificationToCustomer, SendSmsNotificationToCustomer,
SendSmsNotificationSaleReceipt, SendSmsNotificationSaleReceipt,

View File

@@ -1,18 +1,24 @@
import Agenda from 'agenda'; import Agenda from 'agenda';
import WelcomeEmailJob from 'jobs/welcomeEmail';
import WelcomeSMSJob from 'jobs/WelcomeSMS';
import ResetPasswordMailJob from 'jobs/ResetPasswordMail'; import ResetPasswordMailJob from 'jobs/ResetPasswordMail';
import ComputeItemCost from 'jobs/ComputeItemCost'; import ComputeItemCost from 'jobs/ComputeItemCost';
import RewriteInvoicesJournalEntries from 'jobs/WriteInvoicesJEntries'; import RewriteInvoicesJournalEntries from 'jobs/writeInvoicesJEntries';
import UserInviteMailJob from 'jobs/UserInviteMail'; import UserInviteMailJob from 'jobs/UserInviteMail';
import OrganizationSetupJob from 'jobs/OrganizationSetup'; import OrganizationSetupJob from 'jobs/OrganizationSetup';
import OrganizationUpgrade from 'jobs/OrganizationUpgrade'; import OrganizationUpgrade from 'jobs/OrganizationUpgrade';
import SmsNotification from 'jobs/SmsNotification';
export default ({ agenda }: { agenda: Agenda }) => { export default ({ agenda }: { agenda: Agenda }) => {
new WelcomeEmailJob(agenda);
new ResetPasswordMailJob(agenda); new ResetPasswordMailJob(agenda);
new WelcomeSMSJob(agenda);
new UserInviteMailJob(agenda); new UserInviteMailJob(agenda);
new ComputeItemCost(agenda); new ComputeItemCost(agenda);
new RewriteInvoicesJournalEntries(agenda); new RewriteInvoicesJournalEntries(agenda);
new OrganizationSetupJob(agenda); new OrganizationSetupJob(agenda);
new OrganizationUpgrade(agenda); new OrganizationUpgrade(agenda);
new SmsNotification(agenda);
agenda.start(); agenda.start();
}; };

View File

@@ -21,8 +21,6 @@ export const transformLedgerEntryToTransaction = (
transactionNumber: entry.transactionNumber, transactionNumber: entry.transactionNumber,
referenceNumber: entry.referenceNumber, referenceNumber: entry.referenceNumber,
note: entry.note,
index: entry.index, index: entry.index,
indexGroup: entry.indexGroup, indexGroup: entry.indexGroup,

View File

@@ -5,24 +5,59 @@ import Mail from '@/lib/Mail';
@Service() @Service()
export default class AuthenticationMailMesssages { export default class AuthenticationMailMesssages {
/**
* Sends welcome message.
* @param {ISystemUser} user - The system user.
* @param {string} organizationName -
* @return {Promise<void>}
*/
async sendWelcomeMessage(
user: ISystemUser,
organizationId: string
): Promise<void> {
const root = __dirname + '/../../../views/images/bigcapital.png';
const mail = new Mail()
.setView('mail/Welcome.html')
.setSubject('Welcome to Bigcapital')
.setTo(user.email)
.setAttachments([
{
filename: 'bigcapital.png',
path: root,
cid: 'bigcapital_logo',
},
])
.setData({
firstName: user.firstName,
organizationId,
successPhoneNumber: config.customerSuccess.phoneNumber,
successEmail: config.customerSuccess.email,
});
await mail.send();
}
/** /**
* Sends reset password message. * Sends reset password message.
* @param {ISystemUser} user - The system user. * @param {ISystemUser} user - The system user.
* @param {string} token - Reset password token. * @param {string} token - Reset password token.
* @return {Promise<void>} * @return {Promise<void>}
*/ */
public async sendResetPasswordMessage( async sendResetPasswordMessage(
user: ISystemUser, user: ISystemUser,
token: string token: string
): Promise<void> { ): Promise<void> {
await new Mail() const root = __dirname + '/../../../views/images/bigcapital.png';
const mail = new Mail()
.setSubject('Bigcapital - Password Reset') .setSubject('Bigcapital - Password Reset')
.setView('mail/ResetPassword.html') .setView('mail/ResetPassword.html')
.setTo(user.email) .setTo(user.email)
.setAttachments([ .setAttachments([
{ {
filename: 'bigcapital.png', filename: 'bigcapital.png',
path: `${global.__views_dir}/images/bigcapital.png`, path: root,
cid: 'bigcapital_logo', cid: 'bigcapital_logo',
}, },
]) ])
@@ -30,7 +65,9 @@ export default class AuthenticationMailMesssages {
resetPasswordUrl: `${config.baseURL}/auth/reset_password/${token}`, resetPasswordUrl: `${config.baseURL}/auth/reset_password/${token}`,
first_name: user.firstName, first_name: user.firstName,
last_name: user.lastName, last_name: user.lastName,
}) contact_us_email: config.contactUsMail,
.send(); });
await mail.send();
} }
} }

View File

@@ -0,0 +1,19 @@
import { Service, Inject } from 'typedi';
import { ISystemUser, ITenant } from '@/interfaces';
@Service()
export default class AuthenticationSMSMessages {
@Inject('SMSClient')
smsClient: any;
/**
* Sends welcome sms message.
* @param {ITenant} tenant
* @param {ISystemUser} user
*/
sendWelcomeMessage(tenant: ITenant, user: ISystemUser) {
const message: string = `Hi ${user.firstName}, Welcome to Bigcapital, You've joined the new workspace, if you need any help please don't hesitate to contact us.`;
return this.smsClient.sendMessage(user.phoneNumber, message);
}
}

View File

@@ -26,7 +26,7 @@ export default class CashflowTransactionJournalEntries {
/** /**
* Retrieves the common entry of cashflow transaction. * Retrieves the common entry of cashflow transaction.
* @param {ICashflowTransaction} cashflowTransaction * @param {ICashflowTransaction} cashflowTransaction
* @returns {Partial<ILedgerEntry>} * @returns {}
*/ */
private getCommonEntry = (cashflowTransaction: ICashflowTransaction) => { private getCommonEntry = (cashflowTransaction: ICashflowTransaction) => {
const { entries, ...transaction } = cashflowTransaction; const { entries, ...transaction } = cashflowTransaction;
@@ -41,9 +41,7 @@ export default class CashflowTransactionJournalEntries {
), ),
transactionId: transaction.id, transactionId: transaction.id,
transactionNumber: transaction.transactionNumber, transactionNumber: transaction.transactionNumber,
referenceNumber: transaction.referenceNo, referenceNo: transaction.referenceNo,
note: transaction.description,
branchId: cashflowTransaction.branchId, branchId: cashflowTransaction.branchId,
userId: cashflowTransaction.userId, userId: cashflowTransaction.userId,
@@ -107,7 +105,7 @@ export default class CashflowTransactionJournalEntries {
* @param {ICashflowTransaction} cashflowTransaction * @param {ICashflowTransaction} cashflowTransaction
* @param {ICashflowTransactionLine} entry * @param {ICashflowTransactionLine} entry
* @param {number} index * @param {number} index
* @returns {ILedgerEntry[]} * @returns
*/ */
private getJournalEntries = ( private getJournalEntries = (
cashflowTransaction: ICashflowTransaction cashflowTransaction: ICashflowTransaction
@@ -132,7 +130,6 @@ export default class CashflowTransactionJournalEntries {
* Write the journal entries of the given cashflow transaction. * Write the journal entries of the given cashflow transaction.
* @param {number} tenantId * @param {number} tenantId
* @param {ICashflowTransaction} cashflowTransaction * @param {ICashflowTransaction} cashflowTransaction
* @return {Promise<void>}
*/ */
public writeJournalEntries = async ( public writeJournalEntries = async (
tenantId: number, tenantId: number,
@@ -156,7 +153,6 @@ export default class CashflowTransactionJournalEntries {
* Delete the journal entries. * Delete the journal entries.
* @param {number} tenantId - Tenant id. * @param {number} tenantId - Tenant id.
* @param {number} cashflowTransactionId - Cashflow transaction id. * @param {number} cashflowTransactionId - Cashflow transaction id.
* @return {Promise<void>}
*/ */
public revertJournalEntries = async ( public revertJournalEntries = async (
tenantId: number, tenantId: number,

View File

@@ -9,6 +9,7 @@ import events from '@/subscribers/events';
import UnitOfWork from '@/services/UnitOfWork'; import UnitOfWork from '@/services/UnitOfWork';
import { EventPublisher } from '@/lib/EventPublisher/EventPublisher'; import { EventPublisher } from '@/lib/EventPublisher/EventPublisher';
import { CommandExpenseValidator } from './CommandExpenseValidator'; import { CommandExpenseValidator } from './CommandExpenseValidator';
import { ExpenseCategory } from 'models';
import HasTenancyService from '@/services/Tenancy/TenancyService'; import HasTenancyService from '@/services/Tenancy/TenancyService';
@Service() @Service()
@@ -36,7 +37,7 @@ export class DeleteExpense {
expenseId: number, expenseId: number,
authorizedUser: ISystemUser authorizedUser: ISystemUser
): Promise<void> => { ): Promise<void> => {
const { Expense, ExpenseCategory } = this.tenancy.models(tenantId); const { Expense } = this.tenancy.models(tenantId);
// Retrieves the expense transaction with associated entries or // Retrieves the expense transaction with associated entries or
// throw not found error. // throw not found error.
@@ -59,7 +60,7 @@ export class DeleteExpense {
} as IExpenseDeletingPayload); } as IExpenseDeletingPayload);
// Deletes expense associated entries. // Deletes expense associated entries.
await ExpenseCategory.query(trx).where('expenseId', expenseId).delete(); await ExpenseCategory.query(trx).findById(expenseId).delete();
// Deletes expense transactions. // Deletes expense transactions.
await Expense.query(trx).findById(expenseId).delete(); await Expense.query(trx).findById(expenseId).delete();

View File

@@ -46,7 +46,7 @@ export class ExpenseGLEntries {
...commonEntry, ...commonEntry,
credit: expense.localAmount, credit: expense.localAmount,
accountId: expense.paymentAccountId, accountId: expense.paymentAccountId,
accountNormal: AccountNormal.DEBIT, accountNormal: AccountNormal.CREDIT,
index: 1, index: 1,
}; };
}; };

View File

@@ -4,7 +4,7 @@ import events from '@/subscribers/events';
@Service() @Service()
export default class AuthenticationSubscriber { export default class AuthenticationSubscriber {
@Inject('agenda') @Inject('agenda')
private agenda: any; agenda: any;
/** /**
* Attaches events with handlers. * Attaches events with handlers.

View File

@@ -0,0 +1,28 @@
import { Service, Inject } from 'typedi';
import events from '@/subscribers/events';
@Service()
export default class AuthSendWelcomeMailSubscriber {
@Inject('agenda')
agenda: any;
/**
* Attaches events with handlers.
*/
public attach(bus) {
bus.subscribe(events.auth.signUp, this.sendWelcomeEmailOnceUserRegister);
}
/**
* Sends welcome email once the user register.
*/
private sendWelcomeEmailOnceUserRegister = async (payload) => {
const { tenant, user } = payload;
// Send welcome mail to the user.
await this.agenda.now('welcome-email', {
organizationId: tenant.organizationId,
user,
});
};
}

View File

@@ -0,0 +1,411 @@
<!doctype html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Bigcapital | Reset your password</title>
<style>
/* -------------------------------------
GLOBAL RESETS
------------------------------------- */
/*All the styling goes here*/
img {
border: none;
-ms-interpolation-mode: bicubic;
max-width: 100%;
}
body {
background-color: #f6f6f6;
font-family: sans-serif;
-webkit-font-smoothing: antialiased;
font-size: 14px;
line-height: 1.4;
margin: 0;
padding: 0;
-ms-text-size-adjust: 100%;
-webkit-text-size-adjust: 100%;
}
table {
border-collapse: separate;
mso-table-lspace: 0pt;
mso-table-rspace: 0pt;
width: 100%; }
table td {
font-family: sans-serif;
font-size: 14px;
vertical-align: top;
}
/* -------------------------------------
BODY & CONTAINER
------------------------------------- */
.body {
background-color: #f6f6f6;
width: 100%;
}
/* Set a max-width, and make it display as block so it will automatically stretch to that width, but will also shrink down on a phone or something */
.container {
display: block;
margin: 0 auto !important;
/* makes it centered */
max-width: 580px;
padding: 10px;
width: 580px;
}
/* This should also be a block element, so that it will fill 100% of the .container */
.content {
box-sizing: border-box;
display: block;
margin: 0 auto;
max-width: 580px;
padding: 10px;
}
/* -------------------------------------
HEADER, FOOTER, MAIN
------------------------------------- */
.main {
background: #ffffff;
border-radius: 3px;
width: 100%;
}
.wrapper {
box-sizing: border-box;
padding: 20px;
}
.content-block {
padding-bottom: 10px;
padding-top: 10px;
}
.footer {
clear: both;
margin-top: 10px;
text-align: center;
width: 100%;
}
.footer td,
.footer p,
.footer span,
.footer a {
color: #999999;
font-size: 12px;
text-align: center;
}
/* -------------------------------------
TYPOGRAPHY
------------------------------------- */
h1,
h2,
h3,
h4 {
color: #000000;
font-family: sans-serif;
font-weight: bold;
line-height: 1.4;
margin: 0;
margin-bottom: 0;
}
h1 {
font-size: 35px;
font-weight: 300;
text-align: center;
text-transform: capitalize;
}
p,
ul,
ol {
font-family: sans-serif;
font-size: 14px;
font-weight: normal;
margin: 0;
margin-bottom: 15px;
}
p li,
ul li,
ol li {
list-style-position: inside;
margin-left: 5px;
}
a {
color: #3498db;
text-decoration: underline;
}
/* -------------------------------------
BUTTONS
------------------------------------- */
.btn {
box-sizing: border-box;
width: 100%;
}
.btn > tbody > tr > td {
padding-bottom: 15px; }
.btn table {
width: auto;
}
.btn table td {
background-color: #ffffff;
border-radius: 5px;
text-align: center;
}
.btn a {
background-color: #ffffff;
border: solid 1px #3498db;
border-radius: 5px;
box-sizing: border-box;
color: #3498db;
cursor: pointer;
display: inline-block;
font-size: 14px;
font-weight: bold;
margin: 0;
padding: 12px 25px;
text-decoration: none;
text-transform: capitalize;
}
.btn-primary table td {
background-color: #2d95fd;
}
.btn-primary a {
background-color: #2d95fd;
border-color: #2d95fd;
color: #ffffff;
}
/* -------------------------------------
OTHER STYLES THAT MIGHT BE USEFUL
------------------------------------- */
.last {
margin-bottom: 0;
}
.first {
margin-top: 0;
}
.align-center {
text-align: center;
}
.align-right {
text-align: right;
}
.align-left {
text-align: left;
}
.clear {
clear: both;
}
.mt0 {
margin-top: 0;
}
.mb0 {
margin-bottom: 0;
}
.mb4{
margin-bottom: 4rem;
}
.preheader {
color: transparent;
display: none;
height: 0;
max-height: 0;
max-width: 0;
opacity: 0;
overflow: hidden;
mso-hide: all;
visibility: hidden;
width: 0;
}
.powered-by a {
text-decoration: none;
}
hr {
border: 0;
border-bottom: 1px solid #f6f6f6;
margin: 20px 0;
}
/* -------------------------------------
RESPONSIVE AND MOBILE FRIENDLY STYLES
------------------------------------- */
@media only screen and (max-width: 620px) {
table[class=body] h1 {
font-size: 28px !important;
margin-bottom: 10px !important;
}
table[class=body] p,
table[class=body] ul,
table[class=body] ol,
table[class=body] td,
table[class=body] span,
table[class=body] a {
font-size: 16px !important;
}
table[class=body] .wrapper,
table[class=body] .article {
padding: 10px !important;
}
table[class=body] .content {
padding: 0 !important;
}
table[class=body] .container {
padding: 0 !important;
width: 100% !important;
}
table[class=body] .main {
border-left-width: 0 !important;
border-radius: 0 !important;
border-right-width: 0 !important;
}
table[class=body] .btn table {
width: 100% !important;
}
table[class=body] .btn a {
width: 100% !important;
}
table[class=body] .img-responsive {
height: auto !important;
max-width: 100% !important;
width: auto !important;
}
}
/* -------------------------------------
PRESERVE THESE STYLES IN THE HEAD
------------------------------------- */
@media all {
.ExternalClass {
width: 100%;
}
.ExternalClass,
.ExternalClass p,
.ExternalClass span,
.ExternalClass font,
.ExternalClass td,
.ExternalClass div {
line-height: 100%;
}
.apple-link a {
color: inherit !important;
font-family: inherit !important;
font-size: inherit !important;
font-weight: inherit !important;
line-height: inherit !important;
text-decoration: none !important;
}
#MessageViewBody a {
color: inherit;
text-decoration: none;
font-size: inherit;
font-family: inherit;
font-weight: inherit;
line-height: inherit;
}
.btn-primary table td:hover {
background-color: #004dd0 !important;
}
.btn-primary a:hover {
background-color: #004dd0 !important;
border-color: #004dd0 !important;
}
}
[data-icon="bigcapital"] path {
fill: #004dd0;
}
[data-icon='bigcapital'] .path-1,
[data-icon='bigcapital'] .path-13 {
fill: #2d95fd;
}
</style>
</head>
<body class="">
<span class="preheader">This is preheader text. Some clients will show this text as a preview.</span>
<table role="presentation" border="0" cellpadding="0" cellspacing="0" class="body">
<tr>
<td>&nbsp;</td>
<td class="container">
<div class="content">
<!-- START CENTERED WHITE CONTAINER -->
<table role="presentation" class="main">
<!-- START MAIN CONTENT AREA -->
<tr>
<td class="wrapper">
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tr>
<td>
<p class="align-center">
<svg data-icon="bigcapital" class="bigcapital" width="190" height="37" viewBox="0 0 309.09 42.89"><desc>bigcapital</desc><path d="M56,3.16,61.33,8.5,31.94,37.9l-5.35-5.35Z" class="path-1" fill-rule="evenodd"></path><path d="M29.53,6.94l5.35,5.34L5.49,41.67.14,36.33l15.8-15.8Z" class="path-2" fill-rule="evenodd"></path><path d="M94.36,38.87H79.62v-31H94c6.33,0,10.22,3.15,10.22,8V16a7.22,7.22,0,0,1-4.07,6.69c3.58,1.37,5.8,3.45,5.8,7.61v.09C106,36,101.35,38.87,94.36,38.87Zm3.1-21.81c0-2-1.59-3.19-4.47-3.19H86.26v6.55h6.29c3,0,4.91-1,4.91-3.28Zm1.72,12.39c0-2.08-1.54-3.37-5-3.37H86.26V32.9h8.1c3,0,4.82-1.06,4.82-3.36Z" class="path-3" fill-rule="evenodd"></path><path d="M110.56,12.54v-6h7.08v6Zm.18,26.33V15.15h6.72V38.87Z" class="path-4" fill-rule="evenodd"></path><path d="M134,46a22.55,22.55,0,0,1-10.49-2.47l2.3-5a15.52,15.52,0,0,0,8,2.17c4.61,0,6.78-2.21,6.78-6.46V33.08c-2,2.39-4.16,3.85-7.75,3.85-5.53,0-10.53-4-10.53-11.07v-.09c0-7.08,5.09-11.06,10.53-11.06a9.63,9.63,0,0,1,7.66,3.54v-3.1h6.72V33.52C147.2,42.46,142.78,46,134,46Zm6.6-20.27a5.79,5.79,0,0,0-11.56,0v.09a5.42,5.42,0,0,0,5.76,5.49,5.49,5.49,0,0,0,5.8-5.49Z" class="path-5" fill-rule="evenodd"></path><path d="M164,39.41a12.11,12.11,0,0,1-12.35-12.26v-.09a12.18,12.18,0,0,1,12.44-12.35c4.47,0,7.25,1.5,9.47,4l-4.12,4.43a6.93,6.93,0,0,0-5.4-2.61c-3.36,0-5.75,3-5.75,6.46v.09c0,3.63,2.34,6.55,6,6.55,2.26,0,3.8-1,5.44-2.53l3.94,4A12,12,0,0,1,164,39.41Z" class="path-6" fill-rule="evenodd"></path><path d="M191.51,38.87V36.31a9.15,9.15,0,0,1-7.17,3c-4.47,0-8.15-2.57-8.15-7.26V32c0-5.18,3.94-7.57,9.56-7.57a16.74,16.74,0,0,1,5.8,1V25c0-2.79-1.72-4.34-5.09-4.34a17.57,17.57,0,0,0-6.55,1.28l-1.68-5.13a21,21,0,0,1,9.21-1.9c7.34,0,10.57,3.8,10.57,10.22V38.87Zm.13-9.55a10.3,10.3,0,0,0-4.29-.89c-2.88,0-4.65,1.15-4.65,3.27v.09c0,1.82,1.5,2.88,3.67,2.88,3.15,0,5.27-1.73,5.27-4.16Z" class="path-7" fill-rule="evenodd"></path><path d="M217.49,39.32a9.1,9.1,0,0,1-7.39-3.54V46h-6.73V15.15h6.73v3.41a8.7,8.7,0,0,1,7.39-3.85c5.53,0,10.8,4.34,10.8,12.26v.09C228.29,35,223.11,39.32,217.49,39.32ZM221.56,27c0-3.94-2.66-6.55-5.8-6.55S210,23,210,27v.09c0,3.94,2.61,6.55,5.75,6.55s5.8-2.57,5.8-6.55Z" class="path-8" fill-rule="evenodd"></path><path d="M232.93,12.54v-6H240v6Zm.18,26.33V15.15h6.73V38.87Z" class="path-9" fill-rule="evenodd"></path><path d="M253.73,39.27c-4.11,0-6.9-1.63-6.9-7.12V20.91H244V15.15h2.83V9.09h6.73v6.06h5.57v5.76h-5.57V31c0,1.55.66,2.3,2.16,2.3A6.84,6.84,0,0,0,259,32.5v5.4A9.9,9.9,0,0,1,253.73,39.27Z" class="path-10" fill-rule="evenodd"></path><path d="M277.55,38.87V36.31a9.15,9.15,0,0,1-7.18,3c-4.46,0-8.14-2.57-8.14-7.26V32c0-5.18,3.94-7.57,9.56-7.57a16.74,16.74,0,0,1,5.8,1V25c0-2.79-1.73-4.34-5.09-4.34A17.57,17.57,0,0,0,266,21.92l-1.68-5.13a20.94,20.94,0,0,1,9.2-1.9c7.35,0,10.58,3.8,10.58,10.22V38.87Zm.13-9.55a10.31,10.31,0,0,0-4.3-.89c-2.87,0-4.64,1.15-4.64,3.27v.09c0,1.82,1.5,2.88,3.67,2.88,3.14,0,5.27-1.73,5.27-4.16Z" class="path-11" fill-rule="evenodd"></path><path d="M289.72,38.87V6.57h6.72v32.3Z" class="path-12" fill-rule="evenodd"></path><path d="M302.06,38.87V31.79h7.17v7.08Z" class="path-13" fill-rule="evenodd"></path></svg>
</p>
<hr />
<p class="align-center">
<h3>License Code</h3>
</p>
<p class="mgb-1x">
<h1>{{ licenseCode }}</h1>
</p>
<p class="email-note">
This is an automatically generated email please do not reply to
this email. If you face any issues, please contact us at <a href="mailto:{{ successEmail }}">{{ successEmail }}</a> or call <u>{{ successPhoneNumber }}</u></p>
</td>
</tr>
</table>
</td>
</tr>
<!-- END MAIN CONTENT AREA -->
</table>
<!-- END CENTERED WHITE CONTAINER -->
<!-- START FOOTER -->
<div class="footer">
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tr>
<td class="content-block powered-by">
Powered by <a href="http://htmlemail.io">Bigcapital.com</a>.
</td>
</tr>
</table>
</div>
<!-- END FOOTER -->
</div>
</td>
<td>&nbsp;</td>
</tr>
</table>
</body>
</html>

View File

@@ -391,8 +391,10 @@
</tr> </tr>
</tbody> </tbody>
</table> </table>
<p>If this was a mistake, just ignore this email and nothing will happen.</p> <p>If you did not make this request, please contact us or ignore this message.</p>
<p class="email-note">This is an automatically generated email please do not reply to this email.</p> <p class="email-note">
This is an automatically generated email please do not reply to
this email. If you face any issues, please contact us at {{ contact_us_email }}</p>
</td> </td>
</tr> </tr>
</table> </table>

View File

@@ -0,0 +1,407 @@
<!doctype html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Bigcapital | Reset your password</title>
<style>
/* -------------------------------------
GLOBAL RESETS
------------------------------------- */
img {
border: none;
-ms-interpolation-mode: bicubic;
max-width: 100%;
}
body {
background-color: #f6f6f6;
font-family: sans-serif;
-webkit-font-smoothing: antialiased;
font-size: 14px;
line-height: 1.4;
margin: 0;
padding: 0;
-ms-text-size-adjust: 100%;
-webkit-text-size-adjust: 100%;
}
table {
border-collapse: separate;
mso-table-lspace: 0pt;
mso-table-rspace: 0pt;
width: 100%; }
table td {
font-family: sans-serif;
font-size: 14px;
vertical-align: top;
}
/* -------------------------------------
BODY & CONTAINER
------------------------------------- */
.body {
background-color: #f6f6f6;
width: 100%;
}
/* Set a max-width, and make it display as block so it will automatically stretch to that width, but will also shrink down on a phone or something */
.container {
display: block;
margin: 0 auto !important;
/* makes it centered */
max-width: 580px;
padding: 10px;
width: 580px;
}
/* This should also be a block element, so that it will fill 100% of the .container */
.content {
box-sizing: border-box;
display: block;
margin: 0 auto;
max-width: 580px;
padding: 10px;
}
/* -------------------------------------
HEADER, FOOTER, MAIN
------------------------------------- */
.main {
background: #ffffff;
border-radius: 3px;
width: 100%;
}
.wrapper {
box-sizing: border-box;
padding: 20px;
}
.content-block {
padding-bottom: 10px;
padding-top: 10px;
}
.footer {
clear: both;
margin-top: 10px;
text-align: center;
width: 100%;
}
.footer td,
.footer p,
.footer span,
.footer a {
color: #999999;
font-size: 12px;
text-align: center;
}
/* -------------------------------------
TYPOGRAPHY
------------------------------------- */
h1,
h2,
h3,
h4 {
color: #000000;
font-family: sans-serif;
font-weight: bold;
line-height: 1.4;
margin: 0;
margin-bottom: 0;
}
h1 {
font-size: 35px;
font-weight: 300;
text-align: center;
text-transform: capitalize;
}
p,
ul,
ol {
font-family: sans-serif;
font-size: 14px;
font-weight: normal;
margin: 0;
margin-bottom: 15px;
}
p li,
ul li,
ol li {
list-style-position: inside;
margin-left: 5px;
}
a {
color: #3498db;
text-decoration: underline;
}
/* -------------------------------------
BUTTONS
------------------------------------- */
.btn {
box-sizing: border-box;
width: 100%;
}
.btn > tbody > tr > td {
padding-bottom: 15px; }
.btn table {
width: auto;
}
.btn table td {
background-color: #ffffff;
border-radius: 5px;
text-align: center;
}
.btn a {
background-color: #ffffff;
border: solid 1px #3498db;
border-radius: 5px;
box-sizing: border-box;
color: #3498db;
cursor: pointer;
display: inline-block;
font-size: 14px;
font-weight: bold;
margin: 0;
padding: 12px 25px;
text-decoration: none;
text-transform: capitalize;
}
.btn-primary table td {
background-color: #2d95fd;
}
.btn-primary a {
background-color: #2d95fd;
border-color: #2d95fd;
color: #ffffff;
}
/* -------------------------------------
OTHER STYLES THAT MIGHT BE USEFUL
------------------------------------- */
.last {
margin-bottom: 0;
}
.first {
margin-top: 0;
}
.align-center {
text-align: center;
}
.align-right {
text-align: right;
}
.align-left {
text-align: left;
}
.clear {
clear: both;
}
.mt0 {
margin-top: 0;
}
.mb0 {
margin-bottom: 0;
}
.mb4{
margin-bottom: 4rem;
}
.preheader {
color: transparent;
display: none;
height: 0;
max-height: 0;
max-width: 0;
opacity: 0;
overflow: hidden;
mso-hide: all;
visibility: hidden;
width: 0;
}
.powered-by a {
text-decoration: none;
}
hr {
border: 0;
border-bottom: 1px solid #f6f6f6;
margin: 20px 0;
}
/* -------------------------------------
RESPONSIVE AND MOBILE FRIENDLY STYLES
------------------------------------- */
@media only screen and (max-width: 620px) {
table[class=body] h1 {
font-size: 28px !important;
margin-bottom: 10px !important;
}
table[class=body] p,
table[class=body] ul,
table[class=body] ol,
table[class=body] td,
table[class=body] span,
table[class=body] a {
font-size: 16px !important;
}
table[class=body] .wrapper,
table[class=body] .article {
padding: 10px !important;
}
table[class=body] .content {
padding: 0 !important;
}
table[class=body] .container {
padding: 0 !important;
width: 100% !important;
}
table[class=body] .main {
border-left-width: 0 !important;
border-radius: 0 !important;
border-right-width: 0 !important;
}
table[class=body] .btn table {
width: 100% !important;
}
table[class=body] .btn a {
width: 100% !important;
}
table[class=body] .img-responsive {
height: auto !important;
max-width: 100% !important;
width: auto !important;
}
}
/* -------------------------------------
PRESERVE THESE STYLES IN THE HEAD
------------------------------------- */
@media all {
.ExternalClass {
width: 100%;
}
.ExternalClass,
.ExternalClass p,
.ExternalClass span,
.ExternalClass font,
.ExternalClass td,
.ExternalClass div {
line-height: 100%;
}
.apple-link a {
color: inherit !important;
font-family: inherit !important;
font-size: inherit !important;
font-weight: inherit !important;
line-height: inherit !important;
text-decoration: none !important;
}
#MessageViewBody a {
color: inherit;
text-decoration: none;
font-size: inherit;
font-family: inherit;
font-weight: inherit;
line-height: inherit;
}
.btn-primary table td:hover {
background-color: #004dd0 !important;
}
.btn-primary a:hover {
background-color: #004dd0 !important;
border-color: #004dd0 !important;
}
}
[data-icon="bigcapital"] path {
fill: #004dd0;
}
[data-icon='bigcapital'] .path-1,
[data-icon='bigcapital'] .path-13 {
fill: #2d95fd;
}
</style>
</head>
<body class="">
<span class="preheader">This is preheader text. Some clients will show this text as a preview.</span>
<table role="presentation" border="0" cellpadding="0" cellspacing="0" class="body">
<tr>
<td>&nbsp;</td>
<td class="container">
<div class="content">
<!-- START CENTERED WHITE CONTAINER -->
<table role="presentation" class="main">
<!-- START MAIN CONTENT AREA -->
<tr>
<td class="wrapper">
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tr>
<td>
<p class="align-center">
<img src="cid:bigcapital_logo" />
</p>
<hr />
<p class="align-center">
<h3>Hi {{ firstName }}, Welcome to Bigcapital, </h3>
</p>
<p class="mgb-1x">
Your organization Id: <strong>{{ organizationId }}</strong>
</p>
<p class="mgb-1x">We are available to help you get started and answer any questions you may have. You can also email <a href="mailto:{{ successEmail }}">{{ successEmail }}</a> or call <u>{{ successPhoneNumber }}</u> about your set-up questions.</p>
<p class="mgb-2-5x">Thank you for trusting Bigcapital Software for your business needs. We look forward to serving you!</p>
</td>
</tr>
</table>
</td>
</tr>
<!-- END MAIN CONTENT AREA -->
</table>
<!-- END CENTERED WHITE CONTAINER -->
<!-- START FOOTER -->
<div class="footer">
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tr>
<td class="content-block powered-by">
Made by Bigcapital Technologies, Inc
</td>
</tr>
</table>
</div>
<!-- END FOOTER -->
</div>
</td>
<td>&nbsp;</td>
</tr>
</table>
</body>
</html>

View File

@@ -1,6 +1,6 @@
{ {
"name": "@bigcapital/webapp", "name": "@bigcapital/webapp",
"version": "0.9.6", "version": "1.7.1",
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
"dependencies": { "dependencies": {
@@ -1227,9 +1227,9 @@
} }
}, },
"@blueprintjs-formik/select": { "@blueprintjs-formik/select": {
"version": "0.2.4", "version": "0.2.3",
"resolved": "https://registry.npmjs.org/@blueprintjs-formik/select/-/select-0.2.4.tgz", "resolved": "https://registry.npmjs.org/@blueprintjs-formik/select/-/select-0.2.3.tgz",
"integrity": "sha512-zB28/hLkuO5zZXkjFmqfiVDGW+uvj9b8e6kHh9aOfY70edSFIfw3bj+NYR7BaDZoIYu3KuZQDFGqgs23ua5Z1g==", "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.3.3", "@blueprintjs-formik/core": "^0.3.3",
"@blueprintjs-formik/datetime": "^0.3.4", "@blueprintjs-formik/datetime": "^0.3.4",
"@blueprintjs-formik/select": "^0.2.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

@@ -5,20 +5,59 @@ import { MenuItem, Button } from '@blueprintjs/core';
import { FSelect } from '../Forms'; import { FSelect } from '../Forms';
/** /**
* Branch select field. *
* @param {*} param0 * @param {*} query
* @returns {JSX.Element} * @param {*} branch
* @param {*} _index
* @param {*} exactMatch
* @returns
*/ */
export function BranchSelect({ branches, ...rest }) { const branchItemPredicate = (query, branch, _index, exactMatch) => {
const normalizedTitle = branch.name.toLowerCase();
const normalizedQuery = query.toLowerCase();
if (exactMatch) {
return normalizedTitle === normalizedQuery;
} else {
return `${branch.code}. ${normalizedTitle}`.indexOf(normalizedQuery) >= 0;
}
};
/**
*
* @param {*} film
* @param {*} param1
* @returns
*/
const branchItemRenderer = (branch, { handleClick, modifiers, query }) => {
const text = `${branch.name}`;
return ( return (
<FSelect <MenuItem
valueAccessor={'id'} active={modifiers.active}
textAccessor={'name'} disabled={modifiers.disabled}
labelAccessor={'code'} label={branch.code}
{...rest} key={branch.id}
items={branches} onClick={handleClick}
text={text}
/> />
); );
};
const branchSelectProps = {
itemPredicate: branchItemPredicate,
itemRenderer: branchItemRenderer,
valueAccessor: 'id',
labelAccessor: 'name',
};
/**
*
* @param {*} param0
* @returns
*/
export function BranchSelect({ branches, ...rest }) {
return <FSelect {...branchSelectProps} {...rest} items={branches} />;
} }
/** /**

View File

@@ -4,7 +4,6 @@ import * as R from 'ramda';
import { ButtonLink } from '../Button'; import { ButtonLink } from '../Button';
import withDrawerActions from '@/containers/Drawer/withDrawerActions'; import withDrawerActions from '@/containers/Drawer/withDrawerActions';
import { DRAWERS } from '@/constants/drawers';
function CustomerDrawerLinkComponent({ function CustomerDrawerLinkComponent({
// #ownProps // #ownProps
@@ -17,7 +16,7 @@ function CustomerDrawerLinkComponent({
}) { }) {
// Handle view customer drawer. // Handle view customer drawer.
const handleCustomerDrawer = (event) => { const handleCustomerDrawer = (event) => {
openDrawer(DRAWERS.CUSTOMER_DETAILS, { customerId }); openDrawer('customer-detail-drawer', { customerId });
event.preventDefault(); event.preventDefault();
}; };

View File

@@ -0,0 +1,119 @@
// @ts-nocheck
import React, { useCallback, useState, useEffect, useMemo } from 'react';
import { FormattedMessage as T } from '@/components';
import intl from 'react-intl-universal';
import * as R from 'ramda';
import { MenuItem, Button } from '@blueprintjs/core';
import { Select } from '@blueprintjs/select';
import classNames from 'classnames';
import { CLASSES } from '@/constants/classes';
import {
itemPredicate,
handleContactRenderer,
createNewItemRenderer,
createNewItemFromQuery,
} from './utils';
import withDrawerActions from '@/containers/Drawer/withDrawerActions';
import { DRAWERS } from '@/constants/drawers';
function CustomerSelectFieldRoot({
// #withDrawerActions
openDrawer,
// #ownProps
contacts,
initialContactId,
selectedContactId,
defaultSelectText = <T id={'select_contact'} />,
onContactSelected,
popoverFill = false,
disabled = false,
allowCreate,
buttonProps,
...restProps
}) {
const localContacts = useMemo(
() =>
contacts.map((contact) => ({
...contact,
_id: `${contact.id}_${contact.contact_type}`,
})),
[contacts],
);
const initialContact = useMemo(
() => contacts.find((a) => a.id === initialContactId),
[initialContactId, contacts],
);
const [selecetedContact, setSelectedContact] = useState(
initialContact || null,
);
useEffect(() => {
if (typeof selectedContactId !== 'undefined') {
const account = selectedContactId
? contacts.find((a) => a.id === selectedContactId)
: null;
setSelectedContact(account);
}
}, [selectedContactId, contacts, setSelectedContact]);
const handleContactSelect = useCallback(
(contact) => {
if (contact.id) {
setSelectedContact({ ...contact });
onContactSelected && onContactSelected(contact);
} else {
openDrawer(DRAWERS.QUICK_CREATE_CUSTOMER);
}
},
[setSelectedContact, onContactSelected, openDrawer],
);
// Maybe inject create new item props to suggest component.
const maybeCreateNewItemRenderer = allowCreate ? createNewItemRenderer : null;
const maybeCreateNewItemFromQuery = allowCreate
? createNewItemFromQuery
: null;
return (
<Select
items={localContacts}
noResults={<MenuItem disabled={true} text={<T id={'no_results'} />} />}
itemRenderer={handleContactRenderer}
itemPredicate={itemPredicate}
filterable={true}
disabled={disabled}
onItemSelect={handleContactSelect}
popoverProps={{ minimal: true, usePortal: !popoverFill }}
className={classNames(CLASSES.FORM_GROUP_LIST_SELECT, {
[CLASSES.SELECT_LIST_FILL_POPOVER]: popoverFill,
})}
inputProps={{
placeholder: intl.get('filter_'),
}}
createNewItemRenderer={maybeCreateNewItemRenderer}
createNewItemFromQuery={maybeCreateNewItemFromQuery}
createNewItemPosition={'top'}
{...restProps}
>
<Button
disabled={disabled}
text={
selecetedContact ? selecetedContact.display_name : defaultSelectText
}
{...buttonProps}
/>
</Select>
);
}
export const CustomerSelectField = R.compose(withDrawerActions)(
CustomerSelectFieldRoot,
);

View File

@@ -1,48 +0,0 @@
// @ts-nocheck
import React from 'react';
import * as R from 'ramda';
import { createNewItemFromQuery, createNewItemRenderer } from './utils';
import { FSelect } from '../Forms';
import withDrawerActions from '@/containers/Drawer/withDrawerActions';
import { DRAWERS } from '@/constants/drawers';
/**
* Customer select field.
* @returns {React.ReactNode}
*/
function CustomerSelectRoot({
// #withDrawerActions
openDrawer,
// #ownProps
items,
allowCreate,
...props
}) {
// Maybe inject create new item props to suggest component.
const maybeCreateNewItemRenderer = allowCreate ? createNewItemRenderer : null;
const maybeCreateNewItemFromQuery = allowCreate
? createNewItemFromQuery
: null;
// Handles the create item click.
const handleCreateItemClick = () => {
openDrawer(DRAWERS.QUICK_CREATE_CUSTOMER);
};
return (
<FSelect
items={items}
textAccessor={'display_name'}
labelAccessor={'code'}
valueAccessor={'id'}
popoverProps={{ minimal: true, usePortal: true, inline: false }}
createNewItemRenderer={maybeCreateNewItemRenderer}
createNewItemFromQuery={maybeCreateNewItemFromQuery}
onCreateItemSelect={handleCreateItemClick}
{...props}
/>
);
}
export const CustomersSelect = R.compose(withDrawerActions)(CustomerSelectRoot);

View File

@@ -1,3 +1,3 @@
// @ts-nocheck // @ts-nocheck
export * from './CustomerSelectField';
export * from './CustomerDrawerLink'; export * from './CustomerDrawerLink';
export * from './CustomersSelect';

View File

@@ -31,28 +31,28 @@ import { DRAWERS } from '@/constants/drawers';
export default function DrawersContainer() { export default function DrawersContainer() {
return ( return (
<div> <div>
<AccountDrawer name={DRAWERS.ACCOUNT_DETAILS} /> <AccountDrawer name={DRAWERS.ACCOUNT} />
<ManualJournalDrawer name={DRAWERS.JOURNAL_DETAILS} /> <ManualJournalDrawer name={DRAWERS.JOURNAL} />
<ExpenseDrawer name={DRAWERS.EXPENSE_DETAILS} /> <ExpenseDrawer name={DRAWERS.EXPENSE} />
<BillDrawer name={DRAWERS.BILL_DETAILS} /> <BillDrawer name={DRAWERS.BILL} />
<InvoiceDetailDrawer name={DRAWERS.INVOICE_DETAILS} /> <InvoiceDetailDrawer name={DRAWERS.INVOICE} />
<EstimateDetailDrawer name={DRAWERS.ESTIMATE_DETAILS} /> <EstimateDetailDrawer name={DRAWERS.ESTIMATE} />
<ReceiptDetailDrawer name={DRAWERS.RECEIPT_DETAILS} /> <ReceiptDetailDrawer name={DRAWERS.RECEIPT} />
<PaymentReceiveDetailDrawer name={DRAWERS.PAYMENT_RECEIVE_DETAILS} /> <PaymentReceiveDetailDrawer name={DRAWERS.PAYMENT_RECEIVE} />
<PaymentMadeDetailDrawer name={DRAWERS.PAYMENT_MADE_DETAILS} /> <PaymentMadeDetailDrawer name={DRAWERS.PAYMENT_MADE} />
<ItemDetailDrawer name={DRAWERS.ITEM_DETAILS} /> <ItemDetailDrawer name={DRAWERS.ITEM} />
<CustomerDetailsDrawer name={DRAWERS.CUSTOMER_DETAILS} /> <CustomerDetailsDrawer name={DRAWERS.CUSTOMER} />
<VendorDetailsDrawer name={DRAWERS.VENDOR_DETAILS} /> <VendorDetailsDrawer name={DRAWERS.VENDOR} />
<InventoryAdjustmentDetailDrawer name={DRAWERS.INVENTORY_ADJUSTMENT_DETAILS} /> <InventoryAdjustmentDetailDrawer name={DRAWERS.INVENTORY_ADJUSTMENT} />
<CashflowTransactionDetailDrawer name={DRAWERS.CASHFLOW_TRNASACTION_DETAILS} /> <CashflowTransactionDetailDrawer name={DRAWERS.CASHFLOW_TRNASACTION} />
<QuickCreateCustomerDrawer name={DRAWERS.QUICK_CREATE_CUSTOMER} /> <QuickCreateCustomerDrawer name={DRAWERS.QUICK_CREATE_CUSTOMER} />
<QuickCreateItemDrawer name={DRAWERS.QUICK_CREATE_ITEM} /> <QuickCreateItemDrawer name={DRAWERS.QUICK_CREATE_ITEM} />
<QuickWriteVendorDrawer name={DRAWERS.QUICK_WRITE_VENDOR} /> <QuickWriteVendorDrawer name={DRAWERS.QUICK_WRITE_VENDOR} />
<CreditNoteDetailDrawer name={DRAWERS.CREDIT_NOTE_DETAILS} /> <CreditNoteDetailDrawer name={DRAWERS.CREDIT_NOTE} />
<VendorCreditDetailDrawer name={DRAWERS.VENDOR_CREDIT_DETAILS} /> <VendorCreditDetailDrawer name={DRAWERS.VENDOR_CREDIT} />
<RefundCreditNoteDetailDrawer name={DRAWERS.REFUND_CREDIT_NOTE_DETAILS} /> <RefundCreditNoteDetailDrawer name={DRAWERS.REFUND_CREDIT_NOTE} />
<RefundVendorCreditDetailDrawer name={DRAWERS.REFUND_VENDOR_CREDIT_DETAILS} /> <RefundVendorCreditDetailDrawer name={DRAWERS.REFUND_VENDOR_CREDIT} />
<WarehouseTransferDetailDrawer name={DRAWERS.WAREHOUSE_TRANSFER_DETAILS} /> <WarehouseTransferDetailDrawer name={DRAWERS.WAREHOUSE_TRANSFER} />
</div> </div>
); );
} }

View File

@@ -16,7 +16,7 @@ export function FSelect({ ...props }) {
/> />
); );
}; };
return <Select input={input} fill={true} {...props} />; return <Select input={input} {...props} fill={true} />;
} }
const SelectButton = styled(Button)` const SelectButton = styled(Button)`

View File

@@ -1,27 +0,0 @@
// @ts-nocheck
import React from 'react';
import intl from 'react-intl-universal';
import { Button } from '@blueprintjs/core';
import { Icon } from '@/components';
export function FormWarehouseSelectButton({ text }) {
return (
<Button
text={intl.get('page_form.warehouse_button.label', { text })}
minimal={true}
small={true}
icon={<Icon icon={'warehouse-16'} iconSize={16} />}
/>
);
}
export function FormBranchSelectButton({ text }) {
return (
<Button
text={intl.get('page_form.branch_button.label', { text })}
minimal={true}
small={true}
icon={<Icon icon={'branch-16'} iconSize={16} />}
/>
);
}

View File

@@ -1,4 +1,3 @@
// @ts-nocheck // @ts-nocheck
export * from './FormTopbar'; export * from './FormTopbar';
export * from './FormTopbarSelectInputs';
export * from './PageFormBigNumber'; export * from './PageFormBigNumber';

View File

@@ -4,7 +4,6 @@ import * as R from 'ramda';
import { ButtonLink } from '../Button'; import { ButtonLink } from '../Button';
import withDrawerActions from '@/containers/Drawer/withDrawerActions'; import withDrawerActions from '@/containers/Drawer/withDrawerActions';
import { DRAWERS } from '@/constants/drawers';
function VendorDrawerLinkComponent({ function VendorDrawerLinkComponent({
// #ownProps // #ownProps
@@ -17,7 +16,7 @@ function VendorDrawerLinkComponent({
}) { }) {
// Handle view customer drawer. // Handle view customer drawer.
const handleVendorDrawer = (event) => { const handleVendorDrawer = (event) => {
openDrawer(DRAWERS.VENDOR_DETAILS, { vendorId }); openDrawer('vendor-detail-drawer', { vendorId });
event.preventDefault(); event.preventDefault();
}; };

View File

@@ -0,0 +1,118 @@
// @ts-nocheck
import React, { useCallback, useState, useEffect, useMemo } from 'react';
import { FormattedMessage as T } from '@/components';
import intl from 'react-intl-universal';
import * as R from 'ramda';
import { MenuItem, Button } from '@blueprintjs/core';
import { Select } from '@blueprintjs/select';
import classNames from 'classnames';
import { CLASSES } from '@/constants/classes';
import {
itemPredicate,
handleContactRenderer,
createNewItemFromQuery,
createNewItemRenderer,
} from './utils';
import withDrawerActions from '@/containers/Drawer/withDrawerActions';
import { DRAWERS } from '@/constants/drawers';
function VendorSelectFieldRoot({
// #withDrawerActions
openDrawer,
// #ownProps
contacts,
initialContactId,
selectedContactId,
defaultSelectText = <T id={'select_contact'} />,
onContactSelected,
popoverFill = false,
disabled = false,
allowCreate,
buttonProps,
...restProps
}) {
const localContacts = useMemo(
() =>
contacts.map((contact) => ({
...contact,
_id: `${contact.id}_${contact.contact_type}`,
})),
[contacts],
);
const initialContact = useMemo(
() => contacts.find((a) => a.id === initialContactId),
[initialContactId, contacts],
);
const [selecetedContact, setSelectedContact] = useState(
initialContact || null,
);
useEffect(() => {
if (typeof selectedContactId !== 'undefined') {
const account = selectedContactId
? contacts.find((a) => a.id === selectedContactId)
: null;
setSelectedContact(account);
}
}, [selectedContactId, contacts, setSelectedContact]);
const handleContactSelect = useCallback(
(contact) => {
if (contact.id) {
setSelectedContact({ ...contact });
onContactSelected && onContactSelected(contact);
} else {
openDrawer(DRAWERS.QUICK_WRITE_VENDOR);
}
},
[setSelectedContact, onContactSelected, openDrawer],
);
// Maybe inject create new item props to suggest component.
const maybeCreateNewItemRenderer = allowCreate ? createNewItemRenderer : null;
const maybeCreateNewItemFromQuery = allowCreate
? createNewItemFromQuery
: null;
return (
<Select
items={localContacts}
noResults={<MenuItem disabled={true} text={<T id={'no_results'} />} />}
itemRenderer={handleContactRenderer}
itemPredicate={itemPredicate}
filterable={true}
disabled={disabled}
onItemSelect={handleContactSelect}
popoverProps={{ minimal: true, usePortal: !popoverFill }}
className={classNames(CLASSES.FORM_GROUP_LIST_SELECT, {
[CLASSES.SELECT_LIST_FILL_POPOVER]: popoverFill,
})}
inputProps={{
placeholder: intl.get('filter_'),
}}
createNewItemRenderer={maybeCreateNewItemRenderer}
createNewItemFromQuery={maybeCreateNewItemFromQuery}
createNewItemPosition={'top'}
{...restProps}
>
<Button
disabled={disabled}
text={
selecetedContact ? selecetedContact.display_name : defaultSelectText
}
{...buttonProps}
/>
</Select>
);
}
export const VendorSelectField = R.compose(withDrawerActions)(
VendorSelectFieldRoot,
);

View File

@@ -1,49 +0,0 @@
// @ts-nocheck
import React from 'react';
import * as R from 'ramda';
import withDrawerActions from '@/containers/Drawer/withDrawerActions';
import { createNewItemFromQuery, createNewItemRenderer } from './utils';
import { FSelect } from '../Forms';
import { DRAWERS } from '@/constants/drawers';
/**
* Vendor select.
* @returns {React.ReactNode}
*/
function VendorsSelectRoot({
// #withDrawerActions
openDrawer,
// #ownProps
items,
allowCreate,
...restProps
}) {
// Maybe inject create new item props to suggest component.
const maybeCreateNewItemRenderer = allowCreate ? createNewItemRenderer : null;
const maybeCreateNewItemFromQuery = allowCreate
? createNewItemFromQuery
: null;
// Handles the create item click.
const handleCreateItemClick = () => {
openDrawer(DRAWERS.QUICK_WRITE_VENDOR);
};
return (
<FSelect
items={items}
textAccessor={'display_name'}
labelAccessor={'code'}
valueAccessor={'id'}
popoverProps={{ minimal: true, usePortal: true, inline: false }}
createNewItemRenderer={maybeCreateNewItemRenderer}
createNewItemFromQuery={maybeCreateNewItemFromQuery}
onCreateItemSelect={handleCreateItemClick}
{...restProps}
/>
);
}
export const VendorsSelect = R.compose(withDrawerActions)(VendorsSelectRoot);

View File

@@ -1,3 +1,3 @@
// @ts-nocheck // @ts-nocheck
export * from './VendorDrawerLink' export * from './VendorDrawerLink'
export * from './VendorsSelect'; export * from './VendorSelectField'

View File

@@ -1,21 +1,75 @@
// @ts-nocheck // @ts-nocheck
import React from 'react'; import React from 'react';
import { MenuItem, Button } from '@blueprintjs/core';
import { FSelect } from '../Forms'; import { FSelect } from '../Forms';
/** /**
* Warehouse select field. *
* @param {*} query
* @param {*} warehouse
* @param {*} _index
* @param {*} exactMatch
* @returns
*/
const warehouseItemPredicate = (query, warehouse, _index, exactMatch) => {
const normalizedTitle = warehouse.name.toLowerCase();
const normalizedQuery = query.toLowerCase();
if (exactMatch) {
return normalizedTitle === normalizedQuery;
} else {
return (
`${warehouse.code}. ${normalizedTitle}`.indexOf(normalizedQuery) >= 0
);
}
};
/**
*
* @param {*} film
* @param {*} param1
* @returns
*/
const warehouseItemRenderer = (
warehouse,
{ handleClick, modifiers, query },
) => {
const text = `${warehouse.name}`;
return (
<MenuItem
active={modifiers.active}
disabled={modifiers.disabled}
label={warehouse.code}
key={warehouse.id}
onClick={handleClick}
text={text}
/>
);
};
const warehouseSelectProps = {
itemPredicate: warehouseItemPredicate,
itemRenderer: warehouseItemRenderer,
valueAccessor: 'id',
labelAccessor: 'name',
};
/**
*
* @param {*} param0 * @param {*} param0
* @returns * @returns
*/ */
export function WarehouseSelect({ warehouses, ...rest }) { export function WarehouseSelect({ warehouses, ...rest }) {
return ( return <FSelect {...warehouseSelectProps} {...rest} items={warehouses} />;
<FSelect }
valueAccessor={'id'}
labelAccessor={'code'} /**
textAccessor={'name'} *
popoverProps={{ minimal: true, usePortal: true, inline: false }} * @param {*} param0
{...rest} * @returns
items={warehouses} */
/> export function WarehouseSelectButton({ label, ...rest }) {
); return <Button text={label} />;
} }

View File

@@ -0,0 +1,7 @@
// @ts-nocheck
import intl from 'react-intl-universal';
export default [
{ name: intl.get('decrement'), value: 'decrement' },
{ name: intl.get('increment'), value: 'increment' },
]

View File

@@ -1,25 +1,25 @@
// @ts-nocheck // @ts-nocheck
export enum DRAWERS { export enum DRAWERS {
ACCOUNT_DETAILS = 'account-drawer', ACCOUNT = 'account-drawer',
JOURNAL_DETAILS = 'journal-drawer', JOURNAL = 'journal-drawer',
EXPENSE_DETAILS = 'expense-drawer', EXPENSE = 'expense-drawer',
BILL_DETAILS = 'bill-drawer', BILL = 'bill-drawer',
INVOICE_DETAILS = 'invoice-detail-drawer', INVOICE = 'invoice-detail-drawer',
RECEIPT_DETAILS = 'receipt-detail-drawer', RECEIPT = 'receipt-detail-drawer',
PAYMENT_RECEIVE_DETAILS = 'payment-receive-detail-drawer', PAYMENT_RECEIVE = 'payment-receive-detail-drawer',
PAYMENT_MADE_DETAILS = 'payment-made-drawer', PAYMENT_MADE = 'payment-made-drawer',
ESTIMATE_DETAILS = 'estimate-detail-drawer', ESTIMATE = 'estimate-detail-drawer',
ITEM_DETAILS = 'item-detail-drawer', ITEM = 'item-detail-drawer',
CUSTOMER_DETAILS = 'customer-detail-drawer', CUSTOMER = 'customer-detail-drawer',
VENDOR_DETAILS = 'vendor-detail-drawer', VENDOR = 'vendor-detail-drawer',
INVENTORY_ADJUSTMENT_DETAILS = 'inventory-adjustment-drawer', INVENTORY_ADJUSTMENT = 'inventory-adjustment-drawer',
CASHFLOW_TRNASACTION_DETAILS = 'cashflow-transaction-drawer', CASHFLOW_TRNASACTION = 'cashflow-transaction-drawer',
QUICK_CREATE_CUSTOMER = 'quick-create-customer', QUICK_CREATE_CUSTOMER = 'quick-create-customer',
QUICK_CREATE_ITEM = 'quick-create-item', QUICK_CREATE_ITEM = 'quick-create-item',
QUICK_WRITE_VENDOR = 'quick-write-vendor', QUICK_WRITE_VENDOR = 'quick-write-vendor',
CREDIT_NOTE_DETAILS = 'credit-note-detail-drawer', CREDIT_NOTE = 'credit-note-detail-drawer',
VENDOR_CREDIT_DETAILS = 'vendor-credit-detail-drawer', VENDOR_CREDIT = 'vendor-credit-detail-drawer',
REFUND_CREDIT_NOTE_DETAILS = 'refund-credit-detail-drawer', REFUND_CREDIT_NOTE = 'refund-credit-detail-drawer',
REFUND_VENDOR_CREDIT_DETAILS = 'refund-vendor-detail-drawer', REFUND_VENDOR_CREDIT = 'refund-vendor-detail-drawer',
WAREHOUSE_TRANSFER_DETAILS = 'warehouse-transfer-detail-drawer', WAREHOUSE_TRANSFER = 'warehouse-transfer-detail-drawer',
} }

View File

@@ -4,6 +4,7 @@ export * from './tableStyle';
export * from './features'; export * from './features';
export * from './cellTypes'; export * from './cellTypes';
export * from './classes'; export * from './classes';
export * from './adjustmentType';
export * from './cashflowOptions'; export * from './cashflowOptions';
export const Align = { Left: 'left', Right: 'right', Center: 'center' }; export const Align = { Left: 'left', Right: 'right', Center: 'center' };

View File

@@ -25,14 +25,13 @@ import {
CashflowAction, CashflowAction,
PreferencesAbility, PreferencesAbility,
} from '@/constants/abilityOption'; } from '@/constants/abilityOption';
import { DialogsName } from './dialogs';
export const SidebarMenu = [ export const SidebarMenu = [
// --------------- // ---------------
// # Homepage // # Homepage
// --------------- // ---------------
{ {
text: <T id={'sidebar.homepage'} />, text: <T id={'homepage'} />,
type: ISidebarMenuItemType.Link, type: ISidebarMenuItemType.Link,
disabled: false, disabled: false,
href: '/', href: '/',
@@ -42,20 +41,20 @@ export const SidebarMenu = [
// # Sales & Inventory // # Sales & Inventory
// --------------- // ---------------
{ {
text: <T id={'sidebar.sales_inventory'} />, text: <T id={'sales_inventory'} />,
type: ISidebarMenuItemType.Group, type: ISidebarMenuItemType.Group,
children: [ children: [
{ {
text: <T id={'sidebar.items'} />, text: <T id={'items'} />,
type: ISidebarMenuItemType.Overlay, type: ISidebarMenuItemType.Overlay,
overlayId: ISidebarMenuOverlayIds.Items, overlayId: ISidebarMenuOverlayIds.Items,
children: [ children: [
{ {
text: <T id={'sidebar.items'} />, text: <T id={'items'} />,
type: ISidebarMenuItemType.Group, type: ISidebarMenuItemType.Group,
children: [ children: [
{ {
text: <T id={'sidebar.items'} />, text: <T id={'items'} />,
href: '/items', href: '/items',
type: ISidebarMenuItemType.Link, type: ISidebarMenuItemType.Link,
permission: { permission: {
@@ -64,7 +63,7 @@ export const SidebarMenu = [
}, },
}, },
{ {
text: <T id={'sidebar.inventory_adjustments'} />, text: <T id={'inventory_adjustments'} />,
href: '/inventory-adjustments', href: '/inventory-adjustments',
type: ISidebarMenuItemType.Link, type: ISidebarMenuItemType.Link,
permission: { permission: {
@@ -72,6 +71,12 @@ export const SidebarMenu = [
ability: InventoryAdjustmentAction.View, ability: InventoryAdjustmentAction.View,
}, },
}, },
{
text: <T id={'sidebar_warehouse_transfer'} />,
href: '/warehouses-transfers',
type: ISidebarMenuItemType.Link,
feature: Features.Warehouses,
},
{ {
text: <T id={'category_list'} />, text: <T id={'category_list'} />,
href: '/items/categories', href: '/items/categories',
@@ -81,20 +86,14 @@ export const SidebarMenu = [
ability: ItemAction.View, ability: ItemAction.View,
}, },
}, },
{
text: <T id={'sidebar.warehouse_transfer'} />,
href: '/warehouses-transfers',
type: ISidebarMenuItemType.Link,
feature: Features.Warehouses,
},
], ],
}, },
{ {
text: <T id={'sidebar.new_tasks'} />, text: <T id={'New tasks'} />,
type: ISidebarMenuItemType.Group, type: ISidebarMenuItemType.Group,
children: [ children: [
{ {
text: <T id={'sidebar.new_inventory_item'} />, text: <T id={'New inventory item'} />,
href: '/items/new', href: '/items/new',
type: ISidebarMenuItemType.Link, type: ISidebarMenuItemType.Link,
permission: { permission: {
@@ -103,30 +102,32 @@ export const SidebarMenu = [
}, },
}, },
{ {
text: <T id={'sidebar.new_service'} />, text: (
href: '/items/new', <T id={'warehouse_transfer.label.new_warehouse_transfer'} />
type: ISidebarMenuItemType.Link, ),
permission: {
subject: AbilitySubject.Item,
ability: ItemAction.Create,
},
},
{
text: <T id={'sidebar.new_item_category'} />,
href: '/items/categories/new',
type: ISidebarMenuItemType.Dialog,
dialogName: DialogsName.ItemCategoryForm,
permission: {
subject: AbilitySubject.Item,
ability: ItemAction.Create,
},
},
{
text: <T id={'sidebar.new_warehouse_transfer'} />,
href: '/warehouses-transfers/new', href: '/warehouses-transfers/new',
type: ISidebarMenuItemType.Link, type: ISidebarMenuItemType.Link,
feature: Features.Warehouses, feature: Features.Warehouses,
}, },
{
text: <T id={'New service'} />,
href: '/items/new',
type: ISidebarMenuItemType.Link,
permission: {
subject: AbilitySubject.Item,
ability: ItemAction.Create,
},
},
{
text: <T id={'New item category'} />,
href: '/items/categories/new',
type: ISidebarMenuItemType.Dialog,
dialogName: 'item-category-form',
permission: {
subject: AbilitySubject.Item,
ability: ItemAction.Create,
},
},
], ],
}, },
], ],
@@ -137,16 +138,16 @@ export const SidebarMenu = [
// # Sales // # Sales
// --------------- // ---------------
{ {
text: <T id={'sidebar.sales'} />, text: <T id={'sales'} />,
type: ISidebarMenuItemType.Overlay, type: ISidebarMenuItemType.Overlay,
overlayId: ISidebarMenuOverlayIds.Sales, overlayId: ISidebarMenuOverlayIds.Sales,
children: [ children: [
{ {
text: <T id={'sidebar.sales'} />, text: <T id={'sales'} />,
type: ISidebarMenuItemType.Group, type: ISidebarMenuItemType.Group,
children: [ children: [
{ {
text: <T id={'sidebar.estimates'} />, text: <T id={'estimates'} />,
href: '/estimates', href: '/estimates',
type: ISidebarMenuItemType.Link, type: ISidebarMenuItemType.Link,
permission: { permission: {
@@ -155,7 +156,7 @@ export const SidebarMenu = [
}, },
}, },
{ {
text: <T id={'sidebar.invoices'} />, text: <T id={'invoices'} />,
href: '/invoices', href: '/invoices',
type: ISidebarMenuItemType.Link, type: ISidebarMenuItemType.Link,
permission: { permission: {
@@ -164,7 +165,7 @@ export const SidebarMenu = [
}, },
}, },
{ {
text: <T id={'sidebar.receipts'} />, text: <T id={'receipts'} />,
href: '/receipts', href: '/receipts',
type: ISidebarMenuItemType.Link, type: ISidebarMenuItemType.Link,
permission: { permission: {
@@ -173,12 +174,12 @@ export const SidebarMenu = [
}, },
}, },
{ {
text: <T id={'sidebar.credit_notes'} />, text: <T id={'sidebar_credit_note'} />,
href: '/credit-notes', href: '/credit-notes',
type: ISidebarMenuItemType.Link, type: ISidebarMenuItemType.Link,
}, },
{ {
text: <T id={'sidebar.payment_receives'} />, text: <T id={'payment_receives'} />,
href: '/payment-receives', href: '/payment-receives',
type: ISidebarMenuItemType.Link, type: ISidebarMenuItemType.Link,
permission: { permission: {
@@ -189,11 +190,11 @@ export const SidebarMenu = [
], ],
}, },
{ {
text: <T id={'sidebar.new_tasks'} />, text: <T id={'New tasks'} />,
type: ISidebarMenuItemType.Group, type: ISidebarMenuItemType.Group,
children: [ children: [
{ {
text: <T id={'sidebar.new_estimate'} />, text: <T id={'new_estimate'} />,
href: '/estimates/new', href: '/estimates/new',
type: ISidebarMenuItemType.Link, type: ISidebarMenuItemType.Link,
permission: { permission: {
@@ -202,7 +203,7 @@ export const SidebarMenu = [
}, },
}, },
{ {
text: <T id={'sidebar.new_invoice'} />, text: <T id={'new_invoice'} />,
href: '/invoices/new', href: '/invoices/new',
type: ISidebarMenuItemType.Link, type: ISidebarMenuItemType.Link,
permission: { permission: {
@@ -211,7 +212,7 @@ export const SidebarMenu = [
}, },
}, },
{ {
text: <T id={'sidebar.new_receipt'} />, text: <T id={'new_receipt'} />,
href: '/receipts/new', href: '/receipts/new',
type: ISidebarMenuItemType.Link, type: ISidebarMenuItemType.Link,
permission: { permission: {
@@ -220,12 +221,12 @@ export const SidebarMenu = [
}, },
}, },
{ {
text: <T id={'sidebar.new_credit_note'} />, text: <T id={'credit_note.label.new_credit_note'} />,
href: '/credit-notes/new', href: '/credit-notes/new',
type: ISidebarMenuItemType.Link, type: ISidebarMenuItemType.Link,
}, },
{ {
text: <T id={'sidebar.new_payment_receive'} />, text: <T id={'new_payment_receive'} />,
href: '/payment-receives/new', href: '/payment-receives/new',
type: ISidebarMenuItemType.Link, type: ISidebarMenuItemType.Link,
permission: { permission: {
@@ -241,12 +242,12 @@ export const SidebarMenu = [
// # Purchases // # Purchases
// --------------- // ---------------
{ {
text: <T id={'sidebar.purchases'} />, text: <T id={'purchases'} />,
type: ISidebarMenuItemType.Overlay, type: ISidebarMenuItemType.Overlay,
overlayId: ISidebarMenuOverlayIds.Purchases, overlayId: ISidebarMenuOverlayIds.Purchases,
children: [ children: [
{ {
text: <T id={'sidebar.purchases'} />, text: <T id={'purchases'} />,
type: ISidebarMenuItemType.Group, type: ISidebarMenuItemType.Group,
children: [ children: [
{ {
@@ -275,11 +276,11 @@ export const SidebarMenu = [
], ],
}, },
{ {
text: <T id={'sidebar.new_tasks'} />, text: <T id={'New tasks'} />,
type: ISidebarMenuItemType.Group, type: ISidebarMenuItemType.Group,
children: [ children: [
{ {
text: <T id={'sidebar.new_purchase_invoice'} />, text: <T id={'New purchase invoice'} />,
href: '/bills/new', href: '/bills/new',
type: ISidebarMenuItemType.Link, type: ISidebarMenuItemType.Link,
permission: { permission: {
@@ -288,7 +289,7 @@ export const SidebarMenu = [
}, },
}, },
{ {
text: <T id={'sidebar.new_vendor_credit'} />, text: <T id={'vendor_credits.label.new_vendor_credit'} />,
href: '/vendor-credits/new', href: '/vendor-credits/new',
type: ISidebarMenuItemType.Link, type: ISidebarMenuItemType.Link,
permission: { permission: {
@@ -297,7 +298,7 @@ export const SidebarMenu = [
}, },
}, },
{ {
text: <T id={'sidebar.new_payment_made'} />, text: <T id={'new_payment_made'} />,
href: '/payment-mades/new', href: '/payment-mades/new',
type: ISidebarMenuItemType.Link, type: ISidebarMenuItemType.Link,
permission: { permission: {
@@ -313,16 +314,16 @@ export const SidebarMenu = [
// # Contacts // # Contacts
// --------------- // ---------------
{ {
text: <T id={'sidebar.contacts'} />, text: <T id={'contacts'} />,
type: ISidebarMenuItemType.Overlay, type: ISidebarMenuItemType.Overlay,
overlayId: ISidebarMenuOverlayIds.Contacts, overlayId: ISidebarMenuOverlayIds.Contacts,
children: [ children: [
{ {
text: <T id={'sidebar.contacts'} />, text: <T id={'contacts'} />,
type: ISidebarMenuItemType.Group, type: ISidebarMenuItemType.Group,
children: [ children: [
{ {
text: <T id={'sidebar.customers'} />, text: <T id={'customers'} />,
href: '/customers', href: '/customers',
type: ISidebarMenuItemType.Link, type: ISidebarMenuItemType.Link,
permission: { permission: {
@@ -331,7 +332,7 @@ export const SidebarMenu = [
}, },
}, },
{ {
text: <T id={'sidebar.vendors'} />, text: <T id={'vendors'} />,
href: '/vendors', href: '/vendors',
type: ISidebarMenuItemType.Link, type: ISidebarMenuItemType.Link,
permission: { permission: {
@@ -342,11 +343,11 @@ export const SidebarMenu = [
], ],
}, },
{ {
text: <T id={'sidebar.new_tasks'} />, text: <T id={'New tasks'} />,
type: ISidebarMenuItemType.Group, type: ISidebarMenuItemType.Group,
children: [ children: [
{ {
text: <T id={'sidebar.new_customer'} />, text: <T id={'new_customer'} />,
href: '/customers/new', href: '/customers/new',
type: ISidebarMenuItemType.Link, type: ISidebarMenuItemType.Link,
permission: { permission: {
@@ -355,7 +356,7 @@ export const SidebarMenu = [
}, },
}, },
{ {
text: <T id={'sidebar.new_vendor'} />, text: <T id={'new_vendor'} />,
href: '/vendors/new', href: '/vendors/new',
type: ISidebarMenuItemType.Link, type: ISidebarMenuItemType.Link,
permission: { permission: {
@@ -371,20 +372,20 @@ export const SidebarMenu = [
// # Accounting // # Accounting
// --------------- // ---------------
{ {
text: <T id={'sidebar.accounting'} />, text: <T id={'accounting'} />,
type: ISidebarMenuItemType.Group, type: ISidebarMenuItemType.Group,
children: [ children: [
{ {
text: <T id={'sidebar.financial'} />, text: <T id={'financial'} />,
type: ISidebarMenuItemType.Overlay, type: ISidebarMenuItemType.Overlay,
overlayId: ISidebarMenuOverlayIds.Financial, overlayId: ISidebarMenuOverlayIds.Financial,
children: [ children: [
{ {
text: <T id={'sidebar.financial'} />, text: <T id={'financial'} />,
type: ISidebarMenuItemType.Group, type: ISidebarMenuItemType.Group,
children: [ children: [
{ {
text: <T id={'sidebar.accounts_chart'} />, text: <T id={'accounts_chart'} />,
href: '/accounts', href: '/accounts',
type: ISidebarMenuItemType.Link, type: ISidebarMenuItemType.Link,
permission: { permission: {
@@ -393,7 +394,7 @@ export const SidebarMenu = [
}, },
}, },
{ {
text: <T id={'sidebar.manual_journals'} />, text: <T id={'manual_journals'} />,
href: '/manual-journals', href: '/manual-journals',
type: ISidebarMenuItemType.Link, type: ISidebarMenuItemType.Link,
permission: { permission: {
@@ -409,11 +410,11 @@ export const SidebarMenu = [
], ],
}, },
{ {
text: <T id={'sidebar.new_tasks'} />, text: <T id={'New tasks'} />,
type: ISidebarMenuItemType.Group, type: ISidebarMenuItemType.Group,
children: [ children: [
{ {
text: <T id={'sidebar.make_journal_entry'} />, text: <T id={'make_journal_entry'} />,
href: '/make-journal-entry', href: '/make-journal-entry',
type: ISidebarMenuItemType.Link, type: ISidebarMenuItemType.Link,
permission: { permission: {
@@ -440,7 +441,7 @@ export const SidebarMenu = [
type: ISidebarMenuItemType.Group, type: ISidebarMenuItemType.Group,
children: [ children: [
{ {
text: <T id={'sidebar.cash_bank_accounts'} />, text: <T id={'siebar.cashflow.label_cash_and_bank_accounts'} />,
href: '/cashflow-accounts', href: '/cashflow-accounts',
type: ISidebarMenuItemType.Link, type: ISidebarMenuItemType.Link,
permission: { permission: {
@@ -451,45 +452,42 @@ export const SidebarMenu = [
], ],
}, },
{ {
text: <T id={'sidebar.new_tasks'} />, text: <T id={'New tasks'} />,
type: ISidebarMenuItemType.Group, type: ISidebarMenuItemType.Group,
divider: true, divider: true,
children: [ children: [
{ {
text: <T id={'sidebar.add_money_in'} />, text: <T id={'cash_flow.label.add_money_in'} />,
href: '/cashflow-accounts', href: '/cashflow-accounts',
type: ISidebarMenuItemType.Dialog, type: ISidebarMenuItemType.Dialog,
dialogName: DialogsName.MoneyInForm, dialogName: 'money-in',
permission: { permission: {
subject: AbilitySubject.Cashflow, subject: AbilitySubject.Cashflow,
ability: CashflowAction.Create, ability: CashflowAction.Create,
}, },
}, },
{ {
text: <T id={'sidebar.add_money_out'} />, text: <T id={'cash_flow.label.add_money_out'} />,
href: '/cashflow-accounts', href: '/cashflow-accounts',
type: ISidebarMenuItemType.Dialog, type: ISidebarMenuItemType.Dialog,
dialogName: DialogsName.MoneyOutForm,
permission: { permission: {
subject: AbilitySubject.Cashflow, subject: AbilitySubject.Cashflow,
ability: CashflowAction.Create, ability: CashflowAction.Create,
}, },
}, },
{ {
text: <T id={'sidebar.add_cash_account'} />, text: <T id={'cash_flow.label.add_cash_account'} />,
href: '/cashflow-accounts', href: '/cashflow-accounts',
type: ISidebarMenuItemType.Dialog, type: ISidebarMenuItemType.Dialog,
dialogName: DialogsName.AccountForm,
permission: { permission: {
subject: AbilitySubject.Cashflow, subject: AbilitySubject.Cashflow,
ability: CashflowAction.Create, ability: CashflowAction.Create,
}, },
}, },
{ {
text: <T id={'sidebar.add_bank_account'} />, text: <T id={'cash_flow.label.add_bank_account'} />,
href: '/cashflow-accounts', href: '/cashflow-accounts',
type: ISidebarMenuItemType.Dialog, type: ISidebarMenuItemType.Dialog,
dialogName: DialogsName.AccountForm,
permission: { permission: {
subject: AbilitySubject.Cashflow, subject: AbilitySubject.Cashflow,
ability: CashflowAction.Create, ability: CashflowAction.Create,
@@ -503,16 +501,16 @@ export const SidebarMenu = [
// # Expenses // # Expenses
// --------------- // ---------------
{ {
text: <T id={'sidebar.expenses'} />, text: <T id={'expenses'} />,
type: ISidebarMenuItemType.Overlay, type: ISidebarMenuItemType.Overlay,
overlayId: ISidebarMenuOverlayIds.Expenses, overlayId: ISidebarMenuOverlayIds.Expenses,
children: [ children: [
{ {
text: <T id={'sidebar.expenses'} />, text: <T id={'expenses'} />,
type: ISidebarMenuItemType.Group, type: ISidebarMenuItemType.Group,
children: [ children: [
{ {
text: <T id={'sidebar.expenses'} />, text: <T id={'expenses'} />,
href: '/expenses', href: '/expenses',
type: ISidebarMenuItemType.Link, type: ISidebarMenuItemType.Link,
permission: { permission: {
@@ -523,11 +521,11 @@ export const SidebarMenu = [
], ],
}, },
{ {
text: <T id={'sidebar.new_tasks'} />, text: <T id={'New tasks'} />,
type: ISidebarMenuItemType.Group, type: ISidebarMenuItemType.Group,
children: [ children: [
{ {
text: <T id={'sidebar.new_expense'} />, text: <T id={'new_expense'} />,
href: '/expenses/new', href: '/expenses/new',
type: ISidebarMenuItemType.Link, type: ISidebarMenuItemType.Link,
permission: { permission: {
@@ -543,16 +541,16 @@ export const SidebarMenu = [
// # Projects Management // # Projects Management
// --------------------- // ---------------------
// { // {
// text: <T id={'sidebar.projects'} />, // text: 'Projects',
// type: ISidebarMenuItemType.Overlay, // type: ISidebarMenuItemType.Overlay,
// overlayId: ISidebarMenuOverlayIds.Projects, // overlayId: ISidebarMenuOverlayIds.Projects,
// children: [ // children: [
// { // {
// text: <T id={'sidebar.projects'} />, // text: 'Projects',
// type: ISidebarMenuItemType.Group, // type: ISidebarMenuItemType.Group,
// children: [ // children: [
// { // {
// text: <T id={'sidebar.projects'} />, // text: 'Projects',
// href: '/projects', // href: '/projects',
// type: ISidebarMenuItemType.Link, // type: ISidebarMenuItemType.Link,
// permission: { // permission: {
@@ -563,11 +561,11 @@ export const SidebarMenu = [
// ], // ],
// }, // },
// { // {
// text: <T id={'sidebar.new_tasks'} />, // text: <T id={'New tasks'} />,
// type: ISidebarMenuItemType.Group, // type: ISidebarMenuItemType.Group,
// children: [ // children: [
// { // {
// text: <T id={'sidebar.new_project'} />, // text: <T id={'projects.label.new_project'} />,
// type: ISidebarMenuItemType.Dialog, // type: ISidebarMenuItemType.Dialog,
// dialogName: 'project-form', // dialogName: 'project-form',
// permission: { // permission: {
@@ -576,18 +574,18 @@ export const SidebarMenu = [
// }, // },
// }, // },
// { // {
// text: <T id={'sidebar.new_time_entry'} />, // text: <T id={'projects.label.new_time_entry'} />,
// type: ISidebarMenuItemType.Dialog, // type: ISidebarMenuItemType.Dialog,
// dialogName: 'project-time-entry-form', // dialogName: 'project-time-entry-form',
// }, // },
// ], // ],
// }, // },
// { // {
// text: <T id={'sidebar.reports'} />, // text: <T id={'Reports'} />,
// type: ISidebarMenuItemType.Group, // type: ISidebarMenuItemType.Group,
// children: [ // children: [
// { // {
// text: <T id={'sidebar.project_profitability_summary'} />, // text: <T id={'project_profitability_summary'} />,
// href: '/financial-reports/project-profitability-summary', // href: '/financial-reports/project-profitability-summary',
// type: ISidebarMenuItemType.Link, // type: ISidebarMenuItemType.Link,
// }, // },
@@ -599,16 +597,16 @@ export const SidebarMenu = [
// # Reports // # Reports
// --------------- // ---------------
{ {
text: <T id={'sidebar.reports'} />, text: <T id={'Reports'} />,
type: ISidebarMenuItemType.Overlay, type: ISidebarMenuItemType.Overlay,
overlayId: ISidebarMenuOverlayIds.Reports, overlayId: ISidebarMenuOverlayIds.Reports,
children: [ children: [
{ {
text: <T id={'sidebar.reports'} />, text: <T id={'Reports'} />,
type: ISidebarMenuItemType.Group, type: ISidebarMenuItemType.Group,
children: [ children: [
{ {
text: <T id={'sidebar.balance_sheet'} />, text: <T id={'balance_sheet'} />,
href: '/financial-reports/balance-sheet', href: '/financial-reports/balance-sheet',
type: ISidebarMenuItemType.Link, type: ISidebarMenuItemType.Link,
permission: { permission: {
@@ -617,7 +615,7 @@ export const SidebarMenu = [
}, },
}, },
{ {
text: <T id={'sidebar.trial_balance_sheet'} />, text: <T id={'trial_balance_sheet'} />,
href: '/financial-reports/trial-balance-sheet', href: '/financial-reports/trial-balance-sheet',
type: ISidebarMenuItemType.Link, type: ISidebarMenuItemType.Link,
permission: { permission: {
@@ -626,7 +624,7 @@ export const SidebarMenu = [
}, },
}, },
{ {
text: <T id={'sidebar.journal'} />, text: <T id={'journal'} />,
href: '/financial-reports/journal-sheet', href: '/financial-reports/journal-sheet',
type: ISidebarMenuItemType.Link, type: ISidebarMenuItemType.Link,
permission: { permission: {
@@ -635,7 +633,7 @@ export const SidebarMenu = [
}, },
}, },
{ {
text: <T id={'sidebar.general_ledger'} />, text: <T id={'general_ledger'} />,
href: '/financial-reports/general-ledger', href: '/financial-reports/general-ledger',
type: ISidebarMenuItemType.Link, type: ISidebarMenuItemType.Link,
permission: { permission: {
@@ -644,7 +642,7 @@ export const SidebarMenu = [
}, },
}, },
{ {
text: <T id={'sidebar.profit_loss_sheet'} />, text: <T id={'profit_loss_sheet'} />,
href: '/financial-reports/profit-loss-sheet', href: '/financial-reports/profit-loss-sheet',
type: ISidebarMenuItemType.Link, type: ISidebarMenuItemType.Link,
permission: { permission: {
@@ -653,7 +651,7 @@ export const SidebarMenu = [
}, },
}, },
{ {
text: <T id={'sidebar.cash_flow_statement'} />, text: <T id={'cash_flow_statement'} />,
href: '/financial-reports/cash-flow', href: '/financial-reports/cash-flow',
type: ISidebarMenuItemType.Link, type: ISidebarMenuItemType.Link,
permission: { permission: {
@@ -662,7 +660,7 @@ export const SidebarMenu = [
}, },
}, },
{ {
text: <T id={'sidebar.ar_aging_Summary'} />, text: <T id={'AR_Aging_Summary'} />,
href: '/financial-reports/receivable-aging-summary', href: '/financial-reports/receivable-aging-summary',
type: ISidebarMenuItemType.Link, type: ISidebarMenuItemType.Link,
permission: { permission: {
@@ -671,7 +669,7 @@ export const SidebarMenu = [
}, },
}, },
{ {
text: <T id={'sidebar.ap_aging_summary'} />, text: <T id={'AP_Aging_Summary'} />,
href: '/financial-reports/payable-aging-summary', href: '/financial-reports/payable-aging-summary',
type: ISidebarMenuItemType.Link, type: ISidebarMenuItemType.Link,
permission: { permission: {
@@ -682,11 +680,11 @@ export const SidebarMenu = [
], ],
}, },
{ {
text: <T id={'sidebar.sales_purchases'} />, text: <T id={'Sales/Purchases'} />,
type: ISidebarMenuItemType.Group, type: ISidebarMenuItemType.Group,
children: [ children: [
{ {
text: <T id={'sidebar.purchases_by_items'} />, text: <T id={'purchases_by_items'} />,
type: ISidebarMenuItemType.Link, type: ISidebarMenuItemType.Link,
href: '/financial-reports/purchases-by-items', href: '/financial-reports/purchases-by-items',
permission: { permission: {
@@ -695,7 +693,7 @@ export const SidebarMenu = [
}, },
}, },
{ {
text: <T id={'sidebar.sales_by_items'} />, text: <T id={'sales_by_items'} />,
href: '/financial-reports/sales-by-items', href: '/financial-reports/sales-by-items',
type: ISidebarMenuItemType.Link, type: ISidebarMenuItemType.Link,
permission: { permission: {
@@ -704,7 +702,7 @@ export const SidebarMenu = [
}, },
}, },
{ {
text: <T id={'sidebar.customers_transactions'} />, text: <T id={'customers_transactions'} />,
href: '/financial-reports/transactions-by-customers', href: '/financial-reports/transactions-by-customers',
type: ISidebarMenuItemType.Link, type: ISidebarMenuItemType.Link,
permission: { permission: {
@@ -713,7 +711,7 @@ export const SidebarMenu = [
}, },
}, },
{ {
text: <T id={'sidebar.vendors_transactions'} />, text: <T id={'vendors_transactions'} />,
href: '/financial-reports/transactions-by-vendors', href: '/financial-reports/transactions-by-vendors',
type: ISidebarMenuItemType.Link, type: ISidebarMenuItemType.Link,
permission: { permission: {
@@ -722,7 +720,7 @@ export const SidebarMenu = [
}, },
}, },
{ {
text: <T id={'sidebar.customers_balance_summary'} />, text: <T id={'customers_balance_summary'} />,
href: '/financial-reports/customers-balance-summary', href: '/financial-reports/customers-balance-summary',
type: ISidebarMenuItemType.Link, type: ISidebarMenuItemType.Link,
permission: { permission: {
@@ -731,7 +729,7 @@ export const SidebarMenu = [
}, },
}, },
{ {
text: <T id={'sidebar.vendors_balance_summary'} />, text: <T id={'vendors_balance_summary'} />,
href: '/financial-reports/vendors-balance-summary', href: '/financial-reports/vendors-balance-summary',
type: ISidebarMenuItemType.Link, type: ISidebarMenuItemType.Link,
permission: { permission: {
@@ -742,11 +740,11 @@ export const SidebarMenu = [
], ],
}, },
{ {
text: <T id={'sidebar.inventory'} />, text: <T id={'inventory'} />,
type: ISidebarMenuItemType.Group, type: ISidebarMenuItemType.Group,
children: [ children: [
{ {
text: <T id={'sidebar.inventory_item_details'} />, text: <T id={'inventory_item_details'} />,
href: '/financial-reports/inventory-item-details', href: '/financial-reports/inventory-item-details',
type: ISidebarMenuItemType.Link, type: ISidebarMenuItemType.Link,
permission: { permission: {
@@ -755,7 +753,7 @@ export const SidebarMenu = [
}, },
}, },
{ {
text: <T id={'sidebar.inventory_valuation'} />, text: <T id={'inventory_valuation'} />,
href: '/financial-reports/inventory-valuation', href: '/financial-reports/inventory-valuation',
type: ISidebarMenuItemType.Link, type: ISidebarMenuItemType.Link,
permission: { permission: {
@@ -768,11 +766,11 @@ export const SidebarMenu = [
], ],
}, },
{ {
text: <T id={'sidebar.system'} />, text: <T id={'system'} />,
type: ISidebarMenuItemType.Group, type: ISidebarMenuItemType.Group,
children: [ children: [
{ {
text: <T id={'sidebar.preferences'} />, text: <T id={'preferences'} />,
href: '/preferences', href: '/preferences',
type: ISidebarMenuItemType.Link, type: ISidebarMenuItemType.Link,
permission: { permission: {

View File

@@ -25,7 +25,6 @@ import { useMemorizedColumnsWidths } from '@/hooks';
import { useManualJournalsColumns } from './utils'; import { useManualJournalsColumns } from './utils';
import { compose } from '@/utils'; import { compose } from '@/utils';
import { DRAWERS } from '@/constants/drawers';
/** /**
* Manual journals data-table. * Manual journals data-table.
@@ -80,16 +79,14 @@ function ManualJournalsDataTable({
// Handle view detail journal. // Handle view detail journal.
const handleViewDetailJournal = ({ id }) => { const handleViewDetailJournal = ({ id }) => {
openDrawer(DRAWERS.JOURNAL_DETAILS, { openDrawer('journal-drawer', {
manualJournalId: id, manualJournalId: id,
}); });
}; };
// Handle cell click. // Handle cell click.
const handleCellClick = (cell, event) => { const handleCellClick = (cell, event) => {
openDrawer(DRAWERS.JOURNAL_DETAILS, { openDrawer('journal-drawer', { manualJournalId: cell.row.original.id });
manualJournalId: cell.row.original.id,
});
}; };
// Local storage memorizing columns widths. // Local storage memorizing columns widths.

View File

@@ -1,8 +1,14 @@
// @ts-nocheck // @ts-nocheck
import React from 'react'; import React from 'react';
import { InputGroup, FormGroup, Position } from '@blueprintjs/core'; import {
import { FastField, ErrorMessage } from 'formik'; InputGroup,
FormGroup,
Position,
ControlGroup,
} from '@blueprintjs/core';
import { FastField, ErrorMessage, useFormikContext } from 'formik';
import { DateInput } from '@blueprintjs/datetime'; import { DateInput } from '@blueprintjs/datetime';
import * as R from 'ramda';
import classNames from 'classnames'; import classNames from 'classnames';
import { CLASSES } from '@/constants/classes'; import { CLASSES } from '@/constants/classes';
@@ -14,15 +20,99 @@ import {
} from '@/utils'; } from '@/utils';
import { import {
Hint, Hint,
FieldHint,
FieldRequiredHint, FieldRequiredHint,
Icon, Icon,
InputPrependButton,
CurrencySelectList, CurrencySelectList,
FormattedMessage as T, FormattedMessage as T,
FInputGroup,
FFormGroup,
} from '@/components'; } from '@/components';
import { useMakeJournalFormContext } from './MakeJournalProvider'; import { useMakeJournalFormContext } from './MakeJournalProvider';
import { JournalExchangeRateInputField } from './components'; import { JournalExchangeRateInputField } from './components';
import { currenciesFieldShouldUpdate } from './utils'; import { currenciesFieldShouldUpdate } from './utils';
import { MakeJournalTransactionNoField } from './MakeJournalTransactionNoField';
import withSettings from '@/containers/Settings/withSettings';
import withDialogActions from '@/containers/Dialog/withDialogActions';
/**
* Journal number field of make journal form.
*/
const MakeJournalTransactionNoField = R.compose(
withDialogActions,
withSettings(({ manualJournalsSettings }) => ({
journalAutoIncrement: manualJournalsSettings?.autoIncrement,
})),
)(
({
// #withDialog
openDialog,
// #withSettings
journalAutoIncrement,
}) => {
const { setFieldValue, values } = useFormikContext();
const handleJournalNumberChange = () => {
openDialog('journal-number-form');
};
const handleJournalNoBlur = (event) => {
const newValue = event.target.value;
if (values.journal_number !== newValue && journalAutoIncrement) {
openDialog('journal-number-form', {
initialFormValues: {
onceManualNumber: newValue,
incrementMode: 'manual-transaction',
},
});
}
if (!journalAutoIncrement) {
setFieldValue('journal_number', newValue);
setFieldValue('journal_number_manually', newValue);
}
};
return (
<FFormGroup
name={'journal_number'}
label={<T id={'journal_no'} />}
labelInfo={
<>
<FieldRequiredHint />
<FieldHint />
</>
}
fill={true}
inline={true}
fastField={true}
>
<ControlGroup fill={true}>
<FInputGroup
name={'journal_number'}
fill={true}
asyncControl={true}
onBlur={handleJournalNoBlur}
fastField={true}
onChange={() => {}}
/>
<InputPrependButton
buttonProps={{
onClick: handleJournalNumberChange,
icon: <Icon icon={'settings-18'} />,
}}
tooltip={true}
tooltipProps={{
content: <T id={'setting_your_auto_generated_journal_number'} />,
position: Position.BOTTOM_LEFT,
}}
/>
</ControlGroup>
</FFormGroup>
);
},
);
/** /**
* Make journal entries header. * Make journal entries header.

View File

@@ -1,7 +1,6 @@
// @ts-nocheck // @ts-nocheck
import React from 'react'; import React from 'react';
import styled from 'styled-components'; import styled from 'styled-components';
import intl from 'react-intl-universal';
import { FFormGroup, FEditableText, FormattedMessage as T } from '@/components'; import { FFormGroup, FEditableText, FormattedMessage as T } from '@/components';
export function MakeJournalFormFooterLeft() { export function MakeJournalFormFooterLeft() {
@@ -14,7 +13,7 @@ export function MakeJournalFormFooterLeft() {
> >
<FEditableText <FEditableText
name={'description'} name={'description'}
placeholder={intl.get('make_jorunal.decscrption.placeholder')} placeholder={<T id={'make_jorunal.decscrption.placeholder'} />}
/> />
</DescriptionFormGroup> </DescriptionFormGroup>
</React.Fragment> </React.Fragment>

View File

@@ -11,7 +11,6 @@ import {
FeatureCan, FeatureCan,
FormTopbar, FormTopbar,
DetailsBarSkeletonBase, DetailsBarSkeletonBase,
FormBranchSelectButton,
} from '@/components'; } from '@/components';
import { useMakeJournalFormContext } from './MakeJournalProvider'; import { useMakeJournalFormContext } from './MakeJournalProvider';
@@ -52,9 +51,18 @@ function MakeJournalFormSelectBranch() {
<BranchSelect <BranchSelect
name={'branch_id'} name={'branch_id'}
branches={branches} branches={branches}
input={FormBranchSelectButton} input={MakeJournalBranchSelectButton}
popoverProps={{ minimal: true }} popoverProps={{ minimal: true }}
fill={false} />
);
}
function MakeJournalBranchSelectButton({ label }) {
return (
<Button
text={intl.get('make_journal.branch_button.label', { label })}
minimal={true}
small={true}
icon={<Icon icon={'branch-16'} iconSize={16} />}
/> />
); );
} }

View File

@@ -1,97 +0,0 @@
// @ts-nocheck
import React from 'react';
import { Position, ControlGroup } from '@blueprintjs/core';
import { useFormikContext } from 'formik';
import * as R from 'ramda';
import {
FieldHint,
FieldRequiredHint,
Icon,
InputPrependButton,
FormattedMessage as T,
FInputGroup,
FFormGroup,
} from '@/components';
import withSettings from '@/containers/Settings/withSettings';
import withDialogActions from '@/containers/Dialog/withDialogActions';
/**
* Journal number field of make journal form.
*/
export const MakeJournalTransactionNoField = R.compose(
withDialogActions,
withSettings(({ manualJournalsSettings }) => ({
journalAutoIncrement: manualJournalsSettings?.autoIncrement,
})),
)(
({
// #withDialog
openDialog,
// #withSettings
journalAutoIncrement,
}) => {
const { setFieldValue, values } = useFormikContext();
const handleJournalNumberChange = () => {
openDialog('journal-number-form');
};
const handleJournalNoBlur = (event) => {
const newValue = event.target.value;
if (values.journal_number !== newValue && journalAutoIncrement) {
openDialog('journal-number-form', {
initialFormValues: {
onceManualNumber: newValue,
incrementMode: 'manual-transaction',
},
});
}
if (!journalAutoIncrement) {
setFieldValue('journal_number', newValue);
setFieldValue('journal_number_manually', newValue);
}
};
return (
<FFormGroup
name={'journal_number'}
label={<T id={'journal_no'} />}
labelInfo={
<>
<FieldRequiredHint />
<FieldHint />
</>
}
fill={true}
inline={true}
fastField={true}
>
<ControlGroup fill={true}>
<FInputGroup
name={'journal_number'}
fill={true}
asyncControl={true}
onBlur={handleJournalNoBlur}
fastField={true}
onChange={() => {}}
/>
<InputPrependButton
buttonProps={{
onClick: handleJournalNumberChange,
icon: <Icon icon={'settings-18'} />,
}}
tooltip={true}
tooltipProps={{
content: <T id={'setting_your_auto_generated_journal_number'} />,
position: Position.BOTTOM_LEFT,
}}
/>
</ControlGroup>
</FFormGroup>
);
},
);
MakeJournalTransactionNoField.displayName = 'MakeJournalTransactionNoField';

View File

@@ -1,7 +1,7 @@
// @ts-nocheck // @ts-nocheck
import React, { useEffect } from 'react'; import React, { useEffect } from 'react';
import intl from 'react-intl-universal'; import intl from 'react-intl-universal';
import { Menu, MenuItem, Position, Button, Intent } from '@blueprintjs/core'; import { Menu, MenuItem, Position, Button } from '@blueprintjs/core';
import { Popover2 } from '@blueprintjs/popover2'; import { Popover2 } from '@blueprintjs/popover2';
import { useFormikContext } from 'formik'; import { useFormikContext } from 'formik';
import * as R from 'ramda'; import * as R from 'ramda';
@@ -74,7 +74,6 @@ export const ActionsCellRenderer = ({
const exampleMenu = ( const exampleMenu = (
<Menu> <Menu>
<MenuItem <MenuItem
intent={Intent.DANGER}
onClick={handleClickRemoveRole} onClick={handleClickRemoveRole}
text={intl.get('make_journal.entries.remove_row')} text={intl.get('make_journal.entries.remove_row')}
/> />

View File

@@ -3,7 +3,6 @@ import intl from 'react-intl-universal';
import { RESOURCES_TYPES } from '@/constants/resourcesTypes'; import { RESOURCES_TYPES } from '@/constants/resourcesTypes';
import { AbilitySubject, ManualJournalAction } from '@/constants/abilityOption'; import { AbilitySubject, ManualJournalAction } from '@/constants/abilityOption';
import withDrawerActions from '@/containers/Drawer/withDrawerActions'; import withDrawerActions from '@/containers/Drawer/withDrawerActions';
import { DRAWERS } from '@/constants/drawers';
/** /**
* Universal search manual journal item select action. * Universal search manual journal item select action.
@@ -18,7 +17,7 @@ function JournalUniversalSearchSelectComponent({
openDrawer, openDrawer,
}) { }) {
if (resourceType === RESOURCES_TYPES.MANUAL_JOURNAL) { if (resourceType === RESOURCES_TYPES.MANUAL_JOURNAL) {
openDrawer(DRAWERS.JOURNAL_DETAILS, { manualJournalId: resourceId }); openDrawer('journal-drawer', { manualJournalId: resourceId });
onAction && onAction(); onAction && onAction();
} }
return null; return null;

View File

@@ -5,7 +5,6 @@ import withDrawerActions from '@/containers/Drawer/withDrawerActions';
import { AbilitySubject, AccountAction } from '@/constants/abilityOption'; import { AbilitySubject, AccountAction } from '@/constants/abilityOption';
import { RESOURCES_TYPES } from '@/constants/resourcesTypes'; import { RESOURCES_TYPES } from '@/constants/resourcesTypes';
import { DRAWERS } from '@/constants/drawers';
function AccountUniversalSearchItemSelectComponent({ function AccountUniversalSearchItemSelectComponent({
// #ownProps // #ownProps
@@ -17,7 +16,7 @@ function AccountUniversalSearchItemSelectComponent({
openDrawer, openDrawer,
}) { }) {
if (resourceType === RESOURCES_TYPES.ACCOUNT) { if (resourceType === RESOURCES_TYPES.ACCOUNT) {
openDrawer(DRAWERS.ACCOUNT_DETAILS, { accountId: resourceId }); openDrawer('account-drawer', { accountId: resourceId });
onAction && onAction(); onAction && onAction();
} }
return null; return null;

View File

@@ -23,7 +23,6 @@ import withAlertsActions from '@/containers/Alert/withAlertActions';
import withDialogActions from '@/containers/Dialog/withDialogActions'; import withDialogActions from '@/containers/Dialog/withDialogActions';
import withDrawerActions from '@/containers/Drawer/withDrawerActions'; import withDrawerActions from '@/containers/Drawer/withDrawerActions';
import { compose } from '@/utils'; import { compose } from '@/utils';
import { DRAWERS } from '@/constants/drawers';
/** /**
* Accounts data-table. * Accounts data-table.
@@ -72,7 +71,7 @@ function AccountsDataTable({
// Handle view detail account. // Handle view detail account.
const handleViewDetailAccount = ({ id }) => { const handleViewDetailAccount = ({ id }) => {
openDrawer(DRAWERS.ACCOUNT_DETAILS, { accountId: id }); openDrawer('account-drawer', { accountId: id });
}; };
// Handle new child button click. // Handle new child button click.
@@ -85,7 +84,7 @@ function AccountsDataTable({
}; };
// Handle cell click. // Handle cell click.
const handleCellClick = (cell, event) => { const handleCellClick = (cell, event) => {
openDrawer(DRAWERS.ACCOUNT_DETAILS, { accountId: cell.row.original.id }); openDrawer('account-drawer', { accountId: cell.row.original.id });
}; };
// Local storage memorizing columns widths. // Local storage memorizing columns widths.
const [initialColumnsWidths, , handleColumnResizing] = const [initialColumnsWidths, , handleColumnResizing] =

View File

@@ -16,7 +16,6 @@ import withDrawerActions from '@/containers/Drawer/withDrawerActions';
import { useDeleteAccount } from '@/hooks/query'; import { useDeleteAccount } from '@/hooks/query';
import { compose } from '@/utils'; import { compose } from '@/utils';
import { DRAWERS } from '@/constants/drawers';
/** /**
* Account delete alerts. * Account delete alerts.
@@ -49,7 +48,7 @@ function AccountDeleteAlert({
intent: Intent.SUCCESS, intent: Intent.SUCCESS,
}); });
closeAlert(name); closeAlert(name);
closeDrawer(DRAWERS.ACCOUNT_DETAILS); closeDrawer('account-drawer');
}) })
.catch( .catch(
({ ({

View File

@@ -11,7 +11,6 @@ import withDrawerActions from '@/containers/Drawer/withDrawerActions';
import { handleDeleteErrors } from '@/containers/Purchases/Bills/BillForm/utils'; import { handleDeleteErrors } from '@/containers/Purchases/Bills/BillForm/utils';
import { useDeleteBill } from '@/hooks/query'; import { useDeleteBill } from '@/hooks/query';
import { compose } from '@/utils'; import { compose } from '@/utils';
import { DRAWERS } from '@/constants/drawers';
/** /**
* Bill delete alert. * Bill delete alert.
@@ -44,7 +43,8 @@ function BillDeleteAlert({
message: intl.get('the_bill_has_been_deleted_successfully'), message: intl.get('the_bill_has_been_deleted_successfully'),
intent: Intent.SUCCESS, intent: Intent.SUCCESS,
}); });
closeDrawer(DRAWERS.BILL_DETAILS);
closeDrawer('bill-drawer');
}) })
.catch( .catch(
({ ({

View File

@@ -15,7 +15,6 @@ import withAlertActions from '@/containers/Alert/withAlertActions';
import withDrawerActions from '@/containers/Drawer/withDrawerActions'; import withDrawerActions from '@/containers/Drawer/withDrawerActions';
import { compose } from '@/utils'; import { compose } from '@/utils';
import { DRAWERS } from '@/constants/drawers';
/** /**
* Account delete transaction alert. * Account delete transaction alert.
@@ -49,7 +48,7 @@ function AccountDeleteTransactionAlert({
message: intl.get('cash_flow_transaction.delete.alert_message'), message: intl.get('cash_flow_transaction.delete.alert_message'),
intent: Intent.SUCCESS, intent: Intent.SUCCESS,
}); });
closeDrawer(DRAWERS.CASHFLOW_TRNASACTION_DETAILS); closeDrawer('cashflow-transaction-drawer');
}) })
.catch( .catch(
({ ({

View File

@@ -15,7 +15,6 @@ import withDrawerActions from '@/containers/Drawer/withDrawerActions';
import { useDeleteCreditNote } from '@/hooks/query'; import { useDeleteCreditNote } from '@/hooks/query';
import { handleDeleteErrors } from '@/containers/Sales/CreditNotes/CreditNotesLanding/utils'; import { handleDeleteErrors } from '@/containers/Sales/CreditNotes/CreditNotesLanding/utils';
import { compose } from '@/utils'; import { compose } from '@/utils';
import { DRAWERS } from '@/constants/drawers';
/** /**
* Credit note delete alert. * Credit note delete alert.
@@ -47,7 +46,7 @@ function CreditNoteDeleteAlert({
message: intl.get('credit_note.alert.delete_message'), message: intl.get('credit_note.alert.delete_message'),
intent: Intent.SUCCESS, intent: Intent.SUCCESS,
}); });
closeDrawer(DRAWERS.CREDIT_NOTE_DETAILS); closeDrawer('credit-note-detail-drawer');
}) })
.catch( .catch(
({ ({

View File

@@ -11,7 +11,6 @@ import withAlertStoreConnect from '@/containers/Alert/withAlertStoreConnect';
import withDrawerActions from '@/containers/Drawer/withDrawerActions'; import withDrawerActions from '@/containers/Drawer/withDrawerActions';
import { compose } from '@/utils'; import { compose } from '@/utils';
import { DRAWERS } from '@/constants/drawers';
/** /**
* Refund credit transactions delete alert * Refund credit transactions delete alert
@@ -43,7 +42,7 @@ function RefundCreditNoteDeleteAlert({
message: intl.get('refund_credit_transactions.alert.delete_message'), message: intl.get('refund_credit_transactions.alert.delete_message'),
intent: Intent.SUCCESS, intent: Intent.SUCCESS,
}); });
closeDrawer(DRAWERS.REFUND_CREDIT_NOTE_DETAILS); closeDrawer('refund-credit-detail-drawer');
}) })
.catch(() => {}) .catch(() => {})
.finally(() => { .finally(() => {

View File

@@ -15,7 +15,6 @@ import withDrawerActions from '@/containers/Drawer/withDrawerActions';
import { useDeleteCustomer } from '@/hooks/query'; import { useDeleteCustomer } from '@/hooks/query';
import { compose } from '@/utils'; import { compose } from '@/utils';
import { DRAWERS } from '@/constants/drawers';
/** /**
* Customer delete alert. * Customer delete alert.
@@ -48,7 +47,7 @@ function CustomerDeleteAlert({
message: intl.get('the_customer_has_been_deleted_successfully'), message: intl.get('the_customer_has_been_deleted_successfully'),
intent: Intent.SUCCESS, intent: Intent.SUCCESS,
}); });
closeDrawer(DRAWERS.CUSTOMER_DETAILS); closeDrawer('customer-detail-drawer');
}) })
.catch( .catch(
({ ({

View File

@@ -15,7 +15,6 @@ import withAlertActions from '@/containers/Alert/withAlertActions';
import withDrawerActions from '@/containers/Drawer/withDrawerActions'; import withDrawerActions from '@/containers/Drawer/withDrawerActions';
import { compose } from '@/utils'; import { compose } from '@/utils';
import { DRAWERS } from '@/constants/drawers';
/** /**
* Estimate delete alert. * Estimate delete alert.
@@ -48,7 +47,7 @@ function EstimateDeleteAlert({
message: intl.get('the_estimate_has_been_deleted_successfully'), message: intl.get('the_estimate_has_been_deleted_successfully'),
intent: Intent.SUCCESS, intent: Intent.SUCCESS,
}); });
closeDrawer(DRAWERS.ESTIMATE_DETAILS); closeDrawer('estimate-detail-drawer');
}) })
.catch( .catch(
({ ({

View File

@@ -10,7 +10,6 @@ import withDrawerActions from '@/containers/Drawer/withDrawerActions';
import { useDeleteExpense } from '@/hooks/query'; import { useDeleteExpense } from '@/hooks/query';
import { compose } from '@/utils'; import { compose } from '@/utils';
import { DRAWERS } from '@/constants/drawers';
/** /**
* Expense delete alert. * Expense delete alert.
@@ -43,7 +42,7 @@ function ExpenseDeleteAlert({
}), }),
intent: Intent.SUCCESS, intent: Intent.SUCCESS,
}); });
closeDrawer(DRAWERS.EXPENSE_DETAILS); closeDrawer('expense-drawer');
}) })
.catch( .catch(
({ ({

View File

@@ -16,7 +16,6 @@ import withAlertActions from '@/containers/Alert/withAlertActions';
import withDrawerActions from '@/containers/Drawer/withDrawerActions'; import withDrawerActions from '@/containers/Drawer/withDrawerActions';
import { compose } from '@/utils'; import { compose } from '@/utils';
import { DRAWERS } from '@/constants/drawers';
/** /**
* Invoice delete alert. * Invoice delete alert.
@@ -49,7 +48,7 @@ function InvoiceDeleteAlert({
message: intl.get('the_invoice_has_been_deleted_successfully'), message: intl.get('the_invoice_has_been_deleted_successfully'),
intent: Intent.SUCCESS, intent: Intent.SUCCESS,
}); });
closeDrawer(DRAWERS.INVOICE_DETAILS); closeDrawer('invoice-detail-drawer');
}) })
.catch( .catch(
({ ({

View File

@@ -14,7 +14,6 @@ import withDrawerActions from '@/containers/Drawer/withDrawerActions';
import { useDeleteInventoryAdjustment } from '@/hooks/query'; import { useDeleteInventoryAdjustment } from '@/hooks/query';
import { compose } from '@/utils'; import { compose } from '@/utils';
import { DRAWERS } from '@/constants/drawers';
/** /**
* Inventory Adjustment delete alerts. * Inventory Adjustment delete alerts.
@@ -50,7 +49,7 @@ function InventoryAdjustmentDeleteAlert({
), ),
intent: Intent.SUCCESS, intent: Intent.SUCCESS,
}); });
closeDrawer(DRAWERS.INVENTORY_ADJUSTMENT_DETAILS); closeDrawer('inventory-adjustment-drawer');
}) })
.catch((errors) => {}) .catch((errors) => {})
.finally(() => { .finally(() => {

View File

@@ -17,7 +17,6 @@ import withItemsActions from '@/containers/Items/withItemsActions';
import withDrawerActions from '@/containers/Drawer/withDrawerActions'; import withDrawerActions from '@/containers/Drawer/withDrawerActions';
import { compose } from '@/utils'; import { compose } from '@/utils';
import { DRAWERS } from '@/constants/drawers';
/** /**
* Item delete alerts. * Item delete alerts.
@@ -55,7 +54,7 @@ function ItemDeleteAlert({
}); });
// Reset to page number one. // Reset to page number one.
setItemsTableState({ page: 1 }); setItemsTableState({ page: 1 });
closeDrawer(DRAWERS.ITEM_DETAILS); closeDrawer('item-detail-drawer');
}) })
.catch( .catch(
({ ({

View File

@@ -10,7 +10,6 @@ import withAlertStoreConnect from '@/containers/Alert/withAlertStoreConnect';
import withDrawerActions from '@/containers/Drawer/withDrawerActions'; import withDrawerActions from '@/containers/Drawer/withDrawerActions';
import { compose } from '@/utils'; import { compose } from '@/utils';
import { DRAWERS } from '@/constants/drawers';
/** /**
* Journal delete alert. * Journal delete alert.
@@ -46,7 +45,7 @@ function JournalDeleteAlert({
intent: Intent.SUCCESS, intent: Intent.SUCCESS,
}); });
closeAlert(name); closeAlert(name);
closeDrawer(DRAWERS.JOURNAL_DETAILS); closeDrawer('journal-drawer');
}) })
.catch(() => { .catch(() => {
closeAlert(name); closeAlert(name);

View File

@@ -11,7 +11,6 @@ import withDrawerActions from '@/containers/Drawer/withDrawerActions';
import { useDeletePaymentMade } from '@/hooks/query'; import { useDeletePaymentMade } from '@/hooks/query';
import { compose } from '@/utils'; import { compose } from '@/utils';
import { DRAWERS } from '@/constants/drawers';
/** /**
* Payment made delete alert. * Payment made delete alert.
@@ -45,7 +44,7 @@ function PaymentMadeDeleteAlert({
message: intl.get('the_payment_made_has_been_deleted_successfully'), message: intl.get('the_payment_made_has_been_deleted_successfully'),
intent: Intent.SUCCESS, intent: Intent.SUCCESS,
}); });
closeDrawer(DRAWERS.PAYMENT_MADE_DETAILS); closeDrawer('payment-made-detail-drawer');
}) })
.finally(() => { .finally(() => {
closeAlert(name); closeAlert(name);

View File

@@ -15,7 +15,6 @@ import withAlertActions from '@/containers/Alert/withAlertActions';
import withDrawerActions from '@/containers/Drawer/withDrawerActions'; import withDrawerActions from '@/containers/Drawer/withDrawerActions';
import { compose } from '@/utils'; import { compose } from '@/utils';
import { DRAWERS } from '@/constants/drawers';
/** /**
* Payment receive delete alert. * Payment receive delete alert.
@@ -51,7 +50,7 @@ function PaymentReceiveDeleteAlert({
), ),
intent: Intent.SUCCESS, intent: Intent.SUCCESS,
}); });
closeDrawer(DRAWERS.PAYMENT_RECEIVE_DETAILS); closeDrawer('payment-receive-detail-drawer');
}) })
.catch(() => {}) .catch(() => {})
.finally(() => { .finally(() => {

View File

@@ -15,7 +15,6 @@ import withAlertActions from '@/containers/Alert/withAlertActions';
import withDrawerActions from '@/containers/Drawer/withDrawerActions'; import withDrawerActions from '@/containers/Drawer/withDrawerActions';
import { compose } from '@/utils'; import { compose } from '@/utils';
import { DRAWERS } from '@/constants/drawers';
/** /**
* Invoice alert. * Invoice alert.
@@ -48,7 +47,7 @@ function NameDeleteAlert({
message: intl.get('the_receipt_has_been_deleted_successfully'), message: intl.get('the_receipt_has_been_deleted_successfully'),
intent: Intent.SUCCESS, intent: Intent.SUCCESS,
}); });
closeDrawer(DRAWERS.RECEIPT_DETAILS); closeDrawer('receipt-detail-drawer');
}) })
.catch(() => {}) .catch(() => {})
.finally(() => { .finally(() => {

View File

@@ -10,7 +10,6 @@ import withAlertStoreConnect from '@/containers/Alert/withAlertStoreConnect';
import withDrawerActions from '@/containers/Drawer/withDrawerActions'; import withDrawerActions from '@/containers/Drawer/withDrawerActions';
import { compose } from '@/utils'; import { compose } from '@/utils';
import { DRAWERS } from '@/constants/drawers';
/** /**
* Refund Vendor transactions delete alert. * Refund Vendor transactions delete alert.
@@ -44,7 +43,7 @@ function RefundVendorCreditDeleteAlert({
), ),
intent: Intent.SUCCESS, intent: Intent.SUCCESS,
}); });
closeDrawer(DRAWERS.REFUND_VENDOR_CREDIT_DETAILS); closeDrawer('refund-vendor-detail-drawer');
}) })
.catch(() => {}) .catch(() => {})
.finally(() => { .finally(() => {

View File

@@ -14,7 +14,6 @@ import withDrawerActions from '@/containers/Drawer/withDrawerActions';
import { handleDeleteErrors } from '@/containers/Purchases/CreditNotes/CreditNotesLanding/utils'; import { handleDeleteErrors } from '@/containers/Purchases/CreditNotes/CreditNotesLanding/utils';
import { useDeleteVendorCredit } from '@/hooks/query'; import { useDeleteVendorCredit } from '@/hooks/query';
import { compose } from '@/utils'; import { compose } from '@/utils';
import { DRAWERS } from '@/constants/drawers';
/** /**
* Vendor Credit delete alert. * Vendor Credit delete alert.
@@ -46,7 +45,7 @@ function VendorCreditDeleteAlert({
message: intl.get('vendor_credits.alert.delete_message'), message: intl.get('vendor_credits.alert.delete_message'),
intent: Intent.SUCCESS, intent: Intent.SUCCESS,
}); });
closeDrawer(DRAWERS.VENDOR_CREDIT_DETAILS); closeDrawer('vendor-credit-detail-drawer');
}) })
.catch( .catch(
({ ({

View File

@@ -16,7 +16,6 @@ import withAlertActions from '@/containers/Alert/withAlertActions';
import withDrawerActions from '@/containers/Drawer/withDrawerActions'; import withDrawerActions from '@/containers/Drawer/withDrawerActions';
import { compose } from '@/utils'; import { compose } from '@/utils';
import { DRAWERS } from '@/constants/drawers';
/** /**
* Vendor delete alert. * Vendor delete alert.
@@ -49,7 +48,7 @@ function VendorDeleteAlert({
message: intl.get('the_vendor_has_been_deleted_successfully'), message: intl.get('the_vendor_has_been_deleted_successfully'),
intent: Intent.SUCCESS, intent: Intent.SUCCESS,
}); });
closeDrawer(DRAWERS.VENDOR_DETAILS); closeDrawer('vendor-detail-drawer');
}) })
.catch( .catch(
({ ({

View File

@@ -14,7 +14,6 @@ import withAlertActions from '@/containers/Alert/withAlertActions';
import withDrawerActions from '@/containers/Drawer/withDrawerActions'; import withDrawerActions from '@/containers/Drawer/withDrawerActions';
import { compose } from '@/utils'; import { compose } from '@/utils';
import { DRAWERS } from '@/constants/drawers';
/** /**
* Warehouse transfer delete alert * Warehouse transfer delete alert
@@ -49,7 +48,7 @@ function WarehouseTransferDeleteAlert({
message: intl.get('warehouse_transfer.alert.delete_message'), message: intl.get('warehouse_transfer.alert.delete_message'),
intent: Intent.SUCCESS, intent: Intent.SUCCESS,
}); });
closeDrawer(DRAWERS.WAREHOUSE_TRANSFER_DETAILS); closeDrawer('warehouse-transfer-detail-drawer');
}) })
.catch( .catch(
({ ({

View File

@@ -23,11 +23,11 @@ export const RegisterSchema = Yup.object().shape({
first_name: Yup.string().required().label(intl.get('first_name_')), first_name: Yup.string().required().label(intl.get('first_name_')),
last_name: Yup.string().required().label(intl.get('last_name_')), last_name: Yup.string().required().label(intl.get('last_name_')),
email: Yup.string().email().required().label(intl.get('email')), email: Yup.string().email().required().label(intl.get('email')),
password: Yup.string().min(6).required().label(intl.get('password')), password: Yup.string().min(4).required().label(intl.get('password')),
}); });
export const ResetPasswordSchema = Yup.object().shape({ export const ResetPasswordSchema = Yup.object().shape({
password: Yup.string().min(6).required().label(intl.get('password')), password: Yup.string().min(4).required().label(intl.get('password')),
confirm_password: Yup.string() confirm_password: Yup.string()
.oneOf([Yup.ref('password'), null]) .oneOf([Yup.ref('password'), null])
.required() .required()

View File

@@ -9,7 +9,6 @@ import {
import { Select } from '@blueprintjs/select'; import { Select } from '@blueprintjs/select';
import { Icon } from '@/components'; import { Icon } from '@/components';
import { DRAWERS } from '@/constants/drawers';
export const CashFlowMenuItems = ({ export const CashFlowMenuItems = ({
text, text,
@@ -54,40 +53,40 @@ export const CashFlowMenuItems = ({
export const handleCashFlowTransactionType = (reference, openDrawer) => { export const handleCashFlowTransactionType = (reference, openDrawer) => {
switch (reference.reference_type) { switch (reference.reference_type) {
case 'SaleReceipt': case 'SaleReceipt':
return openDrawer(DRAWERS.RECEIPT_DETAILS, { return openDrawer('receipt-detail-drawer', {
receiptId: reference.reference_id, receiptId: reference.reference_id,
}); });
case 'Journal': case 'Journal':
return openDrawer(DRAWERS.JOURNAL_DETAILS, { return openDrawer('journal-drawer', {
manualJournalId: reference.reference_id, manualJournalId: reference.reference_id,
}); });
case 'Expense': case 'Expense':
return openDrawer(DRAWERS.EXPENSE_DETAILS, { return openDrawer('expense-drawer', {
expenseId: reference.reference_id, expenseId: reference.reference_id,
}); });
case 'PaymentReceive': case 'PaymentReceive':
return openDrawer(DRAWERS.PAYMENT_RECEIVE_DETAILS, { return openDrawer('payment-receive-detail-drawer', {
paymentReceiveId: reference.reference_id, paymentReceiveId: reference.reference_id,
}); });
case 'BillPayment': case 'BillPayment':
return openDrawer(DRAWERS.PAYMENT_MADE_DETAILS, { return openDrawer('payment-made-detail-drawer', {
paymentMadeId: reference.reference_id, paymentMadeId: reference.reference_id,
}); });
case 'RefundCreditNote': case 'RefundCreditNote':
return openDrawer(DRAWERS.REFUND_CREDIT_NOTE_DETAILS, { return openDrawer('refund-credit-detail-drawer', {
refundTransactionId: reference.reference_id, refundTransactionId: reference.reference_id,
}); });
case 'RefundVendorCredit': case 'RefundVendorCredit':
return openDrawer(DRAWERS.REFUND_VENDOR_CREDIT_DETAILS, { return openDrawer('refund-vendor-detail-drawer', {
refundTransactionId: reference.reference_id, refundTransactionId: reference.reference_id,
}); });
case 'InventoryAdjustment': case 'InventoryAdjustment':
return openDrawer(DRAWERS.INVENTORY_ADJUSTMENT_DETAILS, { return openDrawer('inventory-adjustment-drawer', {
inventoryId: reference.reference_id, inventoryId: reference.reference_id,
}); });
default: default:
return openDrawer(DRAWERS.CASHFLOW_TRNASACTION_DETAILS, { return openDrawer('cashflow-transaction-drawer', {
referenceId: reference.reference_id, referenceId: reference.reference_id,
}); });
} }

View File

@@ -28,7 +28,6 @@ import withDialogActions from '@/containers/Dialog/withDialogActions';
import { AccountDialogAction } from '@/containers/Dialogs/AccountDialog/utils'; import { AccountDialogAction } from '@/containers/Dialogs/AccountDialog/utils';
import { safeCallback } from '@/utils'; import { safeCallback } from '@/utils';
import { DRAWERS } from '@/constants/drawers';
const CASHFLOW_SKELETON_N = 4; const CASHFLOW_SKELETON_N = 4;
@@ -64,7 +63,7 @@ function CashflowBankAccount({
}) { }) {
// Handle view detail account. // Handle view detail account.
const handleViewClick = () => { const handleViewClick = () => {
openDrawer(DRAWERS.ACCOUNT_DETAILS, { accountId: account.id }); openDrawer('account-drawer', { accountId: account.id });
}; };
// Handle delete action account. // Handle delete action account.
const handleDeleteClick = () => { const handleDeleteClick = () => {

View File

@@ -1,22 +1,18 @@
// @ts-nocheck // @ts-nocheck
import React, { useMemo } from 'react'; import React from 'react';
import { useFormikContext } from 'formik';
import OwnerContributionFormFields from './OwnerContribution/OwnerContributionFormFields'; import OwnerContributionFormFields from './OwnerContribution/OwnerContributionFormFields';
import OtherIncomeFormFields from './OtherIncome/OtherIncomeFormFields'; import OtherIncomeFormFields from './OtherIncome/OtherIncomeFormFields';
import TransferFromAccountFormFields from './TransferFromAccount/TransferFromAccountFormFields'; import TransferFromAccountFormFields from './TransferFromAccount/TransferFromAccountFormFields';
import { MoneyInFieldsProvider } from './MoneyInFieldsProvider';
/** /**
* Money-in dialog content. *
* Switches between fields based on the given transaction type. * @param param0
* @returns {JSX.Element} * @returns
*/ */
export default function MoneyInContentFields() { export default function MoneyInContentFields({ accountType }) {
const { values } = useFormikContext(); const handleTransactionType = () => {
switch (accountType) {
const transactionFields = useMemo(() => {
switch (values.transaction_type) {
case 'owner_contribution': case 'owner_contribution':
return <OwnerContributionFormFields />; return <OwnerContributionFormFields />;
@@ -28,10 +24,6 @@ export default function MoneyInContentFields() {
default: default:
break; break;
} }
}, [values.transaction_type]); };
return <React.Fragment>{handleTransactionType()}</React.Fragment>;
// Cannot continue if transaction type or account is not selected.
if (!values.transaction_type || !values.cashflow_account_id) return null;
return <MoneyInFieldsProvider>{transactionFields}</MoneyInFieldsProvider>;
} }

View File

@@ -1,5 +1,6 @@
// @ts-nocheck // @ts-nocheck
import React from 'react'; import React from 'react';
import { MoneyInDialogProvider } from './MoneyInDialogProvider'; import { MoneyInDialogProvider } from './MoneyInDialogProvider';
import MoneyInForm from './MoneyInForm'; import MoneyInForm from './MoneyInForm';

View File

@@ -1,10 +1,11 @@
// @ts-nocheck // @ts-nocheck
import React, { useState } from 'react'; import React from 'react';
import { DialogContent } from '@/components'; import { DialogContent } from '@/components';
import { Features } from '@/constants'; import { Features } from '@/constants';
import { useFeatureCan } from '@/hooks/state'; import { useFeatureCan } from '@/hooks/state';
import { import {
useCreateCashflowTransaction, useCreateCashflowTransaction,
useAccount,
useAccounts, useAccounts,
useBranches, useBranches,
useCashflowAccounts, useCashflowAccounts,
@@ -17,20 +18,21 @@ const MoneyInDialogContent = React.createContext();
* Money in dialog provider. * Money in dialog provider.
*/ */
function MoneyInDialogProvider({ function MoneyInDialogProvider({
accountId: defaultAccountId, accountId,
accountType, accountType,
dialogName, dialogName,
...props ...props
}) { }) {
// Holds the selected account id of the dialog.
const [accountId, setAccountId] = useState<number | null>(defaultAccountId);
// Detarmines whether the feature is enabled.
const { featureCan } = useFeatureCan(); const { featureCan } = useFeatureCan();
const isBranchFeatureCan = featureCan(Features.Branches); const isBranchFeatureCan = featureCan(Features.Branches);
// Fetches accounts list. // Fetches accounts list.
const { isLoading: isAccountsLoading, data: accounts } = useAccounts(); const { isFetching: isAccountsLoading, data: accounts } = useAccounts();
// Fetches the specific account details.
const { data: account, isLoading: isAccountLoading } = useAccount(accountId, {
enabled: !!accountId,
});
// Fetches the branches list. // Fetches the branches list.
const { const {
@@ -39,11 +41,10 @@ function MoneyInDialogProvider({
isSuccess: isBranchesSuccess, isSuccess: isBranchesSuccess,
} = useBranches({}, { enabled: isBranchFeatureCan }); } = useBranches({}, { enabled: isBranchFeatureCan });
// Fetch cash flow list. // Fetch cash flow list .
const { data: cashflowAccounts, isLoading: isCashFlowAccountsLoading } = const { data: cashflowAccounts, isLoading: isCashFlowAccountsLoading } =
useCashflowAccounts({}, { keepPreviousData: true }); useCashflowAccounts({}, { keepPreviousData: true });
// Mutation create cashflow transaction.
const { mutateAsync: createCashflowTransactionMutate } = const { mutateAsync: createCashflowTransactionMutate } =
useCreateCashflowTransaction(); useCreateCashflowTransaction();
@@ -53,15 +54,12 @@ function MoneyInDialogProvider({
// Submit payload. // Submit payload.
const [submitPayload, setSubmitPayload] = React.useState({}); const [submitPayload, setSubmitPayload] = React.useState({});
// Provider data. // provider.
const provider = { const provider = {
accounts, accounts,
account,
branches, branches,
accountId, accountId,
defaultAccountId,
setAccountId,
accountType, accountType,
isAccountsLoading, isAccountsLoading,
isBranchesSuccess, isBranchesSuccess,
@@ -75,14 +73,15 @@ function MoneyInDialogProvider({
setSubmitPayload, setSubmitPayload,
}; };
const isLoading = return (
<DialogContent
isLoading={
isAccountsLoading || isAccountsLoading ||
isCashFlowAccountsLoading || isCashFlowAccountsLoading ||
isBranchesLoading || isBranchesLoading ||
isSettingsLoading; isSettingsLoading
}
return ( >
<DialogContent isLoading={isLoading}>
<MoneyInDialogContent.Provider value={provider} {...props} /> <MoneyInDialogContent.Provider value={provider} {...props} />
</DialogContent> </DialogContent>
); );

View File

@@ -1,26 +0,0 @@
// @ts-nocheck
import React from 'react';
import { ExchangeRateMutedField } from '@/components';
import { useForeignAccount } from './utils';
import { useFormikContext } from 'formik';
import { useMoneyInFieldsContext } from './MoneyInFieldsProvider';
export function MoneyInExchangeRateField() {
const { account } = useMoneyInFieldsContext();
const { values } = useFormikContext();
const isForeigAccount = useForeignAccount();
if (!isForeigAccount) return null;
return (
<ExchangeRateMutedField
name={'exchange_rate'}
fromCurrency={values.currency_code}
toCurrency={account.currency_code}
formGroupProps={{ label: '', inline: false }}
date={values.date}
exchangeRate={values.exchange_rate}
/>
);
}

View File

@@ -1,34 +0,0 @@
// @ts-nocheck
import React from 'react';
import { DialogContent } from '@/components';
import { useAccount } from '@/hooks/query';
import { useMoneyInDailogContext } from './MoneyInDialogProvider';
const MoneyInFieldsContext = React.createContext();
/**
* Money in dialog provider.
*/
function MoneyInFieldsProvider({ ...props }) {
const { accountId } = useMoneyInDailogContext();
// Fetches the specific account details.
const { data: account, isLoading: isAccountLoading } = useAccount(accountId, {
enabled: !!accountId,
});
// Provider data.
const provider = {
account,
};
const isLoading = isAccountLoading;
return (
<DialogContent isLoading={isLoading}>
<MoneyInFieldsContext.Provider value={provider} {...props} />
</DialogContent>
);
}
const useMoneyInFieldsContext = () => React.useContext(MoneyInFieldsContext);
export { MoneyInFieldsProvider, useMoneyInFieldsContext };

View File

@@ -53,6 +53,7 @@ function MoneyInForm({
accountId, accountId,
accountType, accountType,
createCashflowTransactionMutate, createCashflowTransactionMutate,
submitPayload,
} = useMoneyInDailogContext(); } = useMoneyInDailogContext();
// transaction number. // transaction number.
@@ -60,6 +61,7 @@ function MoneyInForm({
transactionNumberPrefix, transactionNumberPrefix,
transactionNextNumber, transactionNextNumber,
); );
// Initial form values. // Initial form values.
const initialValues = { const initialValues = {
...defaultInitialValues, ...defaultInitialValues,
@@ -93,6 +95,7 @@ function MoneyInForm({
}; };
return ( return (
<div>
<Formik <Formik
validationSchema={CreateMoneyInFormSchema} validationSchema={CreateMoneyInFormSchema}
initialValues={initialValues} initialValues={initialValues}
@@ -100,6 +103,7 @@ function MoneyInForm({
> >
<MoneyInFormContent /> <MoneyInFormContent />
</Formik> </Formik>
</div>
); );
} }

View File

@@ -12,13 +12,17 @@ import { useMoneyInDailogContext } from './MoneyInDialogProvider';
* Money in form fields. * Money in form fields.
*/ */
function MoneyInFormFields() { function MoneyInFormFields() {
const { values } = useFormikContext();
// Money in dialog context. // Money in dialog context.
const { defaultAccountId } = useMoneyInDailogContext(); const { accountId } = useMoneyInDailogContext();
return ( return (
<div className={Classes.DIALOG_BODY}> <div className={Classes.DIALOG_BODY}>
{!defaultAccountId && <TransactionTypeFields />} <If condition={!accountId}>
<MoneyInContentFields /> <TransactionTypeFields />
</If>
<MoneyInContentFields accountType={values.transaction_type} />
</div> </div>
); );
} }

View File

@@ -1,9 +1,10 @@
// @ts-nocheck // @ts-nocheck
import React from 'react'; import React from 'react';
import { FastField, ErrorMessage } from 'formik'; import { FastField, Field, ErrorMessage, useFormikContext } from 'formik';
import { import {
Classes, Classes,
FormGroup, FormGroup,
InputGroup,
TextArea, TextArea,
Position, Position,
ControlGroup, ControlGroup,
@@ -17,15 +18,14 @@ import {
FieldRequiredHint, FieldRequiredHint,
Col, Col,
Row, Row,
If,
FeatureCan, FeatureCan,
BranchSelect, BranchSelect,
BranchSelectButton, BranchSelectButton,
FInputGroup, ExchangeRateMutedField,
FFormGroup,
FTextArea,
FMoneyInputGroup,
} from '@/components'; } from '@/components';
import { DateInput } from '@blueprintjs/datetime'; import { DateInput } from '@blueprintjs/datetime';
import { useAutofocus } from '@/hooks';
import { CLASSES, ACCOUNT_TYPE, Features } from '@/constants'; import { CLASSES, ACCOUNT_TYPE, Features } from '@/constants';
import { import {
@@ -36,18 +36,22 @@ import {
} from '@/utils'; } from '@/utils';
import { useMoneyInDailogContext } from '../MoneyInDialogProvider'; import { useMoneyInDailogContext } from '../MoneyInDialogProvider';
import { useSetPrimaryBranchToForm, BranchRowDivider } from '../utils'; import {
useSetPrimaryBranchToForm,
useForeignAccount,
BranchRowDivider,
} from '../utils';
import { MoneyInOutTransactionNoField } from '../../_components'; import { MoneyInOutTransactionNoField } from '../../_components';
import { useMoneyInFieldsContext } from '../MoneyInFieldsProvider';
import { MoneyInExchangeRateField } from '../MoneyInExchangeRateField';
/** /**
* Other income form fields. * Other income form fields.
*/ */
export default function OtherIncomeFormFields() { export default function OtherIncomeFormFields() {
// Money in dialog context. // Money in dialog context.
const { accounts, branches } = useMoneyInDailogContext(); const { accounts, account, branches } = useMoneyInDailogContext();
const { account } = useMoneyInFieldsContext(); const { values } = useFormikContext();
const amountFieldRef = useAutofocus();
const isForeigAccount = useForeignAccount();
// Sets the primary branch to form. // Sets the primary branch to form.
useSetPrimaryBranchToForm(); useSetPrimaryBranchToForm();
@@ -57,14 +61,17 @@ export default function OtherIncomeFormFields() {
<FeatureCan feature={Features.Branches}> <FeatureCan feature={Features.Branches}>
<Row> <Row>
<Col xs={5}> <Col xs={5}>
<FFormGroup name={'amount'} label={<T id={'branch'} />}> <FormGroup
label={<T id={'branch'} />}
className={classNames('form-group--select-list', Classes.FILL)}
>
<BranchSelect <BranchSelect
name={'branch_id'} name={'branch_id'}
branches={branches} branches={branches}
input={BranchSelectButton} input={BranchSelectButton}
popoverProps={{ minimal: true }} popoverProps={{ minimal: true }}
/> />
</FFormGroup> </FormGroup>
</Col> </Col>
</Row> </Row>
<BranchRowDivider /> <BranchRowDivider />
@@ -99,32 +106,53 @@ export default function OtherIncomeFormFields() {
)} )}
</FastField> </FastField>
</Col> </Col>
<Col xs={5}> <Col xs={5}>
{/*------------ Transaction number -----------*/} {/*------------ Transaction number -----------*/}
<MoneyInOutTransactionNoField /> <MoneyInOutTransactionNoField />
</Col> </Col>
</Row> </Row>
{/*------------ amount -----------*/}
{/*------------ Amount -----------*/} <FastField name={'amount'}>
<Row> {({
<Col xs={10}> form: { values, setFieldValue },
<FFormGroup field: { value },
name={'amount'} meta: { error, touched },
}) => (
<FormGroup
label={<T id={'amount'} />} label={<T id={'amount'} />}
labelInfo={<FieldRequiredHint />} labelInfo={<FieldRequiredHint />}
intent={inputIntent({ error, touched })}
helperText={<ErrorMessage name="amount" />}
className={'form-group--amount'}
> >
<ControlGroup> <ControlGroup>
<InputPrependText text={account.currency_code} /> <InputPrependText text={account.currency_code} />
<FMoneyInputGroup name={'amount'} minimal={true} />
<MoneyInputGroup
value={value}
minimal={true}
onChange={(amount) => {
setFieldValue('amount', amount);
}}
inputRef={(ref) => (amountFieldRef.current = ref)}
intent={inputIntent({ error, touched })}
/>
</ControlGroup> </ControlGroup>
</FFormGroup> </FormGroup>
</Col> )}
</Row> </FastField>
{/*------------ Exchange rate -----------*/}
<MoneyInExchangeRateField />
<If condition={isForeigAccount}>
{/*------------ exchange rate -----------*/}
<ExchangeRateMutedField
name={'exchange_rate'}
fromCurrency={values.currency_code}
toCurrency={account.currency_code}
formGroupProps={{ label: '', inline: false }}
date={values.date}
exchangeRate={values.exchange_rate}
/>
</If>
<Row> <Row>
<Col xs={5}> <Col xs={5}>
{/*------------ other income account -----------*/} {/*------------ other income account -----------*/}
@@ -154,24 +182,43 @@ export default function OtherIncomeFormFields() {
)} )}
</FastField> </FastField>
</Col> </Col>
<Col xs={5}> <Col xs={5}>
{/*------------ Reference -----------*/} {/*------------ Reference -----------*/}
<FFormGroup label={<T id={'reference_no'} />} name={'reference_no'}> <FastField name={'reference_no'}>
<FInputGroup name={'reference_no'} /> {({ form, field, meta: { error, touched } }) => (
</FFormGroup> <FormGroup
label={<T id={'reference_no'} />}
intent={inputIntent({ error, touched })}
helperText={<ErrorMessage name="reference_no" />}
className={'form-group--reference-no'}
>
<InputGroup
intent={inputIntent({ error, touched })}
{...field}
/>
</FormGroup>
)}
</FastField>
</Col> </Col>
</Row> </Row>
{/*------------ description -----------*/}
{/*------------ Description -----------*/} <FastField name={'description'}>
<FFormGroup name={'description'} label={<T id={'description'} />}> {({ field, meta: { error, touched } }) => (
<FTextArea <FormGroup
name={'description'} label={<T id={'description'} />}
className={'form-group--description'}
intent={inputIntent({ error, touched })}
helperText={<ErrorMessage name={'description'} />}
>
<TextArea
growVertically={true} growVertically={true}
large={true} large={true}
fill={true} intent={inputIntent({ error, touched })}
{...field}
/> />
</FFormGroup> </FormGroup>
)}
</FastField>
</React.Fragment> </React.Fragment>
); );
} }

View File

@@ -1,24 +1,32 @@
// @ts-nocheck // @ts-nocheck
import React from 'react'; import React from 'react';
import { FastField, ErrorMessage } from 'formik'; import { FastField, Field, ErrorMessage, useFormikContext } from 'formik';
import { FormGroup, Position, ControlGroup } from '@blueprintjs/core'; import {
Classes,
FormGroup,
InputGroup,
TextArea,
Position,
ControlGroup,
} from '@blueprintjs/core';
import classNames from 'classnames'; import classNames from 'classnames';
import { DateInput } from '@blueprintjs/datetime';
import { import {
FormattedMessage as T, FormattedMessage as T,
AccountsSuggestField, AccountsSuggestField,
InputPrependText, InputPrependText,
MoneyInputGroup,
FieldRequiredHint, FieldRequiredHint,
Col, Col,
Row, Row,
If,
ExchangeRateMutedField,
BranchSelect, BranchSelect,
BranchSelectButton, BranchSelectButton,
FeatureCan, FeatureCan,
FFormGroup,
FMoneyInputGroup,
FTextArea,
FInputGroup,
} from '@/components'; } from '@/components';
import { DateInput } from '@blueprintjs/datetime';
import { useAutofocus } from '@/hooks';
import { ACCOUNT_TYPE, CLASSES, Features } from '@/constants'; import { ACCOUNT_TYPE, CLASSES, Features } from '@/constants';
import { import {
inputIntent, inputIntent,
@@ -29,11 +37,10 @@ import {
import { useMoneyInDailogContext } from '../MoneyInDialogProvider'; import { useMoneyInDailogContext } from '../MoneyInDialogProvider';
import { import {
useSetPrimaryBranchToForm, useSetPrimaryBranchToForm,
useForeignAccount,
BranchRowDivider, BranchRowDivider,
} from '../../MoneyInDialog/utils'; } from '../../MoneyInDialog/utils';
import { MoneyInOutTransactionNoField } from '../../_components'; import { MoneyInOutTransactionNoField } from '../../_components';
import { useMoneyInFieldsContext } from '../MoneyInFieldsProvider';
import { MoneyInExchangeRateField } from '../MoneyInExchangeRateField';
/** /**
/** /**
@@ -41,8 +48,13 @@ import { MoneyInExchangeRateField } from '../MoneyInExchangeRateField';
*/ */
export default function OwnerContributionFormFields() { export default function OwnerContributionFormFields() {
// Money in dialog context. // Money in dialog context.
const { accounts, branches } = useMoneyInDailogContext(); const { accounts, account, branches } = useMoneyInDailogContext();
const { account } = useMoneyInFieldsContext();
const { values } = useFormikContext();
const amountFieldRef = useAutofocus();
const isForeigAccount = useForeignAccount();
// Sets the primary branch to form. // Sets the primary branch to form.
useSetPrimaryBranchToForm(); useSetPrimaryBranchToForm();
@@ -52,19 +64,21 @@ export default function OwnerContributionFormFields() {
<FeatureCan feature={Features.Branches}> <FeatureCan feature={Features.Branches}>
<Row> <Row>
<Col xs={5}> <Col xs={5}>
<FFormGroup name={'branch_id'} label={<T id={'branch'} />}> <FormGroup
label={<T id={'branch'} />}
className={classNames('form-group--select-list', Classes.FILL)}
>
<BranchSelect <BranchSelect
name={'branch_id'} name={'branch_id'}
branches={branches} branches={branches}
input={BranchSelectButton} input={BranchSelectButton}
popoverProps={{ minimal: true }} popoverProps={{ minimal: true }}
/> />
</FFormGroup> </FormGroup>
</Col> </Col>
</Row> </Row>
<BranchRowDivider /> <BranchRowDivider />
</FeatureCan> </FeatureCan>
<Row> <Row>
<Col xs={5}> <Col xs={5}>
{/*------------ Date -----------*/} {/*------------ Date -----------*/}
@@ -99,26 +113,47 @@ export default function OwnerContributionFormFields() {
<MoneyInOutTransactionNoField /> <MoneyInOutTransactionNoField />
</Col> </Col>
</Row> </Row>
{/*------------ amount -----------*/}
{/*------------ Amount -----------*/} <Field name={'amount'}>
<Row> {({
<Col xs={10}> form: { values, setFieldValue },
<FFormGroup field: { value },
name={'amount'} meta: { error, touched },
}) => (
<FormGroup
label={<T id={'amount'} />} label={<T id={'amount'} />}
labelInfo={<FieldRequiredHint />} labelInfo={<FieldRequiredHint />}
intent={inputIntent({ error, touched })}
helperText={<ErrorMessage name="amount" />}
className={'form-group--amount'}
> >
<ControlGroup> <ControlGroup>
<InputPrependText text={account?.currency_code || '--'} /> <InputPrependText text={account?.currency_code} />
<FMoneyInputGroup name={'amount'} minimal={true} />
<MoneyInputGroup
value={value}
minimal={true}
onChange={(amount) => {
setFieldValue('amount', amount);
}}
inputRef={(ref) => (amountFieldRef.current = ref)}
intent={inputIntent({ error, touched })}
/>
</ControlGroup> </ControlGroup>
</FFormGroup> </FormGroup>
</Col> )}
</Row> </Field>
<If condition={isForeigAccount}>
{/*------------ Exchange rate -----------*/} {/*------------ exchange rate -----------*/}
<MoneyInExchangeRateField /> <ExchangeRateMutedField
name={'exchange_rate'}
fromCurrency={values.currency_code}
toCurrency={account.currency_code}
formGroupProps={{ label: '', inline: false }}
date={values.date}
exchangeRate={values.exchange_rate}
/>
</If>
<Row> <Row>
<Col xs={5}> <Col xs={5}>
{/*------------ equity account -----------*/} {/*------------ equity account -----------*/}
@@ -146,24 +181,43 @@ export default function OwnerContributionFormFields() {
)} )}
</FastField> </FastField>
</Col> </Col>
<Col xs={5}> <Col xs={5}>
{/*------------ Reference -----------*/} {/*------------ Reference -----------*/}
<FFormGroup name={'reference_no'} label={<T id={'reference_no'} />}> <FastField name={'reference_no'}>
<FInputGroup name={'reference_no'} /> {({ form, field, meta: { error, touched } }) => (
</FFormGroup> <FormGroup
label={<T id={'reference_no'} />}
intent={inputIntent({ error, touched })}
helperText={<ErrorMessage name="reference_no" />}
className={'form-group--reference-no'}
>
<InputGroup
intent={inputIntent({ error, touched })}
{...field}
/>
</FormGroup>
)}
</FastField>
</Col> </Col>
</Row> </Row>
{/*------------ description -----------*/}
{/*------------ Description -----------*/} <FastField name={'description'}>
<FFormGroup name={'description'} label={<T id={'description'} />}> {({ field, meta: { error, touched } }) => (
<FTextArea <FormGroup
name={'description'} label={<T id={'description'} />}
className={'form-group--description'}
intent={inputIntent({ error, touched })}
helperText={<ErrorMessage name={'description'} />}
>
<TextArea
growVertically={true} growVertically={true}
large={true} large={true}
fill={true} intent={inputIntent({ error, touched })}
{...field}
/> />
</FFormGroup> </FormGroup>
)}
</FastField>
</React.Fragment> </React.Fragment>
); );
} }

View File

@@ -10,8 +10,6 @@ import {
ListSelect, ListSelect,
Col, Col,
Row, Row,
FFormGroup,
FSelect,
} from '@/components'; } from '@/components';
import { inputIntent } from '@/utils'; import { inputIntent } from '@/utils';
import { CLASSES, getAddMoneyInOptions } from '@/constants'; import { CLASSES, getAddMoneyInOptions } from '@/constants';
@@ -23,7 +21,7 @@ import { useMoneyInDailogContext } from './MoneyInDialogProvider';
*/ */
export default function TransactionTypeFields() { export default function TransactionTypeFields() {
// Money in dialog context. // Money in dialog context.
const { cashflowAccounts, setAccountId } = useMoneyInDailogContext(); const { cashflowAccounts } = useMoneyInDailogContext();
// Retrieves the add money in button options. // Retrieves the add money in button options.
const addMoneyInOptions = useMemo(() => getAddMoneyInOptions(), []); const addMoneyInOptions = useMemo(() => getAddMoneyInOptions(), []);
@@ -31,23 +29,6 @@ export default function TransactionTypeFields() {
return ( return (
<div className="trasnaction-type-fileds"> <div className="trasnaction-type-fileds">
<Row> <Row>
<Col xs={5}>
{/*------------ Transaction type -----------*/}
<FFormGroup
name={'transaction_type'}
label={<T id={'transaction_type'} />}
labelInfo={<FieldRequiredHint />}
>
<FSelect
name={'transaction_type'}
items={addMoneyInOptions}
popoverProps={{ minimal: true }}
valueAccessor={'value'}
textAccessor={'name'}
/>
</FFormGroup>
</Col>
<Col xs={5}> <Col xs={5}>
{/*------------ Current account -----------*/} {/*------------ Current account -----------*/}
<FastField name={'cashflow_account_id'}> <FastField name={'cashflow_account_id'}>
@@ -65,10 +46,9 @@ export default function TransactionTypeFields() {
> >
<AccountsSuggestField <AccountsSuggestField
accounts={cashflowAccounts} accounts={cashflowAccounts}
onAccountSelected={({ id }) => { onAccountSelected={({ id }) =>
form.setFieldValue('cashflow_account_id', id); form.setFieldValue('cashflow_account_id', id)
setAccountId(id); }
}}
inputProps={{ inputProps={{
intent: inputIntent({ error, touched }), intent: inputIntent({ error, touched }),
}} }}
@@ -76,6 +56,39 @@ export default function TransactionTypeFields() {
</FormGroup> </FormGroup>
)} )}
</FastField> </FastField>
{/*------------ Transaction type -----------*/}
</Col>
<Col xs={5}>
<Field name={'transaction_type'}>
{({
form: { values, setFieldValue },
field: { value },
meta: { error, touched },
}) => (
<FormGroup
label={<T id={'transaction_type'} />}
labelInfo={<FieldRequiredHint />}
helperText={<ErrorMessage name="transaction_type" />}
intent={inputIntent({ error, touched })}
className={classNames(
CLASSES.FILL,
'form-group--transaction_type',
)}
>
<ListSelect
items={addMoneyInOptions}
onItemSelect={(type) => {
setFieldValue('transaction_type', type.value);
}}
filterable={false}
selectedItem={value}
selectedItemProp={'value'}
textProp={'name'}
popoverProps={{ minimal: true }}
/>
</FormGroup>
)}
</Field>
</Col> </Col>
</Row> </Row>
</div> </div>

View File

@@ -1,27 +1,33 @@
// @ts-nocheck // @ts-nocheck
import React from 'react'; import React from 'react';
import { FastField, ErrorMessage } from 'formik'; import { FastField, Field, ErrorMessage, useFormikContext } from 'formik';
import { DateInput } from '@blueprintjs/datetime'; import { DateInput } from '@blueprintjs/datetime';
import { FormGroup, Position, ControlGroup } from '@blueprintjs/core'; import {
Classes,
FormGroup,
InputGroup,
TextArea,
Position,
ControlGroup,
} from '@blueprintjs/core';
import classNames from 'classnames'; import classNames from 'classnames';
import { import {
FormattedMessage as T, FormattedMessage as T,
AccountsSuggestField, AccountsSuggestField,
InputPrependText, InputPrependText,
MoneyInputGroup,
FieldRequiredHint, FieldRequiredHint,
Col, Col,
Row, Row,
If,
ExchangeRateMutedField,
FeatureCan, FeatureCan,
BranchSelect, BranchSelect,
BranchSelectButton, BranchSelectButton,
FMoneyInputGroup,
FInputGroup,
FFormGroup,
FTextArea,
} from '@/components'; } from '@/components';
import { MoneyInOutTransactionNoField } from '../../_components'; import { useAutofocus } from '@/hooks';
import { MoneyInExchangeRateField } from '../MoneyInExchangeRateField';
import { CLASSES, ACCOUNT_TYPE, Features } from '@/constants'; import { CLASSES, ACCOUNT_TYPE, Features } from '@/constants';
import { import {
inputIntent, inputIntent,
momentFormatter, momentFormatter,
@@ -29,19 +35,25 @@ import {
handleDateChange, handleDateChange,
} from '@/utils'; } from '@/utils';
import { useMoneyInDailogContext } from '../MoneyInDialogProvider'; import { useMoneyInDailogContext } from '../MoneyInDialogProvider';
import { useMoneyInFieldsContext } from '../MoneyInFieldsProvider';
import { import {
useSetPrimaryBranchToForm, useSetPrimaryBranchToForm,
useForeignAccount,
BranchRowDivider, BranchRowDivider,
} from '../../MoneyInDialog/utils'; } from '../../MoneyInDialog/utils';
import { MoneyInOutTransactionNoField } from '../../_components';
/** /**
* Transfer from account form fields. * Transfer from account form fields.
*/ */
export default function TransferFromAccountFormFields() { export default function TransferFromAccountFormFields() {
// Money in dialog context. // Money in dialog context.
const { accounts, branches } = useMoneyInDailogContext(); const { accounts, account, branches } = useMoneyInDailogContext();
const { account } = useMoneyInFieldsContext();
const isForeigAccount = useForeignAccount();
const amountFieldRef = useAutofocus();
const { values } = useFormikContext();
// Sets the primary branch to form. // Sets the primary branch to form.
useSetPrimaryBranchToForm(); useSetPrimaryBranchToForm();
@@ -51,14 +63,17 @@ export default function TransferFromAccountFormFields() {
<FeatureCan feature={Features.Branches}> <FeatureCan feature={Features.Branches}>
<Row> <Row>
<Col xs={5}> <Col xs={5}>
<FFormGroup label={<T id={'branch'} />} name={'branch_id'}> <FormGroup
label={<T id={'branch'} />}
className={classNames('form-group--select-list', Classes.FILL)}
>
<BranchSelect <BranchSelect
name={'branch_id'} name={'branch_id'}
branches={branches} branches={branches}
input={BranchSelectButton} input={BranchSelectButton}
popoverProps={{ minimal: true }} popoverProps={{ minimal: true }}
/> />
</FFormGroup> </FormGroup>
</Col> </Col>
</Row> </Row>
<BranchRowDivider /> <BranchRowDivider />
@@ -97,27 +112,50 @@ export default function TransferFromAccountFormFields() {
<MoneyInOutTransactionNoField /> <MoneyInOutTransactionNoField />
</Col> </Col>
</Row> </Row>
{/*------------ Amount -----------*/} {/*------------ amount -----------*/}
<Row> <FastField name={'amount'}>
<Col xs={10}> {({
form: { values, setFieldValue },
field: { value },
meta: { error, touched },
}) => (
<FormGroup <FormGroup
label={<T id={'amount'} />} label={<T id={'amount'} />}
labelInfo={<FieldRequiredHint />} labelInfo={<FieldRequiredHint />}
intent={inputIntent({ error, touched })}
helperText={<ErrorMessage name="amount" />}
className={'form-group--amount'}
> >
<ControlGroup> <ControlGroup>
<InputPrependText text={account.currency_code || '--'} /> <InputPrependText text={account.currency_code} />
<FMoneyInputGroup name={'amount'} minimal={true} />
<MoneyInputGroup
value={value}
minimal={true}
onChange={(amount) => {
setFieldValue('amount', amount);
}}
inputRef={(ref) => (amountFieldRef.current = ref)}
intent={inputIntent({ error, touched })}
/>
</ControlGroup> </ControlGroup>
</FormGroup> </FormGroup>
</Col> )}
</Row> </FastField>
<If condition={isForeigAccount}>
{/*------------ Exchange rate -----------*/} {/*------------ exchange rate -----------*/}
<MoneyInExchangeRateField /> <ExchangeRateMutedField
name={'exchange_rate'}
fromCurrency={values.currency_code}
toCurrency={account.currency_code}
formGroupProps={{ label: '', inline: false }}
date={values.date}
exchangeRate={values.exchange_rate}
/>
</If>
<Row> <Row>
<Col xs={5}> <Col xs={5}>
{/*------------ Transfer from account -----------*/} {/*------------ transfer from account -----------*/}
<FastField name={'credit_account_id'}> <FastField name={'credit_account_id'}>
{({ form, field, meta: { error, touched } }) => ( {({ form, field, meta: { error, touched } }) => (
<FormGroup <FormGroup
@@ -147,24 +185,43 @@ export default function TransferFromAccountFormFields() {
)} )}
</FastField> </FastField>
</Col> </Col>
<Col xs={5}> <Col xs={5}>
{/*------------ Reference -----------*/} {/*------------ Reference -----------*/}
<FFormGroup name={'reference_no'} label={<T id={'reference_no'} />}> <FastField name={'reference_no'}>
<FInputGroup name={'reference_no'} /> {({ form, field, meta: { error, touched } }) => (
</FFormGroup> <FormGroup
</Col> label={<T id={'reference_no'} />}
</Row> intent={inputIntent({ error, touched })}
helperText={<ErrorMessage name="reference_no" />}
{/*------------ Description -----------*/} className={'form-group--reference-no'}
<FormGroup name={'description'} label={<T id={'description'} />}> >
<FTextArea <InputGroup
name={'description'} intent={inputIntent({ error, touched })}
growVertically={true} {...field}
large={true}
fill={true}
/> />
</FormGroup> </FormGroup>
)}
</FastField>
</Col>
</Row>
{/*------------ description -----------*/}
<FastField name={'description'}>
{({ field, meta: { error, touched } }) => (
<FormGroup
label={<T id={'description'} />}
className={'form-group--description'}
intent={inputIntent({ error, touched })}
helperText={<ErrorMessage name={'description'} />}
>
<TextArea
growVertically={true}
large={true}
intent={inputIntent({ error, touched })}
{...field}
/>
</FormGroup>
)}
</FastField>
</React.Fragment> </React.Fragment>
); );
} }

View File

@@ -3,6 +3,7 @@ import React from 'react';
import intl from 'react-intl-universal'; import intl from 'react-intl-universal';
import { Dialog, DialogSuspense } from '@/components'; import { Dialog, DialogSuspense } from '@/components';
import withDialogRedux from '@/components/DialogReduxConnect'; import withDialogRedux from '@/components/DialogReduxConnect';
import { compose } from '@/utils'; import { compose } from '@/utils';
const MoneyInDialogContent = React.lazy(() => import('./MoneyInDialogContent')); const MoneyInDialogContent = React.lazy(() => import('./MoneyInDialogContent'));

View File

@@ -6,7 +6,6 @@ import { transactionNumber } from '@/utils';
import { isEqual, isNull, first } from 'lodash'; import { isEqual, isNull, first } from 'lodash';
import { useMoneyInDailogContext } from './MoneyInDialogProvider'; import { useMoneyInDailogContext } from './MoneyInDialogProvider';
import { useMoneyInFieldsContext } from './MoneyInFieldsProvider';
export const useObserveTransactionNoSettings = (prefix, nextNumber) => { export const useObserveTransactionNoSettings = (prefix, nextNumber) => {
const { setFieldValue } = useFormikContext(); const { setFieldValue } = useFormikContext();
@@ -34,7 +33,7 @@ export const useSetPrimaryBranchToForm = () => {
export const useForeignAccount = () => { export const useForeignAccount = () => {
const { values } = useFormikContext(); const { values } = useFormikContext();
const { account } = useMoneyInFieldsContext(); const { account } = useMoneyInDailogContext();
return ( return (
!isEqual(account.currency_code, values.currency_code) && !isEqual(account.currency_code, values.currency_code) &&

View File

@@ -1,22 +1,13 @@
// @ts-nocheck // @ts-nocheck
import React, { useMemo } from 'react'; import React from 'react';
import { useFormikContext } from 'formik';
import OtherExpnseFormFields from './OtherExpense/OtherExpnseFormFields'; import OtherExpnseFormFields from './OtherExpense/OtherExpnseFormFields';
import OwnerDrawingsFormFields from './OwnerDrawings/OwnerDrawingsFormFields'; import OwnerDrawingsFormFields from './OwnerDrawings/OwnerDrawingsFormFields';
import TransferToAccountFormFields from './TransferToAccount/TransferToAccountFormFields'; import TransferToAccountFormFields from './TransferToAccount/TransferToAccountFormFields';
import { MoneyOutFieldsProvider } from './MoneyOutFieldsProvider';
/** function MoneyOutContentFields({ accountType }) {
* Money out content fields. const handleTransactionType = () => {
* Switches between form fields based on the given transaction type. switch (accountType) {
* @returns {JSX.Element}
*/
function MoneyOutContentFields() {
const { values } = useFormikContext();
const transactionType = useMemo(() => {
switch (values.transaction_type) {
case 'OwnerDrawing': case 'OwnerDrawing':
return <OwnerDrawingsFormFields />; return <OwnerDrawingsFormFields />;
@@ -28,12 +19,8 @@ function MoneyOutContentFields() {
default: default:
break; break;
} }
}, [values.transaction_type]); };
return <React.Fragment>{handleTransactionType()}</React.Fragment>;
// Cannot continue if transaction type or account is not selected.
if (!values.transaction_type || !values.cashflow_account_id) return null;
return <MoneyOutFieldsProvider>{transactionType}</MoneyOutFieldsProvider>;
} }
export default MoneyOutContentFields; export default MoneyOutContentFields;

View File

@@ -1,10 +1,11 @@
// @ts-nocheck // @ts-nocheck
import React, { useState } from 'react'; import React from 'react';
import { DialogContent } from '@/components'; import { DialogContent } from '@/components';
import { Features } from '@/constants'; import { Features } from '@/constants';
import { useFeatureCan } from '@/hooks/state'; import { useFeatureCan } from '@/hooks/state';
import { import {
useAccounts, useAccounts,
useAccount,
useBranches, useBranches,
useCreateCashflowTransaction, useCreateCashflowTransaction,
useCashflowAccounts, useCashflowAccounts,
@@ -16,15 +17,7 @@ const MoneyInDialogContent = React.createContext();
/** /**
* Money out dialog provider. * Money out dialog provider.
*/ */
function MoneyOutProvider({ function MoneyOutProvider({ accountId, accountType, dialogName, ...props }) {
accountId: defaultAccountId,
accountType,
dialogName,
...props
}) {
// Holds the selected account id of the dialog.
const [accountId, setAccountId] = useState<number | null>(defaultAccountId);
// Features guard. // Features guard.
const { featureCan } = useFeatureCan(); const { featureCan } = useFeatureCan();
const isBranchFeatureCan = featureCan(Features.Branches); const isBranchFeatureCan = featureCan(Features.Branches);
@@ -32,6 +25,11 @@ function MoneyOutProvider({
// Fetches accounts list. // Fetches accounts list.
const { isLoading: isAccountsLoading, data: accounts } = useAccounts(); const { isLoading: isAccountsLoading, data: accounts } = useAccounts();
// Fetches the specific account details.
const { data: account, isLoading: isAccountLoading } = useAccount(accountId, {
enabled: !!accountId,
});
// Fetches the branches list. // Fetches the branches list.
const { const {
data: branches, data: branches,
@@ -43,7 +41,6 @@ function MoneyOutProvider({
const { data: cashflowAccounts, isLoading: isCashFlowAccountsLoading } = const { data: cashflowAccounts, isLoading: isCashFlowAccountsLoading } =
useCashflowAccounts({}, { keepPreviousData: true }); useCashflowAccounts({}, { keepPreviousData: true });
// Mutation to create a new cashflow account.
const { mutateAsync: createCashflowTransactionMutate } = const { mutateAsync: createCashflowTransactionMutate } =
useCreateCashflowTransaction(); useCreateCashflowTransaction();
@@ -53,13 +50,11 @@ function MoneyOutProvider({
// Submit payload. // Submit payload.
const [submitPayload, setSubmitPayload] = React.useState({}); const [submitPayload, setSubmitPayload] = React.useState({});
// Provider data. // provider.
const provider = { const provider = {
accountId,
setAccountId,
defaultAccountId,
accounts, accounts,
account,
accountId,
accountType, accountType,
branches, branches,
isAccountsLoading, isAccountsLoading,
@@ -74,14 +69,15 @@ function MoneyOutProvider({
setSubmitPayload, setSubmitPayload,
}; };
const isLoading = return (
<DialogContent
isLoading={
isAccountsLoading || isAccountsLoading ||
isCashFlowAccountsLoading || isCashFlowAccountsLoading ||
isBranchesLoading || isBranchesLoading ||
isSettingsLoading; isSettingsLoading
}
return ( >
<DialogContent isLoading={isLoading}>
<MoneyInDialogContent.Provider value={provider} {...props} /> <MoneyInDialogContent.Provider value={provider} {...props} />
</DialogContent> </DialogContent>
); );

View File

@@ -1,31 +0,0 @@
// @ts-nocheck
import React from 'react';
import { useFormikContext } from 'formik';
import { useForeignAccount } from './utils';
import { ExchangeRateMutedField } from '@/components';
import { useMoneyOutFieldsContext } from './MoneyOutFieldsProvider';
/**
* Money-out exchange rate field.
* @returns {JSX.Element}
*/
export function MoneyOutExchangeRateField() {
const { values } = useFormikContext();
const { account } = useMoneyOutFieldsContext();
const isForeigAccount = useForeignAccount();
// Cannot continue if the account is not foreign account.
if (!isForeigAccount) return null;
return (
<ExchangeRateMutedField
name={'exchange_rate'}
fromCurrency={values?.currency_code}
toCurrency={account?.currency_code}
formGroupProps={{ label: '', inline: false }}
date={values.date}
exchangeRate={values.exchange_rate}
/>
);
}

View File

@@ -1,34 +0,0 @@
// @ts-nocheck
import React from 'react';
import { DialogContent } from '@/components';
import { useAccount } from '@/hooks/query';
import { useMoneyOutDialogContext } from './MoneyOutDialogProvider';
const MoneyOutFieldsContext = React.createContext();
/**
* Money out fields dialog provider.
*/
function MoneyOutFieldsProvider({ ...props }) {
const { accountId } = useMoneyOutDialogContext();
// Fetches the specific account details.
const { data: account, isLoading: isAccountLoading } = useAccount(accountId, {
enabled: !!accountId,
});
// Provider data.
const provider = {
account,
};
const isLoading = isAccountLoading;
return (
<DialogContent isLoading={isLoading}>
<MoneyOutFieldsContext.Provider value={provider} {...props} />
</DialogContent>
);
}
const useMoneyOutFieldsContext = () => React.useContext(MoneyOutFieldsContext);
export { MoneyOutFieldsProvider, useMoneyOutFieldsContext };

View File

@@ -24,16 +24,18 @@ function MoneyOutFloatingActions({
useMoneyOutDialogContext(); useMoneyOutDialogContext();
// handle submit as draft button click. // handle submit as draft button click.
const handleSubmitDraftBtnClick = () => { const handleSubmitDraftBtnClick = (event) => {
setSubmitPayload({ publish: false }); setSubmitPayload({ publish: false });
submitForm(); submitForm();
}; };
// Handle submit button click. // Handle submit button click.
const handleSubmittBtnClick = () => { const handleSubmittBtnClick = (event) => {
setSubmitPayload({ publish: true }); setSubmitPayload({ publish: true });
}; };
// Handle close button click. // Handle close button click.
const handleCloseBtnClick = () => { const handleCloseBtnClick = (event) => {
closeDialog(dialogName); closeDialog(dialogName);
}; };

View File

@@ -92,6 +92,7 @@ function MoneyOutForm({
}); });
}; };
return ( return (
<div>
<Formik <Formik
validationSchema={CreateMoneyOutSchema} validationSchema={CreateMoneyOutSchema}
initialValues={initialValues} initialValues={initialValues}
@@ -99,6 +100,7 @@ function MoneyOutForm({
> >
<MoneyOutFormContent /> <MoneyOutFormContent />
</Formik> </Formik>
</div>
); );
} }

View File

@@ -17,7 +17,6 @@ export default function MoneyOutFormDialog() {
setFieldValue('transaction_number', incrementNumber || ''); setFieldValue('transaction_number', incrementNumber || '');
setFieldValue('transaction_number_manually', manually); setFieldValue('transaction_number_manually', manually);
}; };
return ( return (
<React.Fragment> <React.Fragment>
<TransactionNumberDialog <TransactionNumberDialog

View File

@@ -1,18 +1,28 @@
// @ts-nocheck // @ts-nocheck
import React from 'react'; import React from 'react';
import { useFormikContext } from 'formik';
import { Classes } from '@blueprintjs/core'; import { Classes } from '@blueprintjs/core';
import { If } from '@/components';
import MoneyOutContentFields from './MoneyOutContentFields'; import MoneyOutContentFields from './MoneyOutContentFields';
import TransactionTypeFields from './TransactionTypeFields'; import TransactionTypeFields from './TransactionTypeFields';
import { useMoneyOutDialogContext } from './MoneyOutDialogProvider';
/** /**
* Money out form fields. * Money out form fields.
*/ */
function MoneyOutFormFields() { function MoneyOutFormFields() {
// Money in dialog context.
const { accountId } = useMoneyOutDialogContext();
const { values } = useFormikContext();
return ( return (
<div className={Classes.DIALOG_BODY}> <div className={Classes.DIALOG_BODY}>
<If condition={!accountId}>
<TransactionTypeFields /> <TransactionTypeFields />
<MoneyOutContentFields /> </If>
<MoneyOutContentFields accountType={values.transaction_type} />
</div> </div>
); );
} }

View File

@@ -1,25 +1,33 @@
// @ts-nocheck // @ts-nocheck
import React from 'react'; import React from 'react';
import { FastField, ErrorMessage } from 'formik'; import { FastField, Field, ErrorMessage, useFormikContext } from 'formik';
import { FormGroup, Position, ControlGroup } from '@blueprintjs/core'; import {
Classes,
FormGroup,
InputGroup,
TextArea,
Position,
ControlGroup,
} from '@blueprintjs/core';
import classNames from 'classnames'; import classNames from 'classnames';
import { import {
FormattedMessage as T, FormattedMessage as T,
AccountsSuggestField, AccountsSuggestField,
InputPrependText, InputPrependText,
MoneyInputGroup,
FieldRequiredHint, FieldRequiredHint,
Col, Col,
Row, Row,
If,
FeatureCan, FeatureCan,
BranchSelect, BranchSelect,
BranchSelectButton, BranchSelectButton,
FTextArea, ExchangeRateMutedField,
FFormGroup,
FInputGroup,
FMoneyInputGroup,
} from '@/components'; } from '@/components';
import { DateInput } from '@blueprintjs/datetime'; import { DateInput } from '@blueprintjs/datetime';
import { useAutofocus } from '@/hooks';
import { Features, ACCOUNT_TYPE } from '@/constants'; import { Features, ACCOUNT_TYPE } from '@/constants';
import { import {
inputIntent, inputIntent,
momentFormatter, momentFormatter,
@@ -28,18 +36,25 @@ import {
} from '@/utils'; } from '@/utils';
import { CLASSES } from '@/constants/classes'; import { CLASSES } from '@/constants/classes';
import { useMoneyOutDialogContext } from '../MoneyOutDialogProvider'; import { useMoneyOutDialogContext } from '../MoneyOutDialogProvider';
import { useSetPrimaryBranchToForm, BranchRowDivider } from '../utils'; import {
useSetPrimaryBranchToForm,
useForeignAccount,
BranchRowDivider,
} from '../utils';
import { MoneyInOutTransactionNoField } from '../../_components'; import { MoneyInOutTransactionNoField } from '../../_components';
import { MoneyOutExchangeRateField } from '../MoneyOutExchangeRateField';
import { useMoneyOutFieldsContext } from '../MoneyOutFieldsProvider';
/** /**
* Other expense form fields. * Other expense form fields.
*/ */
export default function OtherExpnseFormFields() { export default function OtherExpnseFormFields() {
// Money in dialog context. // Money in dialog context.
const { accounts, branches } = useMoneyOutDialogContext(); const { accounts, account, branches } = useMoneyOutDialogContext();
const { account } = useMoneyOutFieldsContext();
const isForeigAccount = useForeignAccount();
const { values } = useFormikContext();
const amountFieldRef = useAutofocus();
// Sets the primary branch to form. // Sets the primary branch to form.
useSetPrimaryBranchToForm(); useSetPrimaryBranchToForm();
@@ -49,19 +64,21 @@ export default function OtherExpnseFormFields() {
<FeatureCan feature={Features.Branches}> <FeatureCan feature={Features.Branches}>
<Row> <Row>
<Col xs={5}> <Col xs={5}>
<FFormGroup name={'branch_id'} label={<T id={'branch'} />}> <FormGroup
label={<T id={'branch'} />}
className={classNames('form-group--select-list', Classes.FILL)}
>
<BranchSelect <BranchSelect
name={'branch_id'} name={'branch_id'}
branches={branches} branches={branches}
input={BranchSelectButton} input={BranchSelectButton}
popoverProps={{ minimal: true }} popoverProps={{ minimal: true }}
/> />
</FFormGroup> </FormGroup>
</Col> </Col>
</Row> </Row>
<BranchRowDivider /> <BranchRowDivider />
</FeatureCan> </FeatureCan>
<Row> <Row>
<Col xs={5}> <Col xs={5}>
{/*------------ Date -----------*/} {/*------------ Date -----------*/}
@@ -96,27 +113,47 @@ export default function OtherExpnseFormFields() {
<MoneyInOutTransactionNoField /> <MoneyInOutTransactionNoField />
</Col> </Col>
</Row> </Row>
{/*------------ amount -----------*/} {/*------------ amount -----------*/}
<FastField name={'amount'}>
<Row> {({
<Col xs={10}> form: { values, setFieldValue },
<FFormGroup field: { value },
name={'amount'} meta: { error, touched },
}) => (
<FormGroup
label={<T id={'amount'} />} label={<T id={'amount'} />}
labelInfo={<FieldRequiredHint />} labelInfo={<FieldRequiredHint />}
intent={inputIntent({ error, touched })}
helperText={<ErrorMessage name="amount" />}
className={'form-group--amount'}
> >
<ControlGroup> <ControlGroup>
<InputPrependText text={account.currency_code} /> <InputPrependText text={account.currency_code} />
<FMoneyInputGroup name={'amount'} minimal={true} />
<MoneyInputGroup
value={value}
minimal={true}
onChange={(amount) => {
setFieldValue('amount', amount);
}}
inputRef={(ref) => (amountFieldRef.current = ref)}
intent={inputIntent({ error, touched })}
/>
</ControlGroup> </ControlGroup>
</FFormGroup> </FormGroup>
</Col> )}
</Row> </FastField>
<If condition={isForeigAccount}>
{/*------------ Exchange rate -----------*/} {/*------------ exchange rate -----------*/}
<MoneyOutExchangeRateField /> <ExchangeRateMutedField
name={'exchange_rate'}
fromCurrency={values.currency_code}
toCurrency={account.currency_code}
formGroupProps={{ label: '', inline: false }}
date={values.date}
exchangeRate={values.exchange_rate}
/>
</If>
<Row> <Row>
<Col xs={5}> <Col xs={5}>
{/*------------ other expense account -----------*/} {/*------------ other expense account -----------*/}
@@ -146,24 +183,44 @@ export default function OtherExpnseFormFields() {
)} )}
</FastField> </FastField>
</Col> </Col>
<Col xs={5}> <Col xs={5}>
{/*------------ Reference -----------*/} {/*------------ Reference -----------*/}
<FFormGroup name={'reference_no'} label={<T id={'reference_no'} />}> <FastField name={'reference_no'}>
<FInputGroup name={'reference_no'} /> {({ form, field, meta: { error, touched } }) => (
</FFormGroup> <FormGroup
label={<T id={'reference_no'} />}
intent={inputIntent({ error, touched })}
helperText={<ErrorMessage name="reference_no" />}
className={'form-group--reference-no'}
>
<InputGroup
intent={inputIntent({ error, touched })}
{...field}
/>
</FormGroup>
)}
</FastField>
</Col> </Col>
</Row> </Row>
{/*------------ description -----------*/} {/*------------ description -----------*/}
<FFormGroup name={'description'} label={<T id={'description'} />}> <FastField name={'description'}>
<FTextArea {({ field, meta: { error, touched } }) => (
name={'description'} <FormGroup
label={<T id={'description'} />}
className={'form-group--description'}
intent={inputIntent({ error, touched })}
helperText={<ErrorMessage name={'description'} />}
>
<TextArea
growVertically={true} growVertically={true}
large={true} large={true}
fill={true} intent={inputIntent({ error, touched })}
{...field}
/> />
</FFormGroup> </FormGroup>
)}
</FastField>
</React.Fragment> </React.Fragment>
); );
} }

View File

@@ -1,24 +1,31 @@
// @ts-nocheck // @ts-nocheck
import React from 'react'; import React from 'react';
import { FastField, ErrorMessage } from 'formik'; import { FastField, Field, ErrorMessage, useFormikContext } from 'formik';
import { DateInput } from '@blueprintjs/datetime'; import { DateInput } from '@blueprintjs/datetime';
import { FormGroup, Position, ControlGroup } from '@blueprintjs/core'; import {
Classes,
FormGroup,
InputGroup,
TextArea,
Position,
ControlGroup,
} from '@blueprintjs/core';
import classNames from 'classnames'; import classNames from 'classnames';
import { import {
FormattedMessage as T, FormattedMessage as T,
AccountsSuggestField, AccountsSuggestField,
InputPrependText, InputPrependText,
MoneyInputGroup,
FieldRequiredHint, FieldRequiredHint,
If,
Col, Col,
Row, Row,
FeatureCan, FeatureCan,
BranchSelect, BranchSelect,
BranchSelectButton, BranchSelectButton,
FFormGroup, ExchangeRateMutedField,
FTextArea,
FInputGroup,
FMoneyInputGroup,
} from '@/components'; } from '@/components';
import { useAutofocus } from '@/hooks';
import { CLASSES, Features, ACCOUNT_TYPE } from '@/constants'; import { CLASSES, Features, ACCOUNT_TYPE } from '@/constants';
import { import {
inputIntent, inputIntent,
@@ -29,19 +36,21 @@ import {
import { useMoneyOutDialogContext } from '../MoneyOutDialogProvider'; import { useMoneyOutDialogContext } from '../MoneyOutDialogProvider';
import { import {
useSetPrimaryBranchToForm, useSetPrimaryBranchToForm,
useForeignAccount,
BranchRowDivider, BranchRowDivider,
} from '../../MoneyOutDialog/utils'; } from '../../MoneyOutDialog/utils';
import { MoneyInOutTransactionNoField } from '../../_components'; import { MoneyInOutTransactionNoField } from '../../_components';
import { useMoneyOutFieldsContext } from '../MoneyOutFieldsProvider';
import { MoneyOutExchangeRateField } from '../MoneyOutExchangeRateField';
/** /**
* Owner drawings form fields. * Owner drawings form fields.
*/ */
export default function OwnerDrawingsFormFields() { export default function OwnerDrawingsFormFields() {
// Money out dialog context. // Money out dialog context.
const { accounts, branches } = useMoneyOutDialogContext(); const { accounts, account, branches } = useMoneyOutDialogContext();
const { account } = useMoneyOutFieldsContext(); const { values } = useFormikContext();
const isForeigAccount = useForeignAccount();
const amountFieldRef = useAutofocus();
// Sets the primary branch to form. // Sets the primary branch to form.
useSetPrimaryBranchToForm(); useSetPrimaryBranchToForm();
@@ -51,19 +60,21 @@ export default function OwnerDrawingsFormFields() {
<FeatureCan feature={Features.Branches}> <FeatureCan feature={Features.Branches}>
<Row> <Row>
<Col xs={5}> <Col xs={5}>
<FFormGroup label={<T id={'branch'} />} name={'branch_id'}> <FormGroup
label={<T id={'branch'} />}
className={classNames('form-group--select-list', Classes.FILL)}
>
<BranchSelect <BranchSelect
name={'branch_id'} name={'branch_id'}
branches={branches} branches={branches}
input={BranchSelectButton} input={BranchSelectButton}
popoverProps={{ minimal: true }} popoverProps={{ minimal: true }}
/> />
</FFormGroup> </FormGroup>
</Col> </Col>
</Row> </Row>
<BranchRowDivider /> <BranchRowDivider />
</FeatureCan> </FeatureCan>
<Row> <Row>
<Col xs={5}> <Col xs={5}>
{/*------------ Date -----------*/} {/*------------ Date -----------*/}
@@ -98,27 +109,48 @@ export default function OwnerDrawingsFormFields() {
<MoneyInOutTransactionNoField /> <MoneyInOutTransactionNoField />
</Col> </Col>
</Row> </Row>
{/*------------ amount -----------*/}
{/*------------ Amount -----------*/} <Field name={'amount'}>
{({
<Row> form: { values, setFieldValue },
<Col xs={10}> field: { value },
meta: { error, touched },
}) => (
<FormGroup <FormGroup
name={'amount'}
label={<T id={'amount'} />} label={<T id={'amount'} />}
labelInfo={<FieldRequiredHint />} labelInfo={<FieldRequiredHint />}
intent={inputIntent({ error, touched })}
helperText={<ErrorMessage name="amount" />}
className={'form-group--amount'}
> >
<ControlGroup> <ControlGroup>
<InputPrependText text={account.currency_code} /> <InputPrependText text={account.currency_code} />
<FMoneyInputGroup name={'amount'} minimal={true} />
<MoneyInputGroup
value={value}
minimal={true}
onChange={(amount) => {
setFieldValue('amount', amount);
}}
inputRef={(ref) => (amountFieldRef.current = ref)}
intent={inputIntent({ error, touched })}
/>
</ControlGroup> </ControlGroup>
</FormGroup> </FormGroup>
</Col> )}
</Row> </Field>
{/*------------ Exchange rate -----------*/}
<MoneyOutExchangeRateField />
<If condition={isForeigAccount}>
{/*------------ exchange rate -----------*/}
<ExchangeRateMutedField
name={'exchange_rate'}
fromCurrency={values?.currency_code}
toCurrency={account?.currency_code}
formGroupProps={{ label: '', inline: false }}
date={values.date}
exchangeRate={values.exchange_rate}
/>
</If>
<Row> <Row>
<Col xs={5}> <Col xs={5}>
{/*------------ equitty account -----------*/} {/*------------ equitty account -----------*/}
@@ -145,24 +177,44 @@ export default function OwnerDrawingsFormFields() {
)} )}
</FastField> </FastField>
</Col> </Col>
<Col xs={5}> <Col xs={5}>
{/*------------ Reference -----------*/} {/*------------ Reference -----------*/}
<FFormGroup name={'reference_no'} label={<T id={'reference_no'} />}> <FastField name={'reference_no'}>
<FInputGroup name={'reference_no'} /> {({ form, field, meta: { error, touched } }) => (
</FFormGroup> <FormGroup
label={<T id={'reference_no'} />}
intent={inputIntent({ error, touched })}
helperText={<ErrorMessage name="reference_no" />}
className={'form-group--reference-no'}
>
<InputGroup
intent={inputIntent({ error, touched })}
{...field}
/>
</FormGroup>
)}
</FastField>
</Col> </Col>
</Row> </Row>
{/*------------ description -----------*/} {/*------------ description -----------*/}
<FFormGroup name={'description'} label={<T id={'description'} />}> <FastField name={'description'}>
<FTextArea {({ field, meta: { error, touched } }) => (
name={'description'} <FormGroup
label={<T id={'description'} />}
className={'form-group--description'}
intent={inputIntent({ error, touched })}
helperText={<ErrorMessage name={'description'} />}
>
<TextArea
growVertically={true} growVertically={true}
large={true} large={true}
fill={true} intent={inputIntent({ error, touched })}
{...field}
/> />
</FFormGroup> </FormGroup>
)}
</FastField>
</React.Fragment> </React.Fragment>
); );
} }

View File

@@ -1,21 +1,22 @@
// @ts-nocheck // @ts-nocheck
import React, { useMemo } from 'react'; import React, { useMemo } from 'react';
import { FastField, ErrorMessage } from 'formik'; import { FastField, Field, ErrorMessage } from 'formik';
import { FormGroup } from '@blueprintjs/core'; import { FormGroup } from '@blueprintjs/core';
import classNames from 'classnames'; import classNames from 'classnames';
import { import {
FormattedMessage as T, FormattedMessage as T,
AccountsSuggestField, AccountsSuggestField,
FieldRequiredHint, FieldRequiredHint,
ListSelect,
Col, Col,
Row, Row,
FSelect,
FFormGroup,
} from '@/components'; } from '@/components';
import { inputIntent } from '@/utils'; import { inputIntent } from '@/utils';
import { getAddMoneyOutOptions } from '@/constants/cashflowOptions';
import { useMoneyOutDialogContext } from './MoneyOutDialogProvider';
import { CLASSES } from '@/constants/classes'; import { CLASSES } from '@/constants/classes';
import { getAddMoneyOutOptions } from '@/constants/cashflowOptions';
import { useMoneyOutDialogContext } from './MoneyOutDialogProvider';
/** /**
* Transaction type fields. * Transaction type fields.
@@ -26,32 +27,9 @@ function TransactionTypeFields() {
const addMoneyOutOptions = useMemo(() => getAddMoneyOutOptions(), []); const addMoneyOutOptions = useMemo(() => getAddMoneyOutOptions(), []);
// Money in dialog context.
const { defaultAccountId, setAccountId } = useMoneyOutDialogContext();
// Cannot continue if the default account id is defined.
if (defaultAccountId) return null;
return ( return (
<div className="trasnaction-type-fileds"> <div className="trasnaction-type-fileds">
<Row> <Row>
{/*------------ Transaction type -----------*/}
<Col xs={5}>
<FFormGroup
name={'transaction_type'}
label={<T id={'transaction_type'} />}
labelInfo={<FieldRequiredHint />}
>
<FSelect
name={'transaction_type'}
items={addMoneyOutOptions}
popoverProps={{ minimal: true }}
valueAccessor={'value'}
textAccessor={'name'}
/>
</FFormGroup>
</Col>
<Col xs={5}> <Col xs={5}>
{/*------------ Current account -----------*/} {/*------------ Current account -----------*/}
<FastField name={'cashflow_account_id'}> <FastField name={'cashflow_account_id'}>
@@ -69,10 +47,9 @@ function TransactionTypeFields() {
> >
<AccountsSuggestField <AccountsSuggestField
accounts={cashflowAccounts} accounts={cashflowAccounts}
onAccountSelected={({ id }) => { onAccountSelected={({ id }) =>
form.setFieldValue('cashflow_account_id', id); form.setFieldValue('cashflow_account_id', id)
setAccountId(id); }
}}
inputProps={{ inputProps={{
intent: inputIntent({ error, touched }), intent: inputIntent({ error, touched }),
}} }}
@@ -80,6 +57,39 @@ function TransactionTypeFields() {
</FormGroup> </FormGroup>
)} )}
</FastField> </FastField>
{/*------------ Transaction type -----------*/}
</Col>
<Col xs={5}>
<Field name={'transaction_type'}>
{({
form: { values, setFieldValue },
field: { value },
meta: { error, touched },
}) => (
<FormGroup
label={<T id={'transaction_type'} />}
labelInfo={<FieldRequiredHint />}
helperText={<ErrorMessage name="transaction_type" />}
intent={inputIntent({ error, touched })}
className={classNames(
CLASSES.FILL,
'form-group--transaction_type',
)}
>
<ListSelect
items={addMoneyOutOptions}
onItemSelect={(type) => {
setFieldValue('transaction_type', type.value);
}}
filterable={false}
selectedItem={value}
selectedItemProp={'value'}
textProp={'name'}
popoverProps={{ minimal: true }}
/>
</FormGroup>
)}
</Field>
</Col> </Col>
</Row> </Row>
</div> </div>

View File

@@ -1,46 +1,65 @@
// @ts-nocheck // @ts-nocheck
import React from 'react'; import React from 'react';
import { FastField, ErrorMessage } from 'formik'; import { FastField, Field, ErrorMessage, useFormikContext } from 'formik';
import { FormGroup, Position, ControlGroup } from '@blueprintjs/core'; import {
Classes,
FormGroup,
InputGroup,
TextArea,
Position,
ControlGroup,
} from '@blueprintjs/core';
import classNames from 'classnames'; import classNames from 'classnames';
import { import {
FormattedMessage as T, FormattedMessage as T,
AccountsSuggestField, AccountsSuggestField,
InputPrependText, InputPrependText,
MoneyInputGroup,
FieldRequiredHint, FieldRequiredHint,
Icon,
Col, Col,
Row, Row,
If,
InputPrependButton,
FeatureCan, FeatureCan,
BranchSelect, BranchSelect,
BranchSelectButton, BranchSelectButton,
FFormGroup, ExchangeRateMutedField,
FTextArea,
FMoneyInputGroup,
FInputGroup,
} from '@/components'; } from '@/components';
import { DateInput } from '@blueprintjs/datetime'; import { DateInput } from '@blueprintjs/datetime';
import { useAutofocus } from '@/hooks';
import { ACCOUNT_TYPE } from '@/constants/accountTypes'; import { ACCOUNT_TYPE } from '@/constants/accountTypes';
import { import {
inputIntent, inputIntent,
momentFormatter, momentFormatter,
tansformDateValue, tansformDateValue,
handleDateChange, handleDateChange,
compose,
} from '@/utils'; } from '@/utils';
import { Features } from '@/constants'; import { Features } from '@/constants';
import { CLASSES } from '@/constants/classes'; import { CLASSES } from '@/constants/classes';
import { useMoneyOutDialogContext } from '../MoneyOutDialogProvider'; import { useMoneyOutDialogContext } from '../MoneyOutDialogProvider';
import { useSetPrimaryBranchToForm, BranchRowDivider } from '../utils'; import {
useObserveTransactionNoSettings,
useSetPrimaryBranchToForm,
useForeignAccount,
BranchRowDivider,
} from '../utils';
import withSettings from '@/containers/Settings/withSettings';
import withDialogActions from '@/containers/Dialog/withDialogActions';
import { MoneyInOutTransactionNoField } from '../../_components'; import { MoneyInOutTransactionNoField } from '../../_components';
import { MoneyOutExchangeRateField } from '../MoneyOutExchangeRateField';
import { useMoneyOutFieldsContext } from '../MoneyOutFieldsProvider';
/** /**
* Transfer to account form fields. * Transfer to account form fields.
*/ */
export default function TransferToAccountFormFields() { export default function TransferToAccountFormFields() {
// Money in dialog context. // Money in dialog context.
const { accounts, branches } = useMoneyOutDialogContext(); const { accounts, account, branches } = useMoneyOutDialogContext();
const { account } = useMoneyOutFieldsContext(); const { values } = useFormikContext();
const isForeigAccount = useForeignAccount();
const accountRef = useAutofocus();
// Sets the primary branch to form. // Sets the primary branch to form.
useSetPrimaryBranchToForm(); useSetPrimaryBranchToForm();
@@ -50,19 +69,21 @@ export default function TransferToAccountFormFields() {
<FeatureCan feature={Features.Branches}> <FeatureCan feature={Features.Branches}>
<Row> <Row>
<Col xs={5}> <Col xs={5}>
<FFormGroup label={<T id={'branch'} />} name={'branch_id'}> <FormGroup
label={<T id={'branch'} />}
className={classNames('form-group--select-list', Classes.FILL)}
>
<BranchSelect <BranchSelect
name={'branch_id'} name={'branch_id'}
branches={branches} branches={branches}
input={BranchSelectButton} input={BranchSelectButton}
popoverProps={{ minimal: true }} popoverProps={{ minimal: true }}
/> />
</FFormGroup> </FormGroup>
</Col> </Col>
</Row> </Row>
<BranchRowDivider /> <BranchRowDivider />
</FeatureCan> </FeatureCan>
<Row> <Row>
<Col xs={5}> <Col xs={5}>
{/*------------ Date -----------*/} {/*------------ Date -----------*/}
@@ -92,32 +113,52 @@ export default function TransferToAccountFormFields() {
)} )}
</FastField> </FastField>
</Col> </Col>
<Col xs={5}> <Col xs={5}>
{/*------------ Transaction number -----------*/} {/*------------ Transaction number -----------*/}
<MoneyInOutTransactionNoField /> <MoneyInOutTransactionNoField />
</Col> </Col>
</Row> </Row>
{/*------------ amount -----------*/}
{/*------------ Amount -----------*/} <FastField name={'amount'}>
<Row> {({
<Col xs={10}> form: { values, setFieldValue },
<FFormGroup field: { value },
name={'amount'} meta: { error, touched },
}) => (
<FormGroup
label={<T id={'amount'} />} label={<T id={'amount'} />}
labelInfo={<FieldRequiredHint />} labelInfo={<FieldRequiredHint />}
intent={inputIntent({ error, touched })}
helperText={<ErrorMessage name="amount" />}
className={'form-group--amount'}
> >
<ControlGroup> <ControlGroup>
<InputPrependText text={account.currency_code} /> <InputPrependText text={account.currency_code} />
<FMoneyInputGroup name={'amount'} minimal={true} />
<MoneyInputGroup
value={value}
minimal={true}
onChange={(amount) => {
setFieldValue('amount', amount);
}}
inputRef={accountRef}
intent={inputIntent({ error, touched })}
/>
</ControlGroup> </ControlGroup>
</FFormGroup> </FormGroup>
</Col> )}
</Row> </FastField>
<If condition={isForeigAccount}>
{/*------------ Exchange rate -----------*/} {/*------------ exchange rate -----------*/}
<MoneyOutExchangeRateField /> <ExchangeRateMutedField
name={'exchange_rate'}
fromCurrency={values?.currency_code}
toCurrency={account?.currency_code}
formGroupProps={{ label: '', inline: false }}
date={values.date}
exchangeRate={values.exchange_rate}
/>
</If>
<Row> <Row>
<Col xs={5}> <Col xs={5}>
{/*------------ transfer from account -----------*/} {/*------------ transfer from account -----------*/}
@@ -150,24 +191,43 @@ export default function TransferToAccountFormFields() {
)} )}
</FastField> </FastField>
</Col> </Col>
<Col xs={5}> <Col xs={5}>
{/*------------ Reference -----------*/} {/*------------ Reference -----------*/}
<FFormGroup name={'reference_no'} label={<T id={'reference_no'} />}> <FastField name={'reference_no'}>
<FInputGroup name={'reference_no'} /> {({ form, field, meta: { error, touched } }) => (
</FFormGroup> <FormGroup
label={<T id={'reference_no'} />}
intent={inputIntent({ error, touched })}
helperText={<ErrorMessage name="reference_no" />}
className={'form-group--reference-no'}
>
<InputGroup
intent={inputIntent({ error, touched })}
{...field}
/>
</FormGroup>
)}
</FastField>
</Col> </Col>
</Row> </Row>
{/*------------ description -----------*/}
{/*------------ Description -----------*/} <FastField name={'description'}>
<FFormGroup name={'description'} label={<T id={'description'} />}> {({ field, meta: { error, touched } }) => (
<FTextArea <FormGroup
name={'description'} label={<T id={'description'} />}
className={'form-group--description'}
intent={inputIntent({ error, touched })}
helperText={<ErrorMessage name={'description'} />}
>
<TextArea
growVertically={true} growVertically={true}
large={true} large={true}
fill={true} intent={inputIntent({ error, touched })}
{...field}
/> />
</FFormGroup> </FormGroup>
)}
</FastField>
</React.Fragment> </React.Fragment>
); );
} }

View File

@@ -6,7 +6,6 @@ import { transactionNumber } from '@/utils';
import { first, isEqual, isNull } from 'lodash'; import { first, isEqual, isNull } from 'lodash';
import { useMoneyOutDialogContext } from './MoneyOutDialogProvider'; import { useMoneyOutDialogContext } from './MoneyOutDialogProvider';
import { useMoneyOutFieldsContext } from './MoneyOutFieldsProvider';
export const useObserveTransactionNoSettings = (prefix, nextNumber) => { export const useObserveTransactionNoSettings = (prefix, nextNumber) => {
const { setFieldValue } = useFormikContext(); const { setFieldValue } = useFormikContext();
@@ -34,7 +33,7 @@ export const useSetPrimaryBranchToForm = () => {
export const useForeignAccount = () => { export const useForeignAccount = () => {
const { values } = useFormikContext(); const { values } = useFormikContext();
const { account } = useMoneyOutFieldsContext(); const { account } = useMoneyOutDialogContext();
return ( return (
!isEqual(account.currency_code, values.currency_code) && !isEqual(account.currency_code, values.currency_code) &&

Some files were not shown because too many files have changed in this diff Show More