Compare commits

...

25 Commits

Author SHA1 Message Date
Ahmed Bouhuolia
485138344c Merge pull request #182 from bigcapitalhq/abouhuolia/big-20-selecting-the-default-branch-for-opening-balance-branch-in
fix(webapp): no default branch for customer/vendor opening balance branch
2023-06-28 18:15:19 +02:00
Ahmed Bouhuolia
8d990ae85d fix(webapp): no default branch for customer/vendor opening balance branch 2023-06-28 18:07:47 +02:00
Ahmed Bouhuolia
7fbe51ddf2 Merge pull request #179 from bigcapitalhq/abouhuolia/big-29-no-currency-in-amount-field-on-money-inout-dialogs
fix(webapp): No currency in amount field on money in/out dialogs
2023-06-28 12:27:12 +02:00
Ahmed Bouhuolia
215eb97762 Merge branch 'develop' into abouhuolia/big-29-no-currency-in-amount-field-on-money-inout-dialogs 2023-06-28 12:23:06 +02:00
Ahmed Bouhuolia
3d4fd0b904 fix(webapp): transaction number duplicated variable name 2023-06-28 12:21:22 +02:00
Ahmed Bouhuolia
e552ff6449 Merge pull request #180 from bigcapitalhq/abouhuolia/big-40-storing-cash-flow-transaction-description
fix: Storing cash flow transaction description
2023-06-28 11:08:23 +02:00
Ahmed Bouhuolia
268942af42 Merge pull request #181 from bigcapitalhq/abouhuolia/big-39-the-statement-note-does-not-saving-in-payment-receive-and
fix: internal note of invoice/bill payment does not saving
2023-06-28 11:07:55 +02:00
Ahmed Bouhuolia
02489a907a fix(webapp): internal note of invoice/bill payment does not saving 2023-06-28 11:06:33 +02:00
Ahmed Bouhuolia
4e0037d1c0 fix(server): showing transaction statement on cash flow transactions details drawer 2023-06-28 01:00:27 +02:00
Ahmed Bouhuolia
39786e5b1f fix(server): storing cash flow transaction statement to GL entry note 2023-06-28 00:58:47 +02:00
Ahmed Bouhuolia
6373862044 fix(webapp): No currency in amount field on money in/out dialogs 2023-06-27 21:32:08 +02:00
Ahmed Bouhuolia
59e3a4016b Merge pull request #177 from bigcapitalhq/abouhuolia/big-38-payment-made-form-does-not-handle-not-unique-number-an-error
fix(webapp): payment made form does not handle not unique number an e…
2023-06-26 23:08:57 +02:00
Ahmed Bouhuolia
b6a1c9ab4b fix(webapp): payment made form does not handle not unique number an error message 2023-06-26 20:57:52 +02:00
Ahmed Bouhuolia
c7b4846cb0 Merge pull request #171 from bigcapitalhq/abouhuolia/big-21-close-select-icon-clashes-with-caret-icon
feat(webapp): refactor customer and vendor select component
2023-06-23 16:06:55 +02:00
Ahmed Bouhuolia
d54aac9b32 Merge branch 'develop' into abouhuolia/big-21-close-select-icon-clashes-with-caret-icon 2023-06-23 16:05:21 +02:00
Ahmed Bouhuolia
fe87713df0 Merge pull request #172 from bigcapitalhq/abouhuolia/big-29-no-currency-in-amount-field-on-money-inout-dialogs
fix(webapp): should not show the form before loading account
2023-06-23 15:57:06 +02:00
Ahmed Bouhuolia
4770fdf709 Merge pull request #173 from bigcapitalhq/abouhuolia/big-37-item-drawer-floating
fix(webapp): style of quick item drawer
2023-06-23 15:55:58 +02:00
Ahmed Bouhuolia
1b3c525ba5 Merge pull request #170 from bigcapitalhq/split-components-in-seprate-files
chore(webapp): move auto-increment components in separate files
2023-06-23 15:55:22 +02:00
Ahmed Bouhuolia
e58a1d6ad1 chore(webapp): localization tweaks 2023-06-22 22:12:23 +02:00
Ahmed Bouhuolia
5f191cf335 fix(webapp): customer/vendor select should update deps 2023-06-22 22:07:39 +02:00
Ahmed Bouhuolia
46bf1cc39a fix(webapp): style of quick item drawer 2023-06-22 20:48:27 +02:00
Ahmed Bouhuolia
c98fe00f88 fix(webapp): should not show the form before loading account 2023-06-22 20:13:29 +02:00
Ahmed Bouhuolia
4b95c19d3e chore: update @blueprintjs-formik/select to the latest version 2023-06-22 19:54:54 +02:00
Ahmed Bouhuolia
eadaac30d6 feat(webapp): refactor customer and vendor select component 2023-06-22 17:26:33 +02:00
Ahmed Bouhuolia
ca4d543482 fix(webapp): quick create item drawer 2023-06-22 01:51:42 +02:00
88 changed files with 1303 additions and 1794 deletions

View File

@@ -41,6 +41,8 @@ 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

@@ -21,6 +21,8 @@ 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

@@ -25,8 +25,8 @@ 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 {} * @returns {Partial<ILedgerEntry>}
*/ */
private getCommonEntry = (cashflowTransaction: ICashflowTransaction) => { private getCommonEntry = (cashflowTransaction: ICashflowTransaction) => {
const { entries, ...transaction } = cashflowTransaction; const { entries, ...transaction } = cashflowTransaction;
@@ -41,7 +41,9 @@ export default class CashflowTransactionJournalEntries {
), ),
transactionId: transaction.id, transactionId: transaction.id,
transactionNumber: transaction.transactionNumber, transactionNumber: transaction.transactionNumber,
referenceNo: transaction.referenceNo, referenceNumber: transaction.referenceNo,
note: transaction.description,
branchId: cashflowTransaction.branchId, branchId: cashflowTransaction.branchId,
userId: cashflowTransaction.userId, userId: cashflowTransaction.userId,
@@ -76,9 +78,9 @@ export default class CashflowTransactionJournalEntries {
/** /**
* Retrieves the cashflow credit GL entry. * Retrieves the cashflow credit GL entry.
* @param {ICashflowTransaction} cashflowTransaction * @param {ICashflowTransaction} cashflowTransaction
* @param {ICashflowTransactionLine} entry * @param {ICashflowTransactionLine} entry
* @param {number} index * @param {number} index
* @returns {ILedgerEntry} * @returns {ILedgerEntry}
*/ */
private getCashflowCreditGLEntry = ( private getCashflowCreditGLEntry = (
@@ -102,10 +104,10 @@ export default class CashflowTransactionJournalEntries {
/** /**
* Retrieves the cashflow transaction GL entry. * Retrieves the cashflow transaction GL entry.
* @param {ICashflowTransaction} cashflowTransaction * @param {ICashflowTransaction} cashflowTransaction
* @param {ICashflowTransactionLine} entry * @param {ICashflowTransactionLine} entry
* @param {number} index * @param {number} index
* @returns * @returns {ILedgerEntry[]}
*/ */
private getJournalEntries = ( private getJournalEntries = (
cashflowTransaction: ICashflowTransaction cashflowTransaction: ICashflowTransaction
@@ -118,7 +120,7 @@ export default class CashflowTransactionJournalEntries {
/** /**
* Retrieves the cashflow GL ledger. * Retrieves the cashflow GL ledger.
* @param {ICashflowTransaction} cashflowTransaction * @param {ICashflowTransaction} cashflowTransaction
* @returns {Ledger} * @returns {Ledger}
*/ */
private getCashflowLedger = (cashflowTransaction: ICashflowTransaction) => { private getCashflowLedger = (cashflowTransaction: ICashflowTransaction) => {
@@ -130,6 +132,7 @@ 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,
@@ -153,6 +156,7 @@ 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

@@ -1,6 +1,6 @@
{ {
"name": "@bigcapital/webapp", "name": "@bigcapital/webapp",
"version": "1.7.1", "version": "0.9.6",
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
"dependencies": { "dependencies": {
@@ -1227,9 +1227,9 @@
} }
}, },
"@blueprintjs-formik/select": { "@blueprintjs-formik/select": {
"version": "0.2.3", "version": "0.2.4",
"resolved": "https://registry.npmjs.org/@blueprintjs-formik/select/-/select-0.2.3.tgz", "resolved": "https://registry.npmjs.org/@blueprintjs-formik/select/-/select-0.2.4.tgz",
"integrity": "sha512-j/zkX0B9wgtoHgK6Z/rlowB7F7zemrAajBU+d3caCoEYMMqwAI0XA++GytqrIhv5fEGjkZ1hkxS9j8eqX8vtjA==", "integrity": "sha512-zB28/hLkuO5zZXkjFmqfiVDGW+uvj9b8e6kHh9aOfY70edSFIfw3bj+NYR7BaDZoIYu3KuZQDFGqgs23ua5Z1g==",
"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.3", "@blueprintjs-formik/select": "^0.2.4",
"@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,59 +5,20 @@ import { MenuItem, Button } from '@blueprintjs/core';
import { FSelect } from '../Forms'; import { FSelect } from '../Forms';
/** /**
* * Branch select field.
* @param {*} query
* @param {*} branch
* @param {*} _index
* @param {*} exactMatch
* @returns
*/
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 (
<MenuItem
active={modifiers.active}
disabled={modifiers.disabled}
label={branch.code}
key={branch.id}
onClick={handleClick}
text={text}
/>
);
};
const branchSelectProps = {
itemPredicate: branchItemPredicate,
itemRenderer: branchItemRenderer,
valueAccessor: 'id',
labelAccessor: 'name',
};
/**
*
* @param {*} param0 * @param {*} param0
* @returns * @returns {JSX.Element}
*/ */
export function BranchSelect({ branches, ...rest }) { export function BranchSelect({ branches, ...rest }) {
return <FSelect {...branchSelectProps} {...rest} items={branches} />; return (
<FSelect
valueAccessor={'id'}
textAccessor={'name'}
labelAccessor={'code'}
{...rest}
items={branches}
/>
);
} }
/** /**

View File

@@ -1,119 +0,0 @@
// @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

@@ -0,0 +1,48 @@
// @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

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

View File

@@ -0,0 +1,27 @@
// @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,3 +1,4 @@
// @ts-nocheck // @ts-nocheck
export * from './FormTopbar'; export * from './FormTopbar';
export * from './FormTopbarSelectInputs';
export * from './PageFormBigNumber'; export * from './PageFormBigNumber';

View File

@@ -1,118 +0,0 @@
// @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

@@ -0,0 +1,49 @@
// @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 './VendorSelectField' export * from './VendorsSelect';

View File

@@ -25,6 +25,7 @@ import {
CashflowAction, CashflowAction,
PreferencesAbility, PreferencesAbility,
} from '@/constants/abilityOption'; } from '@/constants/abilityOption';
import { DialogsName } from './dialogs';
export const SidebarMenu = [ export const SidebarMenu = [
// --------------- // ---------------
@@ -114,7 +115,7 @@ export const SidebarMenu = [
text: <T id={'sidebar.new_item_category'} />, text: <T id={'sidebar.new_item_category'} />,
href: '/items/categories/new', href: '/items/categories/new',
type: ISidebarMenuItemType.Dialog, type: ISidebarMenuItemType.Dialog,
dialogName: 'item-category-form', dialogName: DialogsName.ItemCategoryForm,
permission: { permission: {
subject: AbilitySubject.Item, subject: AbilitySubject.Item,
ability: ItemAction.Create, ability: ItemAction.Create,
@@ -458,7 +459,7 @@ export const SidebarMenu = [
text: <T id={'sidebar.add_money_in'} />, text: <T id={'sidebar.add_money_in'} />,
href: '/cashflow-accounts', href: '/cashflow-accounts',
type: ISidebarMenuItemType.Dialog, type: ISidebarMenuItemType.Dialog,
dialogName: 'money-in', dialogName: DialogsName.MoneyInForm,
permission: { permission: {
subject: AbilitySubject.Cashflow, subject: AbilitySubject.Cashflow,
ability: CashflowAction.Create, ability: CashflowAction.Create,
@@ -468,6 +469,7 @@ export const SidebarMenu = [
text: <T id={'sidebar.add_money_out'} />, text: <T id={'sidebar.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,
@@ -477,6 +479,7 @@ export const SidebarMenu = [
text: <T id={'sidebar.add_cash_account'} />, text: <T id={'sidebar.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,
@@ -486,6 +489,7 @@ export const SidebarMenu = [
text: <T id={'sidebar.add_bank_account'} />, text: <T id={'sidebar.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,

View File

@@ -11,6 +11,7 @@ import {
FeatureCan, FeatureCan,
FormTopbar, FormTopbar,
DetailsBarSkeletonBase, DetailsBarSkeletonBase,
FormBranchSelectButton,
} from '@/components'; } from '@/components';
import { useMakeJournalFormContext } from './MakeJournalProvider'; import { useMakeJournalFormContext } from './MakeJournalProvider';
@@ -51,18 +52,9 @@ function MakeJournalFormSelectBranch() {
<BranchSelect <BranchSelect
name={'branch_id'} name={'branch_id'}
branches={branches} branches={branches}
input={MakeJournalBranchSelectButton} input={FormBranchSelectButton}
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,18 +1,22 @@
// @ts-nocheck // @ts-nocheck
import React from 'react'; import React, { useMemo } 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.
* @param param0 * Switches between fields based on the given transaction type.
* @returns * @returns {JSX.Element}
*/ */
export default function MoneyInContentFields({ accountType }) { export default function MoneyInContentFields() {
const handleTransactionType = () => { const { values } = useFormikContext();
switch (accountType) {
const transactionFields = useMemo(() => {
switch (values.transaction_type) {
case 'owner_contribution': case 'owner_contribution':
return <OwnerContributionFormFields />; return <OwnerContributionFormFields />;
@@ -24,6 +28,10 @@ export default function MoneyInContentFields({ accountType }) {
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,6 +1,5 @@
// @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,11 +1,10 @@
// @ts-nocheck // @ts-nocheck
import React from 'react'; import React, { useState } 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,
@@ -18,21 +17,20 @@ const MoneyInDialogContent = React.createContext();
* Money in dialog provider. * Money in dialog provider.
*/ */
function MoneyInDialogProvider({ function MoneyInDialogProvider({
accountId, accountId: defaultAccountId,
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 { isFetching: 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 {
@@ -41,10 +39,11 @@ 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();
@@ -54,12 +53,15 @@ function MoneyInDialogProvider({
// Submit payload. // Submit payload.
const [submitPayload, setSubmitPayload] = React.useState({}); const [submitPayload, setSubmitPayload] = React.useState({});
// provider. // Provider data.
const provider = { const provider = {
accounts, accounts,
account,
branches, branches,
accountId, accountId,
defaultAccountId,
setAccountId,
accountType, accountType,
isAccountsLoading, isAccountsLoading,
isBranchesSuccess, isBranchesSuccess,
@@ -73,15 +75,14 @@ function MoneyInDialogProvider({
setSubmitPayload, setSubmitPayload,
}; };
const isLoading =
isAccountsLoading ||
isCashFlowAccountsLoading ||
isBranchesLoading ||
isSettingsLoading;
return ( return (
<DialogContent <DialogContent isLoading={isLoading}>
isLoading={
isAccountsLoading ||
isCashFlowAccountsLoading ||
isBranchesLoading ||
isSettingsLoading
}
>
<MoneyInDialogContent.Provider value={provider} {...props} /> <MoneyInDialogContent.Provider value={provider} {...props} />
</DialogContent> </DialogContent>
); );

View File

@@ -0,0 +1,26 @@
// @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

@@ -0,0 +1,34 @@
// @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,7 +53,6 @@ function MoneyInForm({
accountId, accountId,
accountType, accountType,
createCashflowTransactionMutate, createCashflowTransactionMutate,
submitPayload,
} = useMoneyInDailogContext(); } = useMoneyInDailogContext();
// transaction number. // transaction number.
@@ -61,7 +60,6 @@ function MoneyInForm({
transactionNumberPrefix, transactionNumberPrefix,
transactionNextNumber, transactionNextNumber,
); );
// Initial form values. // Initial form values.
const initialValues = { const initialValues = {
...defaultInitialValues, ...defaultInitialValues,
@@ -95,15 +93,13 @@ function MoneyInForm({
}; };
return ( return (
<div> <Formik
<Formik validationSchema={CreateMoneyInFormSchema}
validationSchema={CreateMoneyInFormSchema} initialValues={initialValues}
initialValues={initialValues} onSubmit={handleFormSubmit}
onSubmit={handleFormSubmit} >
> <MoneyInFormContent />
<MoneyInFormContent /> </Formik>
</Formik>
</div>
); );
} }

View File

@@ -12,17 +12,13 @@ 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 { accountId } = useMoneyInDailogContext(); const { defaultAccountId } = useMoneyInDailogContext();
return ( return (
<div className={Classes.DIALOG_BODY}> <div className={Classes.DIALOG_BODY}>
<If condition={!accountId}> {!defaultAccountId && <TransactionTypeFields />}
<TransactionTypeFields /> <MoneyInContentFields />
</If>
<MoneyInContentFields accountType={values.transaction_type} />
</div> </div>
); );
} }

View File

@@ -1,10 +1,9 @@
// @ts-nocheck // @ts-nocheck
import React from 'react'; import React from 'react';
import { FastField, Field, ErrorMessage, useFormikContext } from 'formik'; import { FastField, ErrorMessage } from 'formik';
import { import {
Classes, Classes,
FormGroup, FormGroup,
InputGroup,
TextArea, TextArea,
Position, Position,
ControlGroup, ControlGroup,
@@ -18,14 +17,15 @@ import {
FieldRequiredHint, FieldRequiredHint,
Col, Col,
Row, Row,
If,
FeatureCan, FeatureCan,
BranchSelect, BranchSelect,
BranchSelectButton, BranchSelectButton,
ExchangeRateMutedField, FInputGroup,
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,22 +36,18 @@ import {
} from '@/utils'; } from '@/utils';
import { useMoneyInDailogContext } from '../MoneyInDialogProvider'; import { useMoneyInDailogContext } from '../MoneyInDialogProvider';
import { import { useSetPrimaryBranchToForm, BranchRowDivider } from '../utils';
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, account, branches } = useMoneyInDailogContext(); const { accounts, branches } = useMoneyInDailogContext();
const { values } = useFormikContext(); const { account } = useMoneyInFieldsContext();
const amountFieldRef = useAutofocus();
const isForeigAccount = useForeignAccount();
// Sets the primary branch to form. // Sets the primary branch to form.
useSetPrimaryBranchToForm(); useSetPrimaryBranchToForm();
@@ -61,17 +57,14 @@ export default function OtherIncomeFormFields() {
<FeatureCan feature={Features.Branches}> <FeatureCan feature={Features.Branches}>
<Row> <Row>
<Col xs={5}> <Col xs={5}>
<FormGroup <FFormGroup name={'amount'} label={<T id={'branch'} />}>
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 }}
/> />
</FormGroup> </FFormGroup>
</Col> </Col>
</Row> </Row>
<BranchRowDivider /> <BranchRowDivider />
@@ -106,53 +99,32 @@ 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 -----------*/}
<FastField name={'amount'}> {/*------------ Amount -----------*/}
{({ <Row>
form: { values, setFieldValue }, <Col xs={10}>
field: { value }, <FFormGroup
meta: { error, touched }, name={'amount'}
}) => (
<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> </FFormGroup>
)} </Col>
</FastField> </Row>
{/*------------ 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 -----------*/}
@@ -182,43 +154,24 @@ export default function OtherIncomeFormFields() {
)} )}
</FastField> </FastField>
</Col> </Col>
<Col xs={5}> <Col xs={5}>
{/*------------ Reference -----------*/} {/*------------ Reference -----------*/}
<FastField name={'reference_no'}> <FFormGroup label={<T id={'reference_no'} />} name={'reference_no'}>
{({ form, field, meta: { error, touched } }) => ( <FInputGroup name={'reference_no'} />
<FormGroup </FFormGroup>
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 -----------*/}
<FastField name={'description'}> {/*------------ Description -----------*/}
{({ field, meta: { error, touched } }) => ( <FFormGroup name={'description'} label={<T id={'description'} />}>
<FormGroup <FTextArea
label={<T id={'description'} />} name={'description'}
className={'form-group--description'} growVertically={true}
intent={inputIntent({ error, touched })} large={true}
helperText={<ErrorMessage name={'description'} />} fill={true}
> />
<TextArea </FFormGroup>
growVertically={true}
large={true}
intent={inputIntent({ error, touched })}
{...field}
/>
</FormGroup>
)}
</FastField>
</React.Fragment> </React.Fragment>
); );
} }

View File

@@ -1,32 +1,24 @@
// @ts-nocheck // @ts-nocheck
import React from 'react'; import React from 'react';
import { FastField, Field, ErrorMessage, useFormikContext } from 'formik'; import { FastField, ErrorMessage } from 'formik';
import { import { FormGroup, Position, ControlGroup } from '@blueprintjs/core';
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,
@@ -37,10 +29,11 @@ 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';
/** /**
/** /**
@@ -48,13 +41,8 @@ import { MoneyInOutTransactionNoField } from '../../_components';
*/ */
export default function OwnerContributionFormFields() { export default function OwnerContributionFormFields() {
// Money in dialog context. // Money in dialog context.
const { accounts, account, branches } = useMoneyInDailogContext(); const { accounts, 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();
@@ -64,21 +52,19 @@ export default function OwnerContributionFormFields() {
<FeatureCan feature={Features.Branches}> <FeatureCan feature={Features.Branches}>
<Row> <Row>
<Col xs={5}> <Col xs={5}>
<FormGroup <FFormGroup name={'branch_id'} label={<T id={'branch'} />}>
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 }}
/> />
</FormGroup> </FFormGroup>
</Col> </Col>
</Row> </Row>
<BranchRowDivider /> <BranchRowDivider />
</FeatureCan> </FeatureCan>
<Row> <Row>
<Col xs={5}> <Col xs={5}>
{/*------------ Date -----------*/} {/*------------ Date -----------*/}
@@ -113,47 +99,26 @@ export default function OwnerContributionFormFields() {
<MoneyInOutTransactionNoField /> <MoneyInOutTransactionNoField />
</Col> </Col>
</Row> </Row>
{/*------------ amount -----------*/}
<Field name={'amount'}> {/*------------ Amount -----------*/}
{({ <Row>
form: { values, setFieldValue }, <Col xs={10}>
field: { value }, <FFormGroup
meta: { error, touched }, name={'amount'}
}) => (
<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> </FFormGroup>
)} </Col>
</Field> </Row>
<If condition={isForeigAccount}>
{/*------------ exchange rate -----------*/} {/*------------ Exchange rate -----------*/}
<ExchangeRateMutedField <MoneyInExchangeRateField />
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 -----------*/}
@@ -181,43 +146,24 @@ export default function OwnerContributionFormFields() {
)} )}
</FastField> </FastField>
</Col> </Col>
<Col xs={5}> <Col xs={5}>
{/*------------ Reference -----------*/} {/*------------ Reference -----------*/}
<FastField name={'reference_no'}> <FFormGroup name={'reference_no'} label={<T id={'reference_no'} />}>
{({ form, field, meta: { error, touched } }) => ( <FInputGroup name={'reference_no'} />
<FormGroup </FFormGroup>
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 -----------*/}
<FastField name={'description'}> {/*------------ Description -----------*/}
{({ field, meta: { error, touched } }) => ( <FFormGroup name={'description'} label={<T id={'description'} />}>
<FormGroup <FTextArea
label={<T id={'description'} />} name={'description'}
className={'form-group--description'} growVertically={true}
intent={inputIntent({ error, touched })} large={true}
helperText={<ErrorMessage name={'description'} />} fill={true}
> />
<TextArea </FFormGroup>
growVertically={true}
large={true}
intent={inputIntent({ error, touched })}
{...field}
/>
</FormGroup>
)}
</FastField>
</React.Fragment> </React.Fragment>
); );
} }

View File

@@ -10,6 +10,8 @@ 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';
@@ -21,7 +23,7 @@ import { useMoneyInDailogContext } from './MoneyInDialogProvider';
*/ */
export default function TransactionTypeFields() { export default function TransactionTypeFields() {
// Money in dialog context. // Money in dialog context.
const { cashflowAccounts } = useMoneyInDailogContext(); const { cashflowAccounts, setAccountId } = useMoneyInDailogContext();
// Retrieves the add money in button options. // Retrieves the add money in button options.
const addMoneyInOptions = useMemo(() => getAddMoneyInOptions(), []); const addMoneyInOptions = useMemo(() => getAddMoneyInOptions(), []);
@@ -29,6 +31,23 @@ 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'}>
@@ -46,9 +65,10 @@ 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 }),
}} }}
@@ -56,39 +76,6 @@ 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,33 +1,27 @@
// @ts-nocheck // @ts-nocheck
import React from 'react'; import React from 'react';
import { FastField, Field, ErrorMessage, useFormikContext } from 'formik'; import { FastField, ErrorMessage } from 'formik';
import { DateInput } from '@blueprintjs/datetime'; import { DateInput } from '@blueprintjs/datetime';
import { import { FormGroup, Position, ControlGroup } from '@blueprintjs/core';
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 { useAutofocus } from '@/hooks'; import { MoneyInOutTransactionNoField } from '../../_components';
import { MoneyInExchangeRateField } from '../MoneyInExchangeRateField';
import { CLASSES, ACCOUNT_TYPE, Features } from '@/constants'; import { CLASSES, ACCOUNT_TYPE, Features } from '@/constants';
import { import {
inputIntent, inputIntent,
momentFormatter, momentFormatter,
@@ -35,25 +29,19 @@ 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, account, branches } = useMoneyInDailogContext(); const { accounts, 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();
@@ -63,17 +51,14 @@ export default function TransferFromAccountFormFields() {
<FeatureCan feature={Features.Branches}> <FeatureCan feature={Features.Branches}>
<Row> <Row>
<Col xs={5}> <Col xs={5}>
<FormGroup <FFormGroup label={<T id={'branch'} />} name={'branch_id'}>
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 }}
/> />
</FormGroup> </FFormGroup>
</Col> </Col>
</Row> </Row>
<BranchRowDivider /> <BranchRowDivider />
@@ -112,50 +97,27 @@ export default function TransferFromAccountFormFields() {
<MoneyInOutTransactionNoField /> <MoneyInOutTransactionNoField />
</Col> </Col>
</Row> </Row>
{/*------------ amount -----------*/} {/*------------ Amount -----------*/}
<FastField name={'amount'}> <Row>
{({ <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>
</FastField> </Row>
<If condition={isForeigAccount}>
{/*------------ exchange rate -----------*/} {/*------------ Exchange rate -----------*/}
<ExchangeRateMutedField <MoneyInExchangeRateField />
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
@@ -185,43 +147,24 @@ export default function TransferFromAccountFormFields() {
)} )}
</FastField> </FastField>
</Col> </Col>
<Col xs={5}> <Col xs={5}>
{/*------------ Reference -----------*/} {/*------------ Reference -----------*/}
<FastField name={'reference_no'}> <FFormGroup name={'reference_no'} label={<T id={'reference_no'} />}>
{({ form, field, meta: { error, touched } }) => ( <FInputGroup name={'reference_no'} />
<FormGroup </FFormGroup>
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 -----------*/}
<FastField name={'description'}> {/*------------ Description -----------*/}
{({ field, meta: { error, touched } }) => ( <FormGroup name={'description'} label={<T id={'description'} />}>
<FormGroup <FTextArea
label={<T id={'description'} />} name={'description'}
className={'form-group--description'} growVertically={true}
intent={inputIntent({ error, touched })} large={true}
helperText={<ErrorMessage name={'description'} />} fill={true}
> />
<TextArea </FormGroup>
growVertically={true}
large={true}
intent={inputIntent({ error, touched })}
{...field}
/>
</FormGroup>
)}
</FastField>
</React.Fragment> </React.Fragment>
); );
} }

View File

@@ -3,7 +3,6 @@ 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,6 +6,7 @@ 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();
@@ -33,7 +34,7 @@ export const useSetPrimaryBranchToForm = () => {
export const useForeignAccount = () => { export const useForeignAccount = () => {
const { values } = useFormikContext(); const { values } = useFormikContext();
const { account } = useMoneyInDailogContext(); const { account } = useMoneyInFieldsContext();
return ( return (
!isEqual(account.currency_code, values.currency_code) && !isEqual(account.currency_code, values.currency_code) &&

View File

@@ -1,13 +1,22 @@
// @ts-nocheck // @ts-nocheck
import React from 'react'; import React, { useMemo } 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 }) { /**
const handleTransactionType = () => { * Money out content fields.
switch (accountType) { * Switches between form fields based on the given transaction type.
* @returns {JSX.Element}
*/
function MoneyOutContentFields() {
const { values } = useFormikContext();
const transactionType = useMemo(() => {
switch (values.transaction_type) {
case 'OwnerDrawing': case 'OwnerDrawing':
return <OwnerDrawingsFormFields />; return <OwnerDrawingsFormFields />;
@@ -19,8 +28,12 @@ function MoneyOutContentFields({ accountType }) {
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,11 +1,10 @@
// @ts-nocheck // @ts-nocheck
import React from 'react'; import React, { useState } 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,
@@ -17,7 +16,15 @@ const MoneyInDialogContent = React.createContext();
/** /**
* Money out dialog provider. * Money out dialog provider.
*/ */
function MoneyOutProvider({ accountId, accountType, dialogName, ...props }) { function MoneyOutProvider({
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);
@@ -25,11 +32,6 @@ function MoneyOutProvider({ accountId, accountType, dialogName, ...props }) {
// 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,
@@ -41,6 +43,7 @@ function MoneyOutProvider({ accountId, accountType, dialogName, ...props }) {
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();
@@ -50,11 +53,13 @@ function MoneyOutProvider({ accountId, accountType, dialogName, ...props }) {
// Submit payload. // Submit payload.
const [submitPayload, setSubmitPayload] = React.useState({}); const [submitPayload, setSubmitPayload] = React.useState({});
// provider. // Provider data.
const provider = { const provider = {
accounts,
account,
accountId, accountId,
setAccountId,
defaultAccountId,
accounts,
accountType, accountType,
branches, branches,
isAccountsLoading, isAccountsLoading,
@@ -69,15 +74,14 @@ function MoneyOutProvider({ accountId, accountType, dialogName, ...props }) {
setSubmitPayload, setSubmitPayload,
}; };
const isLoading =
isAccountsLoading ||
isCashFlowAccountsLoading ||
isBranchesLoading ||
isSettingsLoading;
return ( return (
<DialogContent <DialogContent isLoading={isLoading}>
isLoading={
isAccountsLoading ||
isCashFlowAccountsLoading ||
isBranchesLoading ||
isSettingsLoading
}
>
<MoneyInDialogContent.Provider value={provider} {...props} /> <MoneyInDialogContent.Provider value={provider} {...props} />
</DialogContent> </DialogContent>
); );

View File

@@ -0,0 +1,31 @@
// @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

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

View File

@@ -92,15 +92,13 @@ function MoneyOutForm({
}); });
}; };
return ( return (
<div> <Formik
<Formik validationSchema={CreateMoneyOutSchema}
validationSchema={CreateMoneyOutSchema} initialValues={initialValues}
initialValues={initialValues} onSubmit={handleFormSubmit}
onSubmit={handleFormSubmit} >
> <MoneyOutFormContent />
<MoneyOutFormContent /> </Formik>
</Formik>
</div>
); );
} }

View File

@@ -17,6 +17,7 @@ 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,28 +1,18 @@
// @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,33 +1,25 @@
// @ts-nocheck // @ts-nocheck
import React from 'react'; import React from 'react';
import { FastField, Field, ErrorMessage, useFormikContext } from 'formik'; import { FastField, ErrorMessage } from 'formik';
import { import { FormGroup, Position, ControlGroup } from '@blueprintjs/core';
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,
ExchangeRateMutedField, FTextArea,
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,
@@ -36,25 +28,18 @@ import {
} from '@/utils'; } from '@/utils';
import { CLASSES } from '@/constants/classes'; import { CLASSES } from '@/constants/classes';
import { useMoneyOutDialogContext } from '../MoneyOutDialogProvider'; import { useMoneyOutDialogContext } from '../MoneyOutDialogProvider';
import { import { useSetPrimaryBranchToForm, BranchRowDivider } from '../utils';
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, account, branches } = useMoneyOutDialogContext(); const { accounts, 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();
@@ -64,21 +49,19 @@ export default function OtherExpnseFormFields() {
<FeatureCan feature={Features.Branches}> <FeatureCan feature={Features.Branches}>
<Row> <Row>
<Col xs={5}> <Col xs={5}>
<FormGroup <FFormGroup name={'branch_id'} label={<T id={'branch'} />}>
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 }}
/> />
</FormGroup> </FFormGroup>
</Col> </Col>
</Row> </Row>
<BranchRowDivider /> <BranchRowDivider />
</FeatureCan> </FeatureCan>
<Row> <Row>
<Col xs={5}> <Col xs={5}>
{/*------------ Date -----------*/} {/*------------ Date -----------*/}
@@ -113,47 +96,27 @@ export default function OtherExpnseFormFields() {
<MoneyInOutTransactionNoField /> <MoneyInOutTransactionNoField />
</Col> </Col>
</Row> </Row>
{/*------------ amount -----------*/} {/*------------ amount -----------*/}
<FastField name={'amount'}>
{({ <Row>
form: { values, setFieldValue }, <Col xs={10}>
field: { value }, <FFormGroup
meta: { error, touched }, name={'amount'}
}) => (
<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> </FFormGroup>
)} </Col>
</FastField> </Row>
<If condition={isForeigAccount}>
{/*------------ exchange rate -----------*/} {/*------------ Exchange rate -----------*/}
<ExchangeRateMutedField <MoneyOutExchangeRateField />
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 -----------*/}
@@ -183,44 +146,24 @@ export default function OtherExpnseFormFields() {
)} )}
</FastField> </FastField>
</Col> </Col>
<Col xs={5}> <Col xs={5}>
{/*------------ Reference -----------*/} {/*------------ Reference -----------*/}
<FastField name={'reference_no'}> <FFormGroup name={'reference_no'} label={<T id={'reference_no'} />}>
{({ form, field, meta: { error, touched } }) => ( <FInputGroup name={'reference_no'} />
<FormGroup </FFormGroup>
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'} />} growVertically={true}
className={'form-group--description'} large={true}
intent={inputIntent({ error, touched })} fill={true}
helperText={<ErrorMessage name={'description'} />} />
> </FFormGroup>
<TextArea
growVertically={true}
large={true}
intent={inputIntent({ error, touched })}
{...field}
/>
</FormGroup>
)}
</FastField>
</React.Fragment> </React.Fragment>
); );
} }

View File

@@ -1,31 +1,24 @@
// @ts-nocheck // @ts-nocheck
import React from 'react'; import React from 'react';
import { FastField, Field, ErrorMessage, useFormikContext } from 'formik'; import { FastField, ErrorMessage } from 'formik';
import { DateInput } from '@blueprintjs/datetime'; import { DateInput } from '@blueprintjs/datetime';
import { import { FormGroup, Position, ControlGroup } from '@blueprintjs/core';
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,
ExchangeRateMutedField, FFormGroup,
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,
@@ -36,21 +29,19 @@ 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, account, branches } = useMoneyOutDialogContext(); const { accounts, branches } = useMoneyOutDialogContext();
const { values } = useFormikContext(); const { account } = useMoneyOutFieldsContext();
const isForeigAccount = useForeignAccount();
const amountFieldRef = useAutofocus();
// Sets the primary branch to form. // Sets the primary branch to form.
useSetPrimaryBranchToForm(); useSetPrimaryBranchToForm();
@@ -60,21 +51,19 @@ export default function OwnerDrawingsFormFields() {
<FeatureCan feature={Features.Branches}> <FeatureCan feature={Features.Branches}>
<Row> <Row>
<Col xs={5}> <Col xs={5}>
<FormGroup <FFormGroup label={<T id={'branch'} />} name={'branch_id'}>
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 }}
/> />
</FormGroup> </FFormGroup>
</Col> </Col>
</Row> </Row>
<BranchRowDivider /> <BranchRowDivider />
</FeatureCan> </FeatureCan>
<Row> <Row>
<Col xs={5}> <Col xs={5}>
{/*------------ Date -----------*/} {/*------------ Date -----------*/}
@@ -109,48 +98,27 @@ export default function OwnerDrawingsFormFields() {
<MoneyInOutTransactionNoField /> <MoneyInOutTransactionNoField />
</Col> </Col>
</Row> </Row>
{/*------------ amount -----------*/}
<Field name={'amount'}> {/*------------ Amount -----------*/}
{({
form: { values, setFieldValue }, <Row>
field: { value }, <Col xs={10}>
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>
</Field> </Row>
{/*------------ 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 -----------*/}
@@ -177,44 +145,24 @@ export default function OwnerDrawingsFormFields() {
)} )}
</FastField> </FastField>
</Col> </Col>
<Col xs={5}> <Col xs={5}>
{/*------------ Reference -----------*/} {/*------------ Reference -----------*/}
<FastField name={'reference_no'}> <FFormGroup name={'reference_no'} label={<T id={'reference_no'} />}>
{({ form, field, meta: { error, touched } }) => ( <FInputGroup name={'reference_no'} />
<FormGroup </FFormGroup>
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'} />} growVertically={true}
className={'form-group--description'} large={true}
intent={inputIntent({ error, touched })} fill={true}
helperText={<ErrorMessage name={'description'} />} />
> </FFormGroup>
<TextArea
growVertically={true}
large={true}
intent={inputIntent({ error, touched })}
{...field}
/>
</FormGroup>
)}
</FastField>
</React.Fragment> </React.Fragment>
); );
} }

View File

@@ -1,22 +1,21 @@
// @ts-nocheck // @ts-nocheck
import React, { useMemo } from 'react'; import React, { useMemo } from 'react';
import { FastField, Field, ErrorMessage } from 'formik'; import { FastField, 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 { CLASSES } from '@/constants/classes';
import { getAddMoneyOutOptions } from '@/constants/cashflowOptions'; import { getAddMoneyOutOptions } from '@/constants/cashflowOptions';
import { useMoneyOutDialogContext } from './MoneyOutDialogProvider'; import { useMoneyOutDialogContext } from './MoneyOutDialogProvider';
import { CLASSES } from '@/constants/classes';
/** /**
* Transaction type fields. * Transaction type fields.
@@ -27,9 +26,32 @@ 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'}>
@@ -47,9 +69,10 @@ 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 }),
}} }}
@@ -57,39 +80,6 @@ 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,65 +1,46 @@
// @ts-nocheck // @ts-nocheck
import React from 'react'; import React from 'react';
import { FastField, Field, ErrorMessage, useFormikContext } from 'formik'; import { FastField, ErrorMessage } from 'formik';
import { import { FormGroup, Position, ControlGroup } from '@blueprintjs/core';
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,
ExchangeRateMutedField, FFormGroup,
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 { import { useSetPrimaryBranchToForm, BranchRowDivider } from '../utils';
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, account, branches } = useMoneyOutDialogContext(); const { accounts, branches } = useMoneyOutDialogContext();
const { values } = useFormikContext(); const { account } = useMoneyOutFieldsContext();
const isForeigAccount = useForeignAccount();
const accountRef = useAutofocus();
// Sets the primary branch to form. // Sets the primary branch to form.
useSetPrimaryBranchToForm(); useSetPrimaryBranchToForm();
@@ -69,21 +50,19 @@ export default function TransferToAccountFormFields() {
<FeatureCan feature={Features.Branches}> <FeatureCan feature={Features.Branches}>
<Row> <Row>
<Col xs={5}> <Col xs={5}>
<FormGroup <FFormGroup label={<T id={'branch'} />} name={'branch_id'}>
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 }}
/> />
</FormGroup> </FFormGroup>
</Col> </Col>
</Row> </Row>
<BranchRowDivider /> <BranchRowDivider />
</FeatureCan> </FeatureCan>
<Row> <Row>
<Col xs={5}> <Col xs={5}>
{/*------------ Date -----------*/} {/*------------ Date -----------*/}
@@ -113,52 +92,32 @@ 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 -----------*/}
<FastField name={'amount'}> {/*------------ Amount -----------*/}
{({ <Row>
form: { values, setFieldValue }, <Col xs={10}>
field: { value }, <FFormGroup
meta: { error, touched }, name={'amount'}
}) => (
<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>
</FormGroup> </FFormGroup>
)} </Col>
</FastField> </Row>
<If condition={isForeigAccount}>
{/*------------ exchange rate -----------*/} {/*------------ Exchange rate -----------*/}
<ExchangeRateMutedField <MoneyOutExchangeRateField />
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 -----------*/}
@@ -191,43 +150,24 @@ export default function TransferToAccountFormFields() {
)} )}
</FastField> </FastField>
</Col> </Col>
<Col xs={5}> <Col xs={5}>
{/*------------ Reference -----------*/} {/*------------ Reference -----------*/}
<FastField name={'reference_no'}> <FFormGroup name={'reference_no'} label={<T id={'reference_no'} />}>
{({ form, field, meta: { error, touched } }) => ( <FInputGroup name={'reference_no'} />
<FormGroup </FFormGroup>
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 -----------*/}
<FastField name={'description'}> {/*------------ Description -----------*/}
{({ field, meta: { error, touched } }) => ( <FFormGroup name={'description'} label={<T id={'description'} />}>
<FormGroup <FTextArea
label={<T id={'description'} />} name={'description'}
className={'form-group--description'} growVertically={true}
intent={inputIntent({ error, touched })} large={true}
helperText={<ErrorMessage name={'description'} />} fill={true}
> />
<TextArea </FFormGroup>
growVertically={true}
large={true}
intent={inputIntent({ error, touched })}
{...field}
/>
</FormGroup>
)}
</FastField>
</React.Fragment> </React.Fragment>
); );
} }

View File

@@ -6,6 +6,7 @@ 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();
@@ -33,7 +34,7 @@ export const useSetPrimaryBranchToForm = () => {
export const useForeignAccount = () => { export const useForeignAccount = () => {
const { values } = useFormikContext(); const { values } = useFormikContext();
const { account } = useMoneyOutDialogContext(); const { account } = useMoneyOutFieldsContext();
return ( return (
!isEqual(account.currency_code, values.currency_code) && !isEqual(account.currency_code, values.currency_code) &&

View File

@@ -38,11 +38,11 @@ export const MoneyInOutSyncIncrementSettingsToForm = R.compose(
// Do not update if the invoice auto-increment is disabled. // Do not update if the invoice auto-increment is disabled.
if (!transactionAutoIncrement) return null; if (!transactionAutoIncrement) return null;
const transactionNumber = transactionNumber( const newTransactionNumber = transactionNumber(
transactionNumberPrefix, transactionNumberPrefix,
transactionNextNumber, transactionNextNumber,
); );
setFieldValue('transaction_number', transactionNumber); setFieldValue('transaction_number', newTransactionNumber);
}, [setFieldValue, transactionNumberPrefix, transactionNextNumber]); }, [setFieldValue, transactionNumberPrefix, transactionNextNumber]);
return null; return null;

View File

@@ -10,7 +10,6 @@ import {
InputPrependText, InputPrependText,
CurrencySelectList, CurrencySelectList,
BranchSelect, BranchSelect,
BranchSelectButton,
FeatureCan, FeatureCan,
Row, Row,
Col, Col,
@@ -78,12 +77,10 @@ export default function CustomerFinancialPanel() {
label={<T id={'customer.label.opening_branch'} />} label={<T id={'customer.label.opening_branch'} />}
name={'opening_balance_branch_id'} name={'opening_balance_branch_id'}
inline={true} inline={true}
className={classNames('form-group--select-list', Classes.FILL)}
> >
<BranchSelect <BranchSelect
name={'opening_balance_branch_id'} name={'opening_balance_branch_id'}
branches={branches} branches={branches}
input={BranchSelectButton}
popoverProps={{ minimal: true }} popoverProps={{ minimal: true }}
/> />
</FFormGroup> </FFormGroup>

View File

@@ -7,6 +7,7 @@ import { Intent } from '@blueprintjs/core';
import { AppToaster } from '@/components'; import { AppToaster } from '@/components';
import { useFormikContext } from 'formik'; import { useFormikContext } from 'formik';
import { useQuickPaymentMadeContext } from './QuickPaymentMadeFormProvider'; import { useQuickPaymentMadeContext } from './QuickPaymentMadeFormProvider';
import { PAYMENT_MADE_ERRORS } from '@/containers/Purchases/PaymentMades/constants';
// Default initial values of payment made. // Default initial values of payment made.
export const defaultPaymentMade = { export const defaultPaymentMade = {
@@ -24,16 +25,16 @@ export const defaultPaymentMade = {
export const transformErrors = (errors, { setFieldError }) => { export const transformErrors = (errors, { setFieldError }) => {
const getError = (errorType) => errors.find((e) => e.type === errorType); const getError = (errorType) => errors.find((e) => e.type === errorType);
if (getError('PAYMENT.NUMBER.NOT.UNIQUE')) { if (getError(PAYMENT_MADE_ERRORS.PAYMENT_NUMBER_NOT_UNIQUE)) {
setFieldError('payment_number', intl.get('payment_number_is_not_unique')); setFieldError('payment_number', intl.get('payment_number_is_not_unique'));
} }
if (getError('INVALID_BILL_PAYMENT_AMOUNT')) { if (getError(PAYMENT_MADE_ERRORS.INVALID_BILL_PAYMENT_AMOUNT)) {
setFieldError( setFieldError(
'payment_amount', 'payment_amount',
intl.get('the_payment_amount_bigger_than_invoice_due_amount'), intl.get('the_payment_amount_bigger_than_invoice_due_amount'),
); );
} }
if (getError('WITHDRAWAL_ACCOUNT_CURRENCY_INVALID')) { if (getError(PAYMENT_MADE_ERRORS.WITHDRAWAL_ACCOUNT_CURRENCY_INVALID)) {
AppToaster.show({ AppToaster.show({
message: intl.get( message: intl.get(
'payment_made.error.withdrawal_account_currency_invalid', 'payment_made.error.withdrawal_account_currency_invalid',

View File

@@ -1,12 +1,13 @@
// @ts-nocheck // @ts-nocheck
import React from 'react'; import React from 'react';
import { Card } from '@/components'; import { Card, CommercialDocBox } from '@/components';
import CashflowTransactionDrawerActionBar from './CashflowTransactionDrawerActionBar'; import CashflowTransactionDrawerActionBar from './CashflowTransactionDrawerActionBar';
import CashflowTransactionDrawerHeader from './CashflowTransactionDrawerHeader'; import CashflowTransactionDrawerHeader from './CashflowTransactionDrawerHeader';
import CashflowTransactionDrawerTable from './CashflowTransactionDrawerTable'; import CashflowTransactionDrawerTable from './CashflowTransactionDrawerTable';
import CashflowTransactionDrawerFooter from './CashflowTransactionDrawerFooter'; import CashflowTransactionDrawerTableFooter from './CashflowTransactionDrawerTableFooter';
import { CashflowTransactionDrawerFooter } from './CashflowTransactionDrawerFooter';
/** /**
* Cashflow transaction view details. * Cashflow transaction view details.
*/ */
@@ -16,11 +17,12 @@ export default function CashflowTransactionDrawerDetails() {
<CashflowTransactionDrawerActionBar /> <CashflowTransactionDrawerActionBar />
<div className="cashflow-drawer__content"> <div className="cashflow-drawer__content">
<Card> <CommercialDocBox>
<CashflowTransactionDrawerHeader /> <CashflowTransactionDrawerHeader />
<CashflowTransactionDrawerTable /> <CashflowTransactionDrawerTable />
<CashflowTransactionDrawerTableFooter />
<CashflowTransactionDrawerFooter /> <CashflowTransactionDrawerFooter />
</Card> </CommercialDocBox>
</div> </div>
</div> </div>
); );

View File

@@ -1,35 +1,18 @@
// @ts-nocheck // @ts-nocheck
import React from 'react'; import React from 'react';
import { CommercialDocFooter, DetailsMenu, DetailItem, T } from '@/components';
import { useCashflowTransactionDrawerContext } from './CashflowTransactionDrawerProvider'; import { useCashflowTransactionDrawerContext } from './CashflowTransactionDrawerProvider';
import { T, FormatNumber } from '@/components';
export default function CashflowTransactionDrawerFooter() { export function CashflowTransactionDrawerFooter() {
const { const { cashflowTransaction } = useCashflowTransactionDrawerContext();
cashflowTransaction: { formatted_amount },
} = useCashflowTransactionDrawerContext();
return ( return (
<div className="cashflow-drawer__content-footer"> <CommercialDocFooter>
<div class="total-lines"> <DetailsMenu direction={'horizantal'} minLabelSize={'180px'}>
<div class="total-lines__line total-lines__line--subtotal"> <DetailItem label={<T id={'cash_flow.drawer.label.statement'} />}>
<div class="title"> {cashflowTransaction.description}
<T id={'manual_journal.details.subtotal'} /> </DetailItem>
</div> </DetailsMenu>
<div class="debit"> </CommercialDocFooter>
<FormatNumber value={formatted_amount} />
</div>
<div class="credit">
<FormatNumber value={formatted_amount} />
</div>
</div>
<div class="total-lines__line total-lines__line--total">
<div class="title">
<T id={'manual_journal.details.total'} />
</div>
<div class="debit">{formatted_amount}</div>
<div class="credit">{formatted_amount}</div>
</div>
</div>
</div>
); );
} }

View File

@@ -0,0 +1,35 @@
// @ts-nocheck
import React from 'react';
import { useCashflowTransactionDrawerContext } from './CashflowTransactionDrawerProvider';
import { T, FormatNumber } from '@/components';
export default function CashflowTransactionDrawerTableFooter() {
const {
cashflowTransaction: { formatted_amount },
} = useCashflowTransactionDrawerContext();
return (
<div className="cashflow-drawer__content-footer">
<div class="total-lines">
<div class="total-lines__line total-lines__line--subtotal">
<div class="title">
<T id={'manual_journal.details.subtotal'} />
</div>
<div class="debit">
<FormatNumber value={formatted_amount} />
</div>
<div class="credit">
<FormatNumber value={formatted_amount} />
</div>
</div>
<div class="total-lines__line total-lines__line--total">
<div class="title">
<T id={'manual_journal.details.total'} />
</div>
<div class="debit">{formatted_amount}</div>
<div class="credit">{formatted_amount}</div>
</div>
</div>
</div>
);
}

View File

@@ -1,6 +1,5 @@
// @ts-nocheck // @ts-nocheck
import React from 'react'; import React from 'react';
import { import {
CommercialDocFooter, CommercialDocFooter,
T, T,

View File

@@ -4,9 +4,8 @@ import {
DrawerHeaderContent, DrawerHeaderContent,
DrawerBody, DrawerBody,
FormattedMessage as T, FormattedMessage as T,
Drawer,
} from '@/components'; } from '@/components';
import { DRAWERS } from '@/constants/drawers';
import QuickCreateItemDrawerForm from './QuickCreateItemDrawerForm'; import QuickCreateItemDrawerForm from './QuickCreateItemDrawerForm';
/** /**
@@ -16,7 +15,7 @@ export default function QuickCreateItemDrawerContent({ itemName }) {
return ( return (
<React.Fragment> <React.Fragment>
<DrawerHeaderContent <DrawerHeaderContent
name={DRAWER.QUICK_CREATE_ITEM} name={DRAWERS.QUICK_CREATE_ITEM}
title={<T id={'create_a_new_item'} />} title={<T id={'create_a_new_item'} />}
/> />
<DrawerBody> <DrawerBody>

View File

@@ -17,16 +17,6 @@ import withDashboardActions from '@/containers/Dashboard/withDashboardActions';
import { useDrawerContext } from '@/components/Drawer/DrawerProvider'; import { useDrawerContext } from '@/components/Drawer/DrawerProvider';
import { DRAWERS } from '@/constants/drawers'; import { DRAWERS } from '@/constants/drawers';
/**
* Drawer item form loading.
* @returns {JSX}
*/
function DrawerItemFormLoading({ children }) {
const { isFormLoading } = useItemFormContext();
return <DrawerLoading loading={isFormLoading}>{children}</DrawerLoading>;
}
/** /**
* Quick create/edit item drawer form. * Quick create/edit item drawer form.
*/ */
@@ -72,6 +62,16 @@ function QuickCreateItemDrawerForm({
); );
} }
/**
* Drawer item form loading.
* @returns {JSX}
*/
function DrawerItemFormLoading({ children }) {
const { isFormLoading } = useItemFormContext();
return <DrawerLoading loading={isFormLoading}>{children}</DrawerLoading>;
}
export default R.compose( export default R.compose(
withDrawerActions, withDrawerActions,
withDashboardActions, withDashboardActions,
@@ -79,10 +79,15 @@ export default R.compose(
const ItemFormCard = styled(Card)` const ItemFormCard = styled(Card)`
margin: 15px; margin: 15px;
padding: 25px;
margin-bottom: calc(15px + 65px); margin-bottom: calc(15px + 65px);
.page-form__floating-actions { .page-form {
margin-left: -36px; padding: 0;
margin-right: -36px;
&__floating-actions {
margin-left: -41px;
margin-right: -41px;
}
} }
`; `;

View File

@@ -3,7 +3,7 @@ import React from 'react';
import { InputGroup, FormGroup, Position, Classes } from '@blueprintjs/core'; import { InputGroup, FormGroup, Position, Classes } from '@blueprintjs/core';
import { DateInput } from '@blueprintjs/datetime'; import { DateInput } from '@blueprintjs/datetime';
import { FastField, ErrorMessage } from 'formik'; import { FastField, ErrorMessage } from 'formik';
import { FormattedMessage as T } from '@/components'; import { CustomersSelect, FormattedMessage as T } from '@/components';
import classNames from 'classnames'; import classNames from 'classnames';
import { CLASSES } from '@/constants/classes'; import { CLASSES } from '@/constants/classes';
import { import {
@@ -121,33 +121,39 @@ export default function ExpenseFormHeader() {
)} )}
</FastField> </FastField>
<FastField {/* ----------- Customer ----------- */}
name={'customer_id'} <ExpenseFormCustomerSelect />
customers={customers}
shouldUpdate={customersFieldShouldUpdate}
>
{({ form, field: { value }, meta: { error, touched } }) => (
<FormGroup
label={<T id={'customer'} />}
className={classNames('form-group--select-list', Classes.FILL)}
labelInfo={<Hint />}
intent={inputIntent({ error, touched })}
helperText={<ErrorMessage name={'assign_to_customer'} />}
inline={true}
>
<CustomerSelectField
contacts={customers}
selectedContactId={value}
defaultSelectText={<T id={'select_customer_account'} />}
onContactSelected={(customer) => {
form.setFieldValue('customer_id', customer.id);
}}
allowCreate={true}
popoverFill={true}
/>
</FormGroup>
)}
</FastField>
</div> </div>
); );
} }
/**
* Customer select field of expense form.
* @returns {React.ReactNode}
*/
function ExpenseFormCustomerSelect() {
const { customers } = useExpenseFormContext();
return (
<FormGroup
label={<T id={'customer'} />}
labelInfo={<Hint />}
inline={true}
name={'customer_id'}
fastField={true}
shouldUpdateDeps={{ items: customers }}
shouldUpdate={customersFieldShouldUpdate}
>
<CustomersSelect
name={'customer_id'}
items={customers}
placeholder={<T id={'select_customer_account'} />}
allowCreate={true}
popoverFill={true}
fastField={true}
shouldUpdateDeps={{ items: customers }}
shouldUpdate={customersFieldShouldUpdate}
/>
</FormGroup>
);
}

View File

@@ -1,16 +1,15 @@
// @ts-nocheck // @ts-nocheck
import React from 'react'; import React from 'react';
import intl from 'react-intl-universal'; import { Alignment, NavbarGroup, Classes } from '@blueprintjs/core';
import { Button, Alignment, NavbarGroup, Classes } from '@blueprintjs/core';
import { useSetPrimaryBranchToForm } from './utils'; import { useSetPrimaryBranchToForm } from './utils';
import { useFeatureCan } from '@/hooks/state'; import { useFeatureCan } from '@/hooks/state';
import { Features } from '@/constants'; import { Features } from '@/constants';
import { import {
Icon,
BranchSelect, BranchSelect,
FeatureCan, FeatureCan,
FormTopbar, FormTopbar,
DetailsBarSkeletonBase, DetailsBarSkeletonBase,
FormBranchSelectButton,
} from '@/components'; } from '@/components';
import { useExpenseFormContext } from './ExpenseFormPageProvider'; import { useExpenseFormContext } from './ExpenseFormPageProvider';
@@ -51,19 +50,9 @@ function ExpenseFormSelectBranch() {
<BranchSelect <BranchSelect
name={'branch_id'} name={'branch_id'}
branches={branches} branches={branches}
input={ExpenseBranchSelectButton} input={FormBranchSelectButton}
popoverProps={{ minimal: true }} popoverProps={{ minimal: true }}
/> fill={false}
);
}
function ExpenseBranchSelectButton({ label }) {
return (
<Button
text={intl.get('expense.branch_button.label', { label })}
minimal={true}
small={true}
icon={<Icon icon={'branch-16'} iconSize={16} />}
/> />
); );
} }

View File

@@ -104,7 +104,7 @@ export const transformToEditForm = (
*/ */
export const customersFieldShouldUpdate = (newProps, oldProps) => { export const customersFieldShouldUpdate = (newProps, oldProps) => {
return ( return (
newProps.customers !== oldProps.customers || newProps.shouldUpdateDeps.items !== oldProps.shouldUpdateDeps.items ||
defaultFastFieldShouldUpdate(newProps, oldProps) defaultFastFieldShouldUpdate(newProps, oldProps)
); );
}; };

View File

@@ -90,7 +90,9 @@ export default function ItemFormFormik({
}; };
return ( return (
<div class={classNames(CLASSES.PAGE_FORM_ITEM, className)}> <div
class={classNames(CLASSES.PAGE_FORM, CLASSES.PAGE_FORM_ITEM, className)}
>
<Formik <Formik
enableReinitialize={true} enableReinitialize={true}
validationSchema={isNewMode ? CreateItemFormSchema : EditItemFormSchema} validationSchema={isNewMode ? CreateItemFormSchema : EditItemFormSchema}

View File

@@ -15,11 +15,10 @@ import {
FMoneyInputGroup, FMoneyInputGroup,
InputPrependText, InputPrependText,
FormattedMessage as T, FormattedMessage as T,
FieldRequiredHint,
CustomerSelectField,
Stack, Stack,
CustomersSelect,
} from '@/components'; } from '@/components';
import { inputIntent, momentFormatter } from '@/utils'; import { momentFormatter } from '@/utils';
import { useProjectFormContext } from './ProjectFormProvider'; import { useProjectFormContext } from './ProjectFormProvider';
/** /**
@@ -27,9 +26,6 @@ import { useProjectFormContext } from './ProjectFormProvider';
* @returns * @returns
*/ */
function ProjectFormFields() { function ProjectFormFields() {
// project form dialog context.
const { customers } = useProjectFormContext();
// Formik context. // Formik context.
const { values } = useFormikContext(); const { values } = useFormikContext();
@@ -37,26 +33,7 @@ function ProjectFormFields() {
<div className={Classes.DIALOG_BODY}> <div className={Classes.DIALOG_BODY}>
<Stack spacing={25}> <Stack spacing={25}>
{/*------------ Contact -----------*/} {/*------------ Contact -----------*/}
<FastField name={'contact_id'}> <ProjectFormCustomerSelect />
{({ form, field: { value }, meta: { error, touched } }) => (
<FormGroup
label={intl.get('projects.dialog.contact')}
className={classNames('form-group--select-list', Classes.FILL)}
intent={inputIntent({ error, touched })}
>
<CustomerSelectField
contacts={customers}
selectedContactId={value}
defaultSelectText={'Find or create a customer'}
onContactSelected={(customer) => {
form.setFieldValue('contact_id', customer.id);
}}
allowCreate={true}
popoverFill={true}
/>
</FormGroup>
)}
</FastField>
{/*------------ Project Name -----------*/} {/*------------ Project Name -----------*/}
<FFormGroup <FFormGroup
@@ -113,4 +90,21 @@ function ProjectFormFields() {
); );
} }
function ProjectFormCustomerSelect() {
// project form dialog context.
const { customers } = useProjectFormContext();
return (
<FormGroup name={'contact_id'} label={intl.get('projects.dialog.contact')}>
<CustomersSelect
name={'contact_id'}
items={customers}
placeholder={'Find or create a customer'}
allowCreate={true}
popoverFill={true}
/>
</FormGroup>
);
}
export default ProjectFormFields; export default ProjectFormFields;

View File

@@ -2,18 +2,18 @@
import React from 'react'; import React from 'react';
import styled from 'styled-components'; import styled from 'styled-components';
import classNames from 'classnames'; import classNames from 'classnames';
import { FastField, ErrorMessage, useFormikContext } from 'formik';
import { FormGroup, InputGroup, Classes, Position } from '@blueprintjs/core'; import { FormGroup, InputGroup, Classes, Position } from '@blueprintjs/core';
import { FastField, ErrorMessage } from 'formik';
import { DateInput } from '@blueprintjs/datetime'; import { DateInput } from '@blueprintjs/datetime';
import { FeatureCan, FormattedMessage as T } from '@/components'; import { FeatureCan, FormattedMessage as T } from '@/components';
import { CLASSES } from '@/constants/classes'; import { CLASSES } from '@/constants/classes';
import { import {
FFormGroup, FFormGroup,
VendorSelectField,
FieldRequiredHint, FieldRequiredHint,
Icon, Icon,
VendorDrawerLink, VendorDrawerLink,
VendorsSelect,
} from '@/components'; } from '@/components';
import { useBillFormContext } from './BillFormProvider'; import { useBillFormContext } from './BillFormProvider';
@@ -43,43 +43,7 @@ function BillFormHeader() {
return ( return (
<div className={classNames(CLASSES.PAGE_FORM_HEADER_FIELDS)}> <div className={classNames(CLASSES.PAGE_FORM_HEADER_FIELDS)}>
{/* ------- Vendor name ------ */} {/* ------- Vendor name ------ */}
<FastField <BillFormVendorField />
name={'vendor_id'}
vendors={vendors}
shouldUpdate={vendorsFieldShouldUpdate}
>
{({ form, field: { value }, meta: { error, touched } }) => (
<FFormGroup
name={'vendor_id'}
label={<T id={'vendor_name'} />}
inline={true}
className={classNames(
'form-group--vendor-name',
'form-group--select-list',
CLASSES.FILL,
)}
labelInfo={<FieldRequiredHint />}
>
<VendorSelectField
contacts={vendors}
selectedContactId={value}
defaultSelectText={<T id={'select_vender_account'} />}
onContactSelected={(contact) => {
form.setFieldValue('vendor_id', contact.id);
form.setFieldValue('currency_code', contact?.currency_code);
}}
popoverFill={true}
allowCreate={true}
/>
{value && (
<VendorButtonLink vendorId={value}>
<T id={'view_vendor_details'} />
</VendorButtonLink>
)}
</FFormGroup>
)}
</FastField>
{/* ----------- Exchange rate ----------- */} {/* ----------- Exchange rate ----------- */}
<BillExchangeRateInputField <BillExchangeRateInputField
@@ -190,6 +154,46 @@ function BillFormHeader() {
); );
} }
/**
* Vendor select field of bill form.
* @returns {JSX.Element}
*/
function BillFormVendorField() {
const { values, setFieldValue } = useFormikContext();
const { vendors } = useBillFormContext();
return (
<FFormGroup
name={'vendor_id'}
label={<T id={'vendor_name'} />}
inline={true}
labelInfo={<FieldRequiredHint />}
fastField={true}
shouldUpdate={vendorsFieldShouldUpdate}
shouldUpdateDeps={{ items: vendors }}
>
<VendorsSelect
name={'vendor_id'}
items={vendors}
placeholder={<T id={'select_vender_account'} />}
onItemChange={(contact) => {
setFieldValue('vendor_id', contact.id);
setFieldValue('currency_code', contact?.currency_code);
}}
allowCreate={true}
fastField={true}
shouldUpdate={vendorsFieldShouldUpdate}
shouldUpdateDeps={{ items: vendors }}
/>
{values.vendor_id && (
<VendorButtonLink vendorId={values.vendor_id}>
<T id={'view_vendor_details'} />
</VendorButtonLink>
)}
</FFormGroup>
);
}
export default compose(withDialogActions)(BillFormHeader); export default compose(withDialogActions)(BillFormHeader);
const VendorButtonLink = styled(VendorDrawerLink)` const VendorButtonLink = styled(VendorDrawerLink)`

View File

@@ -1,11 +1,9 @@
// @ts-nocheck // @ts-nocheck
import React from 'react'; import React from 'react';
import intl from 'react-intl-universal';
import { import {
Alignment, Alignment,
NavbarGroup, NavbarGroup,
NavbarDivider, NavbarDivider,
Button,
Classes, Classes,
} from '@blueprintjs/core'; } from '@blueprintjs/core';
import { import {
@@ -14,12 +12,13 @@ import {
} from './utils'; } from './utils';
import { useFeatureCan } from '@/hooks/state'; import { useFeatureCan } from '@/hooks/state';
import { import {
Icon,
BranchSelect, BranchSelect,
FeatureCan, FeatureCan,
WarehouseSelect, WarehouseSelect,
FormTopbar, FormTopbar,
DetailsBarSkeletonBase, DetailsBarSkeletonBase,
FormWarehouseSelectButton,
FormBranchSelectButton,
} from '@/components'; } from '@/components';
import { useBillFormContext } from './BillFormProvider'; import { useBillFormContext } from './BillFormProvider';
import { Features } from '@/constants'; import { Features } from '@/constants';
@@ -70,8 +69,9 @@ function BillFormSelectBranch() {
<BranchSelect <BranchSelect
name={'branch_id'} name={'branch_id'}
branches={branches} branches={branches}
input={BillBranchSelectButton} input={FormBranchSelectButton}
popoverProps={{ minimal: true }} popoverProps={{ minimal: true }}
fill={false}
/> />
); );
} }
@@ -86,30 +86,9 @@ function BillFormSelectWarehouse() {
<WarehouseSelect <WarehouseSelect
name={'warehouse_id'} name={'warehouse_id'}
warehouses={warehouses} warehouses={warehouses}
input={BillWarehouseSelectButton} input={FormWarehouseSelectButton}
popoverProps={{ minimal: true }} popoverProps={{ minimal: true }}
/> fill={false}
);
}
function BillWarehouseSelectButton({ label }) {
return (
<Button
text={intl.get('bill.warehouse_button.label', { label })}
minimal={true}
small={true}
icon={<Icon icon={'warehouse-16'} iconSize={16} />}
/>
);
}
function BillBranchSelectButton({ label }) {
return (
<Button
text={intl.get('bill.branch_button.label', { label })}
minimal={true}
small={true}
icon={<Icon icon={'branch-16'} iconSize={16} />}
/> />
); );
} }

View File

@@ -19,7 +19,10 @@ import {
ensureEntriesHaveEmptyLine, ensureEntriesHaveEmptyLine,
} from '@/containers/Entries/utils'; } from '@/containers/Entries/utils';
import { useCurrentOrganization } from '@/hooks/state'; import { useCurrentOrganization } from '@/hooks/state';
import { isLandedCostDisabled, getEntriesTotal } from '@/containers/Entries/utils'; import {
isLandedCostDisabled,
getEntriesTotal,
} from '@/containers/Entries/utils';
import { useBillFormContext } from './BillFormProvider'; import { useBillFormContext } from './BillFormProvider';
export const MIN_LINES_NUMBER = 1; export const MIN_LINES_NUMBER = 1;
@@ -153,7 +156,7 @@ export const handleDeleteErrors = (errors) => {
*/ */
export const vendorsFieldShouldUpdate = (newProps, oldProps) => { export const vendorsFieldShouldUpdate = (newProps, oldProps) => {
return ( return (
newProps.vendors !== oldProps.vendors || newProps.shouldUpdateDeps.items !== oldProps.shouldUpdateDeps.items ||
defaultFastFieldShouldUpdate(newProps, oldProps) defaultFastFieldShouldUpdate(newProps, oldProps)
); );
}; };

View File

@@ -9,17 +9,17 @@ import {
ControlGroup, ControlGroup,
} from '@blueprintjs/core'; } from '@blueprintjs/core';
import { DateInput } from '@blueprintjs/datetime'; import { DateInput } from '@blueprintjs/datetime';
import { FastField, ErrorMessage } from 'formik'; import { FastField, ErrorMessage, useFormikContext } from 'formik';
import { CLASSES } from '@/constants/classes'; import { CLASSES } from '@/constants/classes';
import { import {
FFormGroup, FFormGroup,
VendorSelectField,
FieldRequiredHint, FieldRequiredHint,
InputPrependButton, InputPrependButton,
Icon, Icon,
FormattedMessage as T, FormattedMessage as T,
VendorDrawerLink, VendorDrawerLink,
VendorsSelect,
} from '@/components'; } from '@/components';
import { import {
vendorsFieldShouldUpdate, vendorsFieldShouldUpdate,
@@ -51,9 +51,6 @@ function VendorCreditNoteFormHeaderFields({
vendorcreditNumberPrefix, vendorcreditNumberPrefix,
vendorcreditNextNumber, vendorcreditNextNumber,
}) { }) {
// Vendor Credit form context.
const { vendors } = useVendorCreditNoteFormContext();
// Handle vendor credit number changing. // Handle vendor credit number changing.
const handleVendorCreditNumberChange = () => { const handleVendorCreditNumberChange = () => {
openDialog('vendor-credit-form'); openDialog('vendor-credit-form');
@@ -81,39 +78,7 @@ function VendorCreditNoteFormHeaderFields({
return ( return (
<div className={classNames(CLASSES.PAGE_FORM_HEADER_FIELDS)}> <div className={classNames(CLASSES.PAGE_FORM_HEADER_FIELDS)}>
{/* ----------- Vendor name ----------- */} {/* ----------- Vendor name ----------- */}
<FastField <VendorCreditFormVendorSelect />
name={'vendor_id'}
vendors={vendors}
shouldUpdate={vendorsFieldShouldUpdate}
>
{({ form, field: { value }, meta: { error, touched } }) => (
<FFormGroup
name={'vendor_id'}
label={<T id={'vendor_name'} />}
inline={true}
className={classNames(CLASSES.FILL, 'form-group--vendor')}
labelInfo={<FieldRequiredHint />}
>
<VendorSelectField
contacts={vendors}
selectedContactId={value}
defaultSelectText={<T id={'select_vender_account'} />}
onContactSelected={(contact) => {
form.setFieldValue('vendor_id', contact.id);
form.setFieldValue('currency_code', contact?.currency_code);
}}
popoverFill={true}
allowCreate={true}
/>
{value && (
<VendorButtonLink vendorId={value}>
<T id={'view_vendor_details'} />
</VendorButtonLink>
)}
</FFormGroup>
)}
</FastField>
{/* ----------- Exchange rate ----------- */} {/* ----------- Exchange rate ----------- */}
<VendorCreditNoteExchangeRateInputField <VendorCreditNoteExchangeRateInputField
@@ -205,6 +170,49 @@ function VendorCreditNoteFormHeaderFields({
); );
} }
/**
* Vendor select field of vendor credit form.
* @returns {React.ReactNode}
*/
function VendorCreditFormVendorSelect() {
const { values, setFieldValue } = useFormikContext();
// Vendor Credit form context.
const { vendors } = useVendorCreditNoteFormContext();
return (
<FFormGroup
name={'vendor_id'}
label={<T id={'vendor_name'} />}
inline={true}
labelInfo={<FieldRequiredHint />}
fastField={true}
shouldUpdate={vendorsFieldShouldUpdate}
shouldUpdateDeps={{ items: vendors }}
>
<VendorsSelect
name={'vendor_id'}
items={vendors}
placeholder={<T id={'select_vender_account'} />}
onItemChange={(contact) => {
setFieldValue('vendor_id', contact.id);
setFieldValue('currency_code', contact?.currency_code);
}}
popoverFill={true}
allowCreate={true}
fastField={true}
shouldUpdate={vendorsFieldShouldUpdate}
shouldUpdateDeps={{ items: vendors }}
/>
{values.vendor_id && (
<VendorButtonLink vendorId={values.vendor_id}>
<T id={'view_vendor_details'} />
</VendorButtonLink>
)}
</FFormGroup>
);
}
export default compose( export default compose(
withDialogActions, withDialogActions,
withSettings(({ vendorsCreditNoteSetting }) => ({ withSettings(({ vendorsCreditNoteSetting }) => ({

View File

@@ -1,6 +1,5 @@
// @ts-nocheck // @ts-nocheck
import React from 'react'; import React from 'react';
import intl from 'react-intl-universal';
import { import {
Alignment, Alignment,
NavbarGroup, NavbarGroup,
@@ -20,6 +19,8 @@ import {
WarehouseSelect, WarehouseSelect,
FormTopbar, FormTopbar,
DetailsBarSkeletonBase, DetailsBarSkeletonBase,
FormWarehouseSelectButton,
FormBranchSelectButton,
} from '@/components'; } from '@/components';
import { useVendorCreditNoteFormContext } from './VendorCreditNoteFormProvider'; import { useVendorCreditNoteFormContext } from './VendorCreditNoteFormProvider';
import { Features } from '@/constants'; import { Features } from '@/constants';
@@ -70,8 +71,9 @@ function VendorCreditNoteFormSelectBranch() {
<BranchSelect <BranchSelect
name={'branch_id'} name={'branch_id'}
branches={branches} branches={branches}
input={VendorCreditNoteBranchSelectButton} input={FormBranchSelectButton}
popoverProps={{ minimal: true }} popoverProps={{ minimal: true }}
fill={false}
/> />
); );
} }
@@ -86,30 +88,9 @@ function VendorCreditFormSelectWarehouse() {
<WarehouseSelect <WarehouseSelect
name={'warehouse_id'} name={'warehouse_id'}
warehouses={warehouses} warehouses={warehouses}
input={VendorCreditNoteWarehouseSelectButton} input={FormWarehouseSelectButton}
popoverProps={{ minimal: true }} popoverProps={{ minimal: true }}
/> fill={false}
);
}
function VendorCreditNoteWarehouseSelectButton({ label }) {
return (
<Button
text={intl.get('vendor_credit.warehouse_button.label', { label })}
minimal={true}
small={true}
icon={<Icon icon={'warehouse-16'} iconSize={16} />}
/>
);
}
function VendorCreditNoteBranchSelectButton({ label }) {
return (
<Button
text={intl.get('vendor_credit.branch_button.label', { label })}
minimal={true}
small={true}
icon={<Icon icon={'branch-16'} iconSize={16} />}
/> />
); );
} }

View File

@@ -113,7 +113,7 @@ export const transformFormValuesToRequest = (values) => {
*/ */
export const vendorsFieldShouldUpdate = (newProps, oldProps) => { export const vendorsFieldShouldUpdate = (newProps, oldProps) => {
return ( return (
newProps.vendors !== oldProps.vendors || newProps.shouldUpdateDeps.items !== oldProps.shouldUpdateDeps.items ||
defaultFastFieldShouldUpdate(newProps, oldProps) defaultFastFieldShouldUpdate(newProps, oldProps)
); );
}; };

View File

@@ -13,12 +13,14 @@ export function PaymentMadeFormFooterLeft() {
<React.Fragment> <React.Fragment>
{/* --------- Internal Note--------- */} {/* --------- Internal Note--------- */}
<InternalNoteFormGroup <InternalNoteFormGroup
name={'internal_note'} name={'statement'}
label={<T id={'payment_made.form.internal_note.label'} />} label={<T id={'payment_made.form.internal_note.label'} />}
fastField={true}
> >
<FEditableText <FEditableText
name={'internal_note'} name={'statement'}
placeholder={intl.get('payment_made.form.internal_note.placeholder')} placeholder={intl.get('payment_made.form.internal_note.placeholder')}
fastField={true}
/> />
</InternalNoteFormGroup> </InternalNoteFormGroup>
</React.Fragment> </React.Fragment>

View File

@@ -12,14 +12,13 @@ import {
} from '@blueprintjs/core'; } from '@blueprintjs/core';
import { DateInput } from '@blueprintjs/datetime'; import { DateInput } from '@blueprintjs/datetime';
import { FastField, Field, useFormikContext, ErrorMessage } from 'formik'; import { FastField, Field, useFormikContext, ErrorMessage } from 'formik';
import { FormattedMessage as T } from '@/components'; import { FormattedMessage as T, VendorsSelect } from '@/components';
import { toSafeInteger } from 'lodash'; import { toSafeInteger } from 'lodash';
import { CLASSES } from '@/constants/classes'; import { CLASSES } from '@/constants/classes';
import { import {
FFormGroup, FFormGroup,
AccountsSelect, AccountsSelect,
VendorSelectField,
FieldRequiredHint, FieldRequiredHint,
InputPrependText, InputPrependText,
Money, Money,
@@ -55,8 +54,7 @@ function PaymentMadeFormHeaderFields({ organization: { base_currency } }) {
} = useFormikContext(); } = useFormikContext();
// Payment made form context. // Payment made form context.
const { vendors, accounts, isNewMode, setPaymentVendorId } = const { accounts } = usePaymentMadeFormContext();
usePaymentMadeFormContext();
// Sumation of payable full-amount. // Sumation of payable full-amount.
const payableFullAmount = useMemo( const payableFullAmount = useMemo(
@@ -82,41 +80,7 @@ function PaymentMadeFormHeaderFields({ organization: { base_currency } }) {
return ( return (
<div className={classNames(CLASSES.PAGE_FORM_HEADER_FIELDS)}> <div className={classNames(CLASSES.PAGE_FORM_HEADER_FIELDS)}>
{/* ------------ Vendor name ------------ */} {/* ------------ Vendor name ------------ */}
<FastField <PaymentFormVendorSelect />
name={'vendor_id'}
vendors={vendors}
shouldUpdate={vendorsFieldShouldUpdate}
>
{({ form, field: { value }, meta: { error, touched } }) => (
<FFormGroup
name={'vendor_id'}
label={<T id={'vendor_name'} />}
inline={true}
className={classNames('form-group--select-list', Classes.FILL)}
labelInfo={<FieldRequiredHint />}
>
<VendorSelectField
contacts={vendors}
selectedContactId={value}
defaultSelectText={<T id={'select_vender_account'} />}
onContactSelected={(contact) => {
form.setFieldValue('vendor_id', contact.id);
form.setFieldValue('currency_code', contact?.currency_code);
setPaymentVendorId(contact.id);
}}
disabled={!isNewMode}
popoverFill={true}
allowCreate={true}
/>
{value && (
<VendorButtonLink vendorId={value}>
<T id={'view_vendor_details'} />
</VendorButtonLink>
)}
</FFormGroup>
)}
</FastField>
{/* ----------- Exchange rate ----------- */} {/* ----------- Exchange rate ----------- */}
<PaymentMadeExchangeRateInputField <PaymentMadeExchangeRateInputField
@@ -258,6 +222,52 @@ function PaymentMadeFormHeaderFields({ organization: { base_currency } }) {
); );
} }
/**
* Vendor select field of payment receive form.
* @returns {React.ReactNode}
*/
function PaymentFormVendorSelect() {
// Formik form context.
const { values, setFieldValue } = useFormikContext();
// Payment made form context.
const { vendors, isNewMode, setPaymentVendorId } =
usePaymentMadeFormContext();
return (
<FFormGroup
name={'vendor_id'}
label={<T id={'vendor_name'} />}
labelInfo={<FieldRequiredHint />}
inline={true}
fastField={true}
shouldUpdate={vendorsFieldShouldUpdate}
shouldUpdateDeps={{ items: vendors }}
>
<VendorsSelect
name={'vendor_id'}
items={vendors}
placeholder={<T id={'select_vender_account'} />}
onItemChange={(contact) => {
setFieldValue('vendor_id', contact.id);
setFieldValue('currency_code', contact?.currency_code);
setPaymentVendorId(contact.id);
}}
disabled={!isNewMode}
allowCreate={true}
fastField={true}
shouldUpdate={vendorsFieldShouldUpdate}
shouldUpdateDeps={{ items: vendors }}
/>
{values.vendor_id && (
<VendorButtonLink vendorId={values.vendor_id}>
<T id={'view_vendor_details'} />
</VendorButtonLink>
)}
</FFormGroup>
);
}
export default compose(withCurrentOrganization())(PaymentMadeFormHeaderFields); export default compose(withCurrentOrganization())(PaymentMadeFormHeaderFields);
const VendorButtonLink = styled(VendorDrawerLink)` const VendorButtonLink = styled(VendorDrawerLink)`

View File

@@ -1,15 +1,14 @@
// @ts-nocheck // @ts-nocheck
import React from 'react'; import React from 'react';
import intl from 'react-intl-universal'; import { Alignment, NavbarGroup, Classes } from '@blueprintjs/core';
import { Alignment, NavbarGroup, Button, Classes } from '@blueprintjs/core';
import { useSetPrimaryBranchToForm } from './utils'; import { useSetPrimaryBranchToForm } from './utils';
import { useFeatureCan } from '@/hooks/state'; import { useFeatureCan } from '@/hooks/state';
import { import {
Icon,
BranchSelect, BranchSelect,
FeatureCan, FeatureCan,
FormTopbar, FormTopbar,
DetailsBarSkeletonBase, DetailsBarSkeletonBase,
FormBranchSelectButton,
} from '@/components'; } from '@/components';
import { usePaymentMadeFormContext } from './PaymentMadeFormProvider'; import { usePaymentMadeFormContext } from './PaymentMadeFormProvider';
import { Features } from '@/constants'; import { Features } from '@/constants';
@@ -50,19 +49,9 @@ function PaymentMadeFormSelectBranch() {
<BranchSelect <BranchSelect
name={'branch_id'} name={'branch_id'}
branches={branches} branches={branches}
input={PaymentMadeBranchSelectButton} input={FormBranchSelectButton}
popoverProps={{ minimal: true }} popoverProps={{ minimal: true }}
/> fill={false}
);
}
function PaymentMadeBranchSelectButton({ label }) {
return (
<Button
text={intl.get('payment_made.branch_button.label', { label })}
minimal={true}
small={true}
icon={<Icon icon={'branch-16'} iconSize={16} />}
/> />
); );
} }

View File

@@ -15,6 +15,7 @@ import {
formattedAmount, formattedAmount,
} from '@/utils'; } from '@/utils';
import { useCurrentOrganization } from '@/hooks/state'; import { useCurrentOrganization } from '@/hooks/state';
import { PAYMENT_MADE_ERRORS } from '../constants';
export const ERRORS = { export const ERRORS = {
PAYMENT_NUMBER_NOT_UNIQUE: 'PAYMENT.NUMBER.NOT.UNIQUE', PAYMENT_NUMBER_NOT_UNIQUE: 'PAYMENT.NUMBER.NOT.UNIQUE',
@@ -74,7 +75,7 @@ export const transformToNewPageEntries = (entries) => {
*/ */
export const vendorsFieldShouldUpdate = (newProps, oldProps) => { export const vendorsFieldShouldUpdate = (newProps, oldProps) => {
return ( return (
newProps.vendors !== oldProps.vendors || newProps.shouldUpdateDeps.items !== oldProps.shouldUpdateDeps.items ||
defaultFastFieldShouldUpdate(newProps, oldProps) defaultFastFieldShouldUpdate(newProps, oldProps)
); );
}; };
@@ -124,10 +125,10 @@ export const useSetPrimaryBranchToForm = () => {
export const transformErrors = (errors, { setFieldError }) => { export const transformErrors = (errors, { setFieldError }) => {
const getError = (errorType) => errors.find((e) => e.type === errorType); const getError = (errorType) => errors.find((e) => e.type === errorType);
if (getError('PAYMENT_NUMBER_NOT_UNIQUE')) { if (getError(PAYMENT_MADE_ERRORS.PAYMENT_NUMBER_NOT_UNIQUE)) {
setFieldError('payment_number', intl.get('payment_number_is_not_unique')); setFieldError('payment_number', intl.get('payment_number_is_not_unique'));
} }
if (getError('WITHDRAWAL_ACCOUNT_CURRENCY_INVALID')) { if (getError(PAYMENT_MADE_ERRORS.WITHDRAWAL_ACCOUNT_CURRENCY_INVALID)) {
AppToaster.show({ AppToaster.show({
message: intl.get( message: intl.get(
'payment_made.error.withdrawal_account_currency_invalid', 'payment_made.error.withdrawal_account_currency_invalid',

View File

@@ -0,0 +1,5 @@
export const PAYMENT_MADE_ERRORS = {
PAYMENT_NUMBER_NOT_UNIQUE: 'PAYMENT.NUMBER.NOT.UNIQUE',
WITHDRAWAL_ACCOUNT_CURRENCY_INVALID: 'WITHDRAWAL_ACCOUNT_CURRENCY_INVALID',
INVALID_BILL_PAYMENT_AMOUNT: 'INVALID_BILL_PAYMENT_AMOUNT'
};

View File

@@ -4,15 +4,16 @@ import classNames from 'classnames';
import styled from 'styled-components'; import styled from 'styled-components';
import { FormGroup, InputGroup, Position } from '@blueprintjs/core'; import { FormGroup, InputGroup, Position } from '@blueprintjs/core';
import { DateInput } from '@blueprintjs/datetime'; import { DateInput } from '@blueprintjs/datetime';
import { FastField, ErrorMessage } from 'formik'; import { FastField, ErrorMessage, useFormikContext } from 'formik';
import { CLASSES } from '@/constants/classes'; import { CLASSES } from '@/constants/classes';
import { import {
CustomerSelectField,
FieldRequiredHint, FieldRequiredHint,
Icon, Icon,
FormattedMessage as T, FormattedMessage as T,
CustomerDrawerLink, CustomerDrawerLink,
FFormGroup,
CustomersSelect,
} from '@/components'; } from '@/components';
import { customerNameFieldShouldUpdate } from './utils'; import { customerNameFieldShouldUpdate } from './utils';
@@ -30,49 +31,10 @@ import {
* Credit note form header fields. * Credit note form header fields.
*/ */
export default function CreditNoteFormHeaderFields({}) { export default function CreditNoteFormHeaderFields({}) {
// Credit note form context.
const { customers } = useCreditNoteFormContext();
return ( return (
<div className={classNames(CLASSES.PAGE_FORM_HEADER_FIELDS)}> <div className={classNames(CLASSES.PAGE_FORM_HEADER_FIELDS)}>
{/* ----------- Customer name ----------- */} {/* ----------- Customer name ----------- */}
<FastField <CreditNoteCustomersSelect />
name={'customer_id'}
customers={customers}
shouldUpdate={customerNameFieldShouldUpdate}
>
{({ form, field: { value }, meta: { error, touched } }) => (
<FormGroup
label={<T id={'customer_name'} />}
inline={true}
className={classNames(
'form-group--customer-name',
'form-group--select-list',
CLASSES.FILL,
)}
labelInfo={<FieldRequiredHint />}
intent={inputIntent({ error, touched })}
helperText={<ErrorMessage name={'customer_id'} />}
>
<CustomerSelectField
contacts={customers}
selectedContactId={value}
defaultSelectText={<T id={'select_customer_account'} />}
onContactSelected={(customer) => {
form.setFieldValue('customer_id', customer.id);
form.setFieldValue('currency_code', customer?.currency_code);
}}
popoverFill={true}
allowCreate={true}
/>
{value && (
<CustomerButtonLink customerId={value}>
<T id={'view_customer_details'} />
</CustomerButtonLink>
)}
</FormGroup>
)}
</FastField>
{/* ----------- Exchange rate ----------- */} {/* ----------- Exchange rate ----------- */}
<CreditNoteExchangeRateInputField <CreditNoteExchangeRateInputField
@@ -125,6 +87,48 @@ export default function CreditNoteFormHeaderFields({}) {
); );
} }
/**
* Customer select field of credit note form.
* @returns {React.ReactNode}
*/
function CreditNoteCustomersSelect() {
// Credit note form context.
const { customers } = useCreditNoteFormContext();
const { setFieldValue, values } = useFormikContext();
return (
<FFormGroup
name={'customer_id'}
label={<T id={'customer_name'} />}
labelInfo={<FieldRequiredHint />}
inline={true}
fastField={true}
shouldUpdate={customerNameFieldShouldUpdate}
shouldUpdateDeps={{ items: customers }}
>
<CustomersSelect
name={'customer_id'}
items={customers}
placeholder={<T id={'select_customer_account'} />}
onItemChange={(customer) => {
setFieldValue('customer_id', customer.id);
setFieldValue('currency_code', customer?.currency_code);
}}
popoverFill={true}
allowCreate={true}
fastField={true}
shouldUpdate={customerNameFieldShouldUpdate}
shouldUpdateDeps={{ items: customers }}
/>
{values.customer_id && (
<CustomerButtonLink customerId={values.customer_id}>
<T id={'view_customer_details'} />
</CustomerButtonLink>
)}
</FFormGroup>
);
}
const CustomerButtonLink = styled(CustomerDrawerLink)` const CustomerButtonLink = styled(CustomerDrawerLink)`
font-size: 11px; font-size: 11px;
margin-top: 6px; margin-top: 6px;

View File

@@ -1,11 +1,10 @@
// @ts-nocheck // @ts-nocheck
import React from 'react'; import React from 'react';
import intl from 'react-intl-universal';
import { import {
Alignment, Alignment,
NavbarGroup, NavbarGroup,
NavbarDivider, NavbarDivider,
Button,
Classes, Classes,
} from '@blueprintjs/core'; } from '@blueprintjs/core';
import { import {
@@ -15,12 +14,13 @@ import {
import { Features } from '@/constants'; import { Features } from '@/constants';
import { useFeatureCan } from '@/hooks/state'; import { useFeatureCan } from '@/hooks/state';
import { import {
Icon,
BranchSelect, BranchSelect,
FeatureCan, FeatureCan,
WarehouseSelect, WarehouseSelect,
FormTopbar, FormTopbar,
DetailsBarSkeletonBase, DetailsBarSkeletonBase,
FormWarehouseSelectButton,
FormBranchSelectButton,
} from '@/components'; } from '@/components';
import { useCreditNoteFormContext } from './CreditNoteFormProvider'; import { useCreditNoteFormContext } from './CreditNoteFormProvider';
@@ -70,8 +70,9 @@ function CreditNoteFormSelectBranch() {
<BranchSelect <BranchSelect
name={'branch_id'} name={'branch_id'}
branches={branches} branches={branches}
input={CreditNoteBranchSelectButton} input={FormBranchSelectButton}
popoverProps={{ minimal: true }} popoverProps={{ minimal: true }}
fill={false}
/> />
); );
} }
@@ -86,30 +87,9 @@ function CreditFormSelectWarehouse() {
<WarehouseSelect <WarehouseSelect
name={'warehouse_id'} name={'warehouse_id'}
warehouses={warehouses} warehouses={warehouses}
input={CreditNoteWarehouseSelectButton} input={FormWarehouseSelectButton}
popoverProps={{ minimal: true }} popoverProps={{ minimal: true }}
/> fill={false}
);
}
function CreditNoteWarehouseSelectButton({ label }) {
return (
<Button
text={intl.get('credit_note.warehouse_button.label', { label })}
minimal={true}
small={true}
icon={<Icon icon={'warehouse-16'} iconSize={16} />}
/>
);
}
function CreditNoteBranchSelectButton({ label }) {
return (
<Button
text={intl.get('credit_note.branch_button.label', { label })}
minimal={true}
small={true}
icon={<Icon icon={'branch-16'} iconSize={16} />}
/> />
); );
} }

View File

@@ -116,7 +116,7 @@ export const transformFormValuesToRequest = (values) => {
*/ */
export const customerNameFieldShouldUpdate = (newProps, oldProps) => { export const customerNameFieldShouldUpdate = (newProps, oldProps) => {
return ( return (
newProps.customers !== oldProps.customers || newProps.shouldUpdateDeps.items !== oldProps.shouldUpdateDeps.items ||
defaultFastFieldShouldUpdate(newProps, oldProps) defaultFastFieldShouldUpdate(newProps, oldProps)
); );
}; };

View File

@@ -4,16 +4,16 @@ import styled from 'styled-components';
import classNames from 'classnames'; import classNames from 'classnames';
import { FormGroup, InputGroup, Position, Classes } from '@blueprintjs/core'; import { FormGroup, InputGroup, Position, Classes } from '@blueprintjs/core';
import { DateInput } from '@blueprintjs/datetime'; import { DateInput } from '@blueprintjs/datetime';
import { FastField, ErrorMessage } from 'formik'; import { FastField, ErrorMessage, useFormikContext } from 'formik';
import { import {
FeatureCan, FeatureCan,
FFormGroup, FFormGroup,
FormattedMessage as T, FormattedMessage as T,
CustomerSelectField,
FieldRequiredHint, FieldRequiredHint,
Icon, Icon,
CustomerDrawerLink, CustomerDrawerLink,
CustomersSelect,
} from '@/components'; } from '@/components';
import { import {
momentFormatter, momentFormatter,
@@ -42,41 +42,7 @@ export default function EstimateFormHeader() {
return ( return (
<div className={classNames(CLASSES.PAGE_FORM_HEADER_FIELDS)}> <div className={classNames(CLASSES.PAGE_FORM_HEADER_FIELDS)}>
{/* ----------- Customer name ----------- */} {/* ----------- Customer name ----------- */}
<FastField <EstimateFormCustomerSelect />
name={'customer_id'}
customers={customers}
shouldUpdate={customersFieldShouldUpdate}
>
{({ form, field: { value }, meta: { error, touched } }) => (
<FormGroup
label={<T id={'customer_name'} />}
inline={true}
className={classNames(CLASSES.FILL, 'form-group--customer')}
labelInfo={<FieldRequiredHint />}
intent={inputIntent({ error, touched })}
helperText={<ErrorMessage name={'customer_id'} />}
>
<CustomerSelectField
contacts={customers}
selectedContactId={value}
defaultSelectText={<T id={'select_customer_account'} />}
onContactSelected={(customer) => {
form.setFieldValue('customer_id', customer.id);
form.setFieldValue('currency_code', customer?.currency_code);
}}
popoverFill={true}
intent={inputIntent({ error, touched })}
allowCreate={true}
/>
{value && (
<CustomerButtonLink customerId={value}>
<T id={'view_customer_details'} />
</CustomerButtonLink>
)}
</FormGroup>
)}
</FastField>
{/* ----------- Exchange Rate ----------- */} {/* ----------- Exchange Rate ----------- */}
<EstimateExchangeRateInputField <EstimateExchangeRateInputField
@@ -177,6 +143,47 @@ export default function EstimateFormHeader() {
); );
} }
/**
* Customer select field of estimate form.
* @returns {React.ReactNode}
*/
function EstimateFormCustomerSelect() {
const { setFieldValue, values } = useFormikContext();
const { customers } = useEstimateFormContext();
return (
<FFormGroup
label={<T id={'customer_name'} />}
inline={true}
labelInfo={<FieldRequiredHint />}
name={'customer_id'}
fastField={true}
shouldUpdate={customersFieldShouldUpdate}
shouldUpdateDeps={{ items: customers }}
>
<CustomersSelect
name={'customer_id'}
items={customers}
placeholder={<T id={'select_customer_account'} />}
onItemChange={(customer) => {
setFieldValue('customer_id', customer.id);
setFieldValue('currency_code', customer?.currency_code);
}}
popoverFill={true}
allowCreate={true}
fastField={true}
shouldUpdate={customersFieldShouldUpdate}
shouldUpdateDeps={{ items: customers }}
/>
{values.customer_id && (
<CustomerButtonLink customerId={values.customer_id}>
<T id={'view_customer_details'} />
</CustomerButtonLink>
)}
</FFormGroup>
);
}
const CustomerButtonLink = styled(CustomerDrawerLink)` const CustomerButtonLink = styled(CustomerDrawerLink)`
font-size: 11px; font-size: 11px;
margin-top: 6px; margin-top: 6px;

View File

@@ -1,11 +1,9 @@
// @ts-nocheck // @ts-nocheck
import React from 'react'; import React from 'react';
import intl from 'react-intl-universal';
import { import {
Alignment, Alignment,
NavbarGroup, NavbarGroup,
NavbarDivider, NavbarDivider,
Button,
Classes, Classes,
} from '@blueprintjs/core'; } from '@blueprintjs/core';
import { import {
@@ -15,12 +13,13 @@ import {
import { Features } from '@/constants'; import { Features } from '@/constants';
import { useFeatureCan } from '@/hooks/state'; import { useFeatureCan } from '@/hooks/state';
import { import {
Icon,
BranchSelect, BranchSelect,
FeatureCan, FeatureCan,
WarehouseSelect, WarehouseSelect,
FormTopbar, FormTopbar,
DetailsBarSkeletonBase, DetailsBarSkeletonBase,
FormWarehouseSelectButton,
FormBranchSelectButton,
} from '@/components'; } from '@/components';
import { useEstimateFormContext } from './EstimateFormProvider'; import { useEstimateFormContext } from './EstimateFormProvider';
@@ -70,8 +69,9 @@ function EstimateFormSelectBranch() {
<BranchSelect <BranchSelect
name={'branch_id'} name={'branch_id'}
branches={branches} branches={branches}
input={EstimateBranchSelectButton} input={FormBranchSelectButton}
popoverProps={{ minimal: true }} popoverProps={{ minimal: true }}
fill={false}
/> />
); );
} }
@@ -86,30 +86,9 @@ function EstimateFormSelectWarehouse() {
<WarehouseSelect <WarehouseSelect
name={'warehouse_id'} name={'warehouse_id'}
warehouses={warehouses} warehouses={warehouses}
input={EstimateWarehouseSelectButton} input={FormWarehouseSelectButton}
popoverProps={{ minimal: true }} popoverProps={{ minimal: true }}
/> fill={false}
);
}
function EstimateWarehouseSelectButton({ label }) {
return (
<Button
text={intl.get('estimate.warehouse_button.label', { label })}
minimal={true}
small={true}
icon={<Icon icon={'warehouse-16'} iconSize={16} />}
/>
);
}
function EstimateBranchSelectButton({ label }) {
return (
<Button
text={intl.get('estimate.branch_button.label', { label })}
minimal={true}
small={true}
icon={<Icon icon={'branch-16'} iconSize={16} />}
/> />
); );
} }

View File

@@ -80,7 +80,7 @@ export const transformToEditForm = (estimate) => {
*/ */
export const customersFieldShouldUpdate = (newProps, oldProps) => { export const customersFieldShouldUpdate = (newProps, oldProps) => {
return ( return (
newProps.customers !== oldProps.customers || newProps.shouldUpdateDeps.items !== oldProps.shouldUpdateDeps.items ||
defaultFastFieldShouldUpdate(newProps, oldProps) defaultFastFieldShouldUpdate(newProps, oldProps)
); );
}; };

View File

@@ -12,9 +12,9 @@ import {
Col, Col,
Row, Row,
CustomerDrawerLink, CustomerDrawerLink,
CustomerSelectField,
FieldRequiredHint, FieldRequiredHint,
FeatureCan, FeatureCan,
CustomersSelect,
} from '@/components'; } from '@/components';
import { import {
momentFormatter, momentFormatter,
@@ -42,49 +42,13 @@ import { Features } from '@/constants';
*/ */
export default function InvoiceFormHeaderFields() { export default function InvoiceFormHeaderFields() {
// Invoice form context. // Invoice form context.
const { customers, projects } = useInvoiceFormContext(); const { projects } = useInvoiceFormContext();
const { values } = useFormikContext(); const { values } = useFormikContext();
return ( return (
<div className={classNames(CLASSES.PAGE_FORM_HEADER_FIELDS)}> <div className={classNames(CLASSES.PAGE_FORM_HEADER_FIELDS)}>
{/* ----------- Customer name ----------- */} {/* ----------- Customer name ----------- */}
<FastField <InvoiceFormCustomerSelect />
name={'customer_id'}
customers={customers}
shouldUpdate={customerNameFieldShouldUpdate}
>
{({ form, field: { value }, meta: { error, touched } }) => (
<FFormGroup
name={'customer_id'}
label={<T id={'customer_name'} />}
inline={true}
className={classNames(
'form-group--customer-name',
'form-group--select-list',
CLASSES.FILL,
)}
labelInfo={<FieldRequiredHint />}
>
<CustomerSelectField
contacts={customers}
selectedContactId={value}
defaultSelectText={<T id={'select_customer_account'} />}
onContactSelected={(customer) => {
form.setFieldValue('customer_id', customer.id);
form.setFieldValue('currency_code', customer?.currency_code);
}}
popoverFill={true}
allowCreate={true}
/>
{value && (
<CustomerButtonLink customerId={value}>
<T id={'view_customer_details'} />
</CustomerButtonLink>
)}
</FFormGroup>
)}
</FastField>
{/* ----------- Exchange rate ----------- */} {/* ----------- Exchange rate ----------- */}
<InvoiceExchangeRateInputField <InvoiceExchangeRateInputField
@@ -192,6 +156,46 @@ export default function InvoiceFormHeaderFields() {
); );
} }
/**
* Customer select field of the invoice form.
* @returns {React.ReactNode}
*/
function InvoiceFormCustomerSelect() {
const { customers } = useInvoiceFormContext();
const { values, setFieldValue } = useFormikContext();
return (
<FFormGroup
name={'customer_id'}
label={<T id={'customer_name'} />}
inline={true}
labelInfo={<FieldRequiredHint />}
fastField={true}
shouldUpdate={customerNameFieldShouldUpdate}
shouldUpdateDeps={{ items: customers }}
>
<CustomersSelect
name={'customer_id'}
items={customers}
placeholder={<T id={'select_customer_account'} />}
onItemChange={(customer) => {
setFieldValue('customer_id', customer.id);
setFieldValue('currency_code', customer?.currency_code);
}}
allowCreate={true}
fastField={true}
shouldUpdate={customerNameFieldShouldUpdate}
shouldUpdateDeps={{ items: customers }}
/>
{values.customer_id && (
<CustomerButtonLink customerId={values.customer_id}>
<T id={'view_customer_details'} />
</CustomerButtonLink>
)}
</FFormGroup>
);
}
const CustomerButtonLink = styled(CustomerDrawerLink)` const CustomerButtonLink = styled(CustomerDrawerLink)`
font-size: 11px; font-size: 11px;
margin-top: 6px; margin-top: 6px;

View File

@@ -1,12 +1,10 @@
// @ts-nocheck // @ts-nocheck
import React from 'react'; import React from 'react';
import intl from 'react-intl-universal';
import styled from 'styled-components'; import styled from 'styled-components';
import { import {
Alignment, Alignment,
NavbarGroup, NavbarGroup,
NavbarDivider, NavbarDivider,
Button,
Classes, Classes,
} from '@blueprintjs/core'; } from '@blueprintjs/core';
import { import {
@@ -18,11 +16,12 @@ import { Features } from '@/constants';
import { useInvoiceFormContext } from './InvoiceFormProvider'; import { useInvoiceFormContext } from './InvoiceFormProvider';
import { useFeatureCan } from '@/hooks/state'; import { useFeatureCan } from '@/hooks/state';
import { import {
Icon,
BranchSelect, BranchSelect,
FeatureCan, FeatureCan,
WarehouseSelect, WarehouseSelect,
FormTopbar, FormTopbar,
FormWarehouseSelectButton,
FormBranchSelectButton,
} from '@/components'; } from '@/components';
/** /**
@@ -70,8 +69,9 @@ function InvoiceFormSelectBranch() {
<BranchSelect <BranchSelect
name={'branch_id'} name={'branch_id'}
branches={branches} branches={branches}
input={InvoiceBranchSelectButton} input={FormBranchSelectButton}
popoverProps={{ minimal: true }} popoverProps={{ minimal: true }}
fill={false}
/> />
); );
} }
@@ -86,30 +86,9 @@ function InvoiceFormSelectWarehouse() {
<WarehouseSelect <WarehouseSelect
name={'warehouse_id'} name={'warehouse_id'}
warehouses={warehouses} warehouses={warehouses}
input={InvoiceWarehouseSelectButton} input={FormWarehouseSelectButton}
popoverProps={{ minimal: true }} popoverProps={{ minimal: true }}
/> fill={false}
);
}
function InvoiceWarehouseSelectButton({ label }) {
return (
<Button
text={intl.get('invoice.warehouse_button.label', { label })}
minimal={true}
small={true}
icon={<Icon icon={'warehouse-16'} iconSize={16} />}
/>
);
}
function InvoiceBranchSelectButton({ label }) {
return (
<Button
text={intl.get('invoice.branch_button.label', { label })}
minimal={true}
small={true}
icon={<Icon icon={'branch-16'} iconSize={16} />}
/> />
); );
} }

View File

@@ -114,7 +114,7 @@ export const transformErrors = (errors, { setErrors }) => {
*/ */
export const customerNameFieldShouldUpdate = (newProps, oldProps) => { export const customerNameFieldShouldUpdate = (newProps, oldProps) => {
return ( return (
newProps.customers !== oldProps.customers || newProps.shouldUpdateDeps.items !== oldProps.shouldUpdateDeps.items||
defaultFastFieldShouldUpdate(newProps, oldProps) defaultFastFieldShouldUpdate(newProps, oldProps)
); );
}; };

View File

@@ -7,25 +7,18 @@ import { FFormGroup, FEditableText, FormattedMessage as T } from '@/components';
export function PaymentReceiveFormFootetLeft() { export function PaymentReceiveFormFootetLeft() {
return ( return (
<React.Fragment> <React.Fragment>
{/* --------- Statement--------- */}
<PaymentMsgFormGroup
name={'message'}
label={<T id={'payment_receive_form.message.label'} />}
>
<FEditableText
name={'message'}
placeholder={intl.get('payment_receive_form.message.placeholder')}
/>
</PaymentMsgFormGroup>
{/* --------- Internal Note--------- */} {/* --------- Internal Note--------- */}
<TermsConditsFormGroup <TermsConditsFormGroup
name={'internal_note'} name={'statement'}
label={<T id={'payment_receive_form.label.note'} />} label={<T id={'payment_receive_form.label.note'} />}
fastField={true}
> >
<FEditableText <FEditableText
name={'internal_note'} name={'statement'}
placeholder={intl.get('payment_receive_form.internal_note.placeholder')} placeholder={intl.get(
'payment_receive_form.internal_note.placeholder',
)}
fastField={true}
/> />
</TermsConditsFormGroup> </TermsConditsFormGroup>
</React.Fragment> </React.Fragment>
@@ -43,17 +36,3 @@ const TermsConditsFormGroup = styled(FFormGroup)`
} }
} }
`; `;
const PaymentMsgFormGroup = styled(FFormGroup)`
&.bp3-form-group {
margin-bottom: 40px;
.bp3-label {
font-size: 12px;
margin-bottom: 12px;
}
.bp3-form-content {
margin-left: 10px;
}
}
`;

View File

@@ -1,22 +1,21 @@
// @ts-nocheck // @ts-nocheck
import React from 'react'; import React from 'react';
import intl from 'react-intl-universal'; import { Alignment, NavbarGroup, Classes } from '@blueprintjs/core';
import { Alignment, NavbarGroup, Button, Classes } from '@blueprintjs/core';
import { useSetPrimaryBranchToForm } from './utils'; import { useSetPrimaryBranchToForm } from './utils';
import { useFeatureCan } from '@/hooks/state'; import { useFeatureCan } from '@/hooks/state';
import { import {
Icon,
BranchSelect, BranchSelect,
FeatureCan, FeatureCan,
FormTopbar, FormTopbar,
DetailsBarSkeletonBase, DetailsBarSkeletonBase,
FormBranchSelectButton,
} from '@/components'; } from '@/components';
import { usePaymentReceiveFormContext } from './PaymentReceiveFormProvider'; import { usePaymentReceiveFormContext } from './PaymentReceiveFormProvider';
import { Features } from '@/constants'; import { Features } from '@/constants';
/** /**
* Payment receive from top bar. * Payment receive from top bar.
* @returns * @returns {JSX.Element}
*/ */
export default function PaymentReceiveFormTopBar() { export default function PaymentReceiveFormTopBar() {
// Features guard. // Features guard.
@@ -29,7 +28,6 @@ export default function PaymentReceiveFormTopBar() {
if (!featureCan(Features.Branches)) { if (!featureCan(Features.Branches)) {
return null; return null;
} }
return ( return (
<FormTopbar> <FormTopbar>
<NavbarGroup align={Alignment.LEFT}> <NavbarGroup align={Alignment.LEFT}>
@@ -41,6 +39,10 @@ export default function PaymentReceiveFormTopBar() {
); );
} }
/**
* Branch select of payment receive form.
* @returns {JSX.Element}
*/
function PaymentReceiveFormSelectBranch() { function PaymentReceiveFormSelectBranch() {
// payment receive form context. // payment receive form context.
const { branches, isBranchesLoading } = usePaymentReceiveFormContext(); const { branches, isBranchesLoading } = usePaymentReceiveFormContext();
@@ -51,19 +53,9 @@ function PaymentReceiveFormSelectBranch() {
<BranchSelect <BranchSelect
name={'branch_id'} name={'branch_id'}
branches={branches} branches={branches}
input={PaymentReceiveBranchSelectButton} input={FormBranchSelectButton}
popoverProps={{ minimal: true }} popoverProps={{ minimal: true }}
/> fill={false}
);
}
function PaymentReceiveBranchSelectButton({ label }) {
return (
<Button
text={intl.get('payment_receive.branch_button.label', { label })}
minimal={true}
small={true}
icon={<Icon icon={'branch-16'} iconSize={16} />}
/> />
); );
} }

View File

@@ -14,8 +14,11 @@ import { DateInput } from '@blueprintjs/datetime';
import { toSafeInteger } from 'lodash'; import { toSafeInteger } from 'lodash';
import { FastField, Field, useFormikContext, ErrorMessage } from 'formik'; import { FastField, Field, useFormikContext, ErrorMessage } from 'formik';
import { FeatureCan, FormattedMessage as T } from '@/components'; import {
import { useAutofocus } from '@/hooks'; FeatureCan,
CustomersSelect,
FormattedMessage as T,
} from '@/components';
import { CLASSES } from '@/constants/classes'; import { CLASSES } from '@/constants/classes';
import { import {
safeSumBy, safeSumBy,
@@ -27,7 +30,6 @@ import {
import { import {
FFormGroup, FFormGroup,
AccountsSelect, AccountsSelect,
CustomerSelectField,
FieldRequiredHint, FieldRequiredHint,
Icon, Icon,
MoneyInputGroup, MoneyInputGroup,
@@ -58,8 +60,7 @@ import { PaymentReceivePaymentNoField } from './PaymentReceivePaymentNoField';
*/ */
export default function PaymentReceiveHeaderFields() { export default function PaymentReceiveHeaderFields() {
// Payment receive form context. // Payment receive form context.
const { customers, accounts, projects, isNewMode } = const { accounts, projects } = usePaymentReceiveFormContext();
usePaymentReceiveFormContext();
// Formik form context. // Formik form context.
const { const {
@@ -67,8 +68,6 @@ export default function PaymentReceiveHeaderFields() {
setFieldValue, setFieldValue,
} = useFormikContext(); } = useFormikContext();
const customerFieldRef = useAutofocus();
// Calculates the full-amount received. // Calculates the full-amount received.
const totalDueAmount = useMemo( const totalDueAmount = useMemo(
() => safeSumBy(entries, 'due_amount'), () => safeSumBy(entries, 'due_amount'),
@@ -91,45 +90,7 @@ export default function PaymentReceiveHeaderFields() {
return ( return (
<div className={classNames(CLASSES.PAGE_FORM_HEADER_FIELDS)}> <div className={classNames(CLASSES.PAGE_FORM_HEADER_FIELDS)}>
{/* ------------- Customer name ------------- */} {/* ------------- Customer name ------------- */}
<FastField <PaymentReceiveCustomerSelect />
name={'customer_id'}
customers={customers}
shouldUpdate={customersFieldShouldUpdate}
>
{({ form, field: { value }, meta: { error, touched } }) => (
<FormGroup
label={<T id={'customer_name'} />}
inline={true}
className={classNames('form-group--select-list', CLASSES.FILL)}
labelInfo={<FieldRequiredHint />}
intent={inputIntent({ error, touched })}
helperText={<ErrorMessage name={'customer_id'} />}
>
<CustomerSelectField
contacts={customers}
selectedContactId={value}
defaultSelectText={<T id={'select_customer_account'} />}
onContactSelected={(customer) => {
form.setFieldValue('customer_id', customer.id);
form.setFieldValue('full_amount', '');
form.setFieldValue('currency_code', customer?.currency_code);
}}
popoverFill={true}
disabled={!isNewMode}
buttonProps={{
elementRef: (ref) => (customerFieldRef.current = ref),
}}
allowCreate={true}
/>
{value && (
<CustomerButtonLink customerId={value}>
<T id={'view_customer_details'} />
</CustomerButtonLink>
)}
</FormGroup>
)}
</FastField>
{/* ----------- Exchange rate ----------- */} {/* ----------- Exchange rate ----------- */}
<PaymentReceiveExchangeRateInputField <PaymentReceiveExchangeRateInputField
@@ -276,3 +237,49 @@ const CustomerButtonLink = styled(CustomerDrawerLink)`
font-size: 11px; font-size: 11px;
margin-top: 6px; margin-top: 6px;
`; `;
/**
* Customer select field of payment receive form.
* @returns {React.ReactNode}
*/
function PaymentReceiveCustomerSelect() {
// Payment receive form context.
const { customers, isNewMode } = usePaymentReceiveFormContext();
// Formik form context.
const { values, setFieldValue } = useFormikContext();
return (
<FFormGroup
label={<T id={'customer_name'} />}
inline={true}
labelInfo={<FieldRequiredHint />}
name={'customer_id'}
fastField={true}
shouldUpdate={customersFieldShouldUpdate}
shouldUpdateDeps={{ items: customers }}
>
<CustomersSelect
name={'customer_id'}
items={customers}
placeholder={<T id={'select_customer_account'} />}
onItemChange={(customer) => {
setFieldValue('customer_id', customer.id);
setFieldValue('full_amount', '');
setFieldValue('currency_code', customer?.currency_code);
}}
popoverFill={true}
disabled={!isNewMode}
allowCreate={true}
fastField={true}
shouldUpdate={customersFieldShouldUpdate}
shouldUpdateDeps={{ items: customers }}
/>
{values.customer_id && (
<CustomerButtonLink customerId={values.customer_id}>
<T id={'view_customer_details'} />
</CustomerButtonLink>
)}
</FFormGroup>
);
}

View File

@@ -129,7 +129,7 @@ export const fullAmountPaymentEntries = (entries) => {
*/ */
export const customersFieldShouldUpdate = (newProps, oldProps) => { export const customersFieldShouldUpdate = (newProps, oldProps) => {
return ( return (
newProps.customers !== oldProps.customers || newProps.shouldUpdateDeps.items !== oldProps.shouldUpdateDeps.items ||
defaultFastFieldShouldUpdate(newProps, oldProps) defaultFastFieldShouldUpdate(newProps, oldProps)
); );
}; };

View File

@@ -4,7 +4,7 @@ import styled from 'styled-components';
import classNames from 'classnames'; import classNames from 'classnames';
import { FormGroup, InputGroup, Position, Classes } from '@blueprintjs/core'; import { FormGroup, InputGroup, Position, Classes } from '@blueprintjs/core';
import { DateInput } from '@blueprintjs/datetime'; import { DateInput } from '@blueprintjs/datetime';
import { FastField, ErrorMessage } from 'formik'; import { FastField, ErrorMessage, useFormikContext } from 'formik';
import { CLASSES } from '@/constants/classes'; import { CLASSES } from '@/constants/classes';
import { ACCOUNT_TYPE } from '@/constants/accountTypes'; import { ACCOUNT_TYPE } from '@/constants/accountTypes';
@@ -12,7 +12,7 @@ import { Features } from '@/constants';
import { import {
FFormGroup, FFormGroup,
AccountsSelect, AccountsSelect,
CustomerSelectField, CustomersSelect,
FieldRequiredHint, FieldRequiredHint,
Icon, Icon,
CustomerDrawerLink, CustomerDrawerLink,
@@ -38,44 +38,12 @@ import { ReceiptFormReceiptNumberField } from './ReceiptFormReceiptNumberField';
* Receipt form header fields. * Receipt form header fields.
*/ */
export default function ReceiptFormHeader() { export default function ReceiptFormHeader() {
const { accounts, customers, projects } = useReceiptFormContext(); const { accounts, projects } = useReceiptFormContext();
return ( return (
<div className={classNames(CLASSES.PAGE_FORM_HEADER_FIELDS)}> <div className={classNames(CLASSES.PAGE_FORM_HEADER_FIELDS)}>
{/* ----------- Customer name ----------- */} {/* ----------- Customer name ----------- */}
<FastField <ReceiptFormCustomerSelect />
name={'customer_id'}
customers={customers}
shouldUpdate={customersFieldShouldUpdate}
>
{({ form, field: { value }, meta: { error, touched } }) => (
<FormGroup
label={<T id={'customer_name'} />}
inline={true}
className={classNames(CLASSES.FILL, 'form-group--customer')}
labelInfo={<FieldRequiredHint />}
intent={inputIntent({ error, touched })}
helperText={<ErrorMessage name={'customer_id'} />}
>
<CustomerSelectField
contacts={customers}
selectedContactId={value}
defaultSelectText={<T id={'select_customer_account'} />}
onContactSelected={(customer) => {
form.setFieldValue('customer_id', customer.id);
form.setFieldValue('currency_code', customer?.currency_code);
}}
popoverFill={true}
allowCreate={true}
/>
{value && (
<CustomerButtonLink customerId={value}>
<T id={'view_customer_details'} />
</CustomerButtonLink>
)}
</FormGroup>
)}
</FastField>
{/* ----------- Exchange rate ----------- */} {/* ----------- Exchange rate ----------- */}
<ReceiptExchangeRateInputField <ReceiptExchangeRateInputField
@@ -172,6 +140,47 @@ export default function ReceiptFormHeader() {
); );
} }
/**
* Customer select field of receipt form.
* @returns {React.ReactNode}
*/
function ReceiptFormCustomerSelect() {
const { setFieldValue, values } = useFormikContext();
const { customers } = useReceiptFormContext();
return (
<FFormGroup
name={'customer_id'}
label={<T id={'customer_name'} />}
labelInfo={<FieldRequiredHint />}
inline={true}
fastField={true}
shouldUpdate={customersFieldShouldUpdate}
shouldUpdateDeps={{ items: customers }}
>
<CustomersSelect
name={'customer_id'}
items={customers}
placeholder={<T id={'select_customer_account'} />}
onItemChange={(customer) => {
setFieldValue('customer_id', customer.id);
setFieldValue('currency_code', customer?.currency_code);
}}
popoverFill={true}
allowCreate={true}
fastField={true}
shouldUpdate={customersFieldShouldUpdate}
shouldUpdateDeps={{ items: customers }}
/>
{values.customer_id && (
<CustomerButtonLink customerId={values.customer_id}>
<T id={'view_customer_details'} />
</CustomerButtonLink>
)}
</FFormGroup>
);
}
const CustomerButtonLink = styled(CustomerDrawerLink)` const CustomerButtonLink = styled(CustomerDrawerLink)`
font-size: 11px; font-size: 11px;
margin-top: 6px; margin-top: 6px;

View File

@@ -1,12 +1,9 @@
// @ts-nocheck // @ts-nocheck
import React from 'react'; import React from 'react';
import intl from 'react-intl-universal';
import styled from 'styled-components';
import { import {
Alignment, Alignment,
NavbarGroup, NavbarGroup,
NavbarDivider, NavbarDivider,
Button,
Classes, Classes,
} from '@blueprintjs/core'; } from '@blueprintjs/core';
import { import {
@@ -18,12 +15,13 @@ import { Features } from '@/constants';
import { useFeatureCan } from '@/hooks/state'; import { useFeatureCan } from '@/hooks/state';
import { useReceiptFormContext } from './ReceiptFormProvider'; import { useReceiptFormContext } from './ReceiptFormProvider';
import { import {
Icon,
BranchSelect, BranchSelect,
FeatureCan, FeatureCan,
WarehouseSelect, WarehouseSelect,
FormTopbar, FormTopbar,
DetailsBarSkeletonBase, DetailsBarSkeletonBase,
FormBranchSelectButton,
FormWarehouseSelectButton,
} from '@/components'; } from '@/components';
/** /**
@@ -76,8 +74,9 @@ function ReceiptFormSelectBranch() {
<BranchSelect <BranchSelect
name={'branch_id'} name={'branch_id'}
branches={branches} branches={branches}
input={ReceiptBranchSelectButton} input={FormBranchSelectButton}
popoverProps={{ minimal: true }} popoverProps={{ minimal: true }}
fill={false}
/> />
); );
} }
@@ -96,30 +95,9 @@ function ReceiptFormSelectWarehouse() {
<WarehouseSelect <WarehouseSelect
name={'warehouse_id'} name={'warehouse_id'}
warehouses={warehouses} warehouses={warehouses}
input={ReceiptWarehouseSelectButton} input={FormWarehouseSelectButton}
popoverProps={{ minimal: true }} popoverProps={{ minimal: true }}
/> fill={false}
);
}
function ReceiptBranchSelectButton({ label }) {
return (
<Button
text={intl.get('receipt.branch_button.label', { label })}
minimal={true}
small={true}
icon={<Icon icon={'branch-16'} iconSize={16} />}
/>
);
}
function ReceiptWarehouseSelectButton({ label }) {
return (
<Button
text={intl.get('receipt.warehouse_button.label', { label })}
minimal={true}
small={true}
icon={<Icon icon={'warehouse-16'} iconSize={16} />}
/> />
); );
} }

View File

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

View File

@@ -9,7 +9,6 @@ import {
InputPrependText, InputPrependText,
CurrencySelectList, CurrencySelectList,
BranchSelect, BranchSelect,
BranchSelectButton,
FeatureCan, FeatureCan,
Row, Row,
Col, Col,
@@ -75,12 +74,10 @@ export default function VendorFinanicalPanelTab() {
label={<T id={'vendor.label.opening_branch'} />} label={<T id={'vendor.label.opening_branch'} />}
name={'opening_balance_branch_id'} name={'opening_balance_branch_id'}
inline={true} inline={true}
className={classNames('form-group--select-list', Classes.FILL)}
> >
<BranchSelect <BranchSelect
name={'opening_balance_branch_id'} name={'opening_balance_branch_id'}
branches={branches} branches={branches}
input={BranchSelectButton}
popoverProps={{ minimal: true }} popoverProps={{ minimal: true }}
/> />
</FFormGroup> </FFormGroup>

View File

@@ -379,7 +379,7 @@
"the_expenses_have_been_deleted_successfully": "The expenses have been deleted successfully", "the_expenses_have_been_deleted_successfully": "The expenses have been deleted successfully",
"once_delete_these_expenses_you_will_not_able_restore_them": "Once you delete these expenses, you won't be able to retrieve them later. Are you sure you want to delete them?", "once_delete_these_expenses_you_will_not_able_restore_them": "Once you delete these expenses, you won't be able to retrieve them later. Are you sure you want to delete them?",
"the_expense_has_been_published": "The expense has been published", "the_expense_has_been_published": "The expense has been published",
"select_customer": "Select customer", "select_customer": "Select Customer...",
"total_amount_equals_zero": "Total amount equals zero", "total_amount_equals_zero": "Total amount equals zero",
"value": "Value", "value": "Value",
"you_reached_conditions_limit": "You have reached to conditions limit.", "you_reached_conditions_limit": "You have reached to conditions limit.",
@@ -480,7 +480,7 @@
"estimate_date": "Estimate Date", "estimate_date": "Estimate Date",
"expiration_date": "Expiration Date", "expiration_date": "Expiration Date",
"customer_note": "Customer Note", "customer_note": "Customer Note",
"select_customer_account": "Select Customer Account", "select_customer_account": "Select Customer Account...",
"select_product": "Select Product", "select_product": "Select Product",
"reference": "Reference #", "reference": "Reference #",
"clear": "Clear", "clear": "Clear",
@@ -1452,6 +1452,7 @@
"cash_flow.setting_your_auto_generated_transaction_number": "Setting your auto-generated transaction number", "cash_flow.setting_your_auto_generated_transaction_number": "Setting your auto-generated transaction number",
"cash_flow_drawer.label_transaction_type": "Transaction type", "cash_flow_drawer.label_transaction_type": "Transaction type",
"cash_flow.drawer.label_transaction_no": "Transaction number", "cash_flow.drawer.label_transaction_no": "Transaction number",
"cash_flow.drawer.label.statement": "Statement",
"cash_flow.drawer.label_transaction": "Cash flow Transaction {number}", "cash_flow.drawer.label_transaction": "Cash flow Transaction {number}",
"cash_flow.account_transactions.no_results": "There are no deposit/withdrawal transactions on the current account.", "cash_flow.account_transactions.no_results": "There are no deposit/withdrawal transactions on the current account.",
"cash_flow_balance_in": "Balance in {name}", "cash_flow_balance_in": "Balance in {name}",
@@ -1937,8 +1938,8 @@
"warehouse.alert.mark_primary_message": "The given warehouse has been marked as primary.", "warehouse.alert.mark_primary_message": "The given warehouse has been marked as primary.",
"warehouse.alert.are_you_sure_you_want_to_make": "Are you sure you want to make a primary warehouse?", "warehouse.alert.are_you_sure_you_want_to_make": "Are you sure you want to make a primary warehouse?",
"make_primary": "Make as Primary", "make_primary": "Make as Primary",
"invoice.branch_button.label": "Branch: {label}", "page_form.branch_button.label": "Branch: {text}",
"invoice.warehouse_button.label": "Warehouse: {label}", "page_form.warehouse_button.label": "Warehouse: {text}",
"branches_multi_select.label": "Branches", "branches_multi_select.label": "Branches",
"branches_multi_select.placeholder": "Filter by branches…", "branches_multi_select.placeholder": "Filter by branches…",
"warehouses_multi_select.label": "Warehouses", "warehouses_multi_select.label": "Warehouses",
@@ -2023,20 +2024,6 @@
"make_journal.label.total": "TOTAL", "make_journal.label.total": "TOTAL",
"expense.label.subtotal": "Subtotal", "expense.label.subtotal": "Subtotal",
"expense.label.total": "TOTAL", "expense.label.total": "TOTAL",
"expense.branch_button.label": "Branch: {label}",
"make_journal.branch_button.label": "Branch: {label}",
"bill.branch_button.label": "Branch: {label}",
"bill.warehouse_button.label": "Warehouse: {label}",
"vendor_credit.branch_button.label": "Branch: {label}",
"vendor_credit.warehouse_button.label": "Warehouse: {label}",
"payment_receive.branch_button.label": "Branch: {label}",
"payment_made.branch_button.label": "Branch: {label}",
"credit_note.branch_button.label": "Branch: {label}",
"credit_note.warehouse_button.label": "Warehouse: {label}",
"estimate.branch_button.label": "Branch: {label}",
"estimate.warehouse_button.label": "Warehouse: {label}",
"receipt.branch_button.label": "Branch: {label}",
"receipt.warehouse_button.label": "Warehouse: {label}",
"warehouse_transfer.empty_status.title": "Manage transfer orders between warehouses.", "warehouse_transfer.empty_status.title": "Manage transfer orders between warehouses.",
"warehouse_transfer.empty_status.description": "Business with multiply warehouses often transfers items from on warehouse to another when they are in immediate need of vendors.", "warehouse_transfer.empty_status.description": "Business with multiply warehouses often transfers items from on warehouse to another when they are in immediate need of vendors.",
"warehouse_transfer.form.reason.label": "Reason", "warehouse_transfer.form.reason.label": "Reason",

View File

@@ -1,34 +1,14 @@
.dialog--money-in, .dialog--money-in,
.dialog--money-out { .dialog--money-out {
.bp3-form-group {
margin-bottom: 15px;
label.bp3-label {
font-size: 13px;
margin-bottom: 3px;
}
}
.form-group {
&--description {
.bp3-form-content {
textarea {
width: 100%;
min-width: 100%;
font-size: 14px;
}
}
}
&--reference-no,
&--amount,
&--credit_account_id {
max-width: 380px;
}
}
.trasnaction-type-fileds { .trasnaction-type-fileds {
margin-bottom: 18px; margin-bottom: 18px;
padding: 16px 0px 12px 0px; padding: 0 0px 16px 0px;
border-bottom: 2px solid #e9e9e9; border-bottom: 2px solid #e9e9e9;
.bp3-form-group{
margin-bottom: 0;
}
} }
.bp3-dialog-footer { .bp3-dialog-footer {