Feature/wms 56 (#59)

* create warehouse
* edit warehouse changes
* Update: linted and formatted
* add warehouse button
* user access changes
* basic table component changes
* Updated: eslint errors
* basic table component changes
* update: linted
* add New Product form api integrate
* add Inventory changes
* policies change
* add validation for widget
* Fixed: Image upload component
* Updated: Custom styling inputs

Co-authored-by: [Diksha] <[diksha39511@gmail.com]>
Co-authored-by: Llewellyn Dsouza <lledsouza2209@gmail.com>
This commit is contained in:
Dikshajain39511
2022-02-22 13:48:26 +05:30
committed by GitHub
parent 68dca0dc34
commit 302057a0a7
9 changed files with 331 additions and 133 deletions

View File

@@ -4,5 +4,6 @@ export default {
CREATE_WAREHOUSE: '/warehouse/', CREATE_WAREHOUSE: '/warehouse/',
GET_USERS_DATA: '/user/all?page=0&perPage=10', GET_USERS_DATA: '/user/all?page=0&perPage=10',
ADD_PRODUCT: '/item/', ADD_PRODUCT: '/item/',
ADD_INVENTORY: '/inventory',
GET_ROLES_DATA: '/user-role/all?page=0&perPage=10' GET_ROLES_DATA: '/user-role/all?page=0&perPage=10'
}; };

View File

@@ -1,17 +1,28 @@
import DashboardNavbar from 'components/DashboardNavbar'; import DashboardNavbar from 'components/DashboardNavbar';
import DashboardLayout from 'layouts/DashboardLayout'; import DashboardLayout from 'layouts/DashboardLayout';
import { Grid, InputLabel, TableBody, TableCell, TableRow } from '@mui/material'; import { Box, Grid, MenuItem, Select, TableBody, TableCell, TableRow } from '@mui/material';
import MDInput from 'components/MDInput'; import MDInput from 'components/MDInput';
import ImageUpload from 'components/ImageUpload'; import ImageUpload from 'components/ImageUpload';
import Switch from 'components/Switch'; import Switch from 'components/Switch';
import MDTypography from 'components/MDTypography'; import MDTypography from 'components/MDTypography';
import { makeStyles } from '@mui/styles';
import MDBox from 'components/MDBox'; import MDBox from 'components/MDBox';
import Dropdown from 'components/Dropdown'; import Dropdown from 'components/Dropdown';
import MDButton from 'components/Button'; import MDButton from 'components/Button';
import BasicTable from 'components/BasicTable'; import BasicTable from 'components/BasicTable';
import { useFormik } from 'formik';
import schema from 'services/ValidationServices';
import { API } from 'constant';
import { useDispatch } from 'react-redux';
import InventoryActions from 'redux/InventoryRedux';
import LOGGER from 'services/Logger';
const useStyles = makeStyles({ const customStyles = {
labelSize: {
fontSize: '16px',
letterSpacing: '0.01em',
color: '#000',
marginBottom: '4px'
},
textWrap: { textWrap: {
whiteSpace: 'nowrap', whiteSpace: 'nowrap',
fontSize: '16px', fontSize: '16px',
@@ -35,7 +46,7 @@ const useStyles = makeStyles({
marginTop: { marginTop: {
marginTop: '54px' marginTop: '54px'
} }
}); };
const stockBox = [ const stockBox = [
{ {
@@ -95,12 +106,8 @@ const dropdownData = [
} }
]; ];
const dataInventory = [ const inventoryTypes = ['Perishable', 'Material', 'Product', 'Inventory', 'Fleet'];
{
placeholder: 'Lorem Ipsum',
label: 'Inventory Type'
}
];
const dataLevel = [ const dataLevel = [
{ {
placeholder: 'Lorem Ipsum', placeholder: 'Lorem Ipsum',
@@ -113,141 +120,223 @@ const dataLevel = [
]; ];
function InventoryScreen() { function InventoryScreen() {
const previewImg = [1, 2, 3]; const dispatch = useDispatch();
const classes = useStyles();
const formik = useFormik({
initialValues: {
inventoryname: '',
inventorytype: '',
widgetname: '',
policies: false,
images: []
},
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
}
}
}
})
);
onSubmitProps.resetForm();
}
});
return ( return (
<DashboardLayout> <DashboardLayout>
<DashboardNavbar /> <DashboardNavbar />
<MDBox px={5} py={5}> <MDBox px={5} py={5}>
<MDBox <form onSubmit={formik.handleSubmit}>
px={5} <MDBox
py={5} px={5}
sx={{ py={5}
backgroundColor: '#fff', sx={{
justifyContent: 'center', backgroundColor: '#fff',
alignItems: 'center', justifyContent: 'center',
display: 'flex' alignItems: 'center',
}} display: 'flex'
> }}
<Grid container spacing={5}> >
<Grid item xs={12} sm={6} md={6}> <Grid container spacing={5}>
<Grid container spacing={2}> <Grid item xs={12} sm={6} md={6}>
<Grid item xs={12} sm={12} md={12}> <Box component="div" sx={{ marginBottom: '20px' }}>
<InputLabel sx={{ pb: 2 }} id="demo-simple-select-label"> <Box component="div" sx={customStyles.labelSize}>
Inventory Name Inventory Name
</InputLabel> </Box>
<MDInput sx={{ width: '100%' }} /> <MDInput
</Grid> fullWidth
{dataInventory && name="inventoryname"
dataInventory.map((item, index) => ( type="text"
<Grid item xs={12} sm={12} md={12} key={index}> variant="outlined"
<Dropdown items={item} dropdownData={dropdownData} /> value={formik.values.inventoryname}
</Grid> error={formik.touched.inventoryname && Boolean(formik.errors.inventoryname)}
))} helpertText={formik.touched.inventoryname && formik.errors.inventoryname}
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} sm={12} md={12}>
<InputLabel sx={{ pb: 2 }} id="demo-simple-select-label"> <Box component="div" sx={customStyles.labelSize}>
Widget Name Widget Name
</InputLabel> </Box>
<MDInput sx={{ width: '100%' }} /> <MDInput
fullWidth
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}
onChange={formik.handleChange}
/>
</Grid> </Grid>
</Grid> <MDBox sx={{ my: 4 }}>
<MDBox sx={{ my: 4 }}> <MDTypography variant="h5">Policies</MDTypography>
<MDTypography variant="h5">Policies</MDTypography> <MDTypography sx={customStyles.textSize}>
<MDTypography className={classes.textSize}> Egestas pulvinar ornare vulputate porttitor consectetur condimentum at tellus
Egestas pulvinar ornare vulputate porttitor consectetur condimentum at tellus quis. Leo pellentesque ipsum, a purus dignissim aliquam, orci. Elementum
quis. Leo pellentesque ipsum, a purus dignissim aliquam, orci. Elementum ullamcorper a sit eleifend ante ullamcorper ornare mi pharetra.
ullamcorper a sit eleifend ante ullamcorper ornare mi pharetra. </MDTypography>
</MDTypography> </MDBox>
</MDBox> <MDBox
<MDBox mr={{ xs: 0, xl: 8 }}
mr={{ xs: 0, xl: 8 }}
sx={{
width: '40%',
padding: '12.5px 10px',
backgroundColor: '#fff',
border: 'solid 0.5px #c4c4c4',
borderRadius: '4px',
my: 5
}}
>
<div className={classes.wrap}>
{stockBox.map((item) => (
<>
<div className={classes.gridWrap}>
<MDTypography className={classes.textWrap}>{item.text}</MDTypography>
<Switch />
</div>
</>
))}
</div>
</MDBox>
</Grid>
<Grid item xs={12} sm={6} md={6}>
<ImageUpload heading="Upload Inventory Images" previewImg={previewImg} />
</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" className={classes.marginTop}>
{'add hierarchy level'}
</MDButton>
</Grid>
</Grid>
</Grid>
<Grid item xs={12} sm={12} md={12}>
<MDBox
sx={{
// backgroundColor: '#E5E5E5',
width: '100%',
padding: '9px'
}}
>
<MDTypography
sx={{ sx={{
backgroundColor: '#E5E5E5', width: '40%',
padding: '12.5px 10px',
backgroundColor: '#fff',
border: 'solid 0.5px #c4c4c4',
borderRadius: '4px',
my: 5
}}
>
<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>
</>
))}
</div>
</MDBox>
</Grid>
<Grid item xs={12} sm={6} md={6}>
<ImageUpload
multiple
heading="Upload Inventory Images"
accept="image/*"
images={formik.values.images}
setImages={(images) => {
formik.setFieldValue('images', 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%', width: '100%',
padding: '9px' padding: '9px'
}} }}
> >
Widget hierarchy <MDTypography
</MDTypography> sx={{
<BasicTable backgroundColor: '#E5E5E5',
headCells={headCells} width: '100%',
records={records} padding: '9px'
backgroundColor="#E5E5E5" }}
color="#343434" >
> Widget hierarchy
<TableBody> </MDTypography>
{records && <BasicTable
records.map((item) => ( headCells={headCells}
<TableRow key={item.id}> records={records}
<TableCell>{item.level1}</TableCell> backgroundColor="#E5E5E5"
<TableCell>{item.level2}</TableCell> color="#343434"
</TableRow> >
))} <TableBody>
</TableBody> {records &&
</BasicTable> 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">
{'SAVE'}
</MDButton>
<MDButton sx={{ ml: 3 }} color="primary">
{'ADD ITEMS'}
</MDButton>
</MDBox> </MDBox>
</Grid> </Grid>
<MDBox sx={{ ml: 'auto', mr: 'auto', mt: 3 }}> </MDBox>
<MDButton sx={{ ml: 3 }} color="error" variant="outlined"> </form>
{'CANCEL'}
</MDButton>
<MDButton sx={{ ml: 3 }} color="primary" variant="outlined">
{'SAVE'}
</MDButton>
<MDButton sx={{ ml: 3 }} color="primary">
{'ADD ITEMS'}
</MDButton>
</MDBox>
</Grid>
</MDBox>
</MDBox> </MDBox>
</DashboardLayout> </DashboardLayout>
); );

View File

@@ -7,8 +7,13 @@ import FleetIcon from 'assets/images/FleetIcon';
import RawMaterialIcon from 'assets/images/RawMaterialIcon'; import RawMaterialIcon from 'assets/images/RawMaterialIcon';
import { Grid } from '@mui/material'; import { Grid } from '@mui/material';
import Tile from 'components/TileComponent'; import Tile from 'components/TileComponent';
import MDButton from 'components/Button';
import { useNavigate } from 'react-router-dom';
function SetupInventory()
{
const navigate = useNavigate();
function SetupInventory() {
const tiles = [ const tiles = [
{ {
name: 'Raw Material', name: 'Raw Material',
@@ -38,7 +43,11 @@ function SetupInventory() {
]; ];
return ( return (
<DashboardLayout> <DashboardLayout>
<DashboardNavbar /> <DashboardNavbar>
<MDButton sx={{ ml: 3 }} color="primary" onClick={() => navigate('/setup/inventory/inventory-new')}>
+ Add new
</MDButton>
</DashboardNavbar>
<MDBox px={2} py={3}> <MDBox px={2} py={3}>
<Grid container spacing={2}> <Grid container spacing={2}>
{tiles && {tiles &&

View File

@@ -158,7 +158,11 @@ function UserAccessScreen() {
<SearchBar /> <SearchBar />
</Grid> </Grid>
<Grid item xs={12} sm={4} md={2}> <Grid item xs={12} sm={4} md={2}>
<MDButton color="primary" size="medium" onClick={() => navigate('/setup/users-access/create-role')}> <MDButton
color="primary"
size="medium"
onClick={() => navigate('/setup/users-access/create-role')}
>
{'+ CREATE USER'} {'+ CREATE USER'}
</MDButton> </MDButton>
</Grid> </Grid>

View File

@@ -0,0 +1,54 @@
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({
addInventoryAction: ['payload'],
addInventorySuccess: ['data'],
addInventoryFailure: ['error']
});
export const InventoryTypes = Types;
const InventoryActions = Creators;
export default InventoryActions;
/* ------------- Initial State ------------- */
export const INITIAL_STATE = Immutable({
addInventoryDetail: [],
addInventoryLoading: false,
addInventoryerror: {}
});
/* ------------- Selectors ------------- */
export const InventorySelectors = {
addInventoryDetail: (state) => state.inventory.inventoryDetail
};
/* ------------- Reducers ------------- */
export const onAddInventoryAction = (state, { payload }) =>
state.merge({
fetching: _.uniq([state.fetching, payload?.loader]),
error: getErrorValue(state?.error, payload?.loader)
});
export const onAddInventorySuccess = (state, { data }) =>
state.merge({
fetching: getFetchingValue(state.fetching, data?.loader),
error: getErrorValue(state?.error, data?.loader),
addInventoryDetail: data.addInventoryDetail
});
export const onAddInventoryFailure = (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.ADD_INVENTORY_ACTION]: onAddInventoryAction,
[Types.ADD_INVENTORY_SUCCESS]: onAddInventorySuccess,
[Types.ADD_INVENTORY_FAILURE]: onAddInventoryFailure
});

View File

@@ -3,6 +3,7 @@ import { authReducer } from './AuthRedux';
import { warehouseReducer } from './WarehouseRedux'; import { warehouseReducer } from './WarehouseRedux';
import { usersReducer } from './UsersRedux'; import { usersReducer } from './UsersRedux';
import { productReducer } from './ProductsRedux'; import { productReducer } from './ProductsRedux';
import { inventoryReducer } from './InventoryRedux';
import { rolesReducer } from './RolesRedux'; import { rolesReducer } from './RolesRedux';
// Combine all reducers. // Combine all reducers.
@@ -11,6 +12,7 @@ const appReducer = combineReducers({
warehouse: warehouseReducer, warehouse: warehouseReducer,
users: usersReducer, users: usersReducer,
product: productReducer, product: productReducer,
inventory: inventoryReducer,
roles: rolesReducer roles: rolesReducer
}); });

31
src/sagas/Inventory.js Normal file
View File

@@ -0,0 +1,31 @@
import { AuthorizedAPI } from 'config';
import { takeLatest, call, put } from 'redux-saga/effects';
import InventoryActions from 'redux/InventoryRedux';
import { InventoryTypes } from 'redux/InventoryRedux';
import ApiServices from 'services/API/ApiServices';
export function* onRequestAddInventoryData({ payload }) {
const response = yield call(
ApiServices[payload?.method],
AuthorizedAPI,
payload?.slug,
payload?.data
);
if (response?.status === 200) {
yield put(
InventoryActions.addInventorySuccess({
loader: payload?.loader,
addInventoryDetail: response?.data?.data
})
);
} else {
payload.onFailedAddInventoryData(response.data.error);
yield put(
InventoryActions.addInventoryFailure({
loader: payload?.loader,
error: response?.data
})
);
}
}
export default [takeLatest(InventoryTypes.ADD_INVENTORY_ACTION, onRequestAddInventoryData)];

View File

@@ -3,6 +3,7 @@ import AuthSaga from './Auth';
import WarehouseSaga from './Warehouse'; import WarehouseSaga from './Warehouse';
import UsersSaga from './Users'; import UsersSaga from './Users';
import ProductSaga from './Product'; import ProductSaga from './Product';
import InventorySaga from './Inventory';
import RolesSaga from './Roles'; import RolesSaga from './Roles';
export default function* rootSaga() { export default function* rootSaga() {
@@ -10,5 +11,6 @@ export default function* rootSaga() {
yield all([...WarehouseSaga]); yield all([...WarehouseSaga]);
yield all([...UsersSaga]); yield all([...UsersSaga]);
yield all([...ProductSaga]); yield all([...ProductSaga]);
yield all([...InventorySaga]);
yield all([...RolesSaga]); yield all([...RolesSaga]);
} }

View File

@@ -49,6 +49,12 @@ const schema = {
under: Yup.number().required('required'), under: Yup.number().required('required'),
over: Yup.number().required('required'), over: Yup.number().required('required'),
alert: Yup.number().required('required') alert: Yup.number().required('required')
}),
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')
}) })
}; };