mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-20 14:50:32 +00:00
feat: List select component.
This commit is contained in:
35
client/src/components/ListSelect.js
Normal file
35
client/src/components/ListSelect.js
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
import React, { useState, useEffect } from 'react';
|
||||||
|
import {
|
||||||
|
Button,
|
||||||
|
} from '@blueprintjs/core';
|
||||||
|
import { Select } from '@blueprintjs/select';
|
||||||
|
|
||||||
|
export default function ListSelect ({
|
||||||
|
buttonProps,
|
||||||
|
defaultText,
|
||||||
|
labelProp,
|
||||||
|
|
||||||
|
selectedItem,
|
||||||
|
selectedItemProp = 'id',
|
||||||
|
...selectProps
|
||||||
|
}) {
|
||||||
|
const [currentItem, setCurrentItem] = useState(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (selectedItem && selectedItemProp) {
|
||||||
|
const item = selectProps.items.find(i => i[selectedItemProp] === selectedItem);
|
||||||
|
setCurrentItem(item);
|
||||||
|
}
|
||||||
|
}, [selectedItem, selectedItemProp, selectProps.items]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Select
|
||||||
|
{...selectProps}
|
||||||
|
>
|
||||||
|
<Button
|
||||||
|
text={currentItem ? currentItem[labelProp] : defaultText}
|
||||||
|
{...buttonProps}
|
||||||
|
/>
|
||||||
|
</Select>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -3,11 +3,13 @@ import Money from './Money';
|
|||||||
import Icon from './Icon';
|
import Icon from './Icon';
|
||||||
// import Choose from './Utils/Choose';
|
// import Choose from './Utils/Choose';
|
||||||
// import For from './Utils/For';
|
// import For from './Utils/For';
|
||||||
|
import ListSelect from './ListSelect';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
If,
|
If,
|
||||||
Money,
|
Money,
|
||||||
Icon,
|
Icon,
|
||||||
|
ListSelect,
|
||||||
// Choose,
|
// Choose,
|
||||||
// For,
|
// For,
|
||||||
};
|
};
|
||||||
@@ -28,6 +28,9 @@ import Icon from 'components/Icon';
|
|||||||
import ErrorMessage from 'components/ErrorMessage';
|
import ErrorMessage from 'components/ErrorMessage';
|
||||||
import { fetchAccountTypes } from 'store/accounts/accounts.actions';
|
import { fetchAccountTypes } from 'store/accounts/accounts.actions';
|
||||||
|
|
||||||
|
|
||||||
|
import {ListSelect} from 'components';
|
||||||
|
|
||||||
function AccountFormDialog({
|
function AccountFormDialog({
|
||||||
name,
|
name,
|
||||||
payload,
|
payload,
|
||||||
@@ -229,7 +232,6 @@ function AccountFormDialog({
|
|||||||
|
|
||||||
const onChangeAccountType = useCallback(
|
const onChangeAccountType = useCallback(
|
||||||
(accountType) => {
|
(accountType) => {
|
||||||
setSelectedAccountType(accountType);
|
|
||||||
formik.setFieldValue('account_type_id', accountType.id);
|
formik.setFieldValue('account_type_id', accountType.id);
|
||||||
},
|
},
|
||||||
[setSelectedAccountType, formik]
|
[setSelectedAccountType, formik]
|
||||||
@@ -294,19 +296,20 @@ function AccountFormDialog({
|
|||||||
errors.account_type_id && touched.account_type_id && Intent.DANGER
|
errors.account_type_id && touched.account_type_id && Intent.DANGER
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<Select
|
<ListSelect
|
||||||
items={accountsTypes}
|
items={accountsTypes}
|
||||||
noResults={<MenuItem disabled={true} text='No results.' />}
|
noResults={<MenuItem disabled={true} text='No results.' />}
|
||||||
itemRenderer={accountTypeItem}
|
itemRenderer={accountTypeItem}
|
||||||
itemPredicate={filterAccountTypeItems}
|
itemPredicate={filterAccountTypeItems}
|
||||||
popoverProps={{ minimal: true }}
|
popoverProps={{ minimal: true }}
|
||||||
onItemSelect={onChangeAccountType}
|
onItemSelect={onChangeAccountType}
|
||||||
>
|
|
||||||
<Button
|
selectedItem={formik.values.account_type_id}
|
||||||
text={selectedAccountType ? selectedAccountType.name : <T id={'select_account_type'} />}
|
selectedItemProp={'id'}
|
||||||
disabled={payload.action === 'edit'}
|
|
||||||
/>
|
defaultText={<T id={'select_account_type'} />}
|
||||||
</Select>
|
labelProp={'name'}
|
||||||
|
buttonProps={{ disabled: payload.action === 'edit' }} />
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
|
|
||||||
<FormGroup
|
<FormGroup
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import { pick } from 'lodash';
|
|||||||
import { getDialogPayload } from 'store/dashboard/dashboard.reducer';
|
import { getDialogPayload } from 'store/dashboard/dashboard.reducer';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function CurrencyDialog({
|
function CurrencyDialog({
|
||||||
name,
|
name,
|
||||||
payload,
|
payload,
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import React, { useState, useMemo, useCallback,useEffect } from 'react';
|
import React, { useState, useMemo, useCallback,useEffect } from 'react';
|
||||||
import * as Yup from 'yup';
|
import * as Yup from 'yup';
|
||||||
import { useFormik } from 'formik';
|
import { useFormik, Formik } from 'formik';
|
||||||
import {
|
import {
|
||||||
FormGroup,
|
FormGroup,
|
||||||
MenuItem,
|
MenuItem,
|
||||||
@@ -13,31 +13,32 @@ import {
|
|||||||
} from '@blueprintjs/core';
|
} from '@blueprintjs/core';
|
||||||
import { Row, Col } from 'react-grid-system';
|
import { Row, Col } from 'react-grid-system';
|
||||||
import { FormattedMessage as T, useIntl } from 'react-intl';
|
import { FormattedMessage as T, useIntl } from 'react-intl';
|
||||||
import { Select } from '@blueprintjs/select';
|
|
||||||
import { queryCache } from 'react-query';
|
import { queryCache } from 'react-query';
|
||||||
import {useParams ,useHistory} from 'react-router-dom';
|
import { useParams, useHistory } from 'react-router-dom';
|
||||||
import AppToaster from 'components/AppToaster';
|
import { pick } from 'lodash';
|
||||||
import { compose } from 'utils';
|
|
||||||
import ErrorMessage from 'components/ErrorMessage';
|
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
|
|
||||||
|
import AppToaster from 'components/AppToaster';
|
||||||
|
import ErrorMessage from 'components/ErrorMessage';
|
||||||
import Icon from 'components/Icon';
|
import Icon from 'components/Icon';
|
||||||
|
import MoneyInputGroup from 'components/MoneyInputGroup';
|
||||||
|
import Dragzone from 'components/Dragzone';
|
||||||
|
import { ListSelect } from 'components';
|
||||||
|
|
||||||
import withItemsActions from 'containers/Items/withItemsActions';
|
import withItemsActions from 'containers/Items/withItemsActions';
|
||||||
import withItemCategories from 'containers/Items/withItemCategories'
|
import withItemCategories from 'containers/Items/withItemCategories'
|
||||||
import withAccounts from 'containers/Accounts/withAccounts';
|
import withAccounts from 'containers/Accounts/withAccounts';
|
||||||
import withMediaActions from 'containers/Media/withMediaActions';
|
import withMediaActions from 'containers/Media/withMediaActions';
|
||||||
|
|
||||||
import MoneyInputGroup from 'components/MoneyInputGroup';
|
|
||||||
import Dragzone from 'components/Dragzone';
|
|
||||||
import useMedia from 'hooks/useMedia';
|
import useMedia from 'hooks/useMedia';
|
||||||
import withItems from './withItems';
|
import withItems from './withItems';
|
||||||
import withItemDetail from 'containers/Items/withItemDetail'
|
import withItemDetail from 'containers/Items/withItemDetail'
|
||||||
import { pick } from 'lodash';
|
|
||||||
import withDashboardActions from 'containers/Dashboard/withDashboard';
|
import withDashboardActions from 'containers/Dashboard/withDashboard';
|
||||||
import withAccountDetail from 'containers/Accounts/withAccountDetail';
|
import withAccountDetail from 'containers/Accounts/withAccountDetail';
|
||||||
|
|
||||||
|
import { compose } from 'utils';
|
||||||
|
|
||||||
|
|
||||||
const ItemForm = ({
|
const ItemForm = ({
|
||||||
|
|
||||||
// #withItemActions
|
// #withItemActions
|
||||||
requestSubmitItem,
|
requestSubmitItem,
|
||||||
requestEditItem,
|
requestEditItem,
|
||||||
@@ -46,24 +47,17 @@ const ItemForm = ({
|
|||||||
itemDetail,
|
itemDetail,
|
||||||
onFormSubmit,
|
onFormSubmit,
|
||||||
onCancelForm,
|
onCancelForm,
|
||||||
|
|
||||||
|
|
||||||
// #withDashboard
|
// #withDashboard
|
||||||
changePageTitle,
|
changePageTitle,
|
||||||
|
|
||||||
// #withItemCategories
|
// #withItemCategories
|
||||||
categoriesList,
|
categoriesList,
|
||||||
|
|
||||||
|
// #withMediaActions
|
||||||
|
|
||||||
// #withMediaActions
|
|
||||||
requestSubmitMedia,
|
requestSubmitMedia,
|
||||||
requestDeleteMedia,
|
requestDeleteMedia,
|
||||||
|
|
||||||
|
|
||||||
}) => {
|
}) => {
|
||||||
|
|
||||||
const [selectedAccounts, setSelectedAccounts] = useState({});
|
|
||||||
const [payload, setPayload] = useState({});
|
const [payload, setPayload] = useState({});
|
||||||
|
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
@@ -232,19 +226,11 @@ const ItemForm = ({
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const onItemAccountSelect = useCallback((filedName) => {
|
||||||
const onItemAccountSelect = useCallback(
|
return (account) => {
|
||||||
(filedName) => {
|
setFieldValue(filedName, account.id);
|
||||||
return (account) => {
|
};
|
||||||
setSelectedAccounts({
|
}, [setFieldValue]);
|
||||||
...selectedAccounts,
|
|
||||||
[filedName]: account,
|
|
||||||
});
|
|
||||||
setFieldValue(filedName, account.id);
|
|
||||||
};
|
|
||||||
},
|
|
||||||
[setFieldValue, selectedAccounts]
|
|
||||||
);
|
|
||||||
|
|
||||||
const categoryItem = useCallback(
|
const categoryItem = useCallback(
|
||||||
(item, { handleClick }) => (
|
(item, { handleClick }) => (
|
||||||
@@ -253,16 +239,6 @@ const ItemForm = ({
|
|||||||
[]
|
[]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
const getSelectedAccountLabel = useCallback(
|
|
||||||
(fieldName, defaultLabel) => {
|
|
||||||
return typeof selectedAccounts[fieldName] !== 'undefined'
|
|
||||||
? selectedAccounts[fieldName].name
|
|
||||||
: defaultLabel;
|
|
||||||
},
|
|
||||||
[selectedAccounts]
|
|
||||||
);
|
|
||||||
|
|
||||||
const requiredSpan = useMemo(() => <span class='required'>*</span>, []);
|
const requiredSpan = useMemo(() => <span class='required'>*</span>, []);
|
||||||
const infoIcon = useMemo(() => <Icon icon='info-circle' iconSize={12} />, []);
|
const infoIcon = useMemo(() => <Icon icon='info-circle' iconSize={12} />, []);
|
||||||
|
|
||||||
@@ -307,6 +283,8 @@ const ItemForm = ({
|
|||||||
<div class='item-form__primary-section'>
|
<div class='item-form__primary-section'>
|
||||||
<Row>
|
<Row>
|
||||||
<Col xs={7}>
|
<Col xs={7}>
|
||||||
|
|
||||||
|
{/* Item type */}
|
||||||
<FormGroup
|
<FormGroup
|
||||||
medium={true}
|
medium={true}
|
||||||
label={<T id={'item_type'} />}
|
label={<T id={'item_type'} />}
|
||||||
@@ -324,7 +302,8 @@ const ItemForm = ({
|
|||||||
{...getFieldProps('type')}
|
{...getFieldProps('type')}
|
||||||
/>
|
/>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
|
|
||||||
|
{/* Item name */}
|
||||||
<FormGroup
|
<FormGroup
|
||||||
label={<T id={'item_name'} />}
|
label={<T id={'item_name'} />}
|
||||||
labelInfo={requiredSpan}
|
labelInfo={requiredSpan}
|
||||||
@@ -342,14 +321,13 @@ const ItemForm = ({
|
|||||||
/>
|
/>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
|
|
||||||
|
{/* SKU */}
|
||||||
<FormGroup
|
<FormGroup
|
||||||
label={<T id={'sku'} />}
|
label={<T id={'sku'} />}
|
||||||
labelInfo={infoIcon}
|
labelInfo={infoIcon}
|
||||||
className={'form-group--item-sku'}
|
className={'form-group--item-sku'}
|
||||||
intent={errors.sku && touched.sku && Intent.DANGER}
|
intent={errors.sku && touched.sku && Intent.DANGER}
|
||||||
helperText={
|
helperText={<ErrorMessage {...{ errors, touched }} name='sku' />}
|
||||||
<ErrorMessage {...{ errors, touched }} name='sku' />
|
|
||||||
}
|
|
||||||
inline={true}
|
inline={true}
|
||||||
>
|
>
|
||||||
<InputGroup
|
<InputGroup
|
||||||
@@ -359,6 +337,7 @@ const ItemForm = ({
|
|||||||
/>
|
/>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
|
|
||||||
|
{/* Item category */}
|
||||||
<FormGroup
|
<FormGroup
|
||||||
label={<T id={'category'} />}
|
label={<T id={'category'} />}
|
||||||
labelInfo={infoIcon}
|
labelInfo={infoIcon}
|
||||||
@@ -375,24 +354,22 @@ const ItemForm = ({
|
|||||||
Classes.FILL
|
Classes.FILL
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<Select
|
<ListSelect
|
||||||
items={categoriesList}
|
items={categoriesList}
|
||||||
itemRenderer={categoryItem}
|
itemRenderer={categoryItem}
|
||||||
itemPredicate={filterAccounts}
|
itemPredicate={filterAccounts}
|
||||||
popoverProps={{ minimal: true }}
|
popoverProps={{ minimal: true }}
|
||||||
onItemSelect={onItemAccountSelect('category_id')}
|
onItemSelect={onItemAccountSelect('category_id')}
|
||||||
>
|
|
||||||
<Button
|
|
||||||
fill={true}
|
|
||||||
rightIcon='caret-down'
|
|
||||||
text={getSelectedAccountLabel(
|
|
||||||
'category_id',
|
|
||||||
formatMessage({id:'select_category'})
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
</Select>
|
|
||||||
</FormGroup>
|
|
||||||
|
|
||||||
|
selectedItem={values.category_id}
|
||||||
|
selectedItemProp={'id'}
|
||||||
|
|
||||||
|
defaultText={<T id={'select_category'} />}
|
||||||
|
labelProp={'name'}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
|
||||||
|
{/* Active checkbox */}
|
||||||
<FormGroup
|
<FormGroup
|
||||||
label={' '}
|
label={' '}
|
||||||
inline={true}
|
inline={true}
|
||||||
@@ -426,9 +403,7 @@ const ItemForm = ({
|
|||||||
<FormGroup
|
<FormGroup
|
||||||
label={<T id={'selling_price'}/>}
|
label={<T id={'selling_price'}/>}
|
||||||
className={'form-group--item-selling-price'}
|
className={'form-group--item-selling-price'}
|
||||||
intent={
|
intent={errors.selling_price && touched.selling_price && Intent.DANGER}
|
||||||
errors.selling_price && touched.selling_price && Intent.DANGER
|
|
||||||
}
|
|
||||||
helperText={
|
helperText={
|
||||||
<ErrorMessage {...{ errors, touched }} name='selling_price' />
|
<ErrorMessage {...{ errors, touched }} name='selling_price' />
|
||||||
}
|
}
|
||||||
@@ -447,7 +422,8 @@ const ItemForm = ({
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
|
|
||||||
|
{/* Selling account */}
|
||||||
<FormGroup
|
<FormGroup
|
||||||
label={<T id={'account'} />}
|
label={<T id={'account'} />}
|
||||||
labelInfo={infoIcon}
|
labelInfo={infoIcon}
|
||||||
@@ -466,30 +442,26 @@ const ItemForm = ({
|
|||||||
Classes.FILL
|
Classes.FILL
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<Select
|
<ListSelect
|
||||||
items={accounts}
|
items={accounts}
|
||||||
itemRenderer={accountItem}
|
itemRenderer={accountItem}
|
||||||
itemPredicate={filterAccounts}
|
itemPredicate={filterAccounts}
|
||||||
popoverProps={{ minimal: true }}
|
popoverProps={{ minimal: true }}
|
||||||
onItemSelect={onItemAccountSelect('sell_account_id')}
|
onItemSelect={onItemAccountSelect('sell_account_id')}
|
||||||
>
|
|
||||||
<Button
|
selectedItem={values.sell_account_id}
|
||||||
fill={true}
|
selectedItemProp={'id'}
|
||||||
rightIcon='caret-down'
|
|
||||||
text={getSelectedAccountLabel(
|
defaultText={<T id={'select_account'} />}
|
||||||
'sell_account_id',
|
labelProp={'name'}
|
||||||
formatMessage({id:'select_account'})
|
/>
|
||||||
)}
|
|
||||||
/>
|
|
||||||
</Select>
|
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
</Col>
|
</Col>
|
||||||
|
|
||||||
<Col width={404}>
|
<Col width={404}>
|
||||||
<h4>
|
<h4><T id={'sales_information'} /></h4>
|
||||||
<T id={'sales_information'} />
|
|
||||||
</h4>
|
|
||||||
|
|
||||||
|
{/* Cost price */}
|
||||||
<FormGroup
|
<FormGroup
|
||||||
label={<T id={'cost_price'} />}
|
label={<T id={'cost_price'} />}
|
||||||
className={'form-group--item-cost-price'}
|
className={'form-group--item-cost-price'}
|
||||||
@@ -529,23 +501,18 @@ const ItemForm = ({
|
|||||||
Classes.FILL
|
Classes.FILL
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<Select
|
<ListSelect
|
||||||
items={accounts}
|
items={accounts}
|
||||||
itemRenderer={accountItem}
|
itemRenderer={accountItem}
|
||||||
itemPredicate={filterAccounts}
|
itemPredicate={filterAccounts}
|
||||||
popoverProps={{ minimal: true }}
|
popoverProps={{ minimal: true }}
|
||||||
onItemSelect={onItemAccountSelect('cost_account_id')}
|
onItemSelect={onItemAccountSelect('cost_account_id')}
|
||||||
>
|
|
||||||
<Button
|
defaultText={<T id={'select_account'} />}
|
||||||
fill={true}
|
labelProp={'name'}
|
||||||
rightIcon='caret-down'
|
selectedItem={values.cost_account_id}
|
||||||
text={getSelectedAccountLabel(
|
selectedItemProp={'id'}
|
||||||
'cost_account_id',
|
/>
|
||||||
formatMessage({id:'select_account'})
|
|
||||||
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
</Select>
|
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
@@ -564,35 +531,24 @@ const ItemForm = ({
|
|||||||
touched.inventory_account_id &&
|
touched.inventory_account_id &&
|
||||||
Intent.DANGER
|
Intent.DANGER
|
||||||
}
|
}
|
||||||
helperText={
|
helperText={<ErrorMessage {...{ errors, touched }} name='inventory_account_id' />}
|
||||||
<ErrorMessage
|
|
||||||
{...{ errors, touched }}
|
|
||||||
name='inventory_account_id'
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
className={classNames(
|
className={classNames(
|
||||||
'form-group--item-inventory_account',
|
'form-group--item-inventory_account',
|
||||||
'form-group--select-list',
|
'form-group--select-list',
|
||||||
Classes.FILL
|
Classes.FILL
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<Select
|
<ListSelect
|
||||||
items={accounts}
|
items={accounts}
|
||||||
itemRenderer={accountItem}
|
itemRenderer={accountItem}
|
||||||
itemPredicate={filterAccounts}
|
itemPredicate={filterAccounts}
|
||||||
popoverProps={{ minimal: true }}
|
popoverProps={{ minimal: true }}
|
||||||
onItemSelect={onItemAccountSelect('inventory_account_id')}
|
onItemSelect={onItemAccountSelect('inventory_account_id')}
|
||||||
>
|
|
||||||
<Button
|
defaultText={<T id={'select_account'} />}
|
||||||
fill={true}
|
labelProp={'name'}
|
||||||
rightIcon='caret-down'
|
selectedItem={values.inventory_account_id}
|
||||||
text={getSelectedAccountLabel(
|
selectedItemProp={'id'} />
|
||||||
'inventory_account_id',
|
|
||||||
formatMessage({id:'select_account'})
|
|
||||||
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
</Select>
|
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
|
|
||||||
<FormGroup
|
<FormGroup
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ export default {
|
|||||||
const costAccountPromise = Account.query().findById(form.cost_account_id);
|
const costAccountPromise = Account.query().findById(form.cost_account_id);
|
||||||
const sellAccountPromise = Account.query().findById(form.sell_account_id);
|
const sellAccountPromise = Account.query().findById(form.sell_account_id);
|
||||||
const inventoryAccountPromise = (form.type === 'inventory')
|
const inventoryAccountPromise = (form.type === 'inventory')
|
||||||
? Account.query().findByid(form.inventory_account_id) : null;
|
? Account.query().findById(form.inventory_account_id) : null;
|
||||||
|
|
||||||
const itemCategoryPromise = (form.category_id)
|
const itemCategoryPromise = (form.category_id)
|
||||||
? ItemCategory.query().findById(form.category_id) : null;
|
? ItemCategory.query().findById(form.category_id) : null;
|
||||||
|
|||||||
Reference in New Issue
Block a user