From 243f4c5fa1b2b39abe23efec77f66c7548b3bae3 Mon Sep 17 00:00:00 2001 From: Dikshajain39511 <98263148+Dikshajain39511@users.noreply.github.com> Date: Wed, 16 Feb 2022 11:54:27 +0530 Subject: [PATCH] Feature/wms 50 (#57) * create warehouse * edit warehouse changes * Update: linted and formatted * add warehouse button * user access changes * basic table component changes * Updated: eslint errors * basic table component changes * update: linted * add New Product form api integrate * add new product changes * textarea changes * Linted code * Fix: image preview placeholder Co-authored-by: [Diksha] <[diksha39511@gmail.com]> Co-authored-by: Llewellyn Dsouza --- src/constant/Endpoints.js | 1 + src/pages/addNewProduct/index.js | 729 +++++++++++++++++++---------- src/pages/setupInventory/index.js | 2 +- src/redux/ProductsRedux.js | 54 +++ src/redux/index.js | 2 + src/sagas/Product.js | 31 ++ src/sagas/index.js | 2 + src/services/ValidationServices.js | 27 +- 8 files changed, 607 insertions(+), 241 deletions(-) create mode 100644 src/redux/ProductsRedux.js create mode 100644 src/sagas/Product.js diff --git a/src/constant/Endpoints.js b/src/constant/Endpoints.js index e1e5aaf..f83c239 100644 --- a/src/constant/Endpoints.js +++ b/src/constant/Endpoints.js @@ -3,5 +3,6 @@ export default { GET_WAREHOUSE_DATA: '/warehouse/all?page=0&perPage=50', CREATE_WAREHOUSE: '/warehouse/', GET_USERS_DATA: '/user/all?page=0&perPage=10', + ADD_PRODUCT: '/item/', GET_ROLES_DATA: '/user-role/all?page=0&perPage=10' }; diff --git a/src/pages/addNewProduct/index.js b/src/pages/addNewProduct/index.js index 8578442..884350f 100644 --- a/src/pages/addNewProduct/index.js +++ b/src/pages/addNewProduct/index.js @@ -1,5 +1,6 @@ +/* eslint-disable complexity */ import * as React from 'react'; -import { Grid, TextareaAutosize, TextField, Box } from '@mui/material'; +import { Grid, TextField, Box, FormHelperText, TextareaAutosize } from '@mui/material'; import { makeStyles } from '@mui/styles'; import DashboardNavbar from 'components/DashboardNavbar'; import DashboardLayout from 'layouts/DashboardLayout'; @@ -11,6 +12,13 @@ import MDButton from 'components/Button'; import Dialog from '@mui/material/Dialog'; import DialogContent from '@mui/material/DialogContent'; import CrossIcon from 'assets/images/CrossIcon'; +import { useFormik } from 'formik'; +import schema from 'services/ValidationServices'; +import MDInput from 'components/MDInput'; +import { useDispatch } from 'react-redux'; +import ProductActions from 'redux/ProductsRedux'; +import { API } from 'constant'; +import LOGGER from 'services/Logger'; const useStyles = makeStyles({ labelSize: { @@ -23,7 +31,7 @@ const useStyles = makeStyles({ textAreaSize: { width: '100% !important', resize: 'none', - height: '208px !important', + height: '203px !important', boxSizing: 'border-box', border: '1px solid #C4C4C4', borderRadius: '4px', @@ -33,11 +41,15 @@ const useStyles = makeStyles({ cursor: 'pointer' } }); -const previewImg = [1, 2, 3]; + +const inventoryTypes = ['Perishable', 'Material', 'Product', 'Inventory', 'Fleet']; + function AddNewProduct() { const classes = useStyles(); + const dispatch = useDispatch(); const [Manufacturer, setManufacturer] = React.useState(''); const [open, setOpen] = React.useState(false); + const handleClickOpen = () => { setOpen(true); }; @@ -49,262 +61,501 @@ function AddNewProduct() { const handleChange = (event) => { setManufacturer(event.target.value); }; + + const formik = useFormik({ + initialValues: { + warehousename: '', + description: '', + manufacturer: '', + type: '', + unitofmaterial: '', + packagecount: '', + formalname: '', + size: '', + color: '', + unitcost: '', + countperpallet: '', + countperpalletpackage: '', + productfamilyassociation: '', + under: '', + over: '', + alert: '', + images: [] + }, + validationSchema: schema.addNewProduct, + onSubmit: (values, onSubmitProps) => { + LOGGER.log('values', values); + dispatch( + ProductActions.addProductAction({ + loader: 'loading-request', + slug: API.ADD_PRODUCT, + method: 'post', + data: { + commonName: values.warehousename, + formalName: values.formalname, + description: values.description, + manufacturer: values.manufacturer, + size: values.size, + color: values.color, + type: values.type, + unitOfMaterial: values.unitofmaterial, + unitCost: values.unitcost, + packageCount: values.packagecount, + countPerPallet: values.countperpallet, + countPerPalletPackage: values.countperpalletpackage, + customAttributes: [ + { fieldName: 'someName', fieldType: 'String', fieldValue: 'someValue' } + ], + widgetFamilyId: '61dcdd10699e8f55b44c606d' + } + }) + ); + onSubmitProps.resetForm(); + } + }); + return ( <> - - - - - - Warehouse name +
+ + + + + + Warehouse name + + - - - - - Description + + + Description + + + + {formik.errors.description && + formik.touched.description && + formik.errors.description} + - - - - - Manufacturer + + + Manufacturer + + + + + {formik.errors.manufacturer && + formik.touched.manufacturer && + formik.errors.manufacturer} + + - - + + None Selected + + {inventoryTypes.map((name) => ( + + {name} + + ))} + + + {formik.errors.type && formik.touched.type && formik.errors.type} + + + + + + Unit of Material + + + - - - - - Type + onChange={formik.handleChange} + > + + None Selected + + {inventoryTypes.map((name) => ( + + {name} + + ))} + + + {formik.errors.unitofmaterial && + formik.touched.unitofmaterial && + formik.errors.unitofmaterial} + + - - + + None Selected + + {inventoryTypes.map((name) => ( + + {name} + + ))} + + + {formik.errors.size && formik.touched.size && formik.errors.size} + + + + + + Color + + + + + {formik.errors.color && formik.touched.color && formik.errors.color} + + + + + + Unit Cost + + + + + + Count per Pallet + + + + + + Count per Pallet Package + + + + + + Product Family Association + + + - - - - - Unit of Material - - - + + {formik.errors.productfamilyassociation && + formik.touched.productfamilyassociation && + formik.errors.productfamilyassociation} + + + + - - - - - Package Count + onChange={formik.handleChange} + > + + None Selected + + {inventoryTypes.map((name) => ( + + {name} + + ))} + + + {formik.errors.productfamilyassociation && + formik.touched.productfamilyassociation && + formik.errors.productfamilyassociation} + + - - + - - - - Formal Name - - - - - - Size - - - - - - - - Color - - - - - - - - Unit Cost - - - - - - Count per Pallet - - - - - - Count per Pallet Package - - - - - - Product Family Association - - - - - - - - - - - - - - - - add custom fields - - - import - - - - Stock Level Triggers - - - - Under - - + { + formik.setFieldValue('images', images); + }} + /> - - - Over - - + + + add custom fields + + + import + - - - Alert + + Stock Level Triggers + + + + + Under + + - + + + Over + + + + + + Alert + + + + + + + cancel + + + add ITem + - - - cancel - - - add ITem - - - +
diff --git a/src/pages/setupInventory/index.js b/src/pages/setupInventory/index.js index c1feb2d..0e9aab7 100644 --- a/src/pages/setupInventory/index.js +++ b/src/pages/setupInventory/index.js @@ -18,7 +18,7 @@ function SetupInventory() { }, { name: 'Products', - path: { update: '/', addNew: '/setup/inventory/inventory-new', cycleCount: '/', list: '/' }, + path: { update: '/', addNew: '/setup/inventory/product/add-new-product', cycleCount: '/', list: '/' }, icon: }, { diff --git a/src/redux/ProductsRedux.js b/src/redux/ProductsRedux.js new file mode 100644 index 0000000..29d8d88 --- /dev/null +++ b/src/redux/ProductsRedux.js @@ -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({ + addProductAction: ['payload'], + addProductSuccess: ['data'], + addProductFailure: ['error'] +}); + +export const ProductTypes = Types; +const ProductActions = Creators; +export default ProductActions; + +/* ------------- Initial State ------------- */ +export const INITIAL_STATE = Immutable({ + addProductDetail: [], + addProductLoading: false, + addProducterror: {} +}); + +/* ------------- Selectors ------------- */ +export const ProductSelectors = { + addProductDetail: (state) => state.product.productDetail +}; + +/* ------------- Reducers ------------- */ +export const onAddProductAction = (state, { payload }) => + state.merge({ + fetching: _.uniq([state.fetching, payload?.loader]), + error: getErrorValue(state?.error, payload?.loader) + }); + +export const onAddProductSuccess = (state, { data }) => + state.merge({ + fetching: getFetchingValue(state.fetching, data?.loader), + error: getErrorValue(state?.error, data?.loader), + addProductDetail: data.addProductDetail + }); + +export const onAddProductFailure = (state, { error }) => + state.merge({ + fetching: _.without(state.fetching, error?.loader), + error: { ...state.error, [error?.loader]: error?.error } + }); + +/* ------------- Hookup Reducers To Types ------------- */ +export const productReducer = createReducer(INITIAL_STATE, { + [Types.ADD_PRODUCT_ACTION]: onAddProductAction, + [Types.ADD_PRODUCT_SUCCESS]: onAddProductSuccess, + [Types.ADD_PRODUCT_FAILURE]: onAddProductFailure +}); diff --git a/src/redux/index.js b/src/redux/index.js index 4e28d5c..cc75a86 100644 --- a/src/redux/index.js +++ b/src/redux/index.js @@ -2,6 +2,7 @@ import { combineReducers } from 'redux'; import { authReducer } from './AuthRedux'; import { warehouseReducer } from './WarehouseRedux'; import { usersReducer } from './UsersRedux'; +import { productReducer } from './ProductsRedux'; import { rolesReducer } from './RolesRedux'; // Combine all reducers. @@ -9,6 +10,7 @@ const appReducer = combineReducers({ auth: authReducer, warehouse: warehouseReducer, users: usersReducer, + product: productReducer, roles: rolesReducer }); diff --git a/src/sagas/Product.js b/src/sagas/Product.js new file mode 100644 index 0000000..49c2c81 --- /dev/null +++ b/src/sagas/Product.js @@ -0,0 +1,31 @@ +import { AuthorizedAPI } from 'config'; +import { takeLatest, call, put } from 'redux-saga/effects'; +import ProductActions from 'redux/ProductsRedux'; +import { ProductTypes } from 'redux/ProductsRedux'; +import ApiServices from 'services/API/ApiServices'; + +export function* onRequestAddProductData({ payload }) { + const response = yield call( + ApiServices[payload?.method], + AuthorizedAPI, + payload?.slug, + payload?.data + ); + if (response?.status === 200) { + yield put( + ProductActions.addProductSuccess({ + loader: payload?.loader, + addProductDetail: response?.data?.data + }) + ); + } else { + payload.onFailedAddProductData(response.data.error); + yield put( + ProductActions.addProductFailure({ + loader: payload?.loader, + error: response?.data + }) + ); + } +} +export default [takeLatest(ProductTypes.ADD_PRODUCT_ACTION, onRequestAddProductData)]; diff --git a/src/sagas/index.js b/src/sagas/index.js index 141f3c3..ed1d037 100644 --- a/src/sagas/index.js +++ b/src/sagas/index.js @@ -2,11 +2,13 @@ import { all } from 'redux-saga/effects'; import AuthSaga from './Auth'; import WarehouseSaga from './Warehouse'; import UsersSaga from './Users'; +import ProductSaga from './Product'; import RolesSaga from './Roles'; export default function* rootSaga() { yield all([...AuthSaga]); yield all([...WarehouseSaga]); yield all([...UsersSaga]); + yield all([...ProductSaga]); yield all([...RolesSaga]); } diff --git a/src/services/ValidationServices.js b/src/services/ValidationServices.js index cb6040c..29f08ec 100644 --- a/src/services/ValidationServices.js +++ b/src/services/ValidationServices.js @@ -22,8 +22,33 @@ const schema = { warehouseForm: Yup.object({ warehousename: Yup.string('Enter warehouse name').required('warehouse name is required'), address: Yup.string('Enter address').required('address is required'), - inventorytype: Yup.string('Enter inventory Type').required('inventory Type is required'), + inventorytype: Yup.array('Enter inventory Type') + .of(Yup.string()) + .required('inventory Type is required'), attributes: Yup.string('Enter other attributes').required('attributes is required') + }), + + addNewProduct: Yup.object({ + warehousename: Yup.string('Enter warehouse name').required('warehouse name is required'), + description: Yup.string('Enter Description').required('description is required'), + manufacturer: Yup.string('Enter manufacturer').required('manufacturer is required'), + type: Yup.string('Enter type').required('type is required'), + unitofmaterial: Yup.string('Enter unitofmaterial').required('Unit of material is required'), + packagecount: Yup.number('Enter packagecount').required('Package Count is required'), + formalname: Yup.string('Enter formal name').required('Formal Name is required'), + size: Yup.string('Enter Size').required('Size is required'), + color: Yup.string('Enter Color').required('Color is required'), + unitcost: Yup.number('Enter UnitCost').required('Unit Cost is required'), + countperpallet: Yup.number('Enter countperpallet').required('Count per pallet is required'), + countperpalletpackage: Yup.number('Enter countperpalletpackage').required( + 'count per pallet package is required' + ), + productfamilyassociation: Yup.string('Enter productfamilyassociation').required( + 'product Family Association is required' + ), + under: Yup.number().required('required'), + over: Yup.number().required('required'), + alert: Yup.number().required('required') }) };