diff --git a/src/_nav.js b/src/_nav.js
index a38edbb..f264ed6 100644
--- a/src/_nav.js
+++ b/src/_nav.js
@@ -88,7 +88,14 @@ const _nav = [
name: "Attendance",
icon: ,
to: "/attendance/today",
- group: "AttendanceSalesCoOrdinator",
+ group: "Attendance",
+ },
+ {
+ component: CNavItem,
+ name: "Leaves",
+ icon: ,
+ to: "/leaves/today",
+ group: "Leaves",
},
// {
// component: CNavGroup,
diff --git a/src/index.js b/src/index.js
index b47a948..adbdd11 100644
--- a/src/index.js
+++ b/src/index.js
@@ -15,8 +15,8 @@ import { cibGmail } from "@coreui/icons";
import { createRoot } from "react-dom/client";
const setupAxios = () => {
- // axios.defaults.baseURL = "http://localhost:5000";
- axios.defaults.baseURL = "https://cheminova-api-2.onrender.com";
+ axios.defaults.baseURL = "http://localhost:5000";
+ // axios.defaults.baseURL = "https://cheminova-api-2.onrender.com";
axios.defaults.headers = {
"Cache-Control": "no-cache,no-store",
diff --git a/src/routes.js b/src/routes.js
index 8d46c8c..ec2ed38 100644
--- a/src/routes.js
+++ b/src/routes.js
@@ -127,9 +127,12 @@ import Currency from "./views/configuration/Currency";
import SalesCoOrdinator from "./views/SalesCoOrdinators/SalesCoOrdinator";
import EditSalesCoOrdinator from "./views/SalesCoOrdinators/EditSalesCoOrdinator";
import AddSalesCoOrdinator from "./views/SalesCoOrdinators/AddSalesCoOrdinator";
-import TodayAttendanceSales from "./views/SalesAttendance/TodayAttendanceSales";
-import AttendanceSalesCoordinator from "./views/SalesAttendance/AttendanceSalesCoordinator";
-import SingleAttendanceSalesCoOrdinator from "./views/SalesAttendance/SingleAttendanceSalesCoordinator";
+import TodayAttendance from "./views/Attendance/TodayAttendance";
+import AttendanceSalesCoordinator from "./views/Attendance/AttendanceSalesCoordinator";
+import SingleAttendanceSalesCoOrdinator from "./views/Attendance/SingleAttendanceSalesCoordinator";
+import TodayLeave from "./views/Leaves/TodayLeaves";
+import LeaveSalesCoordinator from "./views/Leaves/LeaveSalesCoordinator";
+import SingleLeaveSalesCoOrdinator from "./views/Leaves/SingleLeaveSalesCoordinator";
const routes = [
//dashboard
@@ -197,12 +200,12 @@ const routes = [
element: AddSalesCoOrdinator,
navName: "SalesCoOrdinators",
},
- // Attendence SalesCoOrdinator
+ // Attendence
{
path: "/attendance/today",
- name: "Today's Attendance SalesCoOrdinator",
- element: TodayAttendanceSales,
- navName: "AttendanceSalesCoOrdinator",
+ name: "Today's Attendance",
+ element: TodayAttendance,
+ navName: "Attendance",
},
{
path: "/salescoordinator/attendance",
@@ -216,6 +219,25 @@ const routes = [
element: SingleAttendanceSalesCoOrdinator,
navName: "AttendanceSalesCoOrdinator",
},
+ // Leaves
+ {
+ path: "/leaves/today",
+ name: "Today's leaves",
+ element: TodayLeave,
+ navName: "Leaves",
+ },
+ {
+ path: "/salescoordinator/leave",
+ name: "Leave SalesCoOrdinator",
+ element: LeaveSalesCoordinator,
+ navName: "LeaveSalesCoOrdinator",
+ },
+ {
+ path: "/leave/view/:id",
+ name: "Single SalesCoOrdinator Leave",
+ element: SingleLeaveSalesCoOrdinator,
+ navName: "LeaveSalesCoOrdinator",
+ },
//Gst tax
{
path: "/tax",
diff --git a/src/views/SalesAttendance/AttendanceSalesCoordinator.js b/src/views/Attendance/AttendanceSalesCoordinator.js
similarity index 100%
rename from src/views/SalesAttendance/AttendanceSalesCoordinator.js
rename to src/views/Attendance/AttendanceSalesCoordinator.js
diff --git a/src/views/SalesAttendance/SingleAttendanceSalesCoordinator.js b/src/views/Attendance/SingleAttendanceSalesCoordinator.js
similarity index 100%
rename from src/views/SalesAttendance/SingleAttendanceSalesCoordinator.js
rename to src/views/Attendance/SingleAttendanceSalesCoordinator.js
diff --git a/src/views/SalesAttendance/TodayAttendanceSales.js b/src/views/Attendance/TodayAttendance.js
similarity index 97%
rename from src/views/SalesAttendance/TodayAttendanceSales.js
rename to src/views/Attendance/TodayAttendance.js
index 66243a5..ebcccdf 100644
--- a/src/views/SalesAttendance/TodayAttendanceSales.js
+++ b/src/views/Attendance/TodayAttendance.js
@@ -6,7 +6,7 @@ import { useNavigate } from "react-router-dom";
import { isAutheticated } from "src/auth";
import swal from "sweetalert";
-const TodayAttendanceSales = () => {
+const TodayAttendance = () => {
const token = isAutheticated();
const navigate = useNavigate();
const [loading, setLoading] = useState(false);
@@ -151,7 +151,7 @@ const TodayAttendanceSales = () => {
return (
- {attendance?.user?.id}
+ {attendance?.user?.uniqueId}
|
{attendance?.user?.name}
@@ -180,8 +180,8 @@ const TodayAttendanceSales = () => {
)}
|
- {attendance?.note ? (
- attendance?.note
+ {attendance?.notes ? (
+ attendance?.notes
) : (
No Note Added!
@@ -271,4 +271,4 @@ const TodayAttendanceSales = () => {
);
};
-export default TodayAttendanceSales;
+export default TodayAttendance;
diff --git a/src/views/Leaves/LeaveSalesCoordinator.js b/src/views/Leaves/LeaveSalesCoordinator.js
new file mode 100644
index 0000000..37212ed
--- /dev/null
+++ b/src/views/Leaves/LeaveSalesCoordinator.js
@@ -0,0 +1,319 @@
+import React, { useState, useEffect, useRef } from "react";
+import { Link } from "react-router-dom";
+import axios from "axios";
+import Button from "@material-ui/core/Button";
+import { useNavigate } from "react-router-dom";
+import { isAutheticated } from "src/auth";
+import swal from "sweetalert";
+
+const LeaveSalesCoordinator = () => {
+ const token = isAutheticated();
+ const navigate = useNavigate();
+ const [loading, setLoading] = useState(false);
+ const [salescoordinatorsData, setSalesCoOrdinatorsData] = useState([]);
+ const nameRef = useRef();
+ const mobileRef = useRef();
+ const verifyRef = useRef();
+ const [currentPage, setCurrentPage] = useState(1);
+ const [itemPerPage, setItemPerPage] = useState(10);
+ const [totalData, setTotalData] = useState(0);
+
+ const getSalesCoOrdinatorsData = async () => {
+ setLoading(true);
+ try {
+ const res = await axios.get(`/api/salescoordinator/getAll/`, {
+ headers: {
+ Authorization: `Bearer ${token}`,
+ },
+ params: {
+ page: currentPage,
+ show: itemPerPage,
+ name: nameRef.current.value,
+ mobileNumber: mobileRef.current.value,
+ isVerified: verifyRef.current.value,
+ },
+ });
+ setSalesCoOrdinatorsData(res.data?.salesCoOrinators);
+ setTotalData(res.data?.total_data);
+ } catch (err) {
+ const msg = err?.response?.data?.message || "Something went wrong!";
+ swal({
+ title: "Error",
+ text: msg,
+ icon: "error",
+ button: "Retry",
+ dangerMode: true,
+ });
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ useEffect(() => {
+ getSalesCoOrdinatorsData();
+ }, [currentPage, itemPerPage]);
+
+ const handleFilter = () => {
+ setCurrentPage(1);
+ getSalesCoOrdinatorsData();
+ };
+
+ return (
+
+
+
+
+
+
+
+ Sales Coordinators Leaves
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Name |
+ Mobile No. |
+ Email |
+ Verify |
+ Register On |
+ Action |
+
+
+
+
+ {loading ? (
+
+
+ Loading...
+ |
+
+ ) : salescoordinatorsData.length > 0 ? (
+ salescoordinatorsData.map((salescoordinator, i) => (
+
+
+ {salescoordinator?.name}
+ |
+
+ {salescoordinator?.mobileNumber}
+ |
+
+ {salescoordinator?.email || (
+
+ No Email Added!
+
+ )}
+ |
+
+
+ {salescoordinator?.isVerified ? "YES" : "NO"}
+
+ |
+
+ {new Date(
+ salescoordinator.createdAt
+ ).toLocaleString("en-IN", {
+ weekday: "short",
+ month: "short",
+ day: "numeric",
+ year: "numeric",
+ hour: "numeric",
+ minute: "numeric",
+ hour12: true,
+ })}
+ |
+
+
+
+
+ |
+
+ ))
+ ) : (
+
+
+ No Sales Coordinators Available...
+ |
+
+ )}
+
+
+
+
+
+
+
+ Showing {currentPage * itemPerPage - itemPerPage + 1} to{" "}
+ {Math.min(currentPage * itemPerPage, totalData)} of{" "}
+ {totalData} entries
+
+
+
+
+
+
+ -
+
+ setCurrentPage((prev) =>
+ prev > 1 ? prev - 1 : prev
+ )
+ }
+ >
+ Previous
+
+
+ - = totalData
+ ? "paginate_button page-item next disabled"
+ : "paginate_button page-item next"
+ }
+ >
+
+ setCurrentPage((prev) =>
+ prev * itemPerPage < totalData
+ ? prev + 1
+ : prev
+ )
+ }
+ >
+ Next
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
+
+export default LeaveSalesCoordinator;
diff --git a/src/views/Leaves/SingleLeaveSalesCoordinator.js b/src/views/Leaves/SingleLeaveSalesCoordinator.js
new file mode 100644
index 0000000..0d2fa7b
--- /dev/null
+++ b/src/views/Leaves/SingleLeaveSalesCoordinator.js
@@ -0,0 +1,262 @@
+import React, { useState, useEffect } from "react";
+import { useParams, useNavigate } from "react-router-dom";
+import axios from "axios";
+import Button from "@material-ui/core/Button";
+import { isAutheticated } from "src/auth";
+import swal from "sweetalert";
+
+const SingleLeaveSalesCoOrdinator = () => {
+ const { id } = useParams();
+ const token = isAutheticated();
+ const navigate = useNavigate();
+ const [loading, setLoading] = useState(false);
+ const [salesCoordinator, setSalesCoordinator] = useState({});
+ const [leaveData, setLeaveData] = useState([]);
+ const [currentPage, setCurrentPage] = useState(1);
+ const [itemPerPage, setItemPerPage] = useState(10);
+ const [totalData, setTotalData] = useState(0);
+
+ const getSingleSalesCoOrdinatorLeave = async () => {
+ setLoading(true);
+ try {
+ const res = await axios.get(`/api/v1/leave/${id}`, {
+ headers: {
+ Authorization: `Bearer ${token}`,
+ },
+ params: {
+ page: currentPage,
+ show: itemPerPage,
+ },
+ });
+ // console.log(res.data);
+ setSalesCoordinator(res.data?.user);
+ setLeaveData(res.data?.leave);
+ setTotalData(res.data?.total_data);
+ } catch (err) {
+ const msg = err?.response?.data?.message || "Something went wrong!";
+ swal({
+ title: "Error",
+ text: msg,
+ icon: "error",
+ button: "Retry",
+ dangerMode: true,
+ });
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ useEffect(() => {
+ getSingleSalesCoOrdinatorLeave();
+ }, [itemPerPage, currentPage]);
+
+ return (
+
+
+
+
+
+
+
+ SalesCoOrdinator Leave
+
+ {salesCoordinator.name} ({salesCoordinator.email})
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Date |
+ Time |
+ Location |
+ Reason Type |
+ Reason |
+
+
+
+
+ {loading ? (
+
+
+ Loading...
+ |
+
+ ) : leaveData?.length > 0 ? (
+ leaveData?.map((leave, i) => (
+
+
+ {new Date(leave?.date).toLocaleDateString(
+ "en-IN",
+ {
+ weekday: "short",
+ month: "short",
+ day: "numeric",
+ year: "numeric",
+ }
+ )}
+ |
+
+ {leave?.time || (
+
+ No Time Added!
+
+ )}
+ |
+
+ {leave?.location || (
+
+ No Location Added!
+
+ )}
+ |
+
+ {leave?.leaveType || (
+
+ No Reason Type Added!
+
+ )}
+ |
+
+ {leave?.reason || (
+
+ No Reason Added!
+
+ )}
+ |
+
+ ))
+ ) : (
+
+
+ No Leave Records Available...
+ |
+
+ )}
+
+
+
+
+
+
+
+ Showing {currentPage * itemPerPage - itemPerPage + 1} to{" "}
+ {Math.min(currentPage * itemPerPage, totalData)} of{" "}
+ {totalData} entries
+
+
+
+
+
+
+ -
+
+ setCurrentPage((prev) =>
+ prev > 1 ? prev - 1 : prev
+ )
+ }
+ >
+ Previous
+
+
+ - = totalData
+ ? "paginate_button page-item next disabled"
+ : "paginate_button page-item next"
+ }
+ >
+
+ setCurrentPage((prev) =>
+ prev * itemPerPage < totalData
+ ? prev + 1
+ : prev
+ )
+ }
+ >
+ Next
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
+
+export default SingleLeaveSalesCoOrdinator;
diff --git a/src/views/Leaves/TodayLeaves.js b/src/views/Leaves/TodayLeaves.js
new file mode 100644
index 0000000..ae8a9d7
--- /dev/null
+++ b/src/views/Leaves/TodayLeaves.js
@@ -0,0 +1,283 @@
+import React, { useState, useEffect } from "react";
+import { Link } from "react-router-dom";
+import axios from "axios";
+import Button from "@material-ui/core/Button";
+import { useNavigate } from "react-router-dom";
+import { isAutheticated } from "src/auth";
+import swal from "sweetalert";
+
+const TodayLeave = () => {
+ const token = isAutheticated();
+ const navigate = useNavigate();
+ const [loading, setLoading] = useState(false);
+ const [salescoordinatorsData, setSalesCoOrdinatorsData] = useState([]);
+ const [currentPage, setCurrentPage] = useState(1);
+ const [itemPerPage, setItemPerPage] = useState(10);
+ const [totalData, setTotalData] = useState(0);
+
+ const getTodayLeaveData = async () => {
+ setLoading(true);
+ try {
+ const res = await axios.get(`/api/v1/leave/today`, {
+ headers: {
+ Authorization: `Bearer ${token}`,
+ },
+ params: {
+ page: currentPage,
+ show: itemPerPage,
+ },
+ });
+ console.log(res.data);
+ setSalesCoOrdinatorsData(res.data?.leave);
+ setTotalData(res.data?.total_data);
+ } catch (err) {
+ const msg = err?.response?.data?.message || "Something went wrong!";
+ swal({
+ title: "Error",
+ text: msg,
+ icon: "error",
+ button: "Retry",
+ dangerMode: true,
+ });
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ useEffect(() => {
+ getTodayLeaveData();
+ }, [itemPerPage, currentPage]);
+
+ const today = new Date().toLocaleDateString("en-IN", {
+ weekday: "short",
+ month: "short",
+ day: "numeric",
+ year: "numeric",
+ });
+
+ return (
+
+
+
+
+
+
+
+ Today's SalesCoOrdinators Leave
+
+ Date : {today}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ID |
+ Name |
+ Email |
+ Position |
+ Time |
+ ReasonType |
+ Reason |
+
+
+
+
+ {loading ? (
+
+
+ Loading...
+ |
+
+ ) : salescoordinatorsData?.length > 0 ? (
+ salescoordinatorsData?.map((leave, i) => {
+ return (
+
+
+ {leave?.user?.uniqueId}
+ |
+
+ {leave?.user?.name}
+ |
+
+ {leave?.user?.email ? (
+ leave?.user?.email
+ ) : (
+
+ No Email Added!
+
+ )}
+ |
+
+ {leave?.user?.userType || (
+
+ No Position Added!
+
+ )}
+ |
+
+ {leave?.time || (
+
+ No Time Added!
+
+ )}
+ |
+
+ {leave?.leaveType || (
+
+ No Reason Type Added!
+
+ )}
+ |
+
+ {leave?.reason ? (
+ leave?.reason
+ ) : (
+
+ No Reason Added!
+
+ )}
+ |
+
+ );
+ })
+ ) : (
+
+
+ No Leave Records Available...
+ |
+
+ )}
+
+
+
+
+
+
+
+ Showing {currentPage * itemPerPage - itemPerPage + 1} to{" "}
+ {Math.min(currentPage * itemPerPage, totalData)} of{" "}
+ {totalData} entries
+
+
+
+
+
+
+ -
+
+ setCurrentPage((prev) =>
+ prev > 1 ? prev - 1 : prev
+ )
+ }
+ >
+ Previous
+
+
+ - = totalData
+ ? "paginate_button page-item next disabled"
+ : "paginate_button page-item next"
+ }
+ >
+
+ setCurrentPage((prev) =>
+ prev * itemPerPage < totalData
+ ? prev + 1
+ : prev
+ )
+ }
+ >
+ Next
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
+
+export default TodayLeave;
diff --git a/src/views/PrincipalDistributors/addPrincipalDistributor.js b/src/views/PrincipalDistributors/addPrincipalDistributor.js
index 241e540..1dfee25 100644
--- a/src/views/PrincipalDistributors/addPrincipalDistributor.js
+++ b/src/views/PrincipalDistributors/addPrincipalDistributor.js
@@ -85,26 +85,43 @@ const AddPrincipalDistributor = () => {
};
const generatePassword = (name, email) => {
+ // Combine name and email, and convert to lowercase
const combinedStr = (name + email).toLowerCase();
+
+ // Define character pools
const specialChars = "@#*";
- const alphaChars = combinedStr.match(/[a-zA-Z]/g);
- const filteredChars = combinedStr.match(/[^\W_]/g);
- let passwordChars = alphaChars.concat(filteredChars);
-
- const specialChar = specialChars.charAt(
- Math.floor(Math.random() * specialChars.length)
- );
- const randomIndex = Math.floor(Math.random() * (passwordChars.length + 1));
- passwordChars.splice(randomIndex, 0, specialChar);
-
+ const numbers = "0123456789";
+ const alphaLower = combinedStr.match(/[a-z]/g) || [];
+ const alphaUpper = combinedStr.match(/[A-Z]/g) || [];
+
+ // Ensure at least one character from each category
+ const specialChar = specialChars.charAt(Math.floor(Math.random() * specialChars.length));
+ const numberChar = numbers.charAt(Math.floor(Math.random() * numbers.length));
+ const lowerChar = alphaLower.length > 0 ? alphaLower[Math.floor(Math.random() * alphaLower.length)] : String.fromCharCode(Math.floor(Math.random() * 26) + 97);
+ const upperChar = alphaUpper.length > 0 ? alphaUpper[Math.floor(Math.random() * alphaUpper.length)] : String.fromCharCode(Math.floor(Math.random() * 26) + 65);
+
+ // Combine required characters
+ let passwordChars = [specialChar, numberChar, lowerChar, upperChar];
+
+ // Fill remaining positions with random characters from the combined string
+ const allChars = combinedStr + specialChars + numbers;
+ while (passwordChars.length < 8) {
+ passwordChars.push(allChars.charAt(Math.floor(Math.random() * allChars.length)));
+ }
+
+ // Shuffle characters to ensure randomness
passwordChars = passwordChars.sort(() => Math.random() - 0.5);
- const password = passwordChars.join("").slice(0, 8);
+
+ // Generate password of length 8
+ const password = passwordChars.slice(0, 8).join("");
+
return password;
};
-
+
const handleFormSubmit = async (e) => {
e.preventDefault();
try {
+ // Validate input fields
if (
!user.name ||
!user.email ||
@@ -116,17 +133,21 @@ const AddPrincipalDistributor = () => {
) {
throw new Error("Fill all fields!");
}
+
setLoading(true);
const generatedPassword = generatePassword(user.name, user.email);
-
+
+ // Attempt to register user
const userResponse = await axios.post("/api/v1/user/register", {
...user,
password: generatedPassword,
+ role:"principal-Distributor",
});
-
- if (userResponse.status === 201) {
+
+ if (userResponse.status === 201 || userResponse.status === 200) {
const userId = userResponse.data.userId;
-
+
+ // Add address details for the user
const addressResponse = await axios.post(
`/api/shipping/address/admin/new/${userId}`,
{
@@ -140,6 +161,7 @@ const AddPrincipalDistributor = () => {
},
}
);
+
setLoading(false);
if (addressResponse.status === 201) {
toast.success("Principal Distributor and Address Added Successfully");
@@ -152,6 +174,7 @@ const AddPrincipalDistributor = () => {
toast.error(error.response?.data?.message || "Something went wrong!");
}
};
+
const handleCancel = () => {
navigate("/principal-distributor");
|