Fixes/items-and-images (#73)
* Fixed: warehouse preferred inventories upload * Fix: item redux saga * Item listing * Added: add item * Added: edit handler * Update: add item * Update: multi images * Fix: multiple images * Fix: item api mapping * Update: added keys Co-authored-by: Llewellyn Dsouza <lledsouza2209@gmail.com>
This commit is contained in:
@@ -44,6 +44,7 @@ const buildBreadcrumbs = (route, light) => {
|
||||
fontWeight="regular"
|
||||
textTransform="capitalize"
|
||||
color={light ? 'white' : 'dark'}
|
||||
key={el}
|
||||
sx={{ lineHeight: 0 }}
|
||||
>
|
||||
{el.name}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import * as React from 'react';
|
||||
import Box from '@mui/material/Box';
|
||||
import PropTypes from 'prop-types';
|
||||
import SearchBar from 'components/SearchBar';
|
||||
// import SearchBar from 'components/SearchBar';
|
||||
import MDButton from 'components/Button';
|
||||
import Menu from '@mui/material/Menu';
|
||||
import MenuItem from '@mui/material/MenuItem';
|
||||
import Fade from '@mui/material/Fade';
|
||||
import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown';
|
||||
// import Menu from '@mui/material/Menu';
|
||||
// import MenuItem from '@mui/material/MenuItem';
|
||||
// import Fade from '@mui/material/Fade';
|
||||
// import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown';
|
||||
import { styled } from '@mui/material/styles';
|
||||
import Table from '@mui/material/Table';
|
||||
import TableBody from '@mui/material/TableBody';
|
||||
@@ -19,6 +19,7 @@ import Paper from '@mui/material/Paper';
|
||||
// import IconButton from '@mui/material/IconButton';
|
||||
// import Collapse from '@mui/material/Collapse';
|
||||
import TablePagination from 'components/TablePagination';
|
||||
import { MenuItem, Select } from '@mui/material';
|
||||
|
||||
const StyledTableCell = styled(TableCell)(({ theme }) => ({
|
||||
[`&.${tableCellClasses.head}`]: {
|
||||
@@ -47,16 +48,16 @@ const StyledTableRow = styled(TableRow)(({ theme }) => ({
|
||||
|
||||
Row.propTypes = {
|
||||
rowData: PropTypes.array,
|
||||
tHeads: PropTypes.array
|
||||
tHeads: PropTypes.array,
|
||||
editHandler: PropTypes.any
|
||||
};
|
||||
|
||||
function Row({ tHeads, rowData }) {
|
||||
function Row({ tHeads, rowData, editHandler }) {
|
||||
return (
|
||||
<React.Fragment>
|
||||
<StyledTableRow sx={{ '&odd > *': { borderBottom: 'unset' } }}>
|
||||
<StyledTableCell sx={{ width: '10%', display: 'flex', alignItems: 'center' }}>
|
||||
<MDButton
|
||||
disabled
|
||||
size="small"
|
||||
variant="contained"
|
||||
color="primary"
|
||||
@@ -69,6 +70,9 @@ function Row({ tHeads, rowData }) {
|
||||
fontWeight: '500',
|
||||
padding: '0'
|
||||
}}
|
||||
onClick={() => {
|
||||
editHandler(rowData._id);
|
||||
}}
|
||||
>
|
||||
EDIT
|
||||
</MDButton>
|
||||
@@ -82,7 +86,7 @@ function Row({ tHeads, rowData }) {
|
||||
);
|
||||
}
|
||||
|
||||
function EnhancedTable({ data, tHeads }) {
|
||||
function EnhancedTable({ count, page, setPage, perPage, setPerPage, data, tHeads, editHandler }) {
|
||||
// const [anchorEl, setAnchorEl] = React.useState(false);
|
||||
// const open = Boolean(anchorEl);
|
||||
// const handleClick = (event) => {
|
||||
@@ -101,7 +105,7 @@ function EnhancedTable({ data, tHeads }) {
|
||||
overflow: 'hidden'
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
{/* <Box
|
||||
sx={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
@@ -160,7 +164,7 @@ function EnhancedTable({ data, tHeads }) {
|
||||
<MenuItem>Logout</MenuItem>
|
||||
</Menu>
|
||||
</Box>
|
||||
</Box>
|
||||
</Box> */}
|
||||
{/* Table-row- */}
|
||||
<TableContainer component={Paper} sx={{ borderRadius: '0 !important', boxShadow: 'none' }}>
|
||||
<Table aria-label="collapsible table" sx={{ minWidth: 700 }}>
|
||||
@@ -174,7 +178,14 @@ function EnhancedTable({ data, tHeads }) {
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
{data &&
|
||||
data.map((rowData) => <Row key={rowData._id} rowData={rowData} tHeads={tHeads} />)}
|
||||
data.map((rowData) => (
|
||||
<Row
|
||||
key={rowData._id}
|
||||
editHandler={editHandler}
|
||||
rowData={rowData}
|
||||
tHeads={tHeads}
|
||||
/>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</TableContainer>
|
||||
@@ -265,10 +276,29 @@ function EnhancedTable({ data, tHeads }) {
|
||||
</Box>
|
||||
</Box> */}
|
||||
{/*---- pagination- */}
|
||||
<Box>
|
||||
<TablePagination />
|
||||
<Box sx={{ fontSize: '14px', color: '#000' }}>
|
||||
Per page:{' '}
|
||||
<Select
|
||||
labelId="demo-simple-select-label"
|
||||
id="demo-simple-select"
|
||||
value={perPage}
|
||||
label="Age"
|
||||
onChange={(e) => {
|
||||
setPerPage(e.target.value);
|
||||
}}
|
||||
>
|
||||
<MenuItem value={10}>5</MenuItem>
|
||||
<MenuItem value={20}>10</MenuItem>
|
||||
<MenuItem value={30}>20</MenuItem>
|
||||
</Select>
|
||||
</Box>
|
||||
<Box>
|
||||
<TablePagination count={Math.ceil(count / perPage)} page={page} setPage={setPage} />
|
||||
</Box>
|
||||
<Box sx={{ fontSize: '14px', color: '#000' }}>
|
||||
[{(page - 1) * perPage + 1} to {perPage * page > count ? count : perPage * page} of{' '}
|
||||
{count}]
|
||||
</Box>
|
||||
<Box sx={{ fontSize: '14px', color: '#000' }}>[1 to 10 of 92]</Box>
|
||||
</Box>
|
||||
</Box>
|
||||
</>
|
||||
@@ -276,8 +306,14 @@ function EnhancedTable({ data, tHeads }) {
|
||||
}
|
||||
|
||||
EnhancedTable.propTypes = {
|
||||
count: PropTypes.number,
|
||||
page: PropTypes.number,
|
||||
setPage: PropTypes.any,
|
||||
perPage: PropTypes.number,
|
||||
setPerPage: PropTypes.any,
|
||||
data: PropTypes.array,
|
||||
tHeads: PropTypes.array
|
||||
tHeads: PropTypes.array,
|
||||
editHandler: PropTypes.any
|
||||
};
|
||||
|
||||
export default EnhancedTable;
|
||||
|
||||
128
src/components/ImageUploadMultiple/index.js
Normal file
128
src/components/ImageUploadMultiple/index.js
Normal file
@@ -0,0 +1,128 @@
|
||||
/* eslint-disable no-case-declarations */
|
||||
import MDBox from 'components/MDBox';
|
||||
import PropTypes from 'prop-types';
|
||||
import UploadIcon from 'assets/images/UploadIcon';
|
||||
import MDTypography from 'components/MDTypography';
|
||||
import pxToRem from 'assets/theme-dark/functions/pxToRem';
|
||||
import { Button } from '@mui/material';
|
||||
import Close from 'assets/images/Close';
|
||||
|
||||
function ImageUpload({ heading, accept, multiple, images, setImages }) {
|
||||
const addImage = (e) => {
|
||||
setImages([
|
||||
...images,
|
||||
{ src: URL.createObjectURL(e.target.files[0]), file: e.target.files[0] }
|
||||
]);
|
||||
};
|
||||
|
||||
const removeImage = (index) => {
|
||||
setImages(images.filter((_val, idx) => idx !== index));
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<MDBox
|
||||
sx={{
|
||||
border: '1px solid #c4c4c4',
|
||||
borderRadius: pxToRem(8),
|
||||
padding: pxToRem(16)
|
||||
}}
|
||||
>
|
||||
<MDBox
|
||||
sx={{
|
||||
border: '1px dashed #C4C4C4',
|
||||
borderRadius: pxToRem(6),
|
||||
cursor: 'pointer',
|
||||
position: 'relative',
|
||||
textAlign: 'center',
|
||||
minHeight: pxToRem(200),
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
marginBottom: '16px'
|
||||
}}
|
||||
>
|
||||
<MDBox
|
||||
component="input"
|
||||
name="file"
|
||||
disabled={!multiple && images.length}
|
||||
accept={accept}
|
||||
type="file"
|
||||
sx={{
|
||||
width: '100%',
|
||||
opacity: '0',
|
||||
cursor: 'pointer',
|
||||
position: 'absolute',
|
||||
top: '0',
|
||||
left: '0',
|
||||
right: '0',
|
||||
bottom: '0'
|
||||
}}
|
||||
onChange={addImage}
|
||||
/>
|
||||
<MDBox component="span">
|
||||
{!multiple && images.length ? null : <UploadIcon />}
|
||||
<MDTypography
|
||||
component="span"
|
||||
sx={{ color: '#000', letterSpacing: '0.01em', display: 'block' }}
|
||||
>
|
||||
{!multiple && images.length ? 'Cannot add more images' : heading}
|
||||
</MDTypography>
|
||||
</MDBox>
|
||||
</MDBox>
|
||||
{/* -----------img-preview----------- */}
|
||||
<MDBox sx={{ marginBottom: '-10px' }}>
|
||||
{images &&
|
||||
images.map((item, idx) => {
|
||||
return (
|
||||
<MDBox
|
||||
key={idx}
|
||||
component="span"
|
||||
sx={{
|
||||
width: '80px',
|
||||
height: '63px',
|
||||
marginRight: '16px',
|
||||
display: 'inline-block',
|
||||
borderRadius: '4px',
|
||||
position: 'relative'
|
||||
}}
|
||||
>
|
||||
<img src={item.src} alt="placeholder" width="100%" />
|
||||
<Button
|
||||
sx={{
|
||||
backgroundColor: '#fff !important',
|
||||
boxShadow: '0px 1px 1px rgb(0 0 0 / 25%)',
|
||||
padding: '0',
|
||||
minWidth: '20px',
|
||||
minHeight: '20px',
|
||||
borderRadius: '100%',
|
||||
position: 'absolute',
|
||||
right: '4px',
|
||||
top: '4px',
|
||||
'&:hover': {
|
||||
backgroundColor: 'red !important'
|
||||
}
|
||||
}}
|
||||
onClick={() => {
|
||||
removeImage(idx);
|
||||
}}
|
||||
>
|
||||
<Close />
|
||||
</Button>
|
||||
</MDBox>
|
||||
);
|
||||
})}
|
||||
</MDBox>
|
||||
</MDBox>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default ImageUpload;
|
||||
ImageUpload.propTypes = {
|
||||
images: PropTypes.array,
|
||||
heading: PropTypes.string,
|
||||
multiple: PropTypes.bool,
|
||||
accept: PropTypes.string,
|
||||
setImages: PropTypes.func
|
||||
};
|
||||
@@ -1,33 +1,43 @@
|
||||
import * as React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import Pagination from '@mui/material/Pagination';
|
||||
import Stack from '@mui/material/Stack';
|
||||
import { PaginationItem } from '@mui/material';
|
||||
import NextIcon from 'assets/images/NextIcon';
|
||||
import PreviousIcon from 'assets/images/PreviousIcon';
|
||||
|
||||
function TablePagination() {
|
||||
function TablePagination({ count, page, setPage }) {
|
||||
return (
|
||||
<Stack spacing={2}>
|
||||
<Pagination
|
||||
count={10}
|
||||
shape="rounded"
|
||||
color="primary"
|
||||
size="large"
|
||||
<Pagination
|
||||
count={count}
|
||||
page={page}
|
||||
shape="rounded"
|
||||
color="primary"
|
||||
size="large"
|
||||
renderItem={(item) => (
|
||||
<PaginationItem
|
||||
components={{ previous: PreviousIcon, next: NextIcon }}
|
||||
{...item}
|
||||
sx={{
|
||||
minWidth:'20px',
|
||||
fontWeight:'500',
|
||||
minWidth: '20px',
|
||||
fontWeight: '500',
|
||||
height: '30px'
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
onChange={(event, value) => {
|
||||
setPage(value);
|
||||
}}
|
||||
/>
|
||||
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
|
||||
TablePagination.propTypes = {
|
||||
page: PropTypes.number,
|
||||
count: PropTypes.number,
|
||||
setPage: PropTypes.any
|
||||
};
|
||||
|
||||
export default TablePagination;
|
||||
|
||||
@@ -11,7 +11,8 @@ export default {
|
||||
ADD_NEW_BAY: '/bay',
|
||||
ADD_NEW_LEVEL: '/level',
|
||||
ADD_NEW_SUBLEVEL: '/sublevel',
|
||||
ADD_PRODUCT: '/item/',
|
||||
ADD_ITEM: '/item/',
|
||||
EDIT_ITEM: '/item/',
|
||||
ADD_INVENTORY: '/inventory',
|
||||
GET_INVENTORY: '/inventory/all?page=0&perPage=50',
|
||||
GET_INVENTORY_TYPES: '/inventory/types',
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable indent */
|
||||
/* eslint-disable complexity */
|
||||
import * as React from 'react';
|
||||
import { Grid, TextField, Box, FormHelperText, TextareaAutosize } from '@mui/material';
|
||||
@@ -7,7 +8,7 @@ import DashboardLayout from 'layouts/DashboardLayout';
|
||||
import Select from '@mui/material/Select';
|
||||
import MenuItem from '@mui/material/MenuItem';
|
||||
import FormControl from '@mui/material/FormControl';
|
||||
import ImageUpload from 'components/ImageUpload';
|
||||
import ImageUploadMultiple from 'components/ImageUploadMultiple';
|
||||
import MDButton from 'components/Button';
|
||||
import Dialog from '@mui/material/Dialog';
|
||||
import DialogContent from '@mui/material/DialogContent';
|
||||
@@ -16,13 +17,15 @@ import { useFormik } from 'formik';
|
||||
import schema from 'services/ValidationServices';
|
||||
import MDInput from 'components/MDInput';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import ProductActions from 'redux/ProductsRedux';
|
||||
import { API } from 'constant';
|
||||
import LOGGER from 'services/Logger';
|
||||
import Breadcrumbs from 'components/Breadcrumbs';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { WidgetSelectors } from 'redux/WidgetRedux';
|
||||
import WidgetActions from 'redux/WidgetRedux';
|
||||
import ItemActions from 'redux/ItemRedux';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { ItemSelectors } from 'redux/ItemRedux';
|
||||
|
||||
const useStyles = makeStyles({
|
||||
labelSize: {
|
||||
@@ -48,11 +51,68 @@ const useStyles = makeStyles({
|
||||
|
||||
function AddNewItem() {
|
||||
const classes = useStyles();
|
||||
const { widgetName, inventoryId } = useParams();
|
||||
const { widgetName, inventoryId, itemId } = useParams();
|
||||
const getInitialFormValues = (data) => {
|
||||
return data && data._id === itemId
|
||||
? {
|
||||
commonName: data.commonName,
|
||||
formalName: data.formalName,
|
||||
description: data.description,
|
||||
manufacturer: data.manufacturer,
|
||||
size: data.size,
|
||||
color: data.color,
|
||||
type: data.type,
|
||||
unitOfMaterial: data.unitOfMaterial,
|
||||
unitCost: data.unitCost,
|
||||
packageCount: data.packageCount,
|
||||
countPerPallet: data.countPerPallet,
|
||||
countPerPalletPackage: data.countPerPalletPackage,
|
||||
primaryWidgetFamilyId: data.widgetFamily.parent
|
||||
? data.widgetFamily.parent
|
||||
: data.widgetFamily._id,
|
||||
secondaryWidgetFamilyId: data.widgetFamily.parent ? data.widgetFamily._id : '',
|
||||
policiesMetadata: {
|
||||
underStockLevelCount: data.policiesMetadata.underStockLevelCount,
|
||||
overStockLevelCount: data.policiesMetadata.overStockLevelCount,
|
||||
alertStockLevelCount: data.policiesMetadata.alertStockLevelCount,
|
||||
reorderStockLevelCount: data.policiesMetadata.reorderStockLevelCount
|
||||
},
|
||||
images: data.images.map((img) => ({ ...img, src: img.url }))
|
||||
}
|
||||
: {
|
||||
commonName: '',
|
||||
formalName: '',
|
||||
description: '',
|
||||
manufacturer: '',
|
||||
size: '',
|
||||
color: '',
|
||||
type: '',
|
||||
unitOfMaterial: '',
|
||||
unitCost: 0,
|
||||
packageCount: 0,
|
||||
countPerPallet: 0,
|
||||
countPerPalletPackage: 0,
|
||||
primaryWidgetFamilyId: '',
|
||||
secondaryWidgetFamilyId: '',
|
||||
policiesMetadata: {
|
||||
underStockLevelCount: 0,
|
||||
overStockLevelCount: 0,
|
||||
alertStockLevelCount: 0,
|
||||
reorderStockLevelCount: 0
|
||||
},
|
||||
images: []
|
||||
};
|
||||
};
|
||||
const itemData = getInitialFormValues(useSelector(ItemSelectors.getFormItem(itemId)));
|
||||
const dispatch = useDispatch();
|
||||
const [Manufacturer, setManufacturer] = React.useState('');
|
||||
const [open, setOpen] = React.useState(false);
|
||||
|
||||
const navigate = useNavigate();
|
||||
const navigateTo = (path) => {
|
||||
navigate(path);
|
||||
};
|
||||
|
||||
React.useEffect(() => {
|
||||
dispatch(
|
||||
WidgetActions.widgetRequest({
|
||||
@@ -61,74 +121,99 @@ function AddNewItem() {
|
||||
method: 'get'
|
||||
})
|
||||
);
|
||||
|
||||
itemId &&
|
||||
dispatch(
|
||||
ItemActions.oneItemRequest({
|
||||
loader: 'location-request',
|
||||
slug: API.EDIT_ITEM,
|
||||
method: 'get',
|
||||
widgetName,
|
||||
inventoryId,
|
||||
itemId
|
||||
})
|
||||
);
|
||||
}, []);
|
||||
|
||||
const [pFam, setPFam] = React.useState(null);
|
||||
const primaryFamily = useSelector(WidgetSelectors.getWidgetFamiliesByInventoryId(inventoryId));
|
||||
const secondaryFamily = useSelector(WidgetSelectors.getWidgetsByParentId(pFam));
|
||||
LOGGER.log({ primaryFamily, secondaryFamily });
|
||||
|
||||
const formik = useFormik({
|
||||
initialValues: {
|
||||
commonName: '',
|
||||
formalName: '',
|
||||
description: '',
|
||||
manufacturer: '',
|
||||
size: '',
|
||||
color: '',
|
||||
type: '',
|
||||
unitOfMaterial: '',
|
||||
unitCost: 0,
|
||||
packageCount: 0,
|
||||
countPerPallet: 0,
|
||||
countPerPalletPackage: 0,
|
||||
primaryWidgetFamilyId: '',
|
||||
secondaryWidgetFamilyId: '',
|
||||
policiesMetadata: {
|
||||
underStockLevelCount: 0,
|
||||
overStockLevelCount: 0,
|
||||
alertStockLevelCount: 0,
|
||||
reorderStockLevelCount: 0
|
||||
},
|
||||
images: []
|
||||
},
|
||||
enableReinitialize: true,
|
||||
initialValues: itemData,
|
||||
validationSchema: schema.addNewItem,
|
||||
onSubmit: (values, onSubmitProps) => {
|
||||
onSubmit: (values) => {
|
||||
LOGGER.log('values', values);
|
||||
dispatch(
|
||||
ProductActions.addProductAction({
|
||||
loader: 'loading-request',
|
||||
slug: API.ADD_PRODUCT,
|
||||
method: 'post',
|
||||
data: {
|
||||
commonName: values.commonName,
|
||||
formalName: values.formalName,
|
||||
description: values.description,
|
||||
manufacturer: values.manufacturer,
|
||||
size: values.size,
|
||||
color: values.color,
|
||||
type: values.type,
|
||||
unitOfMaterial: values.unitOfMaterial,
|
||||
unitCost: values.unitCost,
|
||||
packageCount: values.packageCount,
|
||||
countPerPallet: values.countPerPallet,
|
||||
countPerPalletPackage: values.countPerPalletPackage,
|
||||
customAttributes: [],
|
||||
policiesMetadata: {
|
||||
underStockLevelCount: values.policiesMetadata.underStockLevelCount,
|
||||
overStockLevelCount: values.policiesMetadata.overStockLevelCount,
|
||||
alertStockLevelCount: values.policiesMetadata.alertStockLevelCount,
|
||||
reorderStockLevelCount: values.policiesMetadata.reorderStockLevelCount
|
||||
},
|
||||
widgetFamilyId:
|
||||
values.secondaryWidgetFamilyId === ''
|
||||
? values.primaryWidgetFamilyId
|
||||
: values.secondaryWidgetFamilyId
|
||||
}
|
||||
})
|
||||
);
|
||||
// navigate to inventory page?
|
||||
onSubmitProps.resetForm();
|
||||
itemId
|
||||
? dispatch(
|
||||
ItemActions.editItemRequest({
|
||||
loader: 'loading-request',
|
||||
slug: `${API.EDIT_ITEM}${itemId}`,
|
||||
method: 'patch',
|
||||
navigateTo,
|
||||
data: {
|
||||
commonName: values.commonName,
|
||||
formalName: values.formalName,
|
||||
description: values.description,
|
||||
manufacturer: values.manufacturer,
|
||||
size: values.size,
|
||||
color: values.color,
|
||||
type: values.type,
|
||||
unitOfMaterial: values.unitOfMaterial,
|
||||
unitCost: values.unitCost,
|
||||
packageCount: values.packageCount,
|
||||
countPerPallet: values.countPerPallet,
|
||||
countPerPalletPackage: values.countPerPalletPackage,
|
||||
customAttributes: [], // TBD
|
||||
policiesMetadata: {
|
||||
underStockLevelCount: values.policiesMetadata.underStockLevelCount,
|
||||
overStockLevelCount: values.policiesMetadata.overStockLevelCount,
|
||||
alertStockLevelCount: values.policiesMetadata.alertStockLevelCount,
|
||||
reorderStockLevelCount: values.policiesMetadata.reorderStockLevelCount
|
||||
},
|
||||
widgetFamilyId:
|
||||
values.secondaryWidgetFamilyId === ''
|
||||
? values.primaryWidgetFamilyId
|
||||
: values.secondaryWidgetFamilyId,
|
||||
images: values.images
|
||||
}
|
||||
})
|
||||
)
|
||||
: dispatch(
|
||||
ItemActions.addItemRequest({
|
||||
loader: 'loading-request',
|
||||
slug: API.ADD_ITEM,
|
||||
method: 'post',
|
||||
navigateTo,
|
||||
data: {
|
||||
commonName: values.commonName,
|
||||
formalName: values.formalName,
|
||||
description: values.description,
|
||||
manufacturer: values.manufacturer,
|
||||
size: values.size,
|
||||
color: values.color,
|
||||
type: values.type,
|
||||
unitOfMaterial: values.unitOfMaterial,
|
||||
unitCost: values.unitCost,
|
||||
packageCount: values.packageCount,
|
||||
countPerPallet: values.countPerPallet,
|
||||
countPerPalletPackage: values.countPerPalletPackage,
|
||||
customAttributes: [], // TBD
|
||||
policiesMetadata: {
|
||||
underStockLevelCount: values.policiesMetadata.underStockLevelCount,
|
||||
overStockLevelCount: values.policiesMetadata.overStockLevelCount,
|
||||
alertStockLevelCount: values.policiesMetadata.alertStockLevelCount,
|
||||
reorderStockLevelCount: values.policiesMetadata.reorderStockLevelCount
|
||||
},
|
||||
widgetFamilyId:
|
||||
values.secondaryWidgetFamilyId === ''
|
||||
? values.primaryWidgetFamilyId
|
||||
: values.secondaryWidgetFamilyId,
|
||||
images: values.images
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -409,14 +494,27 @@ function AddNewItem() {
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Box>
|
||||
<ImageUpload
|
||||
heading="Upload Product Image"
|
||||
accept="image/*"
|
||||
images={formik.values.images}
|
||||
setImages={(images) => {
|
||||
formik.setFieldValue('images', images);
|
||||
}}
|
||||
/>
|
||||
{itemId ? (
|
||||
<ImageUploadMultiple
|
||||
multiple
|
||||
heading="Upload Product Image"
|
||||
accept="image/*"
|
||||
images={formik.values.images}
|
||||
setImages={(images) => {
|
||||
formik.setFieldValue('images', images);
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<ImageUploadMultiple
|
||||
multiple
|
||||
heading="Upload Product Image"
|
||||
accept="image/*"
|
||||
images={formik.values.images}
|
||||
setImages={(images) => {
|
||||
formik.setFieldValue('images', images);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</Box>
|
||||
<Box
|
||||
sx={{
|
||||
|
||||
@@ -19,7 +19,7 @@ import DashboardLayout from 'layouts/DashboardLayout';
|
||||
import ImageUploadSingle from 'components/ImageUploadSingle';
|
||||
import MDButton from 'components/Button';
|
||||
import { useFormik } from 'formik';
|
||||
import schema from 'services/ValidationServices';
|
||||
// import schema from 'services/ValidationServices';
|
||||
import MDInput from 'components/MDInput';
|
||||
import WarehouseActions from 'redux/WarehouseRedux';
|
||||
import { getChildLocationType } from 'utils/nestedTableTools';
|
||||
@@ -35,6 +35,8 @@ import { API } from 'constant';
|
||||
import NestedDataTable from 'components/NestedTable';
|
||||
import Breadcrumbs from 'components/Breadcrumbs';
|
||||
import { WarehouseSelectors } from 'redux/WarehouseRedux';
|
||||
import { InventorySelectors } from 'redux/InventoryRedux';
|
||||
import InventoryActions from 'redux/InventoryRedux';
|
||||
|
||||
const bottomButtonStyling = {
|
||||
width: '100%',
|
||||
@@ -313,12 +315,22 @@ const WarehouseNestedDetails = () => {
|
||||
);
|
||||
};
|
||||
|
||||
const inventoryTypes = ['Perishable', 'Material', 'Product', 'Inventory', 'Fleet'];
|
||||
|
||||
function EditWarehouseDetails() {
|
||||
const { warehouseId } = useParams();
|
||||
const warehouseData = useSelector(WarehouseSelectors.getWarehouseDetailById(warehouseId));
|
||||
|
||||
const inventoryTypes = useSelector(InventorySelectors.getInventoryDetail);
|
||||
|
||||
React.useEffect(() => {
|
||||
dispatch(
|
||||
InventoryActions.getInventoryAction({
|
||||
loader: 'loading-request',
|
||||
slug: API.GET_INVENTORY,
|
||||
method: 'get'
|
||||
})
|
||||
);
|
||||
}, []);
|
||||
|
||||
const ITEM_HEIGHT = 48;
|
||||
const ITEM_PADDING_TOP = 8;
|
||||
const MenuProps = {
|
||||
@@ -334,12 +346,12 @@ function EditWarehouseDetails() {
|
||||
const formik = useFormik({
|
||||
initialValues: {
|
||||
warehousename: warehouseData.name,
|
||||
address: warehouseData.address,
|
||||
inventorytype: [],
|
||||
specs: warehouseData.specs,
|
||||
image: [{ src: warehouseData.image_url }]
|
||||
address: warehouseData.address || '',
|
||||
preferredInventories: warehouseData.preferredInventories || [],
|
||||
specs: warehouseData.specs || '',
|
||||
image: warehouseData.image_url ? [{ src: warehouseData.image_url }] : []
|
||||
},
|
||||
validationSchema: schema.warehouseForm,
|
||||
// validationSchema: schema.warehouseForm,
|
||||
onSubmit: (values) => {
|
||||
dispatch(
|
||||
WarehouseActions.editWarehouseAction({
|
||||
@@ -350,6 +362,7 @@ function EditWarehouseDetails() {
|
||||
name: values.warehousename,
|
||||
address: values.address,
|
||||
specs: values.specs,
|
||||
preferredInventories: values.preferredInventories,
|
||||
image: values.image
|
||||
}
|
||||
})
|
||||
@@ -446,40 +459,45 @@ function EditWarehouseDetails() {
|
||||
<Select
|
||||
multiple
|
||||
select
|
||||
disabled
|
||||
fullWidth
|
||||
variant="outlined"
|
||||
name="inventorytype"
|
||||
name="preferredInventories"
|
||||
input={<OutlinedInput />}
|
||||
value={formik.values.inventorytype}
|
||||
error={formik.touched.inventorytype && Boolean(formik.errors.inventorytype)}
|
||||
helperText={formik.touched.inventorytype && formik.errors.inventorytype}
|
||||
value={formik.values.preferredInventories}
|
||||
error={
|
||||
formik.touched.preferredInventories &&
|
||||
Boolean(formik.errors.preferredInventories)
|
||||
}
|
||||
helperText={
|
||||
formik.touched.preferredInventories && formik.errors.preferredInventories
|
||||
}
|
||||
renderValue={(selected) => (
|
||||
<Box sx={{ display: 'flex', flexWrap: 'wrap', gap: 0.5 }}>
|
||||
{selected.map((value) => (
|
||||
<Chip key={value} label={value} />
|
||||
<Chip
|
||||
key={value}
|
||||
label={inventoryTypes.find((x) => x._id === value)?.name || 'unknown'}
|
||||
/>
|
||||
))}
|
||||
</Box>
|
||||
)}
|
||||
MenuProps={MenuProps}
|
||||
onChange={(event) => {
|
||||
const {
|
||||
target: { value }
|
||||
} = event;
|
||||
onChange={(e) => {
|
||||
const value = e.target.value;
|
||||
formik.setFieldValue(
|
||||
'inventorytype',
|
||||
'preferredInventories',
|
||||
// On autofill we get a stringified value.
|
||||
typeof value === 'string' ? value.split(',') : value
|
||||
);
|
||||
}}
|
||||
>
|
||||
<MenuItem key={''} value={''}>
|
||||
None Selected
|
||||
</MenuItem>
|
||||
{inventoryTypes.map((name) => (
|
||||
<MenuItem key={name} value={name}>
|
||||
{name}
|
||||
</MenuItem>
|
||||
))}
|
||||
{inventoryTypes &&
|
||||
inventoryTypes.map((inventory) => (
|
||||
<MenuItem key={inventory._id} value={inventory._id}>
|
||||
{inventory.name}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
</Box>
|
||||
<Box component="div" sx={{ marginBottom: '15px' }}>
|
||||
|
||||
@@ -10,41 +10,54 @@ import { useParams } from 'react-router-dom';
|
||||
import LOGGER from 'services/Logger';
|
||||
import { ItemSelectors } from 'redux/ItemRedux';
|
||||
import EnhancedTable from 'components/EnhancedTable';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
|
||||
const tHeads = [
|
||||
{ key: 'name', name: '' },
|
||||
{ key: 'commonName', name: 'Common Name' },
|
||||
{ key: 'formalName', name: 'Formal Name' },
|
||||
{ key: 'description', name: 'Description' },
|
||||
{ key: 'manufacturer', name: 'Manufacturer' }
|
||||
{ key: 'manufacturer', name: 'Manufacturer' },
|
||||
{ key: 'size', name: 'size' },
|
||||
{ key: 'color', name: 'color' },
|
||||
{ key: 'type', name: 'type' },
|
||||
{ key: 'unitOfMaterial', name: 'unitOfMaterial' },
|
||||
{ key: 'unitCost', name: 'unitCost' },
|
||||
{ key: 'packageCount', name: 'packageCount' },
|
||||
{ key: 'countPerPallet', name: 'countPerPallet' },
|
||||
{ key: 'countPerPalletPackage', name: 'countPerPalletPackage' },
|
||||
{ key: 'totalQuantity', name: 'totalQuantity' },
|
||||
{ key: 'reservedQuantity', name: 'reservedQuantity' },
|
||||
{ key: 'availableQuantity', name: 'availableQuantity' }
|
||||
];
|
||||
|
||||
function ItemListing() {
|
||||
const dispatch = useDispatch();
|
||||
const { widgetName, inventoryId } = useParams();
|
||||
const [page /*, setPage*/] = React.useState(0);
|
||||
const [perPage /*, setPerPage*/] = React.useState(10);
|
||||
const [page, setPage] = React.useState(1);
|
||||
const [perPage, setPerPage] = React.useState(10);
|
||||
LOGGER.log({ widgetName, inventoryId });
|
||||
|
||||
const data = useSelector(ItemSelectors.getItemsByInventoryId(inventoryId));
|
||||
const navigate = useNavigate();
|
||||
const navigateTo = (path) => {
|
||||
navigate(path);
|
||||
};
|
||||
|
||||
React.useEffect(
|
||||
() => {
|
||||
dispatch(
|
||||
ItemActions.itemRequest({
|
||||
loader: 'loading-request',
|
||||
slug: API.GET_ITEMS_BY_INVENTORY,
|
||||
method: 'get',
|
||||
page,
|
||||
perPage,
|
||||
inventoryId
|
||||
})
|
||||
);
|
||||
},
|
||||
[
|
||||
/* page, perPage */
|
||||
]
|
||||
);
|
||||
const data = useSelector(ItemSelectors.getItems);
|
||||
const count = useSelector(ItemSelectors.getItemsCount);
|
||||
|
||||
React.useEffect(() => {
|
||||
dispatch(
|
||||
ItemActions.itemRequest({
|
||||
loader: 'loading-request',
|
||||
slug: API.GET_ITEMS_BY_INVENTORY,
|
||||
method: 'get',
|
||||
page: page - 1,
|
||||
perPage,
|
||||
inventoryId
|
||||
})
|
||||
);
|
||||
}, [page, perPage]);
|
||||
|
||||
return (
|
||||
<DashboardLayout>
|
||||
@@ -60,7 +73,18 @@ function ItemListing() {
|
||||
|
||||
<MDBox px={2} py={3}>
|
||||
List of {widgetName}s{/* <pre>{JSON.stringify(data, null, 4)}</pre> */}
|
||||
<EnhancedTable data={data} tHeads={tHeads} />
|
||||
<EnhancedTable
|
||||
count={count}
|
||||
page={page}
|
||||
setPage={setPage}
|
||||
perPage={perPage}
|
||||
setPerPage={setPerPage}
|
||||
editHandler={(id) => {
|
||||
navigateTo(`/setup/inventory/browse/${widgetName}/${inventoryId}/edit/${id}`);
|
||||
}}
|
||||
data={data}
|
||||
tHeads={tHeads}
|
||||
/>
|
||||
</MDBox>
|
||||
</DashboardLayout>
|
||||
);
|
||||
|
||||
@@ -1,23 +1,35 @@
|
||||
import React from 'react';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { Box, Grid, MenuItem, OutlinedInput, Chip, Select } from '@mui/material';
|
||||
import DashboardNavbar from 'components/DashboardNavbar';
|
||||
import DashboardLayout from 'layouts/DashboardLayout';
|
||||
import ImageUploadSingle from 'components/ImageUploadSingle';
|
||||
import MDButton from 'components/Button';
|
||||
import { useFormik } from 'formik';
|
||||
import schema from 'services/ValidationServices';
|
||||
// import schema from 'services/ValidationServices';
|
||||
import MDInput from 'components/MDInput';
|
||||
import WarehouseActions from 'redux/WarehouseRedux';
|
||||
import { API } from 'constant';
|
||||
import Breadcrumbs from 'components/Breadcrumbs';
|
||||
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
|
||||
const inventoryTypes = ['Perishable', 'Material', 'Product', 'Inventory', 'Fleet'];
|
||||
import { InventorySelectors } from 'redux/InventoryRedux';
|
||||
import InventoryActions from 'redux/InventoryRedux';
|
||||
|
||||
function NewWarehouseDetails() {
|
||||
const dispatch = useDispatch();
|
||||
const inventoryTypes = useSelector(InventorySelectors.getInventoryDetail);
|
||||
|
||||
React.useEffect(() => {
|
||||
dispatch(
|
||||
InventoryActions.getInventoryAction({
|
||||
loader: 'loading-request',
|
||||
slug: API.GET_INVENTORY,
|
||||
method: 'get'
|
||||
})
|
||||
);
|
||||
}, []);
|
||||
|
||||
const navigate = useNavigate();
|
||||
|
||||
const navigateTo = (id) => {
|
||||
@@ -38,11 +50,11 @@ function NewWarehouseDetails() {
|
||||
initialValues: {
|
||||
warehousename: '',
|
||||
address: '',
|
||||
inventorytype: [],
|
||||
preferredInventories: [],
|
||||
specs: '',
|
||||
image: []
|
||||
},
|
||||
validationSchema: schema.warehouseForm,
|
||||
// validationSchema: schema.warehouseForm,
|
||||
onSubmit: (values) => {
|
||||
dispatch(
|
||||
WarehouseActions.createWarehouseAction({
|
||||
@@ -53,6 +65,7 @@ function NewWarehouseDetails() {
|
||||
data: {
|
||||
name: values.warehousename,
|
||||
address: values.address,
|
||||
preferredInventories: values.preferredInventories,
|
||||
specs: values.specs,
|
||||
image: values.image,
|
||||
company_id: '61cea5fd028432700a7f8601'
|
||||
@@ -153,25 +166,31 @@ function NewWarehouseDetails() {
|
||||
select
|
||||
fullWidth
|
||||
variant="outlined"
|
||||
name="inventorytype"
|
||||
name="preferredInventories"
|
||||
input={<OutlinedInput />}
|
||||
value={formik.values.inventorytype}
|
||||
error={formik.touched.inventorytype && Boolean(formik.errors.inventorytype)}
|
||||
helperText={formik.touched.inventorytype && formik.errors.inventorytype}
|
||||
value={formik.values.preferredInventories}
|
||||
error={
|
||||
formik.touched.preferredInventories &&
|
||||
Boolean(formik.errors.preferredInventories)
|
||||
}
|
||||
helperText={
|
||||
formik.touched.preferredInventories && formik.errors.preferredInventories
|
||||
}
|
||||
renderValue={(selected) => (
|
||||
<Box sx={{ display: 'flex', flexWrap: 'wrap', gap: 0.5 }}>
|
||||
{selected.map((value) => (
|
||||
<Chip key={value} label={value} />
|
||||
<Chip
|
||||
key={value}
|
||||
label={inventoryTypes.find((x) => x._id === value)?.name || 'unknown'}
|
||||
/>
|
||||
))}
|
||||
</Box>
|
||||
)}
|
||||
MenuProps={MenuProps}
|
||||
onChange={(event) => {
|
||||
const {
|
||||
target: { value }
|
||||
} = event;
|
||||
onChange={(e) => {
|
||||
const value = e.target.value;
|
||||
formik.setFieldValue(
|
||||
'inventorytype',
|
||||
'preferredInventories',
|
||||
// On autofill we get a stringified value.
|
||||
typeof value === 'string' ? value.split(',') : value
|
||||
);
|
||||
@@ -180,11 +199,12 @@ function NewWarehouseDetails() {
|
||||
<MenuItem key={''} value={''}>
|
||||
None Selected
|
||||
</MenuItem>
|
||||
{inventoryTypes.map((name) => (
|
||||
<MenuItem key={name} value={name}>
|
||||
{name}
|
||||
</MenuItem>
|
||||
))}
|
||||
{inventoryTypes &&
|
||||
inventoryTypes.map((inventory) => (
|
||||
<MenuItem key={inventory._id} value={inventory._id}>
|
||||
{inventory.name}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
</Box>
|
||||
<Box component="div" sx={{ marginBottom: '15px' }}>
|
||||
@@ -233,7 +253,14 @@ function NewWarehouseDetails() {
|
||||
columnGap: '20px'
|
||||
}}
|
||||
>
|
||||
<MDButton size="medium" color="error" variant="outlined">
|
||||
<MDButton
|
||||
size="medium"
|
||||
color="error"
|
||||
variant="outlined"
|
||||
onClick={() => {
|
||||
navigate('/setup/warehouse');
|
||||
}}
|
||||
>
|
||||
CANCEL
|
||||
</MDButton>
|
||||
<MDButton size="medium" color="primary" variant="outlined" type="submit">
|
||||
|
||||
@@ -7,10 +7,13 @@ import { getFetchingValue, getErrorValue } from '../services/Utils';
|
||||
const { Types, Creators } = createActions({
|
||||
itemRequest: ['payload'],
|
||||
itemSuccess: ['data'],
|
||||
itemFailure: ['error'],
|
||||
addItemRequest: ['payload'],
|
||||
addItemSuccess: ['data'],
|
||||
editItemRequest: ['payload'],
|
||||
editItemSuccess: ['data'],
|
||||
itemFailure: ['error'],
|
||||
logout: null
|
||||
oneItemRequest: ['payload'],
|
||||
oneItemSuccess: ['data']
|
||||
});
|
||||
|
||||
export const ItemTypes = Types;
|
||||
@@ -20,6 +23,8 @@ export default ItemActions;
|
||||
/* ------------- Initial State ------------- */
|
||||
export const INITIAL_STATE = Immutable({
|
||||
list: [],
|
||||
item: null,
|
||||
count: 0,
|
||||
fetching: [],
|
||||
error: {}
|
||||
});
|
||||
@@ -27,9 +32,9 @@ export const INITIAL_STATE = Immutable({
|
||||
/* ------------- Selectors ------------- */
|
||||
export const ItemSelectors = {
|
||||
getItems: (state) => state.items.list,
|
||||
getItemById: (id) => (state) => state.items.list.find((x) => x._id === id),
|
||||
getItemsByInventoryId: (id) => (state) =>
|
||||
state.items.list.filter((x) => x.widgetFamily?.inventory === id)
|
||||
getFormItem: (itemId) => (state) => state.items.item?._id === itemId ? state.items.item : null,
|
||||
getItemsCount: (state) => state.items.count,
|
||||
getItemById: (id) => (state) => state.items.list.find((x) => x._id === id)
|
||||
};
|
||||
|
||||
/* ------------- Reducers ------------- */
|
||||
@@ -39,49 +44,51 @@ export const onItemRequest = (state, { payload }) =>
|
||||
error: getErrorValue(state?.error, payload?.loader)
|
||||
});
|
||||
|
||||
export const onItemSuccess = (state, { data }) =>
|
||||
state.merge({
|
||||
fetching: getFetchingValue(state.fetching, data?.loader),
|
||||
error: getErrorValue(state?.error, data?.loader),
|
||||
list: data.items,
|
||||
count: data.count
|
||||
});
|
||||
|
||||
export const onOneItemRequest = (state, { payload }) =>
|
||||
state.merge({
|
||||
fetching: _.uniq([...state.fetching, payload?.loader]),
|
||||
error: getErrorValue(state?.error, payload?.loader)
|
||||
});
|
||||
|
||||
export const onOneItemSuccess = (state, { data }) =>
|
||||
state.merge({
|
||||
fetching: getFetchingValue(state.fetching, data?.loader),
|
||||
error: getErrorValue(state?.error, data?.loader),
|
||||
item: data.item
|
||||
});
|
||||
|
||||
export const onAddItemRequest = (state, { payload }) =>
|
||||
state.merge({
|
||||
fetching: _.uniq([...state.fetching, payload?.loader]),
|
||||
error: getErrorValue(state?.error, payload?.loader)
|
||||
});
|
||||
|
||||
export const onAddItemSuccess = (state, { data }) =>
|
||||
state.merge({
|
||||
fetching: getFetchingValue(state.fetching, data?.loader),
|
||||
error: getErrorValue(state?.error, data?.loader),
|
||||
item: null
|
||||
});
|
||||
|
||||
export const onEditItemRequest = (state, { payload }) =>
|
||||
state.merge({
|
||||
fetching: _.uniq([...state.fetching, payload?.loader]),
|
||||
error: getErrorValue(state?.error, payload?.loader)
|
||||
});
|
||||
|
||||
const mergeItemStates = (stateData, items) => {
|
||||
if (!items) return stateData; // undefined check
|
||||
|
||||
const idsInNewItems = items.map((x) => x._id);
|
||||
|
||||
const newState = stateData.filter((x) => !idsInNewItems.includes(x._id));
|
||||
|
||||
return [...newState, ...items];
|
||||
};
|
||||
|
||||
export const onItemSuccess = (state, { data }) =>
|
||||
state.merge({
|
||||
fetching: getFetchingValue(state.fetching, data?.loader),
|
||||
error: getErrorValue(state?.error, data?.loader),
|
||||
list: mergeItemStates(state.list, data.items)
|
||||
});
|
||||
|
||||
const mergeEditItemStates = (stateList, item, type) => {
|
||||
if (!item) return stateList; // undefined check
|
||||
|
||||
if (type === 'add') {
|
||||
return [...stateList, item];
|
||||
} else if (type === 'edit') {
|
||||
const newState = stateList.filter((x) => x._id !== item._id);
|
||||
return [...newState, item];
|
||||
// } else if (type === 'delete') {
|
||||
// return stateList.filter((x) => x._id !== item._id);
|
||||
} else {
|
||||
return stateList;
|
||||
}
|
||||
};
|
||||
|
||||
export const onEditItemSuccess = (state, { data }) =>
|
||||
state.merge({
|
||||
fetching: getFetchingValue(state.fetching, data?.loader),
|
||||
error: getErrorValue(state?.error, data?.loader),
|
||||
list: mergeEditItemStates(state.list, data.item, data.type)
|
||||
item: null
|
||||
});
|
||||
|
||||
export const onItemFailure = (state, { error }) =>
|
||||
@@ -93,8 +100,12 @@ export const onItemFailure = (state, { error }) =>
|
||||
/* ------------- Hookup Reducers To Types ------------- */
|
||||
export const itemReducer = createReducer(INITIAL_STATE, {
|
||||
[Types.ITEM_REQUEST]: onItemRequest,
|
||||
[Types.EDIT_ITEM_REQUEST]: onEditItemRequest,
|
||||
[Types.ITEM_SUCCESS]: onItemSuccess,
|
||||
[Types.ITEM_FAILURE]: onItemFailure,
|
||||
[Types.ADD_ITEM_REQUEST]: onAddItemRequest,
|
||||
[Types.ADD_ITEM_SUCCESS]: onAddItemSuccess,
|
||||
[Types.EDIT_ITEM_REQUEST]: onEditItemRequest,
|
||||
[Types.EDIT_ITEM_SUCCESS]: onEditItemSuccess,
|
||||
[Types.ITEM_FAILURE]: onItemFailure
|
||||
[Types.ONE_ITEM_REQUEST]: onOneItemRequest,
|
||||
[Types.ONE_ITEM_SUCCESS]: onOneItemSuccess
|
||||
});
|
||||
|
||||
@@ -158,6 +158,14 @@ const protectedRoutes = [
|
||||
route: '/setup/inventory/new-item/:widgetName/:inventoryId',
|
||||
component: <AddNewItem />
|
||||
},
|
||||
{
|
||||
name: 'Update Item',
|
||||
key: 'udpate-item',
|
||||
hide: true,
|
||||
route: '/setup/inventory/browse/:widgetName/:inventoryId/edit/:itemId',
|
||||
component: <AddNewItem />
|
||||
},
|
||||
// /setup/inventory/browse/${payload?.widgetName}/${payload?.inventoryId}/edit/${payload?.id}
|
||||
{
|
||||
name: 'View Items',
|
||||
key: 'view-items',
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { AuthorizedAPI } from 'config';
|
||||
import { toast } from 'react-toastify';
|
||||
import { call, put, takeEvery } from 'redux-saga/effects';
|
||||
import ApiServices from 'services/API/ApiServices';
|
||||
import ItemActions, { ItemTypes } from '../redux/ItemRedux';
|
||||
@@ -14,7 +15,8 @@ export function* onRequestItem({ payload }) {
|
||||
yield put(
|
||||
ItemActions.itemSuccess({
|
||||
loader: payload?.loader,
|
||||
items: response?.data?.data,
|
||||
items: response?.data?.data.result,
|
||||
count: response?.data?.data.count,
|
||||
page: payload?.page,
|
||||
reset: !payload.page
|
||||
})
|
||||
@@ -29,22 +31,24 @@ export function* onRequestItem({ payload }) {
|
||||
}
|
||||
}
|
||||
|
||||
export function* onEditRequestItem({ payload }) {
|
||||
export function* onRequestOneItem({ payload }) {
|
||||
const response = yield call(
|
||||
ApiServices[payload?.method],
|
||||
AuthorizedAPI,
|
||||
payload?.slug,
|
||||
payload?.data
|
||||
`${payload.slug}${payload?.itemId}`
|
||||
);
|
||||
if (response?.status === 200) {
|
||||
yield put(
|
||||
ItemActions.editItemSuccess({
|
||||
ItemActions.oneItemSuccess({
|
||||
loader: payload?.loader,
|
||||
item: response?.data?.data,
|
||||
type: payload?.type
|
||||
item: response?.data?.data
|
||||
})
|
||||
);
|
||||
// payload.navigateTo(
|
||||
// `/setup/inventory/browse/${payload?.widgetName}/${payload?.inventoryId}/edit/${payload?.itemId}`
|
||||
// );
|
||||
} else {
|
||||
toast('Failed to get item details');
|
||||
yield put(
|
||||
ItemActions.itemFailure({
|
||||
loader: payload?.loader,
|
||||
@@ -54,7 +58,98 @@ export function* onEditRequestItem({ payload }) {
|
||||
}
|
||||
}
|
||||
|
||||
function addImagesToFormData(formData, images) {
|
||||
let imgIdx = 0;
|
||||
let preImgIdx = 0;
|
||||
images.forEach((image) => {
|
||||
if (image.file) formData.append(`images[${imgIdx++}]`, image.file);
|
||||
else formData.append(`imageIds[${preImgIdx++}]`, image._id);
|
||||
});
|
||||
}
|
||||
|
||||
function buildFormData(formData, data, parentKey) {
|
||||
if (data && typeof data === 'object' && !(data instanceof Date) && !(data instanceof File)) {
|
||||
Object.keys(data).forEach((key) => {
|
||||
if (key !== 'images')
|
||||
buildFormData(formData, data[key], parentKey ? `${parentKey}[${key}]` : key);
|
||||
else addImagesToFormData(formData, data['images']);
|
||||
});
|
||||
} else {
|
||||
// eslint-disable-next-line eqeqeq
|
||||
const value = data == null ? '' : data;
|
||||
|
||||
formData.append(parentKey, value);
|
||||
}
|
||||
}
|
||||
|
||||
const createFormData = (data) => {
|
||||
const formData = new FormData();
|
||||
|
||||
buildFormData(formData, data);
|
||||
|
||||
return formData;
|
||||
};
|
||||
|
||||
export function* onAddRequestItem({ payload }) {
|
||||
const response = yield call(
|
||||
ApiServices[payload?.method],
|
||||
AuthorizedAPI,
|
||||
payload?.slug,
|
||||
createFormData(payload?.data)
|
||||
);
|
||||
if (response?.status === 200) {
|
||||
toast(`Added item: ${payload.data.commonName}`);
|
||||
// payload.navigateTo(
|
||||
// `/setup/inventory/browse/${payload?.widgetName}/${payload?.inventoryId}/edit/${response?.data?.data?._id}`
|
||||
// );
|
||||
payload.navigateTo('/setup/inventory');
|
||||
yield put(
|
||||
ItemActions.addItemSuccess({
|
||||
loader: payload?.loader,
|
||||
item: response?.data?.data
|
||||
})
|
||||
);
|
||||
} else {
|
||||
toast('Failed to add item');
|
||||
yield put(
|
||||
ItemActions.itemFailure({
|
||||
loader: payload?.loader,
|
||||
error: response?.data
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export function* onEditRequestItem({ payload }) {
|
||||
const response = yield call(
|
||||
ApiServices[payload?.method],
|
||||
AuthorizedAPI,
|
||||
payload?.slug,
|
||||
createFormData(payload?.data)
|
||||
);
|
||||
if (response?.status === 200) {
|
||||
toast(`Successfully edited item: ${payload.data.commonName}`);
|
||||
payload.navigateTo('/setup/inventory');
|
||||
yield put(
|
||||
ItemActions.addItemSuccess({
|
||||
loader: payload?.loader,
|
||||
item: response?.data?.data
|
||||
})
|
||||
);
|
||||
} else {
|
||||
toast('Failed to edit item');
|
||||
yield put(
|
||||
ItemActions.itemFailure({
|
||||
loader: payload?.loader,
|
||||
error: response?.data
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default [
|
||||
takeEvery(ItemTypes.ITEM_REQUEST, onRequestItem),
|
||||
takeEvery(ItemTypes.ONE_ITEM_REQUEST, onRequestOneItem),
|
||||
takeEvery(ItemTypes.ADD_ITEM_REQUEST, onAddRequestItem),
|
||||
takeEvery(ItemTypes.EDIT_ITEM_REQUEST, onEditRequestItem)
|
||||
];
|
||||
|
||||
@@ -35,6 +35,10 @@ const makeFormData = (data) => {
|
||||
if (data.address) formData.append('address', data.address);
|
||||
if (data.specs) formData.append('specs', data.specs);
|
||||
if (data.company_id) formData.append('company_id', data.company_id);
|
||||
if (data.preferredInventories)
|
||||
data.preferredInventories.forEach((prefInv, idx) => {
|
||||
formData.append(`preferredInventories[${idx}]`, prefInv);
|
||||
});
|
||||
if (data.image[0].file) formData.append('image', data.image[0].file);
|
||||
return formData;
|
||||
};
|
||||
@@ -47,11 +51,15 @@ export function* onRequestCreateWarehouse({ payload }) {
|
||||
makeFormData(payload?.data)
|
||||
);
|
||||
if (response?.status === 200 && response?.data?.message) {
|
||||
const warehouse = response?.data?.message;
|
||||
toast('Warehouse created successfully');
|
||||
yield put(
|
||||
WarehouseActions.createWarehouseSuccess({
|
||||
loader: payload?.loader,
|
||||
createdWarehouse: response?.data?.message
|
||||
createdWarehouse: {
|
||||
...warehouse,
|
||||
preferredInventories: warehouse.preferredInventories.map((z) => z._id)
|
||||
}
|
||||
})
|
||||
);
|
||||
payload.navigateTo(response?.data?.message?._id);
|
||||
@@ -73,12 +81,16 @@ export function* onRequestEditWarehouse({ payload }) {
|
||||
payload?.slug,
|
||||
makeFormData(payload?.data)
|
||||
);
|
||||
if (response?.status === 200) {
|
||||
if (response?.status === 200 && response?.data?.data) {
|
||||
toast('Warehouse edited successfully');
|
||||
const warehouse = response?.data?.data;
|
||||
yield put(
|
||||
WarehouseActions.editWarehouseSuccess({
|
||||
loader: payload?.loader,
|
||||
editedWarehouse: response?.data?.data
|
||||
editedWarehouse: {
|
||||
...warehouse,
|
||||
preferredInventories: warehouse.preferredInventories.map((z) => z._id)
|
||||
}
|
||||
})
|
||||
);
|
||||
} else {
|
||||
|
||||
@@ -22,10 +22,11 @@ const schema = {
|
||||
warehouseForm: Yup.object({
|
||||
warehousename: Yup.string('Enter warehouse name').required('warehouse name is required'),
|
||||
address: Yup.string('Enter address').required('address is required'),
|
||||
inventorytype: Yup.array('Enter inventory Type')
|
||||
preferredInventories: Yup.array('Enter inventory Type')
|
||||
.of(Yup.string())
|
||||
.required('inventory Type is required'),
|
||||
attributes: Yup.string('Enter other attributes')
|
||||
specs: Yup.string('Enter other attributes'),
|
||||
image: Yup.array()
|
||||
}),
|
||||
|
||||
addNewItem: Yup.object({
|
||||
|
||||
Reference in New Issue
Block a user