From 2ce13ba3129d42708800e4e2e777db12e98111de Mon Sep 17 00:00:00 2001 From: bluestreamlds <85561356+bluestreamlds@users.noreply.github.com> Date: Fri, 25 Feb 2022 11:08:55 +0530 Subject: [PATCH] Feature/wms 39 nestedtable (#62) * Updated: routes * Rewritten nested table logic * Updated: page with sample data and removed unnecessary components * Removed: footer * Fix: initial selected null handler * Added: styling * Updated: Table/button styling * Added: API responses * Fix: dispatch parameters * Update: disable dropdown when no children * Update: better receiving of data * Update: better click handling, row distribution * Update: yay the add form works finally * Added: navigation * Fixed: add zone button * Added some colours * Added: positions for sublevel * Fixed: null check * Added: initial sublevel values * Update: fixed add sublevel * Removed: location edit in sublevel * Fixed: sublevel locations * Added: edit apis handler * Added: dispatch * Fix: handle type seperately * Added: edit warehouse redux * Removed: loggers * Update: edit form payload method * Fix: multiple requests Co-authored-by: Llewellyn D'souza --- src/components/NestedTable/index.js | 522 +++++++++++----------- src/constant/Endpoints.js | 11 +- src/pages/editWarehouseDetails/index.js | 11 +- src/pages/warehouseDetailsTables/index.js | 295 ++++++++++-- src/redux/WarehouseLocationsRedux.js | 181 ++++++++ src/redux/index.js | 6 +- src/routes/index.js | 6 +- src/sagas/WarehouseLocations.js | 99 ++++ src/sagas/index.js | 2 + src/utils/nestedTableTools.js | 131 ++++++ 10 files changed, 948 insertions(+), 316 deletions(-) create mode 100644 src/redux/WarehouseLocationsRedux.js create mode 100644 src/sagas/WarehouseLocations.js create mode 100644 src/utils/nestedTableTools.js diff --git a/src/components/NestedTable/index.js b/src/components/NestedTable/index.js index a303483..844190e 100644 --- a/src/components/NestedTable/index.js +++ b/src/components/NestedTable/index.js @@ -1,287 +1,267 @@ -import * as React from 'react'; -import Box from '@mui/material/Box'; +/* eslint-disable indent */ +import { + Box, + // Chip, + Dialog, + DialogActions, + DialogContent, + DialogTitle, + Grid, + MenuItem, + // OutlinedInput, + Select, + TextField +} from '@mui/material'; +import React, { useEffect } from 'react'; import PropTypes from 'prop-types'; -import SearchBar from 'components/SearchBar'; -import MDButton from 'components/Button'; -import Menu from '@mui/material/Menu'; -import MenuItem from '@mui/material/MenuItem'; -import Fade from '@mui/material/Fade'; -import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown'; -import { styled } from '@mui/material/styles'; -import Table from '@mui/material/Table'; -import TableBody from '@mui/material/TableBody'; -import TableCell, { tableCellClasses } from '@mui/material/TableCell'; -import TableContainer from '@mui/material/TableContainer'; -import TableHead from '@mui/material/TableHead'; -import TableRow from '@mui/material/TableRow'; -import Paper from '@mui/material/Paper'; + +import KeyboardArrowRightIcon from '@mui/icons-material/KeyboardArrowRight'; import KeyboardArrowUpIcon from '@mui/icons-material/KeyboardArrowUp'; import IconButton from '@mui/material/IconButton'; -import Collapse from '@mui/material/Collapse'; -import TablePagination from 'components/TablePagination'; +import MDButton from 'components/Button'; +import { useDispatch, useSelector } from 'react-redux'; +import { WarehouseLocationsSelectors } from 'redux/WarehouseLocationsRedux'; +import LOGGER from 'services/Logger'; +import { useFormik } from 'formik'; +import { getPropertiesOfLocationType } from 'utils/nestedTableTools'; +import { getInitialvaluesFromData } from 'utils/nestedTableTools'; +import { getColorOfLocationType } from 'utils/nestedTableTools'; +import { toTitleCase } from 'utils/nestedTableTools'; +import WarehouseLocationsActions from 'redux/WarehouseLocationsRedux'; +import { getAPIslugOfLocationType } from 'utils/nestedTableTools'; -const StyledTableCell = styled(TableCell)(({ theme }) => ({ - [`&.${tableCellClasses.head}`]: { - backgroundColor: '#e5e7eb', - color: theme.palette.common.black, - fontWeight:400 - }, - [`&.${tableCellClasses.body}`]: { - fontSize: 14, - fontWeight:400 - } -})); - -const StyledTableRow = styled(TableRow)(({ theme }) => ({ - '&:nth-of-type(4n+1)': { - backgroundColor: theme.palette.action.hover - }, - 'td, th' :{ - padding: '0.75rem 0.5rem' - }, - // hide last border - '&:last-child td, &:last-child th': { - border: 0 - } - // '&:nth-of-type(1) td, &:nth-of-type(1) th': { - // width: '10px' - // } -})); - - -function createData(zone, names, type, specifications) { - return { - zone, - names, - type, - specifications, - children:[ - { - rownumber:'10,654', - location:'ALFKI', - employeeid:'4', - orderdate:'08/25/2008', - requiredate:'09/22/2008', - shippeddate:'09/22/2008' - }, - { - rownumber:'10,654', - location:'ALFKI', - employeeid:'4', - orderdate:'08/25/2008', - requiredate:'09/22/2008', - shippeddate:'09/22/2008' - } - ] - }; -} - -const rows = [ - createData('Zone A', 'Semper libero sit element...', 'Ana Trujillo', 'Orci arcu dictum pellentesque'), - createData('Zone A', 'Semper libero sit element...', 'Ana Trujillo', 'Orci arcu dictum pellentesque'), - createData('Zone A', 'Semper libero sit element...', 'Ana Trujillo', 'Orci arcu dictum pellentesque'), - createData('Zone A', 'Semper libero sit element...', 'Ana Trujillo', 'Orci arcu dictum pellentesque'), - createData('Zone A', 'Semper libero sit element...', 'Ana Trujillo', 'Orci arcu dictum pellentesque') -]; - -Row.propTypes = { - row: PropTypes.shape({ - zone: PropTypes.string.isRequired, - names: PropTypes.string.isRequired, - type: PropTypes.string.isRequired, - specifications: PropTypes.string.isRequired, - children: PropTypes.arrayOf( - PropTypes.shape({ - rownumber: PropTypes.string.isRequired, - location: PropTypes.string.isRequired, - employeeid: PropTypes.string.isRequired, - orderdate: PropTypes.string.isRequired, - requiredate: PropTypes.string.isRequired, - shippeddate: PropTypes.string.isRequired - }), - ).isRequired - }).isRequired -}; - -function Row(props) { - const { row } = props; +function NestedDataTable({ data, selected, setSelected, populateChildren }) { + const dispatch = useDispatch(); const [open, setOpen] = React.useState(false); + const [editFormOpen, setEditFormOpen] = React.useState(false); + const children = useSelector(WarehouseLocationsSelectors.getChildrenOfParent(data.id)); + const fields = getPropertiesOfLocationType(data.location); + const formik = useFormik({ + initialValues: getInitialvaluesFromData(data), + onSubmit: (values /*, { resetForm, setSubmitting }*/) => { + LOGGER.log('Form values and field info', values, data); + const formData = { ...values }; + // formData[`${data.location}_id`] = data.id; + dispatch( + WarehouseLocationsActions.editLocationRequest({ + loader: 'location-request', + slug: getAPIslugOfLocationType(data.location) + `/${data.id}`, + method: 'patch', + data: formData, + child: { + id: data.id, + parentId: data.parentId, + type: data.location + } + }) + ); + setEditFormOpen(false); + } + }); - return ( - - *': { borderBottom: 'unset' } }}> - - setOpen(!open)} - > - {open ? : } - - EDIT + useEffect(() => { + populateChildren(data.id, data.location); + }, []); - - - {row.zone} - - {row.names} - {row.type} - {row.specifications} - - - - - - - - - Row no - Number of Bays - Employee ID - Order Date - Required Date - Shipped Date - - - - {row?.children?.map((item , i)=>{ - return( - - {item.rownumber} - {item.location} - {item.employeeid} - {item.orderdate} - {item.requiredate} - {item.shippeddate} - - ); - })} - -
-
-
-
-
-
- ); -} - -export default function NestedTable() { - const [anchorEl, setAnchorEl] = React.useState(null); - const open = Boolean(anchorEl); - const handleClick = (event) => { - setAnchorEl(event.currentTarget); - }; - const handleClose = () => { - setAnchorEl(null); - }; return ( <> - - + + + setOpen(!open)} + > + {open ? : } + + { + setEditFormOpen(true); + }} + > + EDIT + + {data.location} + + { + setSelected(data); + }} + > + + {data.name} + + + {['row', 'level', 'bay'].includes(data.location) ? data.number : data.type} + + {data.location === 'bay' ? ( + + {data.type} + + ) : null} + + {data.specs} + + + + {open && children ? ( + + {/* Add headers here */} + {children.map((data) => ( + + ))} + + ) : null} + + {editFormOpen && ( + { + setEditFormOpen(false); }} > - - - - - Sorting - } - onClick={handleClick} - > - Dashboard - - - Profile - My account - Logout - - - - {/* Table-row- */} - - - - - - Zone - Names - Type - Specifications - - - - {rows.map((row) => ( - + Edit {data.location} details + + {/* Some more text if needed */} + {fields && + fields.map((fieldName) => ( + ))} - -
-
- - - Go to - 1 - - View: - } - sx={{ textTransform:'inherit', minWidth:'45px', minHeight:'28px', marginLeft:'10px', boxShadow:'none', fontWeight:'500', padding:'0', border:' 1px solid #C2C2C2', color:'#000' }} - onClick={handleClick} - > - 12 - - - Profile - My account - Logout - - - - {/*---- pagination- */} - - - - - [1 to 10 of 92] - - - + {data.location === 'sublevel' ? ( + <> + Type:{' '} + + {/* Positions:{' '} */} + {/* */} + + ) : null} + + + { + setEditFormOpen(false); + }} + > + Cancel + + Save + + + )} ); } +NestedDataTable.propTypes = { + data: PropTypes.any, + selected: PropTypes.any, + setSelected: PropTypes.any, + populateChildren: PropTypes.any +}; + +export default NestedDataTable; diff --git a/src/constant/Endpoints.js b/src/constant/Endpoints.js index e74f761..0e5a191 100644 --- a/src/constant/Endpoints.js +++ b/src/constant/Endpoints.js @@ -3,7 +3,14 @@ export default { GET_WAREHOUSE_DATA: '/warehouse/all?page=0&perPage=50', CREATE_WAREHOUSE: '/warehouse/', GET_USERS_DATA: '/user/all?page=0&perPage=10', + GET_ROLES_DATA: '/user-role/all?page=0&perPage=10', + GET_CHILDREN_FROM_PARENT: '/dashboard/get-children-from-parent', + ADD_NEW_ZONE: '/zone', + ADD_NEW_AREA: '/area', + ADD_NEW_ROW: '/row', + ADD_NEW_BAY: '/bay', + ADD_NEW_LEVEL: '/level', + ADD_NEW_SUBLEVEL: '/sublevel', ADD_PRODUCT: '/item/', - ADD_INVENTORY: '/inventory', - GET_ROLES_DATA: '/user-role/all?page=0&perPage=10' + ADD_INVENTORY: '/inventory' }; diff --git a/src/pages/editWarehouseDetails/index.js b/src/pages/editWarehouseDetails/index.js index 318b043..427daca 100644 --- a/src/pages/editWarehouseDetails/index.js +++ b/src/pages/editWarehouseDetails/index.js @@ -12,6 +12,7 @@ import MDInput from 'components/MDInput'; import { useLocation } from 'react-router-dom'; import WarehouseActions from 'redux/WarehouseRedux'; import SnackBar from 'components/SnackBar'; +import { useNavigate } from 'react-router-dom'; const useStyles = makeStyles({ labelSize: { @@ -25,6 +26,7 @@ const useStyles = makeStyles({ const inventoryTypes = ['Perishable', 'Material', 'Product', 'Inventory', 'Fleet']; function EditWarehouseDetails() { + const navigate = useNavigate(); const classes = useStyles(); const location = useLocation(); const [open, setOpen] = useState(false); @@ -208,7 +210,14 @@ function EditWarehouseDetails() { EDIT DETAILS - + { + navigate(`/setup/warehouse/warehouse-details/${location.state.id}`); + }} + > SHOW DETAILS diff --git a/src/pages/warehouseDetailsTables/index.js b/src/pages/warehouseDetailsTables/index.js index 275be9f..256461c 100644 --- a/src/pages/warehouseDetailsTables/index.js +++ b/src/pages/warehouseDetailsTables/index.js @@ -1,92 +1,313 @@ +import React from 'react'; +import PropTypes from 'prop-types'; import MDButton from 'components/Button'; import DashboardNavbar from 'components/DashboardNavbar'; -import NestedTable from 'components/NestedTable'; import DashboardLayout from 'layouts/DashboardLayout'; -import { makeStyles } from '@mui/styles'; -import { Box } from '@mui/material'; +import { + Box, + Chip, + Dialog, + DialogActions, + DialogContent, + DialogTitle, + MenuItem, + OutlinedInput, + Select, + TextField +} from '@mui/material'; +import NestedDataTable from 'components/NestedTable'; +import { useDispatch, useSelector } from 'react-redux'; +import WarehouseLocationsActions from 'redux/WarehouseLocationsRedux'; +import { API } from 'constant'; +import { WarehouseLocationsSelectors } from 'redux/WarehouseLocationsRedux'; +import LOGGER from 'services/Logger'; +import { getPropertiesOfLocationType } from 'utils/nestedTableTools'; +import { useFormik } from 'formik'; +import { getInitialvaluesFromParentData } from 'utils/nestedTableTools'; +import { toTitleCase } from 'utils/nestedTableTools'; +import { getChildLocationType } from 'utils/nestedTableTools'; +import { getAPIslugOfLocationType } from 'utils/nestedTableTools'; +import { useParams } from 'react-router-dom'; -const useStyles = makeStyles({ - customButton: { - width: '100%', - padding: '13px 30px !important', - textTransform: 'uppercase', - borderRadius: '100px !important', - boxShadow: 'none !important' - } -}); +const bottomButtonStyling = { + width: '100%', + textTransform: 'uppercase', + borderRadius: '100px', + padding: '13px 30px' +}; + +const AddForm = ({ addFormOpen, setAddFormOpen, selected, warehouseId }) => { + const dispatch = useDispatch(); + const data = addFormOpen !== 'zone' ? selected : { location: 'warehouse', parentId: warehouseId }; + + const childLocationType = getChildLocationType(data.location); + const fields = getPropertiesOfLocationType(childLocationType); + + const formik = useFormik({ + initialValues: getInitialvaluesFromParentData(data), + onSubmit: (values) => { + LOGGER.log('Form values and parent info', values, data); + const formData = { ...values }; + formData[`${data.location}_id`] = data.id; + dispatch( + WarehouseLocationsActions.addLocationRequest({ + loader: 'location-request', + slug: getAPIslugOfLocationType(childLocationType), + method: 'post', + data: formData, + parent: { + id: data.id, + type: data.location + } + }) + ); + setAddFormOpen(false); + } + }); + + return ( + { + setAddFormOpen(false); + }} + > + Add new {childLocationType} details + + {/* Some more text if needed */} + {fields && + fields.map((fieldName) => ( + + ))} + {childLocationType === 'sublevel' ? ( + <> + Type:{' '} + + Positions:{' '} + + + ) : null} + + + { + setAddFormOpen(false); + }} + > + Cancel + + Save + + + ); +}; + +AddForm.propTypes = { + addFormOpen: PropTypes.any, + setAddFormOpen: PropTypes.any, + selected: PropTypes.any, + warehouseId: PropTypes.any +}; + +const WarehouseNestedDetails = () => { + const [selected, setSelected] = React.useState(null); + const [addFormOpen, setAddFormOpen] = React.useState(false); + const dispatch = useDispatch(); + + const { warehouseId } = useParams(); + LOGGER.log('warehouseID', warehouseId); + const data = useSelector(WarehouseLocationsSelectors.getChildrenOfParent(warehouseId)); + + const populateChildren = (id, type) => { + LOGGER.log('populating:', id, type); + dispatch( + WarehouseLocationsActions.locationRequest({ + loader: 'location-request', + slug: API.GET_CHILDREN_FROM_PARENT, + method: 'post', + data: { id, type } + }) + ); + }; + + React.useEffect(() => { + populateChildren(warehouseId, 'warehouse'); + }, []); -const WarehouseDetailsTables = () => { - const classes = useStyles(); return ( <> - + {data && + data.map((data) => ( + + ))} + {/* Debugging */} + {/*
{JSON.stringify(selected, null, 4)}
*/} + {/* Bottom buttons */} { + setAddFormOpen('zone'); + }} > - add zone + Add zone { + setAddFormOpen(true); + }} > - add area + Add area { + setAddFormOpen(true); + }} > - add row + Add row { + setAddFormOpen(true); + }} > - add bay + Add bay { + setAddFormOpen(true); + }} > - split bay + Add Level { + setAddFormOpen(true); + }} > - split level + Add Sublevel
+ {addFormOpen && ( + + )}
); }; -export default WarehouseDetailsTables; +export default WarehouseNestedDetails; diff --git a/src/redux/WarehouseLocationsRedux.js b/src/redux/WarehouseLocationsRedux.js new file mode 100644 index 0000000..6743746 --- /dev/null +++ b/src/redux/WarehouseLocationsRedux.js @@ -0,0 +1,181 @@ +import { createActions, createReducer } from 'reduxsauce'; +import Immutable from 'seamless-immutable'; +import LOGGER from 'services/Logger'; +import _ from 'underscore'; +import { getChildLocationType } from 'utils/nestedTableTools'; +import { getFetchingValue, getErrorValue } from '../services/Utils'; + +/* ------------- Types and Action Creators ------------- */ +const { Types, Creators } = createActions({ + locationRequest: ['payload'], + locationSuccess: ['data'], + locationFailure: ['error'], + addLocationRequest: ['payload'], + editLocationRequest: ['payload'] +}); + +export const WarehouseLocationsTypes = Types; +const WarehouseLocationsActions = Creators; +export default WarehouseLocationsActions; + +/* ------------- Initial State ------------- */ +export const INITIAL_STATE = Immutable({ + childData: [], + fetching: [], + error: {} +}); + +/* ------------- Selectors ------------- */ +export const WarehouseLocationsSelectors = { + getChildData: (state) => state.warehouseLocations.childData, + getChildrenOfParent: (id) => (state) => + state.warehouseLocations.childData?.filter((c) => c.parentId === id), + // getChildrenOfParent: (id) => () => sampleState?.filter((c) => c.parentId === id), + fetching: (state) => state.warehouseLocations.fetching +}; + +/* ------------- Reducers ------------- */ +export const onLocationRequest = (state, { payload }) => + state.merge({ + fetching: _.uniq([...state.fetching, payload?.loader]), + error: getErrorValue(state?.error, payload?.loader) + }); + +const mapResponseToNestedTable = (stateData, childData) => { + if (!childData) return stateData; // undefined check + let newChildren; + + // incase edited + if (childData.edited) { + newChildren = childData?.childrenData.map((child) => ({ + ...child, + id: child._id, + location: childData.child.type, + parentId: childData.child.parentId + })); + } else { + // created + newChildren = childData?.childrenData.map((child) => ({ + ...child, + id: child._id, + location: getChildLocationType(childData.parent.type), + parentId: childData.parent.id + })); + } + + const idsInNewChildren = newChildren.map((st) => st.id); + + const newState = stateData.filter((st) => !idsInNewChildren.includes(st.id)); + + return [...newState, ...newChildren]; +}; + +export const onLocationSuccess = (state, { data }) => { + LOGGER.log('From onLocationSuccess', state, data); + return state.merge({ + fetching: getFetchingValue(state.fetching, data?.loader), + error: getErrorValue(state?.error, data?.loader), + childData: mapResponseToNestedTable(state.childData, data?.childData) + }); +}; +export const onLocationFailure = (state, { error }) => + state.merge({ + fetching: _.without(state.fetching, error?.loader), + error: { ...state.error, [error?.loader]: error?.error } + }); + +export const onAddLocationRequest = (state, { payload }) => + state.merge({ + fetching: _.uniq([...state.fetching, payload?.loader]), + error: getErrorValue(state?.error, payload?.loader) + }); + +export const onEditLocationRequest = (state, { payload }) => + state.merge({ + fetching: _.uniq([...state.fetching, payload?.loader]), + error: getErrorValue(state?.error, payload?.loader) + }); + +/* ------------- Hookup Reducers To Types ------------- */ +export const WarehouseLocationsReducer = createReducer(INITIAL_STATE, { + [Types.LOCATION_REQUEST]: onLocationRequest, + [Types.LOCATION_SUCCESS]: onLocationSuccess, + [Types.LOCATION_FAILURE]: onLocationFailure, + [Types.ADD_LOCATION_REQUEST]: onAddLocationRequest, + [Types.EDIT_LOCATION_REQUEST]: onEditLocationRequest +}); + +// const sampleState = [ +// { +// parentId: '61cea720ccc4b530015164f0', +// id: 132, +// location: 'Zone', +// name: 'Zone 1', +// type: 'Type 1', +// specifications: 'something really long, idk' +// }, +// { +// parentId: 132, +// id: 154, +// location: 'Area', +// name: 'Area 1', +// type: 'Type 1', +// specifications: 'something really long, idk' +// }, +// { +// parentId: 154, +// id: 254, +// location: 'Row', +// name: 'Row 2', +// type: 'Type 2', +// specifications: 'something really long, idk' +// }, +// { +// parentId: 154, +// id: 233, +// location: 'Row', +// name: 'Row 2', +// type: 'Type 2', +// specifications: 'something really long, idk' +// }, +// { +// parentId: 233, +// id: 254, +// location: 'Bay', +// name: 'Bay 2', +// type: 'Type 2', +// specifications: 'something really long, idk' +// }, +// { +// parentId: 233, +// id: 954, +// location: 'Bay', +// name: 'Bay 2', +// type: 'Type 2', +// specifications: 'something really long, idk' +// }, +// { +// parentId: 954, +// id: 4687, +// location: 'Level', +// name: 'Level 2', +// type: 'Type 2', +// specifications: 'something really long, idk' +// }, +// { +// parentId: 954, +// id: 1264, +// location: 'Level', +// name: 'Level 2', +// type: 'Type 2', +// specifications: 'something really long, idk' +// }, +// { +// parentId: 132, +// id: 133, +// location: 'Area', +// name: 'Area 1', +// type: 'Type 1', +// specifications: 'something really long, idk' +// } +// ]; diff --git a/src/redux/index.js b/src/redux/index.js index ca8ecd3..025c49f 100644 --- a/src/redux/index.js +++ b/src/redux/index.js @@ -5,15 +5,17 @@ import { usersReducer } from './UsersRedux'; import { productReducer } from './ProductsRedux'; import { inventoryReducer } from './InventoryRedux'; import { rolesReducer } from './RolesRedux'; +import { WarehouseLocationsReducer } from './WarehouseLocationsRedux'; // Combine all reducers. const appReducer = combineReducers({ auth: authReducer, warehouse: warehouseReducer, users: usersReducer, + roles: rolesReducer, + warehouseLocations: WarehouseLocationsReducer, product: productReducer, - inventory: inventoryReducer, - roles: rolesReducer + inventory: inventoryReducer }); const rootReducer = (state, action) => { diff --git a/src/routes/index.js b/src/routes/index.js index d2436c2..c8cc42f 100644 --- a/src/routes/index.js +++ b/src/routes/index.js @@ -177,10 +177,10 @@ const protectedRoutes = [ component: }, { - name: 'Warehouse Details Table', - key: 'warehouse-details-table', + name: 'Warehouse Details', + key: 'warehouse-details', hide: true, - route: '/setup/warehouse/warehouse-details-table', + route: '/setup/warehouse/warehouse-details/:warehouseId', component: }, { diff --git a/src/sagas/WarehouseLocations.js b/src/sagas/WarehouseLocations.js new file mode 100644 index 0000000..014ef72 --- /dev/null +++ b/src/sagas/WarehouseLocations.js @@ -0,0 +1,99 @@ +import { AuthorizedAPI } from 'config'; +import { call, put, takeEvery } from 'redux-saga/effects'; +import WarehouseLocationsActions from 'redux/WarehouseLocationsRedux'; +import { WarehouseLocationsTypes } from 'redux/WarehouseLocationsRedux'; +import ApiServices from 'services/API/ApiServices'; +import LOGGER from 'services/Logger'; +// import { +// getError, +// } from '../services/Utils'; + +export function* onRequestLocation({ payload }) { + const response = yield call( + ApiServices[payload?.method], + AuthorizedAPI, + payload?.slug, + payload?.data + ); + if (response?.status === 200) { + yield put( + WarehouseLocationsActions.locationSuccess({ + loader: payload?.loader, + childData: response?.data?.data + }) + ); + } else { + payload.onFailedLocation(response.data.error); + yield put( + WarehouseLocationsActions.locationFailure({ + loader: payload?.loader, + error: response?.data + }) + ); + } +} + +export function* onAddRequestLocation({ payload }) { + const response = yield call( + ApiServices[payload?.method], + AuthorizedAPI, + payload?.slug, + payload?.data + ); + LOGGER.log('add response', response.data); + if (response?.status === 200) { + yield put( + WarehouseLocationsActions.locationSuccess({ + loader: payload?.loader, + childData: { + parent: payload?.parent, + childrenData: [{ ...response?.data }] + } + }) + ); + } else { + payload.onFailedLocation(response.data.error); + yield put( + WarehouseLocationsActions.locationFailure({ + loader: payload?.loader, + error: response?.data + }) + ); + } +} + +export function* onEditRequestLocation({ payload }) { + const response = yield call( + ApiServices[payload?.method], + AuthorizedAPI, + payload?.slug, + payload?.data + ); + LOGGER.log('edit response', response.data); + if (response?.status === 200) { + yield put( + WarehouseLocationsActions.locationSuccess({ + loader: payload?.loader, + childData: { + edited: true, + child: payload?.child, + childrenData: [{ ...response?.data }] + } + }) + ); + } else { + payload.onFailedLocation(response.data.error); + yield put( + WarehouseLocationsActions.locationFailure({ + loader: payload?.loader, + error: response?.data + }) + ); + } +} + +export default [ + takeEvery(WarehouseLocationsTypes.LOCATION_REQUEST, onRequestLocation), + takeEvery(WarehouseLocationsTypes.ADD_LOCATION_REQUEST, onAddRequestLocation), + takeEvery(WarehouseLocationsTypes.EDIT_LOCATION_REQUEST, onEditRequestLocation) +]; diff --git a/src/sagas/index.js b/src/sagas/index.js index c8b6adb..72a2c8c 100644 --- a/src/sagas/index.js +++ b/src/sagas/index.js @@ -5,6 +5,7 @@ import UsersSaga from './Users'; import ProductSaga from './Product'; import InventorySaga from './Inventory'; import RolesSaga from './Roles'; +import WarehouseLocationsSaga from './WarehouseLocations'; export default function* rootSaga() { yield all([...AuthSaga]); @@ -13,4 +14,5 @@ export default function* rootSaga() { yield all([...ProductSaga]); yield all([...InventorySaga]); yield all([...RolesSaga]); + yield all([...WarehouseLocationsSaga]); } diff --git a/src/utils/nestedTableTools.js b/src/utils/nestedTableTools.js new file mode 100644 index 0000000..e52709d --- /dev/null +++ b/src/utils/nestedTableTools.js @@ -0,0 +1,131 @@ +import { API } from 'constant'; +import LOGGER from 'services/Logger'; + +export const getChildLocationType = (parentLocationType) => { + switch (parentLocationType) { + case 'warehouse': + return 'zone'; + case 'zone': + return 'area'; + case 'area': + return 'row'; + case 'row': + return 'bay'; + case 'bay': + return 'level'; + case 'level': + return 'sublevel'; + case 'sublevel': + return 'sublevel'; + default: + return 'unknown'; + } +}; + +export const getAPIslugOfLocationType = (locationType) => { + switch (locationType) { + case 'zone': + return API.ADD_NEW_ZONE; + + case 'area': + return API.ADD_NEW_AREA; + + case 'row': + return API.ADD_NEW_ROW; + + case 'bay': + return API.ADD_NEW_BAY; + + case 'level': + return API.ADD_NEW_LEVEL; + + case 'sublevel': + return API.ADD_NEW_SUBLEVEL; + + default: + throw new Error('default values returned'); + } +}; + +export const getPropertiesOfLocationType = (locationType) => { + switch (locationType) { + case 'zone': + return ['name', 'type', 'specs']; + + case 'area': + return ['name', 'type', 'specs']; + + case 'row': + return ['name', 'number', 'specs']; + + case 'bay': + return ['name', 'type', 'number', 'specs']; + + case 'level': + return ['name', 'type', 'specs']; + + case 'sublevel': + return ['name', 'specs']; + + default: + LOGGER.error('default values returned'); + return ['name', 'type', 'specs']; + } +}; + +export const getColorOfLocationType = (locationType) => { + switch (locationType) { + case 'zone': + return '#9b5de5'; + + case 'area': + return '#f15bb5'; + + case 'row': + return '#fee440'; + + case 'bay': + return '#00bbf9'; + + case 'level': + return '#00f5d4'; + + default: + return '#555555'; + } +}; + +export const toTitleCase = (str) => { + return str.replace(/\w\S*/g, function (txt) { + return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase(); + }); +}; + +export const getInitialvaluesFromData = (data) => { + const properties = getPropertiesOfLocationType(data.location); + const mapper = {}; + properties.forEach((prop) => (mapper[prop] = data[prop] || '')); + if (data.location === 'sublevel') { + mapper['type'] = data['type']; + mapper['parentIsLevel'] = data['current_depth'] === 1; + mapper['parent_id'] = + data['current_depth'] === 1 ? data['main_level_id'] : data['parent_sublevel_id']; + // mapper['positions'] = data['positions'] || []; + } + // LOGGER.log('init form values', mapper); + return mapper; +}; + +export const getInitialvaluesFromParentData = (data) => { + const childType = getChildLocationType(data.location); + const properties = getPropertiesOfLocationType(childType); + const mapper = {}; + properties.forEach((prop) => (mapper[prop] = '')); + if (childType === 'sublevel') { + mapper['parent_id'] = data.id; + mapper['parentIsLevel'] = data.location === 'level' ? true : false; + mapper['positions'] = []; + } + // LOGGER.log('init form values', mapper); + return mapper; +};