territory manager added

This commit is contained in:
Sibunnayak 2024-07-30 13:40:47 +05:30
parent 810d5770b5
commit f9a7338480
11 changed files with 1182 additions and 81 deletions

View File

@ -53,6 +53,7 @@
"draft-js-export-html": "^1.4.1",
"draft-js-import-html": "^1.4.1",
"file-saver": "^2.0.5",
"jwt-decode": "^4.0.0",
"md5": "^2.3.0",
"moment": "^2.30.1",
"prop-types": "^15.7.2",

View File

@ -111,82 +111,159 @@
// };
// export default App;
// import React, { Suspense, useEffect, useState } from "react";
// import axios from "axios";
// import { HashRouter, Routes, Route, Navigate } from "react-router-dom";
// import { Toaster } from "react-hot-toast";
// import "./scss/style.scss";
// import ForgotPassword from "./views/pages/register/ForgotPassword";
// import NewRegister from "./views/pages/register/NewRegister";
// import ProtectedRoute from './components/ProtectedRoute';
// import { isAutheticated } from "./auth";
// import InternetConnectionPopUp from "./views/InternetConnectionPopUp";
// const loading = (
// <div className="pt-3 text-center">
// <div className="sk-spinner sk-spinner-pulse"></div>
// </div>
// );
// const DefaultLayout = React.lazy(() => import("./layout/DefaultLayout"));
// const Login = React.lazy(() => import("./views/pages/login/Login"));
// const Page404 = React.lazy(() => import("./views/pages/register/page404/Page404"));
// const Page500 = React.lazy(() => import("./views/pages/page500/Page500"));
// const App = () => {
// const [userdata, setUserData] = useState(null);
// const token = isAutheticated();
// useEffect(() => {
// const getUser = async () => {
// let existanceData = localStorage.getItem("authToken");
// if (!existanceData) {
// setUserData(false);
// } else {
// try {
// let response = await axios.get(`/api/v1/user/details`, {
// headers: {
// Authorization: `Bearer ${token}`,
// },
// });
// const data = response?.data;
// if (data?.success && (data?.user?.role === "admin" || data?.user?.role === "Employee")) {
// setUserData(data?.user);
// } else {
// setUserData(false);
// }
// } catch (err) {
// setUserData(false);
// console.log(err);
// }
// }
// };
// getUser();
// }, [token]);
// return (
// <HashRouter>
// <Suspense fallback={loading}>
// <Routes>
// <Route path="/" element={<Login />} />
// <Route path="/register" element={<NewRegister />} />
// <Route path="/password/forgot" element={<ForgotPassword />} />
// <Route path="/404" element={<Page404 />} />
// <Route path="/500" element={<Page500 />} />
// <Route
// path="/*"
// element={<ProtectedRoute element={DefaultLayout} />}
// />
// {/* Redirect all other routes to 404 */}
// <Route path="*" element={<Navigate to="/404" />} />
// </Routes>
// <Toaster />
// </Suspense>
// <InternetConnectionPopUp />
// </HashRouter>
// );
// };
// export default App;
import React, { Suspense, useEffect, useState } from "react";
import axios from "axios";
import { HashRouter, Routes, Route, Navigate } from "react-router-dom";
import { Toaster } from "react-hot-toast";
import "./scss/style.scss";
import ForgotPassword from "./views/pages/register/ForgotPassword";
import NewRegister from "./views/pages/register/NewRegister";
import ProtectedRoute from './components/ProtectedRoute';
import { HashRouter, Route, Routes } from "react-router-dom";
import { useSelector } from "react-redux";
import { isAutheticated } from "./auth";
import InternetConnectionPopUp from "./views/InternetConnectionPopUp";
const loading = (
<div className="pt-3 text-center">
<div className="sk-spinner sk-spinner-pulse"></div>
</div>
);
import "./scss/style.scss";
import ProtectedRoute from "./components/ProtectedRoute";
import axios from "axios";
// Containers
const DefaultLayout = React.lazy(() => import("./layout/DefaultLayout"));
// Pages
const Login = React.lazy(() => import("./views/pages/login/Login"));
const Page404 = React.lazy(() => import("./views/pages/register/page404/Page404"));
const Page404 = React.lazy(() =>
import("./views/pages/register/page404/Page404")
);
const Page500 = React.lazy(() => import("./views/pages/page500/Page500"));
const App = () => {
const [userdata, setUserData] = useState(null);
const token = isAutheticated();
const [userdata, setUserData] = useState(null);
const token = isAutheticated();
useEffect(() => {
const getUser = async () => {
let existanceData = localStorage.getItem("authToken");
if (!existanceData) {
setUserData(false);
} else {
try {
let response = await axios.get(`/api/v1/user/details`, {
headers: {
Authorization: `Bearer ${token}`,
},
});
const data = response?.data;
if (data?.success && (data?.user?.role === "admin" || data?.user?.role === "Employee")) {
setUserData(data?.user);
} else {
setUserData(false);
}
} catch (err) {
setUserData(false);
console.log(err);
}
}
};
getUser();
}, [token]);
return (
<HashRouter>
<Suspense fallback={loading}>
<Routes>
<Route path="/" element={<Login />} />
<Route path="/register" element={<NewRegister />} />
<Route path="/password/forgot" element={<ForgotPassword />} />
<Route path="/404" element={<Page404 />} />
<Route path="/500" element={<Page500 />} />
<Route
path="/*"
element={<ProtectedRoute element={DefaultLayout} />}
/>
{/* Redirect all other routes to 404 */}
<Route path="*" element={<Navigate to="/404" />} />
</Routes>
<Toaster />
</Suspense>
<InternetConnectionPopUp />
</HashRouter>
);
useEffect(() => {
const getUser = async () => {
let existanceData = localStorage.getItem("authToken");
if (!existanceData) {
setUserData(false);
} else {
try {
let response = await axios.get(`/api/v1/user/details`, {
headers: {
Authorization: `Bearer ${token}`,
},
});
const data = response?.data;
if (
data?.success &&
(data?.user?.role === "admin" || data?.user?.role === "Employee")
) {
setUserData(data?.user);
} else {
setUserData(false);
}
} catch (err) {
setUserData(false);
console.log(err);
}
}
};
getUser();
}, [token]);
return (
<HashRouter>
<Suspense
fallback={
<div className="pt-3 text-center">
<div className="sk-spinner sk-spinner-pulse"></div>
</div>
}
>
<Routes>
{/* <Route exact path="/change-password" name="My profile" element={<ChangePassword />} /> */}
<Route exact path="/" name="Login Page" element={<Login />} />
<Route exact path="/404" name="Page 404" element={<Page404 />} />
<Route exact path="/500" name="Page 500" element={<Page500 />} />
<Route
path="/*"
element={<ProtectedRoute element={DefaultLayout} />}
/>
<Route path="*" name="Home" element={<DefaultLayout />} />
</Routes>
</Suspense>
</HashRouter>
);
};
export default App;

View File

@ -83,6 +83,13 @@ const _nav = [
to: "/salescoordinators",
group: "SalesCoOrdinator",
},
{
component: CNavItem,
name: "Territory Managers",
icon: <CIcon icon={cilUser} customClassName="nav-icon" />,
to: "/territorymanagers",
group: "TerritoryManager",
},
{
component: CNavItem,
name: "Attendance",

View File

@ -16,20 +16,63 @@
// }
// export default ProtectedRoute
import React, { useEffect } from "react";
import { useNavigate } from "react-router-dom";
const ProtectedRoute = ({ element: Element }) => {
const navigate = useNavigate();
// import React, { useEffect } from "react";
// import { useNavigate } from "react-router-dom";
useEffect(() => {
if (!localStorage.getItem('authToken')) {
navigate('/');
}
}, [navigate]);
// const ProtectedRoute = ({ element: Element }) => {
// const navigate = useNavigate();
return <Element />;
// useEffect(() => {
// if (!localStorage.getItem('authToken')) {
// navigate('/');
// }
// }, [navigate]);
// return <Element />;
// }
// export default ProtectedRoute;
/* eslint-disable react/react-in-jsx-scope */
/* eslint-disable react/prop-types */
import { useEffect } from 'react'
import { useNavigate } from 'react-router-dom'
import { jwtDecode } from 'jwt-decode'
const isTokenExpired = (token) => {
try {
const decodedToken = jwtDecode(token)
// console.log('Decoded Token:', decodedToken) // Debugging
const currentTime = Date.now() / 1000
// console.log('Current Time:', currentTime) // Debugging
// console.log('Token Expiration Time:', decodedToken.exp) // Debugging
return decodedToken.exp < currentTime
} catch (error) {
console.error('Error decoding token:', error) // Debugging
return true // If there's an error decoding the token, consider it expired
}
}
export default ProtectedRoute;
const ProtectedRoute = ({ element: Element }) => {
const navigate = useNavigate()
useEffect(() => {
const checkToken = () => {
const token = localStorage.getItem('authToken')
// console.log('Token:', token) // Debugging
if (!token || isTokenExpired(token)) {
// console.log('Token is expired or not present, redirecting to login')
navigate('/')
} else {
// console.log('Token is valid')
}
}
checkToken()
}, [navigate])
return <Element />
}
export default ProtectedRoute

View File

@ -133,6 +133,10 @@ import SingleAttendanceSalesCoOrdinator from "./views/Attendance/SingleAttendanc
import TodayLeave from "./views/Leaves/TodayLeaves";
import LeaveSalesCoordinator from "./views/Leaves/LeaveSalesCoordinator";
import SingleLeaveSalesCoOrdinator from "./views/Leaves/SingleLeaveSalesCoordinator";
//TerritoryManagers
import EditTerritoryManager from "./views/TerritoryManager/EditTerritoryManager";
import TerritoryManager from "./views/TerritoryManager/TerritoryManager";
import AddTerritoryManager from "./views/TerritoryManager/AddTerritoryManager";
const routes = [
//dashboard
@ -181,7 +185,7 @@ const routes = [
element: Categories,
navName: "Product Management",
},
//SalesCoOrdinator
{
path: "/salescoordinator/edit/:id",
name: "Edit SalesCoOrdinator",
@ -200,6 +204,25 @@ const routes = [
element: AddSalesCoOrdinator,
navName: "SalesCoOrdinators",
},
//TerritoryManager
{
path: "/territorymanager/edit/:id",
name: "Edit TerritoryManager",
element: EditTerritoryManager,
navName: "TerritoryManagers",
},
{
path: "/territorymanagers",
name: "TerritoryManagers",
element: TerritoryManager,
navName: "TerritoryManagers",
},
{
path: "/territorymanager/add",
name: "Add TerritoryManagers",
element: AddTerritoryManager,
navName: "TerritoryManagers",
},
// Attendence
{
path: "/attendance/today",

View File

@ -27,6 +27,7 @@ const TodayAttendance = () => {
show: itemPerPage,
},
});
// console.log(res.data);
setSalesCoOrdinatorsData(res.data?.attendance);
setTotalData(res.data?.total_data);
} catch (err) {
@ -135,6 +136,7 @@ const TodayAttendance = () => {
<th className="text-start">Email</th>
<th className="text-start">Position</th>
<th className="text-start">Time</th>
<th className="text-start">Location</th>
<th className="text-start">Note</th>
</tr>
</thead>
@ -179,6 +181,13 @@ const TodayAttendance = () => {
</small>
)}
</td>
<td className="text-start">
{attendance?.location || (
<small className="m-0 text-secondary">
No Location Added!
</small>
)}
</td>
<td className="text-start">
{attendance?.notes ? (
attendance?.notes

View File

@ -14,7 +14,7 @@ const AddSalesCoOrdinator = () => {
const [formData, setFormData] = useState({
name: "",
email: "",
countryCode: "",
countryCode: "+91",
mobileNumber: "",
otp: "",
});
@ -137,6 +137,7 @@ const AddSalesCoOrdinator = () => {
value={formData.countryCode}
onChange={handleChange}
required
disabled
/>
</div>
<div style={{ flex: 3 }}>

View File

@ -262,6 +262,7 @@ const EditSalesCoOrdinator = () => {
value={formData.countryCode}
onChange={handleChange}
required
disabled
/>
</div>
<div className="mr-2" style={{ flex: 3 }}>

View File

@ -0,0 +1,198 @@
import React, { useState } from "react";
import axios from "axios";
import { useNavigate } from "react-router-dom";
import { isAutheticated } from "src/auth";
import Modal from "react-bootstrap/Modal";
import Button from "react-bootstrap/Button";
import Form from "react-bootstrap/Form";
import swal from "sweetalert";
const AddTerritoryManager = () => {
const navigate = useNavigate();
const token = isAutheticated();
const [formData, setFormData] = useState({
name: "",
email: "",
countryCode: "+91",
mobileNumber: "",
otp: "",
});
const [showModal, setShowModal] = useState(false);
const handleChange = (e) => {
setFormData({ ...formData, [e.target.name]: e.target.value });
};
const handleRegister = async (e) => {
e.preventDefault();
try {
await axios.post("/api/territorymanager/register", formData, {
headers: {
Authorization: `Bearer ${token}`,
},
});
setShowModal(true); // Show OTP modal after registration
} catch (error) {
console.error(error);
let msg =
error?.response?.data?.message ||
"Failed to register TerritoryManager. Please try again.";
swal({
title: "Warning",
text: msg,
icon: "error",
button: "Retry",
dangerMode: true,
});
}
};
const handleVerifyOTP = async () => {
try {
await axios.post("/api/territorymanager/verify-otp", {
otp: formData.otp,
fullMobileNumber: `${formData.countryCode}${formData.mobileNumber}`,
});
setShowModal(false); // Close OTP modal after verification
swal({
title: "Success",
text: "OTP verified successfully!",
icon: "success",
button: "OK",
}).then(() => {
navigate("/territorymanagers"); // Navigate to success page or desired route
});
} catch (error) {
console.error(error);
let msg =
error?.response?.data?.message ||
"OTP verification failed. Please try again.";
swal({
title: "Warning",
text: msg,
icon: "error",
button: "Retry",
dangerMode: true,
});
}
};
// Function to handle cancel button click
const handleCancel = () => {
navigate("/territorymanagers"); // Navigate to '/territorymanagers'
};
return (
<div className="main-content">
<div className="my-3 page-content">
<div className="container-fluid">
<div className="row">
<div className="col-12">
<div className="page-title-box d-flex align-items-center justify-content-between">
<h4 className="mb-3">Add Sales Coordinator</h4>
<Button variant="danger" onClick={handleCancel}>
Cancel
</Button>
</div>
</div>
</div>
<div className="row">
<div className="col-lg-12">
<div className="card">
<div className="card-body">
<form onSubmit={handleRegister}>
<div className="form-group">
<label>Name</label>
<input
type="text"
name="name"
className="form-control"
value={formData.name}
onChange={handleChange}
required
/>
</div>
<div className="form-group">
<label>Email</label>
<input
type="email"
name="email"
className="form-control"
value={formData.email}
onChange={handleChange}
required
/>
</div>
<div className="form-group d-flex">
<div className="mr-2" style={{ flex: 1 }}>
<label>Country Code</label>
<input
type="text"
name="countryCode"
className="form-control"
value={formData.countryCode}
onChange={handleChange}
required
disabled
/>
</div>
<div style={{ flex: 3 }}>
<label>Mobile Number</label>
<input
type="text"
name="mobileNumber"
className="form-control"
value={formData.mobileNumber}
onChange={handleChange}
required
/>
</div>
</div>
<button type="submit" className="btn btn-primary">
Register
</button>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
{/* OTP Modal */}
<Modal show={showModal} onHide={() => setShowModal(false)}>
<Modal.Header closeButton>
<Modal.Title>Enter OTP</Modal.Title>
</Modal.Header>
<Modal.Body>
<Form.Group>
<Form.Label>OTP</Form.Label>
<Form.Control
type="text"
placeholder="Enter OTP"
value={formData.otp}
onChange={(e) =>
setFormData({ ...formData, otp: e.target.value })
}
required
/>
</Form.Group>
</Modal.Body>
<Modal.Footer>
<Button variant="secondary" onClick={() => setShowModal(false)}>
Cancel
</Button>
<Button variant="primary" onClick={handleVerifyOTP}>
Verify OTP
</Button>
</Modal.Footer>
</Modal>
</div>
);
};
export default AddTerritoryManager;

View File

@ -0,0 +1,396 @@
import React, { useState, useEffect } from "react";
import axios from "axios";
import { useNavigate, useParams } from "react-router-dom";
import { isAutheticated } from "src/auth";
import Modal from "react-bootstrap/Modal";
import Button from "react-bootstrap/Button";
import Form from "react-bootstrap/Form";
import swal from "sweetalert";
const EditTerritoryManager = () => {
const navigate = useNavigate();
const token = isAutheticated();
const { id } = useParams();
const [formData, setFormData] = useState({
name: "",
email: "",
countryCode: "",
mobileNumber: "",
currentPassword: "",
newPassword: "",
confirmPassword: "",
otp: "",
});
const [showVerifyModal, setShowVerifyModal] = useState(false);
const [showPasswordModal, setShowPasswordModal] = useState(false);
useEffect(() => {
getTerritoryManagerData();
}, []);
const getTerritoryManagerData = async () => {
try {
const response = await axios.get(`/api/territorymanager/getOne/${id}`, {
headers: {
Authorization: `Bearer ${token}`,
},
});
const { data } = response.data;
// Assuming country code always starts with + and is followed by 1-3 digits
const fullMobileNumber = data?.mobileNumber || "";
const countryCodeMatch = fullMobileNumber.match(/^\+\d{1,2}/);
const countryCode = countryCodeMatch ? countryCodeMatch[0] : "";
const mobileNumber = fullMobileNumber.replace(countryCode, "");
setFormData({
name: data?.name || "",
email: data?.email || "",
countryCode: countryCode,
mobileNumber: mobileNumber,
currentPassword: "",
newPassword: "",
confirmPassword: "",
otp: "",
});
} catch (error) {
console.error("Error fetching sales coordinator data: ", error);
}
};
const handleChange = (e) => {
setFormData({ ...formData, [e.target.name]: e.target.value });
};
const handleUpdateBasicInfo = () => {
axios
.patch(
`/api/territorymanager/profile/update/${id}`,
{
name: formData.name,
email: formData.email,
},
{
headers: {
Authorization: `Bearer ${token}`,
},
}
)
.then((response) => {
swal({
title: "Success",
text: "Sales coordinator information updated successfully!",
icon: "success",
button: "OK",
});
})
.catch((error) => {
let msg = error?.response?.data?.message || "Something went wrong!";
swal({
title: "Warning",
text: msg,
icon: "error",
button: "Retry",
dangerMode: true,
});
});
};
const handleVerifyMobile = () => {
axios
.post(
`/api/territorymanager/update-mobile-number/${id}`,
{
newCountryCode: formData.countryCode,
newMobileNumber: formData.mobileNumber,
},
{
headers: {
Authorization: `Bearer ${token}`,
},
}
)
.then(() => {
setShowVerifyModal(true);
})
.catch((error) => {
let msg = error?.response?.data?.message || "Something went wrong!";
swal({
title: "Warning",
text: msg,
icon: "error",
button: "Retry",
dangerMode: true,
});
});
};
const handleVerifyOTP = () => {
axios
.post(
"/api/territorymanager/verify-updated-mobile-otp",
{
otp: formData.otp,
newMobileNumber: `${formData.countryCode}${formData.mobileNumber}`,
},
{
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json",
},
}
)
.then(() => {
setShowVerifyModal(false);
// Handle success, if needed
})
.catch((error) => {
let msg = error?.response?.data?.message || "Something went wrong!";
swal({
title: "Warning",
text: msg,
icon: "error",
button: "Retry",
dangerMode: true,
});
});
};
const handleChangePassword = () => {
axios
.put(
`/api/territorymanager/password/update/${id}`,
{
oldPassword: formData.currentPassword,
newPassword: formData.newPassword,
confirmPassword: formData.confirmPassword,
},
{
headers: {
Authorization: `Bearer ${token}`,
},
}
)
.then(() => {
setShowPasswordModal(false);
swal({
title: "Success",
text: "Password updated successfully!",
icon: "success",
button: "OK",
});
})
.catch((error) => {
let msg = error?.response?.data?.message || "Something went wrong!";
swal({
title: "Warning",
text: msg,
icon: "error",
button: "Retry",
dangerMode: true,
});
});
};
const onCancel = () => {
navigate("/territorymanagers");
};
return (
<div className="main-content">
<div className="my-3 page-content">
<div className="container-fluid">
<div className="row">
<div className="col-12">
<div className="page-title-box d-flex align-items-center justify-content-between">
<h4 className="mb-3">Edit Sales Coordinator</h4>
<button
onClick={onCancel}
type="button"
className="btn btn-warning btn-cancel waves-effect waves-light mr-3"
>
Back
</button>
</div>
</div>
</div>
<div className="row">
<div className="col-lg-12">
<div className="card">
<div className="card-body">
<div className="form-group">
<label>Name</label>
<input
type="text"
name="name"
className="form-control"
value={formData.name}
onChange={handleChange}
required
/>
</div>
<div className="form-group">
<label>Email</label>
<input
type="email"
name="email"
className="form-control"
value={formData.email}
onChange={handleChange}
required
/>
</div>
<div className="mt-4 mb-4">
<button
type="button"
className="btn btn-primary mr-2"
onClick={handleUpdateBasicInfo}
>
Update
</button>
</div>
<div className="form-group d-flex align-items-center">
<div className="mr-2" style={{ flex: 1 }}>
<label>Country Code</label>
<input
type="text"
name="countryCode"
className="form-control"
value={formData.countryCode}
onChange={handleChange}
required
disabled
/>
</div>
<div className="mr-2" style={{ flex: 3 }}>
<label>Mobile Number</label>
<input
type="text"
name="mobileNumber"
className="form-control"
value={formData.mobileNumber}
onChange={handleChange}
required
/>
</div>
<div className="mr-2" style={{ flex: 1 }}>
<label>&nbsp;</label>
<button
type="button"
className="btn btn-success"
onClick={handleVerifyMobile}
style={{ display: "block" }}
>
Verify Mobile
</button>
</div>
</div>
<div className="mt-4 mb-4">
<button
type="button"
className="btn btn-danger"
onClick={() => setShowPasswordModal(true)}
>
Change Password
</button>
</div>
</div>
</div>
</div>
</div>
{/* OTP Verification Modal */}
<Modal
show={showVerifyModal}
onHide={() => setShowVerifyModal(false)}
>
<Modal.Header closeButton>
<Modal.Title>Verify Mobile</Modal.Title>
</Modal.Header>
<Modal.Body>
<Form.Group>
<Form.Label>Enter OTP</Form.Label>
<Form.Control
type="text"
placeholder="Enter OTP"
name="otp"
value={formData.otp}
onChange={handleChange}
/>
</Form.Group>
</Modal.Body>
<Modal.Footer>
<Button
variant="secondary"
onClick={() => setShowVerifyModal(false)}
>
Cancel
</Button>
<Button variant="primary" onClick={handleVerifyOTP}>
Verify OTP
</Button>
</Modal.Footer>
</Modal>
{/* Change Password Modal */}
<Modal
show={showPasswordModal}
onHide={() => setShowPasswordModal(false)}
>
<Modal.Header closeButton>
<Modal.Title>Change Password</Modal.Title>
</Modal.Header>
<Modal.Body>
<Form.Group>
<Form.Label>Current Password</Form.Label>
<Form.Control
type="password"
placeholder="Enter current password"
name="currentPassword"
value={formData.currentPassword}
onChange={handleChange}
/>
</Form.Group>
<Form.Group>
<Form.Label>New Password</Form.Label>
<Form.Control
type="password"
placeholder="Enter new password"
name="newPassword"
value={formData.newPassword}
onChange={handleChange}
/>
</Form.Group>
<Form.Group>
<Form.Label>Confirm New Password</Form.Label>
<Form.Control
type="password"
placeholder="Confirm new password"
name="confirmPassword"
value={formData.confirmPassword}
onChange={handleChange}
/>
</Form.Group>
</Modal.Body>
<Modal.Footer>
<Button
variant="secondary"
onClick={() => setShowPasswordModal(false)}
>
Cancel
</Button>
<Button variant="danger" onClick={handleChangePassword}>
Change Password
</Button>
</Modal.Footer>
</Modal>
</div>
</div>
</div>
);
};
export default EditTerritoryManager;

View File

@ -0,0 +1,345 @@
import React, { useState, useEffect, useRef, useCallback } 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";
import debounce from 'lodash.debounce';
const TerritoryManager = () => {
const token = isAutheticated();
const navigate = useNavigate();
const [loading, setLoading] = useState(false);
const [success, setSuccess] = useState(true);
const [territorymanagersData, setTerritoryManagersData] = useState([]);
const nameRef = useRef();
const mobileRef = useRef();
const VerifyTerritoryManagerRef = useRef();
const [currentPage, setCurrentPage] = useState(1);
const [itemPerPage, setItemPerPage] = useState(10);
const [totalData, setTotalData] = useState(0);
const getTerritoryManagersData = async () => {
setLoading(true);
try {
const res = await axios.get(`/api/territorymanager/getAll/`, {
headers: {
Authorization: `Bearer ${token}`,
},
params: {
page: currentPage,
show: itemPerPage,
name: nameRef.current.value,
mobileNumber: mobileRef.current.value,
isVerified: VerifyTerritoryManagerRef.current.value,
},
});
setTerritoryManagersData(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(() => {
getTerritoryManagersData();
}, [success, itemPerPage, currentPage]);
const debouncedSearch = useCallback(debounce(() => {
setCurrentPage(1);
getTerritoryManagersData();
}, 500), []);
const handleSearchChange = () => {
debouncedSearch();
};
const handleDelete = (id) => {
swal({
title: "Are you sure?",
icon: "error",
buttons: {
Yes: { text: "Yes", value: true },
Cancel: { text: "Cancel", value: "cancel" },
},
}).then((value) => {
if (value === true) {
axios
.delete(`/api/territorymanager/delete/${id}`, {
headers: {
"Access-Control-Allow-Origin": "*",
Authorization: `Bearer ${token}`,
},
})
.then((res) => {
swal({
title: "Deleted",
text: "TerritoryManager Deleted successfully!",
icon: "success",
button: "ok",
});
setSuccess((prev) => !prev);
})
.catch((err) => {
let msg = err?.response?.data?.message
? err?.response?.data?.message
: "Something went wrong!";
swal({
title: "Warning",
text: msg,
icon: "error",
button: "Retry",
dangerMode: true,
});
});
}
});
};
return (
<div className="main-content">
<div className="page-content">
<div className="container-fluid">
<div className="row">
<div className="col-12">
<div className="page-title-box d-flex align-items-center justify-content-between">
<div style={{ fontSize: "22px" }} className="fw-bold">
TerritoryManagers
</div>
<div className="page-title-right">
<Button
variant="contained"
color="primary"
style={{
fontWeight: "bold",
marginBottom: "1rem",
textTransform: "capitalize",
}}
onClick={() => {
navigate("/territorymanager/add", { replace: true });
}}
>
Add TerritoryManager
</Button>
</div>
</div>
</div>
</div>
<div className="row">
<div className="col-lg-12">
<div className="card">
<div className="card-body">
<div className="row ml-0 mr-0 mb-10">
<div className="col-lg-1">
<div className="dataTables_length">
<label className="w-100">
Show
<select
onChange={(e) => {
setItemPerPage(e.target.value);
setCurrentPage(1);
}}
className="form-control"
disabled={loading}
>
<option value="10">10</option>
<option value="25">25</option>
<option value="50">50</option>
<option value="100">100</option>
</select>
entries
</label>
</div>
</div>
<div className="col-lg-3">
<label>TerritoryManager Name:</label>
<input
type="text"
placeholder="TerritoryManager name"
className="form-control"
ref={nameRef}
onChange={handleSearchChange}
disabled={loading}
/>
</div>
<div className="col-lg-3">
<label>Mobile Number:</label>
<input
type="text"
placeholder="Mobile Number"
className="form-control"
ref={mobileRef}
onChange={handleSearchChange}
disabled={loading}
/>
</div>
<div className="col-lg-3">
<label>Verify TerritoryManager:</label>
<select
className="form-control"
ref={VerifyTerritoryManagerRef}
onChange={handleSearchChange}
disabled={loading}
>
<option value="">----Select----</option>
<option value="true">YES</option>
<option value="false">NO</option>
</select>
</div>
</div>
<div className="table-responsive table-shoot mt-3">
<table className="table table-centered table-nowrap">
<thead
className="thead-light"
style={{ background: "#ecdddd" }}
>
<tr>
<th>Unique Id </th>
<th className="text-start">Name</th>
<th className="text-start">Mobile No.</th>
<th className="text-start">Email</th>
<th className="text-start">Verify</th>
<th className="text-start">Register On</th>
<th className="text-start">Action</th>
</tr>
</thead>
<tbody>
{loading ? (
<tr>
<td className="text-center" colSpan="6">
Loading...
</td>
</tr>
) : territorymanagersData?.length > 0 ? (
territorymanagersData?.map((territorymanager, i) => {
return (
<tr key={i}>
<td className="text-start">
{territorymanager?.uniqueId}
</td>
<td className="text-start">
{territorymanager?.name}
</td>
<td className="text-start">
{territorymanager?.mobileNumber}
</td>
<td className="text-start">
{territorymanager?.email ? (
territorymanager?.email
) : (
<small className="m-0 text-secondary">
No Email Added!
</small>
)}
</td>
<td className="text-start">
<span
className={`badge text-white ${
territorymanager?.isVerified === true
? "text-bg-success"
: "text-bg-danger"
}`}
>
{territorymanager?.isVerified
? "YES"
: "NO"}
</span>
</td>
<td className="text-start">
{new Date(
territorymanager.createdAt
).toLocaleString("en-IN", {
weekday: "short",
month: "short",
day: "numeric",
year: "numeric",
hour: "numeric",
minute: "numeric",
hour12: true,
})}
</td>
<td className="text-start">
<Link
to={`/territorymanager/edit/${territorymanager._id}`}
>
<button
style={{
color: "white",
marginRight: "1rem",
}}
type="button"
className="btn btn-info btn-sm waves-effect waves-light btn-table ml-2"
>
Edit
</button>
</Link>
<button
type="button"
style={{ color: "white" }}
className="btn btn-danger btn-sm waves-effect waves-light btn-table ml-2"
onClick={() => handleDelete(territorymanager._id)}
>
Delete
</button>
</td>
</tr>
);
})
) : (
<tr>
<td className="text-center" colSpan="6">
No TerritoryManager found!
</td>
</tr>
)}
</tbody>
</table>
</div>
<div className="d-flex justify-content-between">
<div>
Showing {territorymanagersData?.length} of {totalData} entries
</div>
<div>
<button
onClick={() => setCurrentPage(currentPage - 1)}
disabled={currentPage === 1 || loading}
className="btn btn-primary"
>
Previous
</button>
<button
onClick={() => setCurrentPage(currentPage + 1)}
disabled={territorymanagersData?.length < itemPerPage || loading}
className="btn btn-primary ml-2"
>
Next
</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
);
};
export default TerritoryManager;