Fixes/ll inventory (#69)
* inventory data changes * update Inventory changes * Fixed: removed unnecessary imports * Disabled: cycle count * Added: Inventory types sagas * Fix: null check * Updated: policies * Fixed: formik values * update: allow single image * Update: Policies control * Updated: new inventory add form * Update: new inventory conditional render * Update: populate formik fields * Added: Validation * Added: edit functionality, disabled fields * Update: housekeeping * Fix: iconslug and key * Update: route handling * Added: endpoints * Added: widget nested page * Added: sagas * Added: redux handling * Update: new product page functionality * Added: inventory page functionality * Fixed: form validation * Fix: route handling Co-authored-by: evdigitech <evdigitech@gmail.com> Co-authored-by: Llewellyn Dsouza <lledsouza2209@gmail.com>
This commit is contained in:
@@ -34,24 +34,24 @@ export default function Tile({ data, children }) {
|
||||
</Box>
|
||||
</AccordionSummary>
|
||||
<AccordionDetails className={`${classes.row2} ${expand ? null : classes.remove}`}>
|
||||
<Link to={data.path.update}>
|
||||
<Link to={`/setup/inventory/update/${data.id}`}>
|
||||
<Box className={classes.box}>
|
||||
Update {data.name} <ArrowRightIcon />
|
||||
</Box>
|
||||
</Link>
|
||||
<Link to={data.path.addNew}>
|
||||
<Link to={`/setup/inventory/new-item/${data.widgetname}/${data.id}`}>
|
||||
<Box className={`${classes.box} ${classes.boxEven}`}>
|
||||
Add New {data.name} <ArrowRightIcon />
|
||||
Add New {data.widgetname} <ArrowRightIcon />
|
||||
</Box>
|
||||
</Link>
|
||||
<Link to={data.path.cycleCount}>
|
||||
<Box className={classes.box}>
|
||||
<Link to="#">
|
||||
<Box className={classes.boxDisabled}>
|
||||
Cycle Count <ArrowRightIcon />
|
||||
</Box>
|
||||
</Link>
|
||||
<Link to={data.path.list}>
|
||||
<Link to="/">
|
||||
<Box className={`${classes.box} ${classes.boxEven}`}>
|
||||
{data.name} List <ArrowRightIcon />
|
||||
{data.widgetname} List <ArrowRightIcon />
|
||||
</Box>
|
||||
</Link>
|
||||
</AccordionDetails>
|
||||
|
||||
@@ -83,6 +83,23 @@ const useStyles = makeStyles({
|
||||
},
|
||||
remove: {
|
||||
display: 'none'
|
||||
},
|
||||
boxDisabled: {
|
||||
display: 'flex',
|
||||
color: '#cccccc',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
padding: '13px 0 13px 10px',
|
||||
borderTop: '1px solid lightgray',
|
||||
'& svg': {
|
||||
opacity: '0'
|
||||
},
|
||||
'&:hover': {
|
||||
cursor: 'auto',
|
||||
'& svg': {
|
||||
opacity: '0'
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
329
src/components/WidgetNestedDataTable/index.js
Normal file
329
src/components/WidgetNestedDataTable/index.js
Normal file
@@ -0,0 +1,329 @@
|
||||
/* eslint-disable indent */
|
||||
import {
|
||||
Box,
|
||||
Dialog,
|
||||
DialogActions,
|
||||
DialogContent,
|
||||
DialogTitle,
|
||||
Grid,
|
||||
TextField
|
||||
} from '@mui/material';
|
||||
import React, { useEffect } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import KeyboardArrowRightIcon from '@mui/icons-material/KeyboardArrowRight';
|
||||
import KeyboardArrowUpIcon from '@mui/icons-material/KeyboardArrowUp';
|
||||
import IconButton from '@mui/material/IconButton';
|
||||
import MDButton from 'components/Button';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { WidgetSelectors } from 'redux/WidgetRedux';
|
||||
import WidgetActions from 'redux/WidgetRedux';
|
||||
import { API } from 'constant';
|
||||
import { useFormik } from 'formik';
|
||||
import LOGGER from 'services/Logger';
|
||||
|
||||
function MaterialForm({ formType, setFormOpen, selected, inventoryId }) {
|
||||
const dispatch = useDispatch();
|
||||
const formik = useFormik({
|
||||
initialValues:
|
||||
formType === 'family'
|
||||
? { name: '', inventoryId }
|
||||
: formType === 'subfamily'
|
||||
? { name: '', inventoryId, parentId: selected._id || '' }
|
||||
: { name: formType.name, inventoryId, parentId: formType.parent?._id || undefined },
|
||||
onSubmit: (values) => {
|
||||
LOGGER.log('Form values and field info', values);
|
||||
['family', 'subfamily'].includes(formType)
|
||||
? dispatch(
|
||||
WidgetActions.editWidgetRequest({
|
||||
loader: 'location-request',
|
||||
slug: API.ADD_WIDGET_FAMILY,
|
||||
method: 'post',
|
||||
data: values,
|
||||
type: 'add'
|
||||
})
|
||||
)
|
||||
: dispatch(
|
||||
WidgetActions.editWidgetRequest({
|
||||
loader: 'location-request',
|
||||
slug: `${API.EDIT_WIDGET_FAMILY}${inventoryId}`,
|
||||
method: 'patch',
|
||||
data: values,
|
||||
type: 'edit'
|
||||
})
|
||||
);
|
||||
setFormOpen(false);
|
||||
}
|
||||
});
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
open
|
||||
onClose={() => {
|
||||
setFormOpen(false);
|
||||
}}
|
||||
>
|
||||
<DialogTitle>
|
||||
{['family', 'subfamily'].includes(formType) ? 'Create' : 'Edit'} material{' '}
|
||||
{['family', 'subfamily'].includes(formType) ? formType : null}
|
||||
</DialogTitle>
|
||||
<DialogContent>
|
||||
{/* <DialogContentText>Some more text if needed</DialogContentText> */}
|
||||
<TextField
|
||||
autoFocus
|
||||
fullWidth
|
||||
margin="dense"
|
||||
label="Name"
|
||||
type="text"
|
||||
name="name"
|
||||
variant="standard"
|
||||
value={formik.values.name}
|
||||
error={formik.touched.name && Boolean(formik.errors.name)}
|
||||
helperText={formik.touched.name && formik.errors.name}
|
||||
onChange={formik.handleChange}
|
||||
/>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<MDButton
|
||||
onClick={() => {
|
||||
setFormOpen(false);
|
||||
}}
|
||||
>
|
||||
Cancel
|
||||
</MDButton>
|
||||
<MDButton onClick={formik.handleSubmit}>Save</MDButton>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
|
||||
MaterialForm.propTypes = {
|
||||
formType: PropTypes.any,
|
||||
setFormOpen: PropTypes.any,
|
||||
selected: PropTypes.any,
|
||||
inventoryId: PropTypes.any
|
||||
};
|
||||
|
||||
function WidgetNestedDataTable({
|
||||
data,
|
||||
selected,
|
||||
setSelected,
|
||||
setFormOpen,
|
||||
setFormType,
|
||||
inventoryId
|
||||
}) {
|
||||
const [open, setOpen] = React.useState(false);
|
||||
const widgetChildren = useSelector(WidgetSelectors.getWidgetsByParentId(data._id));
|
||||
|
||||
return (
|
||||
<>
|
||||
<Box
|
||||
sx={{
|
||||
borderLeftWidth: '2px',
|
||||
borderLeftStyle: 'solid',
|
||||
borderLeftColor: '#aedaed',
|
||||
|
||||
borderTopWidth: '1px',
|
||||
borderTopStyle: 'solid',
|
||||
borderTopColor: '#BDD0DB',
|
||||
|
||||
background:
|
||||
selected?._id === data._id
|
||||
? 'linear-gradient(135deg, ' + '#aedaed' + ' 0%, #f9f9f9 20%)'
|
||||
: '#f9f9f9'
|
||||
}}
|
||||
>
|
||||
<Grid container key={data._id}>
|
||||
<Grid item xs={2}>
|
||||
<IconButton
|
||||
disabled={!widgetChildren?.length}
|
||||
aria-label="expand row"
|
||||
size="small"
|
||||
sx={{ marginLeft: '12px' }}
|
||||
onClick={() => setOpen(!open)}
|
||||
>
|
||||
{open ? <KeyboardArrowUpIcon /> : <KeyboardArrowRightIcon />}
|
||||
</IconButton>
|
||||
<MDButton
|
||||
size="small"
|
||||
variant="contained"
|
||||
color="primary"
|
||||
sx={{
|
||||
textTransform: 'capitalize',
|
||||
minWidth: '45px',
|
||||
minHeight: '28px',
|
||||
marginLeft: '5px',
|
||||
marginRight: '20px',
|
||||
boxShadow: 'none',
|
||||
fontWeight: '500',
|
||||
padding: '0'
|
||||
}}
|
||||
onClick={() => {
|
||||
setFormType(data);
|
||||
setFormOpen(true);
|
||||
}}
|
||||
>
|
||||
EDIT
|
||||
</MDButton>
|
||||
</Grid>
|
||||
<Grid
|
||||
container
|
||||
item
|
||||
xs={10}
|
||||
onClick={() => {
|
||||
setSelected(data);
|
||||
}}
|
||||
>
|
||||
<Grid item xs={9}>
|
||||
{data.name}
|
||||
</Grid>
|
||||
<Grid item xs={1}>
|
||||
<MDButton
|
||||
disabled
|
||||
size="small"
|
||||
variant="contained"
|
||||
color="error"
|
||||
sx={{
|
||||
textTransform: 'capitalize',
|
||||
minWidth: '45px',
|
||||
minHeight: '28px',
|
||||
marginLeft: '5px',
|
||||
marginRight: '20px',
|
||||
boxShadow: 'none',
|
||||
fontWeight: '500',
|
||||
padding: '0 6'
|
||||
}}
|
||||
onClick={() => {
|
||||
// dispatch(
|
||||
// WarehouseLocationsActions.deleteLocationRequest({
|
||||
// loader: 'location-request',
|
||||
// slug: API.LOCATION_DELETE,
|
||||
// method: 'post',
|
||||
// data: { type: data.location, id: data.id }
|
||||
// })
|
||||
// );
|
||||
}}
|
||||
>
|
||||
DELETE
|
||||
</MDButton>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
{open && widgetChildren ? (
|
||||
<Box Box sx={{ marginLeft: '25px', marginBottom: '15px' }}>
|
||||
{/* Add headers here */}
|
||||
{widgetChildren.map((data) => (
|
||||
<WidgetNestedDataTable
|
||||
key={data._id}
|
||||
data={data}
|
||||
selected={selected}
|
||||
setSelected={setSelected}
|
||||
setFormOpen={setFormOpen}
|
||||
setFormType={setFormType}
|
||||
inventoryId={inventoryId}
|
||||
/>
|
||||
))}
|
||||
</Box>
|
||||
) : null}
|
||||
</Box>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
WidgetNestedDataTable.propTypes = {
|
||||
data: PropTypes.any,
|
||||
selected: PropTypes.any,
|
||||
setSelected: PropTypes.any,
|
||||
setFormOpen: PropTypes.any,
|
||||
setFormType: PropTypes.any,
|
||||
inventoryId: PropTypes.any
|
||||
};
|
||||
|
||||
const bottomButtonStyling = {
|
||||
width: '200px',
|
||||
marginTop: '25px',
|
||||
textTransform: 'uppercase',
|
||||
borderRadius: '100px',
|
||||
padding: '13px 30px'
|
||||
};
|
||||
|
||||
function WidgetNestedDataTableContainer({ inventoryId }) {
|
||||
const dispatch = useDispatch();
|
||||
const [selected, setSelected] = React.useState(null);
|
||||
const [formType, setFormType] = React.useState('family');
|
||||
const [formOpen, setFormOpen] = React.useState(false);
|
||||
const widgetFamilyData = useSelector(WidgetSelectors.getWidgetFamiliesByInventoryId(inventoryId));
|
||||
|
||||
useEffect(() => {
|
||||
dispatch(
|
||||
WidgetActions.widgetRequest({
|
||||
loader: 'location-request',
|
||||
slug: `${API.GET_WIDGET_FAMILY_BY_INVENTORY}${inventoryId}`,
|
||||
method: 'get'
|
||||
})
|
||||
);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<>
|
||||
{widgetFamilyData &&
|
||||
widgetFamilyData.map((p) => (
|
||||
<WidgetNestedDataTable
|
||||
key={p._id}
|
||||
data={p}
|
||||
selected={selected}
|
||||
setSelected={setSelected}
|
||||
setFormOpen={setFormOpen}
|
||||
setFormType={setFormType}
|
||||
/>
|
||||
))}
|
||||
<Grid container spacing={5} justifyContent="center">
|
||||
<Grid item>
|
||||
<MDButton
|
||||
size="medium"
|
||||
sx={bottomButtonStyling}
|
||||
color="primary"
|
||||
variant="contained"
|
||||
onClick={() => {
|
||||
setFormType('family');
|
||||
setFormOpen(true);
|
||||
}}
|
||||
>
|
||||
Add Family
|
||||
</MDButton>
|
||||
</Grid>
|
||||
<Grid item>
|
||||
<MDButton
|
||||
size="medium"
|
||||
sx={bottomButtonStyling}
|
||||
disabled={selected?.parent}
|
||||
color={selected && !selected?.parent ? 'primary' : 'secondary'}
|
||||
variant="contained"
|
||||
onClick={() => {
|
||||
setFormType('subfamily');
|
||||
setFormOpen(true);
|
||||
}}
|
||||
>
|
||||
Add SubFamily
|
||||
</MDButton>
|
||||
</Grid>
|
||||
</Grid>
|
||||
{/* <pre>{JSON.stringify(selected, null, 4)}</pre> */}
|
||||
|
||||
{formOpen && (
|
||||
<MaterialForm
|
||||
formType={formType}
|
||||
setFormOpen={setFormOpen}
|
||||
selected={selected}
|
||||
inventoryId={inventoryId}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
WidgetNestedDataTableContainer.propTypes = {
|
||||
inventoryId: PropTypes.any
|
||||
};
|
||||
|
||||
export default WidgetNestedDataTableContainer;
|
||||
@@ -13,5 +13,10 @@ export default {
|
||||
ADD_NEW_SUBLEVEL: '/sublevel',
|
||||
ADD_PRODUCT: '/item/',
|
||||
ADD_INVENTORY: '/inventory',
|
||||
LOCATION_DELETE: '/dashboard/delete-location'
|
||||
GET_INVENTORY: '/inventory/all?page=0&perPage=50',
|
||||
GET_INVENTORY_TYPES: '/inventory/types',
|
||||
LOCATION_DELETE: '/dashboard/delete-location',
|
||||
GET_WIDGET_FAMILY_BY_INVENTORY: '/widget-family/search-by-inventory?inventory=',
|
||||
ADD_WIDGET_FAMILY: '/widget-family',
|
||||
EDIT_WIDGET_FAMILY: '/widget-family/'
|
||||
};
|
||||
|
||||
@@ -15,11 +15,14 @@ import CrossIcon from 'assets/images/CrossIcon';
|
||||
import { useFormik } from 'formik';
|
||||
import schema from 'services/ValidationServices';
|
||||
import MDInput from 'components/MDInput';
|
||||
import { useDispatch } from 'react-redux';
|
||||
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';
|
||||
|
||||
const useStyles = makeStyles({
|
||||
labelSize: {
|
||||
@@ -43,47 +46,53 @@ const useStyles = makeStyles({
|
||||
}
|
||||
});
|
||||
|
||||
const inventoryTypes = ['Perishable', 'Material', 'Product', 'Inventory', 'Fleet'];
|
||||
|
||||
function AddNewProduct() {
|
||||
function AddNewItem() {
|
||||
const classes = useStyles();
|
||||
const { widgetName, inventoryId } = useParams();
|
||||
const dispatch = useDispatch();
|
||||
const [Manufacturer, setManufacturer] = React.useState('');
|
||||
const [open, setOpen] = React.useState(false);
|
||||
|
||||
const handleClickOpen = () => {
|
||||
setOpen(true);
|
||||
};
|
||||
React.useEffect(() => {
|
||||
dispatch(
|
||||
WidgetActions.widgetRequest({
|
||||
loader: 'location-request',
|
||||
slug: `${API.GET_WIDGET_FAMILY_BY_INVENTORY}${inventoryId}`,
|
||||
method: 'get'
|
||||
})
|
||||
);
|
||||
}, []);
|
||||
|
||||
const handleClose = () => {
|
||||
setOpen(false);
|
||||
};
|
||||
|
||||
const handleChange = (event) => {
|
||||
setManufacturer(event.target.value);
|
||||
};
|
||||
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: {
|
||||
warehousename: '',
|
||||
commonName: '',
|
||||
formalName: '',
|
||||
description: '',
|
||||
manufacturer: '',
|
||||
type: '',
|
||||
unitofmaterial: '',
|
||||
packagecount: '',
|
||||
formalname: '',
|
||||
size: '',
|
||||
color: '',
|
||||
unitcost: '',
|
||||
countperpallet: '',
|
||||
countperpalletpackage: '',
|
||||
productfamilyassociation: '',
|
||||
under: '',
|
||||
over: '',
|
||||
alert: '',
|
||||
type: '',
|
||||
unitOfMaterial: '',
|
||||
unitCost: 0,
|
||||
packageCount: 0,
|
||||
countPerPallet: 0,
|
||||
countPerPalletPackage: 0,
|
||||
primaryWidgetFamilyId: '',
|
||||
secondaryWidgetFamilyId: '',
|
||||
policiesMetadata: {
|
||||
underStockLevelCount: 0,
|
||||
overStockLevelCount: 0,
|
||||
alertStockLevelCount: 0,
|
||||
reorderStockLevelCount: 0
|
||||
},
|
||||
images: []
|
||||
},
|
||||
validationSchema: schema.addNewProduct,
|
||||
validationSchema: schema.addNewItem,
|
||||
onSubmit: (values, onSubmitProps) => {
|
||||
LOGGER.log('values', values);
|
||||
dispatch(
|
||||
@@ -92,25 +101,33 @@ function AddNewProduct() {
|
||||
slug: API.ADD_PRODUCT,
|
||||
method: 'post',
|
||||
data: {
|
||||
commonName: values.warehousename,
|
||||
formalName: values.formalname,
|
||||
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: [
|
||||
{ fieldName: 'someName', fieldType: 'String', fieldValue: 'someValue' }
|
||||
],
|
||||
widgetFamilyId: '61dcdd10699e8f55b44c606d'
|
||||
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();
|
||||
}
|
||||
});
|
||||
@@ -124,8 +141,8 @@ function AddNewProduct() {
|
||||
{ name: 'Home', path: '/home' },
|
||||
{ name: 'Setup', path: '/setup' },
|
||||
{ name: 'Inventory', path: '/setup/inventory' },
|
||||
{ name: 'Products' },
|
||||
{ name: 'Add New Product' }
|
||||
{ name: `${widgetName || 'Item'}` },
|
||||
{ name: `Add New ${widgetName || 'Item'}` }
|
||||
]}
|
||||
/>
|
||||
<Box mx={3} my={3}>
|
||||
@@ -135,16 +152,16 @@ function AddNewProduct() {
|
||||
<Grid item xs={12} sm={6} md={6}>
|
||||
<Box component="div" sx={{ marginBottom: '24px' }}>
|
||||
<Box component="div" className={classes.labelSize}>
|
||||
Warehouse name
|
||||
{widgetName || 'Item'} name
|
||||
</Box>
|
||||
<MDInput
|
||||
fullWidth
|
||||
name="warehousename"
|
||||
name="commonName"
|
||||
type="text"
|
||||
variant="outlined"
|
||||
value={formik.values.warehousename}
|
||||
error={formik.touched.warehousename && Boolean(formik.errors.warehousename)}
|
||||
helperText={formik.touched.warehousename && formik.errors.warehousename}
|
||||
value={formik.values.commonName}
|
||||
error={formik.touched.commonName && Boolean(formik.errors.commonName)}
|
||||
helperText={formik.touched.commonName && formik.errors.commonName}
|
||||
onChange={formik.handleChange}
|
||||
/>
|
||||
</Box>
|
||||
@@ -170,91 +187,46 @@ function AddNewProduct() {
|
||||
<Box component="div" className={classes.labelSize}>
|
||||
Manufacturer
|
||||
</Box>
|
||||
<FormControl fullWidth>
|
||||
<Select
|
||||
select
|
||||
fullWidth
|
||||
variant="outlined"
|
||||
name="manufacturer"
|
||||
value={formik.values.manufacturer}
|
||||
error={formik.touched.manufacturer && Boolean(formik.errors.manufacturer)}
|
||||
onChange={formik.handleChange}
|
||||
>
|
||||
<MenuItem key={''} value={''}>
|
||||
None Selected
|
||||
</MenuItem>
|
||||
{inventoryTypes.map((name) => (
|
||||
<MenuItem key={name} value={name}>
|
||||
{name}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
<FormHelperText>
|
||||
{formik.errors.manufacturer &&
|
||||
formik.touched.manufacturer &&
|
||||
formik.errors.manufacturer}
|
||||
</FormHelperText>
|
||||
</FormControl>
|
||||
<MDInput
|
||||
fullWidth
|
||||
name="manufacturer"
|
||||
type="text"
|
||||
variant="outlined"
|
||||
value={formik.values.manufacturer}
|
||||
error={formik.touched.manufacturer && Boolean(formik.errors.manufacturer)}
|
||||
helperText={formik.touched.manufacturer && formik.errors.manufacturer}
|
||||
onChange={formik.handleChange}
|
||||
/>
|
||||
</Box>
|
||||
<Box component="div" sx={{ marginBottom: '24px' }}>
|
||||
<Box component="div" className={classes.labelSize}>
|
||||
Type
|
||||
</Box>
|
||||
<FormControl fullWidth>
|
||||
<Select
|
||||
select
|
||||
fullWidth
|
||||
variant="outlined"
|
||||
name="type"
|
||||
value={formik.values.type}
|
||||
error={formik.touched.type && Boolean(formik.errors.type)}
|
||||
onChange={formik.handleChange}
|
||||
>
|
||||
<MenuItem key={''} value={''}>
|
||||
None Selected
|
||||
</MenuItem>
|
||||
{inventoryTypes.map((name) => (
|
||||
<MenuItem key={name} value={name}>
|
||||
{name}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
<FormHelperText>
|
||||
{formik.errors.type && formik.touched.type && formik.errors.type}
|
||||
</FormHelperText>
|
||||
</FormControl>
|
||||
<MDInput
|
||||
fullWidth
|
||||
name="type"
|
||||
type="text"
|
||||
variant="outlined"
|
||||
value={formik.values.type}
|
||||
error={formik.touched.type && Boolean(formik.errors.type)}
|
||||
helperText={formik.touched.type && formik.errors.type}
|
||||
onChange={formik.handleChange}
|
||||
/>
|
||||
</Box>
|
||||
<Box component="div" sx={{ marginBottom: '24px' }}>
|
||||
<Box component="div" className={classes.labelSize}>
|
||||
Unit of Material
|
||||
</Box>
|
||||
<FormControl fullWidth>
|
||||
<Select
|
||||
select
|
||||
fullWidth
|
||||
variant="outlined"
|
||||
name="unitofmaterial"
|
||||
value={formik.values.unitofmaterial}
|
||||
error={
|
||||
formik.touched.unitofmaterial && Boolean(formik.errors.unitofmaterial)
|
||||
}
|
||||
onChange={formik.handleChange}
|
||||
>
|
||||
<MenuItem key={''} value={''}>
|
||||
None Selected
|
||||
</MenuItem>
|
||||
{inventoryTypes.map((name) => (
|
||||
<MenuItem key={name} value={name}>
|
||||
{name}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
<FormHelperText>
|
||||
{formik.errors.unitofmaterial &&
|
||||
formik.touched.unitofmaterial &&
|
||||
formik.errors.unitofmaterial}
|
||||
</FormHelperText>
|
||||
</FormControl>
|
||||
<MDInput
|
||||
fullWidth
|
||||
name="unitOfMaterial"
|
||||
type="text"
|
||||
variant="outlined"
|
||||
value={formik.values.unitOfMaterial}
|
||||
error={formik.touched.unitOfMaterial && Boolean(formik.errors.unitOfMaterial)}
|
||||
helperText={formik.touched.unitOfMaterial && formik.errors.unitOfMaterial}
|
||||
onChange={formik.handleChange}
|
||||
/>
|
||||
</Box>
|
||||
<Box component="div" sx={{ marginBottom: '24px' }}>
|
||||
<Box component="div" className={classes.labelSize}>
|
||||
@@ -262,12 +234,12 @@ function AddNewProduct() {
|
||||
</Box>
|
||||
<MDInput
|
||||
fullWidth
|
||||
name="packagecount"
|
||||
type="text"
|
||||
name="packageCount"
|
||||
type="number"
|
||||
variant="outlined"
|
||||
value={formik.values.packagecount}
|
||||
error={formik.touched.packagecount && Boolean(formik.errors.packagecount)}
|
||||
helperText={formik.touched.packagecount && formik.errors.packagecount}
|
||||
value={formik.values.packageCount}
|
||||
error={formik.touched.packageCount && Boolean(formik.errors.packageCount)}
|
||||
helperText={formik.touched.packageCount && formik.errors.packageCount}
|
||||
onChange={formik.handleChange}
|
||||
/>
|
||||
</Box>
|
||||
@@ -279,12 +251,12 @@ function AddNewProduct() {
|
||||
</Box>
|
||||
<MDInput
|
||||
fullWidth
|
||||
name="formalname"
|
||||
name="formalName"
|
||||
type="text"
|
||||
variant="outlined"
|
||||
value={formik.values.formalname}
|
||||
error={formik.touched.formalname && Boolean(formik.errors.formalname)}
|
||||
helperText={formik.touched.formalname && formik.errors.formalname}
|
||||
value={formik.values.formalName}
|
||||
error={formik.touched.formalName && Boolean(formik.errors.formalName)}
|
||||
helperText={formik.touched.formalName && formik.errors.formalName}
|
||||
onChange={formik.handleChange}
|
||||
/>
|
||||
</Box>
|
||||
@@ -292,57 +264,31 @@ function AddNewProduct() {
|
||||
<Box component="div" className={classes.labelSize}>
|
||||
Size
|
||||
</Box>
|
||||
<FormControl fullWidth>
|
||||
<Select
|
||||
select
|
||||
fullWidth
|
||||
variant="outlined"
|
||||
name="size"
|
||||
value={formik.values.size}
|
||||
error={formik.touched.size && Boolean(formik.errors.size)}
|
||||
onChange={formik.handleChange}
|
||||
>
|
||||
<MenuItem key={''} value={''}>
|
||||
None Selected
|
||||
</MenuItem>
|
||||
{inventoryTypes.map((name) => (
|
||||
<MenuItem key={name} value={name}>
|
||||
{name}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
<FormHelperText>
|
||||
{formik.errors.size && formik.touched.size && formik.errors.size}
|
||||
</FormHelperText>
|
||||
</FormControl>
|
||||
<MDInput
|
||||
fullWidth
|
||||
name="size"
|
||||
type="text"
|
||||
variant="outlined"
|
||||
value={formik.values.size}
|
||||
error={formik.touched.size && Boolean(formik.errors.size)}
|
||||
helperText={formik.touched.size && formik.errors.size}
|
||||
onChange={formik.handleChange}
|
||||
/>
|
||||
</Box>
|
||||
<Box component="div" sx={{ marginBottom: '24px' }}>
|
||||
<Box component="div" className={classes.labelSize}>
|
||||
Color
|
||||
</Box>
|
||||
<FormControl fullWidth>
|
||||
<Select
|
||||
select
|
||||
fullWidth
|
||||
variant="outlined"
|
||||
name="color"
|
||||
value={formik.values.color}
|
||||
error={formik.touched.color && Boolean(formik.errors.color)}
|
||||
onChange={formik.handleChange}
|
||||
>
|
||||
<MenuItem key={''} value={''}>
|
||||
None Selected
|
||||
</MenuItem>
|
||||
{inventoryTypes.map((name) => (
|
||||
<MenuItem key={name} value={name}>
|
||||
{name}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
<FormHelperText>
|
||||
{formik.errors.color && formik.touched.color && formik.errors.color}
|
||||
</FormHelperText>
|
||||
</FormControl>
|
||||
<MDInput
|
||||
fullWidth
|
||||
name="color"
|
||||
type="text"
|
||||
variant="outlined"
|
||||
value={formik.values.color}
|
||||
error={formik.touched.color && Boolean(formik.errors.color)}
|
||||
helperText={formik.touched.color && formik.errors.color}
|
||||
onChange={formik.handleChange}
|
||||
/>
|
||||
</Box>
|
||||
<Box component="div" sx={{ marginBottom: '24px' }}>
|
||||
<Box component="div" className={classes.labelSize}>
|
||||
@@ -350,12 +296,12 @@ function AddNewProduct() {
|
||||
</Box>
|
||||
<MDInput
|
||||
fullWidth
|
||||
name="unitcost"
|
||||
type="text"
|
||||
name="unitCost"
|
||||
type="number"
|
||||
variant="outlined"
|
||||
value={formik.values.unitcost}
|
||||
error={formik.touched.unitcost && Boolean(formik.errors.unitcost)}
|
||||
helperText={formik.touched.unitcost && formik.errors.unitcost}
|
||||
value={formik.values.unitCost}
|
||||
error={formik.touched.unitCost && Boolean(formik.errors.unitCost)}
|
||||
helperText={formik.touched.unitCost && formik.errors.unitCost}
|
||||
onChange={formik.handleChange}
|
||||
/>
|
||||
</Box>
|
||||
@@ -365,12 +311,12 @@ function AddNewProduct() {
|
||||
</Box>
|
||||
<MDInput
|
||||
fullWidth
|
||||
name="countperpallet"
|
||||
type="text"
|
||||
name="countPerPallet"
|
||||
type="number"
|
||||
variant="outlined"
|
||||
value={formik.values.countperpallet}
|
||||
error={formik.touched.countperpallet && Boolean(formik.errors.countperpallet)}
|
||||
helperText={formik.touched.countperpallet && formik.errors.countperpallet}
|
||||
value={formik.values.countPerPallet}
|
||||
error={formik.touched.countPerPallet && Boolean(formik.errors.countPerPallet)}
|
||||
helperText={formik.touched.countPerPallet && formik.errors.countPerPallet}
|
||||
onChange={formik.handleChange}
|
||||
/>
|
||||
</Box>
|
||||
@@ -380,16 +326,16 @@ function AddNewProduct() {
|
||||
</Box>
|
||||
<MDInput
|
||||
fullWidth
|
||||
name="countperpalletpackage"
|
||||
type="text"
|
||||
name="countPerPalletPackage"
|
||||
type="number"
|
||||
variant="outlined"
|
||||
value={formik.values.countperpalletpackage}
|
||||
value={formik.values.countPerPalletPackage}
|
||||
error={
|
||||
formik.touched.countperpalletpackage &&
|
||||
Boolean(formik.errors.countperpalletpackage)
|
||||
formik.touched.countPerPalletPackage &&
|
||||
Boolean(formik.errors.countPerPalletPackage)
|
||||
}
|
||||
helperText={
|
||||
formik.touched.countperpalletpackage && formik.errors.countperpalletpackage
|
||||
formik.touched.countPerPalletPackage && formik.errors.countPerPalletPackage
|
||||
}
|
||||
onChange={formik.handleChange}
|
||||
/>
|
||||
@@ -398,32 +344,36 @@ function AddNewProduct() {
|
||||
<Box component="div" className={classes.labelSize}>
|
||||
Product Family Association
|
||||
</Box>
|
||||
<FormControl fullWidth sx={{ marginBottom: '32px' }}>
|
||||
<FormControl fullWidth>
|
||||
<Select
|
||||
select
|
||||
fullWidth
|
||||
variant="outlined"
|
||||
name="productfamilyassociation"
|
||||
value={formik.values.productfamilyassociation}
|
||||
name="primaryWidgetFamilyId"
|
||||
value={formik.values.primaryWidgetFamilyId}
|
||||
error={
|
||||
formik.touched.productfamilyassociation &&
|
||||
Boolean(formik.errors.productfamilyassociation)
|
||||
formik.touched.primaryWidgetFamilyId &&
|
||||
Boolean(formik.errors.primaryWidgetFamilyId)
|
||||
}
|
||||
onChange={formik.handleChange}
|
||||
onChange={(e, ...rest) => {
|
||||
setPFam(e.target.value);
|
||||
formik.handleChange(e, ...rest);
|
||||
}}
|
||||
>
|
||||
<MenuItem key={''} value={''}>
|
||||
<MenuItem key={'none'} value={''}>
|
||||
None Selected
|
||||
</MenuItem>
|
||||
{inventoryTypes.map((name) => (
|
||||
<MenuItem key={name} value={name}>
|
||||
{name}
|
||||
</MenuItem>
|
||||
))}
|
||||
{primaryFamily &&
|
||||
primaryFamily.map((fam) => (
|
||||
<MenuItem key={fam._id} value={fam._id}>
|
||||
{fam.name}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
<FormHelperText>
|
||||
{formik.errors.productfamilyassociation &&
|
||||
formik.touched.productfamilyassociation &&
|
||||
formik.errors.productfamilyassociation}
|
||||
{formik.errors.primaryWidgetFamilyId &&
|
||||
formik.touched.primaryWidgetFamilyId &&
|
||||
formik.errors.primaryWidgetFamilyId}
|
||||
</FormHelperText>
|
||||
</FormControl>
|
||||
<FormControl fullWidth>
|
||||
@@ -431,27 +381,28 @@ function AddNewProduct() {
|
||||
select
|
||||
fullWidth
|
||||
variant="outlined"
|
||||
name="productfamilyassociation"
|
||||
value={formik.values.productfamilyassociation}
|
||||
name="secondaryWidgetFamilyId"
|
||||
value={formik.values.secondaryWidgetFamilyId}
|
||||
error={
|
||||
formik.touched.productfamilyassociation &&
|
||||
Boolean(formik.errors.productfamilyassociation)
|
||||
formik.touched.secondaryWidgetFamilyId &&
|
||||
Boolean(formik.errors.secondaryWidgetFamilyId)
|
||||
}
|
||||
onChange={formik.handleChange}
|
||||
>
|
||||
<MenuItem key={''} value={''}>
|
||||
<MenuItem key={'none'} value={''}>
|
||||
None Selected
|
||||
</MenuItem>
|
||||
{inventoryTypes.map((name) => (
|
||||
<MenuItem key={name} value={name}>
|
||||
{name}
|
||||
</MenuItem>
|
||||
))}
|
||||
{secondaryFamily &&
|
||||
secondaryFamily.map((fam) => (
|
||||
<MenuItem key={fam._id} value={fam._id}>
|
||||
{fam.name}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
<FormHelperText>
|
||||
{formik.errors.productfamilyassociation &&
|
||||
formik.touched.productfamilyassociation &&
|
||||
formik.errors.productfamilyassociation}
|
||||
{formik.errors.secondaryWidgetFamilyId &&
|
||||
formik.touched.secondaryWidgetFamilyId &&
|
||||
formik.errors.secondaryWidgetFamilyId}
|
||||
</FormHelperText>
|
||||
</FormControl>
|
||||
</Box>
|
||||
@@ -459,7 +410,6 @@ function AddNewProduct() {
|
||||
</Grid>
|
||||
<Box>
|
||||
<ImageUpload
|
||||
multiple
|
||||
heading="Upload Product Image"
|
||||
accept="image/*"
|
||||
images={formik.values.images}
|
||||
@@ -482,7 +432,9 @@ function AddNewProduct() {
|
||||
size="large"
|
||||
color="primary"
|
||||
variant="outlined"
|
||||
onClick={handleClickOpen}
|
||||
onClick={() => {
|
||||
setOpen(true);
|
||||
}}
|
||||
>
|
||||
add custom fields
|
||||
</MDButton>
|
||||
@@ -508,12 +460,10 @@ function AddNewProduct() {
|
||||
</Box>
|
||||
<MDInput
|
||||
fullWidth
|
||||
name="under"
|
||||
name="policiesMetadata.underStockLevelCount"
|
||||
type="number"
|
||||
variant="outlined"
|
||||
value={formik.values.under}
|
||||
error={formik.touched.under && Boolean(formik.errors.under)}
|
||||
helperText={formik.touched.under && formik.errors.under}
|
||||
value={formik.values.policiesMetadata.underStockLevelCount}
|
||||
onChange={formik.handleChange}
|
||||
/>
|
||||
</Box>
|
||||
@@ -523,12 +473,10 @@ function AddNewProduct() {
|
||||
</Box>
|
||||
<MDInput
|
||||
fullWidth
|
||||
name="over"
|
||||
name="policiesMetadata.overStockLevelCount"
|
||||
type="number"
|
||||
variant="outlined"
|
||||
value={formik.values.over}
|
||||
error={formik.touched.over && Boolean(formik.errors.over)}
|
||||
helperText={formik.touched.over && formik.errors.over}
|
||||
value={formik.values.policiesMetadata.overStockLevelCount}
|
||||
onChange={formik.handleChange}
|
||||
/>
|
||||
</Box>
|
||||
@@ -538,12 +486,23 @@ function AddNewProduct() {
|
||||
</Box>
|
||||
<MDInput
|
||||
fullWidth
|
||||
name="alert"
|
||||
name="policiesMetadata.alertStockLevelCount"
|
||||
type="number"
|
||||
variant="outlined"
|
||||
value={formik.values.alert}
|
||||
error={formik.touched.alert && Boolean(formik.errors.alert)}
|
||||
helperText={formik.touched.alert && formik.errors.alert}
|
||||
value={formik.values.policiesMetadata.alertStockLevelCount}
|
||||
onChange={formik.handleChange}
|
||||
/>
|
||||
</Box>
|
||||
<Box>
|
||||
<Box component="div" className={classes.labelSize}>
|
||||
Reorder
|
||||
</Box>
|
||||
<MDInput
|
||||
fullWidth
|
||||
name="policiesMetadata.reorderStockLevelCount"
|
||||
type="number"
|
||||
variant="outlined"
|
||||
value={formik.values.policiesMetadata.reorderStockLevelCount}
|
||||
onChange={formik.handleChange}
|
||||
/>
|
||||
</Box>
|
||||
@@ -558,10 +517,10 @@ function AddNewProduct() {
|
||||
}}
|
||||
>
|
||||
<MDButton size="medium" color="error" variant="outlined">
|
||||
cancel
|
||||
Cancel
|
||||
</MDButton>
|
||||
<MDButton size="medium" color="primary" variant="contained" type="submit">
|
||||
add ITem
|
||||
Add {widgetName}
|
||||
</MDButton>
|
||||
</Box>
|
||||
</Box>
|
||||
@@ -584,7 +543,12 @@ function AddNewProduct() {
|
||||
padding: '10px 20px'
|
||||
}}
|
||||
>
|
||||
<MDButton sx={{ padding: '0px', minWidth: '14px' }} onClick={handleClose}>
|
||||
<MDButton
|
||||
sx={{ padding: '0px', minWidth: '14px' }}
|
||||
onClick={() => {
|
||||
setOpen(false);
|
||||
}}
|
||||
>
|
||||
<CrossIcon className={classes.cursorPointer} />
|
||||
</MDButton>
|
||||
</Box>
|
||||
@@ -628,7 +592,9 @@ function AddNewProduct() {
|
||||
return <em>Placeholder</em>;
|
||||
}
|
||||
}}
|
||||
onChange={handleChange}
|
||||
onChange={(event) => {
|
||||
setManufacturer(event.target.value);
|
||||
}}
|
||||
>
|
||||
<MenuItem value={10}>Ten</MenuItem>
|
||||
<MenuItem value={20}>Twenty</MenuItem>
|
||||
@@ -648,7 +614,9 @@ function AddNewProduct() {
|
||||
return <em>Placeholder</em>;
|
||||
}
|
||||
}}
|
||||
onChange={handleChange}
|
||||
onChange={(event) => {
|
||||
setManufacturer(event.target.value);
|
||||
}}
|
||||
>
|
||||
<MenuItem value={10}>Ten</MenuItem>
|
||||
<MenuItem value={20}>Twenty</MenuItem>
|
||||
@@ -783,4 +751,4 @@ function AddNewProduct() {
|
||||
);
|
||||
}
|
||||
|
||||
export default AddNewProduct;
|
||||
export default AddNewItem;
|
||||
|
||||
@@ -1,21 +1,24 @@
|
||||
import React from 'react';
|
||||
import DashboardNavbar from 'components/DashboardNavbar';
|
||||
import DashboardLayout from 'layouts/DashboardLayout';
|
||||
import { Box, Grid, MenuItem, Select, TableBody, TableCell, TableRow } from '@mui/material';
|
||||
import { Box, Grid, MenuItem, Select } from '@mui/material';
|
||||
import MDInput from 'components/MDInput';
|
||||
import ImageUpload from 'components/ImageUpload';
|
||||
import Switch from 'components/Switch';
|
||||
import MDTypography from 'components/MDTypography';
|
||||
import MDBox from 'components/MDBox';
|
||||
import Dropdown from 'components/Dropdown';
|
||||
import MDButton from 'components/Button';
|
||||
import BasicTable from 'components/BasicTable';
|
||||
import { useFormik } from 'formik';
|
||||
import schema from 'services/ValidationServices';
|
||||
import { API } from 'constant';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import InventoryActions from 'redux/InventoryRedux';
|
||||
import LOGGER from 'services/Logger';
|
||||
import Breadcrumbs from 'components/Breadcrumbs';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { InventorySelectors } from 'redux/InventoryRedux';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import WidgetNestedDataTable from 'components/WidgetNestedDataTable';
|
||||
|
||||
const customStyles = {
|
||||
labelSize: {
|
||||
@@ -49,110 +52,98 @@ const customStyles = {
|
||||
}
|
||||
};
|
||||
|
||||
const stockBox = [
|
||||
const definedPolicies = [
|
||||
{
|
||||
text: 'Stock Tracking'
|
||||
text: 'Order Tracking',
|
||||
key: 'orderTracking'
|
||||
},
|
||||
{
|
||||
text: 'Replenishment'
|
||||
text: 'Replenishment',
|
||||
key: 'replenishment'
|
||||
},
|
||||
{
|
||||
text: 'Alerting'
|
||||
text: 'Alerting',
|
||||
key: 'alerting'
|
||||
},
|
||||
{
|
||||
text: 'Check In/Out'
|
||||
},
|
||||
{
|
||||
text: 'Maintenance'
|
||||
},
|
||||
{
|
||||
text: 'Location'
|
||||
}
|
||||
];
|
||||
|
||||
const records = [
|
||||
{
|
||||
level1: 'Ipsum',
|
||||
level2: 'Vivera'
|
||||
},
|
||||
{
|
||||
level1: 'Ipsum',
|
||||
level2: 'Vivera'
|
||||
}
|
||||
];
|
||||
|
||||
const headCells = [
|
||||
{
|
||||
id: 'level1',
|
||||
label: 'Level 1'
|
||||
},
|
||||
{
|
||||
id: 'level2',
|
||||
label: 'Level 2'
|
||||
}
|
||||
];
|
||||
|
||||
const dropdownData = [
|
||||
{
|
||||
ID: '1',
|
||||
displayname: 'Regular, full time'
|
||||
},
|
||||
{
|
||||
ID: '2',
|
||||
displayname: 'Regular, part time'
|
||||
},
|
||||
{
|
||||
ID: '3',
|
||||
displayname: 'Contractor- Arise Max'
|
||||
}
|
||||
];
|
||||
|
||||
const inventoryTypes = ['Perishable', 'Material', 'Product', 'Inventory', 'Fleet'];
|
||||
|
||||
const dataLevel = [
|
||||
{
|
||||
placeholder: 'Lorem Ipsum',
|
||||
label: 'Level 1'
|
||||
},
|
||||
{
|
||||
placeholder: 'Lorem Ipsum',
|
||||
label: 'Level 2'
|
||||
text: 'Location',
|
||||
key: 'preferredLocations'
|
||||
}
|
||||
];
|
||||
|
||||
function InventoryScreen() {
|
||||
const dispatch = useDispatch();
|
||||
const navigate = useNavigate();
|
||||
const { inventoryId } = useParams();
|
||||
|
||||
const currentInventoryData = useSelector(InventorySelectors.getInventoryDetailById(inventoryId));
|
||||
LOGGER.log({ currentInventoryData });
|
||||
// const [inventoryAllData, setInventoryAllData] = useState([]);
|
||||
// const initialInventoryName='';
|
||||
|
||||
// useEffect(() => {
|
||||
// const filterData = inventoryData.filter((item) => item._id === inventoryId);
|
||||
// console.log('filterData', filterData);
|
||||
// setInitialInventoryName(filterData[0].name)
|
||||
// setInventoryAllData(filterData[0].widgetName);
|
||||
// }, []);
|
||||
|
||||
// LOGGER.log('initialInventoryName', initialInventoryName);
|
||||
|
||||
/* eslint-disable indent */
|
||||
const formik = useFormik({
|
||||
initialValues: {
|
||||
inventoryname: '',
|
||||
inventorytype: '',
|
||||
widgetname: '',
|
||||
policies: false,
|
||||
images: []
|
||||
},
|
||||
initialValues: inventoryId
|
||||
? {
|
||||
name: currentInventoryData.name,
|
||||
widgetName: currentInventoryData.widgetName,
|
||||
policies: {
|
||||
orderTracking: currentInventoryData.policies.orderTracking,
|
||||
alerting: currentInventoryData.policies.alerting,
|
||||
replenishment: currentInventoryData.policies.replenishment,
|
||||
preferredLocations: false, // TODO: change later when implemented on BE
|
||||
inventory_process: currentInventoryData.policies.inventory_process
|
||||
},
|
||||
image: [{ src: currentInventoryData.image }]
|
||||
}
|
||||
: {
|
||||
name: '',
|
||||
widgetName: '',
|
||||
policies: {
|
||||
orderTracking: false,
|
||||
alerting: false,
|
||||
replenishment: false,
|
||||
preferredLocations: false,
|
||||
inventory_process: 'CCR'
|
||||
},
|
||||
image: []
|
||||
},
|
||||
validationSchema: schema.addInventory,
|
||||
onSubmit: (values, onSubmitProps) => {
|
||||
LOGGER.log('values', values);
|
||||
dispatch(
|
||||
InventoryActions.addInventoryAction({
|
||||
loader: 'loading-request',
|
||||
slug: API.ADD_INVENTORY,
|
||||
method: 'post',
|
||||
data: {
|
||||
name: values.inventoryname,
|
||||
type: values.inventorytype,
|
||||
policies: {
|
||||
alerting: {
|
||||
lowestStockLevel: true,
|
||||
highestStockLevel: true,
|
||||
alertStockLevel: true,
|
||||
reOrderLevel: true
|
||||
inventoryId
|
||||
? dispatch(
|
||||
InventoryActions.updateInventoryAction({
|
||||
loader: 'loading-request',
|
||||
slug: `${API.ADD_INVENTORY}/${inventoryId}`,
|
||||
method: 'patch',
|
||||
data: {
|
||||
...values,
|
||||
image: values.image[0]?.file || null
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
);
|
||||
})
|
||||
)
|
||||
: dispatch(
|
||||
InventoryActions.addInventoryAction({
|
||||
loader: 'loading-request',
|
||||
slug: API.ADD_INVENTORY,
|
||||
method: 'post',
|
||||
data: {
|
||||
...values,
|
||||
image: values.image[0]?.file || null
|
||||
}
|
||||
})
|
||||
);
|
||||
// navigate to edit inventory page
|
||||
onSubmitProps.resetForm();
|
||||
}
|
||||
});
|
||||
@@ -187,67 +178,43 @@ function InventoryScreen() {
|
||||
</Box>
|
||||
<MDInput
|
||||
fullWidth
|
||||
name="inventoryname"
|
||||
disabled={inventoryId}
|
||||
name="name"
|
||||
type="text"
|
||||
variant="outlined"
|
||||
value={formik.values.inventoryname}
|
||||
error={formik.touched.inventoryname && Boolean(formik.errors.inventoryname)}
|
||||
helpertText={formik.touched.inventoryname && formik.errors.inventoryname}
|
||||
value={formik.values.name}
|
||||
error={formik.touched.name && Boolean(formik.errors.name)}
|
||||
helpertText={formik.touched.name && formik.errors.name}
|
||||
onChange={formik.handleChange}
|
||||
/>
|
||||
</Box>
|
||||
<Box component="div" sx={{ marginBottom: '20px' }}>
|
||||
<Box component="div" sx={customStyles.labelSize}>
|
||||
Inventory Type
|
||||
</Box>
|
||||
<Select
|
||||
select
|
||||
fullWidth
|
||||
variant="outlined"
|
||||
name="inventorytype"
|
||||
value={formik.values.inventorytype}
|
||||
error={formik.touched.inventorytype && Boolean(formik.errors.inventorytype)}
|
||||
helperText={formik.touched.inventorytype && formik.errors.inventorytype}
|
||||
onChange={formik.handleChange}
|
||||
>
|
||||
<MenuItem key={''} value={''}>
|
||||
None Selected
|
||||
</MenuItem>
|
||||
{inventoryTypes.map((name) => (
|
||||
<MenuItem key={name} value={name}>
|
||||
{name}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
</Box>
|
||||
|
||||
<Grid item xs={12} sm={12} md={12}>
|
||||
<Grid item xs={12}>
|
||||
<Box component="div" sx={customStyles.labelSize}>
|
||||
Widget Name
|
||||
</Box>
|
||||
<MDInput
|
||||
fullWidth
|
||||
name="widgetname"
|
||||
disabled={inventoryId}
|
||||
name="widgetName"
|
||||
type="text"
|
||||
variant="outlined"
|
||||
value={formik.values.widgetname}
|
||||
error={formik.touched.widgetname && Boolean(formik.errors.widgetname)}
|
||||
helpertext={formik.touched.widgetname && formik.errors.widgetname}
|
||||
value={formik.values.widgetName}
|
||||
error={formik.touched.widgetName && Boolean(formik.errors.widgetName)}
|
||||
helpertext={formik.touched.widgetName && formik.errors.widgetName}
|
||||
onChange={formik.handleChange}
|
||||
/>
|
||||
</Grid>
|
||||
<MDBox sx={{ my: 4 }}>
|
||||
<MDTypography variant="h5">Policies</MDTypography>
|
||||
<MDTypography sx={customStyles.textSize}>
|
||||
Egestas pulvinar ornare vulputate porttitor consectetur condimentum at tellus
|
||||
quis. Leo pellentesque ipsum, a purus dignissim aliquam, orci. Elementum
|
||||
ullamcorper a sit eleifend ante ullamcorper ornare mi pharetra.
|
||||
Choose policies to be applied
|
||||
</MDTypography>
|
||||
</MDBox>
|
||||
<MDBox
|
||||
mr={{ xs: 0, xl: 8 }}
|
||||
sx={{
|
||||
width: '40%',
|
||||
width: '60%',
|
||||
padding: '12.5px 10px',
|
||||
backgroundColor: '#fff',
|
||||
border: 'solid 0.5px #c4c4c4',
|
||||
@@ -256,87 +223,69 @@ function InventoryScreen() {
|
||||
}}
|
||||
>
|
||||
<div sx={customStyles.wrap}>
|
||||
{stockBox.map((item) => (
|
||||
<>
|
||||
<div sx={customStyles.gridWrap}>
|
||||
<MDTypography sx={customStyles.textWrap}>{item.text}</MDTypography>
|
||||
<Switch
|
||||
name="policies"
|
||||
checked={formik.values.policies}
|
||||
onChange={formik.handleChange}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
{definedPolicies.map((item) => (
|
||||
<div sx={customStyles.gridWrap} key={item.key}>
|
||||
<MDTypography sx={customStyles.textWrap}>{item.text}</MDTypography>
|
||||
<Switch
|
||||
disabled={inventoryId}
|
||||
name={`policies.${item.key}`}
|
||||
checked={formik.values.policies[item.key]}
|
||||
onChange={formik.handleChange}
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
<Box component="div" sx={{ marginBottom: '20px' }}>
|
||||
<Box component="div" sx={customStyles.labelSize}>
|
||||
Inventory Process
|
||||
</Box>
|
||||
<Select
|
||||
select
|
||||
fullWidth
|
||||
disabled={inventoryId}
|
||||
variant="outlined"
|
||||
name="policies.inventory_process"
|
||||
value={formik.values.policies.inventory_process}
|
||||
onChange={formik.handleChange}
|
||||
>
|
||||
<MenuItem key="CCR" value="CCR">
|
||||
CCR
|
||||
</MenuItem>
|
||||
<MenuItem key="PPR" value="PPR">
|
||||
PPR
|
||||
</MenuItem>
|
||||
</Select>
|
||||
</Box>
|
||||
</div>
|
||||
</MDBox>
|
||||
</Grid>
|
||||
<Grid item xs={12} sm={6} md={6}>
|
||||
<ImageUpload
|
||||
multiple
|
||||
heading="Upload Inventory Images"
|
||||
heading="Upload Inventory Image"
|
||||
accept="image/*"
|
||||
images={formik.values.images}
|
||||
images={formik.values.image}
|
||||
setImages={(images) => {
|
||||
formik.setFieldValue('images', images);
|
||||
formik.setFieldValue('image', images);
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12} sm={12} md={12}>
|
||||
<Grid container spacing={1}>
|
||||
{dataLevel &&
|
||||
dataLevel.map((item, index) => (
|
||||
<Grid item xs={12} sm={6} md={4} key={index}>
|
||||
<Dropdown items={item} dropdownData={dropdownData} />
|
||||
</Grid>
|
||||
))}
|
||||
<Grid item xs={12} sm={6} md={4}>
|
||||
<MDButton color="primary" circular="true" sx={customStyles.marginTop}>
|
||||
{'add hierarchy level'}
|
||||
</MDButton>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Grid item xs={12} sm={12} md={12}>
|
||||
<MDBox
|
||||
sx={{
|
||||
// backgroundColor: '#E5E5E5',
|
||||
width: '100%',
|
||||
padding: '9px'
|
||||
<MDBox sx={{ ml: 'auto', mr: 'auto', mt: 3 }}>
|
||||
<MDButton
|
||||
sx={{ ml: 3 }}
|
||||
color="error"
|
||||
variant="outlined"
|
||||
onClick={() => {
|
||||
navigate('/setup/inventory');
|
||||
}}
|
||||
>
|
||||
<MDTypography
|
||||
sx={{
|
||||
backgroundColor: '#E5E5E5',
|
||||
width: '100%',
|
||||
padding: '9px'
|
||||
}}
|
||||
>
|
||||
Widget hierarchy
|
||||
</MDTypography>
|
||||
<BasicTable
|
||||
headCells={headCells}
|
||||
records={records}
|
||||
backgroundColor="#E5E5E5"
|
||||
color="#343434"
|
||||
>
|
||||
<TableBody>
|
||||
{records &&
|
||||
records.map((item) => (
|
||||
<TableRow key={item.id}>
|
||||
<TableCell>{item.level1}</TableCell>
|
||||
<TableCell>{item.level2}</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</BasicTable>
|
||||
</MDBox>
|
||||
</Grid>
|
||||
<MDBox sx={{ ml: 'auto', mr: 'auto', mt: 3 }}>
|
||||
<MDButton sx={{ ml: 3 }} color="error" variant="outlined">
|
||||
{'CANCEL'}
|
||||
</MDButton>
|
||||
<MDButton sx={{ ml: 3 }} color="primary" variant="outlined" type="submit">
|
||||
<MDButton
|
||||
sx={{ ml: 3 }}
|
||||
color="primary"
|
||||
variant="outlined"
|
||||
disabled={inventoryId}
|
||||
type="submit"
|
||||
>
|
||||
{'SAVE'}
|
||||
</MDButton>
|
||||
<MDButton sx={{ ml: 3 }} color="primary">
|
||||
@@ -346,6 +295,7 @@ function InventoryScreen() {
|
||||
</Grid>
|
||||
</MDBox>
|
||||
</form>
|
||||
{inventoryId ? <WidgetNestedDataTable inventoryId={inventoryId} /> : null}
|
||||
</MDBox>
|
||||
</DashboardLayout>
|
||||
);
|
||||
|
||||
@@ -5,42 +5,53 @@ import EquipmentIcon from 'assets/images/EquimpmentIcon';
|
||||
import ProductsIcon from 'assets/images/ProductsIcon';
|
||||
import FleetIcon from 'assets/images/FleetIcon';
|
||||
import RawMaterialIcon from 'assets/images/RawMaterialIcon';
|
||||
import InventoryActions from 'redux/InventoryRedux';
|
||||
import { InventorySelectors } from 'redux/InventoryRedux';
|
||||
import { Grid } from '@mui/material';
|
||||
import Tile from 'components/TileComponent';
|
||||
import MDButton from 'components/Button';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import Breadcrumbs from 'components/Breadcrumbs';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { API } from 'constant';
|
||||
|
||||
function getIconFromSlug(slug) {
|
||||
switch (slug) {
|
||||
case 'equipment':
|
||||
return <EquipmentIcon />;
|
||||
case 'product':
|
||||
return <ProductsIcon />;
|
||||
case 'fleet':
|
||||
return <FleetIcon />;
|
||||
case 'rawmaterial':
|
||||
default:
|
||||
return <RawMaterialIcon />;
|
||||
}
|
||||
}
|
||||
|
||||
function SetupInventory() {
|
||||
const navigate = useNavigate();
|
||||
const dispatch = useDispatch();
|
||||
const inventoryData = useSelector(InventorySelectors.getInventoryDetail);
|
||||
const [inventoryAllData, setInventoryAllData] = useState([]);
|
||||
|
||||
const tiles = [
|
||||
{
|
||||
name: 'Raw Material',
|
||||
path: { update: '/', addNew: '/', cycleCount: '/', list: '/' },
|
||||
icon: <RawMaterialIcon />
|
||||
},
|
||||
{
|
||||
name: 'Products',
|
||||
path: {
|
||||
update: '/',
|
||||
addNew: '/setup/inventory/product/add-new-product',
|
||||
cycleCount: '/',
|
||||
list: '/'
|
||||
},
|
||||
icon: <ProductsIcon />
|
||||
},
|
||||
{
|
||||
name: 'Equipment',
|
||||
path: { update: '/', addNew: '/', cycleCount: '/', list: '/' },
|
||||
icon: <EquipmentIcon />
|
||||
},
|
||||
{
|
||||
name: 'Fleet',
|
||||
path: { update: '/', addNew: '/', cycleCount: '/', list: '/' },
|
||||
icon: <FleetIcon />
|
||||
useEffect(() => {
|
||||
if (inventoryData?.length) {
|
||||
setInventoryAllData(inventoryData);
|
||||
}
|
||||
];
|
||||
}, [inventoryData]);
|
||||
|
||||
useEffect(() => {
|
||||
dispatch(
|
||||
InventoryActions.getInventoryAction({
|
||||
loader: 'loading-request',
|
||||
slug: API.GET_INVENTORY,
|
||||
method: 'get'
|
||||
})
|
||||
);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<DashboardLayout>
|
||||
<DashboardNavbar />
|
||||
@@ -51,20 +62,18 @@ function SetupInventory() {
|
||||
{ name: 'Inventory' }
|
||||
]}
|
||||
>
|
||||
<MDButton
|
||||
sx={{ ml: 3 }}
|
||||
color="primary"
|
||||
onClick={() => navigate('/setup/inventory/inventory-new')}
|
||||
>
|
||||
<MDButton sx={{ ml: 3 }} color="primary" onClick={() => navigate('/setup/inventory/new')}>
|
||||
Create Inventory
|
||||
</MDButton>
|
||||
</Breadcrumbs>
|
||||
<MDBox px={2} py={3}>
|
||||
<Grid container spacing={2}>
|
||||
{tiles &&
|
||||
tiles.map((tile) => (
|
||||
<Grid item xs={12} sm={6} md={tiles.length > 4 ? 4 : 6} key={tile.name}>
|
||||
<Tile data={{ name: tile.name, path: tile.path }}>{tile.icon}</Tile>
|
||||
{inventoryAllData &&
|
||||
inventoryAllData.map((tile) => (
|
||||
<Grid item xs={12} sm={6} md={inventoryAllData?.length > 4 ? 4 : 6} key={tile._id}>
|
||||
<Tile data={{ name: tile?.name, widgetname: tile?.widgetName, id: tile?._id }}>
|
||||
{getIconFromSlug(tile.icon_slug)}
|
||||
</Tile>
|
||||
</Grid>
|
||||
))}
|
||||
</Grid>
|
||||
|
||||
@@ -5,9 +5,18 @@ import { getFetchingValue, getErrorValue } from '../services/Utils';
|
||||
|
||||
/* ------------- Types and Action Creators ------------- */
|
||||
const { Types, Creators } = createActions({
|
||||
getInventoryAction: ['payload'],
|
||||
getInventorySuccess: ['data'],
|
||||
getInventoryFailure: ['error'],
|
||||
addInventoryAction: ['payload'],
|
||||
addInventorySuccess: ['data'],
|
||||
addInventoryFailure: ['error']
|
||||
addInventoryFailure: ['error'],
|
||||
updateInventoryAction: ['payload'],
|
||||
updateInventorySuccess: ['data'],
|
||||
updateInventoryFailure: ['error'],
|
||||
getInventoryTypesAction: ['payload'],
|
||||
getInventoryTypesSuccess: ['data'],
|
||||
getInventoryTypesFailure: ['error']
|
||||
});
|
||||
|
||||
export const InventoryTypes = Types;
|
||||
@@ -16,17 +25,44 @@ export default InventoryActions;
|
||||
|
||||
/* ------------- Initial State ------------- */
|
||||
export const INITIAL_STATE = Immutable({
|
||||
getInventoryDetail: [],
|
||||
addInventoryDetail: [],
|
||||
updateInventoryDetail: [],
|
||||
addInventoryLoading: false,
|
||||
addInventoryerror: {}
|
||||
addInventoryerror: {},
|
||||
inventoryTypes: []
|
||||
});
|
||||
|
||||
/* ------------- Selectors ------------- */
|
||||
export const InventorySelectors = {
|
||||
addInventoryDetail: (state) => state.inventory.inventoryDetail
|
||||
addInventoryDetail: (state) => state.inventory.inventoryDetail,
|
||||
getInventoryDetail: (state) => state.inventory.getInventoryDetail,
|
||||
getInventoryDetailById: (id) => (state) =>
|
||||
state.inventory.getInventoryDetail.find((x) => x._id === id),
|
||||
getInventoryTypes: (state) => state.inventory.inventoryTypes,
|
||||
updateInventoryDetail: (state) => state.inventory.updateInventoryDetail
|
||||
};
|
||||
|
||||
/* ------------- Reducers ------------- */
|
||||
export const onGetInventoryAction = (state, { payload }) =>
|
||||
state.merge({
|
||||
fetching: _.uniq([state.fetching, payload?.loader]),
|
||||
error: getErrorValue(state?.error, payload?.loader)
|
||||
});
|
||||
|
||||
export const onGetInventorySuccess = (state, { data }) =>
|
||||
state.merge({
|
||||
fetching: getFetchingValue(state.fetching, data?.loader),
|
||||
error: getErrorValue(state?.error, data?.loader),
|
||||
getInventoryDetail: data.getInventoryDetail
|
||||
});
|
||||
|
||||
export const onGetInventoryFailure = (state, { error }) =>
|
||||
state.merge({
|
||||
fetching: _.without(state.fetching, error?.loader),
|
||||
error: { ...state.error, [error?.loader]: error?.error }
|
||||
});
|
||||
|
||||
export const onAddInventoryAction = (state, { payload }) =>
|
||||
state.merge({
|
||||
fetching: _.uniq([state.fetching, payload?.loader]),
|
||||
@@ -37,7 +73,7 @@ export const onAddInventorySuccess = (state, { data }) =>
|
||||
state.merge({
|
||||
fetching: getFetchingValue(state.fetching, data?.loader),
|
||||
error: getErrorValue(state?.error, data?.loader),
|
||||
addInventoryDetail: data.addInventoryDetail
|
||||
getInventoryDetail: [...state.getInventoryDetail, data.newInventory]
|
||||
});
|
||||
|
||||
export const onAddInventoryFailure = (state, { error }) =>
|
||||
@@ -46,9 +82,59 @@ export const onAddInventoryFailure = (state, { error }) =>
|
||||
error: { ...state.error, [error?.loader]: error?.error }
|
||||
});
|
||||
|
||||
export const onUpdateInventoryAction = (state, { payload }) =>
|
||||
state.merge({
|
||||
fetching: _.uniq([state.fetching, payload?.loader]),
|
||||
error: getErrorValue(state?.error, payload?.loader)
|
||||
});
|
||||
|
||||
export const onUpdateInventorySuccess = (state, { data }) =>
|
||||
state.merge({
|
||||
fetching: getFetchingValue(state.fetching, data?.loader),
|
||||
error: getErrorValue(state?.error, data?.loader),
|
||||
getInventoryDetail: [
|
||||
...state.getInventoryDetail.filter((x) => x._id !== data.newInventory._id),
|
||||
data.newInventory
|
||||
]
|
||||
});
|
||||
|
||||
export const onUpdateInventoryFailure = (state, { error }) =>
|
||||
state.merge({
|
||||
fetching: _.without(state.fetching, error?.loader),
|
||||
error: { ...state.error, [error?.loader]: error?.error }
|
||||
});
|
||||
|
||||
export const onGetInventoryTypesAction = (state, { payload }) =>
|
||||
state.merge({
|
||||
fetching: _.uniq([state.fetching, payload?.loader]),
|
||||
error: getErrorValue(state?.error, payload?.loader)
|
||||
});
|
||||
|
||||
export const onGetInventoryTypesSuccess = (state, { data }) =>
|
||||
state.merge({
|
||||
fetching: getFetchingValue(state.fetching, data?.loader),
|
||||
error: getErrorValue(state?.error, data?.loader),
|
||||
inventoryTypes: data.inventoryTypes
|
||||
});
|
||||
|
||||
export const onGetInventoryTypesFailure = (state, { error }) =>
|
||||
state.merge({
|
||||
fetching: _.without(state.fetching, error?.loader),
|
||||
error: { ...state.error, [error?.loader]: error?.error }
|
||||
});
|
||||
|
||||
/* ------------- Hookup Reducers To Types ------------- */
|
||||
export const inventoryReducer = createReducer(INITIAL_STATE, {
|
||||
[Types.GET_INVENTORY_ACTION]: onGetInventoryAction,
|
||||
[Types.GET_INVENTORY_SUCCESS]: onGetInventorySuccess,
|
||||
[Types.GET_INVENTORY_FAILURE]: onGetInventoryFailure,
|
||||
[Types.ADD_INVENTORY_ACTION]: onAddInventoryAction,
|
||||
[Types.ADD_INVENTORY_SUCCESS]: onAddInventorySuccess,
|
||||
[Types.ADD_INVENTORY_FAILURE]: onAddInventoryFailure
|
||||
[Types.ADD_INVENTORY_FAILURE]: onAddInventoryFailure,
|
||||
[Types.UPDATE_INVENTORY_ACTION]: onUpdateInventoryAction,
|
||||
[Types.UPDATE_INVENTORY_SUCCESS]: onUpdateInventorySuccess,
|
||||
[Types.UPDATE_INVENTORY_FAILURE]: onUpdateInventoryFailure,
|
||||
[Types.GET_INVENTORY_TYPES_ACTION]: onGetInventoryTypesAction,
|
||||
[Types.GET_INVENTORY_TYPES_SUCCESS]: onGetInventoryTypesSuccess,
|
||||
[Types.GET_INVENTORY_TYPES_FAILURE]: onGetInventoryTypesFailure
|
||||
});
|
||||
|
||||
101
src/redux/WidgetRedux.js
Normal file
101
src/redux/WidgetRedux.js
Normal file
@@ -0,0 +1,101 @@
|
||||
import { createActions, createReducer } from 'reduxsauce';
|
||||
import Immutable from 'seamless-immutable';
|
||||
import _ from 'underscore';
|
||||
import { getFetchingValue, getErrorValue } from '../services/Utils';
|
||||
|
||||
/* ------------- Types and Action Creators ------------- */
|
||||
const { Types, Creators } = createActions({
|
||||
widgetRequest: ['payload'],
|
||||
widgetSuccess: ['data'],
|
||||
editWidgetRequest: ['payload'],
|
||||
editWidgetSuccess: ['data'],
|
||||
widgetFailure: ['error'],
|
||||
logout: null
|
||||
});
|
||||
|
||||
export const WidgetTypes = Types;
|
||||
const WidgetActions = Creators;
|
||||
export default WidgetActions;
|
||||
|
||||
/* ------------- Initial State ------------- */
|
||||
export const INITIAL_STATE = Immutable({
|
||||
list: [],
|
||||
fetching: [],
|
||||
error: {}
|
||||
});
|
||||
|
||||
/* ------------- Selectors ------------- */
|
||||
export const WidgetSelectors = {
|
||||
getWidgets: (state) => state.widgets.list,
|
||||
getWidgetById: (id) => (state) => state.widgets.list.find((x) => x._id === id),
|
||||
getWidgetsByInventoryId: (id) => (state) =>
|
||||
state.widgets.list.filter((x) => x.inventory._id === id),
|
||||
getWidgetFamiliesByInventoryId: (id) => (state) =>
|
||||
state.widgets.list.filter((x) => !x.parent && x.inventory._id === id),
|
||||
getWidgetsByParentId: (id) => (state) => state.widgets.list.filter((x) => x.parent?._id === id)
|
||||
};
|
||||
|
||||
/* ------------- Reducers ------------- */
|
||||
export const onWidgetRequest = (state, { payload }) =>
|
||||
state.merge({
|
||||
fetching: _.uniq([...state.fetching, payload?.loader]),
|
||||
error: getErrorValue(state?.error, payload?.loader)
|
||||
});
|
||||
|
||||
export const onEditWidgetRequest = (state, { payload }) =>
|
||||
state.merge({
|
||||
fetching: _.uniq([...state.fetching, payload?.loader]),
|
||||
error: getErrorValue(state?.error, payload?.loader)
|
||||
});
|
||||
|
||||
const mergeWidgetStates = (stateData, widgets) => {
|
||||
if (!widgets) return stateData; // undefined check
|
||||
|
||||
const idsInNewWidgets = widgets.map((x) => x._id);
|
||||
|
||||
const newState = stateData.filter((x) => !idsInNewWidgets.includes(x._id));
|
||||
|
||||
return [...newState, ...widgets];
|
||||
};
|
||||
|
||||
export const onWidgetSuccess = (state, { data }) =>
|
||||
state.merge({
|
||||
fetching: getFetchingValue(state.fetching, data?.loader),
|
||||
error: getErrorValue(state?.error, data?.loader),
|
||||
list: mergeWidgetStates(state.list, data.widgets)
|
||||
});
|
||||
|
||||
const mergeEditWidgetStates = (stateList, widget, type) => {
|
||||
if (!widget) return stateList; // undefined check
|
||||
|
||||
if (type === 'add') {
|
||||
return [...stateList, widget];
|
||||
} else if (type === 'edit') {
|
||||
const newState = stateList.filter((x) => x._id !== widget._id);
|
||||
return [...newState, widget];
|
||||
} else {
|
||||
return stateList;
|
||||
}
|
||||
};
|
||||
|
||||
export const onEditWidgetSuccess = (state, { data }) =>
|
||||
state.merge({
|
||||
fetching: getFetchingValue(state.fetching, data?.loader),
|
||||
error: getErrorValue(state?.error, data?.loader),
|
||||
list: mergeEditWidgetStates(state.list, data.widget, data.type)
|
||||
});
|
||||
|
||||
export const onWidgetFailure = (state, { error }) =>
|
||||
state.merge({
|
||||
fetching: _.without(state.fetching, error?.loader),
|
||||
error: { ...state.error, [error?.loader]: error?.error }
|
||||
});
|
||||
|
||||
/* ------------- Hookup Reducers To Types ------------- */
|
||||
export const widgetReducer = createReducer(INITIAL_STATE, {
|
||||
[Types.WIDGET_REQUEST]: onWidgetRequest,
|
||||
[Types.EDIT_WIDGET_REQUEST]: onEditWidgetRequest,
|
||||
[Types.WIDGET_SUCCESS]: onWidgetSuccess,
|
||||
[Types.EDIT_WIDGET_SUCCESS]: onEditWidgetSuccess,
|
||||
[Types.WIDGET_FAILURE]: onWidgetFailure
|
||||
});
|
||||
@@ -6,6 +6,7 @@ import { productReducer } from './ProductsRedux';
|
||||
import { inventoryReducer } from './InventoryRedux';
|
||||
import { rolesReducer } from './RolesRedux';
|
||||
import { WarehouseLocationsReducer } from './WarehouseLocationsRedux';
|
||||
import { widgetReducer } from './WidgetRedux';
|
||||
|
||||
// Combine all reducers.
|
||||
const appReducer = combineReducers({
|
||||
@@ -15,7 +16,8 @@ const appReducer = combineReducers({
|
||||
roles: rolesReducer,
|
||||
warehouseLocations: WarehouseLocationsReducer,
|
||||
product: productReducer,
|
||||
inventory: inventoryReducer
|
||||
inventory: inventoryReducer,
|
||||
widgets: widgetReducer
|
||||
});
|
||||
|
||||
const rootReducer = (state, action) => {
|
||||
|
||||
@@ -57,7 +57,7 @@ import LabelingHome from 'pages/labellingHome';
|
||||
import SetupInventory from 'pages/setupInventory';
|
||||
import HomeIcon from 'assets/images/HomeIcon';
|
||||
import SetupIcon from 'assets/images/SetupIcon';
|
||||
import AddNewProduct from '../pages/addNewProduct';
|
||||
import AddNewItem from '../pages/addNewProduct';
|
||||
import CreateUserRole from 'pages/createUserRole';
|
||||
import WidgetLabel from 'pages/widgetLabel';
|
||||
|
||||
@@ -141,15 +141,22 @@ const protectedRoutes = [
|
||||
name: 'Inventory Definition',
|
||||
key: 'inventory-new',
|
||||
hide: true,
|
||||
route: '/setup/inventory/inventory-new',
|
||||
route: '/setup/inventory/new',
|
||||
component: <InventoryScreen />
|
||||
},
|
||||
{
|
||||
name: 'Add New Product',
|
||||
key: 'add-new-product',
|
||||
name: 'Inventory Definition',
|
||||
key: 'inventory-update',
|
||||
hide: true,
|
||||
route: '/setup/inventory/product/add-new-product',
|
||||
component: <AddNewProduct />
|
||||
route: '/setup/inventory/update/:inventoryId',
|
||||
component: <InventoryScreen />
|
||||
},
|
||||
{
|
||||
name: 'Add New Item',
|
||||
key: 'add-new-item',
|
||||
hide: true,
|
||||
route: '/setup/inventory/new-item/:widgetName/:inventoryId',
|
||||
component: <AddNewItem />
|
||||
},
|
||||
{
|
||||
name: 'Location Labeling',
|
||||
|
||||
@@ -1,21 +1,85 @@
|
||||
import { AuthorizedAPI } from 'config';
|
||||
import { takeLatest, call, put } from 'redux-saga/effects';
|
||||
import { takeLatest, call, put, takeEvery } from 'redux-saga/effects';
|
||||
import InventoryActions from 'redux/InventoryRedux';
|
||||
import { InventoryTypes } from 'redux/InventoryRedux';
|
||||
import ApiServices from 'services/API/ApiServices';
|
||||
|
||||
export function* onRequestAddInventoryData({ payload }) {
|
||||
export function* onRequestGetInventoryData({ payload }) {
|
||||
const response = yield call(
|
||||
ApiServices[payload?.method],
|
||||
AuthorizedAPI,
|
||||
payload?.slug,
|
||||
payload?.data
|
||||
);
|
||||
if (response?.status === 200) {
|
||||
yield put(
|
||||
InventoryActions.getInventorySuccess({
|
||||
loader: payload?.loader,
|
||||
getInventoryDetail: response?.data?.data
|
||||
})
|
||||
);
|
||||
} else {
|
||||
payload.onFailedGetInventoryData(response.data.error);
|
||||
yield put(
|
||||
InventoryActions.getInventoryFailure({
|
||||
loader: payload?.loader,
|
||||
error: response?.data
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export function* onRequestGetInventoryTypesData({ payload }) {
|
||||
const response = yield call(
|
||||
ApiServices[payload?.method],
|
||||
AuthorizedAPI,
|
||||
payload?.slug,
|
||||
payload?.data
|
||||
);
|
||||
if (response?.status === 200) {
|
||||
yield put(
|
||||
InventoryActions.getInventoryTypesSuccess({
|
||||
loader: payload?.loader,
|
||||
inventoryTypes: response?.data?.data
|
||||
})
|
||||
);
|
||||
} else {
|
||||
payload.onFailedGetInventoryData(response.data.error);
|
||||
yield put(
|
||||
InventoryActions.getInventoryTypesFailure({
|
||||
loader: payload?.loader,
|
||||
error: response?.data
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const parseDataToFormData = (data) => {
|
||||
var formData = new FormData();
|
||||
formData.append('name', data.name);
|
||||
formData.append('widgetName', data.widgetName);
|
||||
formData.append('icon_slug', 'testslug');
|
||||
formData.append('policies[orderTracking]', data.policies.orderTracking);
|
||||
formData.append('policies[alerting]', data.policies.alerting);
|
||||
formData.append('policies[replenishment]', data.policies.replenishment);
|
||||
formData.append('policies[preferredLocations]', data.policies.preferredLocations);
|
||||
formData.append('policies[inventory_process]', data.policies.inventory_process);
|
||||
data.image && formData.append('image', data.image);
|
||||
return formData;
|
||||
};
|
||||
|
||||
export function* onRequestAddInventoryData({ payload }) {
|
||||
const response = yield call(
|
||||
ApiServices[payload?.method],
|
||||
AuthorizedAPI,
|
||||
payload?.slug,
|
||||
parseDataToFormData(payload?.data)
|
||||
);
|
||||
if (response?.status === 200) {
|
||||
yield put(
|
||||
InventoryActions.addInventorySuccess({
|
||||
loader: payload?.loader,
|
||||
addInventoryDetail: response?.data?.data
|
||||
newInventory: response?.data?.data?.inventoryData
|
||||
})
|
||||
);
|
||||
} else {
|
||||
@@ -28,4 +92,34 @@ export function* onRequestAddInventoryData({ payload }) {
|
||||
);
|
||||
}
|
||||
}
|
||||
export default [takeLatest(InventoryTypes.ADD_INVENTORY_ACTION, onRequestAddInventoryData)];
|
||||
|
||||
export function* onRequestUpdateInventoryData({ payload }) {
|
||||
const response = yield call(
|
||||
ApiServices[payload?.method],
|
||||
AuthorizedAPI,
|
||||
payload?.slug,
|
||||
payload?.data
|
||||
);
|
||||
if (response?.status === 200) {
|
||||
yield put(
|
||||
InventoryActions.updateInventorySuccess({
|
||||
loader: payload?.loader,
|
||||
updateInventoryDetail: response?.data?.data
|
||||
})
|
||||
);
|
||||
} else {
|
||||
payload.onFailedUpdateInventoryData(response.data.error);
|
||||
yield put(
|
||||
InventoryActions.updateInventoryFailure({
|
||||
loader: payload?.loader,
|
||||
error: response?.data
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
export default [
|
||||
takeLatest(InventoryTypes.GET_INVENTORY_ACTION, onRequestGetInventoryData),
|
||||
takeLatest(InventoryTypes.ADD_INVENTORY_ACTION, onRequestAddInventoryData),
|
||||
takeLatest(InventoryTypes.UPDATE_INVENTORY_ACTION, onRequestUpdateInventoryData),
|
||||
takeEvery(InventoryTypes.GET_INVENTORY_TYPES_ACTION, onRequestGetInventoryTypesData)
|
||||
];
|
||||
|
||||
58
src/sagas/Widget.js
Normal file
58
src/sagas/Widget.js
Normal file
@@ -0,0 +1,58 @@
|
||||
import { AuthorizedAPI } from 'config';
|
||||
import { call, put, takeEvery } from 'redux-saga/effects';
|
||||
import ApiServices from 'services/API/ApiServices';
|
||||
import WidgetActions, { WidgetTypes } from '../redux/WidgetRedux';
|
||||
|
||||
export function* onRequestWidget({ payload }) {
|
||||
const response = yield call(
|
||||
ApiServices[payload?.method],
|
||||
AuthorizedAPI,
|
||||
payload?.slug,
|
||||
payload?.data
|
||||
);
|
||||
if (response?.status === 200) {
|
||||
yield put(
|
||||
WidgetActions.widgetSuccess({
|
||||
loader: payload?.loader,
|
||||
widgets: response?.data?.data
|
||||
})
|
||||
);
|
||||
} else {
|
||||
yield put(
|
||||
WidgetActions.widgetFailure({
|
||||
loader: payload?.loader,
|
||||
error: response?.message
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export function* onEditRequestWidget({ payload }) {
|
||||
const response = yield call(
|
||||
ApiServices[payload?.method],
|
||||
AuthorizedAPI,
|
||||
payload?.slug,
|
||||
payload?.data
|
||||
);
|
||||
if (response?.status === 200) {
|
||||
yield put(
|
||||
WidgetActions.editWidgetSuccess({
|
||||
loader: payload?.loader,
|
||||
widget: response?.data?.data,
|
||||
type: payload?.type
|
||||
})
|
||||
);
|
||||
} else {
|
||||
yield put(
|
||||
WidgetActions.widgetFailure({
|
||||
loader: payload?.loader,
|
||||
error: response?.message
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default [
|
||||
takeEvery(WidgetTypes.WIDGET_REQUEST, onRequestWidget),
|
||||
takeEvery(WidgetTypes.EDIT_WIDGET_REQUEST, onEditRequestWidget)
|
||||
];
|
||||
@@ -6,6 +6,7 @@ import ProductSaga from './Product';
|
||||
import InventorySaga from './Inventory';
|
||||
import RolesSaga from './Roles';
|
||||
import WarehouseLocationsSaga from './WarehouseLocations';
|
||||
import WidgetSaga from './Widget';
|
||||
|
||||
export default function* rootSaga() {
|
||||
yield all([...AuthSaga]);
|
||||
@@ -15,4 +16,5 @@ export default function* rootSaga() {
|
||||
yield all([...InventorySaga]);
|
||||
yield all([...RolesSaga]);
|
||||
yield all([...WarehouseLocationsSaga]);
|
||||
yield all([...WidgetSaga]);
|
||||
}
|
||||
|
||||
@@ -28,33 +28,41 @@ const schema = {
|
||||
attributes: Yup.string('Enter other attributes')
|
||||
}),
|
||||
|
||||
addNewProduct: Yup.object({
|
||||
warehousename: Yup.string('Enter warehouse name').required('warehouse name is required'),
|
||||
description: Yup.string('Enter Description').required('description is required'),
|
||||
manufacturer: Yup.string('Enter manufacturer').required('manufacturer is required'),
|
||||
type: Yup.string('Enter type').required('type is required'),
|
||||
unitofmaterial: Yup.string('Enter unitofmaterial').required('Unit of material is required'),
|
||||
packagecount: Yup.number('Enter packagecount').required('Package Count is required'),
|
||||
formalname: Yup.string('Enter formal name').required('Formal Name is required'),
|
||||
size: Yup.string('Enter Size').required('Size is required'),
|
||||
color: Yup.string('Enter Color').required('Color is required'),
|
||||
unitcost: Yup.number('Enter UnitCost').required('Unit Cost is required'),
|
||||
countperpallet: Yup.number('Enter countperpallet').required('Count per pallet is required'),
|
||||
countperpalletpackage: Yup.number('Enter countperpalletpackage').required(
|
||||
'count per pallet package is required'
|
||||
),
|
||||
productfamilyassociation: Yup.string('Enter productfamilyassociation').required(
|
||||
'product Family Association is required'
|
||||
),
|
||||
under: Yup.number().required('required'),
|
||||
over: Yup.number().required('required'),
|
||||
alert: Yup.number().required('required')
|
||||
addNewItem: Yup.object({
|
||||
commonName: Yup.string('Enter details').required(),
|
||||
formalName: Yup.string('Enter details').required(),
|
||||
description: Yup.string('Enter details').required(),
|
||||
manufacturer: Yup.string('Enter details').required(),
|
||||
size: Yup.string('Enter details').required(),
|
||||
color: Yup.string('Enter details').required(),
|
||||
type: Yup.string('Enter details').required(),
|
||||
unitOfMaterial: Yup.string('Enter details').required(),
|
||||
unitCost: Yup.number().test((val) => val >= 0),
|
||||
packageCount: Yup.number().test((val) => val >= 0),
|
||||
countPerPallet: Yup.number().test((val) => val >= 0),
|
||||
countPerPalletPackage: Yup.number().test((val) => val >= 0),
|
||||
primaryWidgetFamilyId: Yup.string('Enter details').required(),
|
||||
secondaryWidgetFamilyId: Yup.string('Enter details'),
|
||||
policiesMetadata: Yup.object({
|
||||
underStockLevelCount: Yup.number().test((val) => val >= 0),
|
||||
overStockLevelCount: Yup.number().test((val) => val >= 0),
|
||||
alertStockLevelCount: Yup.number().test((val) => val >= 0),
|
||||
reorderStockLevelCount: Yup.number().test((val) => val >= 0)
|
||||
}),
|
||||
images: Yup.array()
|
||||
}),
|
||||
|
||||
addInventory: Yup.object({
|
||||
inventoryname: Yup.string('Enter Inventory name').required('Inventory name is required'),
|
||||
inventorytype: Yup.string('Enter inventory Type').required('inventory Type is required'),
|
||||
widgetname: Yup.string('Enter Widget Name').required('Widget Name is required')
|
||||
name: Yup.string('Enter Widget Name').required('Widget Name is required'),
|
||||
widgetName: Yup.string('Enter Inventory name').required('Inventory name is required'),
|
||||
policies: Yup.object({
|
||||
orderTracking: Yup.boolean(),
|
||||
alerting: Yup.boolean(),
|
||||
replenishment: Yup.boolean(),
|
||||
preferredLocations: Yup.boolean(),
|
||||
inventory_process: Yup.string()
|
||||
}),
|
||||
image: Yup.array()
|
||||
})
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user