From bfd4a86bf04426df0d2cfdef59bf47c922e8b18d Mon Sep 17 00:00:00 2001 From: elforjani3 Date: Tue, 9 Feb 2021 18:17:53 +0200 Subject: [PATCH] refactor: currency Form. --- .../CurencyFormDialogContent.js | 200 ------------------ .../CurrencyFormDialog/CurrencyForm.js | 97 +++++++++ .../CurrencyFormDialog/CurrencyForm.schema.js | 16 ++ .../CurrencyFormDialog/CurrencyFormContent.js | 14 ++ .../CurrencyFormDialogContent.js | 28 +++ .../CurrencyFormDialog/CurrencyFormFields.js | 62 ++++++ .../CurrencyFormDialog/CurrencyFormFooter.js | 37 ++++ .../CurrencyFormProvider.js | 38 ++++ .../Dialogs/CurrencyFormDialog/index.js | 2 +- client/src/hooks/query/currencies.js | 2 +- 10 files changed, 294 insertions(+), 202 deletions(-) delete mode 100644 client/src/containers/Dialogs/CurrencyFormDialog/CurencyFormDialogContent.js create mode 100644 client/src/containers/Dialogs/CurrencyFormDialog/CurrencyForm.js create mode 100644 client/src/containers/Dialogs/CurrencyFormDialog/CurrencyForm.schema.js create mode 100644 client/src/containers/Dialogs/CurrencyFormDialog/CurrencyFormContent.js create mode 100644 client/src/containers/Dialogs/CurrencyFormDialog/CurrencyFormDialogContent.js create mode 100644 client/src/containers/Dialogs/CurrencyFormDialog/CurrencyFormFields.js create mode 100644 client/src/containers/Dialogs/CurrencyFormDialog/CurrencyFormFooter.js create mode 100644 client/src/containers/Dialogs/CurrencyFormDialog/CurrencyFormProvider.js diff --git a/client/src/containers/Dialogs/CurrencyFormDialog/CurencyFormDialogContent.js b/client/src/containers/Dialogs/CurrencyFormDialog/CurencyFormDialogContent.js deleted file mode 100644 index 84e4046ec..000000000 --- a/client/src/containers/Dialogs/CurrencyFormDialog/CurencyFormDialogContent.js +++ /dev/null @@ -1,200 +0,0 @@ -import React, { useMemo, useCallback } from 'react'; -import { - Button, - Classes, - FormGroup, - InputGroup, - Intent, -} from '@blueprintjs/core'; -import * as Yup from 'yup'; -import { useFormik } from 'formik'; -import { useQuery, queryCache } from 'react-query'; -import { FormattedMessage as T, useIntl } from 'react-intl'; -import { pick } from 'lodash'; -import { - ErrorMessage, - AppToaster, - FieldRequiredHint, - DialogContent, -} from 'components'; - -import withDialogActions from 'containers/Dialog/withDialogActions'; -import withCurrencyDetail from 'containers/Currencies/withCurrencyDetail'; -import withCurrenciesActions from 'containers/Currencies/withCurrenciesActions'; - -import { compose } from 'utils'; - -import 'style/pages/Currency/CurrencyFormDialog.scss' - -function CurencyFormDialogContent({ - // #withCurrencyDetail - currency, - - // #wihtCurrenciesActions - requestFetchCurrencies, - requestSubmitCurrencies, - requestEditCurrency, - - // #withDialogActions - closeDialog, - - // #ownProp - action, - currencyId, - dialogName, -}) { - const { formatMessage } = useIntl(); - const fetchCurrencies = useQuery('currencies', () => - requestFetchCurrencies(), - ); - - const validationSchema = Yup.object().shape({ - currency_name: Yup.string() - .required() - .label(formatMessage({ id: 'currency_name_' })), - currency_code: Yup.string() - .max(4) - .required() - .label(formatMessage({ id: 'currency_code_' })), - }); - const initialValues = useMemo( - () => ({ - currency_name: '', - currency_code: '', - }), - [], - ); - const { - values, - errors, - touched, - isSubmitting, - getFieldProps, - handleSubmit, - resetForm, - } = useFormik({ - enableReinitialize: true, - initialValues: { - ...(action === 'edit' && pick(currency, Object.keys(initialValues))), - }, - validationSchema: validationSchema, - onSubmit: (values, { setSubmitting }) => { - if (action === 'edit') { - requestEditCurrency(currency.id, values) - .then((response) => { - closeDialog(dialogName); - AppToaster.show({ - message: formatMessage({ - id: 'the_currency_has_been_edited_successfully', - }), - intent: Intent.SUCCESS, - }); - setSubmitting(false); - queryCache.invalidateQueries('currencies'); - }) - .catch((error) => { - setSubmitting(false); - }); - } else { - requestSubmitCurrencies(values) - .then((response) => { - closeDialog(dialogName); - AppToaster.show({ - message: formatMessage({ - id: 'the_currency_has_been_created_successfully', - }), - intent: Intent.SUCCESS, - }); - setSubmitting(false); - queryCache.invalidateQueries('currencies'); - }) - .catch((error) => { - setSubmitting(false); - }); - } - }, - }); - const handleClose = useCallback(() => { - closeDialog(dialogName); - }, [dialogName, closeDialog]); - - const onDialogOpening = useCallback(() => { - fetchCurrencies.refetch(); - }, [fetchCurrencies]); - - const onDialogClosed = useCallback(() => { - resetForm(); - closeDialog(dialogName); - }, [closeDialog, dialogName, resetForm]); - - return ( - -
-
- } - labelInfo={FieldRequiredHint} - className={'form-group--currency-name'} - intent={ - errors.currency_name && touched.currency_name && Intent.DANGER - } - helperText={ - - } - inline={true} - > - - - - } - labelInfo={FieldRequiredHint} - className={'form-group--currency-code'} - intent={ - errors.currency_code && touched.currency_code && Intent.DANGER - } - helperText={ - - } - inline={true} - > - - -
- -
-
- - -
-
-
-
- ); -} - -export default compose( - withCurrencyDetail, - withDialogActions, - withCurrenciesActions, -)(CurencyFormDialogContent); diff --git a/client/src/containers/Dialogs/CurrencyFormDialog/CurrencyForm.js b/client/src/containers/Dialogs/CurrencyFormDialog/CurrencyForm.js new file mode 100644 index 000000000..440802aed --- /dev/null +++ b/client/src/containers/Dialogs/CurrencyFormDialog/CurrencyForm.js @@ -0,0 +1,97 @@ +import React, { useMemo, useCallback } from 'react'; +import { Intent } from '@blueprintjs/core'; +import { Formik } from 'formik'; +import { FormattedMessage as T, useIntl } from 'react-intl'; +import { AppToaster } from 'components'; +import { pick } from 'lodash'; +import CurrencyFormContent from './CurrencyFormContent'; + +import { useCurrencyFormContext } from './CurrencyFormProvider'; +import { + CreateCurrencyFormSchema, + EditCurrencyFormSchema, +} from './CurrencyForm.schema'; +import withDialogActions from 'containers/Dialog/withDialogActions'; + +import { compose, transformToForm } from 'utils'; + +const defaultInitialValues = { + currency_name: '', + currency_code: '', +}; + +/** + * Currency form. + */ +function CurrencyForm({ + // #withDialogActions + closeDialog, +}) { + const { formatMessage } = useIntl(); + + const { + createCurrencyMutate, + editCurrencyMutate, + dialogName, + currency, + isEditMode, + } = useCurrencyFormContext(); + + // Form validation schema in create and edit mode. + const validationSchema = isEditMode + ? EditCurrencyFormSchema + : CreateCurrencyFormSchema; + + const initialValues = useMemo( + () => ({ + ...defaultInitialValues, + // ...(isEditMode && pick(currency, Object.keys(defaultInitialValues))), + ...transformToForm(currency, defaultInitialValues), + }), + [], + ); + + // Handles the form submit. + const handleFormSubmit = (values, { setSubmitting, setErrors }) => { + setSubmitting(true); + + // Handle close the dialog after success response. + const afterSubmit = () => { + closeDialog(dialogName); + }; + + const onSuccess = ({ response }) => { + AppToaster.show({ + message: formatMessage({ + id: isEditMode + ? 'the_currency_has_been_edited_successfully' + : 'the_currency_has_been_created_successfully', + }), + intent: Intent.SUCCESS, + }); + afterSubmit(response); + }; + + // Handle the response error. + const onError = (errors) => { + setSubmitting(false); + }; + if (isEditMode) { + editCurrencyMutate([currency.id, values]).then(onSuccess).catch(onError); + } else { + createCurrencyMutate(values).then(onSuccess).catch(onError); + } + }; + + return ( + + + + ); +} + +export default compose(withDialogActions)(CurrencyForm); diff --git a/client/src/containers/Dialogs/CurrencyFormDialog/CurrencyForm.schema.js b/client/src/containers/Dialogs/CurrencyFormDialog/CurrencyForm.schema.js new file mode 100644 index 000000000..31c6dfe8b --- /dev/null +++ b/client/src/containers/Dialogs/CurrencyFormDialog/CurrencyForm.schema.js @@ -0,0 +1,16 @@ +import * as Yup from 'yup'; +import { formatMessage } from 'services/intl'; +import { DATATYPES_LENGTH } from 'common/dataTypes'; + +const Schema = Yup.object().shape({ + currency_name: Yup.string() + .required() + .label(formatMessage({ id: 'currency_name_' })), + currency_code: Yup.string() + .max(4) + .required() + .label(formatMessage({ id: 'currency_code_' })), +}); + +export const CreateCurrencyFormSchema = Schema; +export const EditCurrencyFormSchema = Schema; diff --git a/client/src/containers/Dialogs/CurrencyFormDialog/CurrencyFormContent.js b/client/src/containers/Dialogs/CurrencyFormDialog/CurrencyFormContent.js new file mode 100644 index 000000000..8b70d2add --- /dev/null +++ b/client/src/containers/Dialogs/CurrencyFormDialog/CurrencyFormContent.js @@ -0,0 +1,14 @@ +import React from 'react'; +import { Form } from 'formik'; + +import CurrencyFormFields from './CurrencyFormFields'; +import CurrencyFormFooter from './CurrencyFormFooter'; + +export default function CurrencyFormContent() { + return ( +
+ + + + ); +} diff --git a/client/src/containers/Dialogs/CurrencyFormDialog/CurrencyFormDialogContent.js b/client/src/containers/Dialogs/CurrencyFormDialog/CurrencyFormDialogContent.js new file mode 100644 index 000000000..439e16a71 --- /dev/null +++ b/client/src/containers/Dialogs/CurrencyFormDialog/CurrencyFormDialogContent.js @@ -0,0 +1,28 @@ +import React from 'react'; +import { CurrencyFormProvider } from './CurrencyFormProvider'; +import { pick } from 'lodash'; + +import CurrencyForm from './CurrencyForm'; +import withCurrencyDetail from 'containers/Currencies/withCurrencyDetail'; + +import { compose } from 'utils'; +import 'style/pages/Currency/CurrencyFormDialog.scss'; + +function CurrencyFormDialogContent({ + // #ownProp + action, + currency, + dialogName, +}) { + return ( + + + + ); +} + +export default compose(withCurrencyDetail)(CurrencyFormDialogContent); diff --git a/client/src/containers/Dialogs/CurrencyFormDialog/CurrencyFormFields.js b/client/src/containers/Dialogs/CurrencyFormDialog/CurrencyFormFields.js new file mode 100644 index 000000000..31f10bed2 --- /dev/null +++ b/client/src/containers/Dialogs/CurrencyFormDialog/CurrencyFormFields.js @@ -0,0 +1,62 @@ +import React, { useMemo, useCallback } from 'react'; +import { + Button, + Classes, + FormGroup, + InputGroup, + Intent, +} from '@blueprintjs/core'; +import { Form, useFormikContext, FastField } from 'formik'; +import { FormattedMessage as T, useIntl } from 'react-intl'; +import { pick } from 'lodash'; +import { + ErrorMessage, + AppToaster, + FieldRequiredHint, + DialogContent, +} from 'components'; + +import { useAutofocus } from 'hooks'; +import { inputIntent } from 'utils'; + +export default function CurrencyFormFields() { + const currencyNameFieldRef = useAutofocus(); + + return ( +
+ {/* ----------- Currency name ----------- */} + + {({ field, field: { value }, meta: { error, touched } }) => ( + } + labelInfo={} + className={'form-group--currency-name'} + intent={inputIntent({ error, touched })} + helperText={} + inline={true} + > + (currencyNameFieldRef.current = ref)} + {...field} + /> + + )} + + {/* ----------- Currency Code ----------- */} + + {({ field, field: { value }, meta: { error, touched } }) => ( + } + labelInfo={} + className={'form-group--currency-code'} + intent={inputIntent({ error, touched })} + helperText={} + inline={true} + > + + + )} + +
+ ); +} diff --git a/client/src/containers/Dialogs/CurrencyFormDialog/CurrencyFormFooter.js b/client/src/containers/Dialogs/CurrencyFormDialog/CurrencyFormFooter.js new file mode 100644 index 000000000..5191bbb5b --- /dev/null +++ b/client/src/containers/Dialogs/CurrencyFormDialog/CurrencyFormFooter.js @@ -0,0 +1,37 @@ +import React from 'react'; +import { useFormikContext } from 'formik'; +import { useCurrencyFormContext } from './CurrencyFormProvider'; + +import { Button, Classes, Intent } from '@blueprintjs/core'; +import { FormattedMessage as T } from 'react-intl'; + +import withDialogActions from 'containers/Dialog/withDialogActions'; +import { compose } from 'utils'; + +function CurrencyFormFooter({ + // #withDialogActions + closeDialog, +}) { + const { isSubmitting } = useFormikContext(); + + const { dialogName, isEditMode } = useCurrencyFormContext(); + + const handleClose = () => { + closeDialog(dialogName); + }; + + return ( +
+
+ + +
+
+ ); +} + +export default compose(withDialogActions)(CurrencyFormFooter); diff --git a/client/src/containers/Dialogs/CurrencyFormDialog/CurrencyFormProvider.js b/client/src/containers/Dialogs/CurrencyFormDialog/CurrencyFormProvider.js new file mode 100644 index 000000000..6098b5649 --- /dev/null +++ b/client/src/containers/Dialogs/CurrencyFormDialog/CurrencyFormProvider.js @@ -0,0 +1,38 @@ +import React, { createContext } from 'react'; +import { useCurrencies, useEditCurrency, useCreateCurrency } from 'hooks/query'; +import { DialogContent } from 'components'; + +const CurrencyFormContext = createContext(); + +/** + * Currency Form page provider. + */ + +function CurrencyFormProvider({ isEditMode, currency, dialogName, ...props }) { + // Create and edit item currency mutations. + const { mutateAsync: createCurrencyMutate } = useCreateCurrency(); + const { mutateAsync: editCurrencyMutate } = useEditCurrency(); + + // fetch Currencies list. + const { data: currencies, isFetching: isCurrenciesLoading } = useCurrencies(); + + // Provider state. + const provider = { + createCurrencyMutate, + editCurrencyMutate, + dialogName, + currency, + isCurrenciesLoading, + isEditMode, + }; + + return ( + + + + ); +} + +const useCurrencyFormContext = () => React.useContext(CurrencyFormContext); + +export { CurrencyFormProvider, useCurrencyFormContext }; diff --git a/client/src/containers/Dialogs/CurrencyFormDialog/index.js b/client/src/containers/Dialogs/CurrencyFormDialog/index.js index 19a1a82fc..f97747430 100644 --- a/client/src/containers/Dialogs/CurrencyFormDialog/index.js +++ b/client/src/containers/Dialogs/CurrencyFormDialog/index.js @@ -5,7 +5,7 @@ import withDialogRedux from 'components/DialogReduxConnect'; import { compose } from 'utils'; const CurrencyFormDialogContent = lazy(() => - import('./CurencyFormDialogContent'), + import('./CurrencyFormDialogContent'), ); /** diff --git a/client/src/hooks/query/currencies.js b/client/src/hooks/query/currencies.js index 47a6e3ef5..4dc2cac46 100644 --- a/client/src/hooks/query/currencies.js +++ b/client/src/hooks/query/currencies.js @@ -25,7 +25,7 @@ export function useCreateCurrency(props) { export function useEditCurrency(props) { const queryClient = useQueryClient(); - return useMutation((currencyCode, values) => + return useMutation(([currencyCode, values]) => ApiService.post(`currencies/${currencyCode}`, values), { onSuccess: () => {