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
+
+
+
+
+ Formal Name
+
+
+
+
+
+ Size
+
+
+
+
+ {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}
+ >
+
+ {inventoryTypes.map((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')
})
};