fix: accounts suggest field

This commit is contained in:
Ahmed Bouhuolia
2025-12-21 16:03:15 +02:00
parent b22328cff9
commit 31f5cbf335
22 changed files with 1189 additions and 2224 deletions

View File

@@ -8,7 +8,7 @@
"@bigcapital/utils": "*",
"@blueprintjs-formik/core": "^0.3.7",
"@blueprintjs-formik/datetime": "^0.4.0",
"@blueprintjs-formik/select": "^0.3.5",
"@blueprintjs-formik/select": "^0.4.5",
"@blueprintjs/colors": "4.1.19",
"@blueprintjs/core": "^4.20.2",
"@blueprintjs/datetime": "^4.4.37",

View File

@@ -96,7 +96,7 @@ export function AccountsMultiSelect({
};
return (
<FMultiSelect<AccountSelect>
<FMultiSelect
{...rest}
items={filteredAccounts}
valueAccessor={'id'}

View File

@@ -1,23 +1,34 @@
// @ts-nocheck
import React, { useCallback, useMemo } from 'react';
import * as R from 'ramda';
import React, { useCallback, ComponentType } from 'react';
import intl from 'react-intl-universal';
import classNames from 'classnames';
import { MenuItem } from '@blueprintjs/core';
import { CLASSES } from '@/constants/classes';
import { ItemRenderer, ItemPredicate } from '@blueprintjs/select';
import { DialogsName } from '@/constants/dialogs';
import {
FSuggest,
MenuItemNestedText,
FormattedMessage as T,
} from '@/components';
import { nestedArrayToflatten, filterAccountsByQuery } from '@/utils';
import { FSuggest, Suggest, FormattedMessage as T } from '@/components';
import withDialogActions from '@/containers/Dialog/withDialogActions';
import { usePreprocessingAccounts } from './_hooks';
// Account interface
interface Account {
id: number;
name: string;
code: string;
account_level?: number;
account_type?: string;
account_parent_type?: string;
account_root_type?: string;
account_normal?: string;
}
// Types for renderers and predicates
type AccountItemRenderer = ItemRenderer<Account>;
type AccountItemPredicate = ItemPredicate<Account>;
// Create new account renderer.
const createNewItemRenderer = (query, active, handleClick) => {
const createNewItemRenderer = (
query: string,
active: boolean,
handleClick: (event: React.MouseEvent<HTMLElement>) => void,
): React.ReactElement => {
return (
<MenuItem
icon="add"
@@ -29,12 +40,17 @@ const createNewItemRenderer = (query, active, handleClick) => {
};
// Create new item from the given query string.
const createNewItemFromQuery = (name) => {
const createNewItemFromQuery = (name: string): Partial<Account> => {
return { name };
};
// Filters accounts items.
const filterAccountsPredicater = (query, account, _index, exactMatch) => {
const filterAccountsPredicater: AccountItemPredicate = (
query: string,
account: Account,
_index?: number,
exactMatch?: boolean,
): boolean => {
const normalizedTitle = account.name.toLowerCase();
const normalizedQuery = query.toLowerCase();
@@ -45,78 +61,139 @@ const filterAccountsPredicater = (query, account, _index, exactMatch) => {
}
};
/**
* Accounts suggest field.
*/
function AccountsSuggestFieldRoot({
// #withDialogActions
openDialog,
// #ownProps
accounts,
defaultSelectText = intl.formatMessage({ id: 'select_account' }),
filterByParentTypes = [],
filterByTypes = [],
filterByNormal,
filterByRootTypes = [],
allowCreate,
...suggestProps
}) {
const flattenAccounts = useMemo(
() => nestedArrayToflatten(accounts),
[accounts],
);
const filteredAccounts = useMemo(
() =>
filterAccountsByQuery(flattenAccounts, {
filterByParentTypes,
filterByTypes,
filterByNormal,
filterByRootTypes,
}),
[
flattenAccounts,
filterByParentTypes,
filterByTypes,
filterByNormal,
filterByRootTypes,
],
);
const handleCreateItemSelect = useCallback(
(item) => {
if (!item.id) {
openDialog(DialogsName.AccountForm);
}
},
[openDialog],
);
// Maybe inject new item props to select component.
const maybeCreateNewItemRenderer = allowCreate ? createNewItemRenderer : null;
const maybeCreateNewItemFromQuery = allowCreate
? createNewItemFromQuery
: null;
// Account item renderer for Suggest (non-Formik)
const accountItemRenderer: AccountItemRenderer = (
item: Account,
{ handleClick, modifiers },
): React.ReactElement | null => {
if (!modifiers.matchesPredicate) {
return null;
}
return (
<FSuggest
items={filteredAccounts}
itemPredicate={filterAccountsPredicater}
onCreateItemSelect={handleCreateItemSelect}
valueAccessor="id"
textAccessor="name"
labelAccessor="code"
inputProps={{ placeholder: defaultSelectText }}
resetOnClose
popoverProps={{ minimal: true, boundary: 'window' }}
createNewItemRenderer={maybeCreateNewItemRenderer}
createNewItemFromQuery={maybeCreateNewItemFromQuery}
{...suggestProps}
<MenuItem
active={modifiers.active}
disabled={modifiers.disabled}
label={item.code}
key={item.id}
text={item.name}
onClick={handleClick}
/>
);
};
// Input value renderer for Suggest (non-Formik)
const inputValueRenderer = (item: Account | null): string => {
if (item) {
return item.name || '';
}
return '';
};
// Props specific to the HOC (excluding component's own props)
interface AccountsSuggestFieldOwnProps {
// #withDialogActions
openDialog: (name: string, payload?: any) => void;
// #ownProps
items: Account[];
defaultSelectText?: string;
filterByParentTypes?: string[];
filterByTypes?: string[];
filterByNormal?: string;
filterByRootTypes?: string[];
allowCreate?: boolean;
}
export const AccountsSuggestField = R.compose(withDialogActions)(
AccountsSuggestFieldRoot,
// Props that the HOC provides to the wrapped component (should be omitted from external props)
type ProvidedSuggestProps =
| 'items'
| 'itemPredicate'
| 'onCreateItemSelect'
| 'valueAccessor'
| 'textAccessor'
| 'labelAccessor'
| 'resetOnClose'
| 'createNewItemRenderer'
| 'createNewItemFromQuery';
// Utility type to extract props from a component
type ComponentProps<C> = C extends ComponentType<infer P> ? P : never;
/**
* HOC for Accounts Suggest Field logic.
* Returns a component that accepts the wrapped component's props minus the ones provided by the HOC.
*/
function withAccountsSuggestFieldLogic<C extends ComponentType<any>>(
Component: C,
): ComponentType<
AccountsSuggestFieldOwnProps & Omit<ComponentProps<C>, ProvidedSuggestProps>
> {
return function AccountsSuggestFieldLogic({
// #withDialogActions
openDialog,
// #ownProps
items,
defaultSelectText = intl.formatMessage({ id: 'select_account' }),
filterByParentTypes = [],
filterByTypes = [],
filterByNormal,
filterByRootTypes = [],
allowCreate,
// SuggestProps - props that will be passed to Suggest/FSuggest
...suggestProps
}: AccountsSuggestFieldOwnProps &
Omit<ComponentProps<C>, ProvidedSuggestProps>) {
const filteredAccounts = usePreprocessingAccounts(items, {
filterByParentTypes,
filterByTypes,
filterByNormal: filterByNormal ? [filterByNormal] : [],
filterByRootTypes,
});
const handleCreateItemSelect = useCallback(
(item: Account | Partial<Account>) => {
if (!('id' in item) || !item.id) {
openDialog(DialogsName.AccountForm);
}
},
[openDialog],
);
// Maybe inject new item props to select component.
const maybeCreateNewItemRenderer = allowCreate
? createNewItemRenderer
: undefined;
const maybeCreateNewItemFromQuery = allowCreate
? createNewItemFromQuery
: undefined;
// Build the SuggestProps to pass to the component
const processedSuggestProps = {
items: filteredAccounts,
itemPredicate: filterAccountsPredicater,
onCreateItemSelect: handleCreateItemSelect,
valueAccessor: 'id' as const,
textAccessor: 'name' as const,
labelAccessor: 'code' as const,
inputProps: { placeholder: defaultSelectText },
resetOnClose: true,
popoverProps: { minimal: true, boundary: 'window' as const },
createNewItemRenderer: maybeCreateNewItemRenderer,
createNewItemFromQuery: maybeCreateNewItemFromQuery,
...suggestProps,
} as ComponentProps<C>;
return <Component {...processedSuggestProps} />;
};
}
const AccountsSuggestFieldWithLogic = withAccountsSuggestFieldLogic(Suggest);
const FAccountsSuggestFieldWithLogic = withAccountsSuggestFieldLogic(FSuggest);
export const AccountsSuggestField = withDialogActions(
AccountsSuggestFieldWithLogic,
);
export const FAccountsSuggestField = withDialogActions(
FAccountsSuggestFieldWithLogic,
);

View File

@@ -58,9 +58,9 @@ export default function AccountCellRenderer({
{...formGroupProps}
>
<AccountsSuggestField
accounts={accounts}
onAccountSelected={handleAccountSelected}
selectedAccountId={initialValue}
items={accounts}
onItemSelect={handleAccountSelected}
selectedValue={initialValue}
filterByRootTypes={filterAccountsByRootTypes}
filterByTypes={filterAccountsByTypes}
inputProps={{

View File

@@ -10,7 +10,16 @@ import {
TextArea,
HTMLSelect,
} from '@blueprintjs-formik/core';
import { MultiSelect, SuggestField } from '@blueprintjs-formik/select';
import {
MultiSelect,
Suggest,
Select,
FormikMultiSelect,
FormikSuggest,
withFormikMultiSelect,
withFormikSuggest,
withFormikSelect,
} from '@blueprintjs-formik/select';
import { DateInput, TimezoneSelect } from '@blueprintjs-formik/datetime';
import { FSelect } from './Select';
@@ -22,11 +31,17 @@ export {
RadioGroup as FRadioGroup,
Switch as FSwitch,
FSelect,
MultiSelect as FMultiSelect,
FormikMultiSelect as FMultiSelect,
EditableText as FEditableText,
SuggestField as FSuggest,
FormikSuggest as FSuggest,
TextArea as FTextArea,
DateInput as FDateInput,
HTMLSelect as FHTMLSelect,
TimezoneSelect as FTimezoneSelect,
Suggest,
MultiSelect,
Select,
withFormikSelect,
withFormikMultiSelect,
withFormikSuggest,
};

View File

@@ -1,7 +1,7 @@
// @ts-nocheck
import React from 'react';
import { Button } from '@blueprintjs/core';
import { Select } from '@blueprintjs-formik/select';
import { FormikSelect } from '@blueprintjs-formik/select';
import styled from 'styled-components';
import clsx from 'classnames';
@@ -14,7 +14,7 @@ export function FSelect({ ...props }) {
className={clsx({ 'is-selected': !!text }, props.className)}
/>
);
return <Select input={input} fill={true} {...props} />;
return <FormikSelect input={input} fill={true} {...props} />;
}
export const SelectButton = styled(Button)`

View File

@@ -11,7 +11,7 @@ import {
import classNames from 'classnames';
import {
FormattedMessage as T,
AccountsSuggestField,
FAccountsSuggestField,
InputPrependText,
MoneyInputGroup,
FieldRequiredHint,
@@ -57,7 +57,7 @@ export default function OtherIncomeFormFields() {
<FeatureCan feature={Features.Branches}>
<Row>
<Col xs={5}>
<FFormGroup name={'amount'} label={<T id={'branch'} />}>
<FFormGroup name={'branch_id'} label={<T id={'branch'} />}>
<BranchSelect
name={'branch_id'}
branches={branches}
@@ -75,13 +75,11 @@ export default function OtherIncomeFormFields() {
{/*------------ Date -----------*/}
<FastField name={'date'}>
{({ form, field: { value }, meta: { error, touched } }) => (
<FormGroup
<FFormGroup
name={'date'}
label={<T id={'date'} />}
labelInfo={<FieldRequiredHint />}
intent={inputIntent({ error, touched })}
helperText={<ErrorMessage name="date" />}
minimal={true}
className={classNames(CLASSES.FILL, 'form-group--date')}
fill
>
<DateInput
{...momentFormatter('YYYY/MM/DD')}
@@ -95,7 +93,7 @@ export default function OtherIncomeFormFields() {
}}
intent={inputIntent({ error, touched })}
/>
</FormGroup>
</FFormGroup>
)}
</FastField>
</Col>
@@ -128,31 +126,20 @@ export default function OtherIncomeFormFields() {
<Row>
<Col xs={5}>
{/*------------ other income account -----------*/}
<FastField name={'credit_account_id'}>
{({ form, field, meta: { error, touched } }) => (
<FormGroup
label={<T id={'cash_flow_transaction.other_income_account'} />}
labelInfo={<FieldRequiredHint />}
intent={inputIntent({ error, touched })}
helperText={<ErrorMessage name="credit_account_id" />}
className={'form-group--credit_account_id'}
>
<AccountsSuggestField
accounts={accounts}
onAccountSelected={({ id }) =>
form.setFieldValue('credit_account_id', id)
}
filterByTypes={[
ACCOUNT_TYPE.INCOME,
ACCOUNT_TYPE.OTHER_INCOME,
]}
inputProps={{
intent: inputIntent({ error, touched }),
}}
/>
</FormGroup>
)}
</FastField>
<FFormGroup
name={'credit_account_id'}
label={<T id={'cash_flow_transaction.other_income_account'} />}
labelInfo={<FieldRequiredHint />}
>
<FAccountsSuggestField
name={'credit_account_id'}
items={accounts}
filterByTypes={[
ACCOUNT_TYPE.INCOME,
ACCOUNT_TYPE.OTHER_INCOME,
]}
/>
</FFormGroup>
</Col>
<Col xs={5}>

View File

@@ -1,12 +1,12 @@
// @ts-nocheck
import React from 'react';
import { FastField, ErrorMessage } from 'formik';
import { FormGroup, Position, ControlGroup } from '@blueprintjs/core';
import { Position, ControlGroup } from '@blueprintjs/core';
import classNames from 'classnames';
import { DateInput } from '@blueprintjs/datetime';
import {
FormattedMessage as T,
AccountsSuggestField,
FAccountsSuggestField,
InputPrependText,
FieldRequiredHint,
Col,
@@ -14,6 +14,7 @@ import {
BranchSelect,
BranchSelectButton,
FeatureCan,
FFormGroup,
FMoneyInputGroup,
FTextArea,
@@ -70,13 +71,11 @@ export default function OwnerContributionFormFields() {
{/*------------ Date -----------*/}
<FastField name={'date'}>
{({ form, field: { value }, meta: { error, touched } }) => (
<FormGroup
<FFormGroup
name={'date'}
label={<T id={'date'} />}
labelInfo={<FieldRequiredHint />}
intent={inputIntent({ error, touched })}
helperText={<ErrorMessage name="date" />}
minimal={true}
className={classNames(CLASSES.FILL, 'form-group--date')}
fill
>
<DateInput
{...momentFormatter('YYYY/MM/DD')}
@@ -90,7 +89,7 @@ export default function OwnerContributionFormFields() {
}}
intent={inputIntent({ error, touched })}
/>
</FormGroup>
</FFormGroup>
)}
</FastField>
</Col>
@@ -122,29 +121,17 @@ export default function OwnerContributionFormFields() {
<Row>
<Col xs={5}>
{/*------------ equity account -----------*/}
<FastField name={'credit_account_id'}>
{({ form, field, meta: { error, touched } }) => (
<FormGroup
label={<T id={'cash_flow_transaction.label_equity_account'} />}
labelInfo={<FieldRequiredHint />}
intent={inputIntent({ error, touched })}
helperText={<ErrorMessage name="credit_account_id" />}
className={'form-group--credit_account_id'}
>
<AccountsSuggestField
accounts={accounts}
onAccountSelected={(account) => {
form.setFieldValue('credit_account_id', account.id);
form.setFieldValue('currency_code', account.currency_code);
}}
filterByTypes={ACCOUNT_TYPE.EQUITY}
inputProps={{
intent: inputIntent({ error, touched }),
}}
/>
</FormGroup>
)}
</FastField>
<FFormGroup
name={'credit_account_id'}
label={<T id={'cash_flow_transaction.label_equity_account'} />}
labelInfo={<FieldRequiredHint />}
>
<FAccountsSuggestField
name={'credit_account_id'}
items={accounts}
filterByTypes={ACCOUNT_TYPE.EQUITY}
/>
</FFormGroup>
</Col>
<Col xs={5}>

View File

@@ -1,19 +1,15 @@
// @ts-nocheck
import React, { useMemo } from 'react';
import { FastField, Field, ErrorMessage } from 'formik';
import { FormGroup } from '@blueprintjs/core';
import classNames from 'classnames';
import {
FormattedMessage as T,
AccountsSuggestField,
FAccountsSuggestField,
FieldRequiredHint,
ListSelect,
Col,
Row,
FFormGroup,
FSelect,
} from '@/components';
import { inputIntent } from '@/utils';
import { CLASSES, getAddMoneyInOptions } from '@/constants';
import { useMoneyInDailogContext } from './MoneyInDialogProvider';
@@ -50,32 +46,20 @@ export default function TransactionTypeFields() {
<Col xs={5}>
{/*------------ Current account -----------*/}
<FastField name={'cashflow_account_id'}>
{({ form, field: { value }, meta: { error, touched } }) => (
<FormGroup
label={<T id={'cash_flow_transaction.label_current_account'} />}
labelInfo={<FieldRequiredHint />}
intent={inputIntent({ error, touched })}
helperText={<ErrorMessage name="cashflow_account_id" />}
minimal={true}
className={classNames(
CLASSES.FILL,
'form-group--cashflow_account_id',
)}
>
<AccountsSuggestField
accounts={cashflowAccounts}
onAccountSelected={({ id }) => {
form.setFieldValue('cashflow_account_id', id);
setAccountId(id);
}}
inputProps={{
intent: inputIntent({ error, touched }),
}}
/>
</FormGroup>
)}
</FastField>
<FFormGroup
name={'cashflow_account_id'}
label={<T id={'cash_flow_transaction.label_current_account'} />}
labelInfo={<FieldRequiredHint />}
fill
>
<FAccountsSuggestField
name={'cashflow_account_id'}
items={cashflowAccounts}
onItemSelect={({ id }) => {
setAccountId(id);
}}
/>
</FFormGroup>
</Col>
</Row>
</div>

View File

@@ -6,7 +6,7 @@ import { FormGroup, Position, ControlGroup } from '@blueprintjs/core';
import classNames from 'classnames';
import {
FormattedMessage as T,
AccountsSuggestField,
FAccountsSuggestField,
InputPrependText,
FieldRequiredHint,
Col,
@@ -15,7 +15,6 @@ import {
BranchSelect,
BranchSelectButton,
FMoneyInputGroup,
FInputGroup,
FFormGroup,
FTextArea,
} from '@/components';
@@ -63,18 +62,17 @@ export default function TransferFromAccountFormFields() {
</Row>
<BranchRowDivider />
</FeatureCan>
<Row>
<Col xs={5}>
{/*------------ Date -----------*/}
<FastField name={'date'}>
{({ form, field: { value }, meta: { error, touched } }) => (
<FormGroup
<FFormGroup
name={'date'}
label={<T id={'date'} />}
labelInfo={<FieldRequiredHint />}
intent={inputIntent({ error, touched })}
helperText={<ErrorMessage name="date" />}
minimal={true}
className={classNames(CLASSES.FILL, 'form-group--date')}
fill
>
<DateInput
{...momentFormatter('YYYY/MM/DD')}
@@ -88,7 +86,7 @@ export default function TransferFromAccountFormFields() {
}}
intent={inputIntent({ error, touched })}
/>
</FormGroup>
</FFormGroup>
)}
</FastField>
</Col>
@@ -118,34 +116,23 @@ export default function TransferFromAccountFormFields() {
<Row>
<Col xs={5}>
{/*------------ Transfer from account -----------*/}
<FastField name={'credit_account_id'}>
{({ form, field, meta: { error, touched } }) => (
<FormGroup
label={
<T id={'cash_flow_transaction.label_transfer_from_account'} />
}
labelInfo={<FieldRequiredHint />}
intent={inputIntent({ error, touched })}
helperText={<ErrorMessage name="credit_account_id" />}
className={'form-group--credit_account_id'}
>
<AccountsSuggestField
accounts={accounts}
onAccountSelected={({ id }) =>
form.setFieldValue('credit_account_id', id)
}
filterByTypes={[
ACCOUNT_TYPE.CASH,
ACCOUNT_TYPE.BANK,
ACCOUNT_TYPE.CREDIT_CARD,
]}
inputProps={{
intent: inputIntent({ error, touched }),
}}
/>
</FormGroup>
)}
</FastField>
<FFormGroup
name={'credit_account_id'}
label={
<T id={'cash_flow_transaction.label_transfer_from_account'} />
}
labelInfo={<FieldRequiredHint />}
>
<FAccountsSuggestField
name={'credit_account_id'}
items={accounts as any[]}
filterByTypes={[
ACCOUNT_TYPE.CASH,
ACCOUNT_TYPE.BANK,
ACCOUNT_TYPE.CREDIT_CARD,
]}
/>
</FFormGroup>
</Col>
<Col xs={5}>

View File

@@ -5,7 +5,7 @@ import { FormGroup, Position, ControlGroup } from '@blueprintjs/core';
import classNames from 'classnames';
import {
FormattedMessage as T,
AccountsSuggestField,
FAccountsSuggestField,
InputPrependText,
FieldRequiredHint,
Col,
@@ -67,13 +67,11 @@ export default function OtherExpnseFormFields() {
{/*------------ Date -----------*/}
<FastField name={'date'}>
{({ form, field: { value }, meta: { error, touched } }) => (
<FormGroup
<FFormGroup
name={'date'}
label={<T id={'date'} />}
labelInfo={<FieldRequiredHint />}
intent={inputIntent({ error, touched })}
helperText={<ErrorMessage name="date" />}
minimal={true}
className={classNames(CLASSES.FILL, 'form-group--date')}
fill
>
<DateInput
{...momentFormatter('YYYY/MM/DD')}
@@ -87,7 +85,7 @@ export default function OtherExpnseFormFields() {
}}
intent={inputIntent({ error, touched })}
/>
</FormGroup>
</FFormGroup>
)}
</FastField>
</Col>
@@ -120,31 +118,17 @@ export default function OtherExpnseFormFields() {
<Row>
<Col xs={5}>
{/*------------ other expense account -----------*/}
<FastField name={'credit_account_id'}>
{({ form, field, meta: { error, touched } }) => (
<FormGroup
label={<T id={'cash_flow_transaction.label_expense_account'} />}
labelInfo={<FieldRequiredHint />}
intent={inputIntent({ error, touched })}
helperText={<ErrorMessage name="credit_account_id" />}
className={'form-group--credit_account_id'}
>
<AccountsSuggestField
accounts={accounts}
onAccountSelected={({ id }) =>
form.setFieldValue('credit_account_id', id)
}
filterByTypes={[
ACCOUNT_TYPE.EXPENSE,
ACCOUNT_TYPE.OTHER_EXPENSE,
]}
inputProps={{
intent: inputIntent({ error, touched }),
}}
/>
</FormGroup>
)}
</FastField>
<FFormGroup
name={'credit_account_id'}
label={<T id={'cash_flow_transaction.label_expense_account'} />}
labelInfo={<FieldRequiredHint />}
>
<FAccountsSuggestField
name={'credit_account_id'}
items={accounts}
filterByTypes={[ACCOUNT_TYPE.EXPENSE, ACCOUNT_TYPE.OTHER_EXPENSE]}
/>
</FFormGroup>
</Col>
<Col xs={5}>

View File

@@ -6,7 +6,7 @@ import { FormGroup, Position, ControlGroup } from '@blueprintjs/core';
import classNames from 'classnames';
import {
FormattedMessage as T,
AccountsSuggestField,
FAccountsSuggestField,
InputPrependText,
FieldRequiredHint,
Col,
@@ -69,13 +69,11 @@ export default function OwnerDrawingsFormFields() {
{/*------------ Date -----------*/}
<FastField name={'date'}>
{({ form, field: { value }, meta: { error, touched } }) => (
<FormGroup
<FFormGroup
name={'date'}
label={<T id={'date'} />}
labelInfo={<FieldRequiredHint />}
intent={inputIntent({ error, touched })}
helperText={<ErrorMessage name="date" />}
minimal={true}
className={classNames(CLASSES.FILL, 'form-group--date')}
fill
>
<DateInput
{...momentFormatter('YYYY/MM/DD')}
@@ -89,7 +87,7 @@ export default function OwnerDrawingsFormFields() {
}}
intent={inputIntent({ error, touched })}
/>
</FormGroup>
</FFormGroup>
)}
</FastField>
</Col>
@@ -100,7 +98,6 @@ export default function OwnerDrawingsFormFields() {
</Row>
{/*------------ Amount -----------*/}
<Row>
<Col xs={10}>
<FormGroup
@@ -122,28 +119,17 @@ export default function OwnerDrawingsFormFields() {
<Row>
<Col xs={5}>
{/*------------ equitty account -----------*/}
<FastField name={'credit_account_id'}>
{({ form, field, meta: { error, touched } }) => (
<FormGroup
label={<T id={'cash_flow_transaction.label_equity_account'} />}
labelInfo={<FieldRequiredHint />}
intent={inputIntent({ error, touched })}
helperText={<ErrorMessage name="credit_account_id" />}
className={'form-group--credit_account_id'}
>
<AccountsSuggestField
accounts={accounts}
onAccountSelected={({ id }) =>
form.setFieldValue('credit_account_id', id)
}
filterByTypes={ACCOUNT_TYPE.EQUITY}
inputProps={{
intent: inputIntent({ error, touched }),
}}
/>
</FormGroup>
)}
</FastField>
<FFormGroup
name={'credit_account_id'}
label={<T id={'cash_flow_transaction.label_equity_account'} />}
labelInfo={<FieldRequiredHint />}
>
<FAccountsSuggestField
name={'credit_account_id'}
items={accounts}
filterByTypes={ACCOUNT_TYPE.EQUITY}
/>
</FFormGroup>
</Col>
<Col xs={5}>

View File

@@ -1,18 +1,15 @@
// @ts-nocheck
import React, { useMemo } from 'react';
import { FastField, ErrorMessage } from 'formik';
import { FormGroup } from '@blueprintjs/core';
import classNames from 'classnames';
import {
FormattedMessage as T,
AccountsSuggestField,
FAccountsSuggestField,
FieldRequiredHint,
Col,
Row,
FSelect,
FFormGroup,
} from '@/components';
import { inputIntent } from '@/utils';
import { getAddMoneyOutOptions } from '@/constants/cashflowOptions';
import { useMoneyOutDialogContext } from './MoneyOutDialogProvider';
import { CLASSES } from '@/constants/classes';
@@ -54,32 +51,20 @@ function TransactionTypeFields() {
<Col xs={5}>
{/*------------ Current account -----------*/}
<FastField name={'cashflow_account_id'}>
{({ form, field: { value }, meta: { error, touched } }) => (
<FormGroup
label={<T id={'cash_flow_transaction.label_current_account'} />}
labelInfo={<FieldRequiredHint />}
intent={inputIntent({ error, touched })}
helperText={<ErrorMessage name="cashflow_account_id" />}
minimal={true}
className={classNames(
CLASSES.FILL,
'form-group--cashflow_account_id',
)}
>
<AccountsSuggestField
accounts={cashflowAccounts}
onAccountSelected={({ id }) => {
form.setFieldValue('cashflow_account_id', id);
setAccountId(id);
}}
inputProps={{
intent: inputIntent({ error, touched }),
}}
/>
</FormGroup>
)}
</FastField>
<FFormGroup
name={'cashflow_account_id'}
label={<T id={'cash_flow_transaction.label_current_account'} />}
labelInfo={<FieldRequiredHint />}
fill
>
<FAccountsSuggestField
name={'cashflow_account_id'}
items={cashflowAccounts}
onItemSelect={({ id }) => {
setAccountId(id);
}}
/>
</FFormGroup>
</Col>
</Row>
</div>

View File

@@ -5,7 +5,7 @@ import { FormGroup, Position, ControlGroup } from '@blueprintjs/core';
import classNames from 'classnames';
import {
FormattedMessage as T,
AccountsSuggestField,
FAccountsSuggestField,
InputPrependText,
FieldRequiredHint,
Col,
@@ -121,34 +121,23 @@ export default function TransferToAccountFormFields() {
<Row>
<Col xs={5}>
{/*------------ transfer from account -----------*/}
<FastField name={'credit_account_id'}>
{({ form, field, meta: { error, touched } }) => (
<FormGroup
label={
<T id={'cash_flow_transaction.label_transfer_to_account'} />
}
labelInfo={<FieldRequiredHint />}
intent={inputIntent({ error, touched })}
helperText={<ErrorMessage name="credit_account_id" />}
className={'form-group--credit_account_id'}
>
<AccountsSuggestField
accounts={accounts}
onAccountSelected={({ id }) =>
form.setFieldValue('credit_account_id', id)
}
filterByTypes={[
ACCOUNT_TYPE.CASH,
ACCOUNT_TYPE.BANK,
ACCOUNT_TYPE.CREDIT_CARD,
]}
inputProps={{
intent: inputIntent({ error, touched }),
}}
/>
</FormGroup>
)}
</FastField>
<FFormGroup
name={'credit_account_id'}
label={
<T id={'cash_flow_transaction.label_transfer_to_account'} />
}
labelInfo={<FieldRequiredHint />}
>
<FAccountsSuggestField
name={'credit_account_id'}
items={accounts}
filterByTypes={[
ACCOUNT_TYPE.CASH,
ACCOUNT_TYPE.BANK,
ACCOUNT_TYPE.CREDIT_CARD,
]}
/>
</FFormGroup>
</Col>
<Col xs={5}>

View File

@@ -1,16 +1,31 @@
// @ts-nocheck
import { connect } from 'react-redux';
import { Dispatch } from 'redux';
import { ComponentType } from 'react';
import t from '@/store/types';
export const mapStateToProps = (state, props) => {
return {};
};
export interface WithDialogActionsProps {
openDialog: (name: string, payload?: Record<string, unknown>) => void;
closeDialog: (name: string, payload?: Record<string, unknown>) => void;
}
export const mapDispatchToProps = (dispatch) => ({
export const mapDispatchToProps = (dispatch: Dispatch): WithDialogActionsProps => ({
openDialog: (name, payload) =>
dispatch({ type: t.OPEN_DIALOG, name, payload }),
closeDialog: (name, payload) =>
dispatch({ type: t.CLOSE_DIALOG, name, payload }),
});
export default connect(null, mapDispatchToProps);
/**
* HOC that injects dialog actions (openDialog, closeDialog) into a component.
* Properly preserves the wrapped component's prop types while omitting injected props.
*/
function withDialogActions<P>(
WrappedComponent: ComponentType<P>,
): ComponentType<Omit<P, keyof WithDialogActionsProps>> {
const Connected = connect(null, mapDispatchToProps)(
WrappedComponent as ComponentType<any>,
);
return Connected as unknown as ComponentType<Omit<P, keyof WithDialogActionsProps>>;
}
export default withDialogActions;

View File

@@ -1,7 +1,11 @@
// @ts-nocheck
import React from 'react';
import { FastField, ErrorMessage } from 'formik';
import { FormattedMessage as T } from '@/components';
import {
FMoneyInputGroup,
FTextArea,
FormattedMessage as T,
} from '@/components';
import { useAutofocus } from '@/hooks';
import {
@@ -17,7 +21,7 @@ import { CLASSES } from '@/constants/classes';
import { ACCOUNT_TYPE } from '@/constants/accountTypes';
import { inputIntent } from '@/utils';
import {
AccountsSuggestField,
FAccountsSuggestField,
InputPrependText,
MoneyInputGroup,
FieldRequiredHint,
@@ -31,7 +35,7 @@ import { useBadDebtContext } from './BadDebtFormProvider';
function BadDebtFormFields() {
const amountfieldRef = useAutofocus();
const { accounts ,invoice } = useBadDebtContext();
const { accounts, invoice } = useBadDebtContext();
return (
<div className={Classes.DIALOG_BODY}>
@@ -42,79 +46,45 @@ function BadDebtFormFields() {
</Callout>
{/*------------ Written-off amount -----------*/}
<FastField name={'amount'}>
{({
form: { values, setFieldValue },
field: { value },
meta: { error, touched },
}) => (
<FormGroup
label={<T id={'bad_debt.dialog.written_off_amount'} />}
labelInfo={<FieldRequiredHint />}
className={classNames('form-group--amount', CLASSES.FILL)}
intent={inputIntent({ error, touched })}
helperText={<ErrorMessage name="amount" />}
>
<ControlGroup>
<InputPrependText text={invoice.currency_code} />
<FFormGroup
name={'amount'}
label={<T id={'bad_debt.dialog.written_off_amount'} />}
labelInfo={<FieldRequiredHint />}
fill
>
<ControlGroup>
<InputPrependText text={invoice.currency_code} />
<FMoneyInputGroup
name={'amount'}
minimal={true}
inputRef={(ref) => (amountfieldRef.current = ref)}
/>
</ControlGroup>
</FFormGroup>
<MoneyInputGroup
value={value}
minimal={true}
onChange={(amount) => {
setFieldValue('amount', amount);
}}
intent={inputIntent({ error, touched })}
disabled={amountfieldRef}
/>
</ControlGroup>
</FormGroup>
)}
</FastField>
{/*------------ Expense account -----------*/}
<FastField name={'expense_account_id'}>
{({ form, field: { value }, meta: { error, touched } }) => (
<FormGroup
label={<T id={'expense_account_id'} />}
className={classNames(
'form-group--expense_account_id',
'form-group--select-list',
CLASSES.FILL,
)}
labelInfo={<FieldRequiredHint />}
intent={inputIntent({ error, touched })}
helperText={<ErrorMessage name={'expense_account_id'} />}
>
<AccountsSuggestField
selectedAccountId={value}
accounts={accounts}
onAccountSelected={({ id }) =>
form.setFieldValue('expense_account_id', id)
}
filterByTypes={[ACCOUNT_TYPE.EXPENSE]}
/>
</FormGroup>
)}
</FastField>
<FFormGroup
name={'expense_account_id'}
label={<T id={'expense_account_id'} />}
labelInfo={<FieldRequiredHint />}
fill
>
<FAccountsSuggestField
name={'expense_account_id'}
items={accounts}
filterByTypes={[ACCOUNT_TYPE.EXPENSE]}
/>
</FFormGroup>
{/*------------ reason -----------*/}
<FastField name={'reason'}>
{({ field, meta: { error, touched } }) => (
<FormGroup
label={<T id={'reason'} />}
labelInfo={<FieldRequiredHint />}
className={'form-group--reason'}
intent={inputIntent({ error, touched })}
helperText={<ErrorMessage name={'reason'} />}
>
<TextArea
growVertically={true}
large={true}
intent={inputIntent({ error, touched })}
{...field}
/>
</FormGroup>
)}
</FastField>
<FFormGroup
name={'reason'}
label={<T id={'reason'} />}
labelInfo={<FieldRequiredHint />}
fill
>
<FTextArea name={'reason'} growVertically={true} large={true} fill />
</FFormGroup>
</div>
);
}

View File

@@ -11,7 +11,7 @@ import {
TextArea,
Position,
} from '@blueprintjs/core';
import { FormattedMessage as T } from '@/components';
import { FFormGroup, FormattedMessage as T } from '@/components';
import { DateInput } from '@blueprintjs/datetime';
import { useAutofocus } from '@/hooks';
import {
@@ -23,7 +23,7 @@ import {
BranchSelect,
WarehouseSelect,
BranchSelectButton,
AccountsSuggestField,
FAccountsSuggestField,
} from '@/components';
import {
inputIntent,
@@ -109,13 +109,11 @@ export default function InventoryAdjustmentFormDialogFields() {
{/*------------ Date -----------*/}
<FastField name={'date'}>
{({ form, field: { value }, meta: { error, touched } }) => (
<FormGroup
<FFormGroup
name={'date'}
label={<T id={'date'} />}
labelInfo={<FieldRequiredHint />}
intent={inputIntent({ error, touched })}
helperText={<ErrorMessage name="date" />}
minimal={true}
className={classNames(CLASSES.FILL, 'form-group--date')}
fill
>
<DateInput
{...momentFormatter('YYYY/MM/DD')}
@@ -130,7 +128,7 @@ export default function InventoryAdjustmentFormDialogFields() {
intent={inputIntent({ error, touched })}
inputRef={(ref) => (dateFieldRef.current = ref)}
/>
</FormGroup>
</FFormGroup>
)}
</FastField>
</Col>
@@ -143,12 +141,11 @@ export default function InventoryAdjustmentFormDialogFields() {
field: { value },
meta: { error, touched },
}) => (
<FormGroup
<FFormGroup
name={'type'}
label={<T id={'adjustment_type'} />}
labelInfo={<FieldRequiredHint />}
helperText={<ErrorMessage name="type" />}
intent={inputIntent({ error, touched })}
className={classNames(CLASSES.FILL, 'form-group--type')}
fill
>
<ListSelect
items={adjustmentTypes}
@@ -168,7 +165,7 @@ export default function InventoryAdjustmentFormDialogFields() {
popoverProps={{ minimal: true }}
intent={inputIntent({ error, touched })}
/>
</FormGroup>
</FFormGroup>
)}
</Field>
</Col>
@@ -177,28 +174,20 @@ export default function InventoryAdjustmentFormDialogFields() {
<InventoryAdjustmentQuantityFields />
{/*------------ Adjustment account -----------*/}
<FastField name={'adjustment_account_id'}>
{({ form, field, meta: { error, touched } }) => (
<FormGroup
label={<T id={'adjustment_account'} />}
labelInfo={<FieldRequiredHint />}
intent={inputIntent({ error, touched })}
helperText={<ErrorMessage name="adjustment_account_id" />}
className={'form-group--adjustment-account'}
>
<AccountsSuggestField
accounts={accounts}
onAccountSelected={({ id }) =>
form.setFieldValue('adjustment_account_id', id)
}
inputProps={{
placeholder: intl.get('select_adjustment_account'),
intent: inputIntent({ error, touched }),
}}
/>
</FormGroup>
)}
</FastField>
<FFormGroup
name={'adjustment_account_id'}
label={<T id={'adjustment_account'} />}
labelInfo={<FieldRequiredHint />}
className={'form-group--adjustment-account'}
>
<FAccountsSuggestField
name={'adjustment_account_id'}
items={accounts}
inputProps={{
placeholder: intl.get('select_adjustment_account'),
}}
/>
</FFormGroup>
{/*------------ Reference -----------*/}
<FastField name={'reference_no'}>

View File

@@ -14,7 +14,7 @@ import {
Col,
Row,
FormattedMessage as T,
AccountsSuggestField,
FAccountsSuggestField,
InputPrependText,
MoneyInputGroup,
Icon,
@@ -137,9 +137,9 @@ function QuickPaymentMadeFormFields({
name={'payment_account_id'}
label={<T id={'payment_account'} />}
>
<AccountsSuggestField
<FAccountsSuggestField
name={'payment_account_id'}
accounts={accounts}
items={accounts}
inputProps={{
placeholder: intl.get('select_account'),
}}

View File

@@ -13,7 +13,7 @@ import {
Col,
FieldRequiredHint,
FormattedMessage as T,
AccountsSuggestField,
FAccountsSuggestField,
InputPrependText,
MoneyInputGroup,
Icon,
@@ -143,9 +143,9 @@ function QuickPaymentReceiveFormFields({
name={'deposit_account_id'}
label={<T id={'deposit_to'} />}
>
<AccountsSuggestField
<FAccountsSuggestField
name={'deposit_account_id'}
accounts={accounts}
items={accounts}
inputProps={{
placeholder: intl.get('select_account'),
}}

View File

@@ -21,7 +21,7 @@ import {
Row,
If,
FieldRequiredHint,
AccountsSuggestField,
FAccountsSuggestField,
InputPrependText,
MoneyInputGroup,
FormattedMessage as T,
@@ -29,6 +29,8 @@ import {
BranchSelect,
BranchSelectButton,
FeatureCan,
FInputGroup,
FMoneyInputGroup,
} from '@/components';
import {
inputIntent,
@@ -85,13 +87,11 @@ function RefundCreditNoteFormFields({
{/* ------------- Refund date ------------- */}
<FastField name={'date'}>
{({ form, field: { value }, meta: { error, touched } }) => (
<FormGroup
<FFormGroup
name={'date'}
label={<T id={'refund_credit_note.dialog.refund_date'} />}
labelInfo={<FieldRequiredHint />}
className={classNames('form-group--select-list', CLASSES.FILL)}
intent={inputIntent({ error, touched })}
helperText={<ErrorMessage name="date" />}
// inline={true}
fill
>
<DateInput
{...momentFormatter('YYYY/MM/DD')}
@@ -104,77 +104,53 @@ function RefundCreditNoteFormFields({
leftIcon: <Icon icon={'date-range'} />,
}}
/>
</FormGroup>
</FFormGroup>
)}
</FastField>
</Col>
<Col xs={5}>
{/* ------------ Form account ------------ */}
<FastField name={'from_account_id'}>
{({ form, field: { value }, meta: { error, touched } }) => (
<FormGroup
label={<T id={'refund_credit_note.dialog.from_account'} />}
className={classNames(
'form-group--from_account_id',
'form-group--select-list',
CLASSES.FILL,
)}
labelInfo={<FieldRequiredHint />}
intent={inputIntent({ error, touched })}
helperText={<ErrorMessage name={'from_account_id'} />}
>
<AccountsSuggestField
selectedAccountId={value}
accounts={accounts}
onAccountSelected={({ id }) =>
form.setFieldValue('from_account_id', id)
}
inputProps={{
placeholder: intl.get('select_account'),
}}
filterByTypes={[
ACCOUNT_TYPE.BANK,
ACCOUNT_TYPE.CASH,
ACCOUNT_TYPE.FIXED_ASSET,
]}
/>
</FormGroup>
)}
</FastField>
<FFormGroup
name={'from_account_id'}
label={<T id={'refund_credit_note.dialog.from_account'} />}
labelInfo={<FieldRequiredHint />}
fill
>
<FAccountsSuggestField
name={'from_account_id'}
items={accounts}
inputProps={{
placeholder: intl.get('select_account'),
}}
filterByTypes={[
ACCOUNT_TYPE.BANK,
ACCOUNT_TYPE.CASH,
ACCOUNT_TYPE.FIXED_ASSET,
]}
/>
</FFormGroup>
</Col>
</Row>
{/* ------------- Amount ------------- */}
<FastField name={'amount'}>
{({
form: { values, setFieldValue },
field: { value },
meta: { error, touched },
}) => (
<FormGroup
label={<T id={'refund_credit_note.dialog.amount'} />}
labelInfo={<FieldRequiredHint />}
className={classNames('form-group--amount', CLASSES.FILL)}
intent={inputIntent({ error, touched })}
helperText={<ErrorMessage name="amount" />}
>
<ControlGroup>
<InputPrependText text={values.currency_code} />
<MoneyInputGroup
value={value}
minimal={true}
onChange={(amount) => {
setFieldValue('amount', amount);
}}
intent={inputIntent({ error, touched })}
inputRef={(ref) => (amountFieldRef.current = ref)}
/>
</ControlGroup>
</FormGroup>
)}
</FastField>
{/* ------------- Amount ------------- */}
<FFormGroup
name={'amount'}
label={<T id={'refund_credit_note.dialog.amount'} />}
labelInfo={<FieldRequiredHint />}
fill
>
<ControlGroup>
<InputPrependText text={values.currency_code} />
<FMoneyInputGroup
name={'amount'}
minimal={true}
inputRef={(ref) => (amountFieldRef.current = ref)}
/>
</ControlGroup>
</FFormGroup>
{/*------------ exchange rate -----------*/}
<If condition={!isEqual(base_currency, values.currency_code)}>
{/*------------ exchange rate -----------*/}
<ExchangeRateMutedField
name={'exchange_rate'}
fromCurrency={base_currency}
@@ -186,22 +162,9 @@ function RefundCreditNoteFormFields({
</If>
{/* ------------ Reference No. ------------ */}
<FastField name={'reference_no'}>
{({ form, field, meta: { error, touched } }) => (
<FormGroup
label={<T id={'reference_no'} />}
className={classNames('form-group--reference', CLASSES.FILL)}
intent={inputIntent({ error, touched })}
helperText={<ErrorMessage name="reference" />}
>
<InputGroup
intent={inputIntent({ error, touched })}
minimal={true}
{...field}
/>
</FormGroup>
)}
</FastField>
<FFormGroup name={'reference_no'} label={<T id={'reference_no'} />} fill>
<FInputGroup name={'reference_no'} minimal fill />
</FFormGroup>
{/* --------- Statement --------- */}
<FastField name={'description'}>

View File

@@ -21,7 +21,7 @@ import {
Row,
If,
FieldRequiredHint,
AccountsSuggestField,
FAccountsSuggestField,
InputPrependText,
MoneyInputGroup,
FormattedMessage as T,
@@ -83,12 +83,11 @@ function RefundVendorCreditFormFields({
{/* ------------- Refund date ------------- */}
<FastField name={'refund_date'}>
{({ form, field: { value }, meta: { error, touched } }) => (
<FormGroup
<FFormGroup
name={'refund_date'}
label={<T id={'refund_vendor_credit.dialog.refund_date'} />}
labelInfo={<FieldRequiredHint />}
className={classNames('form-group--select-list', CLASSES.FILL)}
intent={inputIntent({ error, touched })}
helperText={<ErrorMessage name="refund_date" />}
fill
>
<DateInput
{...momentFormatter('YYYY/MM/DD')}
@@ -101,46 +100,32 @@ function RefundVendorCreditFormFields({
leftIcon: <Icon icon={'date-range'} />,
}}
/>
</FormGroup>
</FFormGroup>
)}
</FastField>
</Col>
<Col xs={5}>
{/* ------------ Form account ------------ */}
<FastField name={'deposit_account_id'}>
{({ form, field: { value }, meta: { error, touched } }) => (
<FormGroup
label={
<T id={'refund_vendor_credit.dialog.deposit_to_account'} />
}
className={classNames(
'form-group--deposit_account_id',
'form-group--select-list',
CLASSES.FILL,
)}
labelInfo={<FieldRequiredHint />}
intent={inputIntent({ error, touched })}
helperText={<ErrorMessage name={'deposit_account_id'} />}
>
<AccountsSuggestField
selectedAccountId={value}
accounts={accounts}
onAccountSelected={({ id }) =>
form.setFieldValue('deposit_account_id', id)
}
inputProps={{
placeholder: intl.get('select_account'),
}}
filterByTypes={[
ACCOUNT_TYPE.BANK,
ACCOUNT_TYPE.CASH,
ACCOUNT_TYPE.FIXED_ASSET,
]}
/>
</FormGroup>
)}
</FastField>
<FFormGroup
name={'deposit_account_id'}
label={<T id={'refund_vendor_credit.dialog.deposit_to_account'} />}
labelInfo={<FieldRequiredHint />}
fill
>
<FAccountsSuggestField
name={'deposit_account_id'}
items={accounts}
inputProps={{
placeholder: intl.get('select_account'),
}}
filterByTypes={[
ACCOUNT_TYPE.BANK,
ACCOUNT_TYPE.CASH,
ACCOUNT_TYPE.FIXED_ASSET,
]}
/>
</FFormGroup>
</Col>
</Row>

2330
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff