integration is done

This commit is contained in:
ROSHAN GARG 2024-11-02 11:58:00 +05:30
parent e9fe97e261
commit 6bce3a4083
5 changed files with 642 additions and 53 deletions

View File

@ -248,13 +248,13 @@ const _nav = [
group: "",
items: [
// {
// component: CNavItem,
// name: "Testimonials",
// icon: <CIcon icon={cilCompress} customClassName="nav-icon" />,
// to: "/testimonials",
// group: "Website Related",
// },
{
component: CNavItem,
name: "Transporter",
icon: <CIcon icon={cilCompress} customClassName="nav-icon" />,
to: "/transporter",
group: "Transporter",
},
// {
// component: CNavItem,

View File

@ -169,6 +169,7 @@ import DistributorOpeningInventory from "./views/PrincipalDistributors/OpeningIn
import UploadOpeningInventory from "./views/PrincipalDistributors/UploadOpeningInventory";
import OpeningInventoryReports from "./views/Reports/OpeningInventoryReports";
import StockReports from "./views/Reports/StockReports ";
import Transporter from "./views/Transporter/Transporter";
const routes = [
//dashboard
@ -930,6 +931,14 @@ const routes = [
element: EditEmployee,
navName: "Employees & Access",
},
// Transporter
{
path: "transporter",
name: "Transporter",
element: Transporter,
navName: "Employees & Access",
},
];
export default routes;

View File

@ -0,0 +1,537 @@
import React, { useState, useEffect, useRef, useCallback } from "react";
import axios from "axios";
import { isAutheticated } from "src/auth";
import {
Button,
Box,
IconButton,
Modal,
Pagination,
TextField,
Typography,
} from "@mui/material";
import CloseIcon from "@mui/icons-material/Close";
import { ClipLoader } from "react-spinners";
import swal from "sweetalert";
import { toast } from "react-hot-toast";
import debounce from "lodash.debounce";
const style = {
position: "absolute",
top: "50%",
left: "50%",
transform: "translate(-50%, -50%)",
width: 400,
bgcolor: "background.paper",
borderRadius: "0.5rem",
boxShadow: 24,
width: "500px",
};
const Transporter = () => {
const token = isAutheticated();
const nameRef = useRef();
const [loading, setLoading] = useState(true);
const [updating, setUpdating] = useState(true);
const [saveLoding, setSaveLoading] = useState(true);
const [edit, setEdit] = useState(false);
const [transporterName, settransporterName] = useState("");
const [categoryId, setCategoryId] = useState("");
const [transporter, setTransporter] = useState([]);
const [itemPerPage, setItemPerPage] = useState(10);
const [page, setPage] = useState(1);
const [open, setOpen] = useState(false);
const [oldertransporterName, setOlderCategoruName] = useState("");
const handleOpen = () => setOpen(true);
const handleClose = () => {
setOpen(false);
// setUpdating(false);
setEdit(false);
settransporterName("");
setCategoryId("");
};
const getCategories = async () => {
try {
setLoading(true);
const response = await axios.get("/api/transporter/get", {
headers: {
Authorization: `Bearer ${token}`,
}, // Include pagination and search
});
if (response.status === 200) {
setTransporter(response?.data?.transporters);
}
} catch (error) {
console.error("Failed to fetch brands:", error);
} finally {
setLoading(false); // Set loading to false after fetching
}
};
useEffect(() => {
getCategories();
}, []);
const handleEditClick = (_id, transporterName) => {
setOpen(true);
settransporterName(transporterName);
setCategoryId(_id);
setOlderCategoruName(transporterName);
setEdit(true);
// setUpdating(false);
};
const handleUpdate = async () => {
const filteredArrayNames = transporter
.filter(
(item) =>
item.transporterName.toLowerCase() !==
oldertransporterName.toLowerCase()
)
.map((item) => item.transporterName.toLowerCase());
// console.log(filteredArrayNames, "filter");
if (filteredArrayNames.includes(transporterName.toLowerCase())) {
swal({
title: "Warning",
text: "Transporter name already exists ",
icon: "error",
button: "Retry",
dangerMode: true,
});
}
if (!transporterName) {
swal({
title: "Warning",
text: "Please fill all the required fields!",
icon: "error",
button: "Retry",
dangerMode: true,
});
return;
}
setUpdating(false);
const formData = new FormData();
formData.append("transporterName", transporterName);
try {
await axios.patch(`/api/transporter/edit/${categoryId}`, formData, {
headers: {
Authorization: `Bearer ${token}`,
},
});
handleClose();
toast.success("Transporter updated successfully");
getCategories();
} catch (err) {
swal({
title: "",
text: "Something went wrong!",
icon: "error",
button: "Retry",
dangerMode: true,
});
} finally {
setUpdating(true);
}
};
const handleDelete = (_id) => {
swal({
title: "Are you sure?",
icon: "error",
buttons: {
Yes: { text: "Yes", value: true },
Cancel: { text: "Cancel", value: "cancel" },
},
}).then(async (value) => {
if (value === true) {
try {
await axios.delete(`/api/transporter/delete/${_id}`, {
headers: {
Authorization: `Bearer ${token}`,
},
});
toast.success("Transporter deleted successfully");
getCategories();
} catch (err) {
swal({
title: "",
text: "Something went wrong!",
icon: "error",
button: "Retry",
dangerMode: true,
});
}
}
});
};
const handleSaveCategory = async () => {
if (
transporter.some(
(item) =>
item.transporterName.toLowerCase() === transporterName.toLowerCase()
)
) {
swal({
title: "Warning",
text: "Category already exists ",
icon: "error",
button: "Retry",
dangerMode: true,
});
return;
}
if (!transporterName) {
swal({
title: "Warning",
text: "Please fill all the required fields!",
icon: "error",
button: "Retry",
dangerMode: true,
});
return;
}
setSaveLoading(false);
setLoading(true);
const formData = new FormData();
formData.append("transporterName", transporterName);
try {
await axios.post("/api/transporter/add", formData, {
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "multipart/formdata",
},
});
handleClose();
toast.success("Transpoter added successfully");
getCategories();
} catch (err) {
swal({
title: "",
text: "Something went wrong!",
icon: "error",
button: "Retry",
dangerMode: true,
});
} finally {
setSaveLoading(true);
}
};
const getPageCount = () => {
return Math.max(1, Math.ceil(transporter.length / itemPerPage));
};
const debouncedSearch = useCallback(
debounce(() => {
setPage(1);
getCategories();
}, 500),
[]
);
const handleSearchChange = () => {
debouncedSearch();
};
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">
Transporter
</div>
<div className="page-title-right">
<Button
variant="contained"
color="primary"
style={{
fontWeight: "bold",
marginBottom: "1rem",
textTransform: "capitalize",
}}
onClick={handleOpen}
>
Add New Transporter
</Button>
<Modal
open={open}
onClose={handleClose}
aria-labelledby="modal-modal-title"
aria-describedby="modal-modal-description"
>
<Box sx={style}>
<Box p={2} display={"flex"}>
<Typography
id="modal-modal-title"
variant="body"
component="h2"
flex={1}
>
Transporter name
</Typography>
<IconButton onClick={() => handleClose()}>
<CloseIcon />
</IconButton>
</Box>
<hr />
<TextField
placeholder="Transporter name"
value={transporterName}
fullWidth
inputProps={{
maxLength: 25,
}}
style={{
padding: "1rem",
}}
onChange={(e) =>
settransporterName(
e.target.value.charAt(0).toUpperCase() +
e.target.value.slice(1)
)
}
/>
{transporterName ? (
<>
<small className="charLeft mt-2 ml-3 fst-italic">
{25 - transporterName.length} characters left
</small>
</>
) : (
<></>
)}
<Box
p={2}
display={"flex"}
justifyContent={"right"}
// width={"500px"}
>
{!edit && (
<button
style={{
color: "white",
marginRight: "1rem",
}}
onClick={() => handleSaveCategory()}
type="button"
className="
btn btn-primary btn-sm
waves-effect waves-light
btn-table
mx-1
mt-1
"
>
<ClipLoader loading={!saveLoding} size={18} />
{saveLoding && "Save"}
</button>
)}
{edit && (
<button
style={{
color: "white",
marginRight: "1rem",
}}
onClick={() => handleUpdate()}
type="button"
className="
btn btn-primary btn-sm
waves-effect waves-light
btn-table
mx-1
mt-1
"
>
<ClipLoader loading={!updating} size={18} />
{updating && "update"}
</button>
)}
<button
style={{
color: "black",
marginRight: "1rem",
background: "grey",
}}
onClick={() => setOpen(false)}
type="button"
className="
btn btn-sm
waves-effect waves-light
btn-table
mx-1
mt-1
"
>
Close
</button>
</Box>
</Box>
</Modal>
</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);
setPage(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>Transporter Name:</label>
<input
type="text"
placeholder="Transporter name"
className="form-control"
ref={nameRef}
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" }}
>
<thead
className="thead-info"
style={{ background: "rgb(140, 213, 213)" }}
>
<tr>
<th> Transporter Name</th>
<th>Action</th>
</tr>
</thead>
<tbody>
{!loading && transporter.length === 0 && (
<tr className="text-center">
<td colSpan="2">
<h5>No Data Available</h5>
</td>
</tr>
)}
{loading ? (
<tr>
<td className="text-center" colSpan="6">
Loading...
</td>
</tr>
) : (
transporter &&
transporter
.slice(
(`${page}` - 1) * itemPerPage,
`${page}` * itemPerPage
)
.map((item, i) => (
<tr key={i}>
<td>
<h5>{item.transporterName} </h5>
</td>
<td className="text-start">
<button
style={{
color: "white",
marginRight: "1rem",
}}
type="button"
className="
btn btn-primary btn-sm
waves-effect waves-light
btn-table
mx-1
mt-1
"
onClick={() =>
handleEditClick(
item._id,
item.transporterName
)
}
>
Edit
</button>
<button
style={{
color: "white",
marginRight: "1rem",
background: "red",
}}
type="button"
className="
btn btn-sm
waves-effect waves-light
btn-table
mx-1
mt-1
"
onClick={() => handleDelete(item._id)}
>
Delete
</button>
</td>
</tr>
))
)}
</tbody>
</table>
</div>
<div style={{ display: "flex", justifyContent: "right" }}>
<Pagination
style={{ margin: "2rem" }}
variant="outlined"
size="large"
count={getPageCount()}
color="primary"
onChange={(event, value) => setPage(value)}
/>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
);
};
export default Transporter;

View File

@ -17,7 +17,10 @@ import {
DialogContentText,
DialogTitle,
TextField,
Divider, InputLabel, Select, MenuItem
Divider,
InputLabel,
Select,
MenuItem,
} from "@mui/material";
import onvoicesData from "../../assets/incoicedata.json";
import { useNavigate, useParams } from "react-router-dom";
@ -340,8 +343,8 @@ const ViewOrders = () => {
<TableRow key={index}>
<TableCell>
<img
src={item?.image}
// alt={item?.name}
src={item.productId.image}
alt={item.productId.name}
style={{
width: 50,
height: 50,
@ -349,15 +352,17 @@ const ViewOrders = () => {
}}
/>
<Typography variant="subtitle1">
{item?.name}
{item.productId.name}
</Typography>
</TableCell>
<TableCell align="right">{item.price.toFixed(2)}</TableCell>
<TableCell align="center">{item.quantity}</TableCell>
<TableCell align="right">{subtotal.toFixed(2)}</TableCell>
<TableCell align="right">{item.price}</TableCell>
<TableCell align="center">
{item.quantity}
</TableCell>
<TableCell align="right">{subtotal}</TableCell>
<TableCell align="right">{item.GST}%</TableCell>
<TableCell align="right">{gstAmount.toFixed(2)}</TableCell>
<TableCell align="right">{totalWithGST.toFixed(2)}</TableCell>
<TableCell align="right">{gstAmount}</TableCell>
<TableCell align="right">{totalWithGST}</TableCell>
</TableRow>
);
})}
@ -370,7 +375,8 @@ const ViewOrders = () => {
<>
{" "}
<Typography variant="h4" my={3} gutterBottom>
Order Items {order?.status=="pending"?"to be Processed":"Cancelled"}
Order Items{" "}
{order?.status == "pending" ? "to be Processed" : "Cancelled"}
</Typography>
<PendingOrderTable order={order} />
</>
@ -394,10 +400,10 @@ const ViewOrders = () => {
Total Items: {order?.orderItem.length}
</Typography>
<Typography>Total Subtotal: {order?.subtotal.toFixed(2)}</Typography>
<Typography>Total GST: {order?.gstTotal.toFixed(2)}</Typography>
<Typography>Total Subtotal: {order?.subtotal}</Typography>
<Typography>Total GST: {order?.gstTotal}</Typography>
<Typography variant="h5" sx={{ marginTop: 2 }}>
Grand Total: {order?.grandTotal.toFixed(2)}
Grand Total: {order?.grandTotal}
</Typography>
</Box>
</Grid>

View File

@ -19,6 +19,9 @@ import {
TextField,
Divider,
Chip,
InputLabel,
Select,
MenuItem,
} from "@mui/material";
import onvoicesData from "../../assets/incoicedata.json";
import { useNavigate, useParams } from "react-router-dom";
@ -58,7 +61,7 @@ const ViewInvoices = () => {
Authorization: `Bearer ${token}`,
},
});
// console.log(response);
console.log(response);
setInvoice(response.data);
setStatus(response.data.courierStatus);
@ -139,6 +142,31 @@ const ViewInvoices = () => {
setOpenDispatchDialog(false);
setOpenDeliveredDialog(false); // Close delivered dialog
};
const [transporterName, setTransporterName] = useState("");
const [transporter, setTransporter] = useState([]);
// Get order ID from URL params
const getCategories = async () => {
try {
setLoading(true);
const response = await axios.get("/api/transporter/get", {
headers: {
Authorization: `Bearer ${token}`,
}, // Include pagination and search
});
if (response.status === 200) {
setTransporter(response?.data?.transporters);
}
} catch (error) {
console.error("Failed to fetch brands:", error);
} finally {
setLoading(false); // Set loading to false after fetching
}
};
useEffect(() => {
getCategories();
}, []);
if (loading) {
return <Typography>Loading...</Typography>;
@ -188,27 +216,27 @@ const ViewInvoices = () => {
</TableRow>
</TableHead>
<TableBody>
<TableRow key={invoice.invoiceId}>
<TableCell>{invoice.invoiceId}</TableCell>
<TableRow key={invoice?.invoiceId}>
<TableCell>{invoice?.invoiceId}</TableCell>
<TableCell>
{invoice.items.map((item) => (
{invoice?.items?.map((item) => (
<div key={item.productId}>
{item.name} ({item.SKU}) x{" "}
<b>{item.processquantity}</b>
{item?.name} ({item?.SKU}) x{" "}
<b>{item?.processquantity}</b>
</div>
))}
</TableCell>
<TableCell>{invoice.subtotal.toFixed(2)}</TableCell>
<TableCell>{invoice.gstTotal.toFixed(2)}</TableCell>
<TableCell>{invoice.invoiceAmount.toFixed(2)}</TableCell>
<TableCell>{invoice?.subtotal.toFixed(2)}</TableCell>
<TableCell>{invoice?.gstTotal.toFixed(2)}</TableCell>
<TableCell>{invoice?.invoiceAmount.toFixed(2)}</TableCell>
<TableCell>
<Chip
label={invoice.courierStatus}
label={invoice?.courierStatus}
color={
invoice.courierStatus === "delivered"
invoice?.courierStatus === "delivered"
? "success"
: invoice.courierStatus === "dispatched"
: invoice?.courierStatus === "dispatched"
? "primary"
: "warning"
}
@ -293,7 +321,9 @@ const ViewInvoices = () => {
<Typography>Total Items: {invoice?.items.length}</Typography>
<Typography>Total Subtotal: {invoice?.subtotal}</Typography>
<Typography>Total GST: {invoice?.gstTotal}</Typography>
<Typography>
Total GST: {invoice?.gstTotal.toFixed(2)}
</Typography>
<Typography variant="h5" sx={{ marginTop: 2 }}>
Grand Total: {invoice?.invoiceAmount}
</Typography>
@ -431,28 +461,35 @@ const ViewInvoices = () => {
<form onSubmit={handleConfirmUpdate}>
<DialogContent>
<DialogContentText>
Please provide courier name and ID for dispatch:
Please provide the transporter name:
</DialogContentText>
<TextField
autoFocus
required
margin="dense"
label="Courier Name"
fullWidth
variant="outlined"
value={courierName}
onChange={(e) => setCourierName(e.target.value)}
/>
<TextField
required
margin="dense"
label="Courier ID"
fullWidth
variant="outlined"
value={couriertrackingId}
onChange={(e) => setCourierId(e.target.value)}
/>
<FormControl fullWidth variant="outlined" sx={{ mt: 2 }}>
<InputLabel id="courier-name-label">Transporter Name</InputLabel>
<Select
labelId="courier-name-label"
id="courier_name"
value={transporterName || ""}
onChange={(e) => setTransporterName(e.target.value)}
label="Transporter Name"
MenuProps={{
PaperProps: {
style: {
maxHeight: 200,
},
},
}}
>
<MenuItem value="">
<em>Select Transporter name </em>
</MenuItem>
{transporter?.map((option) => (
<MenuItem key={option._id} value={option.transporterName}>
{option.transporterName}
</MenuItem>
))}
</Select>
</FormControl>
</DialogContent>
<DialogActions>
<Button onClick={handleCancel} color="primary">