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:
@@ -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'
|
||||
};
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
|
||||
@@ -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 &&
|
||||
|
||||
@@ -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>
|
||||
|
||||
54
src/redux/InventoryRedux.js
Normal file
54
src/redux/InventoryRedux.js
Normal 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
|
||||
});
|
||||
@@ -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
31
src/sagas/Inventory.js
Normal 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)];
|
||||
@@ -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]);
|
||||
}
|
||||
|
||||
@@ -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')
|
||||
})
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user