multiple data for product and principal distributor successfully

This commit is contained in:
Sibunnayak 2024-08-08 16:08:28 +05:30
parent 99a358a567
commit 7149c7cf4f
9 changed files with 364 additions and 175 deletions

View File

@ -194,6 +194,7 @@
import React, { Suspense, useEffect, useState } from "react";
import { HashRouter, Route, Routes } from "react-router-dom";
import { useSelector } from "react-redux";
import { Toaster } from "react-hot-toast";
import { isAutheticated } from "./auth";
import "./scss/style.scss";
import ProtectedRoute from "./components/ProtectedRoute";
@ -261,6 +262,7 @@ const App = () => {
/>
<Route path="*" name="Home" element={<DefaultLayout />} />
</Routes>
<Toaster />
</Suspense>
</HashRouter>
);

View File

@ -91,7 +91,7 @@ const _nav = [
},
{
component: CNavItem,
name: "retail Distributor",
name: "Retail Distributor",
icon: <CIcon icon={cilCompress} customClassName="nav-icon" />,
to: "/retail-distributor",
group: "RetailDistributor",

View File

@ -141,6 +141,8 @@ import SingleUserleave from "./views/Leaves/SingleUserLeave";
import LeaveTerritoryManager from "./views/Leaves/LeaveTerritoryManager";
import RetailDistributor from "./views/RetailDistributors/RetailDistributor";
import SingleRetailDistributor from "./views/RetailDistributors/SingleRetailDistributor";
import AddMultipleProduct from "./views/Products/AddMultipleProducts";
import AddMultiplePd from "./views/PrincipalDistributors/AddMultiplePD";
const routes = [
//dashboard
@ -171,6 +173,12 @@ const routes = [
element: AddProduct,
navName: "Product Management",
},
{
path: "/product/add/multiple",
name: "Add products",
element: AddMultipleProduct,
navName: "Product Management",
},
{
path: "/product/edit/:id",
name: "Edit products",
@ -353,6 +361,12 @@ const routes = [
element: addPrincipalDistributor,
navName: "PrincipalDistributor",
},
{
path: "/add-principal-distributor/multiple",
name: "PrincipalDistributor",
element: AddMultiplePd,
navName: "PrincipalDistributor",
},
//------------------ End customers Route-------------------------
// {

View File

@ -0,0 +1,141 @@
import React, { useState } from "react";
import axios from "axios";
import swal from "sweetalert";
import { isAutheticated } from "src/auth.js";
import { useNavigate } from "react-router-dom"; // Import useNavigate
import { toast } from "react-hot-toast";
const AddMultiplePd = () => {
const [file, setFile] = useState(null);
const [loading, setLoading] = useState(false);
const [errors, setErrors] = useState([]);
const navigate = useNavigate(); // Initialize useNavigate
const handleFileChange = (e) => {
const selectedFile = e.target.files[0];
if (
selectedFile &&
selectedFile.type ===
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
) {
setFile(selectedFile);
} else {
swal("Error", "Please upload a valid Excel file", "error");
setFile(null);
}
};
const handleSubmit = async () => {
if (!file) {
swal("Error", "No file selected", "error");
return;
}
setLoading(true);
setErrors([]);
const formData = new FormData();
formData.append('file', file);
try {
const token = isAutheticated();
const response = await axios.post('/api/v1/principaldistributor/upload', formData, {
headers: {
'Content-Type': 'multipart/form-data',
Authorization: `Bearer ${token}`,
},
});
const { data } = response;
if (data.errors && data.errors.length > 0) {
setErrors(data.errors);
swal({
title: "SpreadSheet Upload Successful",
text: "A few Principal Distributor have errors. Please fix them and upload again.",
icon: "warning",
button: "OK",
});
} else {
toast.success("Principal Distributor and Address Added Successfully");
navigate("/principal-distributor");
}
setFile(null); // Clear the file input
document.querySelector('input[type="file"]').value = ""; // Reset file input value
} catch (error) {
console.error("Upload error:", error);
swal("Error", `Failed to upload Principal Distributor: ${error.response?.data?.message || 'An unexpected error occurred'}`, "error");
} finally {
setLoading(false);
}
};
return (
<div className="container mt-4">
<div className="mb-6">
<button
onClick={() => navigate('/principal-distributor')}
className="btn btn-secondary"
>
Back
</button>
</div>
<h5 className="mb-6 mt-4">Add Multiple Principal Distributor</h5>
<div className="my-3">
<div className="row">
<div className="col-lg-9">
<input
type="file"
name="file"
className="form-control"
accept=".xlsx"
onChange={handleFileChange}
/>
</div>
<div className="col-lg-3">
<button
className="btn btn-primary"
onClick={handleSubmit}
disabled={loading}
>
{loading ? "Uploading..." : "Upload"}
</button>
</div>
</div>
<p className="pt-1 pl-2 text-secondary">Upload only .xlsx files*</p>
</div>
{errors.length > 0 && (
<div className="my-4">
<h6>Finding errors while adding the Principal Distributor.</h6>
<table className="table table-bordered">
<thead>
<tr>
<th>Principal Distributor Name</th>
<th>Email</th>
<th>Phone</th>
<th>Pan</th>
<th>GST</th>
<th>Message</th>
</tr>
</thead>
<tbody>
{errors.map((error, index) => (
<tr key={index}>
<td>{error.name || "N/A"}</td>
<td>{error.email || "N/A"}</td>
<td>{error.phone || "N/A"}</td>
<td>{error.panNumber || "N/A"}</td>
<td>{error.gstNumber || "N/A"}</td>
<td>{error.message}</td>
</tr>
))}
</tbody>
</table>
</div>
)}
</div>
);
};
export default AddMultiplePd;

View File

@ -10,7 +10,7 @@ import {
CircularProgress,
} from "@mui/material";
import { useNavigate } from "react-router-dom";
import toast from "react-hot-toast";
import { toast } from "react-hot-toast";
import axios from "axios";
import { isAutheticated } from "src/auth";
import { City, State } from "country-state-city";
@ -84,40 +84,6 @@ const AddPrincipalDistributor = () => {
setSelectedCity(newValue);
};
const generatePassword = (name, email) => {
// Combine name and email, and convert to lowercase
const combinedStr = (name + email).toLowerCase();
// Define character pools
const specialChars = "@#*";
const numbers = "0123456789";
const alphaLower = combinedStr.match(/[a-z]/g) || [];
const alphaUpper = combinedStr.match(/[A-Z]/g) || [];
// Ensure at least one character from each category
const specialChar = specialChars.charAt(Math.floor(Math.random() * specialChars.length));
const numberChar = numbers.charAt(Math.floor(Math.random() * numbers.length));
const lowerChar = alphaLower.length > 0 ? alphaLower[Math.floor(Math.random() * alphaLower.length)] : String.fromCharCode(Math.floor(Math.random() * 26) + 97);
const upperChar = alphaUpper.length > 0 ? alphaUpper[Math.floor(Math.random() * alphaUpper.length)] : String.fromCharCode(Math.floor(Math.random() * 26) + 65);
// Combine required characters
let passwordChars = [specialChar, numberChar, lowerChar, upperChar];
// Fill remaining positions with random characters from the combined string
const allChars = combinedStr + specialChars + numbers;
while (passwordChars.length < 8) {
passwordChars.push(allChars.charAt(Math.floor(Math.random() * allChars.length)));
}
// Shuffle characters to ensure randomness
passwordChars = passwordChars.sort(() => Math.random() - 0.5);
// Generate password of length 8
const password = passwordChars.slice(0, 8).join("");
return password;
};
const handleFormSubmit = async (e) => {
e.preventDefault();
try {
@ -135,18 +101,16 @@ const AddPrincipalDistributor = () => {
}
setLoading(true);
const generatedPassword = generatePassword(user.name, user.email);
// Attempt to register user
const userResponse = await axios.post("/api/v1/user/register", {
...user,
password: generatedPassword,
role:"principal-Distributor",
role: "principal-Distributor",
});
if (userResponse.status === 201 || userResponse.status === 200) {
const userId = userResponse.data.userId;
// console.log(userId);
// Add address details for the user
const addressResponse = await axios.post(
`/api/shipping/address/admin/new/${userId}`,
@ -170,12 +134,14 @@ const AddPrincipalDistributor = () => {
}
} catch (error) {
setLoading(false);
console.error("Error adding principal distributor and address:", error);
toast.error(error.response?.data?.message || "Something went wrong!");
if (error.response && error.response?.data) {
toast.error(error.response?.data.message || "Something went wrong!");
} else {
toast.error("Something went wrong!");
}
}
};
const handleCancel = () => {
navigate("/principal-distributor");
};

View File

@ -33,7 +33,7 @@ const OrderDetails = ({ _id, setLoading1 }) => {
useEffect(() => {
getOrders();
}, [_id]);
console.log(userOrder, "userOrder");
// console.log(userOrder, "userOrder");
// if (loading) {
// return <div>Loading...</div>;

View File

@ -136,17 +136,23 @@ const principalDistributor = () => {
<Button
variant="contained"
color="primary"
style={{
fontWeight: "bold",
marginBottom: "1rem",
textTransform: "capitalize",
}}
className="font-bold mb-2 capitalize mr-2"
onClick={() => {
navigate("/add-principal-distributor");
}}
>
Add Principal Distributor
</Button>
<Button
variant="contained"
color="primary"
className="font-bold mb-2 capitalize"
onClick={() =>
navigate("/add-principal-distributor/multiple", { replace: true })
}
>
Upload Spreadsheet
</Button>
</div>
</div>
</div>

View File

@ -0,0 +1,136 @@
import React, { useState } from "react";
import axios from "axios";
import swal from "sweetalert";
import { isAutheticated } from "src/auth.js";
import { useNavigate } from "react-router-dom"; // Import useNavigate
const AddMultipleProducts = () => {
const [file, setFile] = useState(null);
const [loading, setLoading] = useState(false);
const [errors, setErrors] = useState([]);
const navigate = useNavigate(); // Initialize useNavigate
const handleFileChange = (e) => {
const selectedFile = e.target.files[0];
if (
selectedFile &&
selectedFile.type ===
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
) {
setFile(selectedFile);
} else {
swal("Error", "Please upload a valid Excel file", "error");
setFile(null);
}
};
const handleSubmit = async () => {
if (!file) {
swal("Error", "No file selected", "error");
return;
}
setLoading(true);
setErrors([]);
const formData = new FormData();
formData.append('file', file);
try {
const token = isAutheticated();
const response = await axios.post('/api/products/upload', formData, {
headers: {
'Content-Type': 'multipart/form-data',
Authorization: `Bearer ${token}`,
},
});
const { data } = response;
if (data.errors && data.errors.length > 0) {
setErrors(data.errors);
swal({
title: "SpreadSheet Upload Successful",
text: "A few products have errors. Please fix them and upload again.",
icon: "warning",
button: "OK",
});
} else {
swal("Success", "Products added successfully", "success");
}
setFile(null); // Clear the file input
document.querySelector('input[type="file"]').value = ""; // Reset file input value
} catch (error) {
console.error("Upload error:", error);
swal("Error", `Failed to upload products: ${error.response?.data?.message || 'An unexpected error occurred'}`, "error");
} finally {
setLoading(false);
}
};
return (
<div className="container mt-4">
<div className="mb-6">
<button
onClick={() => navigate('/products')}
className="btn btn-secondary"
>
Back
</button>
</div>
<h5 className="mb-6 mt-4">Add Multiple Products</h5>
<div className="my-3">
<div className="row">
<div className="col-lg-9">
<input
type="file"
name="file"
className="form-control"
accept=".xlsx"
onChange={handleFileChange}
/>
</div>
<div className="col-lg-3">
<button
className="btn btn-primary"
onClick={handleSubmit}
disabled={loading}
>
{loading ? "Uploading..." : "Upload"}
</button>
</div>
</div>
<p className="pt-1 pl-2 text-secondary">Upload only .xlsx files*</p>
</div>
{errors.length > 0 && (
<div className="my-4">
<h6>Finding errors while adding the products.</h6>
<table className="table table-bordered">
<thead>
<tr>
<th>Product Name</th>
<th>Category</th>
<th>GST</th>
<th>Message</th>
</tr>
</thead>
<tbody>
{errors.map((error, index) => (
<tr key={index}>
<td>{error.productName || "N/A"}</td>
<td>{error.category || "N/A"}</td>
<td>{error.GST || "N/A"}</td>
<td>{error.message}</td>
</tr>
))}
</tbody>
</table>
</div>
)}
</div>
);
};
export default AddMultipleProducts;

View File

@ -1,10 +1,11 @@
import React, { useState, useEffect, useRef } from "react";
import React, { useState, useEffect, useRef, useCallback } from "react";
import { Link } from "react-router-dom";
import axios from "axios";
import Button from "@material-ui/core/Button";
import { useNavigate } from "react-router-dom";
import { isAutheticated } from "src/auth";
import swal from "sweetalert";
import debounce from "lodash.debounce";
const Products = () => {
const token = isAutheticated();
const navigate = useNavigate();
@ -15,51 +16,39 @@ const Products = () => {
const nameRef = useRef();
const categoryRef = useRef();
const FeatureProductRef = useRef();
const [currentPage, setCurrentPage] = useState(1);
const [itemPerPage, setItemPerPage] = useState(10);
const [totalData, setTotalData] = useState(0);
// const {
// edit,
// add,
// delete: deletepermission,
// } = checkPermission("Product Master");
const getProductsData = async () => {
setLoading(true);
await axios
.get(`/api/product/getAll/admin/`, {
try {
const response = await axios.get(`/api/product/getAll/admin/`, {
headers: {
Authorization: `Bearer ${token}`,
},
params: {
page: currentPage,
show: itemPerPage,
name: nameRef.current.value,
category: categoryRef.current.value,
FeatureProduct: FeatureProductRef.current.value,
name: nameRef.current?.value || "",
category: categoryRef.current?.value || "",
},
})
.then((res) => {
// console.log(res.data);
setProductsData(res.data?.products);
setTotalData(res.data?.total_data);
setLoading(false);
})
.catch((err) => {
const msg = err?.response?.data?.message || "Something went wrong!";
swal({
title: err,
text: msg,
icon: "error",
button: "Retry",
dangerMode: true,
});
setLoading(false);
});
setLoading(false);
setProductsData(response.data?.products || []);
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 getCatagories = () => {
@ -101,6 +90,18 @@ const Products = () => {
getProductsData();
}, [success, itemPerPage, currentPage]);
const debouncedSearch = useCallback(
debounce(() => {
setCurrentPage(1);
getProductsData();
}, 500),
[]
);
const handleSearchChange = () => {
debouncedSearch();
};
const handleDelete = (id) => {
swal({
title: "Are you sure?",
@ -142,47 +143,6 @@ const Products = () => {
}
});
};
const handleFeaturedProduct = (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/product/admin/feature_product/status/${id}`, {
headers: {
"Access-Control-Allow-Origin": "*",
Authorization: `Bearer ${token}`,
},
})
.then((res) => {
swal({
title: "Changed",
text: " Feature Product status changed successfully!",
icon: "success",
button: "ok",
});
setSuccess((prev) => !prev);
})
.catch((err) => {
let msg = err?.response?.data?.msg
? err?.response?.data?.msg
: "Something went wrong!";
swal({
title: "Warning",
text: msg,
icon: "warning",
button: "ok",
dangerMode: true,
});
});
}
});
};
const handleStatus = (id) => {
swal({
title: "Are you sure?",
@ -243,17 +203,21 @@ const Products = () => {
<Button
variant="contained"
color="primary"
style={{
fontWeight: "bold",
marginBottom: "1rem",
textTransform: "capitalize",
}}
onClick={() => {
navigate("/product/add", { replace: true });
}}
className="font-bold mb-2 capitalize mr-2"
onClick={() => navigate("/product/add", { replace: true })}
>
Add Product
</Button>
<Button
variant="contained"
color="primary"
className="font-bold mb-2 capitalize"
onClick={() =>
navigate("/product/add/multiple", { replace: true })
}
>
Upload Spreadsheet
</Button>
</div>
</div>
</div>
@ -292,6 +256,7 @@ const Products = () => {
placeholder="product name"
className="form-control"
ref={nameRef}
onChange={handleSearchChange}
disabled={loading}
/>
</div>
@ -300,6 +265,7 @@ const Products = () => {
<select
className="form-control"
ref={categoryRef}
onChange={handleSearchChange}
disabled={loading}
>
<option value="">All</option>
@ -310,30 +276,6 @@ const Products = () => {
))}
</select>
</div>
<div className="col-lg-3">
<label>Feature Product:</label>
<select
className="form-control"
ref={FeatureProductRef}
disabled={loading}
>
<option value="">----Select----</option>
<option value="true">YES</option>
<option value="false">NO</option>
</select>
</div>
<div className="col-lg-2">
<button
className="btn btn-primary ms-1 mt-4"
onClick={() => {
getProductsData();
setCurrentPage(1);
}}
disabled={loading}
>
{loading ? "Searching.." : "Filter"}
</button>
</div>
</div>
<div className="table-responsive table-shoot mt-3">
@ -349,7 +291,6 @@ const Products = () => {
<th className="text-start">Image</th>
<th className="text-start">Product</th>
<th className="text-start">Category</th>
<th className="text-start">Feature Product</th>
<th className="text-start">Price</th>
<th className="text-start">Status</th>
@ -397,23 +338,6 @@ const Products = () => {
? product.category?.categoryName
: "Category Not selected "}
</td>
<td className="text-center">
<span className=""></span>
<button
type="button"
className={`badge text-white ${
product?.featured_Product === true
? "text-bg-success"
: "text-bg-danger"
}`}
onClick={() => {
handleFeaturedProduct(product._id);
}}
>
{product?.featured_Product ? "YES" : "NO"}
</button>
</td>
<th className="text-start">
{currencyDetails?.CurrencySymbol}
{product?.price}