From 3184bd7e75bc0800ff4945a29d964cc6b555ef63 Mon Sep 17 00:00:00 2001 From: elforjani3 Date: Sat, 7 Nov 2020 14:59:05 +0200 Subject: [PATCH] Fix: CurrencySelectList --- client/src/components/CurrencySelectList.js | 60 ++++ client/src/components/index.js | 3 + .../ExchangeRateFormDialogContent.js | 261 ++++++++++++++++++ .../containers/Expenses/ExpenseFormHeader.js | 50 +--- 4 files changed, 329 insertions(+), 45 deletions(-) create mode 100644 client/src/components/CurrencySelectList.js create mode 100644 client/src/containers/Dialogs/ExchangeRateFormDialog/ExchangeRateFormDialogContent.js diff --git a/client/src/components/CurrencySelectList.js b/client/src/components/CurrencySelectList.js new file mode 100644 index 000000000..dbcf8a43f --- /dev/null +++ b/client/src/components/CurrencySelectList.js @@ -0,0 +1,60 @@ +import React, { useCallback, useState, useEffect, useMemo } from 'react'; +import { FormattedMessage as T } from 'react-intl'; +import { ListSelect } from 'components'; +import { MenuItem } from '@blueprintjs/core'; + +export default function CurrencySelectList({ + currenciesList, + selectedCurrencyCode, + defaultSelectText = , + onCurrencySelected, + ...restProps +}) { + const [selectedCurrency, setSelectedCurrency] = useState(null); + + // Filters currencies list. + const filterCurrencies = (query, currency, _index, exactMatch) => { + const normalizedTitle = currency.currency_code.toLowerCase(); + const normalizedQuery = query.toLowerCase(); + + if (exactMatch) { + return normalizedTitle === normalizedQuery; + } else { + return ( + `${currency.currency_code} ${normalizedTitle}`.indexOf( + normalizedQuery, + ) >= 0 + ); + } + }; + + const onCurrencySelect = useCallback((currency) => { + setSelectedCurrency({ ...currency }); + onCurrencySelected && onCurrencySelected(currency); + }); + + const currencyCodeRenderer = useCallback((CurrencyCode, { handleClick }) => { + return ( + + ); + }, []); + + return ( + + ); +} diff --git a/client/src/components/index.js b/client/src/components/index.js index 31a83a3c1..00f0948bb 100644 --- a/client/src/components/index.js +++ b/client/src/components/index.js @@ -31,6 +31,8 @@ import Col from './Grid/Col'; import CloudLoadingIndicator from './CloudLoadingIndicator'; import MoneyExchangeRate from './MoneyExchangeRate'; import ContactSelecetList from './ContactSelecetList'; +import CurrencySelectList from './CurrencySelectList' + const Hint = FieldHint; @@ -69,4 +71,5 @@ export { CloudLoadingIndicator, MoneyExchangeRate, ContactSelecetList , + CurrencySelectList }; diff --git a/client/src/containers/Dialogs/ExchangeRateFormDialog/ExchangeRateFormDialogContent.js b/client/src/containers/Dialogs/ExchangeRateFormDialog/ExchangeRateFormDialogContent.js new file mode 100644 index 000000000..26aac7e70 --- /dev/null +++ b/client/src/containers/Dialogs/ExchangeRateFormDialog/ExchangeRateFormDialogContent.js @@ -0,0 +1,261 @@ +import React, { useState, useMemo, useCallback } from 'react'; +import { + Button, + Classes, + FormGroup, + InputGroup, + Intent, + Position, + MenuItem, +} from '@blueprintjs/core'; +import { pick } from 'lodash'; +import * as Yup from 'yup'; +import { useFormik } from 'formik'; +import { useQuery, queryCache } from 'react-query'; +import moment from 'moment'; +import { DateInput } from '@blueprintjs/datetime'; +import { FormattedMessage as T, useIntl } from 'react-intl'; +import { momentFormatter, tansformDateValue } from 'utils'; +import { + AppToaster, + Dialog, + ErrorMessage, + ListSelect, + DialogContent, + FieldRequiredHint, + CurrencySelectList, +} from 'components'; +import classNames from 'classnames'; +import withExchangeRateDetail from 'containers/ExchangeRates/withExchangeRateDetail'; +import withExchangeRatesActions from 'containers/ExchangeRates/withExchangeRatesActions'; + +import withCurrencies from 'containers/Currencies/withCurrencies'; +import withCurrenciesActions from 'containers/Currencies/withCurrenciesActions'; +import withDialogActions from 'containers/Dialog/withDialogActions'; + +import { compose } from 'utils'; + +function ExchangeRateFormDialogContent({ + // #withDialogActions + closeDialog, + + // #withCurrencies + currenciesList, + + //#WithExchangeRateDetail + exchangeRate, + + // #withExchangeRatesActions + requestSubmitExchangeRate, + requestEditExchangeRate, + + // #wihtCurrenciesActions + requestFetchCurrencies, + + // #ownProp + action, + exchangeRateId, + dialogName, +}) { + const { formatMessage } = useIntl(); + const [selectedItems, setSelectedItems] = useState({}); + + const fetchCurrencies = useQuery( + 'currencies', + () => requestFetchCurrencies(), + { enabled: true }, + ); + + const validationSchema = Yup.object().shape({ + exchange_rate: Yup.number() + .required() + .label(formatMessage({ id: 'exchange_rate_' })), + currency_code: Yup.string() + .max(3) + .required(formatMessage({ id: 'currency_code_' })), + date: Yup.date() + .required() + .label(formatMessage({ id: 'date' })), + }); + + const initialValues = useMemo( + () => ({ + exchange_rate: '', + currency_code: '', + date: moment(new Date()).format('YYYY-MM-DD'), + }), + [], + ); + + const { + values, + touched, + errors, + isSubmitting, + handleSubmit, + getFieldProps, + setFieldValue, + resetForm, + } = useFormik({ + enableReinitialize: true, + validationSchema, + initialValues: { + ...initialValues, + ...(action === 'edit' && pick(exchangeRate, Object.keys(initialValues))), + }, + onSubmit: (values, { setSubmitting, setErrors }) => { + if (action === 'edit') { + requestEditExchangeRate(exchangeRateId, values) + .then((response) => { + closeDialog(dialogName); + AppToaster.show({ + message: formatMessage({ + id: 'the_exchange_rate_has_been_successfully_edited', + }), + intent: Intent.SUCCESS, + }); + setSubmitting(false); + queryCache.invalidateQueries('exchange-rates-table'); + }) + .catch((error) => { + setSubmitting(false); + }); + } else { + requestSubmitExchangeRate(values) + .then((response) => { + closeDialog(dialogName); + AppToaster.show({ + message: formatMessage({ + id: 'the_exchange_rate_has_been_successfully_created', + }), + intent: Intent.SUCCESS, + }); + setSubmitting(false); + queryCache.invalidateQueries('exchange-rates-table'); + }) + .catch((errors) => { + if ( + errors.find((e) => e.type === 'EXCHANGE.RATE.DATE.PERIOD.DEFINED') + ) { + setErrors({ + exchange_rate: formatMessage({ + id: + 'there_is_exchange_rate_in_this_date_with_the_same_currency', + }), + }); + } + }); + } + }, + }); + + const handleClose = useCallback(() => { + closeDialog(dialogName); + resetForm(); + }, [dialogName, closeDialog]); + + const handleDateChange = useCallback( + (date_filed) => (date) => { + const formatted = moment(date).format('YYYY-MM-DD'); + setFieldValue(date_filed, formatted); + }, + [setFieldValue], + ); + + const onItemsSelect = useCallback( + (filedName) => { + return (filed) => { + setSelectedItems({ + ...selectedItems, + [filedName]: filed, + }); + setFieldValue(filedName, filed.currency_code); + }; + }, + [setFieldValue, selectedItems], + ); + return ( + +
+
+ } + inline={true} + labelInfo={FieldRequiredHint} + intent={errors.date && touched.date && Intent.DANGER} + helperText={} + > + + + } + labelInfo={FieldRequiredHint} + className={classNames('form-group--select-list', Classes.FILL)} + inline={true} + intent={ + errors.currency_code && touched.currency_code && Intent.DANGER + } + helperText={ + + } + > + + + } + labelInfo={FieldRequiredHint} + intent={ + errors.exchange_rate && touched.exchange_rate && Intent.DANGER + } + helperText={ + + } + inline={true} + > + + +
+
+
+ + +
+
+
+
+ ); +} + +export default compose( + withDialogActions, + withExchangeRatesActions, + withExchangeRateDetail, + withCurrenciesActions, + withCurrencies(({ currenciesList }) => ({ currenciesList })), +)(ExchangeRateFormDialogContent); diff --git a/client/src/containers/Expenses/ExpenseFormHeader.js b/client/src/containers/Expenses/ExpenseFormHeader.js index 1f128b644..e9b525dee 100644 --- a/client/src/containers/Expenses/ExpenseFormHeader.js +++ b/client/src/containers/Expenses/ExpenseFormHeader.js @@ -14,7 +14,7 @@ import moment from 'moment'; import { momentFormatter, compose, tansformDateValue } from 'utils'; import classNames from 'classnames'; import { - ListSelect, + CurrencySelectList, ContactSelecetList, ErrorMessage, AccountsSelectList, @@ -42,28 +42,6 @@ function ExpenseFormHeader({ [setFieldValue], ); - const currencyCodeRenderer = useCallback((item, { handleClick }) => { - return ( - - ); - }, []); - - // Filters Currency code. - const filterCurrencyCode = (query, currency, _index, exactMatch) => { - const normalizedTitle = currency.currency_code.toLowerCase(); - const normalizedQuery = query.toLowerCase(); - - if (exactMatch) { - return normalizedTitle === normalizedQuery; - } else { - return ( - `${currency.currency_code} ${normalizedTitle}`.indexOf( - normalizedQuery, - ) >= 0 - ); - } - }; - // Handles change account. const onChangeAccount = useCallback( (account) => { @@ -91,17 +69,6 @@ function ExpenseFormHeader({ [accountsList], ); - const CustomerRenderer = useCallback( - (cutomer, { handleClick }) => ( - - ), - [], - ); - // handle change customer const onChangeCustomer = useCallback( (filedName) => { @@ -205,17 +172,10 @@ function ExpenseFormHeader({ } > - } - itemRenderer={currencyCodeRenderer} - itemPredicate={filterCurrencyCode} - popoverProps={{ minimal: true }} - onItemSelect={onItemsSelect('currency_code')} - selectedItem={values.currency_code} - selectedItemProp={'currency_code'} - defaultText={} - labelProp={'currency_code'} +