mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-19 14:20:31 +00:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
@@ -76,6 +76,7 @@ export default function AccountsSelectList({
|
|||||||
popoverProps={{ minimal: true }}
|
popoverProps={{ minimal: true }}
|
||||||
filterable={true}
|
filterable={true}
|
||||||
onItemSelect={onAccountSelect}
|
onItemSelect={onAccountSelect}
|
||||||
|
disabled={disabled}
|
||||||
>
|
>
|
||||||
<Button
|
<Button
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
import React, { useCallback } from 'react';
|
import React, { useCallback } from 'react';
|
||||||
import {
|
import { ListSelect } from 'components';
|
||||||
ListSelect,
|
|
||||||
} from 'components';
|
|
||||||
|
|
||||||
export default function AccountsTypesSelect({
|
export default function AccountsTypesSelect({
|
||||||
accountsTypes,
|
accountsTypes,
|
||||||
selectedTypeId,
|
selectedTypeId,
|
||||||
defaultSelectText = 'Select account type',
|
defaultSelectText = 'Select account type',
|
||||||
onTypeSelected,
|
onTypeSelected,
|
||||||
|
disabled = false,
|
||||||
...restProps
|
...restProps
|
||||||
}) {
|
}) {
|
||||||
// Filters accounts types items.
|
// Filters accounts types items.
|
||||||
@@ -28,7 +27,8 @@ export default function AccountsTypesSelect({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const items = accountsTypes.map((type) => ({
|
const items = accountsTypes.map((type) => ({
|
||||||
id: type.id, label: type.label,
|
id: type.id,
|
||||||
|
label: type.label,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -40,6 +40,7 @@ export default function AccountsTypesSelect({
|
|||||||
defaultText={defaultSelectText}
|
defaultText={defaultSelectText}
|
||||||
onItemSelect={handleItemSelected}
|
onItemSelect={handleItemSelected}
|
||||||
itemPredicate={filterAccountTypeItems}
|
itemPredicate={filterAccountTypeItems}
|
||||||
|
disabled={disabled}
|
||||||
{...restProps}
|
{...restProps}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import UserFormDialog from 'containers/Dialogs/UserFormDialog';
|
|||||||
// import ItemCategoryDialog from 'containers/Dialogs/ItemCategoryDialog';
|
// import ItemCategoryDialog from 'containers/Dialogs/ItemCategoryDialog';
|
||||||
import CurrencyFormDialog from 'containers/Dialogs/CurrencyFormDialog';
|
import CurrencyFormDialog from 'containers/Dialogs/CurrencyFormDialog';
|
||||||
// import InviteUserDialog from 'containers/Dialogs/InviteUserDialog';
|
// import InviteUserDialog from 'containers/Dialogs/InviteUserDialog';
|
||||||
// import ExchangeRateDialog from 'containers/Dialogs/ExchangeRateDialog';
|
import ExchangeRateFormDialog from 'containers/Dialogs/ExchangeRateFormDialog';
|
||||||
import JournalNumberDialog from 'containers/Dialogs/JournalNumberDialog';
|
import JournalNumberDialog from 'containers/Dialogs/JournalNumberDialog';
|
||||||
import BillNumberDialog from 'containers/Dialogs/BillNumberDialog';
|
import BillNumberDialog from 'containers/Dialogs/BillNumberDialog';
|
||||||
import PaymentNumberDialog from 'containers/Dialogs/PaymentNumberDialog';
|
import PaymentNumberDialog from 'containers/Dialogs/PaymentNumberDialog';
|
||||||
@@ -25,6 +25,7 @@ export default function DialogsContainer() {
|
|||||||
<InvoiceNumberDialog dialogName={'invoice-number-form'} />
|
<InvoiceNumberDialog dialogName={'invoice-number-form'} />
|
||||||
<CurrencyFormDialog dialogName={'currency-form'} />
|
<CurrencyFormDialog dialogName={'currency-form'} />
|
||||||
<UserFormDialog dialogName={'user-form'} />
|
<UserFormDialog dialogName={'user-form'} />
|
||||||
|
<ExchangeRateFormDialog dialogName={'exchangeRate-form'} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ export default function ListSelect({
|
|||||||
|
|
||||||
initialSelectedItem,
|
initialSelectedItem,
|
||||||
onItemSelect,
|
onItemSelect,
|
||||||
|
disabled = false,
|
||||||
...selectProps
|
...selectProps
|
||||||
}) {
|
}) {
|
||||||
const selectedItemObj = useMemo(
|
const selectedItemObj = useMemo(
|
||||||
@@ -24,7 +24,10 @@ export default function ListSelect({
|
|||||||
);
|
);
|
||||||
|
|
||||||
const selectedInitialItem = useMemo(
|
const selectedInitialItem = useMemo(
|
||||||
() => selectProps.items.find((i) => i[selectedItemProp] === initialSelectedItem),
|
() =>
|
||||||
|
selectProps.items.find(
|
||||||
|
(i) => i[selectedItemProp] === initialSelectedItem,
|
||||||
|
),
|
||||||
[initialSelectedItem],
|
[initialSelectedItem],
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -65,10 +68,12 @@ export default function ListSelect({
|
|||||||
onItemSelect={handleItemSelect}
|
onItemSelect={handleItemSelect}
|
||||||
{...selectProps}
|
{...selectProps}
|
||||||
noResults={noResults}
|
noResults={noResults}
|
||||||
|
disabled={disabled}
|
||||||
>
|
>
|
||||||
<Button
|
<Button
|
||||||
text={currentItem ? currentItem[labelProp] : defaultText}
|
text={currentItem ? currentItem[labelProp] : defaultText}
|
||||||
loading={isLoading}
|
loading={isLoading}
|
||||||
|
disabled={disabled}
|
||||||
{...buttonProps}
|
{...buttonProps}
|
||||||
/>
|
/>
|
||||||
</Select>
|
</Select>
|
||||||
|
|||||||
5
client/src/components/MoneyExchangeRate.js
Normal file
5
client/src/components/MoneyExchangeRate.js
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { formattedExchangeRate } from 'utils';
|
||||||
|
export default function MoneyExchangeRate({ amount, currency }) {
|
||||||
|
return <span>{formattedExchangeRate(amount, currency)}</span>;
|
||||||
|
}
|
||||||
@@ -29,6 +29,7 @@ import CategoriesSelectList from './CategoriesSelectList';
|
|||||||
import Row from './Grid/Row';
|
import Row from './Grid/Row';
|
||||||
import Col from './Grid/Col';
|
import Col from './Grid/Col';
|
||||||
import CloudLoadingIndicator from './CloudLoadingIndicator';
|
import CloudLoadingIndicator from './CloudLoadingIndicator';
|
||||||
|
import MoneyExchangeRate from './MoneyExchangeRate';
|
||||||
|
|
||||||
const Hint = FieldHint;
|
const Hint = FieldHint;
|
||||||
|
|
||||||
@@ -65,4 +66,5 @@ export {
|
|||||||
Col,
|
Col,
|
||||||
Row,
|
Row,
|
||||||
CloudLoadingIndicator,
|
CloudLoadingIndicator,
|
||||||
|
MoneyExchangeRate,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -282,7 +282,7 @@ function AccountFormDialogContent({
|
|||||||
selectedTypeId={values.account_type_id}
|
selectedTypeId={values.account_type_id}
|
||||||
defaultSelectText={<T id={'select_account_type'} />}
|
defaultSelectText={<T id={'select_account_type'} />}
|
||||||
onTypeSelected={onChangeAccountType}
|
onTypeSelected={onChangeAccountType}
|
||||||
buttonProps={{ disabled: action === 'edit' }}
|
disabled={action === 'edit'}
|
||||||
popoverProps={{ minimal: true }}
|
popoverProps={{ minimal: true }}
|
||||||
/>
|
/>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
|
|||||||
@@ -1,33 +1,33 @@
|
|||||||
import { connect } from 'react-redux';
|
// import { connect } from 'react-redux';
|
||||||
import { compose } from 'utils';
|
// import { compose } from 'utils';
|
||||||
|
|
||||||
import withDialogActions from 'containers/Dialog/withDialogActions';
|
// import withDialogActions from 'containers/Dialog/withDialogActions';
|
||||||
import withDialogRedux from 'components/DialogReduxConnect';
|
// import withDialogRedux from 'components/DialogReduxConnect';
|
||||||
import withExchangeRateDetail from 'containers/ExchangeRates/withExchangeRateDetail';
|
// import withExchangeRateDetail from 'containers/ExchangeRates/withExchangeRateDetail';
|
||||||
import withExchangeRatesActions from 'containers/ExchangeRates/withExchangeRatesActions';
|
// import withExchangeRatesActions from 'containers/ExchangeRates/withExchangeRatesActions';
|
||||||
import withExchangeRates from 'containers/ExchangeRates/withExchangeRates';
|
// import withExchangeRates from 'containers/ExchangeRates/withExchangeRates';
|
||||||
import withCurrencies from 'containers/Currencies/withCurrencies';
|
// import withCurrencies from 'containers/Currencies/withCurrencies';
|
||||||
|
|
||||||
const mapStateToProps = (state, props) => ({
|
// const mapStateToProps = (state, props) => ({
|
||||||
dialogName: 'exchangeRate-form',
|
// dialogName: 'exchangeRate-form',
|
||||||
exchangeRateId:
|
// exchangeRateId:
|
||||||
props.payload.action === 'edit' && props.payload.id
|
// props.payload.action === 'edit' && props.payload.id
|
||||||
? props.payload.id
|
// ? props.payload.id
|
||||||
: null,
|
// : null,
|
||||||
});
|
// });
|
||||||
|
|
||||||
const withExchangeRateDialog = connect(mapStateToProps);
|
// const withExchangeRateDialog = connect(mapStateToProps);
|
||||||
|
|
||||||
export default compose(
|
// export default compose(
|
||||||
withDialogRedux(null, 'exchangeRate-form'),
|
// withDialogRedux(null, 'exchangeRate-form'),
|
||||||
withExchangeRateDialog,
|
// withExchangeRateDialog,
|
||||||
withCurrencies(({ currenciesList }) => ({
|
// withCurrencies(({ currenciesList }) => ({
|
||||||
currenciesList,
|
// currenciesList,
|
||||||
})),
|
// })),
|
||||||
withExchangeRatesActions,
|
// withExchangeRatesActions,
|
||||||
withExchangeRateDetail,
|
// withExchangeRateDetail,
|
||||||
withExchangeRates(({ exchangeRatesList }) => ({
|
// withExchangeRates(({ exchangeRatesList }) => ({
|
||||||
exchangeRatesList,
|
// exchangeRatesList,
|
||||||
})),
|
// })),
|
||||||
withDialogActions,
|
// withDialogActions,
|
||||||
);
|
// );
|
||||||
|
|||||||
48
client/src/containers/Dialogs/ExchangeRateFormDialog.js
Normal file
48
client/src/containers/Dialogs/ExchangeRateFormDialog.js
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
import React, { lazy } from 'react';
|
||||||
|
import { FormattedMessage as T, useIntl } from 'react-intl';
|
||||||
|
import {
|
||||||
|
Dialog,
|
||||||
|
DialogSuspense,
|
||||||
|
} from 'components';
|
||||||
|
import withDialogRedux from 'components/DialogReduxConnect';
|
||||||
|
import { compose } from 'utils';
|
||||||
|
|
||||||
|
const ExchangeRateFormDialogContent = lazy(() =>
|
||||||
|
import('./ExchangeRateFormDialogContent'),
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exchange rate form dialog.
|
||||||
|
*/
|
||||||
|
function ExchangeRateFormDialog({
|
||||||
|
dialogName,
|
||||||
|
payload = { action: '', id: null },
|
||||||
|
isOpen,
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<Dialog
|
||||||
|
name={dialogName}
|
||||||
|
title={
|
||||||
|
payload.action === 'edit' ? (
|
||||||
|
<T id={'edit_exchange_rate'} />
|
||||||
|
) : (
|
||||||
|
<T id={'new_exchange_rate'} />
|
||||||
|
)
|
||||||
|
}
|
||||||
|
className={'dialog--exchangeRate-form'}
|
||||||
|
isOpen={isOpen}
|
||||||
|
autoFocus={true}
|
||||||
|
canEscapeKeyClose={true}
|
||||||
|
>
|
||||||
|
<DialogSuspense>
|
||||||
|
<ExchangeRateFormDialogContent
|
||||||
|
dialogName={dialogName}
|
||||||
|
action={payload.action}
|
||||||
|
exchangeRateId={payload.id}
|
||||||
|
/>
|
||||||
|
</DialogSuspense>
|
||||||
|
</Dialog>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default compose(withDialogRedux())(ExchangeRateFormDialog);
|
||||||
@@ -10,25 +10,32 @@ import {
|
|||||||
} from '@blueprintjs/core';
|
} from '@blueprintjs/core';
|
||||||
import { pick } from 'lodash';
|
import { pick } from 'lodash';
|
||||||
import * as Yup from 'yup';
|
import * as Yup from 'yup';
|
||||||
import { FormattedMessage as T, useIntl } from 'react-intl';
|
|
||||||
import { useFormik } from 'formik';
|
import { useFormik } from 'formik';
|
||||||
import { useQuery, queryCache } from 'react-query';
|
import { useQuery, queryCache } from 'react-query';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import { DateInput } from '@blueprintjs/datetime';
|
import { DateInput } from '@blueprintjs/datetime';
|
||||||
|
import { FormattedMessage as T, useIntl } from 'react-intl';
|
||||||
import { momentFormatter, tansformDateValue } from 'utils';
|
import { momentFormatter, tansformDateValue } from 'utils';
|
||||||
import { AppToaster, Dialog, ErrorMessage, ListSelect } from 'components';
|
import {
|
||||||
|
AppToaster,
|
||||||
|
Dialog,
|
||||||
|
ErrorMessage,
|
||||||
|
ListSelect,
|
||||||
|
DialogContent,
|
||||||
|
FieldRequiredHint,
|
||||||
|
} from 'components';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import withExchangeRatesDialog from './ExchangeRateDialog.container';
|
import withExchangeRateDetail from 'containers/ExchangeRates/withExchangeRateDetail';
|
||||||
|
import withExchangeRatesActions from 'containers/ExchangeRates/withExchangeRatesActions';
|
||||||
|
|
||||||
/**
|
import withCurrencies from 'containers/Currencies/withCurrencies';
|
||||||
* Exchange rate dialog.
|
import withCurrenciesActions from 'containers/Currencies/withCurrenciesActions';
|
||||||
*/
|
import withDialogActions from 'containers/Dialog/withDialogActions';
|
||||||
function ExchangeRateDialog({
|
|
||||||
dialogName,
|
|
||||||
payload = {},
|
|
||||||
isOpen,
|
|
||||||
|
|
||||||
// #withDialog
|
import { compose } from 'utils';
|
||||||
|
|
||||||
|
function ExchangeRateFormDialogContent({
|
||||||
|
// #withDialogActions
|
||||||
closeDialog,
|
closeDialog,
|
||||||
|
|
||||||
// #withCurrencies
|
// #withCurrencies
|
||||||
@@ -39,12 +46,25 @@ function ExchangeRateDialog({
|
|||||||
|
|
||||||
// #withExchangeRatesActions
|
// #withExchangeRatesActions
|
||||||
requestSubmitExchangeRate,
|
requestSubmitExchangeRate,
|
||||||
requestFetchExchangeRates,
|
|
||||||
requestEditExchangeRate,
|
requestEditExchangeRate,
|
||||||
|
|
||||||
|
// #wihtCurrenciesActions
|
||||||
|
requestFetchCurrencies,
|
||||||
|
|
||||||
|
// #ownProp
|
||||||
|
action,
|
||||||
|
exchangeRateId,
|
||||||
|
dialogName,
|
||||||
}) {
|
}) {
|
||||||
const { formatMessage } = useIntl();
|
const { formatMessage } = useIntl();
|
||||||
const [selectedItems, setSelectedItems] = useState({});
|
const [selectedItems, setSelectedItems] = useState({});
|
||||||
|
|
||||||
|
const fetchCurrencies = useQuery(
|
||||||
|
'currencies',
|
||||||
|
() => requestFetchCurrencies(),
|
||||||
|
{ enabled: true },
|
||||||
|
);
|
||||||
|
|
||||||
const validationSchema = Yup.object().shape({
|
const validationSchema = Yup.object().shape({
|
||||||
exchange_rate: Yup.number()
|
exchange_rate: Yup.number()
|
||||||
.required()
|
.required()
|
||||||
@@ -66,12 +86,6 @@ function ExchangeRateDialog({
|
|||||||
[],
|
[],
|
||||||
);
|
);
|
||||||
|
|
||||||
const fetchExchangeRatesDialog = useQuery(
|
|
||||||
'exchange-rates-dialog',
|
|
||||||
() => requestFetchExchangeRates(),
|
|
||||||
{ manual: true },
|
|
||||||
);
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
values,
|
values,
|
||||||
touched,
|
touched,
|
||||||
@@ -85,12 +99,12 @@ function ExchangeRateDialog({
|
|||||||
enableReinitialize: true,
|
enableReinitialize: true,
|
||||||
validationSchema,
|
validationSchema,
|
||||||
initialValues: {
|
initialValues: {
|
||||||
...(payload.action === 'edit' &&
|
...initialValues,
|
||||||
pick(exchangeRate, Object.keys(initialValues))),
|
...(action === 'edit' && pick(exchangeRate, Object.keys(initialValues))),
|
||||||
},
|
},
|
||||||
onSubmit: (values, { setSubmitting, setErrors }) => {
|
onSubmit: (values, { setSubmitting, setErrors }) => {
|
||||||
if (payload.action === 'edit') {
|
if (action === 'edit') {
|
||||||
requestEditExchangeRate(payload.id, values)
|
requestEditExchangeRate(exchangeRateId, values)
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
closeDialog(dialogName);
|
closeDialog(dialogName);
|
||||||
AppToaster.show({
|
AppToaster.show({
|
||||||
@@ -100,7 +114,7 @@ function ExchangeRateDialog({
|
|||||||
intent: Intent.SUCCESS,
|
intent: Intent.SUCCESS,
|
||||||
});
|
});
|
||||||
setSubmitting(false);
|
setSubmitting(false);
|
||||||
queryCache.invalidateQueries('exchange-rates-dialog');
|
queryCache.invalidateQueries('exchange-rates-table');
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
setSubmitting(false);
|
setSubmitting(false);
|
||||||
@@ -134,20 +148,10 @@ function ExchangeRateDialog({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const requiredSpan = useMemo(() => <span class="required">*</span>, []);
|
|
||||||
|
|
||||||
const handleClose = useCallback(() => {
|
const handleClose = useCallback(() => {
|
||||||
closeDialog(dialogName);
|
closeDialog(dialogName);
|
||||||
}, [dialogName, closeDialog]);
|
|
||||||
|
|
||||||
const onDialogClosed = useCallback(() => {
|
|
||||||
resetForm();
|
resetForm();
|
||||||
closeDialog(dialogName);
|
}, [dialogName, closeDialog]);
|
||||||
}, [closeDialog, dialogName, resetForm]);
|
|
||||||
|
|
||||||
const onDialogOpening = useCallback(() => {
|
|
||||||
fetchExchangeRatesDialog.refetch();
|
|
||||||
}, [fetchExchangeRatesDialog]);
|
|
||||||
|
|
||||||
const handleDateChange = useCallback(
|
const handleDateChange = useCallback(
|
||||||
(date_filed) => (date) => {
|
(date_filed) => (date) => {
|
||||||
@@ -197,31 +201,13 @@ function ExchangeRateDialog({
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dialog
|
<DialogContent isLoading={fetchCurrencies.isFetching}>
|
||||||
name={dialogName}
|
|
||||||
title={
|
|
||||||
payload.action === 'edit' ? (
|
|
||||||
<T id={'edit_exchange_rate'} />
|
|
||||||
) : (
|
|
||||||
<T id={'new_exchange_rate'} />
|
|
||||||
)
|
|
||||||
}
|
|
||||||
className={classNames(
|
|
||||||
{ 'dialog--loading': fetchExchangeRatesDialog.isFetching },
|
|
||||||
'dialog--exchangeRate-form',
|
|
||||||
)}
|
|
||||||
isOpen={isOpen}
|
|
||||||
onClosed={onDialogClosed}
|
|
||||||
onOpening={onDialogOpening}
|
|
||||||
isLoading={fetchExchangeRatesDialog.isFetching}
|
|
||||||
onClose={handleClose}
|
|
||||||
>
|
|
||||||
<form onSubmit={handleSubmit}>
|
<form onSubmit={handleSubmit}>
|
||||||
<div className={Classes.DIALOG_BODY}>
|
<div className={Classes.DIALOG_BODY}>
|
||||||
<FormGroup
|
<FormGroup
|
||||||
label={<T id={'date'} />}
|
label={<T id={'date'} />}
|
||||||
inline={true}
|
inline={true}
|
||||||
labelInfo={requiredSpan}
|
labelInfo={FieldRequiredHint}
|
||||||
intent={errors.date && touched.date && Intent.DANGER}
|
intent={errors.date && touched.date && Intent.DANGER}
|
||||||
helperText={<ErrorMessage name="date" {...{ errors, touched }} />}
|
helperText={<ErrorMessage name="date" {...{ errors, touched }} />}
|
||||||
>
|
>
|
||||||
@@ -231,33 +217,12 @@ function ExchangeRateDialog({
|
|||||||
value={tansformDateValue(values.date)}
|
value={tansformDateValue(values.date)}
|
||||||
onChange={handleDateChange('date')}
|
onChange={handleDateChange('date')}
|
||||||
popoverProps={{ position: Position.BOTTOM, minimal: true }}
|
popoverProps={{ position: Position.BOTTOM, minimal: true }}
|
||||||
disabled={payload.action === 'edit'}
|
disabled={action === 'edit'}
|
||||||
/>
|
/>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
|
|
||||||
<FormGroup
|
|
||||||
label={<T id={'exchange_rate'} />}
|
|
||||||
labelInfo={requiredSpan}
|
|
||||||
intent={
|
|
||||||
errors.exchange_rate && touched.exchange_rate && Intent.DANGER
|
|
||||||
}
|
|
||||||
helperText={
|
|
||||||
<ErrorMessage name="exchange_rate" {...{ errors, touched }} />
|
|
||||||
}
|
|
||||||
inline={true}
|
|
||||||
>
|
|
||||||
<InputGroup
|
|
||||||
medium={true}
|
|
||||||
intent={
|
|
||||||
errors.exchange_rate && touched.exchange_rate && Intent.DANGER
|
|
||||||
}
|
|
||||||
{...getFieldProps('exchange_rate')}
|
|
||||||
/>
|
|
||||||
</FormGroup>
|
|
||||||
|
|
||||||
<FormGroup
|
<FormGroup
|
||||||
label={<T id={'currency_code'} />}
|
label={<T id={'currency_code'} />}
|
||||||
labelInfo={requiredSpan}
|
labelInfo={FieldRequiredHint}
|
||||||
className={classNames('form-group--select-list', Classes.FILL)}
|
className={classNames('form-group--select-list', Classes.FILL)}
|
||||||
inline={true}
|
inline={true}
|
||||||
intent={
|
intent={
|
||||||
@@ -278,6 +243,26 @@ function ExchangeRateDialog({
|
|||||||
selectedItemProp={'currency_code'}
|
selectedItemProp={'currency_code'}
|
||||||
defaultText={<T id={'select_currency_code'} />}
|
defaultText={<T id={'select_currency_code'} />}
|
||||||
labelProp={'currency_code'}
|
labelProp={'currency_code'}
|
||||||
|
disabled={action === 'edit'}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
<FormGroup
|
||||||
|
label={<T id={'exchange_rate'} />}
|
||||||
|
labelInfo={FieldRequiredHint}
|
||||||
|
intent={
|
||||||
|
errors.exchange_rate && touched.exchange_rate && Intent.DANGER
|
||||||
|
}
|
||||||
|
helperText={
|
||||||
|
<ErrorMessage name="exchange_rate" {...{ errors, touched }} />
|
||||||
|
}
|
||||||
|
inline={true}
|
||||||
|
>
|
||||||
|
<InputGroup
|
||||||
|
medium={true}
|
||||||
|
intent={
|
||||||
|
errors.exchange_rate && touched.exchange_rate && Intent.DANGER
|
||||||
|
}
|
||||||
|
{...getFieldProps('exchange_rate')}
|
||||||
/>
|
/>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
</div>
|
</div>
|
||||||
@@ -291,17 +276,19 @@ function ExchangeRateDialog({
|
|||||||
type="submit"
|
type="submit"
|
||||||
disabled={isSubmitting}
|
disabled={isSubmitting}
|
||||||
>
|
>
|
||||||
{payload.action === 'edit' ? (
|
{action === 'edit' ? <T id={'edit'} /> : <T id={'submit'} />}
|
||||||
<T id={'edit'} />
|
|
||||||
) : (
|
|
||||||
<T id={'submit'} />
|
|
||||||
)}
|
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</Dialog>
|
</DialogContent>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default withExchangeRatesDialog(ExchangeRateDialog);
|
export default compose(
|
||||||
|
withDialogActions,
|
||||||
|
withExchangeRatesActions,
|
||||||
|
withExchangeRateDetail,
|
||||||
|
withCurrenciesActions,
|
||||||
|
withCurrencies(({ currenciesList }) => ({ currenciesList })),
|
||||||
|
)(ExchangeRateFormDialogContent);
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { useCallback, useMemo, useState, useEffect } from 'react';
|
import React, { useCallback, useMemo, useState } from 'react';
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
Popover,
|
Popover,
|
||||||
@@ -10,7 +10,7 @@ import {
|
|||||||
import { FormattedMessage as T, useIntl } from 'react-intl';
|
import { FormattedMessage as T, useIntl } from 'react-intl';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
|
|
||||||
import { DataTable, Money, Icon } from 'components';
|
import { DataTable, Icon, MoneyExchangeRate } from 'components';
|
||||||
import LoadingIndicator from 'components/LoadingIndicator';
|
import LoadingIndicator from 'components/LoadingIndicator';
|
||||||
|
|
||||||
import withDialogActions from 'containers/Dialog/withDialogActions';
|
import withDialogActions from 'containers/Dialog/withDialogActions';
|
||||||
@@ -23,7 +23,7 @@ function ExchangeRateTable({
|
|||||||
// #withExchangeRates
|
// #withExchangeRates
|
||||||
exchangeRatesList,
|
exchangeRatesList,
|
||||||
exchangeRatesLoading,
|
exchangeRatesLoading,
|
||||||
|
exchangeRatesPageination,
|
||||||
// #withDialogActions.
|
// #withDialogActions.
|
||||||
openDialog,
|
openDialog,
|
||||||
|
|
||||||
@@ -31,7 +31,6 @@ function ExchangeRateTable({
|
|||||||
loading,
|
loading,
|
||||||
onFetchData,
|
onFetchData,
|
||||||
onDeleteExchangeRate,
|
onDeleteExchangeRate,
|
||||||
onEditExchangeRate,
|
|
||||||
onSelectedRowsChange,
|
onSelectedRowsChange,
|
||||||
}) {
|
}) {
|
||||||
const [initialMount, setInitialMount] = useState(false);
|
const [initialMount, setInitialMount] = useState(false);
|
||||||
@@ -52,20 +51,25 @@ function ExchangeRateTable({
|
|||||||
(ExchangeRate) => (
|
(ExchangeRate) => (
|
||||||
<Menu>
|
<Menu>
|
||||||
<MenuItem
|
<MenuItem
|
||||||
text={<T id={'edit_exchange_rate'} />}
|
icon={<Icon icon="pen-18" />}
|
||||||
|
text={formatMessage({ id: 'edit_exchange_rate' })}
|
||||||
onClick={handelEditExchangeRate(ExchangeRate)}
|
onClick={handelEditExchangeRate(ExchangeRate)}
|
||||||
/>
|
/>
|
||||||
<MenuItem
|
<MenuItem
|
||||||
text={<T id={'delete_exchange_rate'} />}
|
text={formatMessage({ id: 'delete_exchange_rate' })}
|
||||||
intent={Intent.DANGER}
|
intent={Intent.DANGER}
|
||||||
onClick={handleDeleteExchangeRate(ExchangeRate)}
|
onClick={handleDeleteExchangeRate(ExchangeRate)}
|
||||||
icon={<Icon icon="trash-16" iconSize={16} />}
|
icon={<Icon icon="trash-16" iconSize={16} />}
|
||||||
/>
|
/>
|
||||||
</Menu>
|
</Menu>
|
||||||
),
|
),
|
||||||
[handelEditExchangeRate, handleDeleteExchangeRate],
|
[handelEditExchangeRate, handleDeleteExchangeRate, formatMessage],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const rowContextMenu = (cell) => {
|
||||||
|
return actionMenuList(cell.row.original);
|
||||||
|
};
|
||||||
|
|
||||||
const columns = useMemo(
|
const columns = useMemo(
|
||||||
() => [
|
() => [
|
||||||
{
|
{
|
||||||
@@ -84,7 +88,12 @@ function ExchangeRateTable({
|
|||||||
{
|
{
|
||||||
id: 'exchange_rate',
|
id: 'exchange_rate',
|
||||||
Header: formatMessage({ id: 'exchange_rate' }),
|
Header: formatMessage({ id: 'exchange_rate' }),
|
||||||
accessor: (r) => <Money amount={r.exchange_rate} currency={'USD'} />,
|
accessor: (r) => (
|
||||||
|
<MoneyExchangeRate
|
||||||
|
amount={r.exchange_rate}
|
||||||
|
currency={r.currency_code}
|
||||||
|
/>
|
||||||
|
),
|
||||||
className: 'exchange_rate',
|
className: 'exchange_rate',
|
||||||
width: 150,
|
width: 150,
|
||||||
},
|
},
|
||||||
@@ -94,14 +103,13 @@ function ExchangeRateTable({
|
|||||||
Cell: ({ cell }) => (
|
Cell: ({ cell }) => (
|
||||||
<Popover
|
<Popover
|
||||||
content={actionMenuList(cell.row.original)}
|
content={actionMenuList(cell.row.original)}
|
||||||
position={Position.RIGHT_BOTTOM}
|
position={Position.RIGHT_TOP}
|
||||||
>
|
>
|
||||||
<Button icon={<Icon icon="more-h-16" iconSize={16} />} />
|
<Button icon={<Icon icon="more-h-16" iconSize={16} />} />
|
||||||
</Popover>
|
</Popover>
|
||||||
),
|
),
|
||||||
className: 'actions',
|
className: 'actions',
|
||||||
width: 50,
|
width: 50,
|
||||||
disableResizing: false,
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
[actionMenuList, formatMessage],
|
[actionMenuList, formatMessage],
|
||||||
@@ -143,7 +151,11 @@ function ExchangeRateTable({
|
|||||||
expandable={true}
|
expandable={true}
|
||||||
treeGraph={true}
|
treeGraph={true}
|
||||||
onSelectedRowsChange={handelSelectedRowsChange}
|
onSelectedRowsChange={handelSelectedRowsChange}
|
||||||
spinnerProps={{ size: 30 }}
|
rowContextMenu={rowContextMenu}
|
||||||
|
pagination={true}
|
||||||
|
pagesCount={exchangeRatesPageination.pagesCount}
|
||||||
|
initialPageSize={exchangeRatesPageination.pageSize}
|
||||||
|
initialPageIndex={exchangeRatesPageination.page - 1}
|
||||||
/>
|
/>
|
||||||
</LoadingIndicator>
|
</LoadingIndicator>
|
||||||
);
|
);
|
||||||
@@ -152,8 +164,15 @@ function ExchangeRateTable({
|
|||||||
export default compose(
|
export default compose(
|
||||||
withDialogActions,
|
withDialogActions,
|
||||||
withExchangeRatesActions,
|
withExchangeRatesActions,
|
||||||
withExchangeRates(({ exchangeRatesList, exchangeRatesLoading }) => ({
|
withExchangeRates(
|
||||||
exchangeRatesList,
|
({
|
||||||
exchangeRatesLoading,
|
exchangeRatesList,
|
||||||
})),
|
exchangeRatesLoading,
|
||||||
|
exchangeRatesPageination,
|
||||||
|
}) => ({
|
||||||
|
exchangeRatesList,
|
||||||
|
exchangeRatesLoading,
|
||||||
|
exchangeRatesPageination,
|
||||||
|
}),
|
||||||
|
),
|
||||||
)(ExchangeRateTable);
|
)(ExchangeRateTable);
|
||||||
|
|||||||
@@ -1,11 +1,24 @@
|
|||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { getExchangeRatesList } from 'store/ExchangeRate/exchange.selector';
|
import {
|
||||||
|
getExchangeRatesList,
|
||||||
|
getExchangeRatePaginationMetaFactory,
|
||||||
|
getExchangeRatesTableQueryFactory,
|
||||||
|
} from 'store/ExchangeRate/exchange.selector';
|
||||||
|
|
||||||
export default (mapState) => {
|
export default (mapState) => {
|
||||||
|
const getExchangeRatesPaginationMeta = getExchangeRatePaginationMetaFactory();
|
||||||
|
|
||||||
const mapStateToProps = (state, props) => {
|
const mapStateToProps = (state, props) => {
|
||||||
|
const query = getExchangeRatesTableQueryFactory(state, props);
|
||||||
|
|
||||||
const mapped = {
|
const mapped = {
|
||||||
exchangeRatesList: getExchangeRatesList(state, props),
|
exchangeRatesList: getExchangeRatesList(state, props),
|
||||||
exchangeRatesLoading: state.exchangeRates.loading,
|
exchangeRatesLoading: state.exchangeRates.loading,
|
||||||
|
exchangeRatesPageination: getExchangeRatesPaginationMeta(
|
||||||
|
state,
|
||||||
|
props,
|
||||||
|
query,
|
||||||
|
),
|
||||||
};
|
};
|
||||||
return mapState ? mapState(mapped, state, props) : mapped;
|
return mapState ? mapState(mapped, state, props) : mapped;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ export default {
|
|||||||
new_currency: 'New Currency',
|
new_currency: 'New Currency',
|
||||||
currency_name: 'Currency Name',
|
currency_name: 'Currency Name',
|
||||||
currency_code: 'Currency Code',
|
currency_code: 'Currency Code',
|
||||||
select_currency_code: 'select Currency Code',
|
select_currency_code: 'Select Currency Code',
|
||||||
edit_exchange_rate: 'Edit Exchange Rate',
|
edit_exchange_rate: 'Edit Exchange Rate',
|
||||||
new_exchange_rate: 'New Exchange Rate',
|
new_exchange_rate: 'New Exchange Rate',
|
||||||
delete_exchange_rate: 'Delete Exchange Rate',
|
delete_exchange_rate: 'Delete Exchange Rate',
|
||||||
|
|||||||
@@ -4,26 +4,40 @@ import t from 'store/types';
|
|||||||
export const fetchExchangeRates = () => {
|
export const fetchExchangeRates = () => {
|
||||||
return (dispatch) =>
|
return (dispatch) =>
|
||||||
new Promise((resolve, reject) => {
|
new Promise((resolve, reject) => {
|
||||||
dispatch({
|
|
||||||
type: t.SET_DASHBOARD_REQUEST_LOADING,
|
|
||||||
});
|
|
||||||
dispatch({
|
dispatch({
|
||||||
type: t.EXCHANGE_RATE_TABLE_LOADING,
|
type: t.EXCHANGE_RATE_TABLE_LOADING,
|
||||||
loading: true,
|
payload: {
|
||||||
|
loading: true,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
ApiService.get('exchange_rates')
|
ApiService.get('exchange_rates')
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
|
dispatch({
|
||||||
|
type: t.EXCHANGE_RATES_PAGE_SET,
|
||||||
|
payload: {
|
||||||
|
exchange_rates: response.data.exchange_rates.results,
|
||||||
|
pagination: response.data.exchange_rates.pagination,
|
||||||
|
customViewId: response.data.exchange_rates.customViewId || -1,
|
||||||
|
},
|
||||||
|
});
|
||||||
dispatch({
|
dispatch({
|
||||||
type: t.EXCHANGE_RATE_LIST_SET,
|
type: t.EXCHANGE_RATE_LIST_SET,
|
||||||
exchange_rates: response.data.exchange_rates.results,
|
exchange_rates: response.data.exchange_rates.results,
|
||||||
});
|
});
|
||||||
|
|
||||||
dispatch({
|
dispatch({
|
||||||
type: t.SET_DASHBOARD_REQUEST_COMPLETED,
|
type: t.EXCHANGE_RATES_PAGINATION_SET,
|
||||||
|
payload: {
|
||||||
|
pagination: response.data.exchange_rates.pagination,
|
||||||
|
customViewId: response.data.customViewId || -1,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
dispatch({
|
dispatch({
|
||||||
type: t.EXCHANGE_RATE_TABLE_LOADING,
|
type: t.EXCHANGE_RATE_TABLE_LOADING,
|
||||||
loading: false,
|
payload: {
|
||||||
|
loading: false,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
resolve(response);
|
resolve(response);
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,11 +1,18 @@
|
|||||||
import { createReducer } from '@reduxjs/toolkit';
|
import { createReducer } from '@reduxjs/toolkit';
|
||||||
|
import { createTableQueryReducers } from 'store/queryReducers';
|
||||||
import t from 'store/types';
|
import t from 'store/types';
|
||||||
|
|
||||||
const initialState = {
|
const initialState = {
|
||||||
exchangeRates: {},
|
exchangeRates: {},
|
||||||
|
loading: false,
|
||||||
|
tableQuery: {
|
||||||
|
page_size: 5,
|
||||||
|
page: 1,
|
||||||
|
},
|
||||||
|
currentViewId: -1,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default createReducer(initialState, {
|
const reducer = createReducer(initialState, {
|
||||||
[t.EXCHANGE_RATE_LIST_SET]: (state, action) => {
|
[t.EXCHANGE_RATE_LIST_SET]: (state, action) => {
|
||||||
const _exchangeRates = {};
|
const _exchangeRates = {};
|
||||||
action.exchange_rates.forEach((exchange_rate) => {
|
action.exchange_rates.forEach((exchange_rate) => {
|
||||||
@@ -17,8 +24,51 @@ export default createReducer(initialState, {
|
|||||||
..._exchangeRates,
|
..._exchangeRates,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
[t.EXCHANGE_RATE_TABLE_LOADING]: (state, action) => {
|
[t.EXCHANGE_RATE_TABLE_LOADING]: (state, action) => {
|
||||||
state.loading = action.loading;
|
|
||||||
|
const { loading } = action.payload;
|
||||||
|
state.loading = loading;
|
||||||
|
},
|
||||||
|
|
||||||
|
[t.ESTIMATES_PAGE_SET]: (state, action) => {
|
||||||
|
const { customViewId, exchange_rates, pagination } = action.payload;
|
||||||
|
|
||||||
|
const viewId = customViewId || -1;
|
||||||
|
const view = state.views[viewId] || {};
|
||||||
|
|
||||||
|
state.views[viewId] = {
|
||||||
|
...view,
|
||||||
|
pages: {
|
||||||
|
...(state.views?.[viewId]?.pages || {}),
|
||||||
|
[pagination.page]: {
|
||||||
|
ids: exchange_rates.map((i) => i.id),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
[t.EXCHANGE_RATES_PAGINATION_SET]: (state, action) => {
|
||||||
|
const { pagination, customViewId } = action.payload;
|
||||||
|
|
||||||
|
const mapped = {
|
||||||
|
pageSize: parseInt(pagination.pageSize, 10),
|
||||||
|
page: parseInt(pagination.page, 10),
|
||||||
|
total: parseInt(pagination.total, 10),
|
||||||
|
};
|
||||||
|
const paginationMeta = {
|
||||||
|
...mapped,
|
||||||
|
pagesCount: Math.ceil(mapped.total / mapped.pageSize),
|
||||||
|
pageIndex: Math.max(mapped.page - 1, 0),
|
||||||
|
};
|
||||||
|
|
||||||
|
state.views = {
|
||||||
|
...state.views,
|
||||||
|
[customViewId]: {
|
||||||
|
...(state.views?.[customViewId] || {}),
|
||||||
|
paginationMeta,
|
||||||
|
},
|
||||||
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
[t.EXCHANGE_RATES_BULK_DELETE]: (state, action) => {
|
[t.EXCHANGE_RATES_BULK_DELETE]: (state, action) => {
|
||||||
@@ -35,3 +85,5 @@ export default createReducer(initialState, {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export default createTableQueryReducers('exchange_rates', reducer);
|
||||||
|
|||||||
@@ -1,8 +1,18 @@
|
|||||||
import { createSelector } from 'reselect';
|
import { createSelector } from 'reselect';
|
||||||
import { pickItemsFromIds, getItemById } from 'store/selectors';
|
import {
|
||||||
|
pickItemsFromIds,
|
||||||
|
getItemById,
|
||||||
|
paginationLocationQuery,
|
||||||
|
} from 'store/selectors';
|
||||||
|
|
||||||
const exchangeRateItemsSelector = (state) => state.exchangeRates.exchangeRates;
|
const exchangeRateItemsSelector = (state) => state.exchangeRates.exchangeRates;
|
||||||
const exchangeRateIdPropSelector = (state, props) => props.exchangeRateId;
|
const exchangeRateIdPropSelector = (state, props) => props.exchangeRateId;
|
||||||
|
const exchangeRateTableQuery = (state) => state.exchangeRates.tableQuery;
|
||||||
|
|
||||||
|
const exchangeRatesCurrentViewSelector = (state, props) => {
|
||||||
|
const viewId = state.exchangeRates.currentViewId;
|
||||||
|
return state.exchangeRates.views?.[viewId];
|
||||||
|
};
|
||||||
|
|
||||||
export const getExchangeRatesList = createSelector(
|
export const getExchangeRatesList = createSelector(
|
||||||
exchangeRateItemsSelector,
|
exchangeRateItemsSelector,
|
||||||
@@ -18,3 +28,20 @@ export const getExchangeRateById = createSelector(
|
|||||||
return getItemById(exchangeRates, exchangeRateId);
|
return getItemById(exchangeRates, exchangeRateId);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export const getExchangeRatePaginationMetaFactory = () =>
|
||||||
|
createSelector(exchangeRatesCurrentViewSelector, (exchangeRateView) => {
|
||||||
|
return exchangeRateView?.paginationMeta || {};
|
||||||
|
});
|
||||||
|
|
||||||
|
export const getExchangeRatesTableQueryFactory = () =>
|
||||||
|
createSelector(
|
||||||
|
paginationLocationQuery,
|
||||||
|
exchangeRateTableQuery,
|
||||||
|
(locationQuery, tableQuery) => {
|
||||||
|
return {
|
||||||
|
...locationQuery,
|
||||||
|
...tableQuery,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ export default {
|
|||||||
EXCHANGE_RATE_LIST_SET: 'EXCHANGE_RATE_LIST_SET',
|
EXCHANGE_RATE_LIST_SET: 'EXCHANGE_RATE_LIST_SET',
|
||||||
CLEAR_EXCHANGE_RATE_FORM_ERRORS: 'CLEAR_EXCHANGE_RATE_FORM_ERRORS',
|
CLEAR_EXCHANGE_RATE_FORM_ERRORS: 'CLEAR_EXCHANGE_RATE_FORM_ERRORS',
|
||||||
ExchangeRates_TABLE_QUERIES_ADD: 'ExchangeRates_TABLE_QUERIES_ADD',
|
ExchangeRates_TABLE_QUERIES_ADD: 'ExchangeRates_TABLE_QUERIES_ADD',
|
||||||
EXCHANGE_RATE_TABLE_LOADING:'EXCHANGE_RATE_TABLE_LOADING',
|
EXCHANGE_RATE_TABLE_LOADING: 'EXCHANGE_RATE_TABLE_LOADING',
|
||||||
EXCHANGE_RATES_BULK_DELETE: 'EXCHANGE_RATES_BULK_DELETE',
|
EXCHANGE_RATES_BULK_DELETE: 'EXCHANGE_RATES_BULK_DELETE',
|
||||||
|
EXCHANGE_RATES_PAGE_SET: 'EXCHANGE_RATES_PAGE_SET',
|
||||||
|
EXCHANGE_RATES_PAGINATION_SET: 'EXCHANGE_RATES_PAGINATION_SET',
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -149,11 +149,11 @@ export const editAccount = (id, form) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const activateAccount = ({ id }) => {
|
export const activateAccount = ({ id }) => {
|
||||||
return (dispatch) => ApiService.post(`accounts/${id}/active`);
|
return (dispatch) => ApiService.post(`accounts/${id}/activate`);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const inactiveAccount = ({ id }) => {
|
export const inactiveAccount = ({ id }) => {
|
||||||
return (dispatch) => ApiService.post(`accounts/${id}/inactive`);
|
return (dispatch) => ApiService.post(`accounts/${id}/inactivate`);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const bulkActivateAccounts = ({ ids }) => {
|
export const bulkActivateAccounts = ({ ids }) => {
|
||||||
|
|||||||
@@ -4,20 +4,19 @@ import Currency from 'js-money/lib/currency';
|
|||||||
import PProgress from 'p-progress';
|
import PProgress from 'p-progress';
|
||||||
import accounting from 'accounting';
|
import accounting from 'accounting';
|
||||||
|
|
||||||
|
|
||||||
export function removeEmptyFromObject(obj) {
|
export function removeEmptyFromObject(obj) {
|
||||||
obj = Object.assign({}, obj);
|
obj = Object.assign({}, obj);
|
||||||
var keys = Object.keys(obj);
|
var keys = Object.keys(obj);
|
||||||
|
|
||||||
keys.forEach(function(key) {
|
keys.forEach(function (key) {
|
||||||
const value = obj[key];
|
const value = obj[key];
|
||||||
|
|
||||||
if (value === '' || value === null || value === undefined ) {
|
if (value === '' || value === null || value === undefined) {
|
||||||
delete obj[key];
|
delete obj[key];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return obj;
|
return obj;
|
||||||
};
|
}
|
||||||
|
|
||||||
export const optionsMapToArray = (optionsMap, service = '') => {
|
export const optionsMapToArray = (optionsMap, service = '') => {
|
||||||
return Object.keys(optionsMap).map((optionKey) => {
|
return Object.keys(optionsMap).map((optionKey) => {
|
||||||
@@ -27,7 +26,7 @@ export const optionsMapToArray = (optionsMap, service = '') => {
|
|||||||
key: service ? `${service}_${optionKey}` : `${optionKey}`,
|
key: service ? `${service}_${optionKey}` : `${optionKey}`,
|
||||||
value: optionValue,
|
value: optionValue,
|
||||||
};
|
};
|
||||||
})
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const optionsArrayToMap = (optionsArray) => {
|
export const optionsArrayToMap = (optionsArray) => {
|
||||||
@@ -37,7 +36,7 @@ export const optionsArrayToMap = (optionsArray) => {
|
|||||||
}, {});
|
}, {});
|
||||||
};
|
};
|
||||||
|
|
||||||
export function numberComma(number){
|
export function numberComma(number) {
|
||||||
number = typeof number === 'number' ? String(number) : number;
|
number = typeof number === 'number' ? String(number) : number;
|
||||||
|
|
||||||
const parts = number.split('.');
|
const parts = number.split('.');
|
||||||
@@ -51,11 +50,11 @@ export function numberComma(number){
|
|||||||
|
|
||||||
export const momentFormatter = (format) => {
|
export const momentFormatter = (format) => {
|
||||||
return {
|
return {
|
||||||
formatDate: date => moment(date).format(format),
|
formatDate: (date) => moment(date).format(format),
|
||||||
parseDate: str => moment(str, format).toDate(),
|
parseDate: (str) => moment(str, format).toDate(),
|
||||||
placeholder: `${format}`,
|
placeholder: `${format}`,
|
||||||
};
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
/** Event handler that exposes the target element's value as a boolean. */
|
/** Event handler that exposes the target element's value as a boolean. */
|
||||||
export const handleBooleanChange = (handler) => {
|
export const handleBooleanChange = (handler) => {
|
||||||
@@ -69,7 +68,7 @@ export const handleStringChange = (handler) => {
|
|||||||
|
|
||||||
/** Event handler that exposes the target element's value as a number. */
|
/** Event handler that exposes the target element's value as a number. */
|
||||||
export const handleNumberChange = (handler) => {
|
export const handleNumberChange = (handler) => {
|
||||||
return handleStringChange(value => handler(+value));
|
return handleStringChange((value) => handler(+value));
|
||||||
};
|
};
|
||||||
|
|
||||||
export const objectKeysTransform = (obj, transform) => {
|
export const objectKeysTransform = (obj, transform) => {
|
||||||
@@ -81,29 +80,35 @@ export const objectKeysTransform = (obj, transform) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const compose = (...funcs) =>
|
export const compose = (...funcs) =>
|
||||||
funcs.reduce((a, b) => (...args) => a(b(...args)), arg => arg);
|
funcs.reduce(
|
||||||
|
(a, b) => (...args) => a(b(...args)),
|
||||||
|
(arg) => arg,
|
||||||
|
);
|
||||||
|
|
||||||
export const getObjectDiff = (a, b) => {
|
export const getObjectDiff = (a, b) => {
|
||||||
return _.reduce(a, (result, value, key) => {
|
return _.reduce(
|
||||||
return _.isEqual(value, b[key]) ?
|
a,
|
||||||
result : result.concat(key);
|
(result, value, key) => {
|
||||||
}, []);
|
return _.isEqual(value, b[key]) ? result : result.concat(key);
|
||||||
}
|
},
|
||||||
|
[],
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
export const parseDateRangeQuery = (keyword) => {
|
export const parseDateRangeQuery = (keyword) => {
|
||||||
const queries = {
|
const queries = {
|
||||||
'today': {
|
today: {
|
||||||
range: 'day',
|
range: 'day',
|
||||||
},
|
},
|
||||||
'this_year': {
|
this_year: {
|
||||||
range: 'year',
|
range: 'year',
|
||||||
},
|
},
|
||||||
'this_month': {
|
this_month: {
|
||||||
range: 'month'
|
range: 'month',
|
||||||
|
},
|
||||||
|
this_week: {
|
||||||
|
range: 'week',
|
||||||
},
|
},
|
||||||
'this_week': {
|
|
||||||
range: 'week'
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if (typeof queries[keyword] === 'undefined') {
|
if (typeof queries[keyword] === 'undefined') {
|
||||||
@@ -117,7 +122,6 @@ export const parseDateRangeQuery = (keyword) => {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
export const defaultExpanderReducer = (tableRows, level) => {
|
export const defaultExpanderReducer = (tableRows, level) => {
|
||||||
let currentLevel = 1;
|
let currentLevel = 1;
|
||||||
const expended = [];
|
const expended = [];
|
||||||
@@ -135,7 +139,7 @@ export const defaultExpanderReducer = (tableRows, level) => {
|
|||||||
};
|
};
|
||||||
walker(tableRows);
|
walker(tableRows);
|
||||||
return expended;
|
return expended;
|
||||||
}
|
};
|
||||||
|
|
||||||
export function formattedAmount(cents, currency) {
|
export function formattedAmount(cents, currency) {
|
||||||
const { symbol, decimal_digits: precision } = Currency[currency];
|
const { symbol, decimal_digits: precision } = Currency[currency];
|
||||||
@@ -143,6 +147,17 @@ export function formattedAmount(cents, currency) {
|
|||||||
|
|
||||||
return accounting.formatMoney(amount, { symbol, precision });
|
return accounting.formatMoney(amount, { symbol, precision });
|
||||||
}
|
}
|
||||||
|
export function formattedExchangeRate(amount, currency) {
|
||||||
|
const options = {
|
||||||
|
style: 'currency',
|
||||||
|
currency: currency,
|
||||||
|
minimumFractionDigits: 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
const formatter = new Intl.NumberFormat(undefined, options);
|
||||||
|
|
||||||
|
return formatter.format(amount);
|
||||||
|
}
|
||||||
|
|
||||||
export const ConditionalWrapper = ({ condition, wrapper, children }) =>
|
export const ConditionalWrapper = ({ condition, wrapper, children }) =>
|
||||||
condition ? wrapper(children) : children;
|
condition ? wrapper(children) : children;
|
||||||
@@ -150,9 +165,9 @@ export const ConditionalWrapper = ({ condition, wrapper, children }) =>
|
|||||||
export const checkRequiredProperties = (obj, properties) => {
|
export const checkRequiredProperties = (obj, properties) => {
|
||||||
return properties.some((prop) => {
|
return properties.some((prop) => {
|
||||||
const value = obj[prop];
|
const value = obj[prop];
|
||||||
return (value === '' || value === null || value === undefined);
|
return value === '' || value === null || value === undefined;
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export const saveFilesInAsync = (files, actionCb, extraTasks) => {
|
export const saveFilesInAsync = (files, actionCb, extraTasks) => {
|
||||||
const opers = [];
|
const opers = [];
|
||||||
@@ -164,13 +179,17 @@ export const saveFilesInAsync = (files, actionCb, extraTasks) => {
|
|||||||
actionCb(formData, file, (requestProgress) => {
|
actionCb(formData, file, (requestProgress) => {
|
||||||
progress(requestProgress);
|
progress(requestProgress);
|
||||||
})
|
})
|
||||||
.then((data) => { resolve(data); })
|
.then((data) => {
|
||||||
.catch(error => { reject(error); })
|
resolve(data);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
reject(error);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
opers.push(oper);
|
opers.push(oper);
|
||||||
});
|
});
|
||||||
return PProgress.all(opers);
|
return PProgress.all(opers);
|
||||||
}
|
};
|
||||||
|
|
||||||
export const firstLettersArgs = (...args) => {
|
export const firstLettersArgs = (...args) => {
|
||||||
let letters = [];
|
let letters = [];
|
||||||
@@ -181,22 +200,18 @@ export const firstLettersArgs = (...args) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
return letters.join('').toUpperCase();
|
return letters.join('').toUpperCase();
|
||||||
}
|
};
|
||||||
|
|
||||||
|
|
||||||
export const uniqueMultiProps = (items, props) => {
|
export const uniqueMultiProps = (items, props) => {
|
||||||
return _.uniqBy(items, (item) => {
|
return _.uniqBy(items, (item) => {
|
||||||
return JSON.stringify(_.pick(item, props));
|
return JSON.stringify(_.pick(item, props));
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
|
|
||||||
export const transformUpdatedRows = (rows, rowIndex, columnIdOrObj, value) => {
|
export const transformUpdatedRows = (rows, rowIndex, columnIdOrObj, value) => {
|
||||||
const columnId =
|
const columnId = typeof columnIdOrObj !== 'object' ? columnIdOrObj : null;
|
||||||
typeof columnIdOrObj !== 'object' ? columnIdOrObj : null;
|
|
||||||
|
|
||||||
const updateTable =
|
const updateTable = typeof columnIdOrObj === 'object' ? columnIdOrObj : null;
|
||||||
typeof columnIdOrObj === 'object' ? columnIdOrObj : null;
|
|
||||||
|
|
||||||
const newData = updateTable ? updateTable : { [columnId]: value };
|
const newData = updateTable ? updateTable : { [columnId]: value };
|
||||||
|
|
||||||
@@ -206,7 +221,7 @@ export const transformUpdatedRows = (rows, rowIndex, columnIdOrObj, value) => {
|
|||||||
}
|
}
|
||||||
return { ...row };
|
return { ...row };
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export const tansformDateValue = (date) => {
|
export const tansformDateValue = (date) => {
|
||||||
return moment(date).toDate() || new Date();
|
return moment(date).toDate() || new Date();
|
||||||
@@ -222,7 +237,7 @@ export const repeatValue = (value, len) => {
|
|||||||
|
|
||||||
export const flatToNestedArray = (
|
export const flatToNestedArray = (
|
||||||
data,
|
data,
|
||||||
config = { id: 'id', parentId: 'parent_id' }
|
config = { id: 'id', parentId: 'parent_id' },
|
||||||
) => {
|
) => {
|
||||||
const map = {};
|
const map = {};
|
||||||
const nestedArray = [];
|
const nestedArray = [];
|
||||||
|
|||||||
Reference in New Issue
Block a user