Fix: Item Category Dialog

This commit is contained in:
elforjani3
2020-11-09 20:43:13 +02:00
parent f151e6242e
commit e4f720fe49
5 changed files with 109 additions and 244 deletions

View File

@@ -3,13 +3,13 @@ import React, { lazy } from 'react';
import AccountFormDialog from 'containers/Dialogs/AccountFormDialog'; import AccountFormDialog from 'containers/Dialogs/AccountFormDialog';
import UserFormDialog from 'containers/Dialogs/UserFormDialog'; 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 ExchangeRateFormDialog from 'containers/Dialogs/ExchangeRateFormDialog'; 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 PaymentReceiveNumberDialog from 'containers/Dialogs/PaymentReceiveNumberDialog';
import EstimateNumberDialog from 'containers/Dialogs/EstimateNumberDialog'; import EstimateNumberDialog from 'containers/Dialogs/EstimateNumberDialog';
import ReceiptNumberDialog from 'containers/Dialogs/ReceiptNumberDialog'; import ReceiptNumberDialog from 'containers/Dialogs/ReceiptNumberDialog';
import InvoiceNumberDialog from 'containers/Dialogs/InvoiceNumberDialog'; import InvoiceNumberDialog from 'containers/Dialogs/InvoiceNumberDialog';
@@ -18,14 +18,15 @@ export default function DialogsContainer() {
<div> <div>
<AccountFormDialog dialogName={'account-form'} /> <AccountFormDialog dialogName={'account-form'} />
<JournalNumberDialog dialogName={'journal-number-form'} /> <JournalNumberDialog dialogName={'journal-number-form'} />
<BillNumberDialog dialogName={'bill-number-form'} /> {/* <BillNumberDialog dialogName={'bill-number-form'} /> */}
<PaymentNumberDialog dialogName={'payment-number-form'} /> <PaymentReceiveNumberDialog dialogName={'payment-number-form'} />
<EstimateNumberDialog dialogName={'estimate-number-form'} /> <EstimateNumberDialog dialogName={'estimate-number-form'} />
<ReceiptNumberDialog dialogName={'receipt-number-form'} /> <ReceiptNumberDialog dialogName={'receipt-number-form'} />
<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'} /> <ExchangeRateFormDialog dialogName={'exchangeRate-form'} />
<ItemCategoryDialog dialogName={'item-category-form'} />
</div> </div>
); );
} }

View File

@@ -8,61 +8,61 @@ import {
TextArea, TextArea,
MenuItem, MenuItem,
} from '@blueprintjs/core'; } from '@blueprintjs/core';
import { Select } from '@blueprintjs/select';
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 { compose } from 'utils';
import { useQuery, queryCache } from 'react-query'; import { useQuery, queryCache } from 'react-query';
import { FormattedMessage as T, useIntl } from 'react-intl';
import classNames from 'classnames'; import classNames from 'classnames';
import { connect } from 'react-redux'; import {
ListSelect,
AccountsSelectList,
FieldRequiredHint,
Hint,
AppToaster,
ErrorMessage,
DialogContent,
} from 'components';
import AppToaster from 'components/AppToaster'; import withItemCategories from 'containers/Items/withItemCategories';
import ErrorMessage from 'components/ErrorMessage'; import withItemCategoryDetail from 'containers/Items/withItemCategoryDetail';
import { ListSelect, AccountsSelectList } from 'components'; import withItemCategoriesActions from 'containers/Items/withItemCategoriesActions';
import Dialog from 'components/Dialog';
import withDialogActions from 'containers/Dialog/withDialogActions';
import withDialogRedux from 'components/DialogReduxConnect';
import withAccounts from 'containers/Accounts/withAccounts'; import withAccounts from 'containers/Accounts/withAccounts';
import withAccountsActions from 'containers/Accounts/withAccountsActions'; import withAccountsActions from 'containers/Accounts/withAccountsActions';
import withItemCategoryDetail from 'containers/Items/withItemCategoryDetail';
import withItemCategories from 'containers/Items/withItemCategories';
import withItemCategoriesActions from 'containers/Items/withItemCategoriesActions';
import Icon from 'components/Icon'; import withDialogActions from 'containers/Dialog/withDialogActions';
import { compose } from 'utils';
function ItemCategoryDialog({ function ItemCategoryFormDialogContent({
dialogName, // #withDialogActions
payload = {},
isOpen,
// #withDialog
openDialog,
closeDialog, closeDialog,
// #withItemCategoryDetail // #withItemCategoryDetail
itemCategoryId,
itemCategory, itemCategory,
// #withItemCategories // #withItemCategories
categoriesList, categoriesList,
// #withItemCategoriesActions
requestSubmitItemCategory,
requestEditItemCategory,
requestFetchItemCategories,
//# withAccount //# withAccount
accountsList, accountsList,
// #withItemCategoriesActions
requestSubmitItemCategory,
requestFetchItemCategories,
requestEditItemCategory,
// #withAccountsActions // #withAccountsActions
requestFetchAccounts, requestFetchAccounts,
// #ownProp
action,
itemCategoryId,
dialogName,
}) { }) {
const [selectedParentCategory, setParentCategory] = useState(null);
const { formatMessage } = useIntl(); const { formatMessage } = useIntl();
const [selectedParentCategory, setParentCategory] = useState(null);
const fetchList = useQuery(['items-categories-list'], () => const fetchList = useQuery(['items-categories-list'], () =>
requestFetchItemCategories(), requestFetchItemCategories(),
@@ -101,34 +101,33 @@ function ItemCategoryDialog({
values, values,
errors, errors,
touched, touched,
isSubmitting,
setFieldValue, setFieldValue,
handleSubmit, handleSubmit,
resetForm,
getFieldProps, getFieldProps,
isSubmitting,
} = useFormik({ } = useFormik({
enableReinitialize: true, enableReinitialize: true,
initialValues: {
...(payload.action === 'edit' &&
pick(itemCategory, Object.keys(initialValues))),
},
validationSchema, validationSchema,
initialValues: {
...initialValues,
...(action === 'edit' && pick(itemCategory, Object.keys(initialValues))),
},
onSubmit: (values, { setSubmitting }) => { onSubmit: (values, { setSubmitting }) => {
const afterSubmit = () => { const afterSubmit = () => {
closeDialog(dialogName); closeDialog(dialogName);
queryCache.invalidateQueries('items-categories-list'); queryCache.invalidateQueries('items-categories-list');
queryCache.invalidateQueries('accounts-list'); queryCache.invalidateQueries('accounts-list');
}; };
if (payload.action === 'edit') { if (action === 'edit') {
requestEditItemCategory(payload.id, values) requestEditItemCategory(itemCategoryId, values)
.then((response) => { .then((response) => {
afterSubmit(response);
AppToaster.show({ AppToaster.show({
message: formatMessage({ message: formatMessage({
id: 'the_item_category_has_been_successfully_edited', id: 'the_item_category_has_been_successfully_edited',
}), }),
intent: Intent.SUCCESS, intent: Intent.SUCCESS,
}); });
afterSubmit(response);
}) })
.catch((error) => { .catch((error) => {
setSubmitting(false); setSubmitting(false);
@@ -136,13 +135,13 @@ function ItemCategoryDialog({
} else { } else {
requestSubmitItemCategory(values) requestSubmitItemCategory(values)
.then((response) => { .then((response) => {
afterSubmit(response);
AppToaster.show({ AppToaster.show({
message: formatMessage({ message: formatMessage({
id: 'the_item_category_has_been_successfully_created', id: 'the_item_category_has_been_successfully_created',
}), }),
intent: Intent.SUCCESS, intent: Intent.SUCCESS,
}); });
afterSubmit(response);
}) })
.catch((error) => { .catch((error) => {
setSubmitting(false); setSubmitting(false);
@@ -150,6 +149,7 @@ function ItemCategoryDialog({
} }
}, },
}); });
const filterItemCategory = useCallback( const filterItemCategory = useCallback(
(query, category, _index, exactMatch) => { (query, category, _index, exactMatch) => {
const normalizedTitle = category.name.toLowerCase(); const normalizedTitle = category.name.toLowerCase();
@@ -182,12 +182,6 @@ function ItemCategoryDialog({
closeDialog(dialogName); closeDialog(dialogName);
}, [dialogName, closeDialog]); }, [dialogName, closeDialog]);
// Handle the dialog opening.
const onDialogOpening = useCallback(() => {
fetchList.refetch();
fetchAccounts.refetch();
}, [fetchList, fetchAccounts]);
const onChangeParentCategory = useCallback( const onChangeParentCategory = useCallback(
(parentCategory) => { (parentCategory) => {
setParentCategory(parentCategory); setParentCategory(parentCategory);
@@ -205,41 +199,15 @@ function ItemCategoryDialog({
[setFieldValue], [setFieldValue],
); );
const onDialogClosed = useCallback(() => {
resetForm();
closeDialog(dialogName);
}, [resetForm, closeDialog, dialogName]);
const requiredSpan = useMemo(() => <span class="required">*</span>, []);
const infoIcon = useMemo(() => <Icon icon="info-circle" iconSize={12} />, []);
return ( return (
<Dialog <DialogContent isLoading={fetchList.isFetching || fetchAccounts.isFetching}>
name={dialogName}
title={
payload.action === 'edit' ? (
<T id={'edit_category'} />
) : (
<T id={'new_category'} />
)
}
className={classNames(
{
'dialog--loading': fetchList.isFetching || fetchAccounts.isFetching,
},
'dialog--category-form',
)}
isOpen={isOpen}
onClosed={onDialogClosed}
onOpening={onDialogOpening}
isLoading={fetchList.isFetching || fetchAccounts.isFetching}
onClose={handleClose}
>
<form onSubmit={handleSubmit}> <form onSubmit={handleSubmit}>
<div className={Classes.DIALOG_BODY}> <div className={Classes.DIALOG_BODY}>
{/* ----------- Category name ----------- */}
<FormGroup <FormGroup
label={<T id={'category_name'} />} label={<T id={'category_name'} />}
labelInfo={requiredSpan} labelInfo={FieldRequiredHint}
className={'form-group--category-name'} className={'form-group--category-name'}
intent={errors.name && touched.name && Intent.DANGER} intent={errors.name && touched.name && Intent.DANGER}
helperText={<ErrorMessage name="name" {...{ errors, touched }} />} helperText={<ErrorMessage name="name" {...{ errors, touched }} />}
@@ -251,10 +219,10 @@ function ItemCategoryDialog({
{...getFieldProps('name')} {...getFieldProps('name')}
/> />
</FormGroup> </FormGroup>
{/* ----------- Parent Category ----------- */}
<FormGroup <FormGroup
label={<T id={'parent_category'} />} label={<T id={'parent_category'} />}
labelInfo={infoIcon} labelInfo={Hint}
className={classNames( className={classNames(
'form-group--select-list', 'form-group--select-list',
'form-group--parent-category', 'form-group--parent-category',
@@ -286,7 +254,7 @@ function ItemCategoryDialog({
labelProp={'name'} labelProp={'name'}
/> />
</FormGroup> </FormGroup>
{/* ----------- Description ----------- */}
<FormGroup <FormGroup
label={<T id={'description'} />} label={<T id={'description'} />}
className={'form-group--description'} className={'form-group--description'}
@@ -302,8 +270,7 @@ function ItemCategoryDialog({
{...getFieldProps('description')} {...getFieldProps('description')}
/> />
</FormGroup> </FormGroup>
{/* ----------- Cost account ----------- */}
{/* cost account */}
<FormGroup <FormGroup
label={<T id={'cost_account'} />} label={<T id={'cost_account'} />}
inline={true} inline={true}
@@ -326,8 +293,7 @@ function ItemCategoryDialog({
selectedAccountId={values.cost_account_id} selectedAccountId={values.cost_account_id}
/> />
</FormGroup> </FormGroup>
{/* ----------- Sell account ----------- */}
{/* sell Account */}
<FormGroup <FormGroup
label={<T id={'sell_account'} />} label={<T id={'sell_account'} />}
inline={true} inline={true}
@@ -350,7 +316,7 @@ function ItemCategoryDialog({
selectedAccountId={values.sell_account_id} selectedAccountId={values.sell_account_id}
/> />
</FormGroup> </FormGroup>
{/* inventory Account */} {/* ----------- inventory account ----------- */}
<FormGroup <FormGroup
label={<T id={'inventory_account'} />} label={<T id={'inventory_account'} />}
inline={true} inline={true}
@@ -390,29 +356,16 @@ function ItemCategoryDialog({
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>
); );
} }
const mapStateToProps = (state, props) => ({
dialogName: 'item-category-form',
itemCategoryId: props?.payload?.id || null,
});
const withItemCategoryDialog = connect(mapStateToProps);
export default compose( export default compose(
withDialogRedux(null, 'item-category-form'),
withItemCategoryDialog,
withDialogActions, withDialogActions,
withItemCategoryDetail(), withItemCategoryDetail(),
withItemCategories(({ categoriesList }) => ({ withItemCategories(({ categoriesList }) => ({
@@ -423,4 +376,4 @@ export default compose(
})), })),
withItemCategoriesActions, withItemCategoriesActions,
withAccountsActions, withAccountsActions,
)(ItemCategoryDialog); )(ItemCategoryFormDialogContent);

View File

@@ -0,0 +1,46 @@
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 ItemCategoryFormDialogContent = lazy(() =>
import('./ItemCategoryFormDialogContent'),
);
/**
* Item Category form dialog.
*/
function ItemCategoryFormDialog({
dialogName,
payload = { action: '', id: null },
isOpen,
}) {
return (
<Dialog
name={dialogName}
title={
payload.action === 'edit' ? (
<T id={'edit_category'} />
) : (
<T id={'new_category'} />
)
}
className={'dialog--category-form'}
isOpen={isOpen}
autoFocus={true}
canEscapeKeyClose={true}
>
<DialogSuspense>
<ItemCategoryFormDialogContent
dialogName={dialogName}
action={payload.action}
itemCategoryId={payload.id}
/>
</DialogSuspense>
</Dialog>
);
}
export default compose(withDialogRedux())(ItemCategoryFormDialog);

View File

@@ -1,138 +0,0 @@
// import React, { useState } from 'react';
// import {
// Button,
// Classes,
// FormGroup,
// InputGroup,
// Intent,
// TextArea,
// } from '@blueprintjs/core';
// import * as Yup from 'yup';
// import { FormattedMessage as T, useIntl } from 'react-intl';
// import { useFormik } from 'formik';
// import { compose } from 'utils';
// import Dialog from 'components/Dialog';
// import useAsync from 'hooks/async';
// import AppToaster from 'components/AppToaster';
// import withDialog from 'containers/Dialogs/withDialog';
// import DialogReduxConnect from 'components/DialogReduxConnect';
// // import ItemFormDialogConnect from 'connectors/ItemFormDialog.connect';
// function ItemFromDialog({
// name,
// payload,
// isOpen,
// submitItemCategory,
// fetchCategory,
// openDialog,
// closeDialog,
// }) {
// const [state, setState] = useState({});
// const { formatMessage } = useIntl();
// const ValidationSchema = Yup.object().shape({
// name: Yup.string().required().label(formatMessage({id:'category_name_'})),
// description: Yup.string().trim(),
// });
// const formik = useFormik({
// enableReinitialize: true,
// initialValues: {},
// validationSchema: ValidationSchema,
// onSubmit: (values) => {
// submitItemCategory({ values })
// .then((response) => {
// AppToaster.show({
// message: formatMessage({id:'the_category_has_been_successfully_created'}),
// });
// })
// .catch((error) => {
// alert(error.message);
// });
// },
// });
// const fetchHook = useAsync(async () => {
// await Promise.all([submitItemCategory]);
// });
// const handleClose = () => {
// closeDialog(name);
// };
// const onDialogOpening = () => {
// fetchHook.execute();
// openDialog(name);
// };
// const onDialogClosed = () => {
// // formik.resetForm();
// closeDialog(name);
// };
// return (
// <Dialog
// name={name}
// title={
// payload.action === 'new' ? <T id={'new'} /> : <T id={'new_category'} />
// }
// className={{
// 'dialog--loading': state.isLoading,
// 'dialog--item-form': true,
// }}
// isOpen={isOpen}
// onClosed={onDialogClosed}
// onOpening={onDialogOpening}
// isLoading={fetchHook.pending}
// >
// <form onSubmit={formik.handleSubmit}>
// <div className={Classes.DIALOG_BODY}>
// <FormGroup
// label={<T id={'category_name'} />}
// className={'form-group--category-name'}
// intent={formik.errors.name && Intent.DANGER}
// helperText={formik.errors.name && formik.errors.name}
// inline={true}
// >
// <InputGroup
// medium={formik.values.toString()}
// intent={formik.errors.name && Intent.DANGER}
// {...formik.getFieldProps('name')}
// />
// </FormGroup>
// <FormGroup
// label={<T id={'description'} />}
// className={'form-group--description'}
// intent={formik.errors.description && Intent.DANGER}
// helperText={formik.errors.description && formik.errors.credential}
// inline={true}
// >
// <TextArea
// growVertically={true}
// large={true}
// {...formik.getFieldProps('description')}
// />
// </FormGroup>
// </div>
// <div className={Classes.DIALOG_FOOTER}>
// <div className={Classes.DIALOG_FOOTER_ACTIONS}>
// <Button onClick={handleClose}>
// <T id={'close'} />
// </Button>
// <Button intent={Intent.PRIMARY} type='submit'>
// {payload.action === 'new' ? (
// <T id={'new'} />
// ) : (
// <T id={'submit'} />
// )}
// </Button>
// </div>
// </div>
// </form>
// </Dialog>
// );
// }
// export default compose(
// // ItemFormDialogConnect,
// withDialog,
// DialogReduxConnect
// )(ItemFromDialog);

View File

@@ -219,6 +219,8 @@ export default {
'The item category has been successfully edited.', 'The item category has been successfully edited.',
the_item_category_has_been_successfully_deleted: the_item_category_has_been_successfully_deleted:
'The item category has been successfully deleted', 'The item category has been successfully deleted',
once_delete_these_item_categories_you_will_not_able_restore_them:
"Once you delete these categories, you won't be able to retrieve them later. Are you sure you want to delete them?",
once_delete_these_views_you_will_not_able_restore_them: once_delete_these_views_you_will_not_able_restore_them:
"Once you delete the custom view, you won't be able to restore it later. Are you sure you want to delete this view?", "Once you delete the custom view, you won't be able to restore it later. Are you sure you want to delete this view?",
the_custom_view_has_been_successfully_deleted: the_custom_view_has_been_successfully_deleted:
@@ -346,7 +348,7 @@ export default {
once_delete_this_currency_you_will_able_to_restore_it: `Once you delete this currency, you won\'t be able to restore it later. Are you sure you want to delete this currency?`, once_delete_this_currency_you_will_able_to_restore_it: `Once you delete this currency, you won\'t be able to restore it later. Are you sure you want to delete this currency?`,
once_delete_this_exchange_rate_you_will_able_to_restore_it: `Once you delete this exchange rate, you won\'t be able to restore it later. Are you sure you want to delete this exchange rate?`, once_delete_this_exchange_rate_you_will_able_to_restore_it: `Once you delete this exchange rate, you won\'t be able to restore it later. Are you sure you want to delete this exchange rate?`,
once_delete_these_exchange_rates_you_will_not_able_restore_them: `Once you delete these exchange rates, you won't be able to retrieve them later. Are you sure you want to delete them?`, once_delete_these_exchange_rates_you_will_not_able_restore_them: `Once you delete these exchange rates, you won't be able to retrieve them later. Are you sure you want to delete them?`,
once_delete_this_item_category_you_will_able_to_restore_it: `Once you delete this item, you won\'t be able to restore it later. Are you sure you want to delete this item?`, once_delete_this_item_category_you_will_able_to_restore_it: `Once you delete this category, you won\'t be able to restore it later. Are you sure you want to delete this item?`,
select_business_location: 'Select Business Location', select_business_location: 'Select Business Location',
select_base_currency: 'Select Base Currency', select_base_currency: 'Select Base Currency',
select_fiscal_year: 'Select Fiscal Year', select_fiscal_year: 'Select Fiscal Year',
@@ -807,4 +809,5 @@ export default {
notes: 'Notes', notes: 'Notes',
i_purchase_this_item: 'I purchase this item from a vendor.', i_purchase_this_item: 'I purchase this item from a vendor.',
i_sell_this_item: 'I sell this item to a customer.', i_sell_this_item: 'I sell this item to a customer.',
select_display_name_as:'Select display name as',
}; };