sales data and maprd

This commit is contained in:
Sibunnayak 2024-10-21 17:39:33 +05:30
parent 957cfd5fd9
commit 4ad5003607
10 changed files with 1639 additions and 615 deletions

View File

@ -132,6 +132,13 @@ const _nav = [
to: "/inventory", to: "/inventory",
group: "Inventory", group: "Inventory",
}, },
{
component: CNavItem,
name: "Sales Data",
icon: <CIcon icon={cilAddressBook} customClassName="nav-icon" />,
to: "/sales",
group: "Sales",
},
{ {
component: CNavGroup, component: CNavGroup,
name: "Orders", name: "Orders",

View File

@ -162,6 +162,9 @@ import AddMultiplesc from "./views/SalesCoOrdinators/AddMultipleSC";
import Announcements from "./views/Announcment/announcement"; import Announcements from "./views/Announcment/announcement";
import CreateAnnouncement from "./views/Announcment/createAnnouncement"; import CreateAnnouncement from "./views/Announcment/createAnnouncement";
import TodayTask from "./views/Tasks/TodayTasks"; import TodayTask from "./views/Tasks/TodayTasks";
import Sales from "./views/Sales/Sales";
import SingleSales from "./views/Sales/SingleSale";
import MobileApp from "./views/configuration/MobileApp";
const routes = [ const routes = [
//dashboard //dashboard
@ -483,6 +486,19 @@ const routes = [
element: SingleInventory, element: SingleInventory,
navName: "Inventory", navName: "Inventory",
}, },
//Sales
{
path: "/sales",
name: "Sales",
element: Sales,
navName: "Sales",
},
{
path: "/sales/view/:id",
name: "Sales",
element: SingleSales,
navName: "Sales",
},
//------------------ End customers Route------------------------- //------------------ End customers Route-------------------------
// { // {
@ -775,6 +791,7 @@ const routes = [
navName: "Configuration", navName: "Configuration",
}, },
{ path: "/logo", name: "Logo", element: Logo, navName: "Configuration" }, { path: "/logo", name: "Logo", element: Logo, navName: "Configuration" },
{ path: "/mobile-app", name: "MobileApp", element: MobileApp, navName: "Configuration" },
//----------------- End Configuration Routes----------------------------------- //----------------- End Configuration Routes-----------------------------------
//-----------------Affiliate & Coupons Routes----------------------------------- //-----------------Affiliate & Coupons Routes-----------------------------------

View File

@ -442,7 +442,7 @@ const Categories = () => {
<tbody> <tbody>
{!loading && category.length === 0 && ( {!loading && category.length === 0 && (
<tr className="text-center"> <tr className="text-center">
<td colSpan=""> <td colSpan="2">
<h5>No Data Available</h5> <h5>No Data Available</h5>
</td> </td>
</tr> </tr>

View File

@ -1,65 +1,27 @@
import React, { useState, useEffect, useRef, useCallback } from "react"; import React, { useState, useEffect } from "react";
import axios from "axios"; import axios from "axios";
import { import { Box, Typography, Grid, Paper } from "@mui/material";
Box,
Typography,
Grid,
Paper,
Dialog,
DialogContent,
DialogTitle,
} from "@mui/material";
import { useParams, useNavigate } from "react-router-dom"; import { useParams, useNavigate } from "react-router-dom";
import { isAutheticated } from "../../auth"; import { isAutheticated } from "../../auth";
import Button from "@material-ui/core/Button"; import Button from "@material-ui/core/Button";
import swal from "sweetalert"; import swal from "sweetalert";
import debounce from "lodash.debounce"; import PDmodal from "./ModalPD.js";
import TextField from "@mui/material/TextField"; import SCmodal from "./ModalSC.js";
import DialogActions from "@mui/material/DialogActions"; import TMmodal from "./ModalTM.js";
const MapRD = () => { const MapRD = () => {
const { id } = useParams(); const { id } = useParams();
const token = isAutheticated(); const token = isAutheticated();
const navigate = useNavigate(); const navigate = useNavigate();
const [loading, setLoading] = useState(false);
const [success, setSuccess] = useState(true); const [success, setSuccess] = useState(true);
const [data, setData] = useState(null); const [data, setData] = useState(null);
const pdnameRef = useRef();
const pdmobileRef = useRef();
const scnameRef = useRef();
const scmobileRef = useRef();
const tmnameRef = useRef();
const tmmobileRef = useRef();
const [modalcurrentPage, setmodalCurrentPage] = useState(1);
const modalitemPerPage = 10;
const [openPDModal, setOpenPDModal] = useState(false); const [openPDModal, setOpenPDModal] = useState(false);
const [openSCModal, setOpenSCModal] = useState(false); const [openSCModal, setOpenSCModal] = useState(false);
const [openTMModal, setOpenTMModal] = useState(false); const [openTMModal, setOpenTMModal] = useState(false);
// For opening each modal
const handleOpenPDModal = () => setOpenPDModal(true);
const handleOpenSCModal = () => setOpenSCModal(true);
const handleOpenTMModal = () => setOpenTMModal(true);
// For closing each modal
const handleClosePDModal = () => setOpenPDModal(false);
const handleCloseSCModal = () => setOpenSCModal(false);
const handleCloseTMModal = () => setOpenTMModal(false);
const [modalTotalData, setModalTotalData] = useState(0);
const [modalSalesCoordinators, setModalSalesCoordinators] = useState([]);
const [modalPrincipalDistributors, setmodalPrincipalDistributors] = useState(
[]
);
const [modalterritorymanagers, setmodalterritorymanagers] = useState([]);
useEffect(() => { useEffect(() => {
const fetchData = async () => { const fetchData = async () => {
try { try {
// Commented out the API call and using dummy data
const response = await axios.get(`/api/getRD/${id}`, { const response = await axios.get(`/api/getRD/${id}`, {
headers: { headers: {
"Access-Control-Allow-Origin": "*", "Access-Control-Allow-Origin": "*",
@ -67,8 +29,7 @@ const MapRD = () => {
"Content-Type": "multipart/form-data", "Content-Type": "multipart/form-data",
}, },
}); });
setData(response.data); setData(response?.data);
// console.log('Retailer Details: ', response.data);
} catch (error) { } catch (error) {
console.error("Error fetching data: ", error); console.error("Error fetching data: ", error);
} }
@ -77,161 +38,6 @@ const MapRD = () => {
fetchData(); fetchData();
}, [id, token, success]); }, [id, token, success]);
// SC
const getSalesCoOrdinatorsData = async () => {
setLoading(true);
try {
const res = await axios.get(`/api/salescoordinator/getAll`, {
headers: {
Authorization: `Bearer ${token}`,
},
params: {
page: modalcurrentPage,
show: modalitemPerPage,
name: scnameRef.current?.value,
mobileNumber: scmobileRef.current?.value,
},
});
setModalSalesCoordinators(res.data?.salesCoOrinators);
setModalTotalData(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(() => {
if (openSCModal) {
getSalesCoOrdinatorsData();
}
}, [openSCModal, modalcurrentPage]);
// Debounced search for Sales Coordinators in modal
const debouncedmodalSearchforSC = useCallback(
debounce(() => {
setmodalCurrentPage(1);
getSalesCoOrdinatorsData();
}, 500),
[modalcurrentPage]
);
const handlemodalSearchChangeinSC = useCallback(() => {
debouncedmodalSearchforSC();
}, [debouncedmodalSearchforSC]);
// PD
const getprincipaldistributorData = async () => {
setLoading(true);
try {
const res = await axios.get(`/api/v1/admin/users`, {
headers: {
Authorization: `Bearer ${token}`,
},
params: {
page: modalcurrentPage,
show: modalitemPerPage,
name: pdnameRef.current?.value,
mobileNumber: pdmobileRef.current?.value,
},
});
setmodalPrincipalDistributors(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 (openPDModal) {
getprincipaldistributorData();
}
}, [openPDModal, modalcurrentPage]);
// Debounced search for Principal Distributors in modal
const debouncedmodalSearchforPD = useCallback(
debounce(() => {
setmodalCurrentPage(1);
getprincipaldistributorData();
}, 500),
[modalcurrentPage]
);
const handlemodalSearchChangeinPD = useCallback(() => {
debouncedmodalSearchforPD();
}, [debouncedmodalSearchforPD]);
// TM
const getTerritorymanagersData = async () => {
setLoading(true);
try {
const res = await axios.get(`/api/territorymanager/getAll`, {
headers: {
Authorization: `Bearer ${token}`,
},
params: {
page: modalcurrentPage,
show: modalitemPerPage,
name: tmnameRef.current?.value,
mobileNumber: tmmobileRef.current?.value,
},
});
setmodalterritorymanagers(res.data?.territoryManager);
setModalTotalData(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(() => {
if (openTMModal) {
getTerritorymanagersData();
}
}, [openTMModal, modalcurrentPage]);
// Debounced search for Territory manager in modal
const debouncedmodalSearchforTM = useCallback(
debounce(() => {
setmodalCurrentPage(1);
getTerritorymanagersData();
}, 500),
[modalcurrentPage]
);
const handlemodalSearchChangeinTM = useCallback(() => {
debouncedmodalSearchforTM();
}, [debouncedmodalSearchforTM]);
const handlePreviousPage = () => {
if (modalcurrentPage > 1) {
setmodalCurrentPage(modalcurrentPage - 1);
}
};
const handleDelete = (designation) => { const handleDelete = (designation) => {
swal({ swal({
title: "Are you sure?", title: "Are you sure?",
@ -242,7 +48,6 @@ const MapRD = () => {
}, },
}).then((value) => { }).then((value) => {
if (value === true) { if (value === true) {
// Create the data object based on designation
let data = {}; let data = {};
if (designation === "TM") { if (designation === "TM") {
data.mappedTM = true; data.mappedTM = true;
@ -252,18 +57,13 @@ const MapRD = () => {
data.principal_distributor = true; data.principal_distributor = true;
} }
// Make the PATCH request with the constructed data object
axios axios
.patch( .patch(`/api/unmap/${id}`, data, {
`/api/unmap/${id}`,
data, // Send the constructed data object
{
headers: { headers: {
"Access-Control-Allow-Origin": "*", "Access-Control-Allow-Origin": "*",
Authorization: `Bearer ${token}`, Authorization: `Bearer ${token}`,
}, },
} })
)
.then((res) => { .then((res) => {
swal({ swal({
title: "Deleted", title: "Deleted",
@ -287,59 +87,19 @@ const MapRD = () => {
}); });
}; };
const handleUpdateMapping = async (rdid, designation) => { const handleOpenPDModal = () => setOpenPDModal(true);
try { const handleClosePDModal = () => setOpenPDModal(false);
// Create the data object based on designation
let data = {};
if (designation === "TM") {
data.mappedTM = rdid;
} else if (designation === "SC") {
data.mappedSC = rdid;
} else {
data.principal_distributor = rdid;
}
// Make the API request const handleOpenSCModal = () => setOpenSCModal(true);
await axios.put( const handleCloseSCModal = () => setOpenSCModal(false);
`/api/mapped/${id}`,
data, // Send the constructed data object
{
headers: {
Authorization: `Bearer ${token}`,
},
}
);
// Success alert const handleOpenTMModal = () => setOpenTMModal(true);
swal({ const handleCloseTMModal = () => setOpenTMModal(false);
title: "Success",
text: "Mapped successfully!",
icon: "success",
button: "Ok",
});
// Trigger success state change and close modals const refreshData = () => {
setSuccess((prev) => !prev); setSuccess((prev) => !prev);
handleClosePDModal();
handleCloseSCModal();
handleCloseTMModal();
} catch (err) {
// Handle error and show error message
const msg = err?.response?.data?.message || "Something went wrong!";
swal({
title: "Error",
text: msg,
icon: "error",
button: "Retry",
dangerMode: true,
});
}
}; };
if (!data) {
return <Typography>Loading...</Typography>;
}
return ( return (
<Box sx={{ p: 3 }}> <Box sx={{ p: 3 }}>
<Box <Box
@ -374,28 +134,28 @@ const MapRD = () => {
<Grid container spacing={2}> <Grid container spacing={2}>
<Grid item xs={6}> <Grid item xs={6}>
<Typography> <Typography>
<strong>Trade Name:</strong> {data.kyc.trade_name} <strong>Trade Name:</strong> {data?.kyc.trade_name}
</Typography> </Typography>
<Typography> <Typography>
<strong>Name:</strong> {data.name} <strong>Name:</strong> {data?.name}
</Typography> </Typography>
<Typography> <Typography>
<strong>Address:</strong> {data.kyc.address} <strong>Address:</strong> {data?.kyc.address}
</Typography> </Typography>
<Typography> <Typography>
<strong>Town/City:</strong> {data.kyc.city} <strong>Town/City:</strong> {data?.kyc.city}
</Typography> </Typography>
<Typography> <Typography>
<strong>District:</strong> {data.kyc.district} <strong>District:</strong> {data?.kyc.district}
</Typography> </Typography>
<Typography> <Typography>
<strong>State:</strong> {data.kyc.state} <strong>State:</strong> {data?.kyc.state}
</Typography> </Typography>
<Typography> <Typography>
<strong>Pincode:</strong> {data.kyc.pincode} <strong>Pincode:</strong> {data?.kyc.pincode}
</Typography> </Typography>
<Typography> <Typography>
<strong>Mobile Number:</strong> {data.mobile_number} <strong>Mobile Number:</strong> {data?.mobile_number}
</Typography> </Typography>
</Grid> </Grid>
<Grid item xs={6}> <Grid item xs={6}>
@ -414,7 +174,6 @@ const MapRD = () => {
</Grid> </Grid>
</Grid> </Grid>
</Paper> </Paper>
{/* Territory Managers */} {/* Territory Managers */}
<Paper sx={{ p: 2, mb: 3 }}> <Paper sx={{ p: 2, mb: 3 }}>
<Box <Box
@ -451,19 +210,18 @@ const MapRD = () => {
<Grid container spacing={2}> <Grid container spacing={2}>
<Grid item xs={6}> <Grid item xs={6}>
<Typography> <Typography>
<strong>Name:</strong> {data.mappedTM?.name || "Not Mapped"} <strong>Name:</strong> {data?.mappedTM?.name || "Not Mapped"}
</Typography> </Typography>
<Typography> <Typography>
<strong>Mobile Number:</strong>{" "} <strong>Mobile Number:</strong>{" "}
{data.mappedTM?.mobileNumber || "Not Mapped"} {data?.mappedTM?.mobileNumber || "Not Mapped"}
</Typography> </Typography>
<Typography> <Typography>
<strong>Email:</strong> {data.mappedTM?.email || "Not Mapped"} <strong>Email:</strong> {data?.mappedTM?.email || "Not Mapped"}
</Typography> </Typography>
</Grid> </Grid>
</Grid> </Grid>
</Paper> </Paper>
{/* Sales Coordinators */} {/* Sales Coordinators */}
<Paper sx={{ p: 2, mb: 3 }}> <Paper sx={{ p: 2, mb: 3 }}>
<Box <Box
@ -500,19 +258,18 @@ const MapRD = () => {
<Grid container spacing={2}> <Grid container spacing={2}>
<Grid item xs={6}> <Grid item xs={6}>
<Typography> <Typography>
<strong>Name:</strong> {data.mappedSC?.name || "Not Mapped"} <strong>Name:</strong> {data?.mappedSC?.name || "Not Mapped"}
</Typography> </Typography>
<Typography> <Typography>
<strong>Mobile Number:</strong>{" "} <strong>Mobile Number:</strong>{" "}
{data.mappedSC?.mobileNumber || "Not Mapped"} {data?.mappedSC?.mobileNumber || "Not Mapped"}
</Typography> </Typography>
<Typography> <Typography>
<strong>Email:</strong> {data.mappedSC?.email || "Not Mapped"} <strong>Email:</strong> {data?.mappedSC?.email || "Not Mapped"}
</Typography> </Typography>
</Grid> </Grid>
</Grid> </Grid>
</Paper> </Paper>
{/* Principal Distributor */} {/* Principal Distributor */}
<Paper sx={{ p: 2, mb: 3 }}> <Paper sx={{ p: 2, mb: 3 }}>
<Box <Box
@ -529,8 +286,8 @@ const MapRD = () => {
<Button <Button
variant="contained" variant="contained"
color="primary" color="primary"
size="small" // Set button size to small size="small"
style={{ backgroundColor: "blue", marginRight: "8px" }} // marginRight for gap style={{ backgroundColor: "blue", marginRight: "8px" }}
onClick={handleOpenPDModal} onClick={handleOpenPDModal}
> >
Map PD Map PD
@ -538,7 +295,7 @@ const MapRD = () => {
<Button <Button
variant="contained" variant="contained"
color="secondary" color="secondary"
size="small" // Set button size to small size="small"
style={{ backgroundColor: "red" }} style={{ backgroundColor: "red" }}
onClick={() => handleDelete("PD")} onClick={() => handleDelete("PD")}
> >
@ -550,346 +307,38 @@ const MapRD = () => {
<Grid item xs={6}> <Grid item xs={6}>
<Typography> <Typography>
<strong>Name:</strong>{" "} <strong>Name:</strong>{" "}
{data.principal_distributer?.name || "Not Mapped"} {data?.principal_distributer?.name || "Not Mapped"}
</Typography> </Typography>
<Typography> <Typography>
<strong>Mobile Number:</strong>{" "} <strong>Mobile Number:</strong>{" "}
{data.principal_distributer?.phone || "Not Mapped"} {data?.principal_distributer?.phone || "Not Mapped"}
</Typography> </Typography>
<Typography> <Typography>
<strong>Email:</strong>{" "} <strong>Email:</strong>{" "}
{data.principal_distributer?.email || "Not Mapped"} {data?.principal_distributer?.email || "Not Mapped"}
</Typography> </Typography>
</Grid> </Grid>
</Grid> </Grid>
</Paper> </Paper>
{/* Principal Distributor */}
<Dialog
open={openPDModal}
onClose={handleClosePDModal}
maxWidth="md"
fullWidth
>
<DialogTitle>Search and Add Principal Distributor</DialogTitle>
<DialogContent>
<div
style={{
display: "flex",
gap: "16px",
marginBottom: "2rem",
marginTop: "-1rem",
}}
>
<TextField
label="Principal Distributor Name"
placeholder="Principal Distributor name"
inputRef={pdnameRef}
onChange={handlemodalSearchChangeinPD}
disabled={loading}
style={{ flex: 1, marginRight: "16px" }}
/>
<TextField
style={{ flex: 1 }}
label="Mobile Number"
placeholder="Mobile Number"
inputRef={pdmobileRef}
onChange={handlemodalSearchChangeinPD}
disabled={loading}
/>
</div>
<div className="table-responsive table-shoot mt-3">
<table className="table table-centered table-nowrap">
<thead>
<tr>
<th>Id</th>
<th>SBU</th>
<th>Name</th>
<th>Mobile</th>
<th>Email</th>
<th>SC</th>
<th>TM</th>
<th>Action</th>
</tr>
</thead>
<tbody>
{modalPrincipalDistributors.length > 0 ? (
modalPrincipalDistributors.map((PD) => (
<tr key={PD._id}>
<td>{PD.uniqueId}</td>
<td>{PD.SBU}</td>
<td>{PD.name}</td>
<td>{PD.phone}</td>
<td>{PD.email}</td>
<td>{PD.mappedbySC?.name || "N/A"}</td>
<td>{PD.mappedby?.name || "N/A"}</td>
<td>
<Button
variant="contained"
color="primary"
onClick={() => handleUpdateMapping(PD._id, "PD")}
>
Add
</Button>
</td>
</tr>
))
) : (
<tr>
<td colSpan="6" className="text-center">
No Principal Distributor found!
</td>
</tr>
)}
</tbody>
</table>
</div>
<div className="d-flex justify-content-between">
<div>
Showing {modalPrincipalDistributors?.length} of {modalTotalData}{" "}
entries
</div>
<div>
<button
onClick={handlePreviousPage}
disabled={modalcurrentPage === 1 || loading}
className="btn btn-primary"
>
Previous
</button>
<button
onClick={
modalPrincipalDistributors.length === modalitemPerPage
? setmodalCurrentPage(modalcurrentPage + 1)
: null
}
disabled={
modalPrincipalDistributors?.length < modalitemPerPage ||
loading
}
className="btn btn-primary ml-2"
>
Next
</button>
</div>
</div>
</DialogContent>
<DialogActions>
<Button onClick={handleClosePDModal} color="secondary">
Cancel
</Button>
</DialogActions>
</Dialog>
{/* Sales Coordinator */}
<Dialog
open={openSCModal}
onClose={handleCloseSCModal}
maxWidth="md"
fullWidth
>
<DialogTitle>Search and Add Sales Coordinator</DialogTitle>
<DialogContent>
<div
style={{
display: "flex",
gap: "16px",
marginBottom: "2rem",
marginTop: "-1rem",
}}
>
<TextField
label="Sales Coordinator Name"
placeholder="Sales Coordinator name"
inputRef={scnameRef}
onChange={handlemodalSearchChangeinSC}
disabled={loading}
style={{ flex: 1, marginRight: "16px" }}
/>
<TextField
style={{ flex: 1 }}
label="Mobile Number"
placeholder="Mobile Number"
inputRef={scmobileRef}
onChange={handlemodalSearchChangeinSC}
disabled={loading}
/>
</div>
<div className="table-responsive table-shoot mt-3"> <PDmodal
<table className="table table-centered table-nowrap"> rdid={id}
<thead> openPDModal={openPDModal}
<tr> handleClosePDModal={handleClosePDModal}
<th>Id</th> refreshData={refreshData}
<th>Name</th>
<th>Mobile</th>
<th>TM</th>
<th>Action</th>
</tr>
</thead>
<tbody>
{modalSalesCoordinators.map((coordinator) => (
<tr key={coordinator._id}>
<td>{coordinator.uniqueId}</td>
<td>{coordinator.name}</td>
<td>{coordinator.mobileNumber}</td>
<td>{coordinator.mappedby?.name || "N/A"}</td>
<td>
<Button
variant="contained"
color="primary"
onClick={() => handleUpdateMapping(coordinator._id, "SC")}
>
Add
</Button>
</td>
</tr>
))}
</tbody>
</table>
</div>
<div className="d-flex justify-content-between">
<div>
Showing {modalSalesCoordinators?.length} of {modalTotalData}{" "}
entries
</div>
<div>
<button
onClick={handlePreviousPage}
disabled={modalcurrentPage === 1 || loading}
className="btn btn-primary"
>
Previous
</button>
<button
onClick={
modalSalesCoordinators.length === modalitemPerPage
? setmodalCurrentPage(modalcurrentPage + 1)
: null
}
disabled={
modalSalesCoordinators?.length < modalitemPerPage || loading
}
className="btn btn-primary ml-2"
>
Next
</button>
</div>
</div>
</DialogContent>
<DialogActions>
<Button onClick={handleCloseSCModal} color="secondary">
Cancel
</Button>
</DialogActions>
</Dialog>
{/* Territory Manager */}
<Dialog
open={openTMModal}
onClose={handleCloseTMModal}
maxWidth="md"
fullWidth
>
<DialogTitle>Search and Add Territory Manager</DialogTitle>
<DialogContent>
<div
style={{
display: "flex",
gap: "16px",
marginBottom: "2rem",
marginTop: "-1rem",
}}
>
<TextField
label="Territory Manager Name"
placeholder="Territory Manager name"
inputRef={tmnameRef}
onChange={handlemodalSearchChangeinTM}
disabled={loading}
style={{ flex: 1, marginRight: "16px" }}
/> />
<TextField <SCmodal
style={{ flex: 1 }} rdid={id}
label="Mobile Number" openSCModal={openSCModal}
placeholder="Mobile Number" handleCloseSCModal={handleCloseSCModal}
inputRef={tmmobileRef} refreshData={refreshData}
onChange={handlemodalSearchChangeinTM} />
disabled={loading} <TMmodal
rdid={id}
openTMModal={openTMModal}
handleCloseTMModal={handleCloseTMModal}
refreshData={refreshData}
/> />
</div>
<div className="table-responsive table-shoot mt-3">
<table className="table table-centered table-nowrap">
<thead>
<tr>
<th>Id</th>
<th>Name</th>
<th>Mobile</th>
<th>Email</th>
<th>Action</th>
</tr>
</thead>
<tbody>
{modalterritorymanagers.length > 0 ? (
modalterritorymanagers.map((TM) => (
<tr key={TM._id}>
<td>{TM.uniqueId}</td>
<td>{TM.name}</td>
<td>{TM.mobileNumber}</td>
<td>{TM.email}</td>
<td>
<Button
variant="contained"
color="primary"
onClick={() => handleUpdateMapping(TM._id, "TM")}
>
Add
</Button>
</td>
</tr>
))
) : (
<tr>
<td colSpan="6" className="text-center">
No Territory Manager found!
</td>
</tr>
)}
</tbody>
</table>
</div>
<div className="d-flex justify-content-between">
<div>
Showing {modalterritorymanagers?.length} of {modalTotalData}{" "}
entries
</div>
<div>
<button
onClick={handlePreviousPage}
disabled={modalcurrentPage === 1 || loading}
className="btn btn-primary"
>
Previous
</button>
<button
onClick={
modalterritorymanagers.length === modalitemPerPage
? setmodalCurrentPage(modalcurrentPage + 1)
: null
}
disabled={
modalterritorymanagers?.length < modalitemPerPage || loading
}
className="btn btn-primary ml-2"
>
Next
</button>
</div>
</div>
</DialogContent>
<DialogActions>
<Button onClick={handleCloseTMModal} color="secondary">
Cancel
</Button>
</DialogActions>
</Dialog>
</Box> </Box>
); );
}; };

View File

@ -0,0 +1,224 @@
import React, { useState, useEffect, useRef, useCallback } from "react";
import axios from "axios";
import {
Box,
Typography,
Grid,
Paper,
Dialog,
DialogContent,
DialogTitle,
Button,
TextField,
DialogActions,
} from "@mui/material";
import { isAutheticated } from "../../auth";
import swal from "sweetalert";
import debounce from "lodash.debounce";
const PDmodal = ({ openPDModal, handleClosePDModal, refreshData, rdid }) => {
const token = isAutheticated();
const [modalPrincipalDistributors, setmodalPrincipalDistributors] = useState(
[]
);
const [modalTotalData, setModalTotalData] = useState(0);
const [modalcurrentPage, setmodalCurrentPage] = useState(1);
const [modalitemPerPage, setmodalItemPerPage] = useState(10);
const [loading, setLoading] = useState(false);
const pdnameRef = useRef();
const pdmobileRef = useRef();
const getprincipaldistributorData = async () => {
setLoading(true);
try {
const res = await axios.get(`/api/v1/admin/users`, {
headers: {
Authorization: `Bearer ${token}`,
},
params: {
page: modalcurrentPage,
show: modalitemPerPage,
name: pdnameRef.current?.value,
mobileNumber: pdmobileRef.current?.value,
},
});
setmodalPrincipalDistributors(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);
}
};
const handlePDMap = (id) => {
const data = {
principal_distributor: id,
};
axios
.put(`/api/mapped/${rdid}`, data, {
headers: {
Authorization: `Bearer ${token}`,
},
})
.then((res) => {
swal({
title: "Success",
text: "Principal Distributor mapped successfully!",
icon: "success",
button: "Ok",
});
refreshData(); // Call the refresh function
handleClosePDModal();
})
.catch((err) => {
const msg = err?.response?.data?.message || "Something went wrong!";
swal({
title: "Error",
text: msg,
icon: "error",
button: "Retry",
dangerMode: true,
});
});
};
useEffect(() => {
getprincipaldistributorData();
}, [modalcurrentPage]);
const handleInputChange = useCallback(
debounce(() => {
getprincipaldistributorData();
}, 1000),
[]
);
const handleNextPage = () => {
setmodalCurrentPage((prev) => prev + 1);
};
const handlePreviousPage = () => {
setmodalCurrentPage((prev) => prev - 1);
};
return (
<Dialog
open={openPDModal}
onClose={handleClosePDModal}
fullWidth
maxWidth="lg"
>
<DialogTitle>Map Principal Distributor</DialogTitle>
<DialogTitle>Search and Add Principal Distributor</DialogTitle>
<DialogContent>
<div
style={{
display: "flex",
gap: "16px",
marginBottom: "2rem",
marginTop: "-1rem",
}}
>
<TextField
label="Principal Distributor Name"
placeholder="Principal Distributor name"
inputRef={pdnameRef}
onChange={handleInputChange}
disabled={loading}
style={{ flex: 1, marginRight: "16px" }}
/>
<TextField
style={{ flex: 1 }}
label="Mobile Number"
placeholder="Mobile Number"
inputRef={pdmobileRef}
onChange={handleInputChange}
disabled={loading}
/>
</div>
<div className="table-responsive table-shoot mt-3">
<table className="table table-centered table-nowrap">
<thead>
<tr>
<th>Id</th>
<th>SBU</th>
<th>Name</th>
<th>Mobile</th>
<th>Email</th>
<th>SC</th>
<th>TM</th>
<th>Action</th>
</tr>
</thead>
<tbody>
{modalPrincipalDistributors.length > 0 ? (
modalPrincipalDistributors.map((PD) => (
<tr key={PD._id}>
<td>{PD.uniqueId}</td>
<td>{PD.SBU}</td>
<td>{PD.name}</td>
<td>{PD.phone}</td>
<td>{PD.email}</td>
<td>{PD.mappedbySC?.name || "N/A"}</td>
<td>{PD.mappedby?.name || "N/A"}</td>
<td>
<Button
variant="contained"
color="primary"
onClick={() => handlePDMap(PD._id)}
>
Add
</Button>
</td>
</tr>
))
) : (
<tr>
<td colSpan="8" className="text-center">
No Principal Distributor found!
</td>
</tr>
)}
</tbody>
</table>
</div>
<div className="d-flex justify-content-between">
<div>
Showing {modalPrincipalDistributors.length} of {modalTotalData}{" "}
entries
</div>
<div>
<Button
onClick={handlePreviousPage}
disabled={modalcurrentPage === 1 || loading}
className="btn btn-primary"
>
Previous
</Button>
<Button
onClick={handleNextPage}
disabled={
modalPrincipalDistributors.length < modalitemPerPage || loading
}
className="btn btn-primary ml-2"
>
Next
</Button>
</div>
</div>
</DialogContent>
<DialogActions>
<Button onClick={handleClosePDModal} color="secondary">
Cancel
</Button>
</DialogActions>
</Dialog>
);
};
export default PDmodal;

View File

@ -0,0 +1,206 @@
import React, { useState, useEffect, useRef, useCallback } from "react";
import axios from "axios";
import {
Dialog,
DialogContent,
DialogTitle,
Button,
TextField,
DialogActions,
} from "@mui/material";
import { isAutheticated } from "../../auth";
import swal from "sweetalert";
import debounce from "lodash.debounce";
const SCmodal = ({ openSCModal, handleCloseSCModal, refreshData, rdid }) => {
const token = isAutheticated();
const [modalSalesCoordinators, setmodalSalesCoordinators] = useState(
[]
);
const [modalTotalData, setModalTotalData] = useState(0);
const [modalcurrentPage, setmodalCurrentPage] = useState(1);
const [modalitemPerPage, setmodalItemPerPage] = useState(10);
const [loading, setLoading] = useState(false);
const scnameRef = useRef();
const scmobileRef = useRef();
const getSalesCoOrdinatorsData = async () => {
setLoading(true);
try {
const res = await axios.get(`/api/salescoordinator/getAll`, {
headers: {
Authorization: `Bearer ${token}`,
},
params: {
page: modalcurrentPage,
show: modalitemPerPage,
name: scnameRef.current?.value,
mobileNumber: scmobileRef.current?.value,
},
});
setmodalSalesCoordinators(res.data?.salesCoOrinators);
setModalTotalData(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);
}
};
const handleSCMap = (id) => {
const data = {
mappedSC: id,
};
axios
.put(`/api/mapped/${rdid}`, data, {
headers: {
Authorization: `Bearer ${token}`,
},
})
.then((res) => {
swal({
title: "Success",
text: "Principal Distributor mapped successfully!",
icon: "success",
button: "Ok",
});
refreshData(); // Call the refresh function
handleCloseSCModal();
})
.catch((err) => {
const msg = err?.response?.data?.message || "Something went wrong!";
swal({
title: "Error",
text: msg,
icon: "error",
button: "Retry",
dangerMode: true,
});
});
};
useEffect(() => {
getSalesCoOrdinatorsData();
}, [modalcurrentPage]);
const handleInputChange = useCallback(
debounce(() => {
getSalesCoOrdinatorsData();
}, 1000),
[]
);
const handleNextPage = () => {
setmodalCurrentPage((prev) => prev + 1);
};
const handlePreviousPage = () => {
setmodalCurrentPage((prev) => prev - 1);
};
return (
<Dialog
open={openSCModal}
onClose={handleCloseSCModal}
fullWidth
maxWidth="lg"
>
<DialogTitle>Search and Add Sales Coordinator</DialogTitle>
<DialogContent>
<div
style={{
display: "flex",
gap: "16px",
marginBottom: "2rem",
marginTop: "-1rem",
}}
>
<TextField
label="Sales Coordinator Name"
placeholder="Sales Coordinator name"
inputRef={scnameRef}
onChange={handleInputChange}
disabled={loading}
style={{ flex: 1, marginRight: "16px" }}
/>
<TextField
style={{ flex: 1 }}
label="Mobile Number"
placeholder="Mobile Number"
inputRef={scmobileRef}
onChange={handleInputChange}
disabled={loading}
/>
</div>
<div className="table-responsive table-shoot mt-3">
<table className="table table-centered table-nowrap">
<thead>
<tr>
<th>Id</th>
<th>Name</th>
<th>Mobile</th>
<th>TM</th>
<th>Action</th>
</tr>
</thead>
<tbody>
{modalSalesCoordinators.map((coordinator) => (
<tr key={coordinator._id}>
<td>{coordinator.uniqueId}</td>
<td>{coordinator.name}</td>
<td>{coordinator.mobileNumber}</td>
<td>{coordinator.mappedby?.name || "N/A"}</td>
<td>
<Button
variant="contained"
color="primary"
onClick={() => handleSCMap(coordinator._id)}
>
Add
</Button>
</td>
</tr>
))}
</tbody>
</table>
</div>
<div className="d-flex justify-content-between">
<div>
Showing {modalSalesCoordinators?.length} of {modalTotalData}{" "}
entries
</div>
<div>
<button
onClick={handlePreviousPage}
disabled={modalcurrentPage === 1 || loading}
className="btn btn-primary"
>
Previous
</button>
<button
onClick={handleNextPage}
disabled={
modalSalesCoordinators?.length < modalitemPerPage || loading
}
className="btn btn-primary ml-2"
>
Next
</button>
</div>
</div>
</DialogContent>
<DialogActions>
<Button onClick={handleCloseSCModal} color="secondary">
Cancel
</Button>
</DialogActions>
</Dialog>
);
};
export default SCmodal;

View File

@ -0,0 +1,213 @@
import React, { useState, useEffect, useRef, useCallback } from "react";
import axios from "axios";
import {
Dialog,
DialogContent,
DialogTitle,
Button,
TextField,
DialogActions,
} from "@mui/material";
import { isAutheticated } from "../../auth";
import swal from "sweetalert";
import debounce from "lodash.debounce";
const TMmodal = ({ openTMModal, handleCloseTMModal, refreshData, rdid }) => {
const token = isAutheticated();
const [modalTerritoryManagers, setmodalTerritoryManagers] = useState(
[]
);
const [modalTotalData, setModalTotalData] = useState(0);
const [modalcurrentPage, setmodalCurrentPage] = useState(1);
const [modalitemPerPage, setmodalItemPerPage] = useState(10);
const [loading, setLoading] = useState(false);
const tmnameRef = useRef();
const tmmobileRef = useRef();
const getTerritorymanagersData = async () => {
setLoading(true);
try {
const res = await axios.get(`/api/territorymanager/getAll`, {
headers: {
Authorization: `Bearer ${token}`,
},
params: {
page: modalcurrentPage,
show: modalitemPerPage,
name: tmnameRef.current?.value,
mobileNumber: tmmobileRef.current?.value,
},
});
setmodalTerritoryManagers(res.data?.territoryManager);
setModalTotalData(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);
}
};
const handleTMMap = (id) => {
const data = {
mappedTM: id,
};
axios
.put(`/api/mapped/${rdid}`, data, {
headers: {
Authorization: `Bearer ${token}`,
},
})
.then((res) => {
swal({
title: "Success",
text: "Principal Distributor mapped successfully!",
icon: "success",
button: "Ok",
});
refreshData(); // Call the refresh function
handleCloseTMModal();
})
.catch((err) => {
const msg = err?.response?.data?.message || "Something went wrong!";
swal({
title: "Error",
text: msg,
icon: "error",
button: "Retry",
dangerMode: true,
});
});
};
useEffect(() => {
getTerritorymanagersData();
}, [modalcurrentPage]);
const handleInputChange = useCallback(
debounce(() => {
getTerritorymanagersData();
}, 1000),
[]
);
const handleNextPage = () => {
setmodalCurrentPage((prev) => prev + 1);
};
const handlePreviousPage = () => {
setmodalCurrentPage((prev) => prev - 1);
};
return (
<Dialog
open={openTMModal}
onClose={handleCloseTMModal}
fullWidth
maxWidth="lg"
>
<DialogTitle>Search and Add Territory Manager</DialogTitle>
<DialogContent>
<div
style={{
display: "flex",
gap: "16px",
marginBottom: "2rem",
marginTop: "-1rem",
}}
>
<TextField
label="Territory Manager Name"
placeholder="Territory Manager name"
inputRef={tmnameRef}
onChange={handleInputChange}
disabled={loading}
style={{ flex: 1, marginRight: "16px" }}
/>
<TextField
style={{ flex: 1 }}
label="Mobile Number"
placeholder="Mobile Number"
inputRef={tmmobileRef}
onChange={handleInputChange}
disabled={loading}
/>
</div>
<div className="table-responsive table-shoot mt-3">
<table className="table table-centered table-nowrap">
<thead>
<tr>
<th>Id</th>
<th>Name</th>
<th>Mobile</th>
<th>Email</th>
<th>Action</th>
</tr>
</thead>
<tbody>
{modalTerritoryManagers.length > 0 ? (
modalTerritoryManagers.map((TM) => (
<tr key={TM._id}>
<td>{TM.uniqueId}</td>
<td>{TM.name}</td>
<td>{TM.mobileNumber}</td>
<td>{TM.email}</td>
<td>
<Button
variant="contained"
color="primary"
onClick={() => handleTMMap(TM._id)}
>
Add
</Button>
</td>
</tr>
))
) : (
<tr>
<td colSpan="6" className="text-center">
No Territory Manager found!
</td>
</tr>
)}
</tbody>
</table>
</div>
<div className="d-flex justify-content-between">
<div>
Showing {modalTerritoryManagers?.length} of {modalTotalData}{" "}
entries
</div>
<div>
<button
onClick={handlePreviousPage}
disabled={modalcurrentPage === 1 || loading}
className="btn btn-primary"
>
Previous
</button>
<button
onClick={handleNextPage}
disabled={
modalTerritoryManagers?.length < modalitemPerPage || loading
}
className="btn btn-primary ml-2"
>
Next
</button>
</div>
</div>
</DialogContent>
<DialogActions>
<Button onClick={handleCloseTMModal} color="secondary">
Cancel
</Button>
</DialogActions>
</Dialog>
);
};
export default TMmodal;

481
src/views/Sales/Sales.js Normal file
View File

@ -0,0 +1,481 @@
import React, { useState, useEffect, useRef, useCallback } from "react";
import { Link } from "react-router-dom";
import axios from "axios";
import { isAutheticated } from "src/auth";
import swal from "sweetalert";
import debounce from "lodash.debounce";
const Sales = () => {
const token = isAutheticated();
const [loading, setLoading] = useState(false);
const [SalesData, setSalesData] = useState([]);
const nameRef = useRef();
const startDateRef = useRef();
const endDateRef = useRef();
const [currentPage, setCurrentPage] = useState(1);
const [itemPerPage, setItemPerPage] = useState(10);
const [totalData, setTotalData] = useState(0);
const getSalesData = async () => {
setLoading(true);
try {
const response = await axios.get(`/api/sales/all`, {
headers: {
Authorization: `Bearer ${token}`,
},
params: {
page: currentPage,
show: itemPerPage,
startDate: startDateRef.current?.value || "",
endDate: endDateRef.current?.value || "",
name: nameRef.current?.value || "",
},
});
// console.log("response", response.data);
const transformedData =
response.data?.Sales?.map((entry) => ({
id: entry._id,
uniqueId: entry.uniqueId,
tradeName: entry.tradeName || "N/A",
designation: entry.addedFor === "PrincipalDistributor" ? "PD" : "RD",
products: entry.products.map((product) => ({
SKU: product.SKU,
ProductName: product.ProductName,
SalesAmount: product.SalesAmount,
QuantitySold: product.QuantitySold,
})),
createdAt: entry.createdAt,
updatedAt: entry.updatedAt,
})) || [];
setSalesData(transformedData);
setTotalData(response.data?.total_data || 0);
} catch (err) {
const msg = err?.response?.data?.msg || "Something went wrong!";
swal({
title: "Error",
text: msg,
icon: "error",
button: "Retry",
dangerMode: true,
});
} finally {
setLoading(false);
}
};
const debouncedSearch = useCallback(
debounce(() => {
setCurrentPage(1);
getSalesData();
}, 500),
[]
);
const handleSearchChange = () => {
debouncedSearch();
};
useEffect(() => {
getSalesData();
}, [itemPerPage, currentPage]);
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">
Sales List
</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>Trade Name:</label>
<input
type="text"
placeholder="Trade name"
className="form-control"
ref={nameRef}
onChange={handleSearchChange}
disabled={loading}
/>
</div>
<div className="col-lg-3">
<label>Start Date:</label>
<input
type="date"
className="form-control"
ref={startDateRef}
onChange={handleSearchChange}
disabled={loading}
/>
</div>
<div className="col-lg-3">
<label>End Date:</label>
<input
type="date"
className="form-control"
ref={endDateRef}
onChange={handleSearchChange}
disabled={loading}
/>
</div>
</div>
<div className="table-responsive table-shoot mt-3">
<table
className="table table-centered table-nowrap"
style={{
border: "1px solid",
borderCollapse: "collapse",
}} // Ensure borders collapse for clean lines
>
<thead
className="thead-light"
style={{ background: "#ecdddd" }}
>
<tr>
<th
className="text-start"
style={{ border: "1px solid" }}
>
ID
</th>
<th
className="text-start"
style={{ border: "1px solid" }}
>
Date
</th>
<th
className="text-start"
style={{ border: "1px solid" }}
>
Time
</th>
<th
className="text-start"
style={{ border: "1px solid" }}
>
Trade Name
</th>
<th
className="text-start"
style={{ border: "1px solid" }}
>
PD/RD
</th>
<th
className="text-start"
style={{ border: "1px solid" }}
>
Product SKU
</th>
<th
className="text-start"
style={{ border: "1px solid" }}
>
Product Name
</th>
<th
className="text-start"
style={{ border: "1px solid" }}
>
QuantitySold
</th>
<th
className="text-start"
style={{ border: "1px solid" }}
>
SalesAmount
</th>
<th
className="text-start"
style={{ border: "1px solid" }}
>
Actions
</th>
</tr>
</thead>
<tbody>
{loading ? (
<tr>
<td
className="text-center"
colSpan="10"
style={{ border: "1px solid" }}
>
Loading...
</td>
</tr>
) : SalesData.length > 0 ? (
SalesData.map((entry, i) =>
entry.products.map((product, j) => (
<tr key={`${i}-${j}`}>
{/* Only show ID, Date, Time, Trade Name, PD/RD, and Actions on the first row of each entry */}
{j === 0 && (
<>
<td
className="text-start"
rowSpan={entry.products.length}
style={{ border: "1px solid" }}
>
{entry.uniqueId}
</td>
<td
className="text-start"
rowSpan={entry.products.length}
style={{ border: "1px solid" }}
>
{new Date(entry.createdAt).toLocaleString(
"en-IN",
{
month: "short",
day: "numeric",
year: "numeric",
}
)}
</td>
<td
className="text-start"
rowSpan={entry.products.length}
style={{ border: "1px solid" }}
>
{new Date(entry.createdAt).toLocaleString(
"en-IN",
{
hour: "numeric",
minute: "numeric",
hour12: true,
}
)}
</td>
<td
className="text-start"
rowSpan={entry.products.length}
style={{ border: "1px solid" }}
>
{entry.tradeName}
</td>
<td
className="text-start"
rowSpan={entry.products.length}
style={{ border: "1px solid" }}
>
{entry.designation}
</td>
</>
)}
{/* Product details */}
<td
className="text-start"
style={{ border: "1px solid" }}
>
{product.SKU}
</td>
<td
className="text-start"
style={{ border: "1px solid" }}
>
{product.ProductName}
</td>
<td
className="text-start"
style={{ border: "1px solid" }}
>
{product.QuantitySold}
</td>
<td
className="text-start"
style={{ border: "1px solid" }}
>
{product.SalesAmount}
</td>
{/* Actions: only show on the first row of each entry */}
{j === 0 && (
<td
className="text-start"
rowSpan={entry.products.length}
style={{ border: "1px solid" }}
>
<Link
to={`/sales/view/${entry.id}`}
state={{ product }}
>
<button
style={{
color: "white",
marginRight: "1rem",
}}
type="button"
className="btn btn-primary btn-sm waves-effect waves-light btn-table mx-1 mt-1"
>
View
</button>
</Link>
</td>
)}
</tr>
))
)
) : (
<tr className="text-center">
<td colSpan="10" style={{ border: "1px solid" }}>
<h5>No Data Available...</h5>
</td>
</tr>
)}
</tbody>
</table>
</div>
<div className="row mt-20">
<div className="col-sm-12 col-md-6 mb-20">
<div
className="dataTables_info"
id="datatable_info"
role="status"
aria-live="polite"
>
Showing {currentPage * itemPerPage - itemPerPage + 1} to{" "}
{Math.min(currentPage * itemPerPage, totalData)} of{" "}
{totalData} entries
</div>
</div>
<div className="col-sm-12 col-md-6">
<div className="d-flex">
<ul className="pagination ms-auto">
<li
className={
currentPage === 1
? "paginate_button page-item previous disabled"
: "paginate_button page-item previous"
}
>
<span
className="page-link"
style={{ cursor: "pointer" }}
onClick={() => setCurrentPage((prev) => prev - 1)}
disabled={loading}
>
Previous
</span>
</li>
{!(currentPage - 1 < 1) && (
<li className="paginate_button page-item">
<span
className="page-link"
style={{ cursor: "pointer" }}
onClick={(e) =>
setCurrentPage((prev) => prev - 1)
}
disabled={loading}
>
{currentPage - 1}
</span>
</li>
)}
<li className="paginate_button page-item active">
<span
className="page-link"
style={{ cursor: "pointer" }}
>
{currentPage}
</span>
</li>
{!(
(currentPage + 1) * itemPerPage - itemPerPage >
totalData - 1
) && (
<li className="paginate_button page-item ">
<span
className="page-link"
style={{ cursor: "pointer" }}
onClick={() => {
setCurrentPage((prev) => prev + 1);
}}
disabled={loading}
>
{currentPage + 1}
</span>
</li>
)}
<li
className={
!(
(currentPage + 1) * itemPerPage - itemPerPage >
totalData - 1
)
? "paginate_button page-item next"
: "paginate_button page-item next disabled"
}
>
<span
className="page-link"
style={{ cursor: "pointer" }}
onClick={() => setCurrentPage((prev) => prev + 1)}
disabled={loading}
>
Next
</span>
</li>
</ul>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
);
};
export default Sales;

View File

@ -0,0 +1,178 @@
import React, { useState, useEffect } from "react";
import axios from "axios";
import {
Box,
Typography,
Grid,
Paper,
IconButton,
Table,
TableBody,
TableCell,
TableContainer,
TableHead,
TableRow,
Paper as MuiPaper,
} from "@mui/material";
import { useParams, useNavigate } from "react-router-dom";
import { isAutheticated } from "../../auth";
import CancelIcon from "@mui/icons-material/Cancel"; // Add this import
const SingleSales = () => {
const { id } = useParams();
const [SalesDetails, setSalesDetails] = useState(null);
const token = isAutheticated();
const navigate = useNavigate();
useEffect(() => {
const fetchData = async () => {
try {
const response = await axios.get(`/api/sales/${id}`, {
headers: {
"Access-Control-Allow-Origin": "*",
Authorization: `Bearer ${token}`,
"Content-Type": "application/json",
},
});
setSalesDetails(response.data);
// console.log("Inventory Details: ", response.data);
} catch (error) {
console.error("Error fetching data: ", error);
}
};
fetchData();
}, [id]);
const handleCancel = () => {
navigate("/inventory");
};
if (!SalesDetails) {
return <Typography>Loading...</Typography>;
}
return (
<Box sx={{ p: 3 }}>
<Box
sx={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
mb: 3,
}}
>
<Typography variant="h4">Sales Details</Typography>
<IconButton sx={{ color: "red" }} onClick={handleCancel}>
<CancelIcon />
</IconButton>
</Box>
<Paper sx={{ p: 2, mb: 3 }}>
<Typography variant="h5" gutterBottom>
Sales Data
</Typography>
<Grid container spacing={2}>
<Grid item xs={12}>
<Typography>
<strong>Timestamp:</strong>{" "}
{new Date(SalesDetails.createdAt).toLocaleString("en-IN", {
weekday: "short",
month: "short",
day: "numeric",
year: "numeric",
hour: "numeric",
minute: "numeric",
hour12: true,
})}
</Typography>
</Grid>
</Grid>
</Paper>
<Paper sx={{ p: 2, mb: 3 }}>
<Typography variant="h6" gutterBottom>
Product Details
</Typography>
<TableContainer component={MuiPaper}>
<Table>
<TableHead >
<TableRow>
<TableCell><strong>Product Name</strong></TableCell>
<TableCell><strong>SKU</strong></TableCell>
<TableCell><strong>QuantitySold</strong></TableCell>
<TableCell><strong>SalesAmount</strong></TableCell>
</TableRow>
</TableHead>
<TableBody>
{SalesDetails.products.map((product, index) => (
<TableRow key={index}>
<TableCell>{product.ProductName}</TableCell>
<TableCell>{product.SKU}</TableCell>
<TableCell>{product.QuantitySold}</TableCell>
<TableCell>{product.SalesAmount}</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</TableContainer>
</Paper>
<Paper sx={{ p: 2, mb: 3 }}>
<Typography variant="h6" gutterBottom>
Data Added For
</Typography>
<Grid container spacing={2}>
<Grid item xs={6}>
<Typography>
<strong>PD or RD:</strong>{" "}
{SalesDetails.addedFor}
</Typography>
<Typography>
<strong>Name:</strong> {SalesDetails.addedForData.name}
</Typography>
<Typography>
<strong>Mobile Number:</strong>{" "}
{SalesDetails.addedForData.phone || SalesDetails.addedForData.mobile_number}
</Typography>
<Typography>
<strong>Email:</strong> {SalesDetails.addedForData.email||'N/A'}
</Typography>
<Typography>
<strong>Trade Name:</strong>{" "}
{SalesDetails.addedForData.shippingAddress?.tradeName||SalesDetails.addedForData.kyc.trade_name}
</Typography>
</Grid>
</Grid>
</Paper>
<Paper sx={{ p: 2, mb: 3 }}>
<Typography variant="h6" gutterBottom>
Data Entered By
</Typography>
<Grid container spacing={2}>
<Grid item xs={6}>
<Typography>
<strong>Designation:</strong> {SalesDetails.userType}
</Typography>
<Typography>
<strong>Name:</strong> {SalesDetails.user?.name}
</Typography>
<Typography>
<strong>ID:</strong> {SalesDetails.user?.uniqueId}
</Typography>
<Typography>
<strong>Email:</strong> {SalesDetails.user?.email}
</Typography>
<Typography>
<strong>Mobile Number:</strong>{" "}
{SalesDetails.user?.mobileNumber}
</Typography>
</Grid>
</Grid>
</Paper>
</Box>
);
};
export default SingleSales;

View File

@ -0,0 +1,249 @@
import React, { useEffect, useState } from "react";
import swal from "sweetalert";
import ClipLoader from "react-spinners/ClipLoader";
import { Link } from "react-router-dom";
import axios from "axios";
import { isAutheticated } from "src/auth";
function MobileApp() {
const [loading, setLoading] = useState(false);
const [PDApp, setPDApp] = useState("");
const [RDApp, setRDApp] = useState("");
const [SCApp, setSCApp] = useState("");
const [TMApp, setTMApp] = useState("");
const [display, setDisplay] = useState(true);
const token = isAutheticated();
// urlcreated images
const [PDAppUrl, setPDAppUrl] = useState("");
const [RDAppUrl, setRDAppUrl] = useState("");
const [SCAppUrl, setSCAppUrl] = useState("");
const [TMAppUrl, setTMAppUrl] = useState("");
useEffect(() => {
async function getConfiguration() {
const configDetails = await axios.get(`/api/config`, {
headers: {
Authorization: `Bearer ${token}`,
},
});
// console.log(configDetails.data.result[0]?.logo[0]);
const data = configDetails.data.result[0]?.logo[0];
setPDApp(data?.PDApp);
setRDApp(data?.RDApp);
setSCApp(data?.SCApp);
setTMApp(data?.TMApp);
}
getConfiguration();
}, []);
async function handelSubmit() {
setLoading(true);
const formdata = new FormData();
formdata.append("PDApp", PDApp);
formdata.append("RDApp", RDApp);
formdata.append("SCApp", SCApp);
formdata.append("TMApp", TMApp);
await axios
.post(`/api/config/logo`, formdata, {
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "multipart/formdata",
"Access-Control-Allow-Origin": "*",
},
})
.then((res) => {
setLoading(false);
swal("Success!", res.data.message, res.data.status);
})
.catch((error) => {
setLoading(false);
});
}
return (
<div>
<div className="main-content">
<div className="page-content">
<div className="container-fluid">
<div className="row">
<div className="col-lg-12">
<div className="card">
<div className="card-body">
<div className="row">
<div className="col-md-12 col-lg-6 col-xl-6">
<h1 className="text-left head-small">Mobile App</h1>
<form>
<div className="row">
<div className="col-lg-12">
<div className="form-group">
<>
<label
htmlFor="basicpill-phoneno-input"
className="label-100 mt-3"
style={{ fontWeight: "bold" }}
>
Header Logo for user Website(250 x 100
pixels) <br />
</label>
<div>
<input
type="file"
name="Logo htmlFor Website Header(148 x 48 px)"
onChange={(e) => {
setPDApp(e.target.files[0]);
if (
e.target.files &&
e.target.files[0]
) {
setPDAppUrl({
image: URL.createObjectURL(
e.target.files[0]
),
});
console.log(setPDAppUrl);
}
}}
className="form-control input-field mb-3 col-md-6 d-inline-block"
id="basicpill-phoneno-input"
/>
{display ? (
<img
className="ms-1"
style={{ width: "100px" }}
src={
PDAppUrl.image
? PDAppUrl.image
: PDApp
}
alt=""
/>
) : (
""
)}
</div>
<label
htmlFor="basicpill-phoneno-input"
className="label-100 mt-3"
style={{ fontWeight: "bold" }}
>
{/* Logo htmlFor Website Footer(148 x 48 px) */}
Footer logo for user Website(250 x 100
pixels) <br />
</label>
<br />
<input
type="file"
name="Logo htmlFor Website Footer(148 x 48 px)"
onChange={(e) => {
setRDApp(e.target.files[0]);
if (e.target.files && e.target.files[0]) {
setRDAppUrl({
image: URL.createObjectURL(
e.target.files[0]
),
});
}
}}
className="form-control input-field mt-1 col-md-6 d-inline-block"
id="basicpill-phoneno-input"
/>{" "}
{display ? (
<img
style={{ width: "100px" }}
src={
RDAppUrl.image
? RDAppUrl.image
: RDApp
}
alt=""
/>
) : (
""
)}
<label
htmlFor="basicpill-phoneno-input"
className="label-100 mt-2 row ms-1"
style={{ fontWeight: "bold" }}
>
{/* Logo htmlFor Admin Header(148 x 48 px) */}
Logo for admin website(250 x 100 pixels){" "}
<br />
</label>
<input
type="file"
name="Logo htmlFor Admin Header(148 x 48 px)"
onChange={(e) => {
setSCApp(e.target.files[0]);
if (e.target.files && e.target.files[0]) {
setSCAppUrl({
image: URL.createObjectURL(
e.target.files[0]
),
});
}
}}
className="form-control input-field col-md-6 d-inline-block"
id="basicpill-phoneno-input"
/>{" "}
{display ? (
<img
style={{ width: "100px" }}
src={
SCAppUrl.image
? SCAppUrl.image
: SCApp
}
alt=""
/>
) : (
""
)}
</>
</div>
</div>
</div>
<div className="row">
<div className="col-lg-12">
<div className="form-group text-left">
<button
type="button"
disabled={
SCApp === "" ||
RDApp === "" ||
PDApp === ""
}
onClick={handelSubmit}
className="btn btn-success btn-login waves-effect waves-light mr-3 pt-2 pb-2 pr-4 pl-4"
>
<ClipLoader loading={loading} size={18} />
{!loading && "Save"}
</button>
</div>
</div>
</div>
</form>
</div>
</div>
{/* <!-- end table-responsive --> */}
</div>
</div>
</div>
</div>
</div>
{/* <!-- container-fluid --> */}
</div>
{/* <!-- End Page-content --> */}
</div>
</div>
);
}
export default MobileApp;