mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-20 06:40:31 +00:00
refactoring: migrating to react-query to manage service-side state.
This commit is contained in:
@@ -3,24 +3,29 @@ import { Intent } from '@blueprintjs/core';
|
||||
import { Formik } from 'formik';
|
||||
import { useIntl } from 'react-intl';
|
||||
import { omit } from 'lodash';
|
||||
import { useQuery, queryCache } from 'react-query';
|
||||
import { AppToaster, DialogContent } from 'components';
|
||||
|
||||
import AccountFormDialogFields from './AccountFormDialogFields';
|
||||
|
||||
import withAccountsActions from 'containers/Accounts/withAccountsActions';
|
||||
import withAccountDetail from 'containers/Accounts/withAccountDetail';
|
||||
import withDialogActions from 'containers/Dialog/withDialogActions';
|
||||
import {
|
||||
EditAccountFormSchema,
|
||||
CreateAccountFormSchema,
|
||||
} from './AccountForm.schema';
|
||||
|
||||
import {
|
||||
useAccounts,
|
||||
useAccountsTypes,
|
||||
useCreateAccount,
|
||||
useAccount,
|
||||
useEditAccount
|
||||
} from 'hooks/query';
|
||||
import { compose, transformToForm } from 'utils';
|
||||
import { transformApiErrors, transformAccountToForm } from './utils';
|
||||
|
||||
import 'style/pages/Accounts/AccountFormDialog.scss';
|
||||
|
||||
|
||||
// Default initial form values.
|
||||
const defaultInitialValues = {
|
||||
account_type: '',
|
||||
parent_account_id: '',
|
||||
@@ -34,16 +39,7 @@ const defaultInitialValues = {
|
||||
* Account form dialog content.
|
||||
*/
|
||||
function AccountFormDialogContent({
|
||||
// #withAccountDetail
|
||||
account,
|
||||
|
||||
// #withAccountsActions
|
||||
requestFetchAccounts,
|
||||
requestFetchAccountTypes,
|
||||
requestFetchAccount,
|
||||
requestSubmitAccount,
|
||||
requestEditAccount,
|
||||
|
||||
// #withDialogActions
|
||||
closeDialog,
|
||||
|
||||
// #ownProp
|
||||
@@ -61,6 +57,27 @@ function AccountFormDialogContent({
|
||||
? CreateAccountFormSchema
|
||||
: EditAccountFormSchema;
|
||||
|
||||
const { mutateAsync: createAccountMutate } = useCreateAccount();
|
||||
const { mutateAsync: editAccountMutate } = useEditAccount();
|
||||
|
||||
// Fetches accounts list.
|
||||
const {
|
||||
data: accounts,
|
||||
isLoading: isAccountsLoading,
|
||||
} = useAccounts();
|
||||
|
||||
// Fetches accounts types.
|
||||
const {
|
||||
data: accountsTypes,
|
||||
isLoading: isAccountsTypesLoading
|
||||
} = useAccountsTypes();
|
||||
|
||||
// Fetches the specific account details.
|
||||
const {
|
||||
data: account,
|
||||
isLoading: isAccountLoading,
|
||||
} = useAccount(accountId, { enabled: !!accountId });
|
||||
|
||||
// Callbacks handles form submit.
|
||||
const handleFormSubmit = (values, { setSubmitting, setErrors }) => {
|
||||
const form = omit(values, ['subaccount']);
|
||||
@@ -71,11 +88,6 @@ function AccountFormDialogContent({
|
||||
// Handle request success.
|
||||
const handleSuccess = () => {
|
||||
closeDialog(dialogName);
|
||||
queryCache.invalidateQueries('accounts-table');
|
||||
|
||||
setTimeout(() => {
|
||||
queryCache.invalidateQueries('accounts-list');
|
||||
}, 1000);
|
||||
|
||||
AppToaster.show({
|
||||
message: formatMessage(
|
||||
@@ -94,16 +106,16 @@ function AccountFormDialogContent({
|
||||
};
|
||||
// Handle request error.
|
||||
const handleError = (errors) => {
|
||||
const errorsTransformed = transformApiErrors(errors);
|
||||
setErrors({ ...errorsTransformed });
|
||||
setSubmitting(false);
|
||||
// const errorsTransformed = transformApiErrors(errors);
|
||||
// setErrors({ ...errorsTransformed });
|
||||
// setSubmitting(false);
|
||||
};
|
||||
if (accountId) {
|
||||
requestEditAccount(accountId, form)
|
||||
editAccountMutate(accountId, form)
|
||||
.then(handleSuccess)
|
||||
.catch(handleError);
|
||||
} else {
|
||||
requestSubmitAccount({ form }).then(handleSuccess).catch(handleError);
|
||||
createAccountMutate({ ...form }).then(handleSuccess).catch(handleError);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -130,27 +142,10 @@ function AccountFormDialogContent({
|
||||
closeDialog(dialogName);
|
||||
}, [closeDialog, dialogName]);
|
||||
|
||||
// Fetches accounts list.
|
||||
const fetchAccountsList = useQuery('accounts-list', () =>
|
||||
requestFetchAccounts(),
|
||||
);
|
||||
|
||||
// Fetches accounts types.
|
||||
const fetchAccountsTypes = useQuery('accounts-types-list', () =>
|
||||
requestFetchAccountTypes(),
|
||||
);
|
||||
|
||||
// Fetch the given account id on edit mode.
|
||||
const fetchAccount = useQuery(
|
||||
['account', accountId],
|
||||
(key, _id) => requestFetchAccount(_id),
|
||||
{ enabled: accountId },
|
||||
);
|
||||
|
||||
const isFetching =
|
||||
fetchAccountsList.isFetching ||
|
||||
fetchAccountsTypes.isFetching ||
|
||||
fetchAccount.isFetching;
|
||||
isAccountsLoading ||
|
||||
isAccountsTypesLoading ||
|
||||
isAccountLoading;
|
||||
|
||||
return (
|
||||
<DialogContent isLoading={isFetching}>
|
||||
@@ -160,6 +155,8 @@ function AccountFormDialogContent({
|
||||
onSubmit={handleFormSubmit}
|
||||
>
|
||||
<AccountFormDialogFields
|
||||
accounts={accounts}
|
||||
accountsTypes={accountsTypes}
|
||||
dialogName={dialogName}
|
||||
action={action}
|
||||
onClose={handleClose}
|
||||
@@ -170,7 +167,5 @@ function AccountFormDialogContent({
|
||||
}
|
||||
|
||||
export default compose(
|
||||
withAccountsActions,
|
||||
withAccountDetail,
|
||||
withDialogActions,
|
||||
)(AccountFormDialogContent);
|
||||
|
||||
@@ -28,11 +28,9 @@ import { useAutofocus } from 'hooks';
|
||||
* Account form dialogs fields.
|
||||
*/
|
||||
function AccountFormDialogFields({
|
||||
// #ownPropscl
|
||||
// #ownProps
|
||||
onClose,
|
||||
action,
|
||||
|
||||
// #withAccounts
|
||||
accounts,
|
||||
accountsTypes,
|
||||
}) {
|
||||
|
||||
@@ -4,10 +4,16 @@ import { FormGroup, InputGroup } from '@blueprintjs/core';
|
||||
import { inputIntent } from 'utils';
|
||||
import { Row, Col, MoneyInputGroup } from 'components';
|
||||
import { FormattedMessage as T } from 'react-intl';
|
||||
import { useAutofocus } from 'hooks';
|
||||
import { decrementQuantity } from './utils';
|
||||
import { toSafeNumber } from 'utils';
|
||||
|
||||
/**
|
||||
* Decrement adjustment fields.
|
||||
*/
|
||||
function DecrementAdjustmentFields() {
|
||||
const decrementFieldRef = useAutofocus();
|
||||
|
||||
return (
|
||||
<Row className={'row--decrement-fields'}>
|
||||
{/*------------ Quantity on hand -----------*/}
|
||||
@@ -47,6 +53,7 @@ function DecrementAdjustmentFields() {
|
||||
value={field.value}
|
||||
allowDecimals={false}
|
||||
allowNegativeValue={true}
|
||||
inputRef={(ref) => (decrementFieldRef.current = ref)}
|
||||
onChange={(value) => {
|
||||
setFieldValue('quantity', value);
|
||||
}}
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
import React from 'react';
|
||||
import { Field, FastField, ErrorMessage } from 'formik';
|
||||
import { FormGroup, InputGroup } from '@blueprintjs/core';
|
||||
import { useAutofocus } from 'hooks';
|
||||
import { Row, Col, MoneyInputGroup } from 'components';
|
||||
import { inputIntent, toSafeNumber } from 'utils';
|
||||
import { FormattedMessage as T } from 'react-intl';
|
||||
import { decrementQuantity, incrementQuantity } from './utils';
|
||||
|
||||
function IncrementAdjustmentFields() {
|
||||
export default function IncrementAdjustmentFields() {
|
||||
const incrementFieldRef = useAutofocus();
|
||||
|
||||
return (
|
||||
<Row>
|
||||
{/*------------ Quantity on hand -----------*/}
|
||||
@@ -47,6 +50,7 @@ function IncrementAdjustmentFields() {
|
||||
value={field.value}
|
||||
allowDecimals={false}
|
||||
allowNegativeValue={true}
|
||||
inputRef={(ref) => (incrementFieldRef.current = ref)}
|
||||
onChange={(value) => {
|
||||
setFieldValue('quantity', value);
|
||||
}}
|
||||
@@ -131,5 +135,3 @@ function IncrementAdjustmentFields() {
|
||||
</Row>
|
||||
);
|
||||
}
|
||||
|
||||
export default IncrementAdjustmentFields;
|
||||
|
||||
@@ -2,29 +2,45 @@ import React from 'react';
|
||||
import { Intent, Button, Classes } from '@blueprintjs/core';
|
||||
import { useFormikContext } from 'formik';
|
||||
import { FormattedMessage as T } from 'react-intl';
|
||||
import { saveInvoke } from 'utils';
|
||||
|
||||
export default function InventoryAdjustmentFloatingActions({
|
||||
onCloseClick,
|
||||
onSubmitClick,
|
||||
import { useInventoryAdjContext } from './InventoryAdjustmentFormProvider';
|
||||
import withDialogActions from 'containers/Dialog/withDialogActions';
|
||||
import { compose } from 'utils';
|
||||
|
||||
/**
|
||||
* Inventory adjustment floating actions.
|
||||
*/
|
||||
function InventoryAdjustmentFloatingActions({
|
||||
// #withDialogActions
|
||||
closeDialog,
|
||||
}) {
|
||||
const { isSubmitting } = useFormikContext();
|
||||
// Formik context.
|
||||
const { isSubmitting, submitForm } = useFormikContext();
|
||||
|
||||
// Inventory adjustment dialog context.
|
||||
const { dialogName, setSubmitPayload } = useInventoryAdjContext();
|
||||
|
||||
// handle submit as draft button click.
|
||||
const handleSubmitDraftBtnClick = (event) => {
|
||||
saveInvoke(onSubmitClick, event, {
|
||||
publish: false,
|
||||
});
|
||||
setSubmitPayload({ publish: false });
|
||||
submitForm();
|
||||
};
|
||||
|
||||
// Handle submit make adjustment button click.
|
||||
const handleSubmitMakeAdjustmentBtnClick = (event) => {
|
||||
saveInvoke(onSubmitClick, event, {
|
||||
publish: true,
|
||||
});
|
||||
setSubmitPayload({ publish: true });
|
||||
submitForm();
|
||||
};
|
||||
|
||||
// Handle close button click.
|
||||
const handleCloseBtnClick = (event) => {
|
||||
closeDialog(dialogName)
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={Classes.DIALOG_FOOTER}>
|
||||
<div className={Classes.DIALOG_FOOTER_ACTIONS}>
|
||||
<Button onClick={onCloseClick} style={{ minWidth: '75px' }}>
|
||||
<Button onClick={handleCloseBtnClick} style={{ minWidth: '75px' }}>
|
||||
<T id={'close'} />
|
||||
</Button>
|
||||
|
||||
@@ -49,3 +65,7 @@ export default function InventoryAdjustmentFloatingActions({
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default compose(
|
||||
withDialogActions
|
||||
)(InventoryAdjustmentFloatingActions);
|
||||
@@ -0,0 +1,90 @@
|
||||
import React from 'react';
|
||||
import moment from 'moment';
|
||||
import { Intent } from '@blueprintjs/core';
|
||||
import { Formik } from 'formik';
|
||||
import { omit, get } from 'lodash';
|
||||
import { useIntl } from 'react-intl';
|
||||
|
||||
import 'style/pages/Items/ItemAdjustmentDialog.scss';
|
||||
|
||||
import { AppToaster } from 'components';
|
||||
import { CreateInventoryAdjustmentFormSchema } from './InventoryAdjustmentForm.schema';
|
||||
|
||||
import InventoryAdjustmentFormContent from './InventoryAdjustmentFormContent';
|
||||
import { useInventoryAdjContext } from './InventoryAdjustmentFormProvider';
|
||||
|
||||
import withDialogActions from 'containers/Dialog/withDialogActions';
|
||||
import { compose } from 'utils';
|
||||
|
||||
const defaultInitialValues = {
|
||||
date: moment(new Date()).format('YYYY-MM-DD'),
|
||||
type: 'decrement',
|
||||
adjustment_account_id: '',
|
||||
item_id: '',
|
||||
reason: '',
|
||||
cost: '',
|
||||
quantity: '',
|
||||
reference_no: '',
|
||||
quantity_on_hand: '',
|
||||
publish: '',
|
||||
};
|
||||
|
||||
/**
|
||||
* Inventory adjustment form.
|
||||
*/
|
||||
function InventoryAdjustmentForm({
|
||||
// #withDialogActions
|
||||
closeDialog,
|
||||
}) {
|
||||
const {
|
||||
dialogName,
|
||||
item,
|
||||
itemId,
|
||||
submitPayload,
|
||||
createInventoryAdjMutate,
|
||||
} = useInventoryAdjContext();
|
||||
|
||||
const { formatMessage } = useIntl();
|
||||
|
||||
// Initial form values.
|
||||
const initialValues = {
|
||||
...defaultInitialValues,
|
||||
item_id: itemId,
|
||||
quantity_on_hand: get(item, 'quantity_on_hand', 0),
|
||||
};
|
||||
|
||||
// Handles the form submit.
|
||||
const handleFormSubmit = (values, { setSubmitting, setErrors }) => {
|
||||
const form = {
|
||||
...omit(values, ['quantity_on_hand', 'new_quantity', 'action']),
|
||||
publish: submitPayload.publish,
|
||||
};
|
||||
setSubmitting(true);
|
||||
createInventoryAdjMutate(form)
|
||||
.then(() => {
|
||||
closeDialog(dialogName);
|
||||
|
||||
AppToaster.show({
|
||||
message: formatMessage({
|
||||
id: 'the_make_adjustment_has_been_created_successfully',
|
||||
}),
|
||||
intent: Intent.SUCCESS,
|
||||
});
|
||||
})
|
||||
.finally(() => {
|
||||
setSubmitting(true);
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<Formik
|
||||
validationSchema={CreateInventoryAdjustmentFormSchema}
|
||||
initialValues={initialValues}
|
||||
onSubmit={handleFormSubmit}
|
||||
>
|
||||
<InventoryAdjustmentFormContent />
|
||||
</Formik>
|
||||
);
|
||||
}
|
||||
|
||||
export default compose(withDialogActions)(InventoryAdjustmentForm);
|
||||
@@ -0,0 +1,16 @@
|
||||
import React from 'react';
|
||||
import { Form } from 'formik';
|
||||
import InventoryAdjustmentFormDialogFields from './InventoryAdjustmentFormDialogFields';
|
||||
import InventoryAdjustmentFloatingActions from './InventoryAdjustmentFloatingActions';
|
||||
|
||||
/**
|
||||
* Inventory adjustment form content.
|
||||
*/
|
||||
export default function InventoryAdjustmentFormContent() {
|
||||
return (
|
||||
<Form>
|
||||
<InventoryAdjustmentFormDialogFields />
|
||||
<InventoryAdjustmentFloatingActions />
|
||||
</Form>
|
||||
);
|
||||
}
|
||||
@@ -1,142 +1,21 @@
|
||||
import React, { useState, useCallback } from 'react';
|
||||
import { Intent } from '@blueprintjs/core';
|
||||
import { Formik, Form } from 'formik';
|
||||
import { useIntl } from 'react-intl';
|
||||
import { useQuery, queryCache } from 'react-query';
|
||||
import moment from 'moment';
|
||||
import { omit, get } from 'lodash';
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import 'style/pages/Items/ItemAdjustmentDialog.scss';
|
||||
|
||||
import { AppToaster, DialogContent } from 'components';
|
||||
|
||||
import { CreateInventoryAdjustmentFormSchema } from './InventoryAdjustmentForm.schema';
|
||||
|
||||
import InventoryAdjustmentFormDialogFields from './InventoryAdjustmentFormDialogFields';
|
||||
import InventoryAdjustmentFloatingActions from './InventoryAdjustmentFloatingActions';
|
||||
|
||||
import withDialogActions from 'containers/Dialog/withDialogActions';
|
||||
import withInventoryAdjustmentActions from 'containers/Items/withInventoryAdjustmentActions';
|
||||
import withAccountsActions from 'containers/Accounts/withAccountsActions';
|
||||
import withItem from 'containers/Items/withItem';
|
||||
import withItemsActions from 'containers/Items/withItemsActions';
|
||||
|
||||
import { compose } from 'utils';
|
||||
|
||||
const defaultInitialValues = {
|
||||
date: moment(new Date()).format('YYYY-MM-DD'),
|
||||
type: 'decrement',
|
||||
adjustment_account_id: '',
|
||||
item_id: '',
|
||||
reason: '',
|
||||
cost: '',
|
||||
quantity: '',
|
||||
reference_no: '',
|
||||
quantity_on_hand: '',
|
||||
publish: '',
|
||||
};
|
||||
|
||||
import { InventoryAdjustmentFormProvider } from './InventoryAdjustmentFormProvider';
|
||||
import InventoryAdjustmentForm from './InventoryAdjustmentForm';
|
||||
|
||||
/**
|
||||
* Inventory adjustment form dialog content.
|
||||
*/
|
||||
function InventoryAdjustmentFormDialogContent({
|
||||
// #withDialogActions
|
||||
closeDialog,
|
||||
|
||||
// #withAccountsActions
|
||||
requestFetchAccounts,
|
||||
|
||||
// #withInventoryAdjustmentActions
|
||||
requestSubmitInventoryAdjustment,
|
||||
|
||||
// #withItemsActions
|
||||
requestFetchItem,
|
||||
|
||||
// #withItem
|
||||
item,
|
||||
|
||||
// #ownProp
|
||||
itemId,
|
||||
export default function InventoryAdjustmentFormDialogContent({
|
||||
// #ownProps
|
||||
dialogName,
|
||||
itemId
|
||||
}) {
|
||||
const { formatMessage } = useIntl();
|
||||
const [submitPayload, setSubmitPayload] = useState({});
|
||||
|
||||
// Fetches accounts list.
|
||||
const fetchAccount = useQuery('accounts-list', () => requestFetchAccounts());
|
||||
|
||||
// Fetches the item details.
|
||||
const fetchItem = useQuery(['item', itemId],
|
||||
(key, id) => requestFetchItem(id));
|
||||
|
||||
// Initial form values.
|
||||
const initialValues = {
|
||||
...defaultInitialValues,
|
||||
item_id: itemId,
|
||||
quantity_on_hand: get(item, 'quantity_on_hand', 0),
|
||||
};
|
||||
|
||||
// Handles the form submit.
|
||||
const handleFormSubmit = (values, { setSubmitting, setErrors }) => {
|
||||
const form = {
|
||||
...omit(values, ['quantity_on_hand', 'new_quantity', 'action']),
|
||||
publish: submitPayload.publish,
|
||||
};
|
||||
const onSuccess = ({ response }) => {
|
||||
closeDialog(dialogName);
|
||||
queryCache.invalidateQueries('accounts-list');
|
||||
queryCache.invalidateQueries('items-table');
|
||||
|
||||
AppToaster.show({
|
||||
message: formatMessage({
|
||||
id: 'the_make_adjustment_has_been_created_successfully',
|
||||
}),
|
||||
intent: Intent.SUCCESS,
|
||||
});
|
||||
};
|
||||
const onError = (error) => {
|
||||
setSubmitting(false);
|
||||
};
|
||||
requestSubmitInventoryAdjustment({ form }).then(onSuccess).catch(onError);
|
||||
};
|
||||
|
||||
// Handles dialog close.
|
||||
const handleCloseClick = useCallback(() => {
|
||||
closeDialog(dialogName);
|
||||
}, [closeDialog, dialogName]);
|
||||
|
||||
const handleSubmitClick = useCallback(
|
||||
(event, payload) => {
|
||||
setSubmitPayload({ ...payload });
|
||||
},
|
||||
[setSubmitPayload],
|
||||
);
|
||||
|
||||
return (
|
||||
<DialogContent isLoading={fetchAccount.isFetching || fetchItem.isFetching}>
|
||||
<Formik
|
||||
validationSchema={CreateInventoryAdjustmentFormSchema}
|
||||
initialValues={initialValues}
|
||||
onSubmit={handleFormSubmit}
|
||||
>
|
||||
<Form>
|
||||
<InventoryAdjustmentFormDialogFields dialogName={dialogName} />
|
||||
<InventoryAdjustmentFloatingActions
|
||||
onSubmitClick={handleSubmitClick}
|
||||
onCloseClick={handleCloseClick}
|
||||
/>
|
||||
</Form>
|
||||
</Formik>
|
||||
</DialogContent>
|
||||
<InventoryAdjustmentFormProvider itemId={itemId} dialogName={dialogName}>
|
||||
<InventoryAdjustmentForm />
|
||||
</InventoryAdjustmentFormProvider>
|
||||
);
|
||||
}
|
||||
|
||||
export default compose(
|
||||
withInventoryAdjustmentActions,
|
||||
withDialogActions,
|
||||
withAccountsActions,
|
||||
withItem(({ item }) => ({
|
||||
item: item
|
||||
})),
|
||||
withItemsActions,
|
||||
)(InventoryAdjustmentFormDialogContent);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React from 'react';
|
||||
import { FastField, ErrorMessage, Field, useFormikContext } from 'formik';
|
||||
import { FastField, ErrorMessage, Field } from 'formik';
|
||||
import {
|
||||
Classes,
|
||||
FormGroup,
|
||||
@@ -10,7 +10,7 @@ import {
|
||||
import classNames from 'classnames';
|
||||
import { FormattedMessage as T, useIntl } from 'react-intl';
|
||||
import { DateInput } from '@blueprintjs/datetime';
|
||||
import { compose } from 'redux';
|
||||
import { useAutofocus } from 'hooks';
|
||||
import { ListSelect, FieldRequiredHint, Col, Row } from 'components';
|
||||
import {
|
||||
inputIntent,
|
||||
@@ -23,18 +23,20 @@ import { CLASSES } from 'common/classes';
|
||||
import adjustmentType from 'common/adjustmentType';
|
||||
|
||||
import AccountsSuggestField from 'components/AccountsSuggestField';
|
||||
import withAccounts from 'containers/Accounts/withAccounts';
|
||||
import { useInventoryAdjContext } from './InventoryAdjustmentFormProvider'
|
||||
import { diffQuantity } from './utils';
|
||||
import InventoryAdjustmentQuantityFields from './InventoryAdjustmentQuantityFields';
|
||||
|
||||
/**
|
||||
* Inventory adjustment form dialogs fields.
|
||||
*/
|
||||
function InventoryAdjustmentFormDialogFields({
|
||||
//# withAccount
|
||||
accountsList,
|
||||
}) {
|
||||
const { values } = useFormikContext();
|
||||
export default function InventoryAdjustmentFormDialogFields() {
|
||||
const dateFieldRef = useAutofocus();
|
||||
|
||||
// Inventory adjustment dialog context.
|
||||
const { accounts } = useInventoryAdjContext();
|
||||
|
||||
// Intl context.
|
||||
const { formatMessage } = useIntl();
|
||||
|
||||
return (
|
||||
@@ -62,6 +64,7 @@ function InventoryAdjustmentFormDialogFields({
|
||||
position: Position.BOTTOM,
|
||||
minimal: true,
|
||||
}}
|
||||
inputRef={(ref) => (dateFieldRef.current = ref)}
|
||||
/>
|
||||
</FormGroup>
|
||||
)}
|
||||
@@ -115,7 +118,7 @@ function InventoryAdjustmentFormDialogFields({
|
||||
className={'form-group--adjustment-account'}
|
||||
>
|
||||
<AccountsSuggestField
|
||||
accounts={accountsList}
|
||||
accounts={accounts}
|
||||
onAccountSelected={(item) =>
|
||||
form.setFieldValue('adjustment_account_id', item.id)
|
||||
}
|
||||
@@ -159,9 +162,3 @@ function InventoryAdjustmentFormDialogFields({
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default compose(
|
||||
withAccounts(({ accountsList }) => ({
|
||||
accountsList,
|
||||
})),
|
||||
)(InventoryAdjustmentFormDialogFields);
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
import React, { useState, createContext } from 'react';
|
||||
import { DialogContent } from 'components';
|
||||
import {
|
||||
useItem,
|
||||
useAccounts,
|
||||
useCreateInventoryAdjustment,
|
||||
} from 'hooks/query';
|
||||
|
||||
const InventoryAdjustmentContext = createContext();
|
||||
|
||||
/**
|
||||
* Inventory adjustment dialog provider.
|
||||
*/
|
||||
function InventoryAdjustmentFormProvider({ itemId, dialogName, ...props }) {
|
||||
// Fetches accounts list.
|
||||
const { isFetching: isAccountsLoading, data: accounts } = useAccounts();
|
||||
|
||||
// Fetches the item details.
|
||||
const { isFetching: isItemLoading, data: item } = useItem(itemId);
|
||||
|
||||
const {
|
||||
mutateAsync: createInventoryAdjMutate,
|
||||
} = useCreateInventoryAdjustment();
|
||||
|
||||
// Submit payload.
|
||||
const [submitPayload, setSubmitPayload] = useState({});
|
||||
|
||||
// State provider.
|
||||
const provider = {
|
||||
itemId,
|
||||
isAccountsLoading,
|
||||
accounts,
|
||||
isItemLoading,
|
||||
item,
|
||||
submitPayload,
|
||||
dialogName,
|
||||
|
||||
createInventoryAdjMutate,
|
||||
setSubmitPayload,
|
||||
};
|
||||
|
||||
return (
|
||||
<DialogContent isLoading={isAccountsLoading || isItemLoading}>
|
||||
<InventoryAdjustmentContext.Provider value={provider} {...props} />
|
||||
</DialogContent>
|
||||
);
|
||||
}
|
||||
|
||||
const useInventoryAdjContext = () => React.useContext(InventoryAdjustmentContext);
|
||||
|
||||
export { InventoryAdjustmentFormProvider, useInventoryAdjContext };
|
||||
@@ -1,165 +1,111 @@
|
||||
import React, { useCallback } from 'react';
|
||||
import {
|
||||
Button,
|
||||
Classes,
|
||||
FormGroup,
|
||||
InputGroup,
|
||||
Intent,
|
||||
TextArea,
|
||||
MenuItem,
|
||||
} from '@blueprintjs/core';
|
||||
import { FormattedMessage as T } from 'react-intl';
|
||||
import classNames from 'classnames';
|
||||
import { ErrorMessage, Form, FastField } from 'formik';
|
||||
import {
|
||||
ListSelect,
|
||||
AccountsSelectList,
|
||||
FieldRequiredHint,
|
||||
Hint,
|
||||
} from 'components';
|
||||
import { inputIntent } from 'utils';
|
||||
import React, { useMemo } from 'react';
|
||||
import { useIntl } from 'react-intl';
|
||||
import { Intent } from '@blueprintjs/core';
|
||||
import { Formik } from 'formik';
|
||||
|
||||
import { useAutofocus } from 'hooks';
|
||||
import { AppToaster } from 'components';
|
||||
import { useItemCategoryContext } from './ItemCategoryProvider';
|
||||
import { transformToForm } from 'utils';
|
||||
import {
|
||||
CreateItemCategoryFormSchema,
|
||||
EditItemCategoryFormSchema,
|
||||
} from './ItemCategoryForm.schema';
|
||||
|
||||
export default function ItemCategoryForm({
|
||||
itemCategoryId,
|
||||
accountsList,
|
||||
categoriesList,
|
||||
isSubmitting,
|
||||
onClose,
|
||||
import withDialogActions from 'containers/Dialog/withDialogActions';
|
||||
import ItemCategoryFormContent from './ItemCategoryFormContent'
|
||||
import { compose } from 'utils';
|
||||
|
||||
const defaultInitialValues = {
|
||||
name: '',
|
||||
description: '',
|
||||
cost_account_id: '',
|
||||
sell_account_id: '',
|
||||
inventory_account_id: '',
|
||||
};
|
||||
|
||||
/**
|
||||
* Item category form.
|
||||
*/
|
||||
function ItemCategoryForm({
|
||||
// #withDialogActions
|
||||
closeDialog,
|
||||
}) {
|
||||
const categoryNameFieldRef = useAutofocus();
|
||||
const { formatMessage } = useIntl();
|
||||
const {
|
||||
isNewMode,
|
||||
itemCategory,
|
||||
itemCategoryId,
|
||||
dialogName,
|
||||
createItemCategoryMutate,
|
||||
editItemCategoryMutate,
|
||||
} = useItemCategoryContext();
|
||||
|
||||
// Initial values.
|
||||
const initialValues = useMemo(
|
||||
() => ({
|
||||
...defaultInitialValues,
|
||||
...transformToForm(itemCategory, defaultInitialValues),
|
||||
}),
|
||||
[itemCategory],
|
||||
);
|
||||
|
||||
// Transformes response errors.
|
||||
const transformErrors = (errors, { setErrors }) => {
|
||||
if (errors.find((error) => error.type === 'CATEGORY_NAME_EXISTS')) {
|
||||
setErrors({
|
||||
name: formatMessage({ id: 'category_name_exists' }),
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// Handles the form submit.
|
||||
const handleFormSubmit = (values, { setSubmitting, setErrors }) => {
|
||||
setSubmitting(true);
|
||||
const form = { ...values };
|
||||
|
||||
// Handle close the dialog after success response.
|
||||
const afterSubmit = () => {
|
||||
closeDialog(dialogName);
|
||||
};
|
||||
// Handle the response success/
|
||||
const onSuccess = ({ response }) => {
|
||||
AppToaster.show({
|
||||
message: formatMessage({
|
||||
id: isNewMode
|
||||
? 'the_item_category_has_been_created_successfully'
|
||||
: 'the_item_category_has_been_edited_successfully',
|
||||
}),
|
||||
intent: Intent.SUCCESS,
|
||||
});
|
||||
afterSubmit(response);
|
||||
};
|
||||
// Handle the response error.
|
||||
const onError = (errors) => {
|
||||
transformErrors(errors, { setErrors });
|
||||
setSubmitting(false);
|
||||
};
|
||||
if (isNewMode) {
|
||||
createItemCategoryMutate(form).then(onSuccess).catch(onError);
|
||||
} else {
|
||||
editItemCategoryMutate([itemCategoryId, form])
|
||||
.then(onSuccess)
|
||||
.catch(onError);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Form>
|
||||
<div className={Classes.DIALOG_BODY}>
|
||||
{/* ----------- Category name ----------- */}
|
||||
<FastField name={'name'}>
|
||||
{({ field, field: { value }, meta: { error, touched } }) => (
|
||||
<FormGroup
|
||||
label={<T id={'category_name'} />}
|
||||
labelInfo={<FieldRequiredHint />}
|
||||
className={'form-group--category-name'}
|
||||
intent={inputIntent({ error, touched })}
|
||||
helperText={<ErrorMessage name="name" />}
|
||||
inline={true}
|
||||
>
|
||||
<InputGroup
|
||||
medium={true}
|
||||
inputRef={(ref) => (categoryNameFieldRef.current = ref)}
|
||||
{...field}
|
||||
/>
|
||||
</FormGroup>
|
||||
)}
|
||||
</FastField>
|
||||
|
||||
|
||||
{/* ----------- Description ----------- */}
|
||||
<FastField name={'description'}>
|
||||
{({ field, field: { value }, meta: { error, touched } }) => (
|
||||
<FormGroup
|
||||
label={<T id={'description'} />}
|
||||
className={'form-group--description'}
|
||||
intent={inputIntent({ error, touched })}
|
||||
helperText={<ErrorMessage name="description" />}
|
||||
inline={true}
|
||||
>
|
||||
<TextArea growVertically={true} large={true} {...field} />
|
||||
</FormGroup>
|
||||
)}
|
||||
</FastField>
|
||||
|
||||
{/* ----------- Cost account ----------- */}
|
||||
<FastField name={'cost_account_id'}>
|
||||
{({ form, field: { value }, meta: { error, touched } }) => (
|
||||
<FormGroup
|
||||
label={<T id={'cost_account'} />}
|
||||
inline={true}
|
||||
intent={inputIntent({ error, touched })}
|
||||
helperText={<ErrorMessage name="cost_account_id" />}
|
||||
className={classNames(
|
||||
'form-group--cost-account',
|
||||
'form-group--select-list',
|
||||
Classes.FILL,
|
||||
)}
|
||||
>
|
||||
<AccountsSelectList
|
||||
accounts={accountsList}
|
||||
onAccountSelected={(account) => {
|
||||
form.setFieldValue('cost_account_id', account.id);
|
||||
}}
|
||||
defaultSelectText={<T id={'select_account'} />}
|
||||
selectedAccountId={value}
|
||||
filterByTypes={['cost_of_goods_sold']}
|
||||
/>
|
||||
</FormGroup>
|
||||
)}
|
||||
</FastField>
|
||||
|
||||
{/* ----------- Sell account ----------- */}
|
||||
<FastField name={'sell_account_id'}>
|
||||
{({ form, field: { value }, meta: { error, touched } }) => (
|
||||
<FormGroup
|
||||
label={<T id={'sell_account'} />}
|
||||
inline={true}
|
||||
intent={inputIntent({ error, touched })}
|
||||
helperText={<ErrorMessage name="sell_account_id" />}
|
||||
className={classNames(
|
||||
'form-group--sell-account',
|
||||
'form-group--select-list',
|
||||
Classes.FILL,
|
||||
)}
|
||||
>
|
||||
<AccountsSelectList
|
||||
accounts={accountsList}
|
||||
onAccountSelected={(account) => {
|
||||
form.setFieldValue('sell_account_id', account.id);
|
||||
}}
|
||||
defaultSelectText={<T id={'select_account'} />}
|
||||
selectedAccountId={value}
|
||||
filterByTypes={['income']}
|
||||
/>
|
||||
</FormGroup>
|
||||
)}
|
||||
</FastField>
|
||||
|
||||
{/* ----------- inventory account ----------- */}
|
||||
<FastField name={'inventory_account_id'}>
|
||||
{({ form, field: { value }, meta: { error, touched } }) => (
|
||||
<FormGroup
|
||||
label={<T id={'inventory_account'} />}
|
||||
inline={true}
|
||||
intent={inputIntent({ error, touched })}
|
||||
helperText={<ErrorMessage name="inventory_account_id" />}
|
||||
className={classNames(
|
||||
'form-group--sell-account',
|
||||
'form-group--select-list',
|
||||
Classes.FILL,
|
||||
)}
|
||||
>
|
||||
<AccountsSelectList
|
||||
accounts={accountsList}
|
||||
onAccountSelected={(account) => {
|
||||
form.setFieldValue('inventory_account_id', account.id);
|
||||
}}
|
||||
defaultSelectText={<T id={'select_account'} />}
|
||||
selectedAccountId={value}
|
||||
/>
|
||||
</FormGroup>
|
||||
)}
|
||||
</FastField>
|
||||
</div>
|
||||
|
||||
<div className={Classes.DIALOG_FOOTER}>
|
||||
<div className={Classes.DIALOG_FOOTER_ACTIONS}>
|
||||
<Button onClick={onClose}>
|
||||
<T id={'close'} />
|
||||
</Button>
|
||||
<Button intent={Intent.PRIMARY} type="submit" disabled={isSubmitting}>
|
||||
{itemCategoryId ? <T id={'edit'} /> : <T id={'submit'} />}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</Form>
|
||||
<Formik
|
||||
validationSchema={
|
||||
isNewMode ? CreateItemCategoryFormSchema : EditItemCategoryFormSchema
|
||||
}
|
||||
initialValues={initialValues}
|
||||
onSubmit={handleFormSubmit}
|
||||
>
|
||||
<ItemCategoryFormContent />
|
||||
</Formik>
|
||||
);
|
||||
}
|
||||
|
||||
export default compose(
|
||||
withDialogActions,
|
||||
)(ItemCategoryForm);
|
||||
@@ -0,0 +1,13 @@
|
||||
import React from 'react';
|
||||
import { Form } from 'formik';
|
||||
import ItemCategoryFormFields from './ItemCategoryFormFields';
|
||||
import ItemCategoryFormFooter from './ItemCategoryFormFooter';
|
||||
|
||||
export default function ItemCategoryForm() {
|
||||
return (
|
||||
<Form>
|
||||
<ItemCategoryFormFields />
|
||||
<ItemCategoryFormFooter />
|
||||
</Form>
|
||||
);
|
||||
}
|
||||
@@ -1,168 +1,23 @@
|
||||
import React, { useMemo, useCallback } from 'react';
|
||||
import { Intent } from '@blueprintjs/core';
|
||||
import { useQuery, queryCache } from 'react-query';
|
||||
import { FormattedMessage as T, useIntl } from 'react-intl';
|
||||
import { Formik } from 'formik';
|
||||
import { AppToaster, DialogContent } from 'components';
|
||||
|
||||
import React from 'react';
|
||||
import { ItemCategoryProvider } from './ItemCategoryProvider';
|
||||
import ItemCategoryForm from './ItemCategoryForm';
|
||||
import withItemCategories from 'containers/Items/withItemCategories';
|
||||
import withItemCategoryDetail from 'containers/Items/withItemCategoryDetail';
|
||||
import withItemCategoriesActions from 'containers/Items/withItemCategoriesActions';
|
||||
|
||||
import withAccounts from 'containers/Accounts/withAccounts';
|
||||
import withAccountsActions from 'containers/Accounts/withAccountsActions';
|
||||
import withDialogActions from 'containers/Dialog/withDialogActions';
|
||||
|
||||
import {
|
||||
EditItemCategoryFormSchema,
|
||||
CreateItemCategoryFormSchema,
|
||||
} from './itemCategoryForm.schema';
|
||||
import { compose, transformToForm } from 'utils';
|
||||
|
||||
import 'style/pages/ItemCategory/ItemCategoryDialog.scss'
|
||||
|
||||
const defaultInitialValues = {
|
||||
name: '',
|
||||
description: '',
|
||||
cost_account_id: '',
|
||||
sell_account_id: '',
|
||||
inventory_account_id: '',
|
||||
};
|
||||
import 'style/pages/ItemCategory/ItemCategoryDialog.scss';
|
||||
|
||||
/**
|
||||
* Item Category form dialog content.
|
||||
*/
|
||||
|
||||
function ItemCategoryFormDialogContent({
|
||||
// #withDialogActions
|
||||
closeDialog,
|
||||
|
||||
// #withItemCategoryDetail
|
||||
itemCategoryDetail,
|
||||
|
||||
// #withItemCategories
|
||||
categoriesList,
|
||||
|
||||
// #withItemCategoriesActions
|
||||
requestSubmitItemCategory,
|
||||
requestEditItemCategory,
|
||||
requestFetchItemCategories,
|
||||
|
||||
//# withAccount
|
||||
accountsList,
|
||||
|
||||
// #withAccountsActions
|
||||
requestFetchAccounts,
|
||||
|
||||
export default function ItemCategoryFormDialogContent({
|
||||
// #ownProp
|
||||
action,
|
||||
itemCategoryId,
|
||||
dialogName,
|
||||
}) {
|
||||
const isNewMode = !itemCategoryId;
|
||||
|
||||
const { formatMessage } = useIntl();
|
||||
|
||||
// Fetches categories list.
|
||||
const fetchCategoriesList = useQuery(['items-categories-list'], () =>
|
||||
requestFetchItemCategories(),
|
||||
);
|
||||
|
||||
// Fetches accounts list.
|
||||
const fetchAccountsList = useQuery('accounts-list', () =>
|
||||
requestFetchAccounts(),
|
||||
);
|
||||
|
||||
const initialValues = useMemo(
|
||||
() => ({
|
||||
...defaultInitialValues,
|
||||
...transformToForm(itemCategoryDetail, defaultInitialValues),
|
||||
}),
|
||||
[],
|
||||
);
|
||||
|
||||
const transformErrors = (errors, { setErrors }) => {
|
||||
if (errors.find((error) => error.type === 'CATEGORY_NAME_EXISTS')) {
|
||||
setErrors({
|
||||
name: formatMessage({ id: 'category_name_exists' }),
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// Handles the form submit.
|
||||
const handleFormSubmit = (values, { setSubmitting, setErrors }) => {
|
||||
setSubmitting(true);
|
||||
const form = { ...values };
|
||||
const afterSubmit = () => {
|
||||
closeDialog(dialogName);
|
||||
queryCache.invalidateQueries('items-categories-list');
|
||||
queryCache.invalidateQueries('accounts-list');
|
||||
};
|
||||
const onSuccess = ({ response }) => {
|
||||
AppToaster.show({
|
||||
message: formatMessage({
|
||||
id: isNewMode
|
||||
? 'the_item_category_has_been_created_successfully'
|
||||
: 'the_item_category_has_been_edited_successfully',
|
||||
}),
|
||||
intent: Intent.SUCCESS,
|
||||
});
|
||||
afterSubmit(response);
|
||||
};
|
||||
|
||||
const onError = (errors) => {
|
||||
transformErrors(errors, { setErrors });
|
||||
setSubmitting(false);
|
||||
};
|
||||
if (isNewMode) {
|
||||
requestSubmitItemCategory(form).then(onSuccess).catch(onError);
|
||||
} else {
|
||||
requestEditItemCategory(itemCategoryId, form)
|
||||
.then(onSuccess)
|
||||
.catch(onError);
|
||||
}
|
||||
};
|
||||
|
||||
// Handles dialog close.
|
||||
const handleClose = useCallback(() => {
|
||||
closeDialog(dialogName);
|
||||
}, [closeDialog, dialogName]);
|
||||
|
||||
return (
|
||||
<DialogContent
|
||||
isLoading={fetchCategoriesList.isFetching || fetchAccountsList.isFetching}
|
||||
<ItemCategoryProvider
|
||||
itemCategoryId={itemCategoryId}
|
||||
dialogName={dialogName}
|
||||
>
|
||||
<Formik
|
||||
validationSchema={
|
||||
isNewMode ? CreateItemCategoryFormSchema : EditItemCategoryFormSchema
|
||||
}
|
||||
initialValues={initialValues}
|
||||
onSubmit={handleFormSubmit}
|
||||
>
|
||||
{({ isSubmitting }) => (
|
||||
<ItemCategoryForm
|
||||
itemCategoryId={itemCategoryId}
|
||||
accountsList={accountsList}
|
||||
categoriesList={categoriesList}
|
||||
isSubmitting={isSubmitting}
|
||||
onClose={handleClose}
|
||||
/>
|
||||
)}
|
||||
</Formik>
|
||||
</DialogContent>
|
||||
<ItemCategoryForm />
|
||||
</ItemCategoryProvider>
|
||||
);
|
||||
}
|
||||
|
||||
export default compose(
|
||||
withDialogActions,
|
||||
withItemCategoryDetail(),
|
||||
withItemCategories(({ categoriesList }) => ({
|
||||
categoriesList,
|
||||
})),
|
||||
withAccounts(({ accountsList }) => ({
|
||||
accountsList,
|
||||
})),
|
||||
withItemCategoriesActions,
|
||||
withAccountsActions,
|
||||
)(ItemCategoryFormDialogContent);
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
import React from 'react';
|
||||
import { Classes, FormGroup, InputGroup, TextArea } from '@blueprintjs/core';
|
||||
import { FormattedMessage as T } from 'react-intl';
|
||||
import { ErrorMessage, FastField } from 'formik';
|
||||
|
||||
import { useAutofocus } from 'hooks';
|
||||
import { FieldRequiredHint } from 'components';
|
||||
import { inputIntent } from 'utils';
|
||||
|
||||
/**
|
||||
* Item category form fields.
|
||||
*/
|
||||
export default function ItemCategoryFormFields() {
|
||||
const categoryNameFieldRef = useAutofocus();
|
||||
|
||||
return (
|
||||
<div className={Classes.DIALOG_BODY}>
|
||||
{/* ----------- Category name ----------- */}
|
||||
<FastField name={'name'}>
|
||||
{({ field, field: { value }, meta: { error, touched } }) => (
|
||||
<FormGroup
|
||||
label={<T id={'category_name'} />}
|
||||
labelInfo={<FieldRequiredHint />}
|
||||
className={'form-group--category-name'}
|
||||
intent={inputIntent({ error, touched })}
|
||||
helperText={<ErrorMessage name="name" />}
|
||||
inline={true}
|
||||
>
|
||||
<InputGroup
|
||||
medium={true}
|
||||
inputRef={(ref) => (categoryNameFieldRef.current = ref)}
|
||||
{...field}
|
||||
/>
|
||||
</FormGroup>
|
||||
)}
|
||||
</FastField>
|
||||
|
||||
{/* ----------- Description ----------- */}
|
||||
<FastField name={'description'}>
|
||||
{({ field, field: { value }, meta: { error, touched } }) => (
|
||||
<FormGroup
|
||||
label={<T id={'description'} />}
|
||||
className={'form-group--description'}
|
||||
intent={inputIntent({ error, touched })}
|
||||
helperText={<ErrorMessage name="description" />}
|
||||
inline={true}
|
||||
>
|
||||
<TextArea growVertically={true} large={true} {...field} />
|
||||
</FormGroup>
|
||||
)}
|
||||
</FastField>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
import React from 'react';
|
||||
import { Classes, Button, Intent } from '@blueprintjs/core';
|
||||
import { FormattedMessage as T } from 'react-intl';
|
||||
import { useFormikContext } from 'formik';
|
||||
|
||||
import withDialogActions from 'containers/Dialog/withDialogActions';
|
||||
import { useItemCategoryContext } from './ItemCategoryProvider';
|
||||
|
||||
import { compose } from 'utils';
|
||||
|
||||
/**
|
||||
* Item category form footer.
|
||||
*/
|
||||
function ItemCategoryFormFooter({
|
||||
// #withDialogActions
|
||||
closeDialog,
|
||||
}) {
|
||||
// Item category context.
|
||||
const { isNewMode, dialogName } = useItemCategoryContext();
|
||||
|
||||
// Formik context.
|
||||
const { isSubmitting } = useFormikContext();
|
||||
|
||||
// Handle close button click.
|
||||
const handleCloseBtnClick = () => {
|
||||
closeDialog(dialogName);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={Classes.DIALOG_FOOTER}>
|
||||
<div className={Classes.DIALOG_FOOTER_ACTIONS}>
|
||||
<Button onClick={handleCloseBtnClick}>
|
||||
<T id={'close'} />
|
||||
</Button>
|
||||
|
||||
<Button intent={Intent.PRIMARY} type="submit" disabled={isSubmitting}>
|
||||
{isNewMode ? <T id={'submit'} /> : <T id={'edit'} />}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
export default compose(withDialogActions)(ItemCategoryFormFooter);
|
||||
@@ -0,0 +1,57 @@
|
||||
import React, { createContext } from 'react';
|
||||
import { DialogContent } from 'components';
|
||||
import {
|
||||
useItemCategory,
|
||||
useEditItemCategory,
|
||||
useCreateItemCategory,
|
||||
} from 'hooks/query';
|
||||
|
||||
const ItemCategoryContext = createContext();
|
||||
|
||||
/**
|
||||
* Accounts chart data provider.
|
||||
*/
|
||||
function ItemCategoryProvider({ itemCategoryId, dialogName, ...props }) {
|
||||
const { data: itemCategory, isFetching: isItemCategoryLoading } = useItemCategory(
|
||||
itemCategoryId,
|
||||
{
|
||||
enabled: !!itemCategoryId,
|
||||
},
|
||||
);
|
||||
// Create and edit item category mutations.
|
||||
const { mutateAsync: createItemCategoryMutate } = useCreateItemCategory();
|
||||
const { mutateAsync: editItemCategoryMutate } = useEditItemCategory();
|
||||
|
||||
// Detarmines whether the new mode form.
|
||||
const isNewMode = !itemCategoryId;
|
||||
const isEditMode = !isNewMode;
|
||||
|
||||
// Provider state.
|
||||
const provider = {
|
||||
itemCategoryId,
|
||||
dialogName,
|
||||
|
||||
itemCategory,
|
||||
isItemCategoryLoading,
|
||||
|
||||
createItemCategoryMutate,
|
||||
editItemCategoryMutate,
|
||||
|
||||
isNewMode,
|
||||
isEditMode
|
||||
};
|
||||
|
||||
return (
|
||||
<DialogContent
|
||||
isLoading={isItemCategoryLoading}
|
||||
name={'item-category-form'}
|
||||
>
|
||||
<ItemCategoryContext.Provider value={provider} {...props} />
|
||||
</DialogContent>
|
||||
);
|
||||
}
|
||||
|
||||
const useItemCategoryContext = () =>
|
||||
React.useContext(ItemCategoryContext);
|
||||
|
||||
export { ItemCategoryProvider, useItemCategoryContext };
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, { lazy } from 'react';
|
||||
import { FormattedMessage as T, useIntl } from 'react-intl';
|
||||
import { FormattedMessage as T } from 'react-intl';
|
||||
import { Dialog, DialogSuspense } from 'components';
|
||||
|
||||
import withDialogRedux from 'components/DialogReduxConnect';
|
||||
|
||||
@@ -7,9 +7,6 @@ const Schema = Yup.object().shape({
|
||||
.required()
|
||||
.max(DATATYPES_LENGTH.STRING)
|
||||
.label(formatMessage({ id: 'category_name_' })),
|
||||
cost_account_id: Yup.number().nullable(),
|
||||
sell_account_id: Yup.number().nullable(),
|
||||
inventory_account_id: Yup.number().nullable(),
|
||||
description: Yup.string().trim().max(DATATYPES_LENGTH.TEXT).nullable(),
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user