feat/delete-item-warehouse (#78)

Delete item
Delete warehouse
Delete confirmation messages
Bonus: Full cover image

Co-authored-by: Llewellyn Dsouza <lledsouza2209@gmail.com>
This commit is contained in:
bluestreamlds
2022-03-04 16:27:53 +05:30
committed by GitHub
parent 5381f7d727
commit 8cccf1f034
11 changed files with 258 additions and 13 deletions

2
.gitignore vendored
View File

@@ -1,7 +1,7 @@
# See https://help.github.com/ignore-files/ for more about ignoring files. # See https://help.github.com/ignore-files/ for more about ignoring files.
# dependencies # dependencies
/node_modules node_modules
.DS_Store .DS_Store
# testing # testing

View File

@@ -41,10 +41,11 @@ const StyledTableRow = styled(TableRow)(({ theme }) => ({
Row.propTypes = { Row.propTypes = {
rowData: PropTypes.array, rowData: PropTypes.array,
tHeads: PropTypes.array, tHeads: PropTypes.array,
editHandler: PropTypes.any editHandler: PropTypes.any,
deleteHandler: PropTypes.any
}; };
function Row({ tHeads, rowData, editHandler }) { function Row({ tHeads, rowData, editHandler, deleteHandler }) {
return ( return (
<React.Fragment> <React.Fragment>
<StyledTableRow sx={{ '&odd > *': { borderBottom: 'unset' } }}> <StyledTableRow sx={{ '&odd > *': { borderBottom: 'unset' } }}>
@@ -68,6 +69,25 @@ function Row({ tHeads, rowData, editHandler }) {
> >
EDIT EDIT
</MDButton> </MDButton>
<MDButton
size="small"
variant="contained"
color="error"
sx={{
textTransform: 'capitalize',
minWidth: '45px',
minHeight: '28px',
marginLeft: '10px',
boxShadow: 'none',
fontWeight: '500',
padding: '0'
}}
onClick={() => {
deleteHandler(rowData._id);
}}
>
DELETE
</MDButton>
</StyledTableCell> </StyledTableCell>
{tHeads && {tHeads &&
tHeads tHeads
@@ -87,6 +107,7 @@ function EnhancedTable({
data, data,
tHeads, tHeads,
editHandler, editHandler,
deleteHandler,
filtersControl, filtersControl,
resetFilters resetFilters
}) { }) {
@@ -172,6 +193,7 @@ function EnhancedTable({
<Row <Row
key={rowData._id} key={rowData._id}
editHandler={editHandler} editHandler={editHandler}
deleteHandler={deleteHandler}
rowData={rowData} rowData={rowData}
tHeads={tHeads} tHeads={tHeads}
/> />
@@ -304,6 +326,7 @@ EnhancedTable.propTypes = {
data: PropTypes.array, data: PropTypes.array,
tHeads: PropTypes.array, tHeads: PropTypes.array,
editHandler: PropTypes.any, editHandler: PropTypes.any,
deleteHandler: PropTypes.any,
filtersControl: PropTypes.any, filtersControl: PropTypes.any,
resetFilters: PropTypes.any resetFilters: PropTypes.any
}; };

View File

@@ -38,6 +38,7 @@ function AuthLayout({ header, title, description, illustration, children }) {
mt={2} mt={2}
sx={{ sx={{
backgroundImage: `url(${illustration})`, backgroundImage: `url(${illustration})`,
backgroundSize: 'cover',
backgroundRepeat: 'no-repeat', backgroundRepeat: 'no-repeat',
backgroundPosition: 'center' backgroundPosition: 'center'
}} }}

View File

@@ -12,7 +12,9 @@ import {
DialogTitle, DialogTitle,
DialogContent, DialogContent,
TextField, TextField,
DialogActions DialogActions,
Button,
DialogContentText
} from '@mui/material'; } from '@mui/material';
import DashboardNavbar from 'components/DashboardNavbar'; import DashboardNavbar from 'components/DashboardNavbar';
import DashboardLayout from 'layouts/DashboardLayout'; import DashboardLayout from 'layouts/DashboardLayout';
@@ -319,6 +321,9 @@ const WarehouseNestedDetails = () => {
function EditWarehouseDetails() { function EditWarehouseDetails() {
const { warehouseId } = useParams(); const { warehouseId } = useParams();
const navigate = useNavigate(); const navigate = useNavigate();
const navigateTo = (to) => {
navigate(to);
};
const warehouseData = useSelector(WarehouseSelectors.getWarehouseDetailById(warehouseId)); const warehouseData = useSelector(WarehouseSelectors.getWarehouseDetailById(warehouseId));
const inventoryTypes = useSelector(InventorySelectors.getInventoryDetail); const inventoryTypes = useSelector(InventorySelectors.getInventoryDetail);
@@ -372,6 +377,14 @@ function EditWarehouseDetails() {
} }
}); });
const [deleteAlertOpen, setDeleteAlertOpen] = React.useState(null);
const handleDeleteAlertClose = () => {
setDeleteAlertOpen(false);
};
const handleDeleteAlertOpen = () => {
setDeleteAlertOpen(true);
};
return ( return (
<> <>
<DashboardLayout> <DashboardLayout>
@@ -516,7 +529,49 @@ function EditWarehouseDetails() {
/> />
</Box> </Box>
</Grid> </Grid>
<Grid item xs={12} sm={6} md={6}> <Grid item sx={{ textAlign: 'end' }} xs={12} sm={6} md={6}>
<MDButton
size="large"
color="error"
variant="outlined"
onClick={handleDeleteAlertOpen}
>
Delete Warehouse
</MDButton>
<Dialog
open={deleteAlertOpen}
aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description"
onClose={handleDeleteAlertClose}
>
<DialogTitle id="alert-dialog-title">Confirm Warehouse Delete</DialogTitle>
<DialogContent>
<DialogContentText id="alert-dialog-description">
Are you sure you want to delete this warehouse?
</DialogContentText>
</DialogContent>
<DialogActions>
<Button autoFocus onClick={handleDeleteAlertClose}>
No
</Button>
<Button
onClick={() => {
dispatch(
WarehouseActions.deleteWarehouseAction({
loader: 'loading-request',
slug: '/warehouse/',
method: 'delete',
warehouseId: warehouseData._id,
navigateTo
})
);
handleDeleteAlertClose();
}}
>
Yes
</Button>
</DialogActions>
</Dialog>
<Box sx={{ marginTop: '30px' }}> <Box sx={{ marginTop: '30px' }}>
<ImageUploadSingle <ImageUploadSingle
heading="Upload Warehouse Image" heading="Upload Warehouse Image"

View File

@@ -14,7 +14,17 @@ import EnhancedTable from 'components/EnhancedTable';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import WidgetActions from 'redux/WidgetRedux'; import WidgetActions from 'redux/WidgetRedux';
import { WidgetSelectors } from 'redux/WidgetRedux'; import { WidgetSelectors } from 'redux/WidgetRedux';
import { Grid, MenuItem, Select } from '@mui/material'; import {
Button,
Dialog,
DialogActions,
DialogContent,
DialogContentText,
DialogTitle,
Grid,
MenuItem,
Select
} from '@mui/material';
const tHeads = [ const tHeads = [
{ key: 'name', name: '' }, { key: 'name', name: '' },
@@ -76,6 +86,14 @@ function ItemListing() {
); );
}, []); }, []);
const [deleteAlertOpen, setDeleteAlertOpen] = React.useState(null);
const handleDeleteAlertClose = () => {
setDeleteAlertOpen(null);
};
const handleDeleteAlertOpen = (id) => {
setDeleteAlertOpen(id);
};
return ( return (
<DashboardLayout> <DashboardLayout>
<DashboardNavbar /> <DashboardNavbar />
@@ -90,6 +108,53 @@ function ItemListing() {
/> />
<MDBox px={5} py={3}> <MDBox px={5} py={3}>
<Dialog
open={deleteAlertOpen}
aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description"
onClose={handleDeleteAlertClose}
>
<DialogTitle id="alert-dialog-title">Confirm Delete</DialogTitle>
<DialogContent>
<DialogContentText id="alert-dialog-description">
Are you sure you want to delete this item?
</DialogContentText>
</DialogContent>
<DialogActions>
<Button autoFocus onClick={handleDeleteAlertClose}>
No
</Button>
<Button
onClick={() => {
const refreshDispatch = () => {
dispatch(
ItemActions.itemRequest({
loader: 'loading-request',
slug: API.GET_ITEMS_BY_INVENTORY,
method: 'get',
page: page - 1,
perPage,
inventoryId,
family: sFam || pFam || null
})
);
};
dispatch(
ItemActions.deleteItemRequest({
loader: 'loading-request',
slug: '/item/',
method: 'delete',
itemId: deleteAlertOpen,
refreshDispatch
})
);
handleDeleteAlertClose();
}}
>
Yes
</Button>
</DialogActions>
</Dialog>
<EnhancedTable <EnhancedTable
count={count} count={count}
page={page} page={page}
@@ -99,6 +164,9 @@ function ItemListing() {
editHandler={(id) => { editHandler={(id) => {
navigateTo(`/setup/inventory/browse/${widgetName}/${inventoryId}/edit/${id}`); navigateTo(`/setup/inventory/browse/${widgetName}/${inventoryId}/edit/${id}`);
}} }}
deleteHandler={(id) => {
handleDeleteAlertOpen(id);
}}
resetFilters={() => { resetFilters={() => {
setPFam(''); setPFam('');
setSFam(''); setSFam('');

View File

@@ -20,7 +20,7 @@ function SetupHome() {
icon: <InventoryIcon width={96} height={96} color="#007AFF" /> icon: <InventoryIcon width={96} height={96} color="#007AFF" />
}, },
{ {
name: 'User & Access', name: 'User Access',
path: '/setup/users-access', path: '/setup/users-access',
icon: <ProfileCircleIcon width={96} height={96} color="#007AFF" /> icon: <ProfileCircleIcon width={96} height={96} color="#007AFF" />
}, },
@@ -33,7 +33,7 @@ function SetupHome() {
return ( return (
<DashboardLayout> <DashboardLayout>
<DashboardNavbar /> <DashboardNavbar />
<Breadcrumbs title="Setup Warehouse, Inventory, Users" route={[{ name: 'Home', path: '/home' }, { name: 'Setup' }]} /> <Breadcrumbs title="Warehouse Management System Setup" route={[{ name: 'Home', path: '/home' }, { name: 'Setup' }]} />
<TileBasic tiles={data} /> <TileBasic tiles={data} />
</DashboardLayout> </DashboardLayout>
); );

View File

@@ -221,7 +221,7 @@ function UserAccessScreen() {
route={[ route={[
{ name: 'Home', path: '/home' }, { name: 'Home', path: '/home' },
{ name: 'Setup', path: '/setup' }, { name: 'Setup', path: '/setup' },
{ name: 'Users and Access', path: '/setup/users-access' } { name: 'Users Access' }
]} ]}
/> />
<MDBox px={5} py={3}> <MDBox px={5} py={3}>

View File

@@ -12,6 +12,8 @@ const { Types, Creators } = createActions({
addItemSuccess: ['data'], addItemSuccess: ['data'],
editItemRequest: ['payload'], editItemRequest: ['payload'],
editItemSuccess: ['data'], editItemSuccess: ['data'],
deleteItemRequest: ['payload'],
deleteItemSuccess: ['data'],
oneItemRequest: ['payload'], oneItemRequest: ['payload'],
oneItemSuccess: ['data'] oneItemSuccess: ['data']
}); });
@@ -91,6 +93,18 @@ export const onEditItemSuccess = (state, { data }) =>
item: null item: null
}); });
export const onDeleteItemRequest = (state, { payload }) =>
state.merge({
fetching: _.uniq([...state.fetching, payload?.loader]),
error: getErrorValue(state?.error, payload?.loader)
});
export const onDeleteItemSuccess = (state, { data }) =>
state.merge({
fetching: getFetchingValue(state.fetching, data?.loader),
error: getErrorValue(state?.error, data?.loader)
});
export const onItemFailure = (state, { error }) => export const onItemFailure = (state, { error }) =>
state.merge({ state.merge({
fetching: _.without(state.fetching, error?.loader), fetching: _.without(state.fetching, error?.loader),
@@ -106,6 +120,8 @@ export const itemReducer = createReducer(INITIAL_STATE, {
[Types.ADD_ITEM_SUCCESS]: onAddItemSuccess, [Types.ADD_ITEM_SUCCESS]: onAddItemSuccess,
[Types.EDIT_ITEM_REQUEST]: onEditItemRequest, [Types.EDIT_ITEM_REQUEST]: onEditItemRequest,
[Types.EDIT_ITEM_SUCCESS]: onEditItemSuccess, [Types.EDIT_ITEM_SUCCESS]: onEditItemSuccess,
[Types.DELETE_ITEM_REQUEST]: onDeleteItemRequest,
[Types.DELETE_ITEM_SUCCESS]: onDeleteItemSuccess,
[Types.ONE_ITEM_REQUEST]: onOneItemRequest, [Types.ONE_ITEM_REQUEST]: onOneItemRequest,
[Types.ONE_ITEM_SUCCESS]: onOneItemSuccess [Types.ONE_ITEM_SUCCESS]: onOneItemSuccess
}); });

View File

@@ -15,7 +15,10 @@ const { Types, Creators } = createActions({
editWarehouseAction: ['payload'], editWarehouseAction: ['payload'],
editWarehouseSuccess: ['data'], editWarehouseSuccess: ['data'],
editWarehouseFailure: ['error'] editWarehouseFailure: ['error'],
deleteWarehouseAction: ['payload'],
deleteWarehouseSuccess: ['data']
}); });
export const WarehouseTypes = Types; export const WarehouseTypes = Types;
@@ -96,6 +99,21 @@ export const onEditWarehouseSuccess = (state, { data }) =>
] ]
}); });
export const onDeleteWarehouseAction = (state, { payload }) =>
state.merge({
fetching: _.uniq([state.fetching, payload?.loader]),
error: getErrorValue(state?.error, payload?.loader)
});
export const onDeleteWarehouseSuccess = (state, { data }) =>
state.merge({
fetching: getFetchingValue(state.fetching, data?.loader),
error: getErrorValue(state?.error, data?.loader),
warehouseDetail: data?.deletedWarehouseID
? [...state.warehouseDetail.filter((x) => x._id !== data?.deletedWarehouseID)]
: state.warehouseDetail
});
export const onEditWarehouseFailure = (state, { error }) => export const onEditWarehouseFailure = (state, { error }) =>
state.merge({ state.merge({
fetching: _.without(state.fetching, error?.loader), fetching: _.without(state.fetching, error?.loader),
@@ -113,5 +131,7 @@ export const warehouseReducer = createReducer(INITIAL_STATE, {
[Types.EDIT_WAREHOUSE_ACTION]: onEditWarehouseAction, [Types.EDIT_WAREHOUSE_ACTION]: onEditWarehouseAction,
[Types.EDIT_WAREHOUSE_SUCCESS]: onEditWarehouseSuccess, [Types.EDIT_WAREHOUSE_SUCCESS]: onEditWarehouseSuccess,
[Types.EDIT_WAREHOUSE_FAILURE]: onEditWarehouseFailure [Types.EDIT_WAREHOUSE_FAILURE]: onEditWarehouseFailure,
[Types.DELETE_WAREHOUSE_ACTION]: onDeleteWarehouseAction,
[Types.DELETE_WAREHOUSE_SUCCESS]: onDeleteWarehouseSuccess
}); });

View File

@@ -159,9 +159,40 @@ export function* onEditRequestItem({ payload }) {
} }
} }
export function* onDeleteRequestItem({ payload }) {
const response = yield call(
ApiServices[payload?.method],
AuthorizedAPI,
payload?.slug + payload?.itemId
);
if (response?.status === 200) {
toast.success(`Successfully deleted item`, {
theme: 'colored'
});
payload.refreshDispatch();
yield put(
ItemActions.deleteItemSuccess({
loader: payload?.loader,
item: response?.data?.data
})
);
} else {
toast.error('Failed to delete item', {
theme: 'colored'
});
yield put(
ItemActions.itemFailure({
loader: payload?.loader,
error: response?.data
})
);
}
}
export default [ export default [
takeEvery(ItemTypes.ITEM_REQUEST, onRequestItem), takeEvery(ItemTypes.ITEM_REQUEST, onRequestItem),
takeEvery(ItemTypes.ONE_ITEM_REQUEST, onRequestOneItem), takeEvery(ItemTypes.ONE_ITEM_REQUEST, onRequestOneItem),
takeEvery(ItemTypes.ADD_ITEM_REQUEST, onAddRequestItem), takeEvery(ItemTypes.ADD_ITEM_REQUEST, onAddRequestItem),
takeEvery(ItemTypes.EDIT_ITEM_REQUEST, onEditRequestItem) takeEvery(ItemTypes.EDIT_ITEM_REQUEST, onEditRequestItem),
takeEvery(ItemTypes.DELETE_ITEM_REQUEST, onDeleteRequestItem)
]; ];

View File

@@ -112,8 +112,39 @@ export function* onRequestEditWarehouse({ payload }) {
} }
} }
export function* onRequestDeleteWarehouse({ payload }) {
const response = yield call(
ApiServices[payload?.method],
AuthorizedAPI,
payload?.slug + payload?.warehouseId
);
if (response?.status === 200) {
toast.success('Warehouse deleted successfully', {
theme: 'colored'
});
payload.navigateTo('/setup/warehouse');
yield put(
WarehouseActions.deleteWarehouseSuccess({
loader: payload?.loader,
deletedWarehouseID: payload?.warehouseId
})
);
} else {
toast.error('Failed to delete warehouse', {
theme: 'colored'
});
yield put(
WarehouseActions.editWarehouseFailure({
loader: payload?.loader,
error: response?.data
})
);
}
}
export default [ export default [
takeLatest(WarehouseTypes.WAREHOUSE_DATA_ACTION, onRequestWarehouseData), takeLatest(WarehouseTypes.WAREHOUSE_DATA_ACTION, onRequestWarehouseData),
takeLatest(WarehouseTypes.CREATE_WAREHOUSE_ACTION, onRequestCreateWarehouse), takeLatest(WarehouseTypes.CREATE_WAREHOUSE_ACTION, onRequestCreateWarehouse),
takeLatest(WarehouseTypes.EDIT_WAREHOUSE_ACTION, onRequestEditWarehouse) takeLatest(WarehouseTypes.EDIT_WAREHOUSE_ACTION, onRequestEditWarehouse),
takeLatest(WarehouseTypes.DELETE_WAREHOUSE_ACTION, onRequestDeleteWarehouse)
]; ];