Merge branch 'feature/item-duplicate'

This commit is contained in:
elforjani3
2021-03-03 22:42:31 +02:00
5 changed files with 51 additions and 28 deletions

View File

@@ -60,14 +60,14 @@ function ItemForm({
createItemMutate, createItemMutate,
editItemMutate, editItemMutate,
submitPayload, submitPayload,
isNewMode isNewMode,
} = useItemFormContext(); } = useItemFormContext();
// History context. // History context.
const history = useHistory(); const history = useHistory();
const { formatMessage } = useIntl(); const { formatMessage } = useIntl();
/** /**
* Initial values in create and edit mode. * Initial values in create and edit mode.
*/ */
@@ -97,7 +97,11 @@ function ItemForm({
// Transform API errors. // Transform API errors.
const transformApiErrors = (error) => { const transformApiErrors = (error) => {
const { response: { data: { errors } } } = error; const {
response: {
data: { errors },
},
} = error;
const fields = {}; const fields = {};
if (errors.find((e) => e.type === 'ITEM.NAME.ALREADY.EXISTS')) { if (errors.find((e) => e.type === 'ITEM.NAME.ALREADY.EXISTS')) {
@@ -118,9 +122,10 @@ function ItemForm({
AppToaster.show({ AppToaster.show({
message: formatMessage( message: formatMessage(
{ {
id: isNewMode id:
? 'the_item_has_been_created_successfully' isNewMode
: 'the_item_has_been_edited_successfully', ? 'the_item_has_been_created_successfully'
: 'the_item_has_been_edited_successfully',
}, },
{ {
number: itemId, number: itemId,
@@ -151,7 +156,7 @@ function ItemForm({
editItemMutate([itemId, form]).then(onSuccess).catch(onError); editItemMutate([itemId, form]).then(onSuccess).catch(onError);
} }
}; };
return ( return (
<div class={classNames(CLASSES.PAGE_FORM_ITEM)}> <div class={classNames(CLASSES.PAGE_FORM_ITEM)}>
<Formik <Formik

View File

@@ -1,5 +1,6 @@
import React, { useEffect, createContext, useState } from 'react'; import React, { useEffect, createContext, useState } from 'react';
import { useIntl } from 'react-intl'; import { useIntl } from 'react-intl';
import { useLocation, useParams } from 'react-router-dom';
import DashboardInsider from 'components/Dashboard/DashboardInsider'; import DashboardInsider from 'components/Dashboard/DashboardInsider';
import { import {
useItem, useItem,
@@ -16,6 +17,9 @@ const ItemFormContext = createContext();
* Accounts chart data provider. * Accounts chart data provider.
*/ */
function ItemFormProvider({ itemId, ...props }) { function ItemFormProvider({ itemId, ...props }) {
const { state } = useLocation();
const duplicateId = state?.action;
// Fetches the accounts list. // Fetches the accounts list.
const { isFetching: isAccountsLoading, data: accounts } = useAccounts(); const { isFetching: isAccountsLoading, data: accounts } = useAccounts();
@@ -26,9 +30,12 @@ function ItemFormProvider({ itemId, ...props }) {
} = useItemsCategories(); } = useItemsCategories();
// Fetches the given item details. // Fetches the given item details.
const { isFetching: isItemLoading, data: item } = useItem(itemId, { const { isFetching: isItemLoading, data: item } = useItem(
enabled: !!itemId, itemId || duplicateId,
}); {
enabled: !!itemId || !!duplicateId,
},
);
// Create and edit item mutations. // Create and edit item mutations.
const { mutateAsync: editItemMutate } = useEditItem(); const { mutateAsync: editItemMutate } = useEditItem();
const { mutateAsync: createItemMutate } = useCreateItem(); const { mutateAsync: createItemMutate } = useCreateItem();
@@ -37,7 +44,7 @@ function ItemFormProvider({ itemId, ...props }) {
const [submitPayload, setSubmitPayload] = useState({}); const [submitPayload, setSubmitPayload] = useState({});
// Detarmines whether the form new mode. // Detarmines whether the form new mode.
const isNewMode = !itemId; const isNewMode = duplicateId || !itemId;
// Provider state. // Provider state.
const provider = { const provider = {
@@ -54,20 +61,20 @@ function ItemFormProvider({ itemId, ...props }) {
createItemMutate, createItemMutate,
editItemMutate, editItemMutate,
setSubmitPayload setSubmitPayload,
}; };
// Format message intl. // Format message intl.
const { formatMessage } = useIntl(); const { formatMessage } = useIntl();
// Change page title dispatcher. // Change page title dispatcher.
const changePageTitle = useDashboardPageTitle(); const changePageTitle = useDashboardPageTitle();
// Changes the page title in new and edit mode. // Changes the page title in new and edit mode.
useEffect(() => { useEffect(() => {
!isNewMode isNewMode
? changePageTitle(formatMessage({ id: 'edit_item_details' })) ? changePageTitle(formatMessage({ id: 'new_item' }))
: changePageTitle(formatMessage({ id: 'new_item' })); : changePageTitle(formatMessage({ id: 'edit_item_details' }));
}, [changePageTitle, isNewMode, formatMessage]); }, [changePageTitle, isNewMode, formatMessage]);
return ( return (

View File

@@ -7,7 +7,6 @@ import ItemsEmptyStatus from './ItemsEmptyStatus';
import TableSkeletonRows from 'components/Datatable/TableSkeletonRows'; import TableSkeletonRows from 'components/Datatable/TableSkeletonRows';
import TableSkeletonHeader from 'components/Datatable/TableHeaderSkeleton'; import TableSkeletonHeader from 'components/Datatable/TableHeaderSkeleton';
import withItems from 'containers/Items/withItems'; import withItems from 'containers/Items/withItems';
import withItemsActions from 'containers/Items/withItemsActions'; import withItemsActions from 'containers/Items/withItemsActions';
import withAlertsActions from 'containers/Alert/withAlertActions'; import withAlertsActions from 'containers/Alert/withAlertActions';
@@ -94,6 +93,11 @@ function ItemsDataTable({
}; };
// Display empty status instead of the table. // Display empty status instead of the table.
const handleDuplicate = ({ id }) => {
history.push(`/items/new?duplicate=${id}`, { action: id });
};
// Cannot continue in case the items has empty status.
if (isEmptyStatus) { if (isEmptyStatus) {
return <ItemsEmptyStatus />; return <ItemsEmptyStatus />;
} }
@@ -103,29 +107,23 @@ function ItemsDataTable({
columns={columns} columns={columns}
data={items} data={items}
initialState={itemsTableState} initialState={itemsTableState}
loading={isItemsLoading} loading={isItemsLoading}
headerLoading={isItemsLoading} headerLoading={isItemsLoading}
progressBarLoading={isItemsFetching} progressBarLoading={isItemsFetching}
noInitialFetch={true} noInitialFetch={true}
selectionColumn={true} selectionColumn={true}
spinnerProps={{ size: 30 }} spinnerProps={{ size: 30 }}
expandable={false} expandable={false}
sticky={true} sticky={true}
rowClassNames={rowClassNames} rowClassNames={rowClassNames}
pagination={true} pagination={true}
manualSortBy={true} manualSortBy={true}
manualPagination={true} manualPagination={true}
pagesCount={pagination.pagesCount} pagesCount={pagination.pagesCount}
autoResetSortBy={false} autoResetSortBy={false}
autoResetPage={true} autoResetPage={true}
TableLoadingRenderer={TableSkeletonRows} TableLoadingRenderer={TableSkeletonRows}
TableHeaderSkeletonRenderer={TableSkeletonHeader} TableHeaderSkeletonRenderer={TableSkeletonHeader}
ContextMenu={ItemsActionMenuList} ContextMenu={ItemsActionMenuList}
onFetchData={handleFetchData} onFetchData={handleFetchData}
payload={{ payload={{
@@ -134,6 +132,7 @@ function ItemsDataTable({
onInactivateItem: handleInactiveItem, onInactivateItem: handleInactiveItem,
onActivateItem: handleActivateItem, onActivateItem: handleActivateItem,
onMakeAdjustment: handleMakeAdjustment, onMakeAdjustment: handleMakeAdjustment,
onDuplicate: handleDuplicate,
}} }}
noResults={'There is no items in the table yet.'} noResults={'There is no items in the table yet.'}
{...tableProps} {...tableProps}

View File

@@ -79,10 +79,10 @@ export function ItemsActionMenuList({
onActivateItem, onActivateItem,
onMakeAdjustment, onMakeAdjustment,
onDeleteItem, onDeleteItem,
onDuplicate,
}, },
}) { }) {
const { formatMessage } = useIntl(); const { formatMessage } = useIntl();
return ( return (
<Menu> <Menu>
<MenuItem <MenuItem
@@ -95,6 +95,11 @@ export function ItemsActionMenuList({
text={formatMessage({ id: 'edit_item' })} text={formatMessage({ id: 'edit_item' })}
onClick={safeCallback(onEditItem, original)} onClick={safeCallback(onEditItem, original)}
/> />
<MenuItem
icon={<Icon icon="duplicate-18" />}
text={formatMessage({ id: 'duplicate' })}
onClick={safeCallback(onDuplicate, original)}
/>
<If condition={original.active}> <If condition={original.active}>
<MenuItem <MenuItem
text={formatMessage({ id: 'inactivate_item' })} text={formatMessage({ id: 'inactivate_item' })}
@@ -153,7 +158,7 @@ export const useItemsTableColumns = () => {
width: 180, width: 180,
}, },
{ {
id:'code', id: 'code',
Header: formatMessage({ id: 'item_code' }), Header: formatMessage({ id: 'item_code' }),
accessor: 'code', accessor: 'code',
className: 'code', className: 'code',
@@ -174,7 +179,7 @@ export const useItemsTableColumns = () => {
width: 150, width: 150,
}, },
{ {
id:'sell_price', id: 'sell_price',
Header: formatMessage({ id: 'sell_price' }), Header: formatMessage({ id: 'sell_price' }),
Cell: SellPriceCell, Cell: SellPriceCell,
accessor: 'sell_price', accessor: 'sell_price',
@@ -182,7 +187,7 @@ export const useItemsTableColumns = () => {
width: 150, width: 150,
}, },
{ {
id:'cost_price', id: 'cost_price',
Header: formatMessage({ id: 'cost_price' }), Header: formatMessage({ id: 'cost_price' }),
Cell: CostPriceCell, Cell: CostPriceCell,
accessor: 'cost_price', accessor: 'cost_price',
@@ -190,7 +195,7 @@ export const useItemsTableColumns = () => {
width: 150, width: 150,
}, },
{ {
id:'quantity_on_hand', id: 'quantity_on_hand',
Header: formatMessage({ id: 'quantity_on_hand' }), Header: formatMessage({ id: 'quantity_on_hand' }),
accessor: 'quantity_on_hand', accessor: 'quantity_on_hand',
Cell: QuantityOnHandCell, Cell: QuantityOnHandCell,

View File

@@ -71,6 +71,13 @@ export default [
pageTitle: formatMessage({ id: 'edit_item' }), pageTitle: formatMessage({ id: 'edit_item' }),
backLink: true, backLink: true,
}, },
{
path: `/items/new?duplicate=/:id`,
component: lazy({
loader: () => import('containers/Items/ItemFormPage'),
}),
breadcrumb: 'Duplicate Item',
},
{ {
path: `/items/new`, path: `/items/new`,
component: lazy(() => import('containers/Items/ItemFormPage')), component: lazy(() => import('containers/Items/ItemFormPage')),