Mapping PD/RD and search functionality
This commit is contained in:
parent
237861d6a8
commit
7ca86eeafa
@ -146,6 +146,8 @@ import SingleInventory from "./views/Inventory/SingleInventory";
|
||||
import ViewProductManual from "./views/ProductManual/SingleProductManual";
|
||||
import ViewSalesCoOrdinatorTM from "./views/TerritoryManager/ViewSalesCoOrdinatorTM";
|
||||
import ViewPrincipalDistributorTM from "./views/TerritoryManager/ViewPrincipalDistributorTM";
|
||||
import ViewRetailDistributorTM from "./views/TerritoryManager/ViewRetailDistributor";
|
||||
import AddRetailDistributor from "./views/RetailDistributors/addRetailDistributor";
|
||||
const routes = [
|
||||
//dashboard
|
||||
|
||||
@ -268,6 +270,12 @@ const routes = [
|
||||
element: ViewPrincipalDistributorTM,
|
||||
navName: "TerritoryManagers",
|
||||
},
|
||||
{
|
||||
path: "/view/retaildistributor/:id",
|
||||
name: "View Retail Distributor",
|
||||
element: ViewRetailDistributorTM,
|
||||
navName: "TerritoryManagers",
|
||||
},
|
||||
// Attendence
|
||||
{
|
||||
path: "/attendance/today",
|
||||
@ -331,6 +339,12 @@ const routes = [
|
||||
element: SingleRetailDistributor,
|
||||
navName: "RetailDistributor",
|
||||
},
|
||||
{
|
||||
path: "/retaildistributor/add",
|
||||
name: "Add Retail Distributor",
|
||||
element: AddRetailDistributor,
|
||||
navName: "RetailDistributor",
|
||||
},
|
||||
//----------------------- End Product Management Routes------------------------------------------------
|
||||
|
||||
//Departure
|
||||
|
@ -1,54 +1,45 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import React, { useState, useEffect, useRef, useCallback } from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
import Button from "@material-ui/core/Button";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import axios from "axios";
|
||||
import { isAutheticated } from "src/auth";
|
||||
import swal from "sweetalert";
|
||||
import {
|
||||
Box,
|
||||
FormControl,
|
||||
IconButton,
|
||||
InputLabel,
|
||||
MenuItem,
|
||||
Select,
|
||||
TextField,
|
||||
} from "@mui/material";
|
||||
import SearchIcon from "@mui/icons-material/Search";
|
||||
import Fuse from "fuse.js";
|
||||
import { Typography } from "@material-ui/core";
|
||||
import OrderDetails from "./orderDetails";
|
||||
import debounce from "lodash.debounce";
|
||||
const principalDistributor = () => {
|
||||
const token = isAutheticated();
|
||||
const [query, setQuery] = useState("");
|
||||
const navigate = useNavigate();
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [loading1, setLoading1] = useState(true);
|
||||
const [success, setSuccess] = useState(true);
|
||||
const [users, setUsers] = useState([]);
|
||||
|
||||
const [totalPages, setTotalPages] = useState(1);
|
||||
const [currentPage, setCurrentPage] = useState(1);
|
||||
const [itemPerPage, setItemPerPage] = useState(10);
|
||||
const [showData, setShowData] = useState(users);
|
||||
|
||||
const handleShowEntries = (e) => {
|
||||
setCurrentPage(1);
|
||||
setItemPerPage(e.target.value);
|
||||
};
|
||||
|
||||
const [totalData, setTotalData] = useState(0);
|
||||
const nameRef = useRef();
|
||||
const SBURef = useRef();
|
||||
const getUsers = async () => {
|
||||
axios
|
||||
setLoading(true);
|
||||
try {
|
||||
const res = await axios
|
||||
.get(`/api/v1/admin/users`, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`,
|
||||
},
|
||||
})
|
||||
.then((res) => {
|
||||
params: {
|
||||
page: currentPage,
|
||||
show: itemPerPage,
|
||||
name: nameRef.current.value,
|
||||
SBU: SBURef.current.value,
|
||||
},
|
||||
});
|
||||
// console.log(res.data);
|
||||
setUsers(res.data.users);
|
||||
setLoading(false);
|
||||
})
|
||||
.catch((error) => {
|
||||
setTotalData(res.data?.total_data);
|
||||
setTotalPages(res.data?.total_pages);
|
||||
}catch(error) {
|
||||
swal({
|
||||
title: error,
|
||||
text: "please login to access the resource or refresh the page ",
|
||||
@ -56,23 +47,26 @@ const principalDistributor = () => {
|
||||
button: "Retry",
|
||||
dangerMode: true,
|
||||
});
|
||||
} finally {
|
||||
setLoading(false);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
getUsers();
|
||||
}, [success]);
|
||||
// console.log(users);
|
||||
}, [itemPerPage, currentPage]);
|
||||
|
||||
useEffect(() => {
|
||||
const loadData = () => {
|
||||
const indexOfLastPost = currentPage * itemPerPage;
|
||||
const indexOfFirstPost = indexOfLastPost - itemPerPage;
|
||||
setShowData(users.slice(indexOfFirstPost, indexOfLastPost));
|
||||
};
|
||||
loadData();
|
||||
}, [currentPage, itemPerPage, users]);
|
||||
const debouncedSearch = useCallback(
|
||||
debounce(() => {
|
||||
setCurrentPage(1);
|
||||
getUsers();
|
||||
}, 500),
|
||||
[]
|
||||
);
|
||||
|
||||
const handleSearchChange = () => {
|
||||
debouncedSearch();
|
||||
};
|
||||
// console.log(users);
|
||||
|
||||
// const handleDelete = (id) => {
|
||||
@ -165,19 +159,17 @@ const principalDistributor = () => {
|
||||
<div className="card">
|
||||
<div className="card-body">
|
||||
<div className="row ml-0 mr-0 mb-10 ">
|
||||
<div className="col-sm-12 col-md-12">
|
||||
<div className="col-lg-1">
|
||||
<div className="dataTables_length">
|
||||
<label className="w-100">
|
||||
Show
|
||||
<select
|
||||
style={{ width: "10%" }}
|
||||
name=""
|
||||
onChange={(e) => handleShowEntries(e)}
|
||||
className="
|
||||
select-w
|
||||
custom-select custom-select-sm
|
||||
form-control form-control-sm
|
||||
"
|
||||
onChange={(e) => {
|
||||
setItemPerPage(Number(e.target.value));
|
||||
setCurrentPage(1); // Reset to first page when changing items per page
|
||||
}}
|
||||
className="form-control"
|
||||
disabled={loading}
|
||||
>
|
||||
<option value="10">10</option>
|
||||
<option value="25">25</option>
|
||||
@ -188,6 +180,30 @@ const principalDistributor = () => {
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-lg-3">
|
||||
<label>Trade Name:</label>
|
||||
<input
|
||||
type="text"
|
||||
name="searchTerm"
|
||||
placeholder="Trade name"
|
||||
className="form-control"
|
||||
ref={nameRef}
|
||||
onChange={handleSearchChange}
|
||||
disabled={loading}
|
||||
/>
|
||||
</div>
|
||||
<div className="col-lg-3">
|
||||
<label>SBU:</label>
|
||||
<input
|
||||
type="text"
|
||||
name="searchTerm"
|
||||
placeholder="SBU"
|
||||
className="form-control"
|
||||
ref={SBURef}
|
||||
onChange={handleSearchChange}
|
||||
disabled={loading}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="table-responsive table-shoot mt-3">
|
||||
@ -213,55 +229,47 @@ const principalDistributor = () => {
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{!loading && showData.length === 0 && (
|
||||
{loading ? (
|
||||
<tr className="text-center">
|
||||
<td colSpan="6">
|
||||
<h5>No Data Available</h5>
|
||||
<h5>Loading....</h5>
|
||||
</td>
|
||||
</tr>
|
||||
)}
|
||||
{loading ? (
|
||||
<tr>
|
||||
<td className="text-center" colSpan="6">
|
||||
Loading...
|
||||
</td>
|
||||
</tr>
|
||||
) : (
|
||||
showData.map((user, i) => {
|
||||
return (
|
||||
<tr key={i}>
|
||||
<td>{user.uniqueId}</td>
|
||||
<td>{user.SBU?user.SBU:"N/A"}</td>
|
||||
<td className="text-start">{user.name}</td>
|
||||
<td>{user.email}</td>
|
||||
<td className="text-start">
|
||||
{new Date(user.createdAt).toLocaleString(
|
||||
"en-IN",
|
||||
{
|
||||
weekday: "short",
|
||||
month: "short",
|
||||
day: "numeric",
|
||||
year: "numeric",
|
||||
hour: "numeric",
|
||||
minute: "numeric",
|
||||
hour12: true,
|
||||
}
|
||||
)}
|
||||
</td>
|
||||
{loading1 && (
|
||||
<>
|
||||
<td className="text-start">loading...</td>
|
||||
<td className="text-start">loading...</td>
|
||||
</>
|
||||
) : users.length > 0 ? (
|
||||
users.map((user, i) => (
|
||||
<tr key={i}>
|
||||
<td>{user.uniqueId}</td>
|
||||
<td>{user.SBU ? user.SBU : "N/A"}</td>
|
||||
<td className="text-start">{user.name}</td>
|
||||
<td>{user.email}</td>
|
||||
<td className="text-start">
|
||||
{new Date(user.createdAt).toLocaleString(
|
||||
"en-IN",
|
||||
{
|
||||
weekday: "short",
|
||||
month: "short",
|
||||
day: "numeric",
|
||||
year: "numeric",
|
||||
hour: "numeric",
|
||||
minute: "numeric",
|
||||
hour12: true,
|
||||
}
|
||||
)}
|
||||
</td>
|
||||
{loading1 && (
|
||||
<>
|
||||
<td className="text-start">loading...</td>
|
||||
<td className="text-start">loading...</td>
|
||||
</>
|
||||
)}
|
||||
|
||||
<OrderDetails
|
||||
_id={user?._id}
|
||||
setLoading1={setLoading1}
|
||||
/>
|
||||
<OrderDetails
|
||||
_id={user?._id}
|
||||
setLoading1={setLoading1}
|
||||
/>
|
||||
|
||||
<td className="text-start">
|
||||
{/* <Link
|
||||
<td className="text-start">
|
||||
{/* <Link
|
||||
to={`/users-address/view/${userAddress._id}`}
|
||||
>
|
||||
<button
|
||||
@ -325,20 +333,25 @@ const principalDistributor = () => {
|
||||
Delete
|
||||
</button>
|
||||
</Link> */}
|
||||
<Link
|
||||
to={`/principal-distributor/${user?._id}`}
|
||||
<Link
|
||||
to={`/principal-distributor/${user?._id}`}
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
className="mt-1 btn btn-info btn-sm waves-effect waves-light btn-table ml-2"
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
className="mt-1 btn btn-info btn-sm waves-effect waves-light btn-table ml-2"
|
||||
>
|
||||
View
|
||||
</button>
|
||||
</Link>
|
||||
</td>
|
||||
</tr>
|
||||
);
|
||||
})
|
||||
View
|
||||
</button>
|
||||
</Link>
|
||||
</td>
|
||||
</tr>
|
||||
))
|
||||
) : (
|
||||
<tr>
|
||||
<td colSpan="6" className="text-center">
|
||||
<h5>No Principal Distributor found!</h5>
|
||||
</td>
|
||||
</tr>
|
||||
)}
|
||||
</tbody>
|
||||
</table>
|
||||
@ -352,88 +365,60 @@ const principalDistributor = () => {
|
||||
role="status"
|
||||
aria-live="polite"
|
||||
>
|
||||
Showing {currentPage * itemPerPage - itemPerPage + 1} to{" "}
|
||||
{Math.min(currentPage * itemPerPage, users.length)} of{" "}
|
||||
{users.length} entries
|
||||
Showing {users?.length} of {totalData} entries
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="col-sm-12 col-md-6">
|
||||
<div className="d-flex">
|
||||
<ul className="pagination ms-auto">
|
||||
<div className="dataTables_paginate paging_simple_numbers">
|
||||
<ul className="pagination">
|
||||
<li
|
||||
className={
|
||||
currentPage === 1
|
||||
? "paginate_button page-item previous disabled"
|
||||
: "paginate_button page-item previous"
|
||||
}
|
||||
className={`paginate_button page-item previous ${
|
||||
currentPage === 1 ? "disabled" : ""
|
||||
}`}
|
||||
>
|
||||
<span
|
||||
<a
|
||||
className="page-link"
|
||||
style={{ cursor: "pointer" }}
|
||||
onClick={() => setCurrentPage((prev) => prev - 1)}
|
||||
onClick={() =>
|
||||
setCurrentPage((prev) => Math.max(prev - 1, 1))
|
||||
}
|
||||
aria-controls="datatable"
|
||||
>
|
||||
Previous
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
{!(currentPage - 1 < 1) && (
|
||||
<li className="paginate_button page-item">
|
||||
<span
|
||||
className="page-link"
|
||||
style={{ cursor: "pointer" }}
|
||||
onClick={(e) =>
|
||||
setCurrentPage((prev) => prev - 1)
|
||||
}
|
||||
>
|
||||
{currentPage - 1}
|
||||
</span>
|
||||
</li>
|
||||
)}
|
||||
|
||||
<li className="paginate_button page-item active">
|
||||
<span
|
||||
className="page-link"
|
||||
style={{ cursor: "pointer" }}
|
||||
{Array.from({ length: totalPages }, (_, index) => (
|
||||
<li
|
||||
key={index}
|
||||
className={`paginate_button page-item ${
|
||||
currentPage === index + 1 ? "active" : ""
|
||||
}`}
|
||||
>
|
||||
{currentPage}
|
||||
</span>
|
||||
</li>
|
||||
|
||||
{!(
|
||||
(currentPage + 1) * itemPerPage - itemPerPage >
|
||||
users.length - 1
|
||||
) && (
|
||||
<li className="paginate_button page-item ">
|
||||
<span
|
||||
<a
|
||||
className="page-link"
|
||||
style={{ cursor: "pointer" }}
|
||||
onClick={() => {
|
||||
setCurrentPage((prev) => prev + 1);
|
||||
}}
|
||||
onClick={() => setCurrentPage(index + 1)}
|
||||
aria-controls="datatable"
|
||||
>
|
||||
{currentPage + 1}
|
||||
</span>
|
||||
{index + 1}
|
||||
</a>
|
||||
</li>
|
||||
)}
|
||||
|
||||
))}
|
||||
<li
|
||||
className={
|
||||
!(
|
||||
(currentPage + 1) * itemPerPage - itemPerPage >
|
||||
users.length - 1
|
||||
)
|
||||
? "paginate_button page-item next"
|
||||
: "paginate_button page-item next disabled"
|
||||
}
|
||||
className={`paginate_button page-item next ${
|
||||
currentPage === totalPages ? "disabled" : ""
|
||||
}`}
|
||||
>
|
||||
<span
|
||||
<a
|
||||
className="page-link"
|
||||
style={{ cursor: "pointer" }}
|
||||
onClick={() => setCurrentPage((prev) => prev + 1)}
|
||||
onClick={() =>
|
||||
setCurrentPage((prev) =>
|
||||
Math.min(prev + 1, totalPages)
|
||||
)
|
||||
}
|
||||
aria-controls="datatable"
|
||||
>
|
||||
Next
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
@ -1,5 +1,6 @@
|
||||
import React, { useState, useEffect, useCallback } from "react";
|
||||
import React, { useState, useEffect, useCallback, useRef } from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import axios from "axios";
|
||||
import Button from "@material-ui/core/Button";
|
||||
import { isAutheticated } from "src/auth";
|
||||
@ -8,18 +9,17 @@ import debounce from "lodash.debounce";
|
||||
|
||||
const RetailDistributor = () => {
|
||||
const token = isAutheticated();
|
||||
const Navigate = useNavigate();
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [allRetailDistributorsData, setAllRetailDistributorsData] = useState(
|
||||
[]
|
||||
);
|
||||
const [filteredRetailDistributorsData, setFilteredRetailDistributorsData] =
|
||||
useState([]);
|
||||
const [searchTerm, setSearchTerm] = useState("");
|
||||
const [searchPrincipalDistributor, setSearchPrincipalDistributor] =
|
||||
useState("");
|
||||
|
||||
const nameRef = useRef();
|
||||
const principalDistributorRef = useRef();
|
||||
const [totalPages, setTotalPages] = useState(1);
|
||||
const [currentPage, setCurrentPage] = useState(1);
|
||||
const [itemPerPage, setItemPerPage] = useState(10);
|
||||
const [totalData, setTotalData] = useState(0);
|
||||
|
||||
const getRetailDistributorsData = async () => {
|
||||
setLoading(true);
|
||||
@ -28,9 +28,16 @@ const RetailDistributor = () => {
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`,
|
||||
},
|
||||
params: {
|
||||
page: currentPage,
|
||||
show: itemPerPage,
|
||||
name: nameRef.current.value,
|
||||
principaldistributor: principalDistributorRef.current.value,
|
||||
},
|
||||
});
|
||||
setAllRetailDistributorsData(res.data || []);
|
||||
setFilteredRetailDistributorsData(res.data || []); // Initialize filtered data
|
||||
setAllRetailDistributorsData(res.data?.kycs);
|
||||
setTotalData(res.data?.total_data);
|
||||
setTotalPages(res.data?.total_pages);
|
||||
} catch (err) {
|
||||
const msg = err?.response?.data?.message || "Something went wrong!";
|
||||
swal({
|
||||
@ -47,65 +54,17 @@ const RetailDistributor = () => {
|
||||
|
||||
useEffect(() => {
|
||||
getRetailDistributorsData();
|
||||
}, []);
|
||||
}, [ itemPerPage, currentPage]);
|
||||
|
||||
useEffect(() => {
|
||||
filterData();
|
||||
}, [searchTerm, searchPrincipalDistributor, allRetailDistributorsData]);
|
||||
const debouncedSearch = useCallback(debounce(() => {
|
||||
setCurrentPage(1);
|
||||
getRetailDistributorsData();
|
||||
}, 500), []);
|
||||
|
||||
const filterData = () => {
|
||||
let filteredData = allRetailDistributorsData;
|
||||
|
||||
if (searchTerm) {
|
||||
filteredData = filteredData.filter((item) =>
|
||||
item.trade_name.toLowerCase().includes(searchTerm.toLowerCase())
|
||||
);
|
||||
}
|
||||
|
||||
if (searchPrincipalDistributor) {
|
||||
filteredData = filteredData.filter((item) =>
|
||||
item.principal_distributer?.name
|
||||
?.toLowerCase()
|
||||
.includes(searchPrincipalDistributor.toLowerCase())
|
||||
);
|
||||
}
|
||||
|
||||
setFilteredRetailDistributorsData(filteredData);
|
||||
setCurrentPage(1); // Reset to first page when filtering
|
||||
};
|
||||
|
||||
const debouncedSearch = useCallback(
|
||||
debounce(() => {
|
||||
filterData();
|
||||
}, 500),
|
||||
[searchTerm, searchPrincipalDistributor]
|
||||
);
|
||||
|
||||
const handleSearchChange = (e) => {
|
||||
const { name, value } = e.target;
|
||||
if (name === "searchTerm") {
|
||||
setSearchTerm(value);
|
||||
} else if (name === "searchPrincipalDistributor") {
|
||||
setSearchPrincipalDistributor(value);
|
||||
}
|
||||
const handleSearchChange = () => {
|
||||
debouncedSearch();
|
||||
};
|
||||
|
||||
const totalPages = Math.ceil(
|
||||
filteredRetailDistributorsData.length / itemPerPage
|
||||
);
|
||||
const paginatedData = filteredRetailDistributorsData.slice(
|
||||
(currentPage - 1) * itemPerPage,
|
||||
currentPage * itemPerPage
|
||||
);
|
||||
|
||||
const handleResetSearch = () => {
|
||||
setSearchTerm("");
|
||||
setSearchPrincipalDistributor("");
|
||||
setFilteredRetailDistributorsData(allRetailDistributorsData); // Reset filtered data
|
||||
setCurrentPage(1); // Reset to first page
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="main-content">
|
||||
<div className="page-content">
|
||||
@ -116,6 +75,18 @@ const RetailDistributor = () => {
|
||||
<div style={{ fontSize: "22px" }} className="fw-bold">
|
||||
Retail Distributors
|
||||
</div>
|
||||
<div className="page-title-right">
|
||||
<Button
|
||||
variant="contained"
|
||||
color="primary"
|
||||
className="font-bold mb-2 capitalize mr-2"
|
||||
onClick={() => {
|
||||
Navigate("/retaildistributor/add");
|
||||
}}
|
||||
>
|
||||
Add Retail Distributor
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -153,9 +124,9 @@ const RetailDistributor = () => {
|
||||
name="searchTerm"
|
||||
placeholder="Trade name"
|
||||
className="form-control"
|
||||
ref={nameRef}
|
||||
onChange={handleSearchChange}
|
||||
disabled={loading}
|
||||
value={searchTerm}
|
||||
/>
|
||||
</div>
|
||||
<div className="col-lg-3">
|
||||
@ -167,18 +138,9 @@ const RetailDistributor = () => {
|
||||
className="form-control"
|
||||
onChange={handleSearchChange}
|
||||
disabled={loading}
|
||||
value={searchPrincipalDistributor}
|
||||
ref={principalDistributorRef}
|
||||
/>
|
||||
</div>
|
||||
<div className="col-lg-3">
|
||||
<Button
|
||||
variant="outlined"
|
||||
color="primary"
|
||||
onClick={handleResetSearch}
|
||||
>
|
||||
Reset Search
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="table-responsive table-shoot mt-3">
|
||||
@ -205,8 +167,8 @@ const RetailDistributor = () => {
|
||||
Loading...
|
||||
</td>
|
||||
</tr>
|
||||
) : paginatedData.length > 0 ? (
|
||||
paginatedData.map((retailDistributor) => (
|
||||
) : allRetailDistributorsData.length > 0 ? (
|
||||
allRetailDistributorsData.map((retailDistributor) => (
|
||||
<tr key={retailDistributor._id}>
|
||||
<td className="text-start">
|
||||
{retailDistributor._id}
|
||||
@ -272,12 +234,7 @@ const RetailDistributor = () => {
|
||||
role="status"
|
||||
aria-live="polite"
|
||||
>
|
||||
Showing {currentPage * itemPerPage - itemPerPage + 1} to{" "}
|
||||
{Math.min(
|
||||
currentPage * itemPerPage,
|
||||
filteredRetailDistributorsData.length
|
||||
)}{" "}
|
||||
of {filteredRetailDistributorsData.length} entries
|
||||
Showing {allRetailDistributorsData?.length} of {totalData} entries
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -98,7 +98,7 @@ const SingleRetailDistributor = () => {
|
||||
<strong>Mobile Number:</strong> {retailerDetails.mobile_number}
|
||||
</Typography>
|
||||
<Typography>
|
||||
<strong>Mapped Principal Distributor:</strong> {retailerDetails.principal_distributer.name}
|
||||
<strong>Mapped Principal Distributor:</strong> {retailerDetails?.principal_distributer?.name || 'Not Mapped'}
|
||||
</Typography>
|
||||
</Grid>
|
||||
</Grid>
|
||||
@ -181,13 +181,13 @@ const SingleRetailDistributor = () => {
|
||||
<Grid container spacing={2}>
|
||||
<Grid item xs={6}>
|
||||
<Typography>
|
||||
<strong>Designation:</strong> {retailerDetails.userType}
|
||||
<strong>Designation:</strong> {retailerDetails?.userType|| 'Not Available'}
|
||||
</Typography>
|
||||
<Typography>
|
||||
<strong>Name:</strong> {retailerDetails.addedBy.name}
|
||||
<strong>Name:</strong> {retailerDetails?.addedBy?.name || 'Not Available'}
|
||||
</Typography>
|
||||
<Typography>
|
||||
<strong>ID:</strong> {retailerDetails.addedBy.uniqueId}
|
||||
<strong>ID:</strong> {retailerDetails?.addedBy?.uniqueId || 'Not Available'}
|
||||
</Typography>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
524
src/views/RetailDistributors/addRetailDistributor.js
Normal file
524
src/views/RetailDistributors/addRetailDistributor.js
Normal file
@ -0,0 +1,524 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import {
|
||||
TextField,
|
||||
Button,
|
||||
Card,
|
||||
Grid,
|
||||
Typography,
|
||||
Autocomplete,
|
||||
CircularProgress,
|
||||
} from "@mui/material";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { toast } from "react-hot-toast";
|
||||
import axios from "axios";
|
||||
import { isAutheticated } from "src/auth";
|
||||
import { City, State } from "country-state-city";
|
||||
|
||||
const AddRetailDistributor = () => {
|
||||
const navigate = useNavigate();
|
||||
const token = isAutheticated();
|
||||
|
||||
const [user, setUser] = useState({
|
||||
name: "",
|
||||
trade_name: "",
|
||||
address: "",
|
||||
state: "",
|
||||
city: "",
|
||||
district: "",
|
||||
pincode: "",
|
||||
mobile_number: "",
|
||||
pan_number: "",
|
||||
aadhar_number: "",
|
||||
gst_number: "",
|
||||
});
|
||||
|
||||
const [files, setFiles] = useState({
|
||||
selfieEntranceImg: null,
|
||||
panImg: null,
|
||||
aadharImg: null,
|
||||
gstImg: null,
|
||||
pesticideLicenseImg: null,
|
||||
fertilizerLicenseImg: null,
|
||||
});
|
||||
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [stateOptions, setStateOptions] = useState([]);
|
||||
const [cityOptions, setCityOptions] = useState([]);
|
||||
const [selectedState, setSelectedState] = useState(null);
|
||||
const [selectedCity, setSelectedCity] = useState(null);
|
||||
const [errors, setErrors] = useState({});
|
||||
|
||||
useEffect(() => {
|
||||
const fetchStates = async () => {
|
||||
const states = State.getStatesOfCountry("IN").map((state) => ({
|
||||
label: state.name,
|
||||
value: state.isoCode,
|
||||
}));
|
||||
setStateOptions(states);
|
||||
};
|
||||
fetchStates();
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const fetchCities = async () => {
|
||||
if (selectedState) {
|
||||
const cities = City.getCitiesOfState("IN", selectedState.value).map(
|
||||
(city) => ({
|
||||
label: city.name,
|
||||
value: city.name,
|
||||
})
|
||||
);
|
||||
setCityOptions(cities);
|
||||
}
|
||||
};
|
||||
fetchCities();
|
||||
}, [selectedState]);
|
||||
|
||||
const handleInputChange = (e) => {
|
||||
setUser({ ...user, [e.target.name]: e.target.value });
|
||||
};
|
||||
|
||||
const handleStateChange = (event, newValue) => {
|
||||
setSelectedState(newValue);
|
||||
};
|
||||
|
||||
const handleCityChange = (event, newValue) => {
|
||||
setSelectedCity(newValue);
|
||||
};
|
||||
|
||||
const handleFileChange = (e) => {
|
||||
const { name, files } = e.target;
|
||||
if (files.length > 0) {
|
||||
const file = files[0];
|
||||
if (["image/png", "image/jpeg", "image/jpg"].includes(file.type)) {
|
||||
setFiles((prev) => ({ ...prev, [name]: file }));
|
||||
} else {
|
||||
toast.error("Only PNG, JPG, and JPEG files are allowed.");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleFormSubmit = async (e) => {
|
||||
e.preventDefault();
|
||||
try {
|
||||
// Validate input fields
|
||||
if (
|
||||
!user.name ||
|
||||
!user.trade_name ||
|
||||
!user.address ||
|
||||
!user.mobile_number ||
|
||||
!user.pan_number ||
|
||||
!user.aadhar_number ||
|
||||
!user.gst_number ||
|
||||
!selectedState ||
|
||||
!selectedCity
|
||||
) {
|
||||
setErrors({ message: "Fill all required fields!" });
|
||||
return;
|
||||
}
|
||||
|
||||
setLoading(true);
|
||||
|
||||
const formData = new FormData();
|
||||
formData.append("name", user.name);
|
||||
formData.append("trade_name", user.trade_name);
|
||||
formData.append("address", user.address);
|
||||
formData.append("state", selectedState.value);
|
||||
formData.append("city", selectedCity.value);
|
||||
formData.append("district", user.district);
|
||||
formData.append("pincode", user.pincode);
|
||||
formData.append("mobile_number", user.mobile_number);
|
||||
formData.append("pan_number", user.pan_number);
|
||||
formData.append("aadhar_number", user.aadhar_number);
|
||||
formData.append("gst_number", user.gst_number);
|
||||
|
||||
// Ensure files are included only if they exist
|
||||
Object.keys(files).forEach((key) => {
|
||||
if (files[key]) {
|
||||
formData.append(key, files[key]);
|
||||
}
|
||||
});
|
||||
|
||||
// Attempt to create distributor
|
||||
const response = await axios.post("/api/kyc/create-admin/", formData, {
|
||||
headers: {
|
||||
"Content-Type": "multipart/form-data",
|
||||
"Authorization": `Bearer ${token}`,
|
||||
},
|
||||
});
|
||||
|
||||
if (response.data.success) {
|
||||
toast.success("Retail Distributor created successfully!");
|
||||
navigate("/retail-distributor");
|
||||
}
|
||||
} catch (error) {
|
||||
setLoading(false);
|
||||
if (error.response && error.response.data) {
|
||||
toast.error(error.response.data.message || "Something went wrong!");
|
||||
} else {
|
||||
toast.error("Something went wrong!");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleCancel = () => {
|
||||
navigate("/retail-distributor");
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Card
|
||||
sx={{ padding: "1rem", marginBottom: "1rem", position: "relative" }}
|
||||
>
|
||||
<Button
|
||||
variant="outlined"
|
||||
color="secondary"
|
||||
onClick={handleCancel}
|
||||
sx={{ position: "absolute", top: "10px", right: "10px" }}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
<Typography variant="h5" sx={{ mb: 3 }}>
|
||||
Add Retail Distributor
|
||||
</Typography>
|
||||
<form onSubmit={handleFormSubmit}>
|
||||
<Typography variant="h5" sx={{ mb: 2 }}>
|
||||
Basic Information
|
||||
</Typography>
|
||||
<Grid container spacing={2} sx={{ mb: 2 }}>
|
||||
{/* Name */}
|
||||
<Grid item xs={12} className="d-flex align-items-center">
|
||||
<Grid item xs={2}>
|
||||
<Typography
|
||||
variant="body1"
|
||||
htmlFor="name"
|
||||
className="form-label"
|
||||
>
|
||||
Name*
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={10}>
|
||||
<TextField
|
||||
id="name"
|
||||
required
|
||||
type="text"
|
||||
fullWidth
|
||||
name="name"
|
||||
value={user.name}
|
||||
variant="outlined"
|
||||
onChange={handleInputChange}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
{/* Trade Name */}
|
||||
<Grid item xs={12} className="d-flex align-items-center">
|
||||
<Grid item xs={2}>
|
||||
<Typography
|
||||
variant="body1"
|
||||
htmlFor="trade_name"
|
||||
className="form-label"
|
||||
>
|
||||
Trade Name*
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={10}>
|
||||
<TextField
|
||||
id="trade_name"
|
||||
required
|
||||
type="text"
|
||||
fullWidth
|
||||
name="trade_name"
|
||||
value={user.trade_name}
|
||||
variant="outlined"
|
||||
onChange={handleInputChange}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
{/* Address */}
|
||||
<Grid item xs={12} className="d-flex align-items-center">
|
||||
<Grid item xs={2}>
|
||||
<Typography
|
||||
variant="body1"
|
||||
htmlFor="address"
|
||||
className="form-label"
|
||||
>
|
||||
Address*
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={10}>
|
||||
<TextField
|
||||
id="address"
|
||||
required
|
||||
type="text"
|
||||
fullWidth
|
||||
name="address"
|
||||
value={user.address}
|
||||
variant="outlined"
|
||||
onChange={handleInputChange}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
{/* Mobile Number */}
|
||||
<Grid item xs={12} className="d-flex align-items-center">
|
||||
<Grid item xs={2}>
|
||||
<Typography
|
||||
variant="body1"
|
||||
htmlFor="mobile_number"
|
||||
className="form-label"
|
||||
>
|
||||
Mobile Number*
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={10}>
|
||||
<TextField
|
||||
id="mobile_number"
|
||||
required
|
||||
type="text"
|
||||
fullWidth
|
||||
name="mobile_number"
|
||||
value={user.mobile_number}
|
||||
variant="outlined"
|
||||
onChange={handleInputChange}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
{/* PAN Number */}
|
||||
<Grid item xs={12} className="d-flex align-items-center">
|
||||
<Grid item xs={2}>
|
||||
<Typography
|
||||
variant="body1"
|
||||
htmlFor="pan_number"
|
||||
className="form-label"
|
||||
>
|
||||
PAN Number*
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={10}>
|
||||
<TextField
|
||||
id="pan_number"
|
||||
required
|
||||
type="text"
|
||||
fullWidth
|
||||
name="pan_number"
|
||||
value={user.pan_number}
|
||||
variant="outlined"
|
||||
onChange={handleInputChange}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
{/* Aadhar Number */}
|
||||
<Grid item xs={12} className="d-flex align-items-center">
|
||||
<Grid item xs={2}>
|
||||
<Typography
|
||||
variant="body1"
|
||||
htmlFor="aadhar_number"
|
||||
className="form-label"
|
||||
>
|
||||
Aadhar Number*
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={10}>
|
||||
<TextField
|
||||
id="aadhar_number"
|
||||
required
|
||||
type="text"
|
||||
fullWidth
|
||||
name="aadhar_number"
|
||||
value={user.aadhar_number}
|
||||
variant="outlined"
|
||||
onChange={handleInputChange}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
{/* GST Number */}
|
||||
<Grid item xs={12} className="d-flex align-items-center">
|
||||
<Grid item xs={2}>
|
||||
<Typography
|
||||
variant="body1"
|
||||
htmlFor="gst_number"
|
||||
className="form-label"
|
||||
>
|
||||
GST Number*
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={10}>
|
||||
<TextField
|
||||
id="gst_number"
|
||||
required
|
||||
type="text"
|
||||
fullWidth
|
||||
name="gst_number"
|
||||
value={user.gst_number}
|
||||
variant="outlined"
|
||||
onChange={handleInputChange}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
{/* State */}
|
||||
<Grid item xs={12} className="d-flex align-items-center">
|
||||
<Grid item xs={2}>
|
||||
<Typography
|
||||
variant="body1"
|
||||
htmlFor="state"
|
||||
className="form-label"
|
||||
>
|
||||
State*
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={10}>
|
||||
<Autocomplete
|
||||
options={stateOptions}
|
||||
value={selectedState}
|
||||
onChange={handleStateChange}
|
||||
renderInput={(params) => (
|
||||
<TextField
|
||||
{...params}
|
||||
id="state"
|
||||
required
|
||||
variant="outlined"
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
{/* City */}
|
||||
<Grid item xs={12} className="d-flex align-items-center">
|
||||
<Grid item xs={2}>
|
||||
<Typography
|
||||
variant="body1"
|
||||
htmlFor="city"
|
||||
className="form-label"
|
||||
>
|
||||
City*
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={10}>
|
||||
<Autocomplete
|
||||
options={cityOptions}
|
||||
value={selectedCity}
|
||||
onChange={handleCityChange}
|
||||
renderInput={(params) => (
|
||||
<TextField
|
||||
{...params}
|
||||
id="city"
|
||||
required
|
||||
variant="outlined"
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
{/* District */}
|
||||
<Grid item xs={12} className="d-flex align-items-center">
|
||||
<Grid item xs={2}>
|
||||
<Typography
|
||||
variant="body1"
|
||||
htmlFor="district"
|
||||
className="form-label"
|
||||
>
|
||||
District*
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={10}>
|
||||
<TextField
|
||||
id="district"
|
||||
type="text"
|
||||
fullWidth
|
||||
name="district"
|
||||
value={user.district}
|
||||
variant="outlined"
|
||||
onChange={handleInputChange}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
{/* Pincode */}
|
||||
<Grid item xs={12} className="d-flex align-items-center">
|
||||
<Grid item xs={2}>
|
||||
<Typography
|
||||
variant="body1"
|
||||
htmlFor="pincode"
|
||||
className="form-label"
|
||||
>
|
||||
Pincode*
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={10}>
|
||||
<TextField
|
||||
id="pincode"
|
||||
type="text"
|
||||
fullWidth
|
||||
name="pincode"
|
||||
value={user.pincode}
|
||||
variant="outlined"
|
||||
onChange={handleInputChange}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
{/* File Uploads */}
|
||||
{[
|
||||
{ label: "Selfie Entrance Image*", name: "selfieEntranceImg" },
|
||||
{ label: "PAN Image*", name: "panImg" },
|
||||
{ label: "Aadhar Image*", name: "aadharImg" },
|
||||
{ label: "GST Image*", name: "gstImg" },
|
||||
{ label: "Pesticide License Image*", name: "pesticideLicenseImg" },
|
||||
{ label: "Fertilizer License Image*", name: "fertilizerLicenseImg" },
|
||||
].map(({ label, name }) => (
|
||||
<Grid item xs={12} className="d-flex align-items-center" key={name}>
|
||||
<Grid item xs={2}>
|
||||
<Typography
|
||||
variant="body1"
|
||||
htmlFor={name}
|
||||
className="form-label"
|
||||
>
|
||||
{label}
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={10}>
|
||||
<input
|
||||
type="file"
|
||||
id={name}
|
||||
name={name}
|
||||
onChange={handleFileChange}
|
||||
accept=".png,.jpg,.jpeg"
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
))}
|
||||
|
||||
{/* Submit Button */}
|
||||
<Grid item xs={12} className="d-flex align-items-center">
|
||||
<Grid item xs={2}></Grid>
|
||||
<Grid item xs={10}>
|
||||
<Button
|
||||
type="submit"
|
||||
variant="contained"
|
||||
color="primary"
|
||||
disabled={loading}
|
||||
>
|
||||
{loading ? (
|
||||
<CircularProgress size={24} />
|
||||
) : (
|
||||
"Submit"
|
||||
)}
|
||||
</Button>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</form>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default AddRetailDistributor;
|
@ -302,6 +302,20 @@ const TerritoryManager = () => {
|
||||
PD
|
||||
</button>
|
||||
</Link>
|
||||
<Link
|
||||
to={`/view/retaildistributor/${territorymanager._id}`}
|
||||
>
|
||||
<button
|
||||
style={{
|
||||
color: "white",
|
||||
marginRight: "1rem",
|
||||
}}
|
||||
type="button"
|
||||
className="btn btn-primary btn-sm waves-effect waves-light btn-table ml-2"
|
||||
>
|
||||
RD
|
||||
</button>
|
||||
</Link>
|
||||
<Link
|
||||
to={`/territorymanager/edit/${territorymanager._id}`}
|
||||
>
|
||||
|
554
src/views/TerritoryManager/ViewRetailDistributor.js
Normal file
554
src/views/TerritoryManager/ViewRetailDistributor.js
Normal file
@ -0,0 +1,554 @@
|
||||
import React, { useState, useEffect, useRef, useCallback } from "react";
|
||||
import { Link, useParams } 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";
|
||||
import Dialog from "@material-ui/core/Dialog";
|
||||
import DialogActions from "@material-ui/core/DialogActions";
|
||||
import DialogContent from "@material-ui/core/DialogContent";
|
||||
import DialogTitle from "@material-ui/core/DialogTitle";
|
||||
import TextField from "@material-ui/core/TextField";
|
||||
|
||||
const ViewRetailDistributorTM = () => {
|
||||
const token = isAutheticated();
|
||||
const { id } = useParams();
|
||||
const navigate = useNavigate();
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [success, setSuccess] = useState(true);
|
||||
const [retaildistributorData, setretaildistributorData] = useState([]);
|
||||
const [data, setData] = useState({});
|
||||
const nameRef = useRef();
|
||||
const mobileRef = useRef();
|
||||
const rdnameRef = useRef();
|
||||
const rdmobileRef = useRef();
|
||||
|
||||
const [currentPage, setCurrentPage] = useState(1);
|
||||
const [itemPerPage, setItemPerPage] = useState(10);
|
||||
const [modalcurrentPage, setmodalCurrentPage] = useState(1);
|
||||
const modalitemPerPage = 10;
|
||||
const [totalData, setTotalData] = useState(0);
|
||||
const [openModal, setOpenModal] = useState(false);
|
||||
const [modalRetailDistributors, setmodalRetailDistributors] = useState(
|
||||
[]
|
||||
);
|
||||
const [modalTotalData, setModalTotalData] = useState(0);
|
||||
|
||||
// Fetch territory manager data
|
||||
useEffect(() => {
|
||||
axios
|
||||
.get(`/api/territorymanager/getOne/${id}`, {
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
})
|
||||
.then((response) => setData(response.data.data))
|
||||
.catch((error) => console.error("Error fetching TM data:", error));
|
||||
}, [id, token]);
|
||||
|
||||
// Fetch Retail Distributors data
|
||||
const getTMsretaildistributorData = async () => {
|
||||
setLoading(true);
|
||||
axios
|
||||
.get(`/api/kyc/getAllapprovedbytmid/${id}`, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`,
|
||||
},
|
||||
params: {
|
||||
page: currentPage,
|
||||
show: itemPerPage,
|
||||
tradename: nameRef.current?.value,
|
||||
},
|
||||
})
|
||||
.then((res) => {
|
||||
// console.log(res.data);
|
||||
setretaildistributorData(res.data?.retaildistributor);
|
||||
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(() => {
|
||||
getTMsretaildistributorData();
|
||||
}, [success, itemPerPage, currentPage]);
|
||||
|
||||
// Debounced search for Retail Distributors
|
||||
const debouncedSearch = useCallback(
|
||||
debounce(() => {
|
||||
setCurrentPage(1);
|
||||
getTMsretaildistributorData();
|
||||
}, 500),
|
||||
[currentPage, itemPerPage]
|
||||
);
|
||||
|
||||
const handleSearchChange = useCallback(() => {
|
||||
debouncedSearch();
|
||||
}, [debouncedSearch]);
|
||||
// Fetch Retail Distributors data for modal
|
||||
const getretaildistributorData = async () => {
|
||||
setLoading(true);
|
||||
try {
|
||||
const res = await axios.get(`/api/v1/admin/users`, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`,
|
||||
},
|
||||
params: {
|
||||
page: modalcurrentPage,
|
||||
show: modalitemPerPage,
|
||||
name: rdnameRef.current?.value,
|
||||
mobileNumber: rdmobileRef.current?.value,
|
||||
},
|
||||
});
|
||||
setmodalRetailDistributors(res.data?.users);
|
||||
setModalTotalData(res.data?.totalUsers);
|
||||
} 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(() => {
|
||||
if (openModal) {
|
||||
getretaildistributorData();
|
||||
}
|
||||
}, [openModal, modalcurrentPage]);
|
||||
|
||||
// Debounced search for Retail Distributors in modal
|
||||
const debouncedmodalSearch = useCallback(
|
||||
debounce(() => {
|
||||
setmodalCurrentPage(1);
|
||||
getretaildistributorData();
|
||||
}, 500),
|
||||
[modalcurrentPage]
|
||||
);
|
||||
|
||||
const handlemodalSearchChange = useCallback(() => {
|
||||
debouncedmodalSearch();
|
||||
}, [debouncedmodalSearch]);
|
||||
|
||||
const handleOpenModal = () => {
|
||||
setOpenModal(true);
|
||||
};
|
||||
|
||||
const handleCloseModal = () => {
|
||||
setOpenModal(false);
|
||||
};
|
||||
const handlePreviousPage = () => {
|
||||
if (modalcurrentPage > 1) {
|
||||
setmodalCurrentPage(modalcurrentPage - 1);
|
||||
}
|
||||
};
|
||||
|
||||
const handleNextPage = () => {
|
||||
if (modalRetailDistributors.length === modalitemPerPage) {
|
||||
setmodalCurrentPage(modalcurrentPage + 1);
|
||||
}
|
||||
};
|
||||
|
||||
const handleDelete = (id) => {
|
||||
swal({
|
||||
title: "Are you sure?",
|
||||
icon: "warning",
|
||||
buttons: {
|
||||
Yes: { text: "Yes", value: true },
|
||||
Cancel: { text: "Cancel", value: "cancel" },
|
||||
},
|
||||
}).then((value) => {
|
||||
if (value === true) {
|
||||
axios
|
||||
.patch(`/api/v1/unmap/${id}`, {}, { // Changed to PATCH and sent an empty body
|
||||
headers: {
|
||||
"Access-Control-Allow-Origin": "*",
|
||||
Authorization: `Bearer ${token}`,
|
||||
},
|
||||
})
|
||||
.then((res) => {
|
||||
swal({
|
||||
title: "Deleted",
|
||||
text: "Retail Distributor Unmapped 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,
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
const handleAddRetailDistributor = async (rdid) => {
|
||||
try {
|
||||
await axios.put(
|
||||
`/api/v1/mappedtm/${rdid}`,
|
||||
{ mappedby: id },
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`,
|
||||
},
|
||||
}
|
||||
);
|
||||
swal({
|
||||
title: "Success",
|
||||
text: "Retail Distributor added successfully!",
|
||||
icon: "success",
|
||||
button: "Ok",
|
||||
});
|
||||
setSuccess((prev) => !prev);
|
||||
handleCloseModal(); // Close modal after adding
|
||||
} catch (err) {
|
||||
const msg = err?.response?.data?.message || "Something went wrong!";
|
||||
swal({
|
||||
title: "Error",
|
||||
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 mb-1 align-items-center justify-content-between">
|
||||
{/* Left Side with Information in Separate Columns */}
|
||||
<div className="d-flex flex-column">
|
||||
<div style={{ fontSize: "18px" }} className="fw-bold">
|
||||
Unique ID: {data?.uniqueId}
|
||||
</div>
|
||||
<div style={{ fontSize: "18px" }} className="fw-bold">
|
||||
Name: {data?.name}
|
||||
</div>
|
||||
<div style={{ fontSize: "18px" }} className="fw-bold">
|
||||
Mobile Number: {data?.mobileNumber}
|
||||
</div>
|
||||
<div style={{ fontSize: "18px" }} className="fw-bold">
|
||||
Mail: {data?.email}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Right Side with the Button */}
|
||||
<div className="page-title-right">
|
||||
{/* <Button
|
||||
variant="contained"
|
||||
color="primary"
|
||||
style={{
|
||||
fontWeight: "bold",
|
||||
marginBottom: "1rem",
|
||||
textTransform: "capitalize",
|
||||
}}
|
||||
onClick={handleOpenModal}
|
||||
>
|
||||
Add Retail Distributor
|
||||
</Button> */}
|
||||
<Button
|
||||
variant="contained"
|
||||
color="secondary"
|
||||
style={{
|
||||
fontWeight: "bold",
|
||||
marginBottom: "1rem",
|
||||
marginLeft: "1rem",
|
||||
textTransform: "capitalize",
|
||||
backgroundColor: "#d32f2f", // Red color for danger
|
||||
color: "#fff",
|
||||
"&:hover": {
|
||||
backgroundColor: "#b71c1c", // Darker red on hover
|
||||
},
|
||||
}}
|
||||
onClick={() => navigate("/territorymanagers")}
|
||||
>
|
||||
Back
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
{/* <Dialog
|
||||
open={openModal}
|
||||
onClose={handleCloseModal}
|
||||
maxWidth="md"
|
||||
fullWidth
|
||||
>
|
||||
<DialogTitle>Search and Add Retail Distributor</DialogTitle>
|
||||
<DialogContent>
|
||||
<div style={{ display: "flex", gap: "16px", marginBottom:"2rem",marginTop:"-1rem" }}>
|
||||
<TextField
|
||||
label="Retail Distributor Trade Name"
|
||||
placeholder="Retail Distributor Trade name"
|
||||
inputRef={rdnameRef}
|
||||
onChange={handlemodalSearchChange}
|
||||
disabled={loading}
|
||||
style={{ flex: 1, marginRight: "16px" }}
|
||||
/>
|
||||
<TextField
|
||||
style={{ flex: 1 }}
|
||||
label="Mobile Number"
|
||||
placeholder="Mobile Number"
|
||||
inputRef={rdmobileRef}
|
||||
onChange={handlemodalSearchChange}
|
||||
disabled={loading}
|
||||
/>
|
||||
</div>
|
||||
<div className="table-responsive table-shoot mt-3">
|
||||
<table className="table table-centered table-nowrap">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Trade Name</th>
|
||||
<th>Mobile</th>
|
||||
<th>Approved PD</th>
|
||||
<th>Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{modalRetailDistributors.length > 0 ? (
|
||||
modalRetailDistributors.map((RD) => (
|
||||
<tr key={RD._id}>
|
||||
<td>{RD.trade_name}</td>
|
||||
<td>{RD.mobile_number}</td>
|
||||
<td>{RD.principal_distributer?.name}</td>
|
||||
<td>
|
||||
<Button
|
||||
variant="contained"
|
||||
color="primary"
|
||||
onClick={() =>
|
||||
handleAddRetailDistributor(RD._id)
|
||||
}
|
||||
>
|
||||
Add
|
||||
</Button>
|
||||
</td>
|
||||
</tr>
|
||||
))
|
||||
) : (
|
||||
<tr>
|
||||
<td colSpan="6" className="text-center">
|
||||
No Retail Distributor found!
|
||||
</td>
|
||||
</tr>
|
||||
)}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div className="d-flex justify-content-between">
|
||||
<div>
|
||||
Showing {modalRetailDistributors?.length} of{" "}
|
||||
{modalTotalData} entries
|
||||
</div>
|
||||
<div>
|
||||
<button
|
||||
onClick={handlePreviousPage}
|
||||
disabled={modalcurrentPage === 1 || loading}
|
||||
className="btn btn-primary"
|
||||
>
|
||||
Previous
|
||||
</button>
|
||||
<button
|
||||
onClick={handleNextPage}
|
||||
disabled={
|
||||
modalRetailDistributors?.length <
|
||||
modalitemPerPage || loading
|
||||
}
|
||||
className="btn btn-primary ml-2"
|
||||
>
|
||||
Next
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button onClick={handleCloseModal} color="secondary">
|
||||
Cancel
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog> */}
|
||||
</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>Trade Name:</label>
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Retail Distributor Trade 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>
|
||||
|
||||
<div className="table-responsive table-shoot mt-3">
|
||||
<table className="table table-centered table-nowrap">
|
||||
<thead
|
||||
className="thead-light"
|
||||
style={{ background: "#ecdddd" }}
|
||||
>
|
||||
<tr>
|
||||
<th className="text-start">ID</th>
|
||||
<th className="text-start">Trade Name</th>
|
||||
<th className="text-start">Approved PD</th>
|
||||
<th className="text-start">Mobile</th>
|
||||
<th className="text-start">Created On</th>
|
||||
{/* <th className="text-start">Action</th> */}
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
{loading ? (
|
||||
<tr>
|
||||
<td className="text-center" colSpan="6">
|
||||
Loading...
|
||||
</td>
|
||||
</tr>
|
||||
) : retaildistributorData?.length > 0 ? (
|
||||
retaildistributorData?.map((RD, i) => {
|
||||
return (
|
||||
<tr key={i}>
|
||||
<td className="text-start">{RD?._id}</td>
|
||||
<td className="text-start">{RD?.trade_name}</td>
|
||||
<td className="text-start">{RD?.principal_distributer?.name}</td>
|
||||
<td className="text-start">
|
||||
{RD?.mobile_number ? (
|
||||
RD?.mobile_number
|
||||
) : (
|
||||
<small className="m-0 text-secondary">
|
||||
No Phone Added!
|
||||
</small>
|
||||
)}
|
||||
</td>
|
||||
<td className="text-start"> {new Date(
|
||||
RD.updatedAt
|
||||
).toLocaleString("en-IN", {
|
||||
weekday: "short",
|
||||
month: "short",
|
||||
day: "numeric",
|
||||
year: "numeric",
|
||||
hour: "numeric",
|
||||
minute: "numeric",
|
||||
hour12: true,
|
||||
})}</td>
|
||||
{/* <td className="text-start">
|
||||
<button
|
||||
type="button"
|
||||
style={{ color: "white" }}
|
||||
className="btn btn-danger btn-sm waves-effect waves-light btn-table ml-2"
|
||||
onClick={() => handleDelete(RD._id)}
|
||||
>
|
||||
Delete
|
||||
</button>
|
||||
</td> */}
|
||||
</tr>
|
||||
);
|
||||
})
|
||||
) : (
|
||||
<tr>
|
||||
<td className="text-center" colSpan="6">
|
||||
No Retail Distributor found!
|
||||
</td>
|
||||
</tr>
|
||||
)}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div className="d-flex justify-content-between">
|
||||
<div>
|
||||
Showing {retaildistributorData?.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={
|
||||
retaildistributorData?.length < itemPerPage ||
|
||||
loading
|
||||
}
|
||||
className="btn btn-primary ml-2"
|
||||
>
|
||||
Next
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ViewRetailDistributorTM;
|
Loading…
Reference in New Issue
Block a user