WIP feature/Bulk delete items

This commit is contained in:
elforjani3
2020-05-23 19:39:20 +02:00
parent 4661e90bc8
commit 9ef180a805
8 changed files with 101 additions and 30 deletions

View File

@@ -15,7 +15,7 @@ import { Row, Col } from 'react-grid-system';
import { FormattedMessage as T, useIntl } from 'react-intl'; import { FormattedMessage as T, useIntl } from 'react-intl';
import { Select } from '@blueprintjs/select'; import { Select } from '@blueprintjs/select';
import { queryCache } from 'react-query'; import { queryCache } from 'react-query';
import {useParams} from 'react-router-dom'; import {useParams ,useHistory} from 'react-router-dom';
import AppToaster from 'components/AppToaster'; import AppToaster from 'components/AppToaster';
import { compose } from 'utils'; import { compose } from 'utils';
import ErrorMessage from 'components/ErrorMessage'; import ErrorMessage from 'components/ErrorMessage';
@@ -27,13 +27,13 @@ import withAccounts from 'containers/Accounts/withAccounts';
import withMediaActions from 'containers/Media/withMediaActions'; import withMediaActions from 'containers/Media/withMediaActions';
import MoneyInputGroup from 'components/MoneyInputGroup'; import MoneyInputGroup from 'components/MoneyInputGroup';
import { useHistory } from 'react-router-dom';
import Dragzone from 'components/Dragzone'; import Dragzone from 'components/Dragzone';
import useMedia from 'hooks/useMedia'; import useMedia from 'hooks/useMedia';
import withItems from './withItems'; import withItems from './withItems';
import withItemDetail from 'containers/Items/withItemDetail' import withItemDetail from 'containers/Items/withItemDetail'
import { pick } from 'lodash'; import { pick } from 'lodash';
import withDashboardActions from 'containers/Dashboard/withDashboard'; import withDashboardActions from 'containers/Dashboard/withDashboard';
import withAccountDetail from 'containers/Accounts/withAccountDetail';
const ItemForm = ({ const ItemForm = ({
@@ -42,11 +42,10 @@ const ItemForm = ({
requestSubmitItem, requestSubmitItem,
requestEditItem, requestEditItem,
accounts, accounts,
accountsTypes,
itemDetail, itemDetail,
onFormSubmit,
onCancelForm,
// #withDashboard // #withDashboard
@@ -65,7 +64,7 @@ const ItemForm = ({
}) => { }) => {
const [selectedAccounts, setSelectedAccounts] = useState({}); const [selectedAccounts, setSelectedAccounts] = useState({});
const [selectedAccountType, setSelectedAccountType] = useState(null); const [payload, setPayload] = useState({});
const history = useHistory(); const history = useHistory();
const { formatMessage } = useIntl(); const { formatMessage } = useIntl();
@@ -132,6 +131,9 @@ const ItemForm = ({
} }
}), [itemDetail, defaultInitialValues]); }), [itemDetail, defaultInitialValues]);
const saveInvokeSubmit = useCallback((payload) => {
onFormSubmit && onFormSubmit(payload)
}, [onFormSubmit]);
useEffect(() => { useEffect(() => {
itemDetail && itemDetail.id ? itemDetail && itemDetail.id ?
@@ -170,6 +172,8 @@ const ItemForm = ({
intent:Intent.SUCCESS intent:Intent.SUCCESS
}); });
setSubmitting(false); setSubmitting(false);
saveInvokeSubmit({action:'update',...payload})
history.push('/items');
resetForm(); resetForm();
}).catch((errors)=>{ }).catch((errors)=>{
setSubmitting(false) setSubmitting(false)
@@ -229,18 +233,6 @@ const ItemForm = ({
}; };
// Set default
// useEffect(()=>{
// if(itemDetail && itemDetail.id){
// const defaultType = itemDetail.find(
// (t) => t.id === itemDetail.id
// );
// defaultType && setSelectedAccountType(defaultType);
// }
// },[])
const onItemAccountSelect = useCallback( const onItemAccountSelect = useCallback(
(filedName) => { (filedName) => {
return (account) => { return (account) => {
@@ -637,10 +629,10 @@ const ItemForm = ({
}; };
export default compose( export default compose(
withAccounts(({accounts,accountsTypes})=>({ withAccounts(({accounts})=>({
accounts, accounts,
accountsTypes
})), })),
withAccountDetail,
withItemsActions, withItemsActions,
withItemDetail, withItemDetail,
withItemCategories(({ categoriesList }) => ({ withItemCategories(({ categoriesList }) => ({

View File

@@ -17,7 +17,7 @@ import { compose } from 'utils';
import DashboardActionsBar from 'components/Dashboard/DashboardActionsBar'; import DashboardActionsBar from 'components/Dashboard/DashboardActionsBar';
import Icon from 'components/Icon'; import Icon from 'components/Icon';
import FilterDropdown from 'components/FilterDropdown'; import FilterDropdown from 'components/FilterDropdown';
import DialogConnect from 'connectors/Dialog.connector'; import withDialog from 'connectors/Dialog.connector';
import withResourceDetail from 'containers/Resources/withResourceDetails'; import withResourceDetail from 'containers/Resources/withResourceDetails';
import withItems from 'containers/Items/withItems'; import withItems from 'containers/Items/withItems';
import { If } from 'components'; import { If } from 'components';
@@ -34,6 +34,7 @@ const ItemsActionsBar = ({
onFilterChanged, onFilterChanged,
selectedRows = [], selectedRows = [],
onBulkDelete,
}) => { }) => {
const { path } = useRouteMatch(); const { path } = useRouteMatch();
const history = useHistory(); const history = useHistory();
@@ -43,9 +44,11 @@ const ItemsActionsBar = ({
<MenuItem href={`${path}/${view.id}/custom_view`} text={view.name} /> <MenuItem href={`${path}/${view.id}/custom_view`} text={view.name} />
)); ));
const onClickNewItem = () => {
const onClickNewItem = useCallback(() => {
history.push('/items/new'); history.push('/items/new');
}; }, [history]);
const hasSelectedRows = useMemo(() => selectedRows.length > 0, [ const hasSelectedRows = useMemo(() => selectedRows.length > 0, [
selectedRows, selectedRows,
]); ]);
@@ -62,6 +65,11 @@ const ItemsActionsBar = ({
openDialog('item-form', {}); openDialog('item-form', {});
}, [openDialog]); }, [openDialog]);
const handleBulkDelete = useCallback(() => {
onBulkDelete && onBulkDelete(selectedRows.map(r => r.id));
}, [onBulkDelete, selectedRows]);
return ( return (
<DashboardActionsBar> <DashboardActionsBar>
<NavbarGroup> <NavbarGroup>
@@ -116,9 +124,10 @@ const ItemsActionsBar = ({
<If condition={hasSelectedRows}> <If condition={hasSelectedRows}>
<Button <Button
className={Classes.MINIMAL} className={Classes.MINIMAL}
intent={Intent.DANGER} icon={<Icon icon='trash' iconSize={15} />}
icon={<Icon icon='trash' />}
text={<T id={'delete'}/>} text={<T id={'delete'}/>}
intent={Intent.DANGER}
onClick={handleBulkDelete}
/> />
</If> </If>
@@ -138,7 +147,7 @@ const ItemsActionsBar = ({
}; };
export default compose( export default compose(
DialogConnect, withDialog,
withItems(({ itemsViews }) => ({ withItems(({ itemsViews }) => ({
itemsViews, itemsViews,
})), })),

View File

@@ -137,6 +137,9 @@ const ItemsDataTable = ({
onFetchData={handleFetchData} onFetchData={handleFetchData}
loading={itemsTableLoading && !initialMount} loading={itemsTableLoading && !initialMount}
noInitialFetch={true} noInitialFetch={true}
expandable={true}
treeGraph={true}
spinnerProps={{size: 30}}
onSelectedRowsChange={handleSelectedRowsChange} /> onSelectedRowsChange={handleSelectedRowsChange} />
</LoadingIndicator> </LoadingIndicator>
); );

View File

@@ -1,4 +1,4 @@
import React, { useEffect, useCallback, useState } from 'react'; import React, { useEffect, useCallback, useState,useMemo } from 'react';
import { import {
Route, Route,
Switch, Switch,
@@ -43,10 +43,12 @@ function ItemsList({
requestDeleteItem, requestDeleteItem,
requestFetchItems, requestFetchItems,
addItemsTableQueries, addItemsTableQueries,
requestDeleteBulkItems,
}) { }) {
const [deleteItem, setDeleteItem] = useState(false); const [deleteItem, setDeleteItem] = useState(false);
const [selectedRows, setSelectedRows] = useState([]); const [selectedRows, setSelectedRows] = useState([]);
const [tableLoading, setTableLoading] = useState(false); const [tableLoading, setTableLoading] = useState(false);
const [bulkDelete, setBulkDelete] = useState(false);
const { formatMessage } = useIntl(); const { formatMessage } = useIntl();
@@ -131,17 +133,45 @@ function ItemsList({
setSelectedRows(accounts); setSelectedRows(accounts);
}, [setSelectedRows]); }, [setSelectedRows]);
// Calculates the data table selected rows count.
const selectedRowsCount = useMemo(() => Object.values(selectedRows).length, [selectedRows]);
// Handle items bulk delete button click.,
const handleBulkDelete = useCallback((itemsIds) => {
setBulkDelete(itemsIds);
}, [setBulkDelete]);
// Handle confirm items bulk delete.
const handleConfirmBulkDelete = useCallback(() => {
requestDeleteBulkItems(bulkDelete).then(() => {
setBulkDelete(false);
AppToaster.show({
message: formatMessage({ id: 'the_items_has_been_successfully_deleted' }),
intent: Intent.SUCCESS,
});
}).catch((errors) => {
setBulkDelete(false);
});
}, [requestDeleteBulkItems, bulkDelete]);
// Handle cancel accounts bulk delete.
const handleCancelBulkDelete = useCallback(() => {
setBulkDelete(false);
}, []);
return ( return (
<DashboardInsider <DashboardInsider
isLoading={fetchHook.isFetching} isLoading={fetchHook.isFetching}
name={'items-list'}> name={'items-list'}>
<ItemsActionsBar <ItemsActionsBar
selectedRows={selectedRows}
onFilterChanged={handleFilterChanged} onFilterChanged={handleFilterChanged}
selectedRows={selectedRows} /> onBulkDelete={handleBulkDelete}/>
<DashboardPageContent> <DashboardPageContent>
<Switch> <Switch>
@@ -174,6 +204,20 @@ function ItemsList({
id={'once_delete_this_item_you_will_able_to_restore_it'} /> id={'once_delete_this_item_you_will_able_to_restore_it'} />
</p> </p>
</Alert> </Alert>
<Alert
cancelButtonText={<T id={'cancel'}/>}
confirmButtonText={`${formatMessage({id:'delete'})} (${selectedRowsCount})`}
icon="trash"
intent={Intent.DANGER}
isOpen={bulkDelete}
onCancel={handleCancelBulkDelete}
onConfirm={handleConfirmBulkDelete}
>
<p>
<T id={'once_delete_these_items_you_will_not_able_restore_them'} />
</p>
</Alert>
</Route> </Route>
</Switch> </Switch>
</DashboardPageContent> </DashboardPageContent>

View File

@@ -4,12 +4,14 @@ import {
deleteItem, deleteItem,
submitItem, submitItem,
editItem, editItem,
deleteBulkItems
} from 'store/items/items.actions'; } from 'store/items/items.actions';
import t from 'store/types'; import t from 'store/types';
export const mapDispatchToProps = (dispatch) => ({ export const mapDispatchToProps = (dispatch) => ({
requestFetchItems: (query) => dispatch(fetchItems({ query })), requestFetchItems: (query) => dispatch(fetchItems({ query })),
requestDeleteItem: (id) => dispatch(deleteItem({ id })), requestDeleteItem: (id) => dispatch(deleteItem({ id })),
requestDeleteBulkItems:(ids)=>dispatch(deleteBulkItems({ids})),
requestSubmitItem: (form) => dispatch(submitItem({ form })), requestSubmitItem: (form) => dispatch(submitItem({ form })),
requestEditItem:(id,form) => dispatch(editItem({id,form})), requestEditItem:(id,form) => dispatch(editItem({id,form})),
addBulkActionItem: (id) => dispatch({ addBulkActionItem: (id) => dispatch({

View File

@@ -322,7 +322,10 @@ export default {
organization_industry_:'Organization industry', organization_industry_:'Organization industry',
base_currency_:'Base currency', base_currency_:'Base currency',
date_format_:'Date format', date_format_:'Date format',
view_name_:'View name' category_name_:'Category name',
view_name_:'View name',
the_items_has_been_successfully_deleted: 'The items have been successfully deleted.',
once_delete_these_items_you_will_not_able_restore_them: 'Once you delete these items, you won\'t be able to retrieve them later. Are you sure you want to delete them?',
}; };

View File

@@ -76,3 +76,19 @@ export const deleteItem = ({ id }) => {
}).catch((error) => { reject(error); }); }).catch((error) => { reject(error); });
}); });
}; };
export const deleteBulkItems = ({ ids }) => {
return dispatch => new Promise((resolve, reject) => {
ApiService.delete(`items`, { params: { ids }}).then((response) => {
dispatch({
type: t.ITEMS_BULK_DELETE,
payload: { ids }
});
resolve(response);
}).catch((error) => {
reject(error);
});
});
};

View File

@@ -12,4 +12,6 @@ export default {
ITEMS_TABLE_LOADING: 'ITEMS_TABLE_LOADING', ITEMS_TABLE_LOADING: 'ITEMS_TABLE_LOADING',
ITEMS_SET_CURRENT_VIEW: 'ITEMS_SET_CURRENT_VIEW', ITEMS_SET_CURRENT_VIEW: 'ITEMS_SET_CURRENT_VIEW',
ITEMS_BULK_DELETE:'ITEMS_BULK_DELETE'
}; };