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/',
GET_USERS_DATA: '/user/all?page=0&perPage=10',
ADD_PRODUCT: '/item/',
ADD_INVENTORY: '/inventory',
GET_ROLES_DATA: '/user-role/all?page=0&perPage=10'
};

View File

@@ -1,17 +1,28 @@
import DashboardNavbar from 'components/DashboardNavbar';
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 ImageUpload from 'components/ImageUpload';
import Switch from 'components/Switch';
import MDTypography from 'components/MDTypography';
import { makeStyles } from '@mui/styles';
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 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: {
whiteSpace: 'nowrap',
fontSize: '16px',
@@ -35,7 +46,7 @@ const useStyles = makeStyles({
marginTop: {
marginTop: '54px'
}
});
};
const stockBox = [
{
@@ -95,12 +106,8 @@ const dropdownData = [
}
];
const dataInventory = [
{
placeholder: 'Lorem Ipsum',
label: 'Inventory Type'
}
];
const inventoryTypes = ['Perishable', 'Material', 'Product', 'Inventory', 'Fleet'];
const dataLevel = [
{
placeholder: 'Lorem Ipsum',
@@ -113,12 +120,46 @@ const dataLevel = [
];
function InventoryScreen() {
const previewImg = [1, 2, 3];
const classes = useStyles();
const dispatch = useDispatch();
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 (
<DashboardLayout>
<DashboardNavbar />
<MDBox px={5} py={5}>
<form onSubmit={formik.handleSubmit}>
<MDBox
px={5}
py={5}
@@ -131,29 +172,64 @@ function InventoryScreen() {
>
<Grid container spacing={5}>
<Grid item xs={12} sm={6} md={6}>
<Grid container spacing={2}>
<Grid item xs={12} sm={12} md={12}>
<InputLabel sx={{ pb: 2 }} id="demo-simple-select-label">
<Box component="div" sx={{ marginBottom: '20px' }}>
<Box component="div" sx={customStyles.labelSize}>
Inventory Name
</InputLabel>
<MDInput sx={{ width: '100%' }} />
</Grid>
{dataInventory &&
dataInventory.map((item, index) => (
<Grid item xs={12} sm={12} md={12} key={index}>
<Dropdown items={item} dropdownData={dropdownData} />
</Grid>
</Box>
<MDInput
fullWidth
name="inventoryname"
type="text"
variant="outlined"
value={formik.values.inventoryname}
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}>
<InputLabel sx={{ pb: 2 }} id="demo-simple-select-label">
<Box component="div" sx={customStyles.labelSize}>
Widget Name
</InputLabel>
<MDInput sx={{ width: '100%' }} />
</Grid>
</Box>
<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>
<MDBox sx={{ my: 4 }}>
<MDTypography variant="h5">Policies</MDTypography>
<MDTypography className={classes.textSize}>
<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.
@@ -170,12 +246,16 @@ function InventoryScreen() {
my: 5
}}
>
<div className={classes.wrap}>
<div sx={customStyles.wrap}>
{stockBox.map((item) => (
<>
<div className={classes.gridWrap}>
<MDTypography className={classes.textWrap}>{item.text}</MDTypography>
<Switch />
<div sx={customStyles.gridWrap}>
<MDTypography sx={customStyles.textWrap}>{item.text}</MDTypography>
<Switch
name="policies"
checked={formik.values.policies}
onChange={formik.handleChange}
/>
</div>
</>
))}
@@ -183,7 +263,15 @@ function InventoryScreen() {
</MDBox>
</Grid>
<Grid item xs={12} sm={6} md={6}>
<ImageUpload heading="Upload Inventory Images" previewImg={previewImg} />
<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}>
@@ -194,7 +282,7 @@ function InventoryScreen() {
</Grid>
))}
<Grid item xs={12} sm={6} md={4}>
<MDButton color="primary" circular="true" className={classes.marginTop}>
<MDButton color="primary" circular="true" sx={customStyles.marginTop}>
{'add hierarchy level'}
</MDButton>
</Grid>
@@ -239,7 +327,7 @@ function InventoryScreen() {
<MDButton sx={{ ml: 3 }} color="error" variant="outlined">
{'CANCEL'}
</MDButton>
<MDButton sx={{ ml: 3 }} color="primary" variant="outlined">
<MDButton sx={{ ml: 3 }} color="primary" variant="outlined" type="submit">
{'SAVE'}
</MDButton>
<MDButton sx={{ ml: 3 }} color="primary">
@@ -248,6 +336,7 @@ function InventoryScreen() {
</MDBox>
</Grid>
</MDBox>
</form>
</MDBox>
</DashboardLayout>
);

View File

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

View File

@@ -158,7 +158,11 @@ function UserAccessScreen() {
<SearchBar />
</Grid>
<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'}
</MDButton>
</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 { usersReducer } from './UsersRedux';
import { productReducer } from './ProductsRedux';
import { inventoryReducer } from './InventoryRedux';
import { rolesReducer } from './RolesRedux';
// Combine all reducers.
@@ -11,6 +12,7 @@ const appReducer = combineReducers({
warehouse: warehouseReducer,
users: usersReducer,
product: productReducer,
inventory: inventoryReducer,
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 UsersSaga from './Users';
import ProductSaga from './Product';
import InventorySaga from './Inventory';
import RolesSaga from './Roles';
export default function* rootSaga() {
@@ -10,5 +11,6 @@ export default function* rootSaga() {
yield all([...WarehouseSaga]);
yield all([...UsersSaga]);
yield all([...ProductSaga]);
yield all([...InventorySaga]);
yield all([...RolesSaga]);
}

View File

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