mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-16 12:50:38 +00:00
Merge branch 'develop' into e2e-onboarding
This commit is contained in:
@@ -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,
|
||||
);
|
||||
48
packages/webapp/src/components/Customers/CustomersSelect.tsx
Normal file
48
packages/webapp/src/components/Customers/CustomersSelect.tsx
Normal 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);
|
||||
@@ -1,3 +1,3 @@
|
||||
// @ts-nocheck
|
||||
export * from './CustomerSelectField';
|
||||
export * from './CustomerDrawerLink';
|
||||
export * from './CustomersSelect';
|
||||
|
||||
@@ -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,
|
||||
);
|
||||
49
packages/webapp/src/components/Vendors/VendorsSelect.tsx
Normal file
49
packages/webapp/src/components/Vendors/VendorsSelect.tsx
Normal 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);
|
||||
@@ -1,3 +1,3 @@
|
||||
// @ts-nocheck
|
||||
export * from './VendorDrawerLink'
|
||||
export * from './VendorSelectField'
|
||||
export * from './VendorsSelect';
|
||||
@@ -3,7 +3,7 @@ import React from 'react';
|
||||
import { InputGroup, FormGroup, Position, Classes } from '@blueprintjs/core';
|
||||
import { DateInput } from '@blueprintjs/datetime';
|
||||
import { FastField, ErrorMessage } from 'formik';
|
||||
import { FormattedMessage as T } from '@/components';
|
||||
import { CustomersSelect, FormattedMessage as T } from '@/components';
|
||||
import classNames from 'classnames';
|
||||
import { CLASSES } from '@/constants/classes';
|
||||
import {
|
||||
@@ -121,33 +121,39 @@ export default function ExpenseFormHeader() {
|
||||
)}
|
||||
</FastField>
|
||||
|
||||
<FastField
|
||||
name={'customer_id'}
|
||||
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>
|
||||
{/* ----------- Customer ----------- */}
|
||||
<ExpenseFormCustomerSelect />
|
||||
</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>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -104,7 +104,7 @@ export const transformToEditForm = (
|
||||
*/
|
||||
export const customersFieldShouldUpdate = (newProps, oldProps) => {
|
||||
return (
|
||||
newProps.customers !== oldProps.customers ||
|
||||
newProps.shouldUpdateDeps.items !== oldProps.shouldUpdateDeps.items ||
|
||||
defaultFastFieldShouldUpdate(newProps, oldProps)
|
||||
);
|
||||
};
|
||||
|
||||
@@ -15,11 +15,10 @@ import {
|
||||
FMoneyInputGroup,
|
||||
InputPrependText,
|
||||
FormattedMessage as T,
|
||||
FieldRequiredHint,
|
||||
CustomerSelectField,
|
||||
Stack,
|
||||
CustomersSelect,
|
||||
} from '@/components';
|
||||
import { inputIntent, momentFormatter } from '@/utils';
|
||||
import { momentFormatter } from '@/utils';
|
||||
import { useProjectFormContext } from './ProjectFormProvider';
|
||||
|
||||
/**
|
||||
@@ -27,9 +26,6 @@ import { useProjectFormContext } from './ProjectFormProvider';
|
||||
* @returns
|
||||
*/
|
||||
function ProjectFormFields() {
|
||||
// project form dialog context.
|
||||
const { customers } = useProjectFormContext();
|
||||
|
||||
// Formik context.
|
||||
const { values } = useFormikContext();
|
||||
|
||||
@@ -37,26 +33,7 @@ function ProjectFormFields() {
|
||||
<div className={Classes.DIALOG_BODY}>
|
||||
<Stack spacing={25}>
|
||||
{/*------------ Contact -----------*/}
|
||||
<FastField name={'contact_id'}>
|
||||
{({ 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>
|
||||
<ProjectFormCustomerSelect />
|
||||
|
||||
{/*------------ Project Name -----------*/}
|
||||
<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;
|
||||
|
||||
@@ -2,18 +2,18 @@
|
||||
import React from 'react';
|
||||
import styled from 'styled-components';
|
||||
import classNames from 'classnames';
|
||||
import { FastField, ErrorMessage, useFormikContext } from 'formik';
|
||||
import { FormGroup, InputGroup, Classes, Position } from '@blueprintjs/core';
|
||||
import { FastField, ErrorMessage } from 'formik';
|
||||
import { DateInput } from '@blueprintjs/datetime';
|
||||
|
||||
import { FeatureCan, FormattedMessage as T } from '@/components';
|
||||
import { CLASSES } from '@/constants/classes';
|
||||
|
||||
import {
|
||||
FFormGroup,
|
||||
VendorSelectField,
|
||||
FieldRequiredHint,
|
||||
Icon,
|
||||
VendorDrawerLink,
|
||||
VendorsSelect,
|
||||
} from '@/components';
|
||||
|
||||
import { useBillFormContext } from './BillFormProvider';
|
||||
@@ -43,43 +43,7 @@ function BillFormHeader() {
|
||||
return (
|
||||
<div className={classNames(CLASSES.PAGE_FORM_HEADER_FIELDS)}>
|
||||
{/* ------- Vendor name ------ */}
|
||||
<FastField
|
||||
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>
|
||||
<BillFormVendorField />
|
||||
|
||||
{/* ----------- Exchange rate ----------- */}
|
||||
<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);
|
||||
|
||||
const VendorButtonLink = styled(VendorDrawerLink)`
|
||||
|
||||
@@ -19,7 +19,10 @@ import {
|
||||
ensureEntriesHaveEmptyLine,
|
||||
} from '@/containers/Entries/utils';
|
||||
import { useCurrentOrganization } from '@/hooks/state';
|
||||
import { isLandedCostDisabled, getEntriesTotal } from '@/containers/Entries/utils';
|
||||
import {
|
||||
isLandedCostDisabled,
|
||||
getEntriesTotal,
|
||||
} from '@/containers/Entries/utils';
|
||||
import { useBillFormContext } from './BillFormProvider';
|
||||
|
||||
export const MIN_LINES_NUMBER = 1;
|
||||
@@ -153,7 +156,7 @@ export const handleDeleteErrors = (errors) => {
|
||||
*/
|
||||
export const vendorsFieldShouldUpdate = (newProps, oldProps) => {
|
||||
return (
|
||||
newProps.vendors !== oldProps.vendors ||
|
||||
newProps.shouldUpdateDeps.items !== oldProps.shouldUpdateDeps.items ||
|
||||
defaultFastFieldShouldUpdate(newProps, oldProps)
|
||||
);
|
||||
};
|
||||
|
||||
@@ -9,17 +9,17 @@ import {
|
||||
ControlGroup,
|
||||
} from '@blueprintjs/core';
|
||||
import { DateInput } from '@blueprintjs/datetime';
|
||||
import { FastField, ErrorMessage } from 'formik';
|
||||
import { FastField, ErrorMessage, useFormikContext } from 'formik';
|
||||
import { CLASSES } from '@/constants/classes';
|
||||
|
||||
import {
|
||||
FFormGroup,
|
||||
VendorSelectField,
|
||||
FieldRequiredHint,
|
||||
InputPrependButton,
|
||||
Icon,
|
||||
FormattedMessage as T,
|
||||
VendorDrawerLink,
|
||||
VendorsSelect,
|
||||
} from '@/components';
|
||||
import {
|
||||
vendorsFieldShouldUpdate,
|
||||
@@ -51,9 +51,6 @@ function VendorCreditNoteFormHeaderFields({
|
||||
vendorcreditNumberPrefix,
|
||||
vendorcreditNextNumber,
|
||||
}) {
|
||||
// Vendor Credit form context.
|
||||
const { vendors } = useVendorCreditNoteFormContext();
|
||||
|
||||
// Handle vendor credit number changing.
|
||||
const handleVendorCreditNumberChange = () => {
|
||||
openDialog('vendor-credit-form');
|
||||
@@ -81,39 +78,7 @@ function VendorCreditNoteFormHeaderFields({
|
||||
return (
|
||||
<div className={classNames(CLASSES.PAGE_FORM_HEADER_FIELDS)}>
|
||||
{/* ----------- Vendor name ----------- */}
|
||||
<FastField
|
||||
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>
|
||||
<VendorCreditFormVendorSelect />
|
||||
|
||||
{/* ----------- Exchange rate ----------- */}
|
||||
<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(
|
||||
withDialogActions,
|
||||
withSettings(({ vendorsCreditNoteSetting }) => ({
|
||||
|
||||
@@ -113,7 +113,7 @@ export const transformFormValuesToRequest = (values) => {
|
||||
*/
|
||||
export const vendorsFieldShouldUpdate = (newProps, oldProps) => {
|
||||
return (
|
||||
newProps.vendors !== oldProps.vendors ||
|
||||
newProps.shouldUpdateDeps.items !== oldProps.shouldUpdateDeps.items ||
|
||||
defaultFastFieldShouldUpdate(newProps, oldProps)
|
||||
);
|
||||
};
|
||||
|
||||
@@ -12,14 +12,13 @@ import {
|
||||
} from '@blueprintjs/core';
|
||||
import { DateInput } from '@blueprintjs/datetime';
|
||||
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 { CLASSES } from '@/constants/classes';
|
||||
|
||||
import {
|
||||
FFormGroup,
|
||||
AccountsSelect,
|
||||
VendorSelectField,
|
||||
FieldRequiredHint,
|
||||
InputPrependText,
|
||||
Money,
|
||||
@@ -55,8 +54,7 @@ function PaymentMadeFormHeaderFields({ organization: { base_currency } }) {
|
||||
} = useFormikContext();
|
||||
|
||||
// Payment made form context.
|
||||
const { vendors, accounts, isNewMode, setPaymentVendorId } =
|
||||
usePaymentMadeFormContext();
|
||||
const { accounts } = usePaymentMadeFormContext();
|
||||
|
||||
// Sumation of payable full-amount.
|
||||
const payableFullAmount = useMemo(
|
||||
@@ -82,41 +80,7 @@ function PaymentMadeFormHeaderFields({ organization: { base_currency } }) {
|
||||
return (
|
||||
<div className={classNames(CLASSES.PAGE_FORM_HEADER_FIELDS)}>
|
||||
{/* ------------ Vendor name ------------ */}
|
||||
<FastField
|
||||
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>
|
||||
<PaymentFormVendorSelect />
|
||||
|
||||
{/* ----------- Exchange rate ----------- */}
|
||||
<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);
|
||||
|
||||
const VendorButtonLink = styled(VendorDrawerLink)`
|
||||
|
||||
@@ -74,7 +74,7 @@ export const transformToNewPageEntries = (entries) => {
|
||||
*/
|
||||
export const vendorsFieldShouldUpdate = (newProps, oldProps) => {
|
||||
return (
|
||||
newProps.vendors !== oldProps.vendors ||
|
||||
newProps.shouldUpdateDeps.items !== oldProps.shouldUpdateDeps.items ||
|
||||
defaultFastFieldShouldUpdate(newProps, oldProps)
|
||||
);
|
||||
};
|
||||
|
||||
@@ -4,15 +4,16 @@ import classNames from 'classnames';
|
||||
import styled from 'styled-components';
|
||||
import { FormGroup, InputGroup, Position } from '@blueprintjs/core';
|
||||
import { DateInput } from '@blueprintjs/datetime';
|
||||
import { FastField, ErrorMessage } from 'formik';
|
||||
import { FastField, ErrorMessage, useFormikContext } from 'formik';
|
||||
|
||||
import { CLASSES } from '@/constants/classes';
|
||||
import {
|
||||
CustomerSelectField,
|
||||
FieldRequiredHint,
|
||||
Icon,
|
||||
FormattedMessage as T,
|
||||
CustomerDrawerLink,
|
||||
FFormGroup,
|
||||
CustomersSelect,
|
||||
} from '@/components';
|
||||
import { customerNameFieldShouldUpdate } from './utils';
|
||||
|
||||
@@ -30,49 +31,10 @@ import {
|
||||
* Credit note form header fields.
|
||||
*/
|
||||
export default function CreditNoteFormHeaderFields({}) {
|
||||
// Credit note form context.
|
||||
const { customers } = useCreditNoteFormContext();
|
||||
|
||||
return (
|
||||
<div className={classNames(CLASSES.PAGE_FORM_HEADER_FIELDS)}>
|
||||
{/* ----------- Customer name ----------- */}
|
||||
<FastField
|
||||
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>
|
||||
<CreditNoteCustomersSelect />
|
||||
|
||||
{/* ----------- Exchange rate ----------- */}
|
||||
<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)`
|
||||
font-size: 11px;
|
||||
margin-top: 6px;
|
||||
|
||||
@@ -116,7 +116,7 @@ export const transformFormValuesToRequest = (values) => {
|
||||
*/
|
||||
export const customerNameFieldShouldUpdate = (newProps, oldProps) => {
|
||||
return (
|
||||
newProps.customers !== oldProps.customers ||
|
||||
newProps.shouldUpdateDeps.items !== oldProps.shouldUpdateDeps.items ||
|
||||
defaultFastFieldShouldUpdate(newProps, oldProps)
|
||||
);
|
||||
};
|
||||
|
||||
@@ -4,16 +4,16 @@ import styled from 'styled-components';
|
||||
import classNames from 'classnames';
|
||||
import { FormGroup, InputGroup, Position, Classes } from '@blueprintjs/core';
|
||||
import { DateInput } from '@blueprintjs/datetime';
|
||||
import { FastField, ErrorMessage } from 'formik';
|
||||
import { FastField, ErrorMessage, useFormikContext } from 'formik';
|
||||
|
||||
import {
|
||||
FeatureCan,
|
||||
FFormGroup,
|
||||
FormattedMessage as T,
|
||||
CustomerSelectField,
|
||||
FieldRequiredHint,
|
||||
Icon,
|
||||
CustomerDrawerLink,
|
||||
CustomersSelect,
|
||||
} from '@/components';
|
||||
import {
|
||||
momentFormatter,
|
||||
@@ -42,41 +42,7 @@ export default function EstimateFormHeader() {
|
||||
return (
|
||||
<div className={classNames(CLASSES.PAGE_FORM_HEADER_FIELDS)}>
|
||||
{/* ----------- Customer name ----------- */}
|
||||
<FastField
|
||||
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>
|
||||
<EstimateFormCustomerSelect />
|
||||
|
||||
{/* ----------- Exchange Rate ----------- */}
|
||||
<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)`
|
||||
font-size: 11px;
|
||||
margin-top: 6px;
|
||||
|
||||
@@ -80,7 +80,7 @@ export const transformToEditForm = (estimate) => {
|
||||
*/
|
||||
export const customersFieldShouldUpdate = (newProps, oldProps) => {
|
||||
return (
|
||||
newProps.customers !== oldProps.customers ||
|
||||
newProps.shouldUpdateDeps.items !== oldProps.shouldUpdateDeps.items ||
|
||||
defaultFastFieldShouldUpdate(newProps, oldProps)
|
||||
);
|
||||
};
|
||||
|
||||
@@ -12,9 +12,9 @@ import {
|
||||
Col,
|
||||
Row,
|
||||
CustomerDrawerLink,
|
||||
CustomerSelectField,
|
||||
FieldRequiredHint,
|
||||
FeatureCan,
|
||||
CustomersSelect,
|
||||
} from '@/components';
|
||||
import {
|
||||
momentFormatter,
|
||||
@@ -42,49 +42,13 @@ import { Features } from '@/constants';
|
||||
*/
|
||||
export default function InvoiceFormHeaderFields() {
|
||||
// Invoice form context.
|
||||
const { customers, projects } = useInvoiceFormContext();
|
||||
const { projects } = useInvoiceFormContext();
|
||||
const { values } = useFormikContext();
|
||||
|
||||
return (
|
||||
<div className={classNames(CLASSES.PAGE_FORM_HEADER_FIELDS)}>
|
||||
{/* ----------- Customer name ----------- */}
|
||||
<FastField
|
||||
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>
|
||||
<InvoiceFormCustomerSelect />
|
||||
|
||||
{/* ----------- Exchange rate ----------- */}
|
||||
<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)`
|
||||
font-size: 11px;
|
||||
margin-top: 6px;
|
||||
|
||||
@@ -114,7 +114,7 @@ export const transformErrors = (errors, { setErrors }) => {
|
||||
*/
|
||||
export const customerNameFieldShouldUpdate = (newProps, oldProps) => {
|
||||
return (
|
||||
newProps.customers !== oldProps.customers ||
|
||||
newProps.shouldUpdateDeps.items !== oldProps.shouldUpdateDeps.items||
|
||||
defaultFastFieldShouldUpdate(newProps, oldProps)
|
||||
);
|
||||
};
|
||||
|
||||
@@ -14,8 +14,11 @@ import { DateInput } from '@blueprintjs/datetime';
|
||||
import { toSafeInteger } from 'lodash';
|
||||
import { FastField, Field, useFormikContext, ErrorMessage } from 'formik';
|
||||
|
||||
import { FeatureCan, FormattedMessage as T } from '@/components';
|
||||
import { useAutofocus } from '@/hooks';
|
||||
import {
|
||||
FeatureCan,
|
||||
CustomersSelect,
|
||||
FormattedMessage as T,
|
||||
} from '@/components';
|
||||
import { CLASSES } from '@/constants/classes';
|
||||
import {
|
||||
safeSumBy,
|
||||
@@ -27,7 +30,6 @@ import {
|
||||
import {
|
||||
FFormGroup,
|
||||
AccountsSelect,
|
||||
CustomerSelectField,
|
||||
FieldRequiredHint,
|
||||
Icon,
|
||||
MoneyInputGroup,
|
||||
@@ -58,8 +60,7 @@ import { PaymentReceivePaymentNoField } from './PaymentReceivePaymentNoField';
|
||||
*/
|
||||
export default function PaymentReceiveHeaderFields() {
|
||||
// Payment receive form context.
|
||||
const { customers, accounts, projects, isNewMode } =
|
||||
usePaymentReceiveFormContext();
|
||||
const { accounts, projects } = usePaymentReceiveFormContext();
|
||||
|
||||
// Formik form context.
|
||||
const {
|
||||
@@ -67,8 +68,6 @@ export default function PaymentReceiveHeaderFields() {
|
||||
setFieldValue,
|
||||
} = useFormikContext();
|
||||
|
||||
const customerFieldRef = useAutofocus();
|
||||
|
||||
// Calculates the full-amount received.
|
||||
const totalDueAmount = useMemo(
|
||||
() => safeSumBy(entries, 'due_amount'),
|
||||
@@ -91,45 +90,7 @@ export default function PaymentReceiveHeaderFields() {
|
||||
return (
|
||||
<div className={classNames(CLASSES.PAGE_FORM_HEADER_FIELDS)}>
|
||||
{/* ------------- Customer name ------------- */}
|
||||
<FastField
|
||||
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>
|
||||
<PaymentReceiveCustomerSelect />
|
||||
|
||||
{/* ----------- Exchange rate ----------- */}
|
||||
<PaymentReceiveExchangeRateInputField
|
||||
@@ -276,3 +237,49 @@ const CustomerButtonLink = styled(CustomerDrawerLink)`
|
||||
font-size: 11px;
|
||||
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>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -129,7 +129,7 @@ export const fullAmountPaymentEntries = (entries) => {
|
||||
*/
|
||||
export const customersFieldShouldUpdate = (newProps, oldProps) => {
|
||||
return (
|
||||
newProps.customers !== oldProps.customers ||
|
||||
newProps.shouldUpdateDeps.items !== oldProps.shouldUpdateDeps.items ||
|
||||
defaultFastFieldShouldUpdate(newProps, oldProps)
|
||||
);
|
||||
};
|
||||
|
||||
@@ -4,7 +4,7 @@ import styled from 'styled-components';
|
||||
import classNames from 'classnames';
|
||||
import { FormGroup, InputGroup, Position, Classes } from '@blueprintjs/core';
|
||||
import { DateInput } from '@blueprintjs/datetime';
|
||||
import { FastField, ErrorMessage } from 'formik';
|
||||
import { FastField, ErrorMessage, useFormikContext } from 'formik';
|
||||
|
||||
import { CLASSES } from '@/constants/classes';
|
||||
import { ACCOUNT_TYPE } from '@/constants/accountTypes';
|
||||
@@ -12,7 +12,7 @@ import { Features } from '@/constants';
|
||||
import {
|
||||
FFormGroup,
|
||||
AccountsSelect,
|
||||
CustomerSelectField,
|
||||
CustomersSelect,
|
||||
FieldRequiredHint,
|
||||
Icon,
|
||||
CustomerDrawerLink,
|
||||
@@ -38,44 +38,12 @@ import { ReceiptFormReceiptNumberField } from './ReceiptFormReceiptNumberField';
|
||||
* Receipt form header fields.
|
||||
*/
|
||||
export default function ReceiptFormHeader() {
|
||||
const { accounts, customers, projects } = useReceiptFormContext();
|
||||
const { accounts, projects } = useReceiptFormContext();
|
||||
|
||||
return (
|
||||
<div className={classNames(CLASSES.PAGE_FORM_HEADER_FIELDS)}>
|
||||
{/* ----------- Customer name ----------- */}
|
||||
<FastField
|
||||
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>
|
||||
<ReceiptFormCustomerSelect />
|
||||
|
||||
{/* ----------- Exchange rate ----------- */}
|
||||
<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)`
|
||||
font-size: 11px;
|
||||
margin-top: 6px;
|
||||
|
||||
@@ -104,7 +104,7 @@ export const accountsFieldShouldUpdate = (newProps, oldProps) => {
|
||||
*/
|
||||
export const customersFieldShouldUpdate = (newProps, oldProps) => {
|
||||
return (
|
||||
newProps.customers !== oldProps.customers ||
|
||||
newProps.shouldUpdateDeps.items !== oldProps.shouldUpdateDeps.items ||
|
||||
defaultFastFieldShouldUpdate(newProps, oldProps)
|
||||
);
|
||||
};
|
||||
|
||||
@@ -379,7 +379,7 @@
|
||||
"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?",
|
||||
"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",
|
||||
"value": "Value",
|
||||
"you_reached_conditions_limit": "You have reached to conditions limit.",
|
||||
@@ -480,7 +480,7 @@
|
||||
"estimate_date": "Estimate Date",
|
||||
"expiration_date": "Expiration Date",
|
||||
"customer_note": "Customer Note",
|
||||
"select_customer_account": "Select Customer Account",
|
||||
"select_customer_account": "Select Customer Account...",
|
||||
"select_product": "Select Product",
|
||||
"reference": "Reference #",
|
||||
"clear": "Clear",
|
||||
|
||||
Reference in New Issue
Block a user