Compare commits
44 Commits
develop
...
feature/wm
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
55d8526808 | ||
|
|
c4d3190d5e | ||
|
|
ceb9256f1b | ||
|
|
8abe5ba900 | ||
|
|
4d3b6ec9df | ||
|
|
b2c0c3f958 | ||
|
|
7561006ce0 | ||
|
|
7131e86792 | ||
|
|
cb71fe1a42 | ||
|
|
787c91fe7a | ||
|
|
c62453e318 | ||
| e17f4fb0b6 | |||
|
|
728406b452 | ||
|
|
30b4b5d7c2 | ||
|
|
51dc7c33c3 | ||
|
|
e75e270cdf | ||
|
|
913c1dbcf2 | ||
|
|
940c1e704e | ||
|
|
0fb3f3bf55 | ||
|
|
70cda3d3f2 | ||
|
|
75b6f2a88b | ||
|
|
be258aea34 | ||
|
|
ef4e3a2d9f | ||
|
|
320ec7061c | ||
|
|
ae7e8547c3 | ||
|
|
74199f6752 | ||
|
|
54369ae9b7 | ||
| 87a890cd23 | |||
|
|
95e05cb51c | ||
| e87dbdeee6 | |||
|
|
eb0e34fef5 | ||
| 61bfd87029 | |||
|
|
1469e4ff5a | ||
|
|
2f8d60049c | ||
|
|
85947c18c2 | ||
|
|
a22c3fcf42 | ||
|
|
8cccf1f034 | ||
|
|
5d2e29fc41 | ||
|
|
5381f7d727 | ||
|
|
e2d3ccfb7e | ||
|
|
fd8d0b1167 | ||
|
|
a883212126 | ||
|
|
7c9bc373d4 | ||
|
|
f1a2210e16 |
@@ -8,6 +8,10 @@ module.exports = {
|
||||
extends: ['eslint:recommended', 'plugin:react/recommended'],
|
||||
parser: '@babel/eslint-parser',
|
||||
parserOptions: {
|
||||
requireConfigFile: false,
|
||||
babelOptions: {
|
||||
presets: ['@babel/preset-react']
|
||||
},
|
||||
ecmaFeatures: {
|
||||
jsx: true,
|
||||
modules: true,
|
||||
@@ -23,7 +27,7 @@ module.exports = {
|
||||
'linebreak-style': ['error', 'unix'],
|
||||
quotes: ['warn', 'single'],
|
||||
semi: ['warn', 'always'],
|
||||
'no-unused-vars' : 'warn',
|
||||
'no-unused-vars': 'warn',
|
||||
'comma-dangle': [
|
||||
'warn',
|
||||
{
|
||||
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,7 +1,7 @@
|
||||
# See https://help.github.com/ignore-files/ for more about ignoring files.
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
node_modules
|
||||
.DS_Store
|
||||
|
||||
# testing
|
||||
|
||||
7144
package-lock.json
generated
7144
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -10,7 +10,7 @@
|
||||
"dependencies": {
|
||||
"@asseinfo/react-kanban": "2.2.0",
|
||||
"@emotion/cache": "11.4.0",
|
||||
"@emotion/react": "11.4.1",
|
||||
"@emotion/react": "^11.4.1",
|
||||
"@emotion/styled": "11.3.0",
|
||||
"@fullcalendar/daygrid": "5.9.0",
|
||||
"@fullcalendar/interaction": "5.9.0",
|
||||
@@ -30,7 +30,6 @@
|
||||
"@zxing/library": "^0.18.5",
|
||||
"apisauce": "^2.1.5",
|
||||
"bootstrap": "^5.1.3",
|
||||
"buffer": "^6.0.3",
|
||||
"chart.js": "3.4.1",
|
||||
"chroma-js": "2.1.2",
|
||||
"date-fns": "^2.28.0",
|
||||
@@ -41,7 +40,6 @@
|
||||
"jsbarcode": "^3.11.5",
|
||||
"jsonwebtoken": "^8.5.1",
|
||||
"moment": "^2.29.1",
|
||||
"process": "^0.11.10",
|
||||
"prop-types": "15.7.2",
|
||||
"ramda": "^0.27.2",
|
||||
"react": "17.0.2",
|
||||
@@ -59,11 +57,9 @@
|
||||
"redux-saga": "^1.1.3",
|
||||
"reduxsauce": "^1.2.1",
|
||||
"seamless-immutable": "^7.1.4",
|
||||
"stream": "^0.0.2",
|
||||
"stylis": "4.0.10",
|
||||
"stylis-plugin-rtl": "2.1.0",
|
||||
"underscore": "^1.13.2",
|
||||
"util": "^0.12.4",
|
||||
"uuid": "8.3.2",
|
||||
"web-vitals": "1.0.1",
|
||||
"yup": "^0.32.11"
|
||||
@@ -104,7 +100,9 @@
|
||||
]
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.17.5",
|
||||
"@babel/eslint-parser": "^7.17.0",
|
||||
"@babel/preset-react": "^7.16.7",
|
||||
"eslint": "^8.2.0",
|
||||
"eslint-config-airbnb": "^19.0.4",
|
||||
"eslint-config-prettier": "8.3.0",
|
||||
|
||||
@@ -52,7 +52,7 @@ import PublicRoutes from 'routes/PublicRoutes';
|
||||
import reduxStore from './redux/Store';
|
||||
import { protectedRoutes as routes } from './routes/index';
|
||||
import PrivateRoute from './routes/PrivateRoute';
|
||||
import MDAlert from 'components/MDAlert';
|
||||
// import MDAlert from 'components/MDAlert';
|
||||
|
||||
import { ToastContainer } from 'react-toastify';
|
||||
import 'react-toastify/dist/ReactToastify.css';
|
||||
@@ -171,7 +171,7 @@ export default function App() {
|
||||
</Routes>
|
||||
{/* <MDAlert dismissible><span>Submitted Successfully!</span></MDAlert> */}
|
||||
</ThemeProvider>
|
||||
<ToastContainer />
|
||||
<ToastContainer position="bottom-right" />
|
||||
</PersistGate>
|
||||
</Provider>
|
||||
);
|
||||
|
||||
@@ -1,12 +1,38 @@
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
const InventoryIcon = ({ width = 25, height = 24, ...props }) => (
|
||||
<svg width={width} height={height} {...props} viewBox="0 0 96 96" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M37.24 58.7998L43.24 64.7998L59.24 48.7998" stroke="#007AFF" strokeWidth="5" strokeLinecap="round" strokeLinejoin="round"/>
|
||||
<path d="M40 24H56C64 24 64 20 64 16C64 8 60 8 56 8H40C36 8 32 8 32 16C32 24 36 24 40 24Z" stroke="#007AFF" strokeWidth="5" strokeMiterlimit="10" strokeLinecap="round" strokeLinejoin="round"/>
|
||||
<path d="M64 16.0801C77.32 16.8001 84 21.7201 84 40.0001V64.0001C84 80.0001 80 88.0001 60 88.0001H36C16 88.0001 12 80.0001 12 64.0001V40.0001C12 21.7601 18.68 16.8001 32 16.0801" stroke="#007AFF" strokeWidth="5" strokeMiterlimit="10" strokeLinecap="round" strokeLinejoin="round"/>
|
||||
const InventoryIcon = ({ width = '25', height = '25', ...props }) => (
|
||||
<svg
|
||||
width={width}
|
||||
height={height}
|
||||
{...props}
|
||||
viewBox="0 0 96 96"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M37.24 58.7998L43.24 64.7998L59.24 48.7998"
|
||||
stroke="#007AFF"
|
||||
strokeWidth="5"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M40 24H56C64 24 64 20 64 16C64 8 60 8 56 8H40C36 8 32 8 32 16C32 24 36 24 40 24Z"
|
||||
stroke="#007AFF"
|
||||
strokeWidth="5"
|
||||
strokeMiterlimit="10"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M64 16.0801C77.32 16.8001 84 21.7201 84 40.0001V64.0001C84 80.0001 80 88.0001 60 88.0001H36C16 88.0001 12 80.0001 12 64.0001V40.0001C12 21.7601 18.68 16.8001 32 16.0801"
|
||||
stroke="#007AFF"
|
||||
strokeWidth="5"
|
||||
strokeMiterlimit="10"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
|
||||
);
|
||||
export default InventoryIcon;
|
||||
|
||||
|
||||
BIN
src/assets/images/blank-profile-picture.webp
Normal file
BIN
src/assets/images/blank-profile-picture.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 17 KiB |
BIN
src/assets/images/fsr-logo.png
Normal file
BIN
src/assets/images/fsr-logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 28 KiB |
BIN
src/assets/images/roofing-company-houston.jpg
Normal file
BIN
src/assets/images/roofing-company-houston.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 136 KiB |
@@ -6,13 +6,13 @@ import TransferList from 'components/MDTransferList';
|
||||
import './AllocationManager.component.scss';
|
||||
|
||||
const AllocationManager = props => {
|
||||
const {boxStyleOverride, component, gridStyleOverride, initlist, list, matchProp, md, onChange, title, variant, xs} = props;
|
||||
const {allDisabled, boxStyleOverride, component, gridStyleOverride, allocatedList, list, matchProp, md, onChange, title, variant, xs} = props;
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const [allocationStatus, setAllocationStatus] = useState();
|
||||
|
||||
const handleAllocationChange = state => {
|
||||
setAllocationStatus(state);
|
||||
onChange && onChange(state.assigned?.map(obj => obj._id).join(','));
|
||||
onChange && onChange(state.assigned);
|
||||
};
|
||||
|
||||
return <Grid item className='c-AllocationManager' xs={xs || 12} md={md || 6} sx={gridStyleOverride}>
|
||||
@@ -24,20 +24,22 @@ const AllocationManager = props => {
|
||||
padding: '12px',
|
||||
borderRadius: '4px'
|
||||
})}
|
||||
className="h-100 d-flex flex-column"
|
||||
>
|
||||
<Typography gutterBottom variant={variant || 'h6'} component={component || 'div'}>
|
||||
{title}
|
||||
</Typography>
|
||||
<TransferList list={list || []} initlist={initlist} matchProp={matchProp} onChange={handleAllocationChange} />
|
||||
<TransferList allDisabled={allDisabled} list={list || []} allocatedList={allocatedList} matchProp={matchProp} onChange={handleAllocationChange} />
|
||||
</MDBox>
|
||||
</Grid>;
|
||||
};
|
||||
|
||||
AllocationManager.propTypes = {
|
||||
allDisabled: PropTypes.bool,
|
||||
boxStyleOverride: PropTypes.object,
|
||||
component: PropTypes.string,
|
||||
gridStyleOverride: PropTypes.object,
|
||||
initlist: PropTypes.oneOfType([
|
||||
allocatedList: PropTypes.oneOfType([
|
||||
PropTypes.string,
|
||||
PropTypes.array
|
||||
]),
|
||||
|
||||
@@ -16,7 +16,7 @@ import { Link } from 'react-router-dom';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
// @mui material components
|
||||
import { Breadcrumbs as MuiBreadcrumbs, Grid, Toolbar } from '@mui/material';
|
||||
import { Box, Breadcrumbs as MuiBreadcrumbs, Grid, Toolbar } from '@mui/material';
|
||||
import ArrowRight from 'assets/images/CarretArrowRightIcon';
|
||||
|
||||
// Material Dashboard 2 PRO React components
|
||||
@@ -53,7 +53,8 @@ const buildBreadcrumbs = (route, light) => {
|
||||
});
|
||||
};
|
||||
|
||||
function Breadcrumbs({ route, light, children }) {
|
||||
function Breadcrumbs({ title, route, children }) {
|
||||
const light = false;
|
||||
return (
|
||||
<Toolbar variant="dense">
|
||||
<MDBox
|
||||
@@ -63,6 +64,19 @@ function Breadcrumbs({ route, light, children }) {
|
||||
// backgroundColor: '#fff'
|
||||
}}
|
||||
>
|
||||
{title && (
|
||||
<Box
|
||||
component="div"
|
||||
sx={{
|
||||
fontSize: '22px',
|
||||
letterSpacing: '0.01em',
|
||||
color: '#000',
|
||||
marginBottom: '15px'
|
||||
}}
|
||||
>
|
||||
{title}
|
||||
</Box>
|
||||
)}
|
||||
<Grid container spacing={2} alignItems="center">
|
||||
<Grid item>
|
||||
<MuiBreadcrumbs
|
||||
@@ -86,15 +100,15 @@ function Breadcrumbs({ route, light, children }) {
|
||||
);
|
||||
}
|
||||
|
||||
// Setting default values for the props of Breadcrumbs
|
||||
Breadcrumbs.defaultProps = {
|
||||
light: false
|
||||
};
|
||||
// // Setting default values for the props of Breadcrumbs
|
||||
// Breadcrumbs.defaultProps = {
|
||||
// light: false
|
||||
// };
|
||||
|
||||
// Typechecking props for the Breadcrumbs
|
||||
Breadcrumbs.propTypes = {
|
||||
route: PropTypes.oneOfType([PropTypes.string, PropTypes.array]).isRequired,
|
||||
light: PropTypes.bool,
|
||||
title: PropTypes.string,
|
||||
children: PropTypes.node
|
||||
};
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import * as React from 'react';
|
||||
import React, {useEffect, useState} from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import Stack from '@mui/material/Stack';
|
||||
import TextField from '@mui/material/TextField';
|
||||
@@ -6,11 +6,15 @@ import AdapterDateFns from '@mui/lab/AdapterDateFns';
|
||||
import LocalizationProvider from '@mui/lab/LocalizationProvider';
|
||||
import DateTimePicker from '@mui/lab/DateTimePicker';
|
||||
|
||||
export default function DateTimeInput({ disabled }) {
|
||||
const [value, setValue] = React.useState(new Date());
|
||||
export default function DateTimeInput({ disabled, value }) {
|
||||
const [date, setDate] = useState(value || new Date());
|
||||
|
||||
useEffect(() => {
|
||||
setDate(value);
|
||||
}, [value]);
|
||||
|
||||
const handleChange = (newValue) => {
|
||||
setValue(newValue);
|
||||
setDate(newValue);
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -19,7 +23,7 @@ export default function DateTimeInput({ disabled }) {
|
||||
<DateTimePicker
|
||||
disabled={disabled}
|
||||
label=""
|
||||
value={value}
|
||||
value={date}
|
||||
renderInput={(params) => <TextField {...params} />}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
@@ -29,5 +33,6 @@ export default function DateTimeInput({ disabled }) {
|
||||
}
|
||||
|
||||
DateTimeInput.propTypes = {
|
||||
disabled: PropTypes.bool
|
||||
disabled: PropTypes.bool,
|
||||
value: PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.object])
|
||||
};
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import React from 'react';
|
||||
import Box from '@mui/material/Box';
|
||||
// import InputLabel from '@mui/material/InputLabel'
|
||||
import PropTypes from 'prop-types';
|
||||
import OutlinedInput from '@mui/material/OutlinedInput';
|
||||
import MenuItem from '@mui/material/MenuItem';
|
||||
import FormControl from '@mui/material/FormControl';
|
||||
import Select from '@mui/material/Select';
|
||||
@@ -15,53 +13,32 @@ const useStyles = makeStyles({
|
||||
color: 'black'
|
||||
}
|
||||
});
|
||||
export default function Dropdown({ items, dropdownData }) {
|
||||
|
||||
export default function Dropdown({ dropdownData, label, onChange, value }) {
|
||||
const classes = useStyles();
|
||||
|
||||
const [age, setAge] = useState('');
|
||||
const [dropDownValue, setDropDownValue] = useState([]);
|
||||
|
||||
useEffect(() => {
|
||||
setDropDownValue(items);
|
||||
}, [items]);
|
||||
|
||||
const handleChange = (event) => {
|
||||
const {
|
||||
target: { value }
|
||||
} = event;
|
||||
setAge(
|
||||
// On autofill we get a stringified value.
|
||||
typeof value === 'string' ? value.split(',') : value
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Box sx={{ width: '100%' }}>
|
||||
<InputLabel className={classes.font} id="demo-simple-select-label" sx={{ pb: 2, pt: 3 }}>
|
||||
{dropDownValue?.label}
|
||||
{label}
|
||||
</InputLabel>
|
||||
<FormControl sx={{ width: '100%' }}>
|
||||
<Select
|
||||
displayEmpty
|
||||
input={<OutlinedInput />}
|
||||
value={age}
|
||||
renderValue={(selected) => {
|
||||
if (selected.length === 0) {
|
||||
return <span>{dropDownValue?.placeholder}</span>;
|
||||
}
|
||||
return selected;
|
||||
}}
|
||||
value={value}
|
||||
inputProps={{ 'aria-label': 'Without label' }}
|
||||
onChange={handleChange}
|
||||
onChange={onChange}
|
||||
>
|
||||
<MenuItem disabled value="">
|
||||
<span>{dropDownValue?.label}</span>
|
||||
None selected
|
||||
</MenuItem>
|
||||
{dropdownData && dropdownData.map((data) => (
|
||||
<MenuItem value={data.displayname} key={data.ID}>{data.displayname}</MenuItem>
|
||||
))}
|
||||
|
||||
{dropdownData &&
|
||||
dropdownData.map((data) => (
|
||||
<MenuItem value={data._id} key={data._id}>
|
||||
{data.name}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
</FormControl>
|
||||
</Box>
|
||||
@@ -69,7 +46,8 @@ export default function Dropdown({ items, dropdownData }) {
|
||||
);
|
||||
}
|
||||
Dropdown.propTypes = {
|
||||
items: PropTypes.object.isRequired,
|
||||
dropdownData: PropTypes.object.isRequired
|
||||
|
||||
dropdownData: PropTypes.array,
|
||||
onChange: PropTypes.any,
|
||||
label: PropTypes.string,
|
||||
value: PropTypes.any
|
||||
};
|
||||
|
||||
@@ -11,7 +11,7 @@ import TableHead from '@mui/material/TableHead';
|
||||
import TableRow from '@mui/material/TableRow';
|
||||
import Paper from '@mui/material/Paper';
|
||||
import TablePagination from 'components/TablePagination';
|
||||
import { Dialog, DialogActions, MenuItem, Select } from '@mui/material';
|
||||
import { Grid, MenuItem, Select } from '@mui/material';
|
||||
|
||||
const StyledTableCell = styled(TableCell)(({ theme }) => ({
|
||||
[`&.${tableCellClasses.head}`]: {
|
||||
@@ -41,10 +41,11 @@ const StyledTableRow = styled(TableRow)(({ theme }) => ({
|
||||
Row.propTypes = {
|
||||
rowData: PropTypes.array,
|
||||
tHeads: PropTypes.array,
|
||||
editHandler: PropTypes.any
|
||||
editHandler: PropTypes.any,
|
||||
deleteHandler: PropTypes.any
|
||||
};
|
||||
|
||||
function Row({ tHeads, rowData, editHandler }) {
|
||||
function Row({ tHeads, rowData, editHandler, deleteHandler }) {
|
||||
return (
|
||||
<React.Fragment>
|
||||
<StyledTableRow sx={{ '&odd > *': { borderBottom: 'unset' } }}>
|
||||
@@ -68,6 +69,25 @@ function Row({ tHeads, rowData, editHandler }) {
|
||||
>
|
||||
EDIT
|
||||
</MDButton>
|
||||
<MDButton
|
||||
size="small"
|
||||
variant="contained"
|
||||
color="error"
|
||||
sx={{
|
||||
textTransform: 'capitalize',
|
||||
minWidth: '45px',
|
||||
minHeight: '28px',
|
||||
marginLeft: '10px',
|
||||
boxShadow: 'none',
|
||||
fontWeight: '500',
|
||||
padding: '0'
|
||||
}}
|
||||
onClick={() => {
|
||||
deleteHandler(rowData._id);
|
||||
}}
|
||||
>
|
||||
DELETE
|
||||
</MDButton>
|
||||
</StyledTableCell>
|
||||
{tHeads &&
|
||||
tHeads
|
||||
@@ -87,15 +107,10 @@ function EnhancedTable({
|
||||
data,
|
||||
tHeads,
|
||||
editHandler,
|
||||
deleteHandler,
|
||||
filtersControl,
|
||||
resetFilters
|
||||
}) {
|
||||
const [filtersOpen, setFiltersOpen] = React.useState(false);
|
||||
|
||||
const handleFiltersClose = () => {
|
||||
setFiltersOpen(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Box
|
||||
@@ -106,7 +121,9 @@ function EnhancedTable({
|
||||
overflow: 'hidden'
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
<Grid
|
||||
container
|
||||
fullWidth
|
||||
sx={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
@@ -114,41 +131,15 @@ function EnhancedTable({
|
||||
padding: '16px'
|
||||
}}
|
||||
>
|
||||
<Box>{/* <SearchBar /> */}</Box>
|
||||
<Box sx={{ display: 'flex', columnGap: '15px' }}>
|
||||
<MDButton
|
||||
size="small"
|
||||
variant="outlined"
|
||||
color="primary"
|
||||
sx={{
|
||||
textTransform: 'capitalize',
|
||||
minWidth: '60px',
|
||||
minHeight: '44px',
|
||||
fontWeight: '500'
|
||||
}}
|
||||
onClick={() => {
|
||||
setFiltersOpen(true);
|
||||
}}
|
||||
>
|
||||
Filter
|
||||
</MDButton>
|
||||
{/* <Box><SearchBar /></Box> */}
|
||||
<Grid container item xs={12} spacing={5}>
|
||||
{filtersControl ? (
|
||||
<Dialog open={filtersOpen} onClose={handleFiltersClose}>
|
||||
<>
|
||||
{filtersControl}
|
||||
<DialogActions>
|
||||
<Grid item sx={4}>
|
||||
<MDButton onClick={resetFilters}>Reset Filters</MDButton>
|
||||
<MDButton
|
||||
size="small"
|
||||
variant="outlined"
|
||||
color="primary"
|
||||
onClick={() => {
|
||||
setFiltersOpen(false);
|
||||
}}
|
||||
>
|
||||
Close
|
||||
</MDButton>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
</Grid>
|
||||
</>
|
||||
) : null}
|
||||
{/* <MDButton
|
||||
id="fade-button"
|
||||
@@ -183,8 +174,8 @@ function EnhancedTable({
|
||||
<MenuItem>My account</MenuItem>
|
||||
<MenuItem>Logout</MenuItem>
|
||||
</Menu> */}
|
||||
</Box>
|
||||
</Box>
|
||||
</Grid>
|
||||
</Grid>
|
||||
{/* Table-row- */}
|
||||
<TableContainer component={Paper} sx={{ borderRadius: '0 !important', boxShadow: 'none' }}>
|
||||
<Table aria-label="collapsible table" sx={{ minWidth: 700 }}>
|
||||
@@ -202,6 +193,7 @@ function EnhancedTable({
|
||||
<Row
|
||||
key={rowData._id}
|
||||
editHandler={editHandler}
|
||||
deleteHandler={deleteHandler}
|
||||
rowData={rowData}
|
||||
tHeads={tHeads}
|
||||
/>
|
||||
@@ -334,6 +326,7 @@ EnhancedTable.propTypes = {
|
||||
data: PropTypes.array,
|
||||
tHeads: PropTypes.array,
|
||||
editHandler: PropTypes.any,
|
||||
deleteHandler: PropTypes.any,
|
||||
filtersControl: PropTypes.any,
|
||||
resetFilters: PropTypes.any
|
||||
};
|
||||
|
||||
@@ -25,7 +25,7 @@ function ImageUploadSingle({ heading, accept, multiple, images, setImages }) {
|
||||
cursor: 'pointer',
|
||||
position: 'relative',
|
||||
textAlign: 'center',
|
||||
minHeight: pxToRem(200),
|
||||
height: pxToRem(250),
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
@@ -72,14 +72,14 @@ function ImageUploadSingle({ heading, accept, multiple, images, setImages }) {
|
||||
cursor: 'pointer',
|
||||
position: 'relative',
|
||||
textAlign: 'center',
|
||||
minHeight: pxToRem(200),
|
||||
height: pxToRem(250),
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
marginBottom: '16px'
|
||||
}}
|
||||
>
|
||||
<img src={images[0].src} alt="" width="100%" height="100%" />
|
||||
<img src={images[0].src} alt="" height="100%" />
|
||||
<Button
|
||||
sx={{
|
||||
backgroundColor: '#fff !important',
|
||||
|
||||
@@ -36,10 +36,14 @@ const useStyles = makeStyles({
|
||||
'& .MuiCheckbox-root': {
|
||||
paddingLeft: '0px'
|
||||
}
|
||||
},
|
||||
maxHeight: {
|
||||
maxHeight: '20rem',
|
||||
overflow: 'auto'
|
||||
}
|
||||
});
|
||||
|
||||
export default function TransferList({list, initlist, matchProp, onChange}) {
|
||||
export default function TransferList({allDisabled, list, allocatedList, matchProp, onChange}) {
|
||||
const classes = useStyles();
|
||||
const [checked, setChecked] = useState([]);
|
||||
const [left, setLeft] = useState(list || []);
|
||||
@@ -49,14 +53,14 @@ export default function TransferList({list, initlist, matchProp, onChange}) {
|
||||
const rightChecked = intersection(checked, right);
|
||||
|
||||
useEffect(() => {
|
||||
if (initlist) {
|
||||
const initlistClone = typeof initlist === 'object' ? initlist : initlist.split(',');
|
||||
const left = notBy(matchProp, list, initlistClone);
|
||||
const right = intersectionBy(matchProp, list, initlistClone);
|
||||
if (typeof allocatedList === 'string') {
|
||||
const allocatedListClone = typeof allocatedList === 'object' ? allocatedList : allocatedList.split(',');
|
||||
const left = notBy(matchProp, list, allocatedListClone);
|
||||
const right = intersectionBy(matchProp, list, allocatedListClone);
|
||||
setLeft(left);
|
||||
setRight(right);
|
||||
}
|
||||
}, []);
|
||||
}, [allocatedList]);
|
||||
|
||||
const handleToggle = (value) => () => {
|
||||
const currentIndex = checked.indexOf(value);
|
||||
@@ -106,13 +110,13 @@ export default function TransferList({list, initlist, matchProp, onChange}) {
|
||||
};
|
||||
|
||||
const customList = items => (
|
||||
<List component="div" role="list">
|
||||
<List component="div" role="list" className={classes.maxHeight}>
|
||||
{items.map((item, key) => {
|
||||
const value = item.name;
|
||||
const labelId = `transfer-list-item-${value}-label`;
|
||||
|
||||
return (
|
||||
<ListItem button key={value + '-' + key} role="listitem" onClick={handleToggle(item)}>
|
||||
<ListItem button disabled={allDisabled} key={value + '-' + key} role="listitem" onClick={handleToggle(item)}>
|
||||
<ListItemIcon className={classes.unsetwidth}>
|
||||
<Checkbox
|
||||
disableRipple
|
||||
@@ -137,7 +141,7 @@ export default function TransferList({list, initlist, matchProp, onChange}) {
|
||||
);
|
||||
|
||||
return (
|
||||
<Grid container>
|
||||
<Grid container className="flex-fill">
|
||||
<Grid item md={5} className={classes.boxStyling}>
|
||||
<Typography gutterBottom variant="caption" component="div">
|
||||
Unassigned
|
||||
@@ -201,7 +205,8 @@ export default function TransferList({list, initlist, matchProp, onChange}) {
|
||||
}
|
||||
|
||||
TransferList.propTypes = {
|
||||
initlist: PropTypes.oneOfType([
|
||||
allDisabled: PropTypes.bool,
|
||||
allocatedList: PropTypes.oneOfType([
|
||||
PropTypes.string,
|
||||
PropTypes.array
|
||||
]),
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
/* eslint-disable indent */
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
// Chip,
|
||||
Dialog,
|
||||
DialogActions,
|
||||
DialogContent,
|
||||
DialogContentText,
|
||||
DialogTitle,
|
||||
Grid,
|
||||
MenuItem,
|
||||
@@ -64,6 +66,14 @@ function NestedDataTable({ data, selected, setSelected, populateChildren }) {
|
||||
populateChildren(data.id, data.location);
|
||||
}, []);
|
||||
|
||||
const [deleteAlertOpen, setDeleteAlertOpen] = React.useState(null);
|
||||
const handleDeleteAlertClose = () => {
|
||||
setDeleteAlertOpen(false);
|
||||
};
|
||||
const handleDeleteAlertOpen = () => {
|
||||
setDeleteAlertOpen(true);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Box
|
||||
@@ -80,7 +90,7 @@ function NestedDataTable({ data, selected, setSelected, populateChildren }) {
|
||||
selected?.id === data.id
|
||||
? 'linear-gradient(135deg, ' +
|
||||
getColorOfLocationType(data.location) +
|
||||
' 0%, #f9f9f9 20%)'
|
||||
' 0%, #f9f9f9 100%)'
|
||||
: '#f9f9f9'
|
||||
}}
|
||||
>
|
||||
@@ -154,18 +164,44 @@ function NestedDataTable({ data, selected, setSelected, populateChildren }) {
|
||||
padding: '0 6'
|
||||
}}
|
||||
onClick={() => {
|
||||
dispatch(
|
||||
WarehouseLocationsActions.deleteLocationRequest({
|
||||
loader: 'location-request',
|
||||
slug: API.LOCATION_DELETE,
|
||||
method: 'post',
|
||||
data: { type: data.location, id: data.id }
|
||||
})
|
||||
);
|
||||
handleDeleteAlertOpen();
|
||||
}}
|
||||
>
|
||||
DELETE
|
||||
</MDButton>
|
||||
<Dialog
|
||||
open={deleteAlertOpen}
|
||||
aria-labelledby="alert-dialog-title"
|
||||
aria-describedby="alert-dialog-description"
|
||||
onClose={handleDeleteAlertClose}
|
||||
>
|
||||
<DialogTitle id="alert-dialog-title">Confirm Delete</DialogTitle>
|
||||
<DialogContent>
|
||||
<DialogContentText id="alert-dialog-description">
|
||||
Are you sure you want to delete this?
|
||||
</DialogContentText>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button autoFocus onClick={handleDeleteAlertClose}>
|
||||
No
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => {
|
||||
dispatch(
|
||||
WarehouseLocationsActions.deleteLocationRequest({
|
||||
loader: 'location-request',
|
||||
slug: API.LOCATION_DELETE,
|
||||
method: 'post',
|
||||
data: { type: data.location, id: data.id }
|
||||
})
|
||||
);
|
||||
handleDeleteAlertClose();
|
||||
}}
|
||||
>
|
||||
Yes
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
3
src/components/PwTablePanel/PwTablePanel.component.scss
Executable file
3
src/components/PwTablePanel/PwTablePanel.component.scss
Executable file
@@ -0,0 +1,3 @@
|
||||
.c-PwTablePanel {
|
||||
|
||||
}
|
||||
79
src/components/PwTablePanel/PwTablePanel.jsx
Executable file
79
src/components/PwTablePanel/PwTablePanel.jsx
Executable file
@@ -0,0 +1,79 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { styled } from '@mui/material/styles';
|
||||
import { TableBody, TableCell, TableRow } from '@mui/material';
|
||||
import BasicTable from 'components/BasicTable';
|
||||
import TabPanel from 'components/Tabs';
|
||||
import EditIcon from '@mui/icons-material/Edit';
|
||||
import './PwTablePanel.component.scss';
|
||||
|
||||
const PwTablePanel = props => {
|
||||
const { backgroundColor, classes, color, dataFetched, headCells, id, loader, index, navUrl, records, table, value } = props;
|
||||
const navigate = useNavigate();
|
||||
|
||||
const StyledTableRow = styled(TableRow)(({ theme }) => ({
|
||||
'&:nth-of-type(even)': {
|
||||
backgroundColor: theme.palette.action.hover
|
||||
}
|
||||
}));
|
||||
|
||||
const rowRenders = ({ records, headers, navUrl, table }) => {
|
||||
return records && records.map((record, keyouter) => {
|
||||
return <StyledTableRow key={record.id + '-' + keyouter}>
|
||||
{headers.map((columnConfig, key) => {
|
||||
const canEdit = columnConfig.isEditAnchor;
|
||||
const isAfter = columnConfig.placement && columnConfig.placement === 'after';
|
||||
const limitWidth = columnConfig.limitWidth;
|
||||
return <TableCell key={key} className={`${isAfter ? 'position-relative pe-5' : ''}${limitWidth ? ' overflow-auto ' + classes.limitWidth : ''}`}
|
||||
onClick={() => canEdit && navigate(navUrl, { state: { [table]: record } })}>
|
||||
{canEdit
|
||||
? isAfter
|
||||
? <span className={classes.iconwrap}>
|
||||
{columnConfig.value(record)}
|
||||
<EditIcon className={classes.iconSize + ' ' + classes.rightPlaced} />
|
||||
</span>
|
||||
: <span className={classes.iconwrap}>
|
||||
<EditIcon className={classes.iconSize} />
|
||||
{columnConfig.value(record)}
|
||||
</span>
|
||||
: <span>{columnConfig.value(record)}</span>}
|
||||
</TableCell>;
|
||||
}
|
||||
)}
|
||||
</StyledTableRow>;
|
||||
});
|
||||
};
|
||||
|
||||
return <TabPanel id={`c-PwTablePanel-${index}`} value={value} index={index} className={classes.radialBorder}>
|
||||
<BasicTable
|
||||
id={id}
|
||||
headCells={headCells}
|
||||
backgroundColor={backgroundColor || '#007AFF'}
|
||||
color={color || '#fff'}
|
||||
>
|
||||
{records && records.length > 0 && <TableBody className={loader ? 'loader' : ''}>
|
||||
{rowRenders({ records, headers: headCells, navUrl, table })}
|
||||
</TableBody>}
|
||||
</BasicTable>
|
||||
{(dataFetched && (!records || records.length === 0))
|
||||
&& <p className='mx-3 my-5 d-flex justify-content-center align-items-center h4'>No Records to Display</p>}
|
||||
</TabPanel>;
|
||||
};
|
||||
|
||||
PwTablePanel.propTypes = {
|
||||
backgroundColor: PropTypes.string,
|
||||
classes: PropTypes.string,
|
||||
color: PropTypes.string,
|
||||
dataFetched: PropTypes.bool,
|
||||
headCells: PropTypes.array,
|
||||
id: PropTypes.string,
|
||||
index: PropTypes.number,
|
||||
loader: PropTypes.bool,
|
||||
navUrl: PropTypes.string,
|
||||
records: PropTypes.array,
|
||||
table: PropTypes.string,
|
||||
value: PropTypes.number
|
||||
};
|
||||
|
||||
export default PwTablePanel;
|
||||
8
src/components/PwTablePanel/PwTablePanel.test.js
Executable file
8
src/components/PwTablePanel/PwTablePanel.test.js
Executable file
@@ -0,0 +1,8 @@
|
||||
import React from "react";
|
||||
import PwTablePanel from "./PwTablePanel";
|
||||
|
||||
describe("PwTablePanel", () => {
|
||||
it("renders without error", () => {
|
||||
|
||||
});
|
||||
});
|
||||
3
src/components/PwTablePanel/index.js
Executable file
3
src/components/PwTablePanel/index.js
Executable file
@@ -0,0 +1,3 @@
|
||||
import PwTablePanel from "./PwTablePanel.jsx";
|
||||
|
||||
export default PwTablePanel;
|
||||
@@ -1,8 +1,10 @@
|
||||
import { TextField, InputAdornment, SvgIcon } from '@mui/material';
|
||||
import PropTypes from 'prop-types';
|
||||
import { makeStyles } from '@mui/styles';
|
||||
import Search from 'assets/images/SearchIcon';
|
||||
|
||||
function SearchBar() {
|
||||
function SearchBar(props) {
|
||||
const { onChange } = props;
|
||||
|
||||
const useStyles = makeStyles(() => ({
|
||||
textField: {
|
||||
@@ -30,8 +32,13 @@ function SearchBar() {
|
||||
}}
|
||||
placeholder="Search"
|
||||
variant="outlined"
|
||||
onChange={onChange}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
SearchBar.propTypes = {
|
||||
onChange: PropTypes.func
|
||||
};
|
||||
export default SearchBar;
|
||||
|
||||
@@ -56,12 +56,13 @@ const IOSSwitch = styled((props) => (
|
||||
}
|
||||
}));
|
||||
|
||||
export default function Switch({ checked, onChange, name }) {
|
||||
return <IOSSwitch checked={checked} sx={{ m: 1 }} name={name} onChange={onChange} />;
|
||||
export default function Switch({ disabled, checked, onChange, name }) {
|
||||
return <IOSSwitch disabled={disabled} checked={checked} sx={{ m: 1 }} name={name} onChange={onChange} />;
|
||||
}
|
||||
|
||||
Switch.propTypes = {
|
||||
checked: PropTypes.any,
|
||||
disabled: PropTypes.bool,
|
||||
name: PropTypes.any,
|
||||
onChange: PropTypes.any
|
||||
};
|
||||
|
||||
@@ -67,7 +67,7 @@ export default function TileBasic({ tiles }) {
|
||||
<Grid container spacing={2}>
|
||||
{tiles &&
|
||||
tiles.map((item) => (
|
||||
<Grid item key={item.name} xs={12} sm={6} md={tiles.length > 4 ? 4 : 6}>
|
||||
<Grid item key={item._id} xs={12} sm={6} md={tiles.length > 4 ? 4 : 6}>
|
||||
{item.disabled ? (
|
||||
<MDBox
|
||||
key={item.name + item.path}
|
||||
|
||||
@@ -39,7 +39,7 @@ export default function Tile({ data, children }) {
|
||||
Update {data.name} <ArrowRightIcon />
|
||||
</Box>
|
||||
</Link>
|
||||
<Link to={`/setup/inventory/new-item/${data.widgetname}/${data.id}`}>
|
||||
<Link to={`/setup/inventory/new-item/${data.name}/${data.widgetname}/${data.id}`}>
|
||||
<Box className={`${classes.box} ${classes.boxEven}`}>
|
||||
Add New {data.widgetname} <ArrowRightIcon />
|
||||
</Box>
|
||||
@@ -49,7 +49,7 @@ export default function Tile({ data, children }) {
|
||||
Cycle Count <ArrowRightIcon />
|
||||
</Box>
|
||||
</Link>
|
||||
<Link to={`/setup/inventory/browse/${data.widgetname}/${data.id}`}>
|
||||
<Link to={`/setup/inventory/browse/${data.name}/${data.widgetname}/${data.id}`}>
|
||||
<Box className={`${classes.box} ${classes.boxEven}`}>
|
||||
{data.widgetname} List <ArrowRightIcon />
|
||||
</Box>
|
||||
|
||||
@@ -17,26 +17,30 @@ const useStyles = makeStyles(() => ({
|
||||
'& .MuiSwitch-root': {
|
||||
margin: '0'
|
||||
}
|
||||
},
|
||||
maxHeight: {
|
||||
maxHeight: '20rem',
|
||||
overflow: 'auto'
|
||||
}
|
||||
}));
|
||||
|
||||
const Toggles = props => {
|
||||
const {boxSx, inittoggles, md, onChange, title, toggles, typoComponent, typoSx, typoVariant, xs} = props;
|
||||
const {allDisabled, boxSx, gridStyleOverride, selectedToggles, md, onChange, title, toggles, typoComponent, typoSx, typoVariant, xs} = props;
|
||||
const [toggleState, updateToggleState] = useState({});
|
||||
const classes = useStyles();
|
||||
|
||||
useEffect(() => {
|
||||
if (inittoggles && typeof inittoggles === 'string') {
|
||||
const initToggleState = {};
|
||||
inittoggles.split(',').forEach(iToggle => initToggleState[iToggle] = true);
|
||||
updateToggleState(initToggleState);
|
||||
if (typeof selectedToggles === 'string') {
|
||||
const selectedToggleState = {};
|
||||
selectedToggles.split(',').forEach(iToggle => selectedToggleState[iToggle] = true);
|
||||
updateToggleState(selectedToggleState);
|
||||
}
|
||||
}, []);
|
||||
}, [selectedToggles]);
|
||||
|
||||
const handleToggle = (e, toggle) => {
|
||||
const toggleStateClone = {...toggleState, [toggle]: e.target.checked};
|
||||
updateToggleState(toggleStateClone);
|
||||
onChange && onChange(Object.keys(toggleStateClone).join(','));
|
||||
onChange && onChange(toggleStateClone);
|
||||
};
|
||||
|
||||
const switchRenders = toggles => toggles && toggles.map((toggle, key) => {
|
||||
@@ -45,24 +49,26 @@ const Toggles = props => {
|
||||
return <MDBox key={key} display='flex' justifyContent='space-between' alignItems='center' lineHeight={1} className={classes.switchSpacer}
|
||||
sx={{ marginBottom: '20px !important' }}>
|
||||
<MDTypography variant='body2'>{toggle}</MDTypography>
|
||||
<Switch id={id} checked={toggleState[toggle] === undefined ? false : toggleState[toggle]} onChange={e => handleToggle(e, toggle)} />
|
||||
<Switch disabled={allDisabled} id={id} checked={toggleState[toggle] === undefined ? false : toggleState[toggle]} onChange={e => handleToggle(e, toggle)} />
|
||||
</MDBox>;
|
||||
});
|
||||
|
||||
return <Grid item id='c-Toggles' xs={xs || 12} md={md || 3} >
|
||||
return <Grid item className='c-Toggles' xs={xs || 12} md={md || 6} sx={gridStyleOverride}>
|
||||
<MDBox sx={boxSx || {backgroundColor: '#fff', border: '1px solid #c2c2c2', borderTop: '7px solid #007aff', borderRadius: '4px'}}>
|
||||
<Typography gutterBottom variant={typoVariant || 'h6'} component={typoComponent || 'div'}
|
||||
sx={typoSx || {borderBottom: '1px solid #c2c2c2', padding: '10px 20px', marginBottom: '20px'}}>
|
||||
{title || 'Title'}
|
||||
</Typography>
|
||||
<Box sx={{ padding: ' 0px 20px' }}>{toggles && switchRenders(toggles)}</Box>
|
||||
<Box sx={{ padding: ' 0px 20px' }} className={classes.maxHeight}>{toggles && switchRenders(toggles)}</Box>
|
||||
</MDBox>
|
||||
</Grid>;
|
||||
};
|
||||
|
||||
Toggles.propTypes = {
|
||||
allDisabled: PropTypes.bool,
|
||||
boxSx: PropTypes.object,
|
||||
inittoggles: PropTypes.string,
|
||||
gridStyleOverride: PropTypes.object,
|
||||
selectedToggles: PropTypes.string,
|
||||
md: PropTypes.number,
|
||||
onChange: PropTypes.func,
|
||||
title: PropTypes.string,
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
/* eslint-disable indent */
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
Dialog,
|
||||
DialogActions,
|
||||
DialogContent,
|
||||
DialogContentText,
|
||||
DialogTitle,
|
||||
Grid,
|
||||
TextField
|
||||
@@ -116,6 +118,14 @@ function WidgetNestedDataTable({
|
||||
const dispatch = useDispatch();
|
||||
const widgetChildren = useSelector(WidgetSelectors.getWidgetsByParentId(data._id));
|
||||
|
||||
const [deleteAlertOpen, setDeleteAlertOpen] = React.useState(null);
|
||||
const handleDeleteAlertClose = () => {
|
||||
setDeleteAlertOpen(false);
|
||||
};
|
||||
const handleDeleteAlertOpen = () => {
|
||||
setDeleteAlertOpen(true);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Box
|
||||
@@ -193,19 +203,45 @@ function WidgetNestedDataTable({
|
||||
}}
|
||||
onClick={() => {
|
||||
setSelected(null);
|
||||
dispatch(
|
||||
WidgetActions.editWidgetRequest({
|
||||
loader: 'location-request',
|
||||
slug: `${API.EDIT_WIDGET_FAMILY}${data._id}`,
|
||||
deletedId: data._id,
|
||||
method: 'delete',
|
||||
type: 'delete'
|
||||
})
|
||||
);
|
||||
handleDeleteAlertOpen();
|
||||
}}
|
||||
>
|
||||
DELETE
|
||||
</MDButton>
|
||||
<Dialog
|
||||
open={deleteAlertOpen}
|
||||
aria-labelledby="alert-dialog-title"
|
||||
aria-describedby="alert-dialog-description"
|
||||
onClose={handleDeleteAlertClose}
|
||||
>
|
||||
<DialogTitle id="alert-dialog-title">Confirm Delete</DialogTitle>
|
||||
<DialogContent>
|
||||
<DialogContentText id="alert-dialog-description">
|
||||
Are you sure you want to delete this?
|
||||
</DialogContentText>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button autoFocus onClick={handleDeleteAlertClose}>
|
||||
No
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => {
|
||||
dispatch(
|
||||
WidgetActions.editWidgetRequest({
|
||||
loader: 'location-request',
|
||||
slug: `${API.EDIT_WIDGET_FAMILY}${data._id}`,
|
||||
deletedId: data._id,
|
||||
method: 'delete',
|
||||
type: 'delete'
|
||||
})
|
||||
);
|
||||
handleDeleteAlertClose();
|
||||
}}
|
||||
>
|
||||
Yes
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
</Grid>
|
||||
</Grid>
|
||||
{open && widgetChildren ? (
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
/* PLOP_INJECT_IMPORT */
|
||||
import PwTablePanel from './PwTablePanel';
|
||||
import Toggles from './Toggles';
|
||||
import AllocationManager from './AllocationManager';
|
||||
|
||||
export {
|
||||
/* PLOP_INJECT_EXPORT */
|
||||
PwTablePanel,
|
||||
Toggles,
|
||||
AllocationManager
|
||||
};
|
||||
|
||||
@@ -24,5 +24,7 @@ export default {
|
||||
GET_WIDGET_FAMILY_BY_INVENTORY: '/widget-family/search-by-inventory?inventory=',
|
||||
ADD_WIDGET_FAMILY: '/widget-family',
|
||||
EDIT_WIDGET_FAMILY: '/widget-family/',
|
||||
GET_LABEL: '/sublevel/filter',
|
||||
GET_PRODUCT_BY_ID: '/item/filter?inventory=',
|
||||
GET_ITEMS_BY_INVENTORY: '/item/filter?inventory='
|
||||
};
|
||||
|
||||
@@ -1,17 +1,32 @@
|
||||
import { useSelector } from 'react-redux';
|
||||
import { AuthSelectors } from 'redux/AuthRedux';
|
||||
import { decode } from 'jsonwebtoken';
|
||||
// import { decode } from 'jsonwebtoken';
|
||||
import LOGGER from 'services/Logger';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import AuthActions from 'redux/AuthRedux';
|
||||
|
||||
function decode(token) {
|
||||
var base64Url = token.split('.')[1];
|
||||
var base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
|
||||
var jsonPayload = decodeURIComponent(
|
||||
atob(base64)
|
||||
.split('')
|
||||
.map(function (c) {
|
||||
return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
|
||||
})
|
||||
.join('')
|
||||
);
|
||||
|
||||
return JSON.parse(jsonPayload);
|
||||
}
|
||||
|
||||
const useAuthentication = () => {
|
||||
const dispatch = useDispatch();
|
||||
const user = useSelector(AuthSelectors.getUser);
|
||||
const token = localStorage.getItem('token');
|
||||
try {
|
||||
const { exp } = decode(token);
|
||||
if (exp < (new Date().getTime() + 1) / 1000) {
|
||||
const decodedToken = token && decode(token);
|
||||
if (!token || decodedToken.exp < (new Date().getTime() + 1) / 1000) {
|
||||
localStorage.removeItem('token');
|
||||
localStorage.removeItem('refreshToken');
|
||||
dispatch(AuthActions.logout());
|
||||
@@ -22,7 +37,6 @@ const useAuthentication = () => {
|
||||
localStorage.removeItem('token');
|
||||
localStorage.removeItem('refreshToken');
|
||||
dispatch(AuthActions.logout());
|
||||
return { isAuthenticated: false };
|
||||
}
|
||||
return { isAuthenticated: !!user };
|
||||
};
|
||||
|
||||
@@ -17,6 +17,7 @@ import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import { BrowserRouter } from 'react-router-dom';
|
||||
import 'bootstrap/dist/css/bootstrap.min.css';
|
||||
import './main.css';
|
||||
import App from 'App';
|
||||
|
||||
// Soft UI Context Provider
|
||||
|
||||
@@ -13,6 +13,8 @@ import PageLayout from 'layouts/PageLayout';
|
||||
// Material Dashboard 2 PRO React context
|
||||
import { useMaterialUIController } from 'context';
|
||||
|
||||
import companyImage from 'assets/images/fsr-logo.png';
|
||||
|
||||
function AuthLayout({ header, title, description, illustration, children }) {
|
||||
const [controller] = useMaterialUIController();
|
||||
const { darkMode } = controller;
|
||||
@@ -34,12 +36,30 @@ function AuthLayout({ header, title, description, illustration, children }) {
|
||||
borderRadius="lg"
|
||||
ml={2}
|
||||
mt={2}
|
||||
sx={{ backgroundImage: `url(${illustration})` }}
|
||||
sx={{
|
||||
backgroundImage: `url(${illustration})`,
|
||||
backgroundSize: 'cover',
|
||||
backgroundRepeat: 'no-repeat',
|
||||
backgroundPosition: 'center'
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={11} sm={8} md={6} lg={4} xl={3} sx={{ mx: 'auto' }}>
|
||||
<MDBox display="flex" flexDirection="column" justifyContent="center" height="100vh">
|
||||
<MDBox py={3} px={3} textAlign="center">
|
||||
<MDBox
|
||||
display={{ xs: 'none', lg: 'flex' }}
|
||||
width="350px"
|
||||
height="117px"
|
||||
borderRadius="lg"
|
||||
ml={2}
|
||||
my={5}
|
||||
sx={{
|
||||
backgroundImage: `url(${companyImage})`,
|
||||
backgroundRepeat: 'no-repeat',
|
||||
backgroundPosition: 'center'
|
||||
}}
|
||||
/>
|
||||
{!header ? (
|
||||
<>
|
||||
<MDBox mb={1} textAlign="center">
|
||||
|
||||
67
src/main.css
Normal file
67
src/main.css
Normal file
@@ -0,0 +1,67 @@
|
||||
fieldset legend {
|
||||
width: 0;
|
||||
}
|
||||
|
||||
.loader {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.loader:before {
|
||||
display: block;
|
||||
content: "";
|
||||
position: absolute;
|
||||
background-color: transparent;
|
||||
background-image: url("./assets/images/favicon.png");
|
||||
background-size: 3rem;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
-webkit-animation: rotating 2s linear infinite;
|
||||
-moz-animation: rotating 2s linear infinite;
|
||||
-ms-animation: rotating 2s linear infinite;
|
||||
-o-animation: rotating 2s linear infinite;
|
||||
animation: rotating 2s linear infinite;
|
||||
z-index: 1050;
|
||||
}
|
||||
|
||||
.loader:after {
|
||||
content: "";
|
||||
top: 0;
|
||||
left: 0;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
background: rgba(255, 255, 255, 0.7);
|
||||
position: absolute;
|
||||
z-index: 1040;
|
||||
}
|
||||
|
||||
@-webkit-keyframes rotating {
|
||||
from {
|
||||
-webkit-transform: rotate(0deg);
|
||||
-o-transform: rotate(0deg);
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
to {
|
||||
-webkit-transform: rotateY(360deg);
|
||||
-o-transform: rotateY(360deg);
|
||||
transform: rotateY(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes rotating {
|
||||
from {
|
||||
-ms-transform: rotate(0deg);
|
||||
-moz-transform: rotate(0deg);
|
||||
-webkit-transform: rotate(0deg);
|
||||
-o-transform: rotate(0deg);
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
to {
|
||||
-ms-transform: rotateY(360deg);
|
||||
-moz-transform: rotateY(360deg);
|
||||
-webkit-transform: rotateY(360deg);
|
||||
-o-transform: rotateY(360deg);
|
||||
transform: rotateY(360deg);
|
||||
}
|
||||
}
|
||||
@@ -51,7 +51,7 @@ const useStyles = makeStyles({
|
||||
|
||||
function AddNewItem() {
|
||||
const classes = useStyles();
|
||||
const { widgetName, inventoryId, itemId } = useParams();
|
||||
const { widgetName, inventoryName, inventoryId, itemId } = useParams();
|
||||
const getInitialFormValues = (data) => {
|
||||
return data && data._id === itemId
|
||||
? {
|
||||
@@ -135,10 +135,6 @@ function AddNewItem() {
|
||||
);
|
||||
}, []);
|
||||
|
||||
const [pFam, setPFam] = React.useState(null);
|
||||
const primaryFamily = useSelector(WidgetSelectors.getWidgetFamiliesByInventoryId(inventoryId));
|
||||
const secondaryFamily = useSelector(WidgetSelectors.getWidgetsByParentId(pFam));
|
||||
|
||||
const formik = useFormik({
|
||||
enableReinitialize: true,
|
||||
initialValues: itemData,
|
||||
@@ -217,17 +213,23 @@ function AddNewItem() {
|
||||
}
|
||||
});
|
||||
|
||||
const primaryFamily = useSelector(WidgetSelectors.getWidgetFamiliesByInventoryId(inventoryId));
|
||||
const secondaryFamily = useSelector(
|
||||
WidgetSelectors.getWidgetsByParentId(formik.values.primaryWidgetFamilyId)
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<DashboardLayout>
|
||||
<DashboardNavbar />
|
||||
<Breadcrumbs
|
||||
title={`${widgetName} Details`}
|
||||
route={[
|
||||
{ name: 'Home', path: '/home' },
|
||||
{ name: 'Setup', path: '/setup' },
|
||||
{ name: 'Inventory', path: '/setup/inventory' },
|
||||
{ name: `${widgetName || 'Item'}` },
|
||||
{ name: `Add New ${widgetName || 'Item'}` }
|
||||
{ name: `${inventoryName || 'Inventory'}` },
|
||||
{ name: `${itemId ? 'Edit' : 'Add'} ${widgetName || 'Item'}` }
|
||||
]}
|
||||
/>
|
||||
<Box mx={3} my={3}>
|
||||
@@ -246,7 +248,12 @@ function AddNewItem() {
|
||||
variant="outlined"
|
||||
value={formik.values.commonName}
|
||||
error={formik.touched.commonName && Boolean(formik.errors.commonName)}
|
||||
helperText={formik.touched.commonName && formik.errors.commonName}
|
||||
helperText={
|
||||
formik.touched.commonName &&
|
||||
formik.errors.commonName && (
|
||||
<div style={{ color: 'red' }}>{formik.errors.commonName}</div>
|
||||
)
|
||||
}
|
||||
onChange={formik.handleChange}
|
||||
/>
|
||||
</Box>
|
||||
@@ -341,7 +348,12 @@ function AddNewItem() {
|
||||
variant="outlined"
|
||||
value={formik.values.formalName}
|
||||
error={formik.touched.formalName && Boolean(formik.errors.formalName)}
|
||||
helperText={formik.touched.formalName && formik.errors.formalName}
|
||||
helperText={
|
||||
formik.touched.formalName &&
|
||||
formik.errors.formalName && (
|
||||
<div style={{ color: 'red' }}>{formik.errors.formalName}</div>
|
||||
)
|
||||
}
|
||||
onChange={formik.handleChange}
|
||||
/>
|
||||
</Box>
|
||||
@@ -440,10 +452,7 @@ function AddNewItem() {
|
||||
formik.touched.primaryWidgetFamilyId &&
|
||||
Boolean(formik.errors.primaryWidgetFamilyId)
|
||||
}
|
||||
onChange={(e, ...rest) => {
|
||||
setPFam(e.target.value);
|
||||
formik.handleChange(e, ...rest);
|
||||
}}
|
||||
onChange={formik.handleChange}
|
||||
>
|
||||
<MenuItem key={'none'} value={''}>
|
||||
None Selected
|
||||
@@ -497,7 +506,7 @@ function AddNewItem() {
|
||||
{itemId ? (
|
||||
<ImageUploadMultiple
|
||||
multiple
|
||||
heading="Upload Product Image"
|
||||
heading={`Upload ${widgetName} Image`}
|
||||
accept="image/*"
|
||||
images={formik.values.images}
|
||||
setImages={(images) => {
|
||||
@@ -507,7 +516,7 @@ function AddNewItem() {
|
||||
) : (
|
||||
<ImageUploadMultiple
|
||||
multiple
|
||||
heading="Upload Product Image"
|
||||
heading={`Upload ${widgetName} Image`}
|
||||
accept="image/*"
|
||||
images={formik.values.images}
|
||||
setImages={(images) => {
|
||||
@@ -516,7 +525,7 @@ function AddNewItem() {
|
||||
/>
|
||||
)}
|
||||
</Box>
|
||||
<Box
|
||||
{/* <Box
|
||||
sx={{
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
@@ -539,7 +548,7 @@ function AddNewItem() {
|
||||
<MDButton disabled size="large" color="primary" variant="outlined">
|
||||
import
|
||||
</MDButton>
|
||||
</Box>
|
||||
</Box> */}
|
||||
<Box
|
||||
component="div"
|
||||
sx={{
|
||||
@@ -614,11 +623,18 @@ function AddNewItem() {
|
||||
marginBottom: '30px'
|
||||
}}
|
||||
>
|
||||
<MDButton size="medium" color="error" variant="outlined">
|
||||
<MDButton
|
||||
size="medium"
|
||||
color="error"
|
||||
variant="outlined"
|
||||
onClick={() => {
|
||||
navigate('/setup/inventory');
|
||||
}}
|
||||
>
|
||||
Cancel
|
||||
</MDButton>
|
||||
<MDButton size="medium" color="primary" variant="contained" type="submit">
|
||||
Add {widgetName}
|
||||
Save
|
||||
</MDButton>
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
@@ -18,7 +18,7 @@ import AuthActions from 'redux/AuthRedux';
|
||||
import { API } from 'constant';
|
||||
|
||||
// Image
|
||||
import bgImage from 'assets/images/illustrations/illustration-reset.jpg';
|
||||
import bgImage from 'assets/images/roofing-company-houston.jpg';
|
||||
import { useFormik } from 'formik';
|
||||
|
||||
import schema from 'services/ValidationServices';
|
||||
@@ -35,8 +35,7 @@ function LoginScreen() {
|
||||
rememberMe: true
|
||||
},
|
||||
validationSchema: schema.login,
|
||||
onSubmit: (values, { resetForm, setSubmitting }) =>
|
||||
{
|
||||
onSubmit: (values, { resetForm, setSubmitting }) => {
|
||||
const onFailedLogin = (errorMessage) => {
|
||||
resetForm();
|
||||
setSubmitting(false);
|
||||
|
||||
@@ -14,7 +14,7 @@ import WarehouseActions, { WarehouseSelectors } from 'redux/WarehouseRedux';
|
||||
import InventoryActions, { InventorySelectors } from 'redux/InventoryRedux';
|
||||
import RolesActions, { RolesSelectors } from 'redux/RolesRedux';
|
||||
import PermissionsActions, { PermissionsSelectors } from 'redux/PermissionsRedux';
|
||||
import { AuthSelectors } from 'redux/AuthRedux';
|
||||
// import { AuthSelectors } from 'redux/AuthRedux';
|
||||
import UsersActions from 'redux/UsersRedux';
|
||||
|
||||
import schema from 'services/ValidationServices';
|
||||
@@ -29,8 +29,9 @@ import DateTimeInput from 'components/DateTimePicker';
|
||||
import MDInput from 'components/MDInput';
|
||||
|
||||
import { API } from 'constant';
|
||||
import UserIcon from 'assets/images/userIcon.png';
|
||||
import BlankImage from 'assets/images/blank-profile-picture.webp';
|
||||
import EditIcon from 'assets/images/edit-icon.png';
|
||||
import Breadcrumbs from 'components/Breadcrumbs';
|
||||
|
||||
const useStyles = makeStyles(() => ({
|
||||
labelSize: {
|
||||
@@ -72,11 +73,14 @@ function CreateEditUser(props) {
|
||||
const warehouses = useSelector(WarehouseSelectors.getWarehouseDetail);
|
||||
const inventories = useSelector(InventorySelectors.getInventoryDetail);
|
||||
const actions = useSelector(PermissionsSelectors.getActionsDetail);
|
||||
const permissions = useSelector(PermissionsSelectors.getPermissionsDetail);
|
||||
const currentUser = useSelector(AuthSelectors.getUser);
|
||||
const visibilities = useSelector(PermissionsSelectors.getPermissionsDetail);
|
||||
// const currentUser = useSelector(AuthSelectors.getUser);
|
||||
const location = useLocation();
|
||||
const [editedUser, setEditedUser] = useState(location?.state?.user);
|
||||
const [selectedRoles, setSelectedRoles] = useState([]);
|
||||
const [uploadedImg, setUploadedImg] = useState();
|
||||
const [loader, setLoader] = useState();
|
||||
// const [selectedPermissions, setSelectedPermissions] = useState({});
|
||||
|
||||
useEffect(() => {
|
||||
if (context === 'edit') {
|
||||
@@ -86,16 +90,52 @@ function CreateEditUser(props) {
|
||||
} else {
|
||||
setEditedUser(editedUser);
|
||||
setSelectedRoles(editedUser.roles);
|
||||
editedUser.image_url && setUploadedImg(editedUser.image_url);
|
||||
}
|
||||
}
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
(!warehouses || warehouses.length === 0) && dispatch(WarehouseActions.warehouseDataAction({loader: 'loading-request', slug: API.GET_WAREHOUSE_DATA,method: 'get'}));
|
||||
(!inventories || inventories.length === 0) && dispatch(InventoryActions.getInventoryAction({loader: 'loading-request', slug: API.GET_INVENTORY,method: 'get'}));
|
||||
(!roles || roles.length === 0) && dispatch(RolesActions.getRolesAction({loader: 'loading-request', slug: API.GET_ROLES_DATA, method: 'get'}));
|
||||
(!permissions || permissions.length === 0) && dispatch(PermissionsActions.getPermissionsAction({loader: 'loading-request', slug: API.GET_PERMISSIONS_DATA, method: 'get'}));
|
||||
(!actions || actions.length === 0) && dispatch(PermissionsActions.getActionsAction({loader: 'loading-request', slug: API.GET_ACTIONS_DATA, method: 'get'}));
|
||||
(!warehouses || warehouses.length === 0) &&
|
||||
dispatch(
|
||||
WarehouseActions.warehouseDataAction({
|
||||
loader: 'loading-request',
|
||||
slug: API.GET_WAREHOUSE_DATA,
|
||||
method: 'get'
|
||||
})
|
||||
);
|
||||
(!inventories || inventories.length === 0) &&
|
||||
dispatch(
|
||||
InventoryActions.getInventoryAction({
|
||||
loader: 'loading-request',
|
||||
slug: API.GET_INVENTORY,
|
||||
method: 'get'
|
||||
})
|
||||
);
|
||||
(!roles || roles.length === 0) &&
|
||||
dispatch(
|
||||
RolesActions.getRolesAction({
|
||||
loader: 'loading-request',
|
||||
slug: API.GET_ROLES_DATA,
|
||||
method: 'get'
|
||||
})
|
||||
);
|
||||
(!visibilities || visibilities.length === 0) &&
|
||||
dispatch(
|
||||
PermissionsActions.getPermissionsAction({
|
||||
loader: 'loading-request',
|
||||
slug: API.GET_PERMISSIONS_DATA,
|
||||
method: 'get'
|
||||
})
|
||||
);
|
||||
(!actions || actions.length === 0) &&
|
||||
dispatch(
|
||||
PermissionsActions.getActionsAction({
|
||||
loader: 'loading-request',
|
||||
slug: API.GET_ACTIONS_DATA,
|
||||
method: 'get'
|
||||
})
|
||||
);
|
||||
}, []);
|
||||
|
||||
const formik = useFormik({
|
||||
@@ -110,10 +150,11 @@ function CreateEditUser(props) {
|
||||
actions: '',
|
||||
visibilities: '',
|
||||
isActive: true,
|
||||
createdBy: currentUser ? currentUser.fullName : '',
|
||||
createdAt: new Date(),
|
||||
updatedBy: currentUser ? currentUser.fullName : '',
|
||||
updatedAt: new Date()
|
||||
image: '',
|
||||
createdBy: '',
|
||||
createdAt: '',
|
||||
updatedBy: '',
|
||||
updatedAt: ''
|
||||
} : {
|
||||
fullName: editedUser ? editedUser.fullName : '',
|
||||
phoneNumber: editedUser ? editedUser.phoneNumber : '',
|
||||
@@ -125,108 +166,207 @@ function CreateEditUser(props) {
|
||||
actions: editedUser?.permissions?.actions ? editedUser.permissions.actions.join(',') : '',
|
||||
visibilities: editedUser?.permissions?.allowedUIModules ? editedUser.permissions.allowedUIModules.join(',') : '',
|
||||
isActive: editedUser && editedUser.isActive !== undefined ? editedUser.isActive : true,
|
||||
image: editedUser ? editedUser.image_url : EditIcon,
|
||||
createdBy: editedUser ? editedUser.createdBy?.fullName : '',
|
||||
createdAt: editedUser ? editedUser.createdAt : '',
|
||||
updatedBy: editedUser ? editedUser.updatedBy?.fullName : '',
|
||||
updatedAt: editedUser ? editedUser.updatedAt : ''
|
||||
},
|
||||
validationSchema: schema.createUser,
|
||||
onSubmit: (values, { setSubmitting }) =>
|
||||
{
|
||||
onSubmit: (values, { setSubmitting }) => {
|
||||
const onValidationFailed = () => {
|
||||
setLoader(false);
|
||||
setSubmitting(false);
|
||||
};
|
||||
const onSuccessfulSubmission = () => {
|
||||
setLoader(false);
|
||||
navigate('/setup/users-access');
|
||||
};
|
||||
const adaptPayload = values => {
|
||||
const valuesClone = {...values};
|
||||
const adaptPayload = (values) => {
|
||||
const valuesClone = { ...values };
|
||||
valuesClone.permissions = {};
|
||||
valuesClone.permissions.inventoryScopes = values.inventories ? values.inventories.split(',').map(inv => ({id: inv, type: 'Inventory'})) : [];
|
||||
valuesClone.permissions.warehouseScopes = values.warehouses ? values.warehouses.split(',').map(wh => ({id: wh, type: 'Warehouse'})) : [];
|
||||
valuesClone.permissions.inventoryScopes = values.inventories
|
||||
? values.inventories.split(',').map((inv) => ({ id: inv, type: 'Inventory' }))
|
||||
: [];
|
||||
valuesClone.permissions.warehouseScopes = values.warehouses
|
||||
? values.warehouses.split(',').map((wh) => ({ id: wh, type: 'Warehouse' }))
|
||||
: [];
|
||||
valuesClone.permissions.actions = values.actions ? values.actions.split(',') : [];
|
||||
valuesClone.permissions.allowedUIModules = values.visibilities ? values.visibilities.split(',') : [];
|
||||
valuesClone.permissions.allowedUIModules = values.visibilities
|
||||
? values.visibilities.split(',')
|
||||
: [];
|
||||
delete valuesClone.inventories;
|
||||
delete valuesClone.warehouses;
|
||||
delete valuesClone.actions;
|
||||
delete valuesClone.visibilities;
|
||||
return valuesClone;
|
||||
valuesClone.permissions = JSON.stringify(valuesClone.permissions);
|
||||
valuesClone.roles = selectedRoles && selectedRoles.length > 0 ? selectedRoles.map(role => role._id) : [];
|
||||
const formData = new FormData();
|
||||
Object.keys(valuesClone).forEach(key => formData.append(key, valuesClone[key]));
|
||||
uploadedImg && formData.append('image', uploadedImg);
|
||||
setLoader(true);
|
||||
return formData;
|
||||
};
|
||||
values.roles = selectedRoles && selectedRoles.length > 0 ? selectedRoles.map(role => role._id) : [];
|
||||
dispatch(
|
||||
UsersActions.createUserAction({
|
||||
loader: 'loading-request',
|
||||
slug: context === 'edit' ? API.UPDATE_USER.replace(':id', editedUser._id): API.CREATE_USER,
|
||||
slug:
|
||||
context === 'edit' ? API.UPDATE_USER.replace(':id', editedUser._id) : API.CREATE_USER,
|
||||
method: 'post',
|
||||
contentType: false,
|
||||
processData: false,
|
||||
data: adaptPayload(values),
|
||||
onValidationFailed,
|
||||
onSuccessfulSubmission,
|
||||
toastMessage: context === 'edit' ? 'Updated user __placeholder__successfully' : 'Added user __placeholder__successfully'
|
||||
toastMessage:
|
||||
context === 'edit'
|
||||
? 'Updated user __placeholder__successfully'
|
||||
: 'Added user __placeholder__successfully'
|
||||
})
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
const handleMultiSelectChange = e => {
|
||||
const handleMultiSelectChange = (e) => {
|
||||
const uniqueRoles = [];
|
||||
e.target.value.forEach(role => {
|
||||
const roleIndex = uniqueRoles.findIndex(uRole => uRole._id === role._id);
|
||||
e.target.value.forEach((role) => {
|
||||
const roleIndex = uniqueRoles.findIndex((uRole) => uRole._id === role._id);
|
||||
if (roleIndex > -1) {
|
||||
uniqueRoles.splice(roleIndex, 1);
|
||||
} else {
|
||||
uniqueRoles.push(role);
|
||||
}
|
||||
});
|
||||
formik.handleChange('roles')(uniqueRoles.map(role => role.name).join());
|
||||
formik.handleChange('roles')(uniqueRoles.map((role) => role.name).join());
|
||||
aggregatePermissions(uniqueRoles);
|
||||
setSelectedRoles(uniqueRoles);
|
||||
};
|
||||
|
||||
const aggregatePermissions = roles => {
|
||||
const actions = [], visibilities = [], warehouses = [], inventories = [];
|
||||
roles.forEach(role => {
|
||||
if (role.permissions) {
|
||||
const currActions = role.permissions.actions;
|
||||
const currVisibilities = role.permissions.allowedUIModules;
|
||||
const currWarehouseScopes = role.permissions.warehouseScopes;
|
||||
const currInventoryScopes = role.permissions.inventoryScopes;
|
||||
currActions.forEach(ac => actions.indexOf(ac) === -1 && actions.push(ac));
|
||||
currVisibilities.forEach(vi => visibilities.indexOf(vi) === -1 && visibilities.push(vi));
|
||||
currWarehouseScopes.forEach(currWh => warehouses.findIndex(wh => wh.id === currWh.id) === -1 && warehouses.push(currWh));
|
||||
currInventoryScopes.forEach(currInv => inventories.findIndex(inv => inv.id === currInv.id) === -1 && inventories.push(currInv));
|
||||
// setSelectedPermissions({...selectedPermissions, actions});
|
||||
}
|
||||
});
|
||||
formik.handleChange('actions')(actions.join(','));
|
||||
formik.handleChange('visibilities')(visibilities.join(','));
|
||||
formik.handleChange('warehouses')(warehouses.map(wh => wh.id).join(','));
|
||||
formik.handleChange('inventories')(inventories.map(inv => inv.id).join(','));
|
||||
};
|
||||
|
||||
const handleFileChange = e => {
|
||||
const [file] = e.target.files;
|
||||
if (file) {
|
||||
setUploadedImg(file);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<DashboardLayout className={classes.createEditUserGlobal}>
|
||||
<DashboardNavbar />
|
||||
<MDBox component='form' role='form' px={2} sx={{ backgroundColor: '#fff' }} onSubmit={formik.handleSubmit}>
|
||||
<MDBox mx={4} sx={{ border: '1px solid #C4C4C4', borderRadius: '4px', padding: '30px' }}>
|
||||
<Breadcrumbs
|
||||
title="User Details"
|
||||
route={[
|
||||
{ name: 'Home', path: '/home' },
|
||||
{ name: 'Setup', path: '/setup' },
|
||||
{ name: 'User Access', path: '/setup/users-access' },
|
||||
{ name: 'User Details' }
|
||||
]}
|
||||
/>
|
||||
<MDBox component="form" role="form" px={2} className={loader ? " loader" : ""} onSubmit={formik.handleSubmit}>
|
||||
<MDBox
|
||||
mx={4}
|
||||
sx={{
|
||||
border: '1px solid #C4C4C4',
|
||||
borderRadius: '4px',
|
||||
padding: '30px',
|
||||
backgroundColor: '#fff'
|
||||
}}
|
||||
>
|
||||
<MDBox sx={{ width: '50%', margin: 'auto' }}>
|
||||
<MDBox sx={{ width: '120px', margin: 'auto', position: 'relative' }}>
|
||||
<img src={UserIcon} alt='img' />
|
||||
<MDBox sx={{ position: 'absolute', bottom: '0', right: '0', cursor: 'pointer' }}>
|
||||
<img src={EditIcon} alt='img' />
|
||||
<img src={uploadedImg ? typeof uploadedImg === 'string' ? uploadedImg : URL.createObjectURL(uploadedImg) : BlankImage}
|
||||
alt='img' width='120' height='120' style={{borderRadius: '50%'}} onError={() => setUploadedImg(BlankImage)} />
|
||||
<MDBox sx={{ position: 'absolute', bottom: '0', right: '0' }}>
|
||||
<label htmlFor="image" style={{ cursor: 'pointer' }}>
|
||||
<img src={EditIcon} />
|
||||
</label>
|
||||
<input id='image' name='image' type="file" className='d-none' accept="image/png, image/gif, image/jpeg"
|
||||
onChange={handleFileChange} />
|
||||
</MDBox>
|
||||
</MDBox>
|
||||
<MDBox sx={{ marginBottom: '24px' }}>
|
||||
<Box component='div' sx={{}} className={classes.labelSize}>
|
||||
<Box component="div" sx={{}} className={classes.labelSize}>
|
||||
User Name
|
||||
</Box>
|
||||
<MDInput fullWidth value={formik.values.fullName} name='fullName' type='text'
|
||||
variant='outlined' error={formik.touched.fullName && Boolean(formik.errors.fullName)}
|
||||
helperText={formik.touched.fullName && formik.errors.fullName} onChange={formik.handleChange} />
|
||||
<MDInput
|
||||
fullWidth
|
||||
value={formik.values.fullName}
|
||||
name="fullName"
|
||||
type="text"
|
||||
variant="outlined"
|
||||
error={formik.touched.fullName && Boolean(formik.errors.fullName)}
|
||||
helperText={formik.touched.fullName && formik.errors.fullName}
|
||||
onChange={formik.handleChange}
|
||||
/>
|
||||
</MDBox>
|
||||
<MDBox sx={{ marginBottom: '24px' }}>
|
||||
<Box component='div' sx={{}} className={classes.labelSize}>
|
||||
<Box component="div" sx={{}} className={classes.labelSize}>
|
||||
Email
|
||||
</Box>
|
||||
<MDInput fullWidth disabled={context === 'edit'} value={formik.values.email} name='email' type='email'
|
||||
variant='outlined' error={formik.touched.email && Boolean(formik.errors.email)}
|
||||
helperText={formik.touched.email && formik.errors.email} onChange={formik.handleChange} />
|
||||
<MDInput
|
||||
fullWidth
|
||||
disabled={context === 'edit'}
|
||||
value={formik.values.email}
|
||||
name="email"
|
||||
type="email"
|
||||
variant="outlined"
|
||||
error={formik.touched.email && Boolean(formik.errors.email)}
|
||||
helperText={formik.touched.email && formik.errors.email}
|
||||
onChange={formik.handleChange}
|
||||
/>
|
||||
</MDBox>
|
||||
<MDBox sx={{ marginBottom: '24px' }}>
|
||||
<Box component='div' sx={{}} className={classes.labelSize}>
|
||||
<Box component="div" sx={{}} className={classes.labelSize}>
|
||||
Password
|
||||
</Box>
|
||||
<MDInput fullWidth value={formik.values.password} name='password' type='password'
|
||||
variant='outlined' error={formik.touched.password && Boolean(formik.errors.password)}
|
||||
helperText={formik.touched.password && formik.errors.password} onChange={formik.handleChange} />
|
||||
<MDInput
|
||||
fullWidth
|
||||
value={formik.values.password}
|
||||
name="password"
|
||||
type="password"
|
||||
variant="outlined"
|
||||
error={formik.touched.password && Boolean(formik.errors.password)}
|
||||
helperText={formik.touched.password && formik.errors.password}
|
||||
onChange={formik.handleChange}
|
||||
/>
|
||||
</MDBox>
|
||||
<MDBox sx={{ marginBottom: '24px' }}>
|
||||
<Box component='div' sx={{}} className={classes.labelSize}>
|
||||
<Box component="div" sx={{}} className={classes.labelSize}>
|
||||
Phone Number
|
||||
</Box>
|
||||
<MDInput fullWidth value={formik.values.phoneNumber} name='phoneNumber' type='text'
|
||||
variant='outlined' error={formik.touched.phoneNumber && Boolean(formik.errors.phoneNumber)}
|
||||
helperText={formik.touched.phoneNumber && formik.errors.phoneNumber} onChange={formik.handleChange} />
|
||||
<MDInput
|
||||
fullWidth
|
||||
value={formik.values.phoneNumber}
|
||||
name="phoneNumber"
|
||||
type="text"
|
||||
variant="outlined"
|
||||
error={formik.touched.phoneNumber && Boolean(formik.errors.phoneNumber)}
|
||||
helperText={formik.touched.phoneNumber && formik.errors.phoneNumber}
|
||||
onChange={formik.handleChange}
|
||||
/>
|
||||
</MDBox>
|
||||
<MDBox sx={{ marginBottom: '24px' }}>
|
||||
<Box component='div' sx={{}} className={classes.labelSize}>
|
||||
<Box component="div" sx={{}} className={classes.labelSize}>
|
||||
Role
|
||||
</Box>
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', columnGap: '20px' }}>
|
||||
@@ -234,16 +374,25 @@ function CreateEditUser(props) {
|
||||
<Select
|
||||
multiple
|
||||
displayEmpty
|
||||
name='roles'
|
||||
name="roles"
|
||||
value={selectedRoles}
|
||||
input={<OutlinedInput />}
|
||||
error={formik.touched.roles && Boolean(formik.errors.roles)}
|
||||
renderValue={() => selectedRoles?.length === 0 ? 'Please select a role' : selectedRoles?.map(role => role.name).join(', ')}
|
||||
renderValue={() =>
|
||||
selectedRoles?.length === 0
|
||||
? 'Please select a role'
|
||||
: selectedRoles?.map((role) => role.name).join(', ')
|
||||
}
|
||||
inputProps={{ 'aria-label': 'Without label' }}
|
||||
sx={{width: '100%'}}
|
||||
sx={{ width: '100%' }}
|
||||
onChange={handleMultiSelectChange}
|
||||
>
|
||||
{roles && roles.map((role, key) => <MenuItem key={key} value={role}>{role.name}</MenuItem>)}
|
||||
{roles &&
|
||||
roles.map((role, key) => (
|
||||
<MenuItem key={key} value={role}>
|
||||
{role.name}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
</Box>
|
||||
<Box
|
||||
@@ -258,7 +407,7 @@ function CreateEditUser(props) {
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
component='div'
|
||||
component="div"
|
||||
sx={{
|
||||
fontSize: '16px',
|
||||
lineHeight: '20px',
|
||||
@@ -278,7 +427,11 @@ function CreateEditUser(props) {
|
||||
left: '20px'
|
||||
}}
|
||||
>
|
||||
<Switch name='isActive' checked={formik.values.isActive} onChange={formik.handleChange} />
|
||||
<Switch
|
||||
name="isActive"
|
||||
checked={formik.values.isActive}
|
||||
onChange={formik.handleChange}
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
</Box>
|
||||
@@ -287,28 +440,42 @@ function CreateEditUser(props) {
|
||||
<Grid item xs={12}>
|
||||
<Grid container spacing={2} className={classes.margin}>
|
||||
<Grid item xs={6}>
|
||||
<Box component='div' className={classes.labelSize}>
|
||||
<Box component="div" className={classes.labelSize}>
|
||||
Created By
|
||||
</Box>
|
||||
<MDInput fullWidth disabled name='createdBy' type='text' value={formik.values.createdBy} variant='outlined' />
|
||||
<MDInput
|
||||
fullWidth
|
||||
disabled
|
||||
name="createdBy"
|
||||
type="text"
|
||||
value={formik.values.createdBy}
|
||||
variant="outlined"
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
<Box component='div' className={classes.labelSize}>
|
||||
<Box component="div" className={classes.labelSize}>
|
||||
Date & Time
|
||||
</Box>
|
||||
<DateTimeInput disabled name='createdAt' value={formik.values.createdAt} />
|
||||
<DateTimeInput disabled name='createdAt' value={new Date(formik.values.createdAt)} />
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
<Box component='div' className={classes.labelSize}>
|
||||
<Box component="div" className={classes.labelSize}>
|
||||
Last Updated by
|
||||
</Box>
|
||||
<MDInput fullWidth disabled name='updatedBy' type='text' value={formik.values.updatedBy} variant='outlined' />
|
||||
<MDInput
|
||||
fullWidth
|
||||
disabled
|
||||
name="updatedBy"
|
||||
type="text"
|
||||
value={formik.values.updatedBy}
|
||||
variant="outlined"
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
<Box component='div' className={classes.labelSize}>
|
||||
<Box component="div" className={classes.labelSize}>
|
||||
Date & Time
|
||||
</Box>
|
||||
<DateTimeInput disabled name='updatedAt' value={formik.values.updatedAt} />
|
||||
<DateTimeInput disabled name='updatedAt' value={new Date(formik.values.updatedAt)} />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
@@ -316,33 +483,81 @@ function CreateEditUser(props) {
|
||||
</MDBox>
|
||||
</MDBox>
|
||||
<Grid container spacing={4} sx={{ marginTop: '-6px' }}>
|
||||
<AllocationManager name='warehouses' gridStyleOverride={{ paddingLeft: '4rem !important' }} initlist={formik.values.warehouses}
|
||||
list={warehouses} matchProp={{a: '_id'}} title='Warehouse' onChange={val => formik.handleChange('warehouses')(val)} />
|
||||
<AllocationManager name='inventories' gridStyleOverride={{ paddingRight: '2rem' }} initlist={formik.values.inventories}
|
||||
list={inventories} matchProp={{a: '_id'}} title='Inventory' onChange={val => formik.handleChange('inventories')(val)} />
|
||||
<AllocationManager
|
||||
allDisabled={selectedRoles?.length > 0}
|
||||
name="warehouses"
|
||||
gridStyleOverride={{ paddingLeft: '4rem !important' }}
|
||||
allocatedList={formik.values.warehouses}
|
||||
list={warehouses}
|
||||
matchProp={{ a: '_id' }}
|
||||
title="Warehouse"
|
||||
onChange={val => {
|
||||
val = val?.map(obj => obj._id).join(',');
|
||||
// setSelectedPermissions({...selectedPermissions, warehouses: val});
|
||||
formik.handleChange('warehouses')(val);
|
||||
}}
|
||||
/>
|
||||
<AllocationManager
|
||||
allDisabled={selectedRoles?.length > 0}
|
||||
name="inventories"
|
||||
gridStyleOverride={{ paddingRight: '2rem' }}
|
||||
allocatedList={formik.values.inventories}
|
||||
list={inventories}
|
||||
matchProp={{ a: '_id' }}
|
||||
title="Inventory"
|
||||
onChange={val => {
|
||||
val = val?.map(obj => obj._id).join(',');
|
||||
// setSelectedPermissions({...selectedPermissions, inventories: val});
|
||||
formik.handleChange('inventories')(val);
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid container spacing={2} sx={{ marginTop: '12px', paddingLeft: '2rem' }}>
|
||||
<Toggles name='actions' title='Actions' toggles={actions} inittoggles={formik.values.actions} onChange={val => formik.handleChange('actions')(val)} />
|
||||
<Toggles name='visibilities' title='Application' toggles={permissions} inittoggles={formik.values.visibilities} onChange={val => formik.handleChange('visibilities')(val)} />
|
||||
<Grid container spacing={4} sx={{ marginTop: '12px'}}>
|
||||
<Toggles
|
||||
allDisabled={selectedRoles?.length > 0}
|
||||
name="actions"
|
||||
gridStyleOverride={{ paddingLeft: '4rem !important' }}
|
||||
title="Actions"
|
||||
toggles={actions}
|
||||
selectedToggles={formik.values.actions}
|
||||
onChange={val => {
|
||||
val = Object.keys(val).join(',');
|
||||
// setSelectedPermissions({...selectedPermissions, actions: val});
|
||||
formik.handleChange('actions')(val);
|
||||
}}
|
||||
/>
|
||||
<Toggles
|
||||
allDisabled={selectedRoles?.length > 0}
|
||||
name="visibilities"
|
||||
gridStyleOverride={{ paddingRight: '2rem' }}
|
||||
title="Application"
|
||||
toggles={visibilities}
|
||||
selectedToggles={formik.values.visibilities}
|
||||
onChange={val => {
|
||||
val = Object.keys(val).join(',');
|
||||
// setSelectedPermissions({...selectedPermissions, visibilities: val});
|
||||
formik.handleChange('visibilities')(val);
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
<MDBox
|
||||
display='flex'
|
||||
justifyContent='center'
|
||||
alignItems='center'
|
||||
display="flex"
|
||||
justifyContent="center"
|
||||
alignItems="center"
|
||||
lineHeight={1}
|
||||
sx={{ marginBottom: '15px', marginTop: '45px', paddingBottom: '30px' }}
|
||||
>
|
||||
<MDButton
|
||||
size='medium'
|
||||
color='error'
|
||||
variant='outlined'
|
||||
type='button'
|
||||
size="medium"
|
||||
color="error"
|
||||
variant="outlined"
|
||||
type="button"
|
||||
sx={{ marginRight: '15px' }}
|
||||
onClick={() => navigate('/setup/users-access')}
|
||||
>
|
||||
Cancel
|
||||
</MDButton>
|
||||
<MDButton size='medium' color='primary' variant='contained' type='submit'>
|
||||
<MDButton size="medium" color="primary" variant="contained" type="submit">
|
||||
{context === 'new' ? 'Create' : 'Save'}
|
||||
</MDButton>
|
||||
</MDBox>
|
||||
|
||||
218
src/pages/createEditUserRole/index.js
Normal file
218
src/pages/createEditUserRole/index.js
Normal file
@@ -0,0 +1,218 @@
|
||||
import React from 'react';
|
||||
import MDBox from 'components/MDBox';
|
||||
import DashboardNavbar from 'components/DashboardNavbar';
|
||||
import Footer from 'components/Footer';
|
||||
import DashboardLayout from 'layouts/DashboardLayout';
|
||||
import { makeStyles } from '@mui/styles';
|
||||
import { Box, Grid } from '@mui/material';
|
||||
import MDButton from 'components/Button';
|
||||
import TransferList from 'components/MDTransferList';
|
||||
import DateTimeInput from 'components/DateTimePicker';
|
||||
import Switch from 'components/Switch';
|
||||
import MDTypography from 'components/MDTypography';
|
||||
import MDInput from 'components/MDInput';
|
||||
import TextareaAutosize from '@mui/material/TextareaAutosize';
|
||||
import Typography from '@mui/material/Typography';
|
||||
|
||||
const useStyles = makeStyles(() => ({
|
||||
labelSize: {
|
||||
fontSize: '16px',
|
||||
letterSpacing: '0.01em',
|
||||
color: '#000',
|
||||
marginBottom: '4px'
|
||||
},
|
||||
boxWrap: {
|
||||
backgroundColor: '#fff',
|
||||
border: '1px solid #c2c2c2',
|
||||
borderTop: '3px solid #007aff',
|
||||
display: 'inline-block',
|
||||
padding: '12px',
|
||||
borderRadius: '4px'
|
||||
},
|
||||
noLegend: {
|
||||
display: 'none'
|
||||
},
|
||||
fullWidth: {
|
||||
width: '100%',
|
||||
borderColor: '#d2d6da',
|
||||
borderRadius: '0.375rem'
|
||||
},
|
||||
switchSpacer: {
|
||||
margin: '0',
|
||||
'& .MuiFormControlLabel-root': {
|
||||
margin: '0'
|
||||
},
|
||||
'& .MuiSwitch-root': {
|
||||
margin: '0'
|
||||
}
|
||||
}
|
||||
}));
|
||||
function CreateEditUserRole() {
|
||||
const classes = useStyles();
|
||||
return (
|
||||
<DashboardLayout>
|
||||
<DashboardNavbar />
|
||||
<MDBox px={2} py={3}>
|
||||
<Grid container spacing={2} className={classes.margin}>
|
||||
<Grid item xs={8} md={8}>
|
||||
<Grid container spacing={2} className={classes.margin}>
|
||||
<Grid item xs={12}>
|
||||
<Box component="div" sx={{}} className={classes.labelSize}>
|
||||
Warehouse name
|
||||
</Box>
|
||||
<MDInput fullWidth name="warehousename" type="text" variant="outlined" />
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<Box component="div" className={classes.labelSize}>
|
||||
Description
|
||||
</Box>
|
||||
<TextareaAutosize className={classes.fullWidth} minRows={5} />
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<Grid container spacing={2} className={classes.margin}>
|
||||
<Grid item xs={6}>
|
||||
<Box component="div" className={classes.labelSize}>
|
||||
Created By
|
||||
</Box>
|
||||
<MDInput fullWidth name="warehousename" type="text" variant="outlined" />
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
<Box component="div" className={classes.labelSize}>
|
||||
Date & Time
|
||||
</Box>
|
||||
<DateTimeInput />
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
<Box component="div" className={classes.labelSize}>
|
||||
Last Updated by
|
||||
</Box>
|
||||
<MDInput fullWidth name="warehousename" type="text" variant="outlined" />
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
<Box component="div" className={classes.labelSize}>
|
||||
Date & Time
|
||||
</Box>
|
||||
<DateTimeInput />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Grid item xs={4}>
|
||||
<Box component="div" className={classes.labelSize}>
|
||||
Choose avatar component here
|
||||
</Box>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Grid container spacing={4} sx={{ marginTop: '-6px' }}>
|
||||
<Grid item xs={12} md={4}>
|
||||
<MDBox
|
||||
sx={{
|
||||
backgroundColor: '#fff',
|
||||
border: '1px solid #c2c2c2',
|
||||
borderTop: '7px solid #007aff',
|
||||
padding: '12px',
|
||||
borderRadius: '4px'
|
||||
}}
|
||||
>
|
||||
<Typography gutterBottom variant="h6" component="div">
|
||||
Warehouse
|
||||
</Typography>
|
||||
<TransferList />
|
||||
</MDBox>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={4}>
|
||||
<MDBox
|
||||
sx={{
|
||||
backgroundColor: '#fff',
|
||||
border: '1px solid #c2c2c2',
|
||||
borderTop: '7px solid #007aff',
|
||||
padding: '12px',
|
||||
borderRadius: '4px'
|
||||
}}
|
||||
>
|
||||
<Typography gutterBottom variant="h6" component="div">
|
||||
Warehouse
|
||||
</Typography>
|
||||
<TransferList />
|
||||
</MDBox>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Grid container spacing={2} sx={{ marginTop: '12px' }}>
|
||||
<Grid item xs={12} md={3}>
|
||||
<MDBox
|
||||
sx={{
|
||||
backgroundColor: '#fff',
|
||||
border: '1px solid #c2c2c2',
|
||||
borderTop: '7px solid #007aff',
|
||||
padding: '12px',
|
||||
borderRadius: '4px'
|
||||
}}
|
||||
>
|
||||
<Typography gutterBottom variant="h6" component="div">
|
||||
Process
|
||||
</Typography>
|
||||
<MDBox
|
||||
display="flex"
|
||||
justifyContent="space-between"
|
||||
alignItems="center"
|
||||
lineHeight={1}
|
||||
className={classes.switchSpacer}
|
||||
>
|
||||
<MDTypography variant="body2">Sidenav Mini</MDTypography>
|
||||
<Switch checked />
|
||||
</MDBox>
|
||||
</MDBox>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={3}>
|
||||
<MDBox
|
||||
sx={{
|
||||
backgroundColor: '#fff',
|
||||
border: '1px solid #c2c2c2',
|
||||
borderTop: '7px solid #007aff',
|
||||
padding: '12px',
|
||||
borderRadius: '4px'
|
||||
}}
|
||||
>
|
||||
<Typography gutterBottom variant="h6" component="div">
|
||||
Application
|
||||
</Typography>
|
||||
<MDBox
|
||||
display="flex"
|
||||
justifyContent="space-between"
|
||||
alignItems="center"
|
||||
lineHeight={1}
|
||||
className={classes.switchSpacer}
|
||||
>
|
||||
<MDTypography variant="body2">Sidenav Mini</MDTypography>
|
||||
<Switch checked />
|
||||
</MDBox>
|
||||
</MDBox>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<MDBox
|
||||
display="flex"
|
||||
justifyContent="center"
|
||||
alignItems="center"
|
||||
lineHeight={1}
|
||||
sx={{ marginBottom: '15px', marginTop: '24px' }}
|
||||
>
|
||||
<MDButton
|
||||
size="medium"
|
||||
color="primary"
|
||||
variant="outlined"
|
||||
type="submit"
|
||||
sx={{ marginRight: '15px' }}
|
||||
>
|
||||
Cancel
|
||||
</MDButton>
|
||||
<MDButton size="medium" color="primary" variant="contained">
|
||||
Save
|
||||
</MDButton>
|
||||
</MDBox>
|
||||
</MDBox>
|
||||
<Footer />
|
||||
</DashboardLayout>
|
||||
);
|
||||
}
|
||||
export default CreateEditUserRole;
|
||||
@@ -1,365 +0,0 @@
|
||||
import React from 'react';
|
||||
import MDBox from 'components/MDBox';
|
||||
import DashboardNavbar from 'components/DashboardNavbar';
|
||||
import DashboardLayout from 'layouts/DashboardLayout';
|
||||
import { makeStyles } from '@mui/styles';
|
||||
import { Box, Grid } from '@mui/material';
|
||||
import MDButton from 'components/Button';
|
||||
import TransferList from 'components/MDTransferList';
|
||||
import DateTimeInput from 'components/DateTimePicker';
|
||||
import Switch from 'components/Switch';
|
||||
import MDTypography from 'components/MDTypography';
|
||||
import MDInput from 'components/MDInput';
|
||||
import Typography from '@mui/material/Typography';
|
||||
import UserIcon from 'assets/images/userIcon.png';
|
||||
import EditIcon from 'assets/images/edit-icon.png';
|
||||
import OutlinedInput from '@mui/material/OutlinedInput';
|
||||
import MenuItem from '@mui/material/MenuItem';
|
||||
import Select from '@mui/material/Select';
|
||||
|
||||
const useStyles = makeStyles(() => ({
|
||||
labelSize: {
|
||||
fontSize: '16px',
|
||||
letterSpacing: '0.01em',
|
||||
color: '#000',
|
||||
marginBottom: '4px'
|
||||
},
|
||||
boxWrap: {
|
||||
backgroundColor: '#fff',
|
||||
border: '1px solid #c2c2c2',
|
||||
borderTop: '3px solid #007aff',
|
||||
display: 'inline-block',
|
||||
padding: '12px',
|
||||
borderRadius: '4px'
|
||||
},
|
||||
noLegend: {
|
||||
display: 'none'
|
||||
},
|
||||
fullWidth: {
|
||||
width: '100%',
|
||||
borderColor: '#d2d6da',
|
||||
borderRadius: '0.375rem'
|
||||
},
|
||||
switchSpacer: {
|
||||
margin: '0',
|
||||
'& .MuiFormControlLabel-root': {
|
||||
margin: '0'
|
||||
},
|
||||
'& .MuiSwitch-root': {
|
||||
margin: '0'
|
||||
}
|
||||
}
|
||||
}));
|
||||
function CreateUserRole() {
|
||||
const classes = useStyles();
|
||||
const [personName, setPersonName] = React.useState([]);
|
||||
|
||||
const handleChange = (event) => {
|
||||
const {
|
||||
target: { value }
|
||||
} = event;
|
||||
setPersonName(
|
||||
// On autofill we get a stringified value.
|
||||
typeof value === 'string' ? value.split(',') : value
|
||||
);
|
||||
};
|
||||
return (
|
||||
<DashboardLayout>
|
||||
<DashboardNavbar />
|
||||
<MDBox px={2} sx={{ backgroundColor: '#fff' }}>
|
||||
<MDBox mx={2} sx={{ border: '1px solid #C4C4C4', borderRadius: '4px', padding: '30px' }}>
|
||||
<MDBox sx={{ width: '50%', margin: 'auto' }}>
|
||||
<MDBox sx={{ width: '120px', margin: 'auto', position: 'relative' }}>
|
||||
<img src={UserIcon} alt="img" />
|
||||
<MDBox sx={{ position: 'absolute', bottom: '0', right: '0', cursor: 'pointer' }}>
|
||||
<img src={EditIcon} alt="img" />
|
||||
</MDBox>
|
||||
</MDBox>
|
||||
<MDBox sx={{ marginBottom: '24px' }}>
|
||||
<Box component="div" sx={{}} className={classes.labelSize}>
|
||||
User Name
|
||||
</Box>
|
||||
<MDInput fullWidth name="warehousename" type="text" variant="outlined" />
|
||||
</MDBox>
|
||||
<MDBox sx={{ marginBottom: '24px' }}>
|
||||
<Box component="div" sx={{}} className={classes.labelSize}>
|
||||
Phone Number
|
||||
</Box>
|
||||
<MDInput fullWidth name="warehousename" type="text" variant="outlined" />
|
||||
</MDBox>
|
||||
<MDBox sx={{ marginBottom: '24px' }}>
|
||||
<Box component="div" sx={{}} className={classes.labelSize}>
|
||||
Role
|
||||
</Box>
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', columnGap: '20px' }}>
|
||||
<Box sx={{ width: '70%' }}>
|
||||
<Select
|
||||
multiple
|
||||
displayEmpty
|
||||
value={personName}
|
||||
input={<OutlinedInput />}
|
||||
renderValue={(selected) => {
|
||||
if (selected.length === 0) {
|
||||
return 'Placeholder';
|
||||
}
|
||||
|
||||
return selected.join(', ');
|
||||
}}
|
||||
inputProps={{ 'aria-label': 'Without label' }}
|
||||
sx={{
|
||||
width: '100%'
|
||||
}}
|
||||
onChange={handleChange}
|
||||
>
|
||||
<MenuItem disabled value="">
|
||||
Placeholder
|
||||
</MenuItem>
|
||||
<MenuItem>Lorem Ipsum</MenuItem>
|
||||
</Select>
|
||||
</Box>
|
||||
<Box
|
||||
sx={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
width: '30%',
|
||||
border: '1px solid #C4C4C4',
|
||||
borderRadius: '4px'
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
component="div"
|
||||
sx={{
|
||||
fontSize: '16px',
|
||||
lineHeight: '20px',
|
||||
letterSpacing: '0.01em',
|
||||
textTransform: 'capitalize',
|
||||
color: '#000',
|
||||
marginLeft: '10px'
|
||||
}}
|
||||
>
|
||||
Access
|
||||
</Box>
|
||||
<Box
|
||||
sx={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
position: 'relative',
|
||||
left: '20px'
|
||||
}}
|
||||
>
|
||||
<Switch checked />
|
||||
</Box>
|
||||
</Box>
|
||||
</Box>
|
||||
</MDBox>
|
||||
<Grid container spacing={2} className={classes.margin}>
|
||||
<Grid item xs={12}>
|
||||
<Grid container spacing={2} className={classes.margin}>
|
||||
<Grid item xs={6}>
|
||||
<Box component="div" className={classes.labelSize}>
|
||||
Created By
|
||||
</Box>
|
||||
<MDInput fullWidth name="warehousename" type="text" variant="outlined" />
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
<Box component="div" className={classes.labelSize}>
|
||||
Date & Time
|
||||
</Box>
|
||||
<DateTimeInput />
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
<Box component="div" className={classes.labelSize}>
|
||||
Last Updated by
|
||||
</Box>
|
||||
<MDInput fullWidth name="warehousename" type="text" variant="outlined" />
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
<Box component="div" className={classes.labelSize}>
|
||||
Date & Time
|
||||
</Box>
|
||||
<DateTimeInput />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</MDBox>
|
||||
</MDBox>
|
||||
|
||||
<Grid container spacing={4} sx={{ marginTop: '-6px' }}>
|
||||
<Grid item xs={12} md={6}>
|
||||
<MDBox
|
||||
sx={{
|
||||
backgroundColor: '#fff',
|
||||
border: '1px solid #c2c2c2',
|
||||
borderTop: '7px solid #007aff',
|
||||
padding: '12px',
|
||||
borderRadius: '4px'
|
||||
}}
|
||||
>
|
||||
<Typography gutterBottom variant="h6" component="div">
|
||||
Warehouse
|
||||
</Typography>
|
||||
<TransferList />
|
||||
</MDBox>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={6}>
|
||||
<MDBox
|
||||
sx={{
|
||||
backgroundColor: '#fff',
|
||||
border: '1px solid #c2c2c2',
|
||||
borderTop: '7px solid #007aff',
|
||||
padding: '12px',
|
||||
borderRadius: '4px'
|
||||
}}
|
||||
>
|
||||
<Typography gutterBottom variant="h6" component="div">
|
||||
Warehouse
|
||||
</Typography>
|
||||
<TransferList />
|
||||
</MDBox>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Grid container spacing={2} sx={{ marginTop: '12px' }}>
|
||||
<Grid item xs={12} md={3}>
|
||||
<MDBox
|
||||
sx={{
|
||||
backgroundColor: '#fff',
|
||||
border: '1px solid #c2c2c2',
|
||||
borderTop: '7px solid #007aff',
|
||||
borderRadius: '4px'
|
||||
}}
|
||||
>
|
||||
<Typography
|
||||
gutterBottom
|
||||
variant="h6"
|
||||
component="div"
|
||||
sx={{
|
||||
borderBottom: '1px solid #c2c2c2',
|
||||
padding: '10px 20px',
|
||||
marginBottom: '20px'
|
||||
}}
|
||||
>
|
||||
Process
|
||||
</Typography>
|
||||
<Box sx={{ padding: ' 0px 20px' }}>
|
||||
<MDBox
|
||||
display="flex"
|
||||
justifyContent="space-between"
|
||||
alignItems="center"
|
||||
lineHeight={1}
|
||||
className={classes.switchSpacer}
|
||||
sx={{ marginBottom: '20px !important' }}
|
||||
>
|
||||
<MDTypography variant="body2">Stock Tracking</MDTypography>
|
||||
<Switch checked />
|
||||
</MDBox>
|
||||
<MDBox
|
||||
display="flex"
|
||||
justifyContent="space-between"
|
||||
alignItems="center"
|
||||
lineHeight={1}
|
||||
className={classes.switchSpacer}
|
||||
sx={{ marginBottom: '20px !important' }}
|
||||
>
|
||||
<MDTypography variant="body2">Replenishment</MDTypography>
|
||||
<Switch checked />
|
||||
</MDBox>
|
||||
<MDBox
|
||||
display="flex"
|
||||
justifyContent="space-between"
|
||||
alignItems="center"
|
||||
lineHeight={1}
|
||||
className={classes.switchSpacer}
|
||||
sx={{ marginBottom: '20px !important' }}
|
||||
>
|
||||
<MDTypography variant="body2">Alerting</MDTypography>
|
||||
<Switch checked />
|
||||
</MDBox>
|
||||
</Box>
|
||||
</MDBox>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={3}>
|
||||
<MDBox
|
||||
sx={{
|
||||
backgroundColor: '#fff',
|
||||
border: '1px solid #c2c2c2',
|
||||
borderTop: '7px solid #007aff',
|
||||
borderRadius: '4px'
|
||||
}}
|
||||
>
|
||||
<Typography
|
||||
gutterBottom
|
||||
variant="h6"
|
||||
component="div"
|
||||
sx={{
|
||||
borderBottom: '1px solid #c2c2c2',
|
||||
padding: '10px 20px',
|
||||
marginBottom: '20px'
|
||||
}}
|
||||
>
|
||||
Application
|
||||
</Typography>
|
||||
<Box sx={{ padding: ' 0px 20px' }}>
|
||||
<MDBox
|
||||
display="flex"
|
||||
justifyContent="space-between"
|
||||
alignItems="center"
|
||||
lineHeight={1}
|
||||
className={classes.switchSpacer}
|
||||
sx={{ marginBottom: '20px !important' }}
|
||||
>
|
||||
<MDTypography variant="body2">Home</MDTypography>
|
||||
<Switch checked />
|
||||
</MDBox>
|
||||
<MDBox
|
||||
display="flex"
|
||||
justifyContent="space-between"
|
||||
alignItems="center"
|
||||
lineHeight={1}
|
||||
className={classes.switchSpacer}
|
||||
sx={{ marginBottom: '20px !important' }}
|
||||
>
|
||||
<MDTypography variant="body2">Setup</MDTypography>
|
||||
<Switch checked />
|
||||
</MDBox>
|
||||
<MDBox
|
||||
display="flex"
|
||||
justifyContent="space-between"
|
||||
alignItems="center"
|
||||
lineHeight={1}
|
||||
className={classes.switchSpacer}
|
||||
sx={{ marginBottom: '20px !important' }}
|
||||
>
|
||||
<MDTypography variant="body2">Reports</MDTypography>
|
||||
<Switch checked />
|
||||
</MDBox>
|
||||
</Box>
|
||||
</MDBox>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<MDBox
|
||||
display="flex"
|
||||
justifyContent="center"
|
||||
alignItems="center"
|
||||
lineHeight={1}
|
||||
sx={{ marginBottom: '15px', marginTop: '45px', paddingBottom: '30px' }}
|
||||
>
|
||||
<MDButton
|
||||
size="medium"
|
||||
color="error"
|
||||
variant="outlined"
|
||||
type="submit"
|
||||
sx={{ marginRight: '15px' }}
|
||||
>
|
||||
Cancel
|
||||
</MDButton>
|
||||
<MDButton size="medium" color="primary" variant="contained">
|
||||
Save
|
||||
</MDButton>
|
||||
</MDBox>
|
||||
</MDBox>
|
||||
</DashboardLayout>
|
||||
);
|
||||
}
|
||||
export default CreateUserRole;
|
||||
@@ -12,7 +12,9 @@ import {
|
||||
DialogTitle,
|
||||
DialogContent,
|
||||
TextField,
|
||||
DialogActions
|
||||
DialogActions,
|
||||
Button,
|
||||
DialogContentText
|
||||
} from '@mui/material';
|
||||
import DashboardNavbar from 'components/DashboardNavbar';
|
||||
import DashboardLayout from 'layouts/DashboardLayout';
|
||||
@@ -37,6 +39,8 @@ import Breadcrumbs from 'components/Breadcrumbs';
|
||||
import { WarehouseSelectors } from 'redux/WarehouseRedux';
|
||||
import { InventorySelectors } from 'redux/InventoryRedux';
|
||||
import InventoryActions from 'redux/InventoryRedux';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import schema from 'services/ValidationServices';
|
||||
|
||||
const bottomButtonStyling = {
|
||||
width: '100%',
|
||||
@@ -317,6 +321,10 @@ const WarehouseNestedDetails = () => {
|
||||
|
||||
function EditWarehouseDetails() {
|
||||
const { warehouseId } = useParams();
|
||||
const navigate = useNavigate();
|
||||
const navigateTo = (to) => {
|
||||
navigate(to);
|
||||
};
|
||||
const warehouseData = useSelector(WarehouseSelectors.getWarehouseDetailById(warehouseId));
|
||||
|
||||
const inventoryTypes = useSelector(InventorySelectors.getInventoryDetail);
|
||||
@@ -347,11 +355,11 @@ function EditWarehouseDetails() {
|
||||
initialValues: {
|
||||
warehousename: warehouseData.name,
|
||||
address: warehouseData.address || '',
|
||||
preferredInventories: warehouseData.preferredInventories || [],
|
||||
preferredInventories: [...warehouseData.preferredInventories] || [],
|
||||
specs: warehouseData.specs || '',
|
||||
image: warehouseData.image_url ? [{ src: warehouseData.image_url }] : []
|
||||
},
|
||||
// validationSchema: schema.warehouseForm,
|
||||
validationSchema: schema.warehouseForm,
|
||||
onSubmit: (values) => {
|
||||
dispatch(
|
||||
WarehouseActions.editWarehouseAction({
|
||||
@@ -370,11 +378,20 @@ function EditWarehouseDetails() {
|
||||
}
|
||||
});
|
||||
|
||||
const [deleteAlertOpen, setDeleteAlertOpen] = React.useState(null);
|
||||
const handleDeleteAlertClose = () => {
|
||||
setDeleteAlertOpen(false);
|
||||
};
|
||||
const handleDeleteAlertOpen = () => {
|
||||
setDeleteAlertOpen(true);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<DashboardLayout>
|
||||
<DashboardNavbar />
|
||||
<Breadcrumbs
|
||||
title="Edit Warehouse Details"
|
||||
route={[
|
||||
{ name: 'Home', path: '/home' },
|
||||
{ name: 'Setup', path: '/setup' },
|
||||
@@ -385,17 +402,6 @@ function EditWarehouseDetails() {
|
||||
<Box mx={3} my={3}>
|
||||
<form onSubmit={formik.handleSubmit}>
|
||||
<Box sx={{ backgroundColor: '#fff', padding: '30px' }}>
|
||||
<Box
|
||||
component="div"
|
||||
sx={{
|
||||
fontSize: '22px',
|
||||
letterSpacing: '0.01em',
|
||||
color: '#000',
|
||||
marginBottom: '30px'
|
||||
}}
|
||||
>
|
||||
Form to Input
|
||||
</Box>
|
||||
<Grid container spacing={2}>
|
||||
<Grid item xs={12} sm={6} md={6}>
|
||||
<Box component="div" sx={{ marginBottom: '15px' }}>
|
||||
@@ -417,7 +423,12 @@ function EditWarehouseDetails() {
|
||||
variant="outlined"
|
||||
value={formik.values.warehousename}
|
||||
error={formik.touched.warehousename && Boolean(formik.errors.warehousename)}
|
||||
helperText={formik.touched.warehousename && formik.errors.warehousename}
|
||||
helperText={
|
||||
formik.touched.warehousename &&
|
||||
formik.errors.warehousename && (
|
||||
<div style={{ color: 'red' }}>{formik.errors.warehousename}</div>
|
||||
)
|
||||
}
|
||||
onChange={formik.handleChange}
|
||||
/>
|
||||
</Box>
|
||||
@@ -440,7 +451,12 @@ function EditWarehouseDetails() {
|
||||
variant="outlined"
|
||||
value={formik.values.address}
|
||||
error={formik.touched.address && Boolean(formik.errors.address)}
|
||||
helperText={formik.touched.address && formik.errors.address}
|
||||
helperText={
|
||||
formik.touched.address &&
|
||||
formik.errors.address && (
|
||||
<div style={{ color: 'red' }}>{formik.errors.address}</div>
|
||||
)
|
||||
}
|
||||
onChange={formik.handleChange}
|
||||
/>
|
||||
</Box>
|
||||
@@ -459,7 +475,6 @@ function EditWarehouseDetails() {
|
||||
<Select
|
||||
multiple
|
||||
select
|
||||
disabled
|
||||
fullWidth
|
||||
variant="outlined"
|
||||
name="preferredInventories"
|
||||
@@ -492,6 +507,9 @@ function EditWarehouseDetails() {
|
||||
);
|
||||
}}
|
||||
>
|
||||
<MenuItem disabled key={'none'} value={''}>
|
||||
None Selected
|
||||
</MenuItem>
|
||||
{inventoryTypes &&
|
||||
inventoryTypes.map((inventory) => (
|
||||
<MenuItem key={inventory._id} value={inventory._id}>
|
||||
@@ -524,7 +542,49 @@ function EditWarehouseDetails() {
|
||||
/>
|
||||
</Box>
|
||||
</Grid>
|
||||
<Grid item xs={12} sm={6} md={6}>
|
||||
<Grid item sx={{ textAlign: 'end' }} xs={12} sm={6} md={6}>
|
||||
<MDButton
|
||||
size="large"
|
||||
color="error"
|
||||
variant="outlined"
|
||||
onClick={handleDeleteAlertOpen}
|
||||
>
|
||||
Delete Warehouse
|
||||
</MDButton>
|
||||
<Dialog
|
||||
open={deleteAlertOpen}
|
||||
aria-labelledby="alert-dialog-title"
|
||||
aria-describedby="alert-dialog-description"
|
||||
onClose={handleDeleteAlertClose}
|
||||
>
|
||||
<DialogTitle id="alert-dialog-title">Confirm Warehouse Delete</DialogTitle>
|
||||
<DialogContent>
|
||||
<DialogContentText id="alert-dialog-description">
|
||||
Are you sure you want to delete this warehouse?
|
||||
</DialogContentText>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button autoFocus onClick={handleDeleteAlertClose}>
|
||||
No
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => {
|
||||
dispatch(
|
||||
WarehouseActions.deleteWarehouseAction({
|
||||
loader: 'loading-request',
|
||||
slug: '/warehouse/',
|
||||
method: 'delete',
|
||||
warehouseId: warehouseData._id,
|
||||
navigateTo
|
||||
})
|
||||
);
|
||||
handleDeleteAlertClose();
|
||||
}}
|
||||
>
|
||||
Yes
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
<Box sx={{ marginTop: '30px' }}>
|
||||
<ImageUploadSingle
|
||||
heading="Upload Warehouse Image"
|
||||
@@ -545,6 +605,16 @@ function EditWarehouseDetails() {
|
||||
columnGap: '20px'
|
||||
}}
|
||||
>
|
||||
<MDButton
|
||||
size="medium"
|
||||
color="error"
|
||||
variant="outlined"
|
||||
onClick={() => {
|
||||
navigate('/setup/warehouse');
|
||||
}}
|
||||
>
|
||||
CANCEL
|
||||
</MDButton>
|
||||
{/* ---edit-- */}
|
||||
<MDButton size="large" color="primary" variant="outlined" type="submit">
|
||||
SAVE
|
||||
|
||||
@@ -37,7 +37,7 @@ function HomepageScreen() {
|
||||
return (
|
||||
<DashboardLayout>
|
||||
<DashboardNavbar />
|
||||
<Breadcrumbs route={[{ name: 'Home', path: '/home' }]} />
|
||||
<Breadcrumbs title="Warehouse Management System" route={[{ name: 'Home', path: '/home' }]} />
|
||||
<TileBasic tiles={data} />
|
||||
</DashboardLayout>
|
||||
);
|
||||
|
||||
@@ -1,7 +1,24 @@
|
||||
import React from 'react';
|
||||
import React, { useEffect } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import DashboardNavbar from 'components/DashboardNavbar';
|
||||
import DashboardLayout from 'layouts/DashboardLayout';
|
||||
import { Box, Grid, MenuItem, Select } from '@mui/material';
|
||||
import {
|
||||
Box,
|
||||
FormControlLabel,
|
||||
Grid,
|
||||
MenuItem,
|
||||
Radio,
|
||||
RadioGroup,
|
||||
useRadioGroup,
|
||||
Select,
|
||||
Dialog,
|
||||
DialogTitle,
|
||||
DialogContent,
|
||||
DialogContentText,
|
||||
DialogActions,
|
||||
Button
|
||||
} from '@mui/material';
|
||||
import { styled } from '@mui/material/styles';
|
||||
import MDInput from 'components/MDInput';
|
||||
import Switch from 'components/Switch';
|
||||
import MDTypography from 'components/MDTypography';
|
||||
@@ -18,6 +35,9 @@ import { useParams } from 'react-router-dom';
|
||||
import { InventorySelectors } from 'redux/InventoryRedux';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import WidgetNestedDataTable from 'components/WidgetNestedDataTable';
|
||||
import { GetIconFromSlug } from 'utils/inventorySlugTools';
|
||||
import { iconSlugs } from 'utils/inventorySlugTools';
|
||||
import AddCircleIcon from '@mui/icons-material/AddCircle';
|
||||
|
||||
const customStyles = {
|
||||
labelSize: {
|
||||
@@ -63,13 +83,34 @@ const definedPolicies = [
|
||||
{
|
||||
text: 'Alerting',
|
||||
key: 'alerting'
|
||||
},
|
||||
{
|
||||
text: 'Location',
|
||||
key: 'preferredLocations'
|
||||
}
|
||||
// {
|
||||
// text: 'Location',
|
||||
// key: 'preferredLocations'
|
||||
// }
|
||||
];
|
||||
|
||||
const StyledFormControlLabel = styled((props) => <FormControlLabel {...props} />)(
|
||||
({ theme, checked }) => ({
|
||||
'.MuiFormControlLabel-label': checked && {
|
||||
border: `1px solid ${theme.palette.primary.light}`,
|
||||
borderRadius: '10px'
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
function MyFormControlLabel(props) {
|
||||
const radioGroup = useRadioGroup();
|
||||
let checked = false;
|
||||
if (radioGroup) {
|
||||
checked = radioGroup.value === props.value;
|
||||
}
|
||||
return <StyledFormControlLabel checked={checked} {...props} />;
|
||||
}
|
||||
MyFormControlLabel.propTypes = {
|
||||
value: PropTypes.any
|
||||
};
|
||||
|
||||
function InventoryScreen() {
|
||||
const dispatch = useDispatch();
|
||||
const navigate = useNavigate();
|
||||
@@ -80,18 +121,16 @@ function InventoryScreen() {
|
||||
};
|
||||
|
||||
const currentInventoryData = useSelector(InventorySelectors.getInventoryDetailById(inventoryId));
|
||||
LOGGER.log({ currentInventoryData });
|
||||
// const [inventoryAllData, setInventoryAllData] = useState([]);
|
||||
// const initialInventoryName='';
|
||||
const [iconSelect, setIconSelect] = React.useState('');
|
||||
|
||||
// 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);
|
||||
useEffect(() => {
|
||||
if (inventoryId) {
|
||||
const iconFilter = iconSlugs.filter(
|
||||
(iconSlug) => iconSlug === currentInventoryData.icon_slug
|
||||
);
|
||||
setIconSelect(GetIconFromSlug(iconFilter[0]));
|
||||
}
|
||||
}, [inventoryId]);
|
||||
|
||||
/* eslint-disable indent */
|
||||
const formik = useFormik({
|
||||
@@ -99,6 +138,7 @@ function InventoryScreen() {
|
||||
? {
|
||||
name: currentInventoryData.name,
|
||||
widgetName: currentInventoryData.widgetName,
|
||||
icon_slug: currentInventoryData.icon_slug,
|
||||
policies: {
|
||||
orderTracking: currentInventoryData.policies.orderTracking,
|
||||
alerting: currentInventoryData.policies.alerting,
|
||||
@@ -110,11 +150,12 @@ function InventoryScreen() {
|
||||
: {
|
||||
name: '',
|
||||
widgetName: '',
|
||||
icon_slug: '',
|
||||
policies: {
|
||||
orderTracking: false,
|
||||
alerting: false,
|
||||
replenishment: false,
|
||||
preferredLocations: false,
|
||||
preferredLocations: false, // TODO: change later
|
||||
inventory_process: 'CCR'
|
||||
}
|
||||
},
|
||||
@@ -130,7 +171,7 @@ function InventoryScreen() {
|
||||
navigateTo,
|
||||
data: {
|
||||
...values,
|
||||
icon_slug: 'testslug'
|
||||
icon_slug: values.icon_slug
|
||||
}
|
||||
})
|
||||
)
|
||||
@@ -142,18 +183,39 @@ function InventoryScreen() {
|
||||
navigateTo,
|
||||
data: {
|
||||
...values,
|
||||
icon_slug: 'testslug'
|
||||
icon_slug: values.icon_slug
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
LOGGER.log('Form values', formik.values);
|
||||
const [deleteAlertOpen, setDeleteAlertOpen] = React.useState(null);
|
||||
const handleDeleteAlertClose = () => {
|
||||
setDeleteAlertOpen(false);
|
||||
};
|
||||
const handleDeleteAlertOpen = () => {
|
||||
setDeleteAlertOpen(true);
|
||||
};
|
||||
|
||||
const [iconSlugOpen, setIconSlugOpen] = React.useState(null);
|
||||
const handleIconSlugClose = () => {
|
||||
setIconSlugOpen(false);
|
||||
};
|
||||
const handleIconSlugOpen = () => {
|
||||
setIconSlugOpen(true);
|
||||
};
|
||||
|
||||
const handleIconSlug = (value) => {
|
||||
const iconFilter = iconSlugs.filter((iconSlug) => iconSlug === value);
|
||||
setIconSelect(GetIconFromSlug(iconFilter[0]));
|
||||
setIconSlugOpen(false);
|
||||
};
|
||||
return (
|
||||
<DashboardLayout>
|
||||
<DashboardNavbar />
|
||||
<Breadcrumbs
|
||||
title="Inventory Details"
|
||||
route={[
|
||||
{ name: 'Home', path: '/home' },
|
||||
{ name: 'Setup', path: '/setup' },
|
||||
@@ -186,7 +248,10 @@ function InventoryScreen() {
|
||||
variant="outlined"
|
||||
value={formik.values.name}
|
||||
error={formik.touched.name && Boolean(formik.errors.name)}
|
||||
helpertText={formik.touched.name && formik.errors.name}
|
||||
helperText={
|
||||
formik.touched.name &&
|
||||
formik.errors.name && <div style={{ color: 'red' }}>{formik.errors.name}</div>
|
||||
}
|
||||
onChange={formik.handleChange}
|
||||
/>
|
||||
</Box>
|
||||
@@ -202,7 +267,12 @@ function InventoryScreen() {
|
||||
variant="outlined"
|
||||
value={formik.values.widgetName}
|
||||
error={formik.touched.widgetName && Boolean(formik.errors.widgetName)}
|
||||
helpertext={formik.touched.widgetName && formik.errors.widgetName}
|
||||
helperText={
|
||||
formik.touched.widgetName &&
|
||||
formik.errors.widgetName && (
|
||||
<div style={{ color: 'red' }}>{formik.errors.widgetName}</div>
|
||||
)
|
||||
}
|
||||
onChange={formik.handleChange}
|
||||
/>
|
||||
</Grid>
|
||||
@@ -257,8 +327,107 @@ function InventoryScreen() {
|
||||
</div>
|
||||
</MDBox>
|
||||
</Grid>
|
||||
<Grid item xs={12} sm={6} md={6}>
|
||||
icon slugs selector
|
||||
<Grid item sx={{ textAlign: 'right' }} xs={12} sm={6} md={6}>
|
||||
<MDButton
|
||||
size="large"
|
||||
color="error"
|
||||
variant="outlined"
|
||||
sx={{
|
||||
marginTop: '20px'
|
||||
}}
|
||||
onClick={handleDeleteAlertOpen}
|
||||
>
|
||||
Delete Inventory
|
||||
</MDButton>
|
||||
<Dialog
|
||||
open={deleteAlertOpen}
|
||||
aria-labelledby="alert-dialog-title"
|
||||
aria-describedby="alert-dialog-description"
|
||||
onClose={handleDeleteAlertClose}
|
||||
>
|
||||
<DialogTitle id="alert-dialog-title">Confirm Inventory Delete</DialogTitle>
|
||||
<DialogContent>
|
||||
<DialogContentText id="alert-dialog-description">
|
||||
Are you sure you want to delete this inventory?
|
||||
</DialogContentText>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button autoFocus onClick={handleDeleteAlertClose}>
|
||||
No
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => {
|
||||
dispatch(
|
||||
InventoryActions.deleteInventoryAction({
|
||||
loader: 'loading-request',
|
||||
slug: '/inventory/' + inventoryId,
|
||||
method: 'delete',
|
||||
inventoryId,
|
||||
navigateTo
|
||||
})
|
||||
);
|
||||
handleDeleteAlertClose();
|
||||
}}
|
||||
>
|
||||
Yes
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
<Box
|
||||
sx={{
|
||||
height: 300,
|
||||
padding: '20px',
|
||||
marginTop: '80px',
|
||||
textAlign: 'left'
|
||||
}}
|
||||
>
|
||||
<MDBox sx={{ my: 4 }}>
|
||||
<MDTypography variant="h5">Inventory Icon</MDTypography>
|
||||
<MDTypography sx={customStyles.textSize}>
|
||||
Choose the icon to represent the inventory
|
||||
</MDTypography>
|
||||
</MDBox>
|
||||
|
||||
<AddCircleIcon fontSize="large" onClick={handleIconSlugOpen} />
|
||||
{iconSelect}
|
||||
<Dialog
|
||||
open={iconSlugOpen}
|
||||
aria-labelledby="alert-dialog-title"
|
||||
aria-describedby="alert-dialog-description"
|
||||
onClose={handleIconSlugClose}
|
||||
>
|
||||
<DialogTitle id="alert-dialog-title">Select Icon</DialogTitle>
|
||||
<DialogContent>
|
||||
<DialogContentText id="alert-dialog-description">
|
||||
<RadioGroup
|
||||
row
|
||||
sx={{
|
||||
marginTop: '15px'
|
||||
}}
|
||||
aria-labelledby="demo-error-radios"
|
||||
name="icon_slug"
|
||||
value={formik.values.icon_slug}
|
||||
onChange={formik.handleChange}
|
||||
>
|
||||
{iconSlugs.map((iconSlug) => (
|
||||
<MyFormControlLabel
|
||||
key={iconSlug}
|
||||
value={iconSlug}
|
||||
control={<Radio style={{ display: 'none' }} />}
|
||||
label={GetIconFromSlug(iconSlug)}
|
||||
/>
|
||||
))}
|
||||
</RadioGroup>
|
||||
</DialogContentText>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button autoFocus onClick={handleIconSlugClose}>
|
||||
No
|
||||
</Button>
|
||||
<Button onClick={() => handleIconSlug(formik.values.icon_slug)}>Yes</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
</Box>
|
||||
</Grid>
|
||||
<MDBox sx={{ ml: 'auto', mr: 'auto', mt: 3 }}>
|
||||
<MDButton
|
||||
@@ -269,12 +438,12 @@ function InventoryScreen() {
|
||||
navigate('/setup/inventory');
|
||||
}}
|
||||
>
|
||||
{'CANCEL'}
|
||||
{'CLOSE'}
|
||||
</MDButton>
|
||||
<MDButton sx={{ ml: 3 }} color="primary" variant="outlined" type="submit">
|
||||
{'SAVE'}
|
||||
</MDButton>
|
||||
<MDButton
|
||||
{/* <MDButton
|
||||
sx={{ ml: 3 }}
|
||||
color="primary"
|
||||
onClick={() => {
|
||||
@@ -284,7 +453,7 @@ function InventoryScreen() {
|
||||
}}
|
||||
>
|
||||
{'ADD ITEMS'}
|
||||
</MDButton>
|
||||
</MDButton> */}
|
||||
</MDBox>
|
||||
</Grid>
|
||||
</MDBox>
|
||||
|
||||
@@ -14,7 +14,17 @@ import EnhancedTable from 'components/EnhancedTable';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import WidgetActions from 'redux/WidgetRedux';
|
||||
import { WidgetSelectors } from 'redux/WidgetRedux';
|
||||
import { DialogContent, DialogContentText, DialogTitle, MenuItem, Select } from '@mui/material';
|
||||
import {
|
||||
Button,
|
||||
Dialog,
|
||||
DialogActions,
|
||||
DialogContent,
|
||||
DialogContentText,
|
||||
DialogTitle,
|
||||
Grid,
|
||||
MenuItem,
|
||||
Select
|
||||
} from '@mui/material';
|
||||
|
||||
const tHeads = [
|
||||
{ key: 'name', name: '' },
|
||||
@@ -34,7 +44,7 @@ const tHeads = [
|
||||
|
||||
function ItemListing() {
|
||||
const dispatch = useDispatch();
|
||||
const { widgetName, inventoryId } = useParams();
|
||||
const { inventoryName, widgetName, inventoryId } = useParams();
|
||||
const [page, setPage] = React.useState(1);
|
||||
const [perPage, setPerPage] = React.useState(10);
|
||||
LOGGER.log({ widgetName, inventoryId });
|
||||
@@ -76,20 +86,76 @@ function ItemListing() {
|
||||
);
|
||||
}, []);
|
||||
|
||||
const [deleteAlertOpen, setDeleteAlertOpen] = React.useState(null);
|
||||
const handleDeleteAlertClose = () => {
|
||||
setDeleteAlertOpen(null);
|
||||
};
|
||||
const handleDeleteAlertOpen = (id) => {
|
||||
setDeleteAlertOpen(id);
|
||||
};
|
||||
|
||||
return (
|
||||
<DashboardLayout>
|
||||
<DashboardNavbar />
|
||||
<Breadcrumbs
|
||||
title={`List of ${widgetName}s`}
|
||||
route={[
|
||||
{ name: 'Home', path: '/home' },
|
||||
{ name: 'Setup', path: '/setup' },
|
||||
{ name: 'Inventory', path: '/setup/inventory' },
|
||||
{ name: inventoryName || 'Inventory' },
|
||||
{ name: `${widgetName}s List` }
|
||||
]}
|
||||
/>
|
||||
|
||||
<MDBox px={2} py={3}>
|
||||
List of {widgetName}s{/* <pre>{JSON.stringify(data, null, 4)}</pre> */}
|
||||
<MDBox px={5} py={3}>
|
||||
<Dialog
|
||||
open={deleteAlertOpen}
|
||||
aria-labelledby="alert-dialog-title"
|
||||
aria-describedby="alert-dialog-description"
|
||||
onClose={handleDeleteAlertClose}
|
||||
>
|
||||
<DialogTitle id="alert-dialog-title">Confirm Delete</DialogTitle>
|
||||
<DialogContent>
|
||||
<DialogContentText id="alert-dialog-description">
|
||||
Are you sure you want to delete this item?
|
||||
</DialogContentText>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button autoFocus onClick={handleDeleteAlertClose}>
|
||||
No
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => {
|
||||
const refreshDispatch = () => {
|
||||
dispatch(
|
||||
ItemActions.itemRequest({
|
||||
loader: 'loading-request',
|
||||
slug: API.GET_ITEMS_BY_INVENTORY,
|
||||
method: 'get',
|
||||
page: page - 1,
|
||||
perPage,
|
||||
inventoryId,
|
||||
family: sFam || pFam || null
|
||||
})
|
||||
);
|
||||
};
|
||||
dispatch(
|
||||
ItemActions.deleteItemRequest({
|
||||
loader: 'loading-request',
|
||||
slug: '/item/',
|
||||
method: 'delete',
|
||||
itemId: deleteAlertOpen,
|
||||
refreshDispatch
|
||||
})
|
||||
);
|
||||
handleDeleteAlertClose();
|
||||
}}
|
||||
>
|
||||
Yes
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
<EnhancedTable
|
||||
count={count}
|
||||
page={page}
|
||||
@@ -97,7 +163,12 @@ function ItemListing() {
|
||||
perPage={perPage}
|
||||
setPerPage={setPerPage}
|
||||
editHandler={(id) => {
|
||||
navigateTo(`/setup/inventory/browse/${widgetName}/${inventoryId}/edit/${id}`);
|
||||
navigateTo(
|
||||
`/setup/inventory/browse/${inventoryName}/${widgetName}/${inventoryId}/edit/${id}`
|
||||
);
|
||||
}}
|
||||
deleteHandler={(id) => {
|
||||
handleDeleteAlertOpen(id);
|
||||
}}
|
||||
resetFilters={() => {
|
||||
setPFam('');
|
||||
@@ -105,21 +176,21 @@ function ItemListing() {
|
||||
}}
|
||||
filtersControl={
|
||||
<>
|
||||
<DialogTitle>Add filters</DialogTitle>
|
||||
<DialogContent>
|
||||
<DialogContentText>Filter by family</DialogContentText>
|
||||
<Grid item sx={4}>
|
||||
<Select
|
||||
select
|
||||
fullWidth
|
||||
variant="outlined"
|
||||
displayEmpty
|
||||
value={pFam}
|
||||
inputProps={{ 'aria-label': 'Without label' }}
|
||||
sx={{
|
||||
width: 200
|
||||
}}
|
||||
onChange={(e) => {
|
||||
setSFam('');
|
||||
setPFam(e.target.value);
|
||||
}}
|
||||
>
|
||||
<MenuItem key={'none'} value={''}>
|
||||
None Selected
|
||||
<MenuItem disabled key={'none'} value={''}>
|
||||
Widget family L1
|
||||
</MenuItem>
|
||||
{primaryFamilies &&
|
||||
primaryFamilies.map((fam) => (
|
||||
@@ -128,17 +199,22 @@ function ItemListing() {
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
</Grid>
|
||||
<Grid item sx={4}>
|
||||
<Select
|
||||
select
|
||||
fullWidth
|
||||
displayEmpty
|
||||
variant="outlined"
|
||||
value={sFam}
|
||||
inputProps={{ 'aria-label': 'Without label' }}
|
||||
sx={{
|
||||
width: 200
|
||||
}}
|
||||
onChange={(e) => {
|
||||
setSFam(e.target.value);
|
||||
}}
|
||||
>
|
||||
<MenuItem key={'none'} value={''}>
|
||||
None Selected
|
||||
<MenuItem disabled key={'none'} value={''}>
|
||||
Widget family L2
|
||||
</MenuItem>
|
||||
{secondaryFamilies &&
|
||||
secondaryFamilies.map((fam) => (
|
||||
@@ -147,14 +223,14 @@ function ItemListing() {
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
</DialogContent>
|
||||
</Grid>
|
||||
</>
|
||||
}
|
||||
data={
|
||||
data
|
||||
? data.map((item) => {
|
||||
return {
|
||||
name: item._id,
|
||||
_id: item._id,
|
||||
commonName: item.commonName,
|
||||
formalName: item.formalName,
|
||||
description: item.description,
|
||||
|
||||
@@ -3,12 +3,29 @@ import DashboardNavbar from 'components/DashboardNavbar';
|
||||
import DashboardLayout from 'layouts/DashboardLayout';
|
||||
import { makeStyles } from '@mui/styles';
|
||||
import Dropdown from 'components/Dropdown';
|
||||
import { Grid, TableBody, TableCell, TableRow } from '@mui/material';
|
||||
import BasicTable from 'components/BasicTable';
|
||||
import { Box, Checkbox, Grid, TableBody, TableCell, TableRow } from '@mui/material';
|
||||
import MDButton from 'components/Button';
|
||||
import Breadcrumbs from 'components/Breadcrumbs';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { LabellingSelectors } from 'redux/LabellingRedux';
|
||||
import { WarehouseSelectors } from 'redux/WarehouseRedux';
|
||||
import { WarehouseLocationsSelectors } from 'redux/WarehouseLocationsRedux';
|
||||
import WarehouseActions from 'redux/WarehouseRedux';
|
||||
import { API } from 'constant';
|
||||
import WarehouseLocationsActions from 'redux/WarehouseLocationsRedux';
|
||||
import LabellingActions from 'redux/LabellingRedux';
|
||||
import BasicTable from 'components/BasicTable';
|
||||
const label = { inputProps: { 'aria-label': 'Checkbox demo' } };
|
||||
|
||||
const useStyles = makeStyles({
|
||||
nodataStyle: {
|
||||
height: '200px',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
width: '300%'
|
||||
},
|
||||
iconSize: {
|
||||
width: '50%',
|
||||
height: '50%',
|
||||
@@ -25,37 +42,10 @@ const useStyles = makeStyles({
|
||||
}
|
||||
});
|
||||
|
||||
const records = [
|
||||
{
|
||||
warehouse: 'Ipsum',
|
||||
zone: 'Vivera',
|
||||
area: 'Nisi',
|
||||
row: 'Nulla',
|
||||
label: 'Mauris',
|
||||
bay: ''
|
||||
},
|
||||
{
|
||||
warehouse: 'Ipsum',
|
||||
zone: 'Vivera',
|
||||
area: 'Nisi',
|
||||
row: 'Nulla',
|
||||
label: 'Mauris',
|
||||
bay: ''
|
||||
},
|
||||
{
|
||||
warehouse: 'Ipsum',
|
||||
zone: 'Vivera',
|
||||
area: 'Nisi',
|
||||
row: 'Nulla',
|
||||
label: 'Mauris',
|
||||
bay: ''
|
||||
}
|
||||
];
|
||||
|
||||
const headCells = [
|
||||
{
|
||||
id: 'warehouse',
|
||||
label: 'warehouse'
|
||||
label: 'Warehouse'
|
||||
},
|
||||
{
|
||||
id: 'zone',
|
||||
@@ -70,65 +60,116 @@ const headCells = [
|
||||
label: 'Row'
|
||||
},
|
||||
{
|
||||
id: 'Label',
|
||||
label: 'label'
|
||||
},
|
||||
{
|
||||
id: 'Bay',
|
||||
label: 'bay'
|
||||
id: 'bay',
|
||||
label: 'Bay'
|
||||
}
|
||||
];
|
||||
|
||||
function LabelingScreen() {
|
||||
const classes = useStyles();
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const dropdownData = [
|
||||
{
|
||||
ID: '1',
|
||||
displayname: 'Regular, full time'
|
||||
},
|
||||
{
|
||||
ID: '2',
|
||||
displayname: 'Regular, part time'
|
||||
},
|
||||
{
|
||||
ID: '3',
|
||||
displayname: 'Contractor- Arise Max'
|
||||
const [warehouseId, setWarehouseId] = useState('');
|
||||
const [zoneId, setZoneId] = useState('');
|
||||
const [areaId, setAreaId] = useState('');
|
||||
const [rowId, setRowId] = useState('');
|
||||
|
||||
const warehouseData = useSelector(WarehouseSelectors.getWarehouseDetail);
|
||||
const zonedata = useSelector(WarehouseLocationsSelectors.getChildrenOfParent(warehouseId));
|
||||
const areadata = useSelector(WarehouseLocationsSelectors.getChildrenOfParent(zoneId));
|
||||
const rowdata = useSelector(WarehouseLocationsSelectors.getChildrenOfParent(areaId));
|
||||
|
||||
const [allLabelData, setAllLabelData] = useState([]);
|
||||
const [totemLabelData, setTotemLabelData] = useState([]);
|
||||
const [locationLabelData, setLocationLabelData] = useState([]);
|
||||
|
||||
const labelData = useSelector(LabellingSelectors.getLabelDetail);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (labelData && warehouseId && zoneId && areaId && rowId) {
|
||||
setAllLabelData(labelData);
|
||||
}
|
||||
];
|
||||
const data = [
|
||||
{
|
||||
placeholder: 'Lorem Ipsum',
|
||||
label: 'Select Warehouse'
|
||||
},
|
||||
{
|
||||
placeholder: 'Lorem Ipsum',
|
||||
label: 'Select Zone'
|
||||
},
|
||||
{
|
||||
placeholder: 'Lorem Ipsum',
|
||||
label: 'Select Area'
|
||||
},
|
||||
{
|
||||
placeholder: 'Warehouse 1',
|
||||
label: 'Select Row'
|
||||
}, [labelData, warehouseId, zoneId, areaId]);
|
||||
|
||||
useEffect(() => {
|
||||
dispatch(
|
||||
WarehouseActions.warehouseDataAction({
|
||||
loader: 'loading-request',
|
||||
slug: API.GET_WAREHOUSE_DATA,
|
||||
method: 'get'
|
||||
})
|
||||
);
|
||||
}, []);
|
||||
|
||||
const warehouseChange = (event) => {
|
||||
const id = event.target.value;
|
||||
const type = 'warehouse';
|
||||
setWarehouseId(id);
|
||||
setZoneId('');
|
||||
setAreaId('');
|
||||
setRowId('');
|
||||
dispatch(
|
||||
WarehouseLocationsActions.locationRequest({
|
||||
loader: 'loading-request',
|
||||
slug: API.GET_CHILDREN_FROM_PARENT,
|
||||
method: 'post',
|
||||
data: { id, type }
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
const zoneChange = (event) => {
|
||||
const id = event.target.value;
|
||||
const type = 'zone';
|
||||
setZoneId(id);
|
||||
setAreaId('');
|
||||
setRowId('');
|
||||
dispatch(
|
||||
WarehouseLocationsActions.locationRequest({
|
||||
loader: 'loading-request',
|
||||
slug: API.GET_CHILDREN_FROM_PARENT,
|
||||
method: 'post',
|
||||
data: { id, type }
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
const areaChange = (event) => {
|
||||
const id = event.target.value;
|
||||
const type = 'area';
|
||||
setAreaId(id);
|
||||
setRowId('');
|
||||
dispatch(
|
||||
WarehouseLocationsActions.locationRequest({
|
||||
loader: 'loading-request',
|
||||
slug: API.GET_CHILDREN_FROM_PARENT,
|
||||
method: 'post',
|
||||
data: { id, type }
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
const rowChange = (event) => {
|
||||
const id = event.target.value;
|
||||
setRowId(id);
|
||||
};
|
||||
|
||||
const getTableItem = (e, item) => {
|
||||
if (e.target.checked) {
|
||||
setTotemLabelData((prev) => [...prev, item.totem_label]);
|
||||
setLocationLabelData((prev) => [...prev, item.location_data]);
|
||||
} else {
|
||||
const filterData = allLabelData.filter((item2) => item2.bay._id !== item.bay._id);
|
||||
setTotemLabelData(filterData);
|
||||
setLocationLabelData(filterData);
|
||||
}
|
||||
];
|
||||
const data2 = [
|
||||
{
|
||||
placeholder: 'Z01-A02-R001-B001',
|
||||
label: 'Bay TOTEM Labels'
|
||||
},
|
||||
{
|
||||
placeholder: 'Z01-A02-R001-B001',
|
||||
label: 'BIN Location Labels'
|
||||
}
|
||||
];
|
||||
};
|
||||
|
||||
return (
|
||||
<DashboardLayout>
|
||||
<DashboardNavbar />
|
||||
<Breadcrumbs
|
||||
title="Search And Print Location Labels"
|
||||
route={[
|
||||
{ name: 'Home', path: '/home' },
|
||||
{ name: 'Setup', path: '/setup' },
|
||||
@@ -137,42 +178,106 @@ function LabelingScreen() {
|
||||
]}
|
||||
/>
|
||||
<MDBox px={5} py={5}>
|
||||
<Grid container spacing={2}>
|
||||
{data &&
|
||||
data.map((item, index) => (
|
||||
<Grid item xs={12} sm={6} md={3} key={index}>
|
||||
<Dropdown items={item} dropdownData={dropdownData} />
|
||||
</Grid>
|
||||
))}
|
||||
<Grid container spacing={2} alignItems="end">
|
||||
<Grid item xs={12} md={2.5}>
|
||||
<Dropdown
|
||||
dropdownData={warehouseData}
|
||||
value={warehouseId}
|
||||
label="Select warehouse"
|
||||
onChange={warehouseChange}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={2.5}>
|
||||
<Dropdown dropdownData={zonedata} label="Select Zone" onChange={zoneChange} />
|
||||
</Grid>
|
||||
<Grid item xs={12} md={2.5}>
|
||||
<Dropdown dropdownData={areadata} label="Select Area" onChange={areaChange} />
|
||||
</Grid>
|
||||
<Grid item xs={12} md={2.5}>
|
||||
<Dropdown dropdownData={rowdata} label="Select Row" onChange={rowChange} />
|
||||
</Grid>
|
||||
<Grid item xs={12} md={2}>
|
||||
<MDButton
|
||||
fullWidth
|
||||
color="primary"
|
||||
sx={{
|
||||
height: '45px'
|
||||
}}
|
||||
onClick={() => {
|
||||
warehouseId &&
|
||||
zoneId &&
|
||||
areaId &&
|
||||
rowId &&
|
||||
dispatch(
|
||||
LabellingActions.getLabelAction({
|
||||
loader: 'labelling-request',
|
||||
slug: API.GET_LABEL,
|
||||
method: 'post',
|
||||
data: {
|
||||
warehouse: warehouseId,
|
||||
zone: zoneId,
|
||||
area: areaId,
|
||||
row: rowId
|
||||
}
|
||||
})
|
||||
);
|
||||
}}
|
||||
>
|
||||
Filter
|
||||
</MDButton>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<br />
|
||||
<BasicTable
|
||||
headCells={headCells}
|
||||
records={records}
|
||||
backgroundColor="#F4F4F4"
|
||||
records={allLabelData}
|
||||
backgroundColor="#E5E5E5"
|
||||
color="#8D8D8D"
|
||||
>
|
||||
<TableBody>
|
||||
{records &&
|
||||
records.map((item) => (
|
||||
<TableRow key={item.id}>
|
||||
<TableCell>{item.warehouse}</TableCell>
|
||||
<TableCell>{item.zone}</TableCell>
|
||||
<TableCell>{item.area}</TableCell>
|
||||
<TableCell>{item.row}</TableCell>
|
||||
<TableCell>{item.label}</TableCell>
|
||||
<TableCell>{item.Bay}</TableCell>
|
||||
{rowId ? (
|
||||
allLabelData &&
|
||||
allLabelData.map((item) => (
|
||||
<TableRow key={item._id}>
|
||||
<TableCell>
|
||||
<Checkbox
|
||||
{...label}
|
||||
sx={{ marginRight: '2px' }}
|
||||
onChange={(e) => getTableItem(e, item)}
|
||||
/>
|
||||
{item?.warehouse?.name}
|
||||
</TableCell>
|
||||
<TableCell>{item?.zone?.name}</TableCell>
|
||||
<TableCell>{item?.row?.name}</TableCell>
|
||||
<TableCell>{item?.area?.name}</TableCell>
|
||||
<TableCell>{item?.bay?.name}</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
))
|
||||
) : (
|
||||
<TableRow className={classes.nodataStyle}>No Data</TableRow>
|
||||
)}
|
||||
</TableBody>
|
||||
</BasicTable>
|
||||
<Grid container spacing={2}>
|
||||
{data2 &&
|
||||
data2.map((item, index) => (
|
||||
<Grid item xs={12} sm={6} md={3} key={index}>
|
||||
<Dropdown items={item} dropdownData={dropdownData} />
|
||||
</Grid>
|
||||
))}
|
||||
<Grid container spacing={2} py={5}>
|
||||
<Grid item xs={12} md={3}>
|
||||
<Box sx={{ backgroundColor: '#FFBC26', padding: '3px 12px' }}>Bay Totem Labels</Box>
|
||||
<Box sx={{ border: '1px solid black', padding: '3px 12px', height: '300px' }}>
|
||||
{totemLabelData && totemLabelData.map((item, index) => <div key={index}>{item}</div>)}
|
||||
</Box>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={3}>
|
||||
<Box sx={{ backgroundColor: '#FFBC26', padding: '3px 12px' }}>Bin Location Labels</Box>
|
||||
<Box sx={{ border: '1px solid black', padding: '3px 12px', height: '300px' }}>
|
||||
{locationLabelData &&
|
||||
locationLabelData.map((item, index) => (
|
||||
<div key={index}>
|
||||
{item.map((data, index) => (
|
||||
<div key={index}>{data.label}</div>
|
||||
))}
|
||||
</div>
|
||||
))}
|
||||
</Box>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<div className={classes.buttondiv}>
|
||||
<MDButton color="primary">{'Print Labels'}</MDButton>
|
||||
|
||||
@@ -23,6 +23,7 @@ function LabelingHome() {
|
||||
<DashboardLayout>
|
||||
<DashboardNavbar />
|
||||
<Breadcrumbs
|
||||
title="Labeling"
|
||||
route={[
|
||||
{ name: 'Home', path: '/home' },
|
||||
{ name: 'Setup', path: '/setup' },
|
||||
|
||||
@@ -15,6 +15,7 @@ import Breadcrumbs from 'components/Breadcrumbs';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { InventorySelectors } from 'redux/InventoryRedux';
|
||||
import InventoryActions from 'redux/InventoryRedux';
|
||||
import schema from 'services/ValidationServices';
|
||||
|
||||
function NewWarehouseDetails() {
|
||||
const dispatch = useDispatch();
|
||||
@@ -54,7 +55,7 @@ function NewWarehouseDetails() {
|
||||
specs: '',
|
||||
image: []
|
||||
},
|
||||
// validationSchema: schema.warehouseForm,
|
||||
validationSchema: schema.warehouseForm,
|
||||
onSubmit: (values) => {
|
||||
dispatch(
|
||||
WarehouseActions.createWarehouseAction({
|
||||
@@ -80,6 +81,7 @@ function NewWarehouseDetails() {
|
||||
<DashboardLayout>
|
||||
<DashboardNavbar />
|
||||
<Breadcrumbs
|
||||
title="Create A Warehouse"
|
||||
route={[
|
||||
{ name: 'Home', path: '/home' },
|
||||
{ name: 'Setup', path: '/setup' },
|
||||
@@ -90,17 +92,6 @@ function NewWarehouseDetails() {
|
||||
<Box mx={3} my={3}>
|
||||
<form onSubmit={formik.handleSubmit}>
|
||||
<Box sx={{ backgroundColor: '#fff', padding: '30px' }}>
|
||||
<Box
|
||||
component="div"
|
||||
sx={{
|
||||
fontSize: '22px',
|
||||
letterSpacing: '0.01em',
|
||||
color: '#000',
|
||||
marginBottom: '30px'
|
||||
}}
|
||||
>
|
||||
Form to Input
|
||||
</Box>
|
||||
<Grid container spacing={2}>
|
||||
<Grid item xs={12} sm={6} md={6}>
|
||||
<Box component="div" sx={{ marginBottom: '15px' }}>
|
||||
@@ -122,7 +113,12 @@ function NewWarehouseDetails() {
|
||||
name="warehousename"
|
||||
value={formik.values.warehousename}
|
||||
error={formik.touched.warehousename && Boolean(formik.errors.warehousename)}
|
||||
helperText={formik.touched.warehousename && formik.errors.warehousename}
|
||||
helperText={
|
||||
formik.touched.warehousename &&
|
||||
formik.errors.warehousename && (
|
||||
<div style={{ color: 'red' }}>{formik.errors.warehousename}</div>
|
||||
)
|
||||
}
|
||||
onChange={formik.handleChange}
|
||||
/>
|
||||
</Box>
|
||||
@@ -145,7 +141,12 @@ function NewWarehouseDetails() {
|
||||
name="address"
|
||||
value={formik.values.address}
|
||||
error={formik.touched.address && Boolean(formik.errors.address)}
|
||||
helperText={formik.touched.address && formik.errors.address}
|
||||
helperText={
|
||||
formik.touched.address &&
|
||||
formik.errors.address && (
|
||||
<div style={{ color: 'red' }}>{formik.errors.address}</div>
|
||||
)
|
||||
}
|
||||
onChange={formik.handleChange}
|
||||
/>
|
||||
</Box>
|
||||
@@ -196,7 +197,7 @@ function NewWarehouseDetails() {
|
||||
);
|
||||
}}
|
||||
>
|
||||
<MenuItem key={''} value={''}>
|
||||
<MenuItem disabled key={'none'} value={''}>
|
||||
None Selected
|
||||
</MenuItem>
|
||||
{inventoryTypes &&
|
||||
|
||||
@@ -20,7 +20,7 @@ function SetupHome() {
|
||||
icon: <InventoryIcon width={96} height={96} color="#007AFF" />
|
||||
},
|
||||
{
|
||||
name: 'User & Access',
|
||||
name: 'User Access',
|
||||
path: '/setup/users-access',
|
||||
icon: <ProfileCircleIcon width={96} height={96} color="#007AFF" />
|
||||
},
|
||||
@@ -33,7 +33,7 @@ function SetupHome() {
|
||||
return (
|
||||
<DashboardLayout>
|
||||
<DashboardNavbar />
|
||||
<Breadcrumbs route={[{ name: 'Home', path: '/home' }, { name: 'Setup' }]} />
|
||||
<Breadcrumbs title="Warehouse Management System Setup" route={[{ name: 'Home', path: '/home' }, { name: 'Setup' }]} />
|
||||
<TileBasic tiles={data} />
|
||||
</DashboardLayout>
|
||||
);
|
||||
|
||||
@@ -56,6 +56,7 @@ function SetupInventory() {
|
||||
<DashboardLayout>
|
||||
<DashboardNavbar />
|
||||
<Breadcrumbs
|
||||
title="List Of Inventories"
|
||||
route={[
|
||||
{ name: 'Home', path: '/home' },
|
||||
{ name: 'Setup', path: '/setup' },
|
||||
|
||||
@@ -1,25 +1,25 @@
|
||||
import React, { useEffect, useMemo } from 'react';
|
||||
import moment from 'moment';
|
||||
import React, { useEffect, useState, useMemo } from 'react';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { Grid, Tabs, Tab } from '@mui/material';
|
||||
import { makeStyles } from '@mui/styles';
|
||||
import MDBox from 'components/MDBox';
|
||||
|
||||
import DashboardNavbar from 'components/DashboardNavbar';
|
||||
import DashboardLayout from 'layouts/DashboardLayout';
|
||||
import { styled } from '@mui/material/styles';
|
||||
import { makeStyles } from '@mui/styles';
|
||||
import BasicTable from 'components/BasicTable';
|
||||
import { Grid, TableBody, TableCell, TableRow } from '@mui/material';
|
||||
import SearchBar from 'components/SearchBar';
|
||||
import EditIcon from '@mui/icons-material/Edit';
|
||||
import MDButton from 'components/Button';
|
||||
import { useState } from 'react';
|
||||
import { Tabs, Tab } from '@mui/material';
|
||||
import TabPanel from 'components/Tabs';
|
||||
import Breadcrumbs from 'components/Breadcrumbs';
|
||||
import { PwTablePanel } from 'components';
|
||||
|
||||
import WarehouseActions, { WarehouseSelectors } from 'redux/WarehouseRedux';
|
||||
import InventoryActions, { InventorySelectors } from 'redux/InventoryRedux';
|
||||
import PermissionsActions, { PermissionsSelectors } from 'redux/PermissionsRedux';
|
||||
import UsersActions, { UsersSelectors } from 'redux/UsersRedux';
|
||||
import RolesActions, { RolesSelectors } from 'redux/RolesRedux';
|
||||
import { AuthSelectors } from 'redux/AuthRedux';
|
||||
|
||||
import { API } from 'constant';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import moment from 'moment';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import Breadcrumbs from 'components/Breadcrumbs';
|
||||
|
||||
const useStyles = makeStyles((theme) => ({
|
||||
iconSize: {
|
||||
@@ -34,6 +34,9 @@ const useStyles = makeStyles((theme) => ({
|
||||
statusInactive: {
|
||||
color: 'red'
|
||||
},
|
||||
limitWidth: {
|
||||
maxWidth: '20rem'
|
||||
},
|
||||
margin: {
|
||||
marginBottom: '20px',
|
||||
borderTop: '1px solid #ddd',
|
||||
@@ -53,6 +56,10 @@ const useStyles = makeStyles((theme) => ({
|
||||
overflow: 'hidden',
|
||||
borderRadius: '0.5rem'
|
||||
},
|
||||
rightPlaced: {
|
||||
position: 'absolute',
|
||||
right: 0
|
||||
},
|
||||
tabs: {
|
||||
borderRadius: 0,
|
||||
'& .MuiButtonBase-root.MuiTab-root': {
|
||||
@@ -83,52 +90,117 @@ function UserAccessScreen() {
|
||||
const [value, setValue] = useState(0);
|
||||
const usersData = useSelector(UsersSelectors.getUsersDetail);
|
||||
const rolesData = useSelector(RolesSelectors.getRolesDetail);
|
||||
const currentUser = useSelector(AuthSelectors.getUser);
|
||||
const warehouses = useSelector(WarehouseSelectors.getWarehouseDetail);
|
||||
const inventories = useSelector(InventorySelectors.getInventoryDetail);
|
||||
const actions = useSelector(PermissionsSelectors.getActionsDetail);
|
||||
const permissions = useSelector(PermissionsSelectors.getPermissionsDetail);
|
||||
const [userRecords, setUserRecords] = useState([]);
|
||||
const [rolesRecords, setRoleRecords] = useState([]);
|
||||
const [userLoader, setUserLoader] = useState(false);
|
||||
const [roleLoader, setRoleLoader] = useState(false);
|
||||
const [roleApiCompleted, setRoleApiCompleted] = useState(false);
|
||||
const [userApiCompleted, setUserApiCompleted] = useState(false);
|
||||
const [originalUserRecords, setOriginalUserRecords] = useState([]);
|
||||
const [originalRolesRecords, setOriginalRoleRecords] = useState([]);
|
||||
const navigate = useNavigate();
|
||||
|
||||
useEffect(() => {
|
||||
(!warehouses || warehouses.length === 0) && dispatch(WarehouseActions.warehouseDataAction({loader: 'loading-request', slug: API.GET_WAREHOUSE_DATA,method: 'get'}));
|
||||
(!inventories || inventories.length === 0) && dispatch(InventoryActions.getInventoryAction({loader: 'loading-request', slug: API.GET_INVENTORY,method: 'get'}));
|
||||
(!rolesData || rolesData.length === 0) && dispatch(RolesActions.getRolesAction({loader: 'loading-request', slug: API.GET_ROLES_DATA, method: 'get'}));
|
||||
(!permissions || permissions.length === 0) && dispatch(PermissionsActions.getPermissionsAction({loader: 'loading-request', slug: API.GET_PERMISSIONS_DATA, method: 'get'}));
|
||||
(!actions || actions.length === 0) && dispatch(PermissionsActions.getActionsAction({loader: 'loading-request', slug: API.GET_ACTIONS_DATA, method: 'get'}));
|
||||
}, []);
|
||||
|
||||
const userHeadCells = [
|
||||
{ id: 'full_name', label: 'User Name', isEditAnchor: true, value: record => record.fullName },
|
||||
{ id: 'phone_number', label: 'Phone Number', value: record => record.phoneNumber },
|
||||
{ id: 'role_name', label: 'Roles', value: record => record.role_name },
|
||||
{ id: 'updated_by_at', label: 'Last Updated By & Date', value: record => `${record.updatedBy?.fullName ? record.updatedBy.fullName + ' | ': ''}${moment(record.updatedAt).format('D/M/YYYY h:m:s A')}` },
|
||||
{ id: 'created_by_at', label: 'Created By & Date', value: record => `${record.createdBy?.fullName ? record.createdBy.fullName + ' | ': ''}${moment(record.createdAt).format('D/M/YYYY h:m:s A')}` },
|
||||
{ id: 'last_login', label: 'Last Login', value: record => record.lastLogin },
|
||||
{ id: 'full_name', label: 'User Name', isEditAnchor: true, value: (record) => record.fullName },
|
||||
{ id: 'phone_number', label: 'Phone Number', value: (record) => record.phoneNumber },
|
||||
{ id: 'role_name', label: 'Roles', value: (record) => record.role_name },
|
||||
{
|
||||
id: 'is_active', label: 'Access', value: record => record.isActive ? <span className={classes.statusActive}>Active</span>
|
||||
: <span className={classes.statusInactive}>Inactive</span>
|
||||
id: 'updated_by_at',
|
||||
label: 'Last Updated By & Date',
|
||||
value: (record) =>
|
||||
`${record.updatedBy?.fullName ? record.updatedBy.fullName + ' | ' : ''}${moment(
|
||||
record.updatedAt
|
||||
).format('D/M/YYYY h:m:s A')}`
|
||||
},
|
||||
{
|
||||
id: 'created_by_at',
|
||||
label: 'Created By & Date',
|
||||
value: (record) =>
|
||||
`${record.createdBy?.fullName ? record.createdBy.fullName + ' | ' : ''}${moment(
|
||||
record.createdAt
|
||||
).format('D/M/YYYY h:m:s A')}`
|
||||
},
|
||||
{ id: 'last_login', label: 'Last Login', value: (record) => record.lastLogin },
|
||||
{
|
||||
id: 'is_active',
|
||||
label: 'Access',
|
||||
value: (record) =>
|
||||
record.isActive ? (
|
||||
<span className={classes.statusActive}>Active</span>
|
||||
) : (
|
||||
<span className={classes.statusInactive}>Inactive</span>
|
||||
)
|
||||
}
|
||||
];
|
||||
|
||||
const rolesHeadCells = [
|
||||
{ id: 'role', label: 'Role' },
|
||||
{ id: 'permissions', label: 'Permissions' },
|
||||
{ id: 'status', label: 'Status' }
|
||||
{ id: 'role', label: 'Role', isEditAnchor: true, value: record => record.name },
|
||||
{ id: 'warehouse', label: 'Warehouse', limitWidth: true, value: record => {
|
||||
const roleWh = record.permissions?.warehouseScopes;
|
||||
return warehouses && roleWh && roleWh.length === warehouses.length ? 'All' : roleWh
|
||||
? warehouses.filter(wh => roleWh.findIndex(whCurr => whCurr.id === wh._id) > -1).map(wh => wh.name).join(', ') : '';
|
||||
}
|
||||
},
|
||||
{ id: 'inventory', label: 'Inventories', limitWidth: true, value: record => {
|
||||
const roleIn = record.permissions?.inventoryScopes;
|
||||
return inventories && roleIn && roleIn.length === inventories.length ? 'All' : roleIn
|
||||
? inventories.filter(inv => roleIn.findIndex(inCurr => inCurr.id === inv._id) > -1).map(inv => inv.name).join(', ') : '';
|
||||
}
|
||||
},
|
||||
{ id: 'actions', label: 'Actions', limitWidth: true, value: record => actions && record.permissions?.actions
|
||||
&& record.permissions?.actions?.length === actions?.length ? 'All' : record.permissions?.actions
|
||||
? record.permissions?.actions.join(', ') : ''},
|
||||
{ id: 'visibilities', label: 'App Modules', limitWidth: true, value: record => permissions && record.permissions?.allowedUIModules
|
||||
&& record.permissions?.allowedUIModules?.length === permissions?.length ? 'All' : record.permissions?.allowedUIModules
|
||||
? record.permissions?.allowedUIModules.join(', ') : ''},
|
||||
{ id: 'status', label: 'Status', value: record => record.status === 'ACTIVE' ? <span className={classes.statusActive}>Active</span>
|
||||
: <span className={classes.statusInactive}>Inactive</span> }
|
||||
];
|
||||
|
||||
|
||||
const usersHandler = () => {
|
||||
setUserLoader(true);
|
||||
dispatch(
|
||||
UsersActions.getUsersAction({
|
||||
loader: 'loading-request',
|
||||
slug: API.GET_USERS_DATA,
|
||||
method: 'get'
|
||||
method: 'get',
|
||||
callback: () => {
|
||||
setUserLoader(false);
|
||||
setUserApiCompleted(true);
|
||||
}
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
const rolesHandler = () => {
|
||||
setRoleLoader(true);
|
||||
dispatch(
|
||||
RolesActions.getRolesAction({
|
||||
loader: 'loading-request',
|
||||
slug: API.GET_ROLES_DATA,
|
||||
method: 'get'
|
||||
method: 'get',
|
||||
callback: () => {
|
||||
setRoleLoader(false);
|
||||
setRoleApiCompleted(true);
|
||||
}
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
useMemo(() => rolesHandler(), []);
|
||||
useMemo(() => usersHandler(), []);
|
||||
|
||||
useEffect(() => {
|
||||
if (usersData.length) {
|
||||
@@ -137,6 +209,7 @@ function UserAccessScreen() {
|
||||
item.role_name = item.roles.map((role) => role.name).join(',');
|
||||
return item;
|
||||
});
|
||||
setOriginalUserRecords(users);
|
||||
setUserRecords(users);
|
||||
}
|
||||
|
||||
@@ -144,13 +217,14 @@ function UserAccessScreen() {
|
||||
let roles = JSON.parse(JSON.stringify(rolesData));
|
||||
roles = roles.map((item) => {
|
||||
item.name = item.name.split('-').join(' ').toUpperCase();
|
||||
item.permissions = item.permissions?.allowedUIModules?.join(',');
|
||||
// item.permissions = item.permissions?.allowedUIModules?.join(',');
|
||||
if (!item.permissions) {
|
||||
item.permissions = 'NA';
|
||||
}
|
||||
item.status = item.status ? 'ACTIVE' : 'INACTIVE';
|
||||
return item;
|
||||
});
|
||||
setOriginalRoleRecords(roles);
|
||||
setRoleRecords(roles);
|
||||
}
|
||||
}, [rolesData, usersData]);
|
||||
@@ -159,94 +233,81 @@ function UserAccessScreen() {
|
||||
setValue(val);
|
||||
};
|
||||
|
||||
const StyledTableRow = styled(TableRow)(({ theme }) => ({
|
||||
'&:nth-of-type(even)': {
|
||||
backgroundColor: theme.palette.action.hover
|
||||
}
|
||||
}));
|
||||
|
||||
const rowRenders = userRecords && userRecords.map(record => {
|
||||
const canEdit = columnConfig => columnConfig.isEditAnchor && currentUser.email !== record.email;
|
||||
return <StyledTableRow key={record.id}>
|
||||
{userHeadCells.map((columnConfig, key) => <TableCell key={key} onClick={() => canEdit(columnConfig) && navigate('/setup/users-access/edit-user', {state: {user: record}})}>
|
||||
{canEdit(columnConfig) ? <span className={classes.iconwrap}>
|
||||
<EditIcon className={classes.iconSize}/>
|
||||
{columnConfig.value(record)}
|
||||
</span> : <span>{columnConfig.value(record)}</span>}
|
||||
</TableCell>)}
|
||||
</StyledTableRow>;
|
||||
});
|
||||
const handleSearch = (e, currentTab) => {
|
||||
const value = e.target.value;
|
||||
let records = currentTab === 0 ? originalUserRecords : originalRolesRecords;
|
||||
records = JSON.parse(JSON.stringify(records));
|
||||
records.forEach(record => record.status = record.status ? 'ACTIVE' : 'INACTIVE');
|
||||
let searchList = currentTab === 0 ? ['fullName', 'phoneNumber', 'role_name', 'status'] : ['name', 'permissions', 'status'];
|
||||
const setter = currentTab === 0 ? setUserRecords : setRoleRecords;
|
||||
searchList = searchList.concat(['createdBy.fullName', 'createdAt', 'updatedBy.fullName', 'updatedAt']);
|
||||
const filteredRecords = records.filter(record => searchList.some(field => {
|
||||
let recordInner = {...record};
|
||||
if (field.indexOf('.') > -1) {
|
||||
field = field.split('.');
|
||||
recordInner = recordInner[field[0]];
|
||||
field = field[1];
|
||||
}
|
||||
return recordInner && recordInner[field] !== undefined && typeof recordInner[field] === 'string'
|
||||
&& recordInner[field].toLowerCase().indexOf(value?.toLowerCase()) > -1;
|
||||
}));
|
||||
records.forEach(record => record.status = record.status === 'ACTIVE');
|
||||
setter(filteredRecords);
|
||||
};
|
||||
|
||||
return (
|
||||
<DashboardLayout>
|
||||
<DashboardNavbar />
|
||||
<Breadcrumbs
|
||||
title="Access Details"
|
||||
route={[
|
||||
{ name: 'Home', path: '/home' },
|
||||
{ name: 'Setup', path: '/setup' },
|
||||
{ name: 'Users and Access', path: '/setup/users-access' }
|
||||
{ name: 'User Access' }
|
||||
]}
|
||||
/>
|
||||
<MDBox px={0} py={3}>
|
||||
<Grid container spacing={1} className={classes.margin}>
|
||||
<Grid item xs={12} sm={4} md={4} className='ps-2 pt-0'>
|
||||
<MDBox px={5} py={3}>
|
||||
<Grid container spacing={1} className={classes.margin + ' w-100 ms-0'}>
|
||||
<Grid item xs={12} sm={4} md={4} className="ps-0 pt-0">
|
||||
<Tabs value={value} className={`p-0 h-100 ${classes.tabs}`} onChange={handleTabs}>
|
||||
<Tab label="Roles" onClick={() => rolesHandler()} />
|
||||
<Tab label="Users" onClick={() => usersHandler()} />
|
||||
<Tab label="Roles" onClick={() => rolesHandler()} />
|
||||
</Tabs>
|
||||
</Grid>
|
||||
<Grid item xs={12} sm={4} md={6} className='py-2' style={{ display: 'flex', alignItems: 'center' }}>
|
||||
<SearchBar />
|
||||
<Grid
|
||||
item
|
||||
xs={12}
|
||||
sm={4}
|
||||
md={6}
|
||||
className="py-2"
|
||||
style={{ display: 'flex', alignItems: 'center', justifyContent: 'end' }}
|
||||
>
|
||||
<SearchBar onChange={e => handleSearch(e, value)} />
|
||||
</Grid>
|
||||
<Grid item xs={12} sm={4} md={2} className='py-2' style={{ display: 'flex', alignItems: 'center' }}>
|
||||
<Grid
|
||||
item
|
||||
xs={12}
|
||||
sm={4}
|
||||
md={2}
|
||||
className="py-2"
|
||||
style={{ display: 'flex', alignItems: 'center', justifyContent: 'end' }}
|
||||
>
|
||||
<MDButton
|
||||
color="primary"
|
||||
size="medium"
|
||||
onClick={() => navigate(`/setup/users-access/${value === 0 ? 'create-role' : 'create-user'}`)}
|
||||
onClick={() =>
|
||||
navigate(`/setup/users-access/${value === 0 ? 'create-user' : 'create-role'}`)
|
||||
}
|
||||
>
|
||||
{value === 0 ? '+ CREATE ROLE' : '+ CREATE USER'}
|
||||
{value === 0 ? '+ CREATE USER' : '+ CREATE ROLE'}
|
||||
</MDButton>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Grid px={2}>
|
||||
<TabPanel value={value} index={0} className={classes.radialBorder}>
|
||||
<BasicTable
|
||||
headCells={rolesHeadCells}
|
||||
records={rolesRecords}
|
||||
backgroundColor="#007AFF"
|
||||
color="#fff"
|
||||
>
|
||||
<TableBody>
|
||||
{rolesRecords &&
|
||||
rolesRecords.map((item) => (
|
||||
<StyledTableRow key={item.id}>
|
||||
<TableCell>
|
||||
<div className={classes.iconwrap}>
|
||||
<EditIcon className={classes.iconSize} />
|
||||
{item.name}
|
||||
</div>
|
||||
</TableCell>
|
||||
<TableCell>{item.permissions}</TableCell>
|
||||
<TableCell>{item.status}</TableCell>
|
||||
</StyledTableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</BasicTable>
|
||||
</TabPanel>
|
||||
<TabPanel value={value} index={1} className={classes.radialBorder}>
|
||||
<BasicTable
|
||||
id="user-list"
|
||||
headCells={userHeadCells}
|
||||
records={userRecords}
|
||||
backgroundColor="#007AFF"
|
||||
color="#fff"
|
||||
>
|
||||
{userRecords && userRecords.length > 0
|
||||
? <TableBody>
|
||||
{rowRenders}
|
||||
</TableBody> : 'No Records to Display'}
|
||||
</BasicTable>
|
||||
</TabPanel>
|
||||
<Grid>
|
||||
<PwTablePanel classes={classes} headCells={userHeadCells} id="user-list" index={0} loader={userLoader} dataFetched={userApiCompleted}
|
||||
records={userRecords} navUrl='/setup/users-access/edit-user' table="user" value={value} />
|
||||
<PwTablePanel classes={classes} headCells={rolesHeadCells} id="role-list" index={1} loader={roleLoader} dataFetched={roleApiCompleted}
|
||||
records={rolesRecords} navUrl='/setup/users-access/edit-role' table="role" value={value} />
|
||||
</Grid>
|
||||
</MDBox>
|
||||
</DashboardLayout>
|
||||
|
||||
@@ -29,6 +29,7 @@ function WarehouseScreen() {
|
||||
<DashboardLayout>
|
||||
<DashboardNavbar />
|
||||
<Breadcrumbs
|
||||
title="List of Warehouses"
|
||||
route={[
|
||||
{ name: 'Home', path: '/home' },
|
||||
{ name: 'Setup', path: '/setup' },
|
||||
|
||||
@@ -1,21 +1,33 @@
|
||||
import { Box, TableBody, TableCell, TableRow } from '@mui/material';
|
||||
import { Box, Grid, TableBody, TableCell, TableRow } from '@mui/material';
|
||||
import DashboardNavbar from 'components/DashboardNavbar';
|
||||
import DashboardLayout from 'layouts/DashboardLayout';
|
||||
import { makeStyles } from '@mui/styles';
|
||||
import OutlinedInput from '@mui/material/OutlinedInput';
|
||||
import MenuItem from '@mui/material/MenuItem';
|
||||
import Select from '@mui/material/Select';
|
||||
import React from 'react';
|
||||
import SearchBar from 'components/SearchBar';
|
||||
import React, { useState } from 'react';
|
||||
import BasicTable from 'components/BasicTable';
|
||||
import Barcodeimage from 'assets/images/barcode-number.png';
|
||||
import MDButton from 'components/Button';
|
||||
import Checkbox from '@mui/material/Checkbox';
|
||||
|
||||
const label = { inputProps: { 'aria-label': 'Checkbox demo' } };
|
||||
import Breadcrumbs from 'components/Breadcrumbs';
|
||||
import Dropdown from 'components/Dropdown';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { InventorySelectors } from 'redux/InventoryRedux';
|
||||
import WidgetActions from 'redux/WidgetRedux';
|
||||
import { API } from 'constant';
|
||||
import MDBox from 'components/MDBox';
|
||||
import { WidgetSelectors } from 'redux/WidgetRedux';
|
||||
import ProductActions from 'redux/ProductsRedux';
|
||||
import { ProductSelectors } from 'redux/ProductsRedux';
|
||||
import InventoryActions from 'redux/InventoryRedux';
|
||||
import QRcode from 'components/QRcode';
|
||||
|
||||
const useStyles = makeStyles({
|
||||
nodataStyle: {
|
||||
height: '200px',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
width: '600%'
|
||||
},
|
||||
labelSize: {
|
||||
fontSize: '16px',
|
||||
letterSpacing: '0.01em',
|
||||
@@ -32,69 +44,6 @@ const useStyles = makeStyles({
|
||||
margin: '52px 0px'
|
||||
}
|
||||
});
|
||||
const records = [
|
||||
{
|
||||
warehouse: 'Ipsum',
|
||||
zone: 'Vivera',
|
||||
area: 'Nisi',
|
||||
row: 'Nulla',
|
||||
label: 'Mauris',
|
||||
bay: 'Senectus',
|
||||
barcodenumber: '2085550112',
|
||||
barcodeimage: Barcodeimage
|
||||
},
|
||||
{
|
||||
warehouse: 'Ipsum',
|
||||
zone: 'Vivera',
|
||||
area: 'Nisi',
|
||||
row: 'Nulla',
|
||||
label: 'Mauris',
|
||||
bay: 'Senectus',
|
||||
barcodenumber: '2085550112',
|
||||
barcodeimage: Barcodeimage
|
||||
},
|
||||
{
|
||||
warehouse: 'Ipsum',
|
||||
zone: 'Vivera',
|
||||
area: 'Nisi',
|
||||
row: 'Nulla',
|
||||
label: 'Mauris',
|
||||
bay: 'Senectus',
|
||||
barcodenumber: '2085550112',
|
||||
barcodeimage: Barcodeimage
|
||||
}
|
||||
];
|
||||
|
||||
const recordsNew = [
|
||||
{
|
||||
warehouse: 'Ipsum',
|
||||
zone: 'Vivera',
|
||||
area: 'Nisi',
|
||||
barcodenumber: '2085550112',
|
||||
barcodeimage: Barcodeimage
|
||||
},
|
||||
{
|
||||
warehouse: 'Ipsum',
|
||||
zone: 'Vivera',
|
||||
area: 'Nisi',
|
||||
barcodenumber: '2085550112',
|
||||
barcodeimage: Barcodeimage
|
||||
},
|
||||
{
|
||||
warehouse: 'Ipsum',
|
||||
zone: 'Vivera',
|
||||
area: 'Nisi',
|
||||
barcodenumber: '2085550112',
|
||||
barcodeimage: Barcodeimage
|
||||
},
|
||||
{
|
||||
warehouse: 'Ipsum',
|
||||
zone: 'Vivera',
|
||||
area: 'Nisi',
|
||||
barcodenumber: '2085550112',
|
||||
barcodeimage: Barcodeimage
|
||||
}
|
||||
];
|
||||
|
||||
const headCells = [
|
||||
{
|
||||
@@ -110,15 +59,15 @@ const headCells = [
|
||||
label: 'Subfamily'
|
||||
},
|
||||
{
|
||||
id: 'Name',
|
||||
id: 'formalName',
|
||||
label: 'Name'
|
||||
},
|
||||
{
|
||||
id: 'Manufacture',
|
||||
id: 'manufacturer',
|
||||
label: 'Manufacture'
|
||||
},
|
||||
{
|
||||
id: 'Size',
|
||||
id: 'size',
|
||||
label: 'Size'
|
||||
},
|
||||
{
|
||||
@@ -136,11 +85,11 @@ const headCellsNew = [
|
||||
label: 'Inventory Name'
|
||||
},
|
||||
{
|
||||
id: 'Item Name',
|
||||
id: 'formalName',
|
||||
label: 'Item Name'
|
||||
},
|
||||
{
|
||||
id: 'Item Description',
|
||||
id: 'description',
|
||||
label: 'Item Description'
|
||||
},
|
||||
{
|
||||
@@ -152,24 +101,103 @@ const headCellsNew = [
|
||||
label: 'Barcode'
|
||||
}
|
||||
];
|
||||
|
||||
function WidgetLabel() {
|
||||
const classes = useStyles();
|
||||
const [personName, setPersonName] = React.useState([]);
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const handleChange = (event) => {
|
||||
const {
|
||||
target: { value }
|
||||
} = event;
|
||||
setPersonName(
|
||||
// On autofill we get a stringified value.
|
||||
typeof value === 'string' ? value.split(',') : value
|
||||
const [labelData, setLabelData] = useState([]);
|
||||
const [inventoryId, setInventoryId] = useState('');
|
||||
const [familyId, setFamilyId] = useState('');
|
||||
const [subFamilyId, setSubFamilyId] = useState('');
|
||||
const [allProductData, setAllProductData] = useState([]);
|
||||
const [filterClick, setFilterClick] = useState(false);
|
||||
|
||||
const inventoryData = useSelector(InventorySelectors.getInventoryDetail);
|
||||
const familyData = useSelector(WidgetSelectors.getWidgetFamiliesByInventoryId(inventoryId));
|
||||
const subFamilyData = useSelector(WidgetSelectors.getWidgetsByParentId(familyId));
|
||||
const productData = useSelector(ProductSelectors.getProductDetail);
|
||||
|
||||
React.useEffect(() => {
|
||||
dispatch(
|
||||
InventoryActions.getInventoryAction({
|
||||
loader: 'loading-request',
|
||||
slug: API.GET_INVENTORY,
|
||||
method: 'get'
|
||||
})
|
||||
);
|
||||
}, []);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (productData.result && filterClick) {
|
||||
setAllProductData(productData?.result);
|
||||
}
|
||||
}, [productData, filterClick]);
|
||||
|
||||
const inventoryChange = (event) => {
|
||||
const id = event.target.value;
|
||||
setInventoryId(id);
|
||||
setFamilyId('');
|
||||
setSubFamilyId('');
|
||||
dispatch(
|
||||
WidgetActions.widgetRequest({
|
||||
loader: 'loading-request',
|
||||
slug: `${API.GET_WIDGET_FAMILY_BY_INVENTORY}${id}`,
|
||||
method: 'get'
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
const familyChange = (event) => {
|
||||
const id = event.target.value;
|
||||
setFamilyId(id);
|
||||
setSubFamilyId('');
|
||||
dispatch(
|
||||
WidgetActions.widgetRequest({
|
||||
loader: 'loading-request',
|
||||
slug: `${API.GET_WIDGET_FAMILY_BY_INVENTORY}${id}`,
|
||||
method: 'get'
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
const subFamilyChange = (event) => {
|
||||
const id = event.target.value;
|
||||
setSubFamilyId(id);
|
||||
dispatch(
|
||||
WidgetActions.widgetRequest({
|
||||
loader: 'loading-request',
|
||||
slug: `${API.GET_WIDGET_FAMILY_BY_INVENTORY}${id}`,
|
||||
method: 'get'
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
const filterHandler = () => {
|
||||
setFilterClick(true);
|
||||
dispatch(
|
||||
ProductActions.getProductByIdAction({
|
||||
loader: 'loading-request',
|
||||
slug: `${API.GET_PRODUCT_BY_ID}${inventoryId}`,
|
||||
method: 'get'
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
const getTableItem = (e, item) => {
|
||||
if (e.target.checked) {
|
||||
setLabelData((prev) => [...prev, item]);
|
||||
} else {
|
||||
const filterData = labelData.filter((item2) => item2._id !== item._id);
|
||||
setLabelData(filterData);
|
||||
}
|
||||
};
|
||||
return (
|
||||
<>
|
||||
<DashboardLayout>
|
||||
<DashboardNavbar />
|
||||
<Breadcrumbs
|
||||
title="Search And Print Location Labels"
|
||||
route={[
|
||||
{ name: 'Home', path: '/home' },
|
||||
{ name: 'Setup', path: '/setup' },
|
||||
@@ -177,159 +205,104 @@ function WidgetLabel() {
|
||||
{ name: 'Widget Label' }
|
||||
]}
|
||||
/>
|
||||
<Box mx={3} my={3}>
|
||||
<MDBox px={5} py={5}>
|
||||
<Grid container spacing={2}>
|
||||
<Grid item xs={12} sm={6} md={3}>
|
||||
<Dropdown
|
||||
label="Select Inventory"
|
||||
dropdownData={inventoryData}
|
||||
value={inventoryId}
|
||||
onChange={inventoryChange}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12} sm={6} md={3}>
|
||||
<Dropdown
|
||||
label="Select Family"
|
||||
dropdownData={familyData}
|
||||
value={familyId}
|
||||
onChange={familyChange}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12} sm={6} md={3}>
|
||||
<Dropdown
|
||||
label="Select Sub Family"
|
||||
value={subFamilyId}
|
||||
dropdownData={subFamilyData}
|
||||
onChange={subFamilyChange}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12} sm={6} md={3}>
|
||||
<MDButton
|
||||
color="primary"
|
||||
sx={{ minWidth: '100%', marginTop: '50px', padding: '13px 40px' }}
|
||||
onClick={() => filterHandler()}
|
||||
>
|
||||
{'Filter'}
|
||||
</MDButton>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Box
|
||||
sx ={{
|
||||
display: 'grid',
|
||||
gridTemplateColumns: ' repeat(5, 1fr)',
|
||||
gridColumnGap :'20px'
|
||||
sx={{
|
||||
marginTop: '24px',
|
||||
backgroundColor: '#FFFFFF',
|
||||
overflowX: 'auto',
|
||||
overflowY: 'auto',
|
||||
height: '60vh'
|
||||
}}
|
||||
>
|
||||
<Box>
|
||||
<Box component="div" className={classes.labelSize}>
|
||||
Select Inventory
|
||||
</Box>
|
||||
<Box className={classes.customLabel}>
|
||||
<Select
|
||||
multiple
|
||||
displayEmpty
|
||||
value={personName}
|
||||
input={<OutlinedInput />}
|
||||
renderValue={(selected) => {
|
||||
if (selected.length === 0) {
|
||||
return 'Placeholder';
|
||||
}
|
||||
|
||||
return selected.join(', ');
|
||||
}}
|
||||
inputProps={{ 'aria-label': 'Without label' }}
|
||||
sx={{
|
||||
width: '100%'
|
||||
}}
|
||||
onChange={handleChange}
|
||||
>
|
||||
<MenuItem disabled value="">
|
||||
Placeholder
|
||||
</MenuItem>
|
||||
<MenuItem>Lorem Ipsum</MenuItem>
|
||||
</Select>
|
||||
</Box>
|
||||
</Box>
|
||||
<Box>
|
||||
<Box component="div" className={classes.labelSize}>
|
||||
Select Family
|
||||
</Box>
|
||||
<Box className={classes.customLabel}>
|
||||
<Select
|
||||
multiple
|
||||
displayEmpty
|
||||
value={personName}
|
||||
input={<OutlinedInput />}
|
||||
renderValue={(selected) => {
|
||||
if (selected.length === 0) {
|
||||
return 'Placeholder';
|
||||
}
|
||||
|
||||
return selected.join(', ');
|
||||
}}
|
||||
inputProps={{ 'aria-label': 'Without label' }}
|
||||
sx={{
|
||||
width: '100%'
|
||||
}}
|
||||
onChange={handleChange}
|
||||
>
|
||||
<MenuItem disabled value="">
|
||||
Placeholder
|
||||
</MenuItem>
|
||||
<MenuItem>Lorem Ipsum</MenuItem>
|
||||
</Select>
|
||||
</Box>
|
||||
</Box>
|
||||
<Box>
|
||||
<Box component="div" className={classes.labelSize}>
|
||||
Select Sub Family
|
||||
</Box>
|
||||
<Box className={classes.customLabel}>
|
||||
<Select
|
||||
multiple
|
||||
displayEmpty
|
||||
value={personName}
|
||||
input={<OutlinedInput />}
|
||||
renderValue={(selected) => {
|
||||
if (selected.length === 0) {
|
||||
return 'Placeholder';
|
||||
}
|
||||
|
||||
return selected.join(', ');
|
||||
}}
|
||||
inputProps={{ 'aria-label': 'Without label' }}
|
||||
sx={{
|
||||
width: '100%'
|
||||
}}
|
||||
onChange={handleChange}
|
||||
>
|
||||
<MenuItem disabled value="">
|
||||
Placeholder
|
||||
</MenuItem>
|
||||
<MenuItem>Lorem Ipsum</MenuItem>
|
||||
</Select>
|
||||
</Box>
|
||||
</Box>
|
||||
<Box>
|
||||
<Box component="div" className={classes.labelSize}>
|
||||
Search Keyword
|
||||
</Box>
|
||||
<Box className={classes.customLabel}>
|
||||
<SearchBar />
|
||||
</Box>
|
||||
</Box>
|
||||
<Box>
|
||||
<MDButton color="primary" sx={{ minWidth:'100%', marginTop:'30px', padding:'13px 40px' }} >{'Filter'}</MDButton>
|
||||
</Box>
|
||||
</Box>
|
||||
<Box sx={{ marginTop: '24px', backgroundColor: '#FFFFFF' }}>
|
||||
<BasicTable
|
||||
headCells={headCells}
|
||||
records={records}
|
||||
records={allProductData}
|
||||
backgroundColor="#E5E5E5"
|
||||
color="#8D8D8D"
|
||||
>
|
||||
<TableBody>
|
||||
{records &&
|
||||
records.map((item) => (
|
||||
{filterClick && allProductData.length ? (
|
||||
allProductData &&
|
||||
allProductData.map((item) => (
|
||||
<TableRow key={item.id}>
|
||||
<TableCell><Checkbox {...label} sx={{ marginRight:'2px' }} /> {item.warehouse}</TableCell>
|
||||
<TableCell>{item.zone}</TableCell>
|
||||
<TableCell>{item.area}</TableCell>
|
||||
<TableCell>{item.row}</TableCell>
|
||||
<TableCell>{item.label}</TableCell>
|
||||
<TableCell>{item.bay}</TableCell>
|
||||
<TableCell>{item.barcodenumber}</TableCell>
|
||||
<TableCell>
|
||||
<img src={item.barcodeimage} alt="img" width="200px" />
|
||||
<Checkbox
|
||||
{...label}
|
||||
sx={{ marginRight: '2px' }}
|
||||
onChange={(e) => getTableItem(e, item)}
|
||||
/>
|
||||
{item?.inventory?.name}
|
||||
</TableCell>
|
||||
<TableCell>{item?.widgetfamily?.name}</TableCell>
|
||||
<TableCell>{item?.location?.sub_levels}</TableCell>
|
||||
<TableCell>{item?.formalName}</TableCell>
|
||||
<TableCell>{item?.manufacturer}</TableCell>
|
||||
<TableCell>{item?.size}</TableCell>
|
||||
<TableCell>{item?._id}</TableCell>
|
||||
<TableCell>
|
||||
<QRcode payload={item._id} width={100} height={100} />
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
))
|
||||
) : (
|
||||
<TableRow className={classes.nodataStyle}>No Data</TableRow>
|
||||
)}
|
||||
</TableBody>
|
||||
</BasicTable>
|
||||
</Box>
|
||||
<Box sx={{ marginTop: '24px', backgroundColor: '#FFFFFF' }}>
|
||||
<BasicTable
|
||||
headCells={headCellsNew}
|
||||
records={records}
|
||||
records={labelData}
|
||||
backgroundColor="#E5E5E5"
|
||||
color="#8D8D8D"
|
||||
>
|
||||
<TableBody>
|
||||
{recordsNew &&
|
||||
recordsNew.map((item) => (
|
||||
{labelData &&
|
||||
labelData.map((item) => (
|
||||
<TableRow key={item.id}>
|
||||
<TableCell>{item.warehouse}</TableCell>
|
||||
<TableCell>{item.zone}</TableCell>
|
||||
<TableCell>{item.area}</TableCell>
|
||||
<TableCell>{item.barcodenumber}</TableCell>
|
||||
<TableCell>{item?.inventory?.name}</TableCell>
|
||||
<TableCell>{item.formalName}</TableCell>
|
||||
<TableCell>{item.description}</TableCell>
|
||||
<TableCell>{item._id}</TableCell>
|
||||
<TableCell>
|
||||
<img src={item.barcodeimage} alt="img" width="200px" />
|
||||
<QRcode payload={item._id} width={100} height={100} />
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
@@ -339,7 +312,7 @@ function WidgetLabel() {
|
||||
<div className={classes.buttondiv}>
|
||||
<MDButton color="primary">{'Print Labels'}</MDButton>
|
||||
</div>
|
||||
</Box>
|
||||
</MDBox>
|
||||
</DashboardLayout>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -13,6 +13,8 @@ const { Types, Creators } = createActions({
|
||||
addInventoryFailure: ['error'],
|
||||
updateInventoryAction: ['payload'],
|
||||
updateInventorySuccess: ['data'],
|
||||
deleteInventoryAction: ['payload'],
|
||||
deleteInventorySuccess: ['data'],
|
||||
updateInventoryFailure: ['error'],
|
||||
getInventoryTypesAction: ['payload'],
|
||||
getInventoryTypesSuccess: ['data'],
|
||||
@@ -98,6 +100,21 @@ export const onUpdateInventorySuccess = (state, { data }) =>
|
||||
]
|
||||
});
|
||||
|
||||
export const onDeleteInventoryAction = (state, { payload }) =>
|
||||
state.merge({
|
||||
fetching: _.uniq([state.fetching, payload?.loader]),
|
||||
error: getErrorValue(state?.error, payload?.loader)
|
||||
});
|
||||
|
||||
export const onDeleteInventorySuccess = (state, { data }) =>
|
||||
state.merge({
|
||||
fetching: getFetchingValue(state.fetching, data?.loader),
|
||||
error: getErrorValue(state?.error, data?.loader),
|
||||
getInventoryDetail: data.deletedInventoryID
|
||||
? [...state.getInventoryDetail.filter((x) => x._id !== data.deletedInventoryID)]
|
||||
: state.getInventoryDetail
|
||||
});
|
||||
|
||||
export const onUpdateInventoryFailure = (state, { error }) =>
|
||||
state.merge({
|
||||
fetching: _.without(state.fetching, error?.loader),
|
||||
@@ -133,6 +150,8 @@ export const inventoryReducer = createReducer(INITIAL_STATE, {
|
||||
[Types.ADD_INVENTORY_FAILURE]: onAddInventoryFailure,
|
||||
[Types.UPDATE_INVENTORY_ACTION]: onUpdateInventoryAction,
|
||||
[Types.UPDATE_INVENTORY_SUCCESS]: onUpdateInventorySuccess,
|
||||
[Types.DELETE_INVENTORY_ACTION]: onDeleteInventoryAction,
|
||||
[Types.DELETE_INVENTORY_SUCCESS]: onDeleteInventorySuccess,
|
||||
[Types.UPDATE_INVENTORY_FAILURE]: onUpdateInventoryFailure,
|
||||
[Types.GET_INVENTORY_TYPES_ACTION]: onGetInventoryTypesAction,
|
||||
[Types.GET_INVENTORY_TYPES_SUCCESS]: onGetInventoryTypesSuccess,
|
||||
|
||||
@@ -12,6 +12,8 @@ const { Types, Creators } = createActions({
|
||||
addItemSuccess: ['data'],
|
||||
editItemRequest: ['payload'],
|
||||
editItemSuccess: ['data'],
|
||||
deleteItemRequest: ['payload'],
|
||||
deleteItemSuccess: ['data'],
|
||||
oneItemRequest: ['payload'],
|
||||
oneItemSuccess: ['data']
|
||||
});
|
||||
@@ -91,6 +93,18 @@ export const onEditItemSuccess = (state, { data }) =>
|
||||
item: null
|
||||
});
|
||||
|
||||
export const onDeleteItemRequest = (state, { payload }) =>
|
||||
state.merge({
|
||||
fetching: _.uniq([...state.fetching, payload?.loader]),
|
||||
error: getErrorValue(state?.error, payload?.loader)
|
||||
});
|
||||
|
||||
export const onDeleteItemSuccess = (state, { data }) =>
|
||||
state.merge({
|
||||
fetching: getFetchingValue(state.fetching, data?.loader),
|
||||
error: getErrorValue(state?.error, data?.loader)
|
||||
});
|
||||
|
||||
export const onItemFailure = (state, { error }) =>
|
||||
state.merge({
|
||||
fetching: _.without(state.fetching, error?.loader),
|
||||
@@ -106,6 +120,8 @@ export const itemReducer = createReducer(INITIAL_STATE, {
|
||||
[Types.ADD_ITEM_SUCCESS]: onAddItemSuccess,
|
||||
[Types.EDIT_ITEM_REQUEST]: onEditItemRequest,
|
||||
[Types.EDIT_ITEM_SUCCESS]: onEditItemSuccess,
|
||||
[Types.DELETE_ITEM_REQUEST]: onDeleteItemRequest,
|
||||
[Types.DELETE_ITEM_SUCCESS]: onDeleteItemSuccess,
|
||||
[Types.ONE_ITEM_REQUEST]: onOneItemRequest,
|
||||
[Types.ONE_ITEM_SUCCESS]: onOneItemSuccess
|
||||
});
|
||||
|
||||
54
src/redux/LabellingRedux.js
Normal file
54
src/redux/LabellingRedux.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({
|
||||
getLabelAction: ['payload'],
|
||||
getLabelSuccess: ['data'],
|
||||
getLabelFailure: ['error']
|
||||
});
|
||||
|
||||
export const LabellingTypes = Types;
|
||||
const LabellingActions = Creators;
|
||||
export default LabellingActions;
|
||||
|
||||
/* ------------- Initial State ------------- */
|
||||
export const INITIAL_STATE = Immutable({
|
||||
getLabelDetail: [],
|
||||
getLabelLoading: false,
|
||||
getLabelerror: {}
|
||||
});
|
||||
|
||||
/* ------------- Selectors ------------- */
|
||||
export const LabellingSelectors = {
|
||||
getLabelDetail: (state) => state.labelling.getLabelDetail
|
||||
};
|
||||
|
||||
/* ------------- Reducers ------------- */
|
||||
export const onGetLabelAction = (state, { payload }) =>
|
||||
state.merge({
|
||||
fetching: _.uniq([state.fetching, payload?.loader]),
|
||||
error: getErrorValue(state?.error, payload?.loader)
|
||||
});
|
||||
|
||||
export const onGetLabelSuccess = (state, { data }) =>
|
||||
state.merge({
|
||||
fetching: getFetchingValue(state.fetching, data?.loader),
|
||||
error: getErrorValue(state?.error, data?.loader),
|
||||
getLabelDetail: data.getLabelDetail
|
||||
});
|
||||
|
||||
export const onGetLabelFailure = (state, { error }) =>
|
||||
state.merge({
|
||||
fetching: _.without(state.fetching, error?.loader),
|
||||
error: { ...state.error, [error?.loader]: error?.error }
|
||||
});
|
||||
|
||||
/* ------------- Hookup Reducers To Types ------------- */
|
||||
export const labellingReducer = createReducer(INITIAL_STATE, {
|
||||
[Types.GET_LABEL_ACTION]: onGetLabelAction,
|
||||
[Types.GET_LABEL_SUCCESS]: onGetLabelSuccess,
|
||||
[Types.GET_LABEL_FAILURE]: onGetLabelFailure
|
||||
});
|
||||
@@ -5,6 +5,9 @@ import { getFetchingValue, getErrorValue } from '../services/Utils';
|
||||
|
||||
/* ------------- Types and Action Creators ------------- */
|
||||
const { Types, Creators } = createActions({
|
||||
getProductByIdAction: ['payload'],
|
||||
getProductByIdSuccess: ['data'],
|
||||
getProductByIdFailure: ['error'],
|
||||
addProductAction: ['payload'],
|
||||
addProductSuccess: ['data'],
|
||||
addProductFailure: ['error']
|
||||
@@ -18,15 +21,35 @@ export default ProductActions;
|
||||
export const INITIAL_STATE = Immutable({
|
||||
addProductDetail: [],
|
||||
addProductLoading: false,
|
||||
addProducterror: {}
|
||||
addProducterror: {},
|
||||
getProductByIdDetail: []
|
||||
});
|
||||
|
||||
/* ------------- Selectors ------------- */
|
||||
export const ProductSelectors = {
|
||||
addProductDetail: (state) => state.product.productDetail
|
||||
addProductDetail: (state) => state.product.productDetail,
|
||||
getProductDetail: (state) => state.product.getProductByIdDetail
|
||||
};
|
||||
|
||||
/* ------------- Reducers ------------- */
|
||||
export const onGetProductByIdAction = (state, { payload }) =>
|
||||
state.merge({
|
||||
fetching: _.uniq([state.fetching, payload?.loader]),
|
||||
error: getErrorValue(state?.error, payload?.loader)
|
||||
});
|
||||
|
||||
export const onGetProductByIdSuccess = (state, { data }) =>
|
||||
state.merge({
|
||||
fetching: getFetchingValue(state.fetching, data?.loader),
|
||||
error: getErrorValue(state?.error, data?.loader),
|
||||
getProductByIdDetail: data.getProductByIdDetail
|
||||
});
|
||||
|
||||
export const onGetProductByIdFailure = (state, { error }) =>
|
||||
state.merge({
|
||||
fetching: _.without(state.fetching, error?.loader),
|
||||
error: { ...state.error, [error?.loader]: error?.error }
|
||||
});
|
||||
export const onAddProductAction = (state, { payload }) =>
|
||||
state.merge({
|
||||
fetching: _.uniq([state.fetching, payload?.loader]),
|
||||
@@ -48,6 +71,10 @@ export const onAddProductFailure = (state, { error }) =>
|
||||
|
||||
/* ------------- Hookup Reducers To Types ------------- */
|
||||
export const productReducer = createReducer(INITIAL_STATE, {
|
||||
[Types.GET_PRODUCT_BY_ID_ACTION]: onGetProductByIdAction,
|
||||
[Types.GET_PRODUCT_BY_ID_SUCCESS]: onGetProductByIdSuccess,
|
||||
[Types.GET_PRODUCT_BY_ID_FAILURE]: onGetProductByIdFailure,
|
||||
[Types.ADD_PRODUCT_FAILURE]: onAddProductFailure,
|
||||
[Types.ADD_PRODUCT_ACTION]: onAddProductAction,
|
||||
[Types.ADD_PRODUCT_SUCCESS]: onAddProductSuccess,
|
||||
[Types.ADD_PRODUCT_FAILURE]: onAddProductFailure
|
||||
|
||||
@@ -15,7 +15,10 @@ const { Types, Creators } = createActions({
|
||||
|
||||
editWarehouseAction: ['payload'],
|
||||
editWarehouseSuccess: ['data'],
|
||||
editWarehouseFailure: ['error']
|
||||
editWarehouseFailure: ['error'],
|
||||
|
||||
deleteWarehouseAction: ['payload'],
|
||||
deleteWarehouseSuccess: ['data']
|
||||
});
|
||||
|
||||
export const WarehouseTypes = Types;
|
||||
@@ -96,6 +99,21 @@ export const onEditWarehouseSuccess = (state, { data }) =>
|
||||
]
|
||||
});
|
||||
|
||||
export const onDeleteWarehouseAction = (state, { payload }) =>
|
||||
state.merge({
|
||||
fetching: _.uniq([state.fetching, payload?.loader]),
|
||||
error: getErrorValue(state?.error, payload?.loader)
|
||||
});
|
||||
|
||||
export const onDeleteWarehouseSuccess = (state, { data }) =>
|
||||
state.merge({
|
||||
fetching: getFetchingValue(state.fetching, data?.loader),
|
||||
error: getErrorValue(state?.error, data?.loader),
|
||||
warehouseDetail: data?.deletedWarehouseID
|
||||
? [...state.warehouseDetail.filter((x) => x._id !== data?.deletedWarehouseID)]
|
||||
: state.warehouseDetail
|
||||
});
|
||||
|
||||
export const onEditWarehouseFailure = (state, { error }) =>
|
||||
state.merge({
|
||||
fetching: _.without(state.fetching, error?.loader),
|
||||
@@ -113,5 +131,7 @@ export const warehouseReducer = createReducer(INITIAL_STATE, {
|
||||
|
||||
[Types.EDIT_WAREHOUSE_ACTION]: onEditWarehouseAction,
|
||||
[Types.EDIT_WAREHOUSE_SUCCESS]: onEditWarehouseSuccess,
|
||||
[Types.EDIT_WAREHOUSE_FAILURE]: onEditWarehouseFailure
|
||||
[Types.EDIT_WAREHOUSE_FAILURE]: onEditWarehouseFailure,
|
||||
[Types.DELETE_WAREHOUSE_ACTION]: onDeleteWarehouseAction,
|
||||
[Types.DELETE_WAREHOUSE_SUCCESS]: onDeleteWarehouseSuccess
|
||||
});
|
||||
|
||||
@@ -8,6 +8,7 @@ import { rolesReducer } from './RolesRedux';
|
||||
import { permissionsReducer } from './PermissionsRedux';
|
||||
import { WarehouseLocationsReducer } from './WarehouseLocationsRedux';
|
||||
import { widgetReducer } from './WidgetRedux';
|
||||
import { labellingReducer } from './LabellingRedux';
|
||||
import { itemReducer } from './ItemRedux';
|
||||
|
||||
// Combine all reducers.
|
||||
@@ -21,6 +22,7 @@ const appReducer = combineReducers({
|
||||
product: productReducer,
|
||||
inventory: inventoryReducer,
|
||||
widgets: widgetReducer,
|
||||
labelling: labellingReducer,
|
||||
items: itemReducer
|
||||
});
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ import NewWarehouseDetails from 'pages/newWarehouseDetails';
|
||||
import EditWarehouseDetails from 'pages/editWarehouseDetails';
|
||||
import LabelingHome from 'pages/labellingHome';
|
||||
import SetupInventory from 'pages/setupInventory';
|
||||
import CreateUserRole from 'pages/createUserRole';
|
||||
import CreateEditUserRole from 'pages/createEditUserRole';
|
||||
import CreateEditUser from 'pages/createEditUser';
|
||||
import WidgetLabel from 'pages/widgetLabel';
|
||||
import ItemListing from 'pages/itemListing';
|
||||
@@ -114,22 +114,21 @@ const protectedRoutes = [
|
||||
name: 'Add New Item',
|
||||
key: 'add-new-item',
|
||||
hide: true,
|
||||
route: '/setup/inventory/new-item/:widgetName/:inventoryId',
|
||||
route: '/setup/inventory/new-item/:inventoryName/:widgetName/:inventoryId',
|
||||
component: <AddNewItem />
|
||||
},
|
||||
{
|
||||
name: 'Update Item',
|
||||
key: 'udpate-item',
|
||||
hide: true,
|
||||
route: '/setup/inventory/browse/:widgetName/:inventoryId/edit/:itemId',
|
||||
route: '/setup/inventory/browse/:inventoryName/:widgetName/:inventoryId/edit/:itemId',
|
||||
component: <AddNewItem />
|
||||
},
|
||||
// /setup/inventory/browse/${payload?.widgetName}/${payload?.inventoryId}/edit/${payload?.id}
|
||||
{
|
||||
name: 'View Items',
|
||||
key: 'view-items',
|
||||
hide: true,
|
||||
route: '/setup/inventory/browse/:widgetName/:inventoryId',
|
||||
route: '/setup/inventory/browse/:inventoryName/:widgetName/:inventoryId',
|
||||
component: <ItemListing />
|
||||
},
|
||||
{
|
||||
@@ -177,21 +176,28 @@ const protectedRoutes = [
|
||||
key: 'create-role',
|
||||
route: '/setup/users-access/create-role',
|
||||
hide: true,
|
||||
component: <CreateUserRole />
|
||||
component: <CreateEditUserRole />
|
||||
},
|
||||
{
|
||||
name: 'Create User',
|
||||
key: 'create-user',
|
||||
route: '/setup/users-access/create-user',
|
||||
hide: true,
|
||||
component: <CreateEditUser context='new' />
|
||||
component: <CreateEditUser context="new" />
|
||||
},
|
||||
{
|
||||
name: 'Edot User',
|
||||
name: 'Edit User',
|
||||
key: 'edit-user',
|
||||
route: '/setup/users-access/edit-user',
|
||||
hide: true,
|
||||
component: <CreateEditUser context='edit' />
|
||||
},
|
||||
{
|
||||
name: 'Edit Role',
|
||||
key: 'edit-role',
|
||||
route: '/setup/users-access/edit-role',
|
||||
hide: true,
|
||||
component: <CreateEditUserRole context='edit' />
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -63,7 +63,9 @@ export function* onRequestAddInventoryData({ payload }) {
|
||||
payload?.data
|
||||
);
|
||||
if (response?.status === 200) {
|
||||
toast('New inventory added');
|
||||
toast.success('New inventory added', {
|
||||
theme: 'colored'
|
||||
});
|
||||
yield put(
|
||||
InventoryActions.addInventorySuccess({
|
||||
loader: payload?.loader,
|
||||
@@ -72,7 +74,9 @@ export function* onRequestAddInventoryData({ payload }) {
|
||||
);
|
||||
payload.navigateTo();
|
||||
} else {
|
||||
toast('Failed to add inventory');
|
||||
toast.error('Failed to add inventory', {
|
||||
theme: 'colored'
|
||||
});
|
||||
payload.onFailedAddInventoryData(response.data.error);
|
||||
yield put(
|
||||
InventoryActions.addInventoryFailure({
|
||||
@@ -91,16 +95,20 @@ export function* onRequestUpdateInventoryData({ payload }) {
|
||||
payload?.data
|
||||
);
|
||||
if (response?.status === 200) {
|
||||
toast('Updated inventory successfully');
|
||||
toast.success('Updated inventory successfully', {
|
||||
theme: 'colored'
|
||||
});
|
||||
yield put(
|
||||
InventoryActions.updateInventorySuccess({
|
||||
loader: payload?.loader,
|
||||
updateInventory: response?.data?.data
|
||||
})
|
||||
);
|
||||
payload.navigateTo();
|
||||
// payload.navigateTo();
|
||||
} else {
|
||||
toast('Failed to update inventory');
|
||||
toast.error('Failed to update inventory', {
|
||||
theme: 'colored'
|
||||
});
|
||||
yield put(
|
||||
InventoryActions.updateInventoryFailure({
|
||||
loader: payload?.loader,
|
||||
@@ -109,9 +117,37 @@ export function* onRequestUpdateInventoryData({ payload }) {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export function* onRequestDeleteInventoryData({ payload }) {
|
||||
const response = yield call(ApiServices[payload?.method], AuthorizedAPI, payload?.slug);
|
||||
if (response?.status === 200) {
|
||||
toast.success('Deleted inventory successfully', {
|
||||
theme: 'colored'
|
||||
});
|
||||
payload.navigateTo();
|
||||
yield put(
|
||||
InventoryActions.deleteInventorySuccess({
|
||||
loader: payload?.loader,
|
||||
deletedInventoryID: payload?.inventoryId
|
||||
})
|
||||
);
|
||||
} else {
|
||||
toast.error('Failed to delete inventory', {
|
||||
theme: 'colored'
|
||||
});
|
||||
yield put(
|
||||
InventoryActions.updateInventoryFailure({
|
||||
loader: payload?.loader,
|
||||
error: response?.data
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default [
|
||||
takeEvery(InventoryTypes.GET_INVENTORY_ACTION, onRequestGetInventoryData),
|
||||
takeEvery(InventoryTypes.ADD_INVENTORY_ACTION, onRequestAddInventoryData),
|
||||
takeEvery(InventoryTypes.DELETE_INVENTORY_ACTION, onRequestDeleteInventoryData),
|
||||
takeEvery(InventoryTypes.UPDATE_INVENTORY_ACTION, onRequestUpdateInventoryData),
|
||||
takeEvery(InventoryTypes.GET_INVENTORY_TYPES_ACTION, onRequestGetInventoryTypesData)
|
||||
];
|
||||
|
||||
@@ -50,7 +50,9 @@ export function* onRequestOneItem({ payload }) {
|
||||
// `/setup/inventory/browse/${payload?.widgetName}/${payload?.inventoryId}/edit/${payload?.itemId}`
|
||||
// );
|
||||
} else {
|
||||
toast('Failed to get item details');
|
||||
toast.error('Failed to get item details', {
|
||||
theme: 'colored'
|
||||
});
|
||||
yield put(
|
||||
ItemActions.itemFailure({
|
||||
loader: payload?.loader,
|
||||
@@ -100,7 +102,9 @@ export function* onAddRequestItem({ payload }) {
|
||||
createFormData(payload?.data)
|
||||
);
|
||||
if (response?.status === 200) {
|
||||
toast(`Added item: ${payload.data.commonName}`);
|
||||
toast.success(`Added item: ${payload.data.commonName}`, {
|
||||
theme: 'colored'
|
||||
});
|
||||
// payload.navigateTo(
|
||||
// `/setup/inventory/browse/${payload?.widgetName}/${payload?.inventoryId}/edit/${response?.data?.data?._id}`
|
||||
// );
|
||||
@@ -112,7 +116,9 @@ export function* onAddRequestItem({ payload }) {
|
||||
})
|
||||
);
|
||||
} else {
|
||||
toast('Failed to add item');
|
||||
toast.error('Failed to add item', {
|
||||
theme: 'colored'
|
||||
});
|
||||
yield put(
|
||||
ItemActions.itemFailure({
|
||||
loader: payload?.loader,
|
||||
@@ -130,7 +136,9 @@ export function* onEditRequestItem({ payload }) {
|
||||
createFormData(payload?.data)
|
||||
);
|
||||
if (response?.status === 200) {
|
||||
toast(`Successfully edited item: ${payload.data.commonName}`);
|
||||
toast.success(`Successfully edited item: ${payload.data.commonName}`, {
|
||||
theme: 'colored'
|
||||
});
|
||||
payload.navigateTo('/setup/inventory');
|
||||
yield put(
|
||||
ItemActions.addItemSuccess({
|
||||
@@ -139,7 +147,39 @@ export function* onEditRequestItem({ payload }) {
|
||||
})
|
||||
);
|
||||
} else {
|
||||
toast('Failed to edit item');
|
||||
toast.error('Failed to edit item', {
|
||||
theme: 'colored'
|
||||
});
|
||||
yield put(
|
||||
ItemActions.itemFailure({
|
||||
loader: payload?.loader,
|
||||
error: response?.data
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export function* onDeleteRequestItem({ payload }) {
|
||||
const response = yield call(
|
||||
ApiServices[payload?.method],
|
||||
AuthorizedAPI,
|
||||
payload?.slug + payload?.itemId
|
||||
);
|
||||
if (response?.status === 200) {
|
||||
toast.success('Successfully deleted item', {
|
||||
theme: 'colored'
|
||||
});
|
||||
payload.refreshDispatch();
|
||||
yield put(
|
||||
ItemActions.deleteItemSuccess({
|
||||
loader: payload?.loader,
|
||||
item: response?.data?.data
|
||||
})
|
||||
);
|
||||
} else {
|
||||
toast.error('Failed to delete item', {
|
||||
theme: 'colored'
|
||||
});
|
||||
yield put(
|
||||
ItemActions.itemFailure({
|
||||
loader: payload?.loader,
|
||||
@@ -153,5 +193,6 @@ export default [
|
||||
takeEvery(ItemTypes.ITEM_REQUEST, onRequestItem),
|
||||
takeEvery(ItemTypes.ONE_ITEM_REQUEST, onRequestOneItem),
|
||||
takeEvery(ItemTypes.ADD_ITEM_REQUEST, onAddRequestItem),
|
||||
takeEvery(ItemTypes.EDIT_ITEM_REQUEST, onEditRequestItem)
|
||||
takeEvery(ItemTypes.EDIT_ITEM_REQUEST, onEditRequestItem),
|
||||
takeEvery(ItemTypes.DELETE_ITEM_REQUEST, onDeleteRequestItem)
|
||||
];
|
||||
|
||||
31
src/sagas/Labelling.js
Normal file
31
src/sagas/Labelling.js
Normal file
@@ -0,0 +1,31 @@
|
||||
import { AuthorizedAPI } from 'config';
|
||||
import { call, put, takeEvery } from 'redux-saga/effects';
|
||||
import LabellingActions from 'redux/LabellingRedux';
|
||||
import { LabellingTypes } from 'redux/LabellingRedux';
|
||||
import ApiServices from 'services/API/ApiServices';
|
||||
|
||||
export function* onRequestGetLabelData({ payload }) {
|
||||
const response = yield call(
|
||||
ApiServices[payload?.method],
|
||||
AuthorizedAPI,
|
||||
payload?.slug,
|
||||
payload?.data
|
||||
);
|
||||
if (response?.status === 200) {
|
||||
yield put(
|
||||
LabellingActions.getLabelSuccess({
|
||||
loader: payload?.loader,
|
||||
getLabelDetail: response?.data?.data
|
||||
})
|
||||
);
|
||||
} else {
|
||||
payload.onFailedGetLabelData(response.data.error);
|
||||
yield put(
|
||||
LabellingActions.getLabelFailure({
|
||||
loader: payload?.loader,
|
||||
error: response?.data
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
export default [takeEvery(LabellingTypes.GET_LABEL_ACTION, onRequestGetLabelData)];
|
||||
@@ -28,4 +28,32 @@ export function* onRequestAddProductData({ payload }) {
|
||||
);
|
||||
}
|
||||
}
|
||||
export default [takeLatest(ProductTypes.ADD_PRODUCT_ACTION, onRequestAddProductData)];
|
||||
|
||||
export function* onRequestGetProductById({ payload }) {
|
||||
const response = yield call(
|
||||
ApiServices[payload?.method],
|
||||
AuthorizedAPI,
|
||||
payload?.slug,
|
||||
payload?.data
|
||||
);
|
||||
if (response?.status === 200) {
|
||||
yield put(
|
||||
ProductActions.getProductByIdSuccess({
|
||||
loader: payload?.loader,
|
||||
getProductByIdDetail: response?.data?.data
|
||||
})
|
||||
);
|
||||
} else {
|
||||
payload.onFailedGetProductById(response.data.error);
|
||||
yield put(
|
||||
ProductActions.getProductByIdFailure({
|
||||
loader: payload?.loader,
|
||||
error: response?.data
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
export default [
|
||||
takeLatest(ProductTypes.ADD_PRODUCT_ACTION, onRequestAddProductData),
|
||||
takeLatest(ProductTypes.GET_PRODUCT_BY_ID_ACTION, onRequestGetProductById)
|
||||
];
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { AuthorizedAPI } from 'config';
|
||||
import { takeLatest, call, put } from 'redux-saga/effects';
|
||||
import { toast } from 'react-toastify';
|
||||
import RolesActions, { RolesTypes } from '../redux/RolesRedux';
|
||||
import ApiServices from 'services/API/ApiServices';
|
||||
|
||||
@@ -10,6 +11,7 @@ export function* onRequestRolesData({ payload }) {
|
||||
payload?.slug,
|
||||
payload?.data
|
||||
);
|
||||
payload?.callback && payload?.callback();
|
||||
if (response?.status === 200) {
|
||||
yield put(
|
||||
RolesActions.getRolesSuccess({
|
||||
@@ -18,6 +20,7 @@ export function* onRequestRolesData({ payload }) {
|
||||
})
|
||||
);
|
||||
} else {
|
||||
toast('Failed to fetch roles');
|
||||
payload.onFailedRolesData(response.data.error);
|
||||
yield put(
|
||||
RolesActions.getRolesFailure({
|
||||
|
||||
@@ -11,6 +11,7 @@ export function* onRequestUsersData({ payload }) {
|
||||
payload?.slug,
|
||||
payload?.data
|
||||
);
|
||||
payload?.callback && payload?.callback();
|
||||
if (response?.status === 200) {
|
||||
yield put(
|
||||
UsersActions.getUsersSuccess({
|
||||
@@ -19,6 +20,7 @@ export function* onRequestUsersData({ payload }) {
|
||||
})
|
||||
);
|
||||
} else {
|
||||
toast('Failed to fetch user list');
|
||||
payload.onFailedUsersData(response.data.error);
|
||||
yield put(
|
||||
UsersActions.getUsersFailure({
|
||||
@@ -34,8 +36,13 @@ export function* onCreateUserData({ payload }) {
|
||||
ApiServices[payload?.method],
|
||||
AuthorizedAPI,
|
||||
payload?.slug,
|
||||
payload?.data
|
||||
payload?.data,
|
||||
{
|
||||
processData: false,
|
||||
contentType: false
|
||||
}
|
||||
);
|
||||
payload?.callback && payload?.callback(false);
|
||||
if (response?.status === 200) {
|
||||
const data = response.data?.data;
|
||||
const msg = payload.toastMessage.replace('__placeholder__', data && data.fullName ? '"' + data.fullName + '" ' : '');
|
||||
@@ -48,8 +55,9 @@ export function* onCreateUserData({ payload }) {
|
||||
})
|
||||
);
|
||||
} else {
|
||||
toast('Something went wrong!');
|
||||
payload.onValidationFailed(response.data?.error);
|
||||
const error = response?.originalError?.response?.data?.error;
|
||||
toast(error && error.indexOf('E11000') > -1 ? 'Email already exists!' : 'Something went wrong!');
|
||||
payload.onValidationFailed();
|
||||
yield put(
|
||||
UsersActions.createUserFailure({
|
||||
loader: payload?.loader,
|
||||
|
||||
@@ -39,7 +39,7 @@ const makeFormData = (data) => {
|
||||
data.preferredInventories.forEach((prefInv, idx) => {
|
||||
formData.append(`preferredInventories[${idx}]`, prefInv);
|
||||
});
|
||||
if (data.image[0].file) formData.append('image', data.image[0].file);
|
||||
if (data.image[0]?.file) formData.append('image', data.image[0].file);
|
||||
return formData;
|
||||
};
|
||||
|
||||
@@ -52,7 +52,9 @@ export function* onRequestCreateWarehouse({ payload }) {
|
||||
);
|
||||
if (response?.status === 200 && response?.data?.message) {
|
||||
const warehouse = response?.data?.message;
|
||||
toast('Warehouse created successfully');
|
||||
toast.success('Warehouse created successfully', {
|
||||
theme: 'colored'
|
||||
});
|
||||
yield put(
|
||||
WarehouseActions.createWarehouseSuccess({
|
||||
loader: payload?.loader,
|
||||
@@ -64,7 +66,9 @@ export function* onRequestCreateWarehouse({ payload }) {
|
||||
);
|
||||
payload.navigateTo(response?.data?.message?._id);
|
||||
} else {
|
||||
toast('Failed to create warehouse');
|
||||
toast.error('Failed to create warehouse', {
|
||||
theme: 'colored'
|
||||
});
|
||||
yield put(
|
||||
WarehouseActions.createWarehouseFailure({
|
||||
loader: payload?.loader,
|
||||
@@ -82,7 +86,9 @@ export function* onRequestEditWarehouse({ payload }) {
|
||||
makeFormData(payload?.data)
|
||||
);
|
||||
if (response?.status === 200 && response?.data?.data) {
|
||||
toast('Warehouse edited successfully');
|
||||
toast.success('Warehouse edited successfully', {
|
||||
theme: 'colored'
|
||||
});
|
||||
const warehouse = response?.data?.data;
|
||||
yield put(
|
||||
WarehouseActions.editWarehouseSuccess({
|
||||
@@ -94,7 +100,39 @@ export function* onRequestEditWarehouse({ payload }) {
|
||||
})
|
||||
);
|
||||
} else {
|
||||
toast('Failed to edit warehouse');
|
||||
toast.error('Failed to edit warehouse', {
|
||||
theme: 'colored'
|
||||
});
|
||||
yield put(
|
||||
WarehouseActions.editWarehouseFailure({
|
||||
loader: payload?.loader,
|
||||
error: response?.data
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export function* onRequestDeleteWarehouse({ payload }) {
|
||||
const response = yield call(
|
||||
ApiServices[payload?.method],
|
||||
AuthorizedAPI,
|
||||
payload?.slug + payload?.warehouseId
|
||||
);
|
||||
if (response?.status === 200) {
|
||||
toast.success('Warehouse deleted successfully', {
|
||||
theme: 'colored'
|
||||
});
|
||||
payload.navigateTo('/setup/warehouse');
|
||||
yield put(
|
||||
WarehouseActions.deleteWarehouseSuccess({
|
||||
loader: payload?.loader,
|
||||
deletedWarehouseID: payload?.warehouseId
|
||||
})
|
||||
);
|
||||
} else {
|
||||
toast.error('Failed to delete warehouse', {
|
||||
theme: 'colored'
|
||||
});
|
||||
yield put(
|
||||
WarehouseActions.editWarehouseFailure({
|
||||
loader: payload?.loader,
|
||||
@@ -107,5 +145,6 @@ export function* onRequestEditWarehouse({ payload }) {
|
||||
export default [
|
||||
takeLatest(WarehouseTypes.WAREHOUSE_DATA_ACTION, onRequestWarehouseData),
|
||||
takeLatest(WarehouseTypes.CREATE_WAREHOUSE_ACTION, onRequestCreateWarehouse),
|
||||
takeLatest(WarehouseTypes.EDIT_WAREHOUSE_ACTION, onRequestEditWarehouse)
|
||||
takeLatest(WarehouseTypes.EDIT_WAREHOUSE_ACTION, onRequestEditWarehouse),
|
||||
takeLatest(WarehouseTypes.DELETE_WAREHOUSE_ACTION, onRequestDeleteWarehouse)
|
||||
];
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { AuthorizedAPI } from 'config';
|
||||
import { toast } from 'react-toastify';
|
||||
import { call, put, takeEvery } from 'redux-saga/effects';
|
||||
import WarehouseLocationsActions from 'redux/WarehouseLocationsRedux';
|
||||
import { WarehouseLocationsTypes } from 'redux/WarehouseLocationsRedux';
|
||||
@@ -42,6 +43,9 @@ export function* onAddRequestLocation({ payload }) {
|
||||
);
|
||||
LOGGER.log('add response', response.data);
|
||||
if (response?.status === 200) {
|
||||
toast.success('Location created successfully', {
|
||||
theme: 'colored'
|
||||
});
|
||||
yield put(
|
||||
WarehouseLocationsActions.locationSuccess({
|
||||
loader: payload?.loader,
|
||||
@@ -52,7 +56,9 @@ export function* onAddRequestLocation({ payload }) {
|
||||
})
|
||||
);
|
||||
} else {
|
||||
payload.onFailedLocation(response.data.error);
|
||||
toast.error('Failed to create warehouse location', {
|
||||
theme: 'colored'
|
||||
});
|
||||
yield put(
|
||||
WarehouseLocationsActions.locationFailure({
|
||||
loader: payload?.loader,
|
||||
@@ -71,6 +77,9 @@ export function* onDeleteRequestLocation({ payload }) {
|
||||
);
|
||||
LOGGER.log('delete response', response.data);
|
||||
if (response?.status === 200) {
|
||||
toast.success('Location deleted successfully', {
|
||||
theme: 'colored'
|
||||
});
|
||||
yield put(
|
||||
WarehouseLocationsActions.locationSuccess({
|
||||
loader: payload?.loader,
|
||||
@@ -78,7 +87,9 @@ export function* onDeleteRequestLocation({ payload }) {
|
||||
})
|
||||
);
|
||||
} else {
|
||||
payload.onFailedLocation(response.data.error);
|
||||
toast.error('Failed to delete warehouse location', {
|
||||
theme: 'colored'
|
||||
});
|
||||
yield put(
|
||||
WarehouseLocationsActions.locationFailure({
|
||||
loader: payload?.loader,
|
||||
@@ -97,6 +108,9 @@ export function* onEditRequestLocation({ payload }) {
|
||||
);
|
||||
LOGGER.log('edit response', response.data);
|
||||
if (response?.status === 200) {
|
||||
toast.success('Location edited successfully', {
|
||||
theme: 'colored'
|
||||
});
|
||||
yield put(
|
||||
WarehouseLocationsActions.locationSuccess({
|
||||
loader: payload?.loader,
|
||||
@@ -108,7 +122,9 @@ export function* onEditRequestLocation({ payload }) {
|
||||
})
|
||||
);
|
||||
} else {
|
||||
payload.onFailedLocation(response.data.error);
|
||||
toast.error('Failed to edit warehouse location', {
|
||||
theme: 'colored'
|
||||
});
|
||||
yield put(
|
||||
WarehouseLocationsActions.locationFailure({
|
||||
loader: payload?.loader,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { AuthorizedAPI } from 'config';
|
||||
import { toast } from 'react-toastify';
|
||||
import { call, put, takeEvery } from 'redux-saga/effects';
|
||||
import ApiServices from 'services/API/ApiServices';
|
||||
import WidgetActions, { WidgetTypes } from '../redux/WidgetRedux';
|
||||
@@ -35,6 +36,12 @@ export function* onEditRequestWidget({ payload }) {
|
||||
payload?.data
|
||||
);
|
||||
if (response?.status === 200) {
|
||||
toast.success(
|
||||
`Successfully ${payload?.type !== 'delete' ? payload?.type : 'delet'}ed widget family`,
|
||||
{
|
||||
theme: 'colored'
|
||||
}
|
||||
);
|
||||
yield put(
|
||||
WidgetActions.editWidgetSuccess({
|
||||
loader: payload?.loader,
|
||||
@@ -44,6 +51,12 @@ export function* onEditRequestWidget({ payload }) {
|
||||
})
|
||||
);
|
||||
} else {
|
||||
toast.error(
|
||||
payload?.type ? `Failed to ${payload?.type} widget family` : 'Failed to fulfill request',
|
||||
{
|
||||
theme: 'colored'
|
||||
}
|
||||
);
|
||||
yield put(
|
||||
WidgetActions.widgetFailure({
|
||||
loader: payload?.loader,
|
||||
|
||||
@@ -8,6 +8,7 @@ import RolesSaga from './Roles';
|
||||
import PermissionsSaga from './Permissions';
|
||||
import WarehouseLocationsSaga from './WarehouseLocations';
|
||||
import WidgetSaga from './Widget';
|
||||
import LabellingSaga from './Labelling';
|
||||
import ItemSaga from './Item';
|
||||
|
||||
export default function* rootSaga() {
|
||||
@@ -20,5 +21,6 @@ export default function* rootSaga() {
|
||||
yield all([...PermissionsSaga]);
|
||||
yield all([...WarehouseLocationsSaga]);
|
||||
yield all([...WidgetSaga]);
|
||||
yield all([...LabellingSaga]);
|
||||
yield all([...ItemSaga]);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// REST API SERVICES
|
||||
export default {
|
||||
post: (API, slug, payload) => API.post(slug, payload),
|
||||
post: (API, slug, payload, headers) => headers ? API.post(slug, payload, {headers}) : API.post(slug, payload),
|
||||
get: (API, slug) => API.get(slug),
|
||||
delete: (API, slug) => {
|
||||
return API.delete(slug);
|
||||
|
||||
@@ -32,17 +32,17 @@ const schema = {
|
||||
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(),
|
||||
description: Yup.string('Enter details'),
|
||||
manufacturer: Yup.string('Enter details'),
|
||||
size: Yup.string('Enter details'),
|
||||
color: Yup.string('Enter details'),
|
||||
type: Yup.string('Enter details'),
|
||||
unitOfMaterial: Yup.string('Enter details'),
|
||||
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(),
|
||||
primaryWidgetFamilyId: Yup.string('Enter details'),
|
||||
secondaryWidgetFamilyId: Yup.string('Enter details'),
|
||||
policiesMetadata: Yup.object({
|
||||
underStockLevelCount: Yup.number().test((val) => val >= 0),
|
||||
@@ -54,8 +54,8 @@ const schema = {
|
||||
}),
|
||||
|
||||
addInventory: Yup.object({
|
||||
name: Yup.string('Enter Widget Name').required('Widget Name is required'),
|
||||
widgetName: Yup.string('Enter Inventory name').required('Inventory name is required'),
|
||||
name: Yup.string('Enter Inventory Name').required('Inventory Name is required'),
|
||||
widgetName: Yup.string('Enter Widget name').required('Widget Name is required'),
|
||||
policies: Yup.object({
|
||||
orderTracking: Yup.boolean(),
|
||||
alerting: Yup.boolean(),
|
||||
@@ -63,11 +63,13 @@ const schema = {
|
||||
preferredLocations: Yup.boolean(),
|
||||
inventory_process: Yup.string()
|
||||
}),
|
||||
image: Yup.array()
|
||||
icons: Yup.string()
|
||||
}),
|
||||
|
||||
createUser: Yup.object({
|
||||
fullName: Yup.string('Enter Full Name').required('User Name is required'),
|
||||
email: Yup.string('Enter Email').required('Email is required'),
|
||||
password: Yup.string('Enter Password').required('Password is required'),
|
||||
phoneNumber: Yup.string('Enter Phone Numbe').required('Phone Number is required'),
|
||||
roles: Yup.string('Please select at least one role').required('At least one role is required')
|
||||
})
|
||||
|
||||
18
src/utils/inventorySlugTools.js
Normal file
18
src/utils/inventorySlugTools.js
Normal file
@@ -0,0 +1,18 @@
|
||||
import EquipmentIcon from 'assets/images/EquimpmentIcon';
|
||||
import FleetIcon from 'assets/images/FleetIcon';
|
||||
import RawMaterialIcon from 'assets/images/RawMaterialIcon';
|
||||
|
||||
export const GetIconFromSlug = (slug) => {
|
||||
switch (slug) {
|
||||
case 'equipment':
|
||||
return <EquipmentIcon />;
|
||||
case 'fleet':
|
||||
return <FleetIcon />;
|
||||
case 'rawmaterial':
|
||||
return <RawMaterialIcon />;
|
||||
default:
|
||||
return <RawMaterialIcon />;
|
||||
}
|
||||
};
|
||||
|
||||
export const iconSlugs = ['equipment', 'fleet', 'rawmaterial'];
|
||||
Reference in New Issue
Block a user