From efdbe2377c688861e1835eeaf4f21b8b286a683d Mon Sep 17 00:00:00 2001 From: Sibunnayak Date: Tue, 8 Oct 2024 17:07:25 +0530 Subject: [PATCH] RD and Tm added multiple by spreadsheet --- src/routes.js | 21 ++ src/views/RetailDistributors/AddMultipleRD.js | 237 ++++++++++++++++++ .../RetailDistributors/RetailDistributor.js | 16 +- .../SingleRetailDistributor.js | 97 ++++--- src/views/SalesCoOrdinators/AddMultipleSC.js | 218 ++++++++++++++++ .../SalesCoOrdinators/SalesCoOrdinator.js | 20 +- src/views/TerritoryManager/AddMultipleTM.js | 218 ++++++++++++++++ .../TerritoryManager/TerritoryManager.js | 56 +++-- 8 files changed, 821 insertions(+), 62 deletions(-) create mode 100644 src/views/RetailDistributors/AddMultipleRD.js create mode 100644 src/views/SalesCoOrdinators/AddMultipleSC.js create mode 100644 src/views/TerritoryManager/AddMultipleTM.js diff --git a/src/routes.js b/src/routes.js index b6704bd..12341ef 100644 --- a/src/routes.js +++ b/src/routes.js @@ -156,6 +156,9 @@ import PendingOrders from "./views/orders/pendingOrders"; import ViewInvoices from "./views/orders/viewInoices"; import SingleDistributorOrder from "./views/RetailDistributors/DistributorOrders"; import DistributorStocks from "./views/RetailDistributors/DistributorStock"; +import AddMultiplerd from "./views/RetailDistributors/AddMultipleRD"; +import AddMultipletm from "./views/TerritoryManager/AddMultipleTM"; +import AddMultiplesc from "./views/SalesCoOrdinators/AddMultipleSC"; const routes = [ //dashboard @@ -259,6 +262,12 @@ const routes = [ element: ViewRetailDistributorSC, navName: "SalesCoOrdinators", }, + { + path: "/add-sales-coordinator/multiple", + name: "Add Sales Coordinators", + element: AddMultiplesc, + navName: "SalesCoOrdinators", + }, //TerritoryManager { path: "/territorymanager/edit/:id", @@ -296,6 +305,12 @@ const routes = [ element: ViewRetailDistributorTM, navName: "TerritoryManagers", }, + { + path: "/add-territory-manager/multiple", + name: "Add Territory Managers", + element: AddMultipletm, + navName: "TerritoryManagers", + }, // Attendence { path: "/attendance/today", @@ -365,6 +380,12 @@ const routes = [ element: AddRetailDistributor, navName: "RetailDistributor", }, + { + path: "/add-retail-distributor/multiple", + name: "Add Retail Distributor", + element: AddMultiplerd, + navName: "RetailDistributor", + }, { path: "/retaildistributor/mapping/:id", name: "Mapping Retail Distributor with PD SC TM", diff --git a/src/views/RetailDistributors/AddMultipleRD.js b/src/views/RetailDistributors/AddMultipleRD.js new file mode 100644 index 0000000..96971d1 --- /dev/null +++ b/src/views/RetailDistributors/AddMultipleRD.js @@ -0,0 +1,237 @@ +import React, { useState } from "react"; +import axios from "axios"; +import swal from "sweetalert"; +import { isAutheticated } from "src/auth"; +import { useNavigate } from "react-router-dom"; +import { toast } from "react-hot-toast"; +const AddMultiplerd = () => { + const [file, setFile] = useState(null); + const [loading, setLoading] = useState(false); + const [errors, setErrors] = useState([]); + const [newlyCreated, setNewlyCreated] = useState([]); + const [updatedDistributors, setUpdatedDistributors] = useState([]); + const navigate = useNavigate(); + const token = isAutheticated(); + const handleFileChange = (e) => { + const selectedFile = e.target.files[0]; + if ( + selectedFile && + selectedFile.type === + "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" + ) { + setFile(selectedFile); + } else { + swal("Error", "Please upload a valid Excel file", "error"); + setFile(null); + } + }; + + const handleSubmit = async (e) => { + e.preventDefault(); + if (!file) { + toast.error("Please select a file to upload"); + return; + } + // console.log(file); + // console.log(token); + setLoading(true); + setErrors([]); + setNewlyCreated([]); + setUpdatedDistributors([]); + try { + const formData = new FormData(); + formData.append("file", file); + + const { data } = await axios.post( + "/api/retaildistributor/upload", + formData, + { + headers: { + "Content-Type": "multipart/form-data", + Authorization: `Bearer ${token}`, + }, + } + ); + // console.log(data); + if (data.errors && data.errors.length > 0) { + setErrors(data.errors); + } + if (data.newlyCreated && data.newlyCreated.length > 0) { + setNewlyCreated(data.newlyCreated); + // console.log(data.newlyCreated); + } + if (data.updatedDistributors && data.updatedDistributors.length > 0) { + setUpdatedDistributors(data.updatedDistributors); + // console.log(data.updatedDistributors); + } + + // Redirect or display success message + if (data.errors && data.errors.length > 0) { + setErrors(data.errors); + swal({ + title: "SpreadSheet Upload Successful", + text: "A few Retail Distributor have errors. Please fix them and upload again.", + icon: "warning", + button: "OK", + }); + } else if ( + data.newlyCreated > 0 || + data.updatedDistributors > 0 + ) { + swal({ + title: "SpreadSheet Upload Successful", + text: "Retail Distributors added successfully.", + icon: "success", + buttons: "OK", + }); + } else { + toast.success("File processed successfully with no new entries."); + navigate("/retail-distributor"); + } + setFile(null); // Clear the file input + document.querySelector('input[type="file"]').value = ""; + } catch (error) { + console.error("Upload error:", error); + swal( + "Error", + `Failed to upload Retail Distributor: ${ + error.response?.data?.message || "An unexpected error occurred" + }`, + "error" + ); + } finally { + setLoading(false); + } + }; + + return ( +
+
+ +
+
Add Multiple Retail Distributor
+
+
+
+ +
+
+ +
+
+

Upload only .xlsx files*

+
+ + {errors.length > 0 && ( +
+
Finding errors while adding the Retail Distributor.
+ + + + + + + + + + + + + + {errors.map((error, index) => ( + + + + + + + + + + ))} + +
Retail Distributor NameEmailPhonePANGSTAAdharMessage
{error.name || "N/A"}{error.email || "N/A"}{error.phone || "N/A"}{error.panNumber || "N/A"}{error.gstNumber || "N/A"}{error.AadharNumber || "N/A"}{error.message}
+
+ )} + {updatedDistributors.length > 0 && ( +
+
Updated Retail Distributors
+ + + + + + + + + + + + + + {updatedDistributors.map((distributor, index) => ( + + + + + + + + + + ))} + +
Retail Distributor NameEmailPhonePANGSTAadharMessage
{distributor.name || "N/A"}{distributor.email || "N/A"}{distributor.mobile_number || "N/A"}{distributor.pan_number || "N/A"}{distributor.gst_number || "N/A"}{distributor.aadhar_number || "N/A"}{distributor.updatedFields}
+
+ )} + {newlyCreated.length > 0 && ( +
+
Newly Created Retail Distributors:
+ + + + + + + + + + + + + {newlyCreated.map((distributor, index) => ( + + + + + + + + + ))} + +
Retail Distributor NameEmailPhonePANGSTAadhar
{distributor?.Kyc?.name || "N/A"}{distributor?.Kyc?.email || "N/A"}{distributor?.Kyc?.mobile_number || "N/A"}{distributor?.Kyc?.pan_number || "N/A"}{distributor?.Kyc?.gst_number || "N/A"}{distributor?.Kyc?.aadhar_number || "N/A"}
+
+ )} +
+ ); +}; + +export default AddMultiplerd; diff --git a/src/views/RetailDistributors/RetailDistributor.js b/src/views/RetailDistributors/RetailDistributor.js index bee702c..89448df 100644 --- a/src/views/RetailDistributors/RetailDistributor.js +++ b/src/views/RetailDistributors/RetailDistributor.js @@ -90,6 +90,18 @@ const RetailDistributor = () => { > Add Retail Distributor + @@ -251,7 +263,9 @@ const RetailDistributor = () => { View - + + +
Add Multiple Sales Coordinators
+
+
+
+ +
+
+ +
+
+

Upload only .xlsx files*

+
+ + {errors.length > 0 && ( +
+
Finding errors while adding the Sales Coordinators.
+ + + + + + + + + + {errors.map((error, index) => ( + + + + + + + ))} + +
Sales Coordinator NameEmailMessage
{error.name || "N/A"}{error.email || "N/A"}{error.phone || "N/A"}{error.message}
+
+ )} + {updatedsalesCoordinators.length > 0 && ( +
+
Updated Sales Coordinators
+ + + + + + + + + + + {updatedsalesCoordinators.map((SC, index) => ( + + + + + + + ))} + +
Sales Coordinator NameEmailPhoneMessage
{SC.name || "N/A"}{SC.email || "N/A"}{SC.mobileNumber || "N/A"}{SC.updatedFields}
+
+ )} + {newlyCreated.length > 0 && ( +
+
Newly Created Sales Coordinators:
+ + + + + + + + + + {newlyCreated.map((SC, index) => ( + + + + + + ))} + +
Sales Coordinator NameEmailPhone
{SC?.salesCoordinator?.name || "N/A"}{SC?.salesCoordinator?.email || "N/A"}{SC?.salesCoordinator?.mobileNumber || "N/A"}
+
+ )} + + ); +}; + +export default AddMultiplesc; diff --git a/src/views/SalesCoOrdinators/SalesCoOrdinator.js b/src/views/SalesCoOrdinators/SalesCoOrdinator.js index f6ae423..0891897 100644 --- a/src/views/SalesCoOrdinators/SalesCoOrdinator.js +++ b/src/views/SalesCoOrdinators/SalesCoOrdinator.js @@ -119,20 +119,28 @@ const SalesCoOrdinator = () => { Sales Coordinators
- + {/* */}
diff --git a/src/views/TerritoryManager/AddMultipleTM.js b/src/views/TerritoryManager/AddMultipleTM.js new file mode 100644 index 0000000..f306cec --- /dev/null +++ b/src/views/TerritoryManager/AddMultipleTM.js @@ -0,0 +1,218 @@ +import React, { useState } from "react"; +import axios from "axios"; +import swal from "sweetalert"; +import { isAutheticated } from "src/auth"; +import { useNavigate } from "react-router-dom"; +import { toast } from "react-hot-toast"; +const AddMultipletm = () => { + const [file, setFile] = useState(null); + const [loading, setLoading] = useState(false); + const [errors, setErrors] = useState([]); + const [newlyCreated, setNewlyCreated] = useState([]); + const [updatedtrritoryManagers, setupdatedtrritoryManagers] = useState([]); + const navigate = useNavigate(); + const token = isAutheticated(); + const handleFileChange = (e) => { + const selectedFile = e.target.files[0]; + if ( + selectedFile && + selectedFile.type === + "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" + ) { + setFile(selectedFile); + } else { + swal("Error", "Please upload a valid Excel file", "error"); + setFile(null); + } + }; + + const handleSubmit = async (e) => { + e.preventDefault(); + if (!file) { + toast.error("Please select a file to upload"); + return; + } + // console.log(file); + // console.log(token); + setLoading(true); + setErrors([]); + setNewlyCreated([]); + setupdatedtrritoryManagers([]); + try { + const formData = new FormData(); + formData.append("file", file); + + const { data } = await axios.post( + "/api/territorymanager/upload", + formData, + { + headers: { + "Content-Type": "multipart/form-data", + Authorization: `Bearer ${token}`, + }, + } + ); + // console.log(data); + if (data.errors && data.errors.length > 0) { + setErrors(data.errors); + } + if (data.newlyCreated && data.newlyCreated.length > 0) { + setNewlyCreated(data.newlyCreated); + // console.log(data.newlyCreated); + } + if (data.updatedtrritoryManagers && data.updatedtrritoryManagers.length > 0) { + setupdatedtrritoryManagers(data.updatedtrritoryManagers); + // console.log(data.updatedtrritoryManagers); + } + + // Redirect or display success message + if (data.errors && data.errors.length > 0) { + setErrors(data.errors); + swal({ + title: "SpreadSheet Upload Successful", + text: "A few Territory Manager have errors. Please fix them and upload again.", + icon: "warning", + button: "OK", + }); + } else if ( + data.newlyCreated > 0 || + data.updatedtrritoryManagers > 0 + ) { + swal({ + title: "SpreadSheet Upload Successful", + text: "Territory Managers added successfully.", + icon: "success", + buttons: "OK", + }); + } else { + toast.success("File processed successfully with no new entries."); + navigate("/territorymanagers"); + } + setFile(null); // Clear the file input + document.querySelector('input[type="file"]').value = ""; + } catch (error) { + console.error("Upload error:", error); + swal( + "Error", + `Failed to upload Territory Managers: ${ + error.response?.data?.message || "An unexpected error occurred" + }`, + "error" + ); + } finally { + setLoading(false); + } + }; + + return ( +
+
+ +
+
Add Multiple Territory Managers
+
+
+
+ +
+
+ +
+
+

Upload only .xlsx files*

+
+ + {errors.length > 0 && ( +
+
Finding errors while adding the Territory Manager.
+ + + + + + + + + + {errors.map((error, index) => ( + + + + + + + ))} + +
Territory Manager NameEmailMessage
{error.name || "N/A"}{error.email || "N/A"}{error.phone || "N/A"}{error.message}
+
+ )} + {updatedtrritoryManagers.length > 0 && ( +
+
Updated Territory Managers
+ + + + + + + + + + + {updatedtrritoryManagers.map((TM, index) => ( + + + + + + + ))} + +
Territory Manager NameEmailPhoneMessage
{TM.name || "N/A"}{TM.email || "N/A"}{TM.mobileNumber || "N/A"}{TM.updatedFields}
+
+ )} + {newlyCreated.length > 0 && ( +
+
Newly Created Territory Managers:
+ + + + + + + + + + {newlyCreated.map((TM, index) => ( + + + + + + ))} + +
Territory Manager NameEmailPhone
{TM?.territoryManager?.name || "N/A"}{TM?.territoryManager?.email || "N/A"}{TM?.territoryManager?.mobileNumber || "N/A"}
+
+ )} +
+ ); +}; + +export default AddMultipletm; diff --git a/src/views/TerritoryManager/TerritoryManager.js b/src/views/TerritoryManager/TerritoryManager.js index e5566b4..1f920a9 100644 --- a/src/views/TerritoryManager/TerritoryManager.js +++ b/src/views/TerritoryManager/TerritoryManager.js @@ -5,7 +5,7 @@ import Button from "@material-ui/core/Button"; import { useNavigate } from "react-router-dom"; import { isAutheticated } from "src/auth"; import swal from "sweetalert"; -import debounce from 'lodash.debounce'; +import debounce from "lodash.debounce"; const TerritoryManager = () => { const token = isAutheticated(); @@ -57,10 +57,13 @@ const TerritoryManager = () => { getTerritoryManagersData(); }, [success, itemPerPage, currentPage]); - const debouncedSearch = useCallback(debounce(() => { - setCurrentPage(1); - getTerritoryManagersData(); - }, 500), []); + const debouncedSearch = useCallback( + debounce(() => { + setCurrentPage(1); + getTerritoryManagersData(); + }, 500), + [] + ); const handleSearchChange = () => { debouncedSearch(); @@ -122,17 +125,25 @@ const TerritoryManager = () => { + @@ -208,7 +219,7 @@ const TerritoryManager = () => { style={{ background: "#ecdddd" }} > - Unique Id + Unique Id Name Mobile No. Email @@ -275,7 +286,7 @@ const TerritoryManager = () => { })} - { type="button" className="btn btn-primary btn-sm waves-effect waves-light btn-table ml-2" > - PD + PD { type="button" className="btn btn-primary btn-sm waves-effect waves-light btn-table ml-2" > - RD + RD - - + + @@ -338,7 +349,9 @@ const TerritoryManager = () => { type="button" style={{ color: "white" }} className="btn btn-danger btn-sm waves-effect waves-light btn-table ml-2" - onClick={() => handleDelete(territorymanager._id)} + onClick={() => + handleDelete(territorymanager._id) + } > Delete @@ -358,7 +371,8 @@ const TerritoryManager = () => {
- Showing {territorymanagersData?.length} of {totalData} entries + Showing {territorymanagersData?.length} of {totalData}{" "} + entries