537 lines
17 KiB
JavaScript
537 lines
17 KiB
JavaScript
import React, { useEffect, useState } from "react";
|
|
import Button from "@material-ui/core/Button";
|
|
import { Link, useNavigate } from "react-router-dom";
|
|
import swal from "sweetalert";
|
|
import axios from "axios";
|
|
import { isAutheticated } from "src/auth";
|
|
import CloudUploadIcon from "@mui/icons-material/CloudUpload";
|
|
import DeleteSharpIcon from "@mui/icons-material/DeleteSharp";
|
|
import {
|
|
Box,
|
|
FormControl,
|
|
IconButton,
|
|
MenuItem,
|
|
Select,
|
|
TextField,
|
|
} from "@mui/material";
|
|
// import { WebsiteURL } from '../WebsiteURL'
|
|
|
|
const AddProduct = () => {
|
|
const token = isAutheticated();
|
|
const navigate = useNavigate();
|
|
|
|
const [loading, setLoading] = useState(false);
|
|
const [allTax, setAllTax] = useState([]);
|
|
const [categories, setCategoies] = useState([]);
|
|
|
|
const [imagesPreview, setImagesPreview] = useState([]);
|
|
// const [allimage, setAllImage] = useState([]);
|
|
const [name, setName] = useState("");
|
|
const [description, setDescription] = useState("");
|
|
const [productImages, setProductImages] = useState([]);
|
|
const [price, setPrice] = useState(0);
|
|
const [category, setCategoryName] = useState("");
|
|
const [error, setError] = useState("");
|
|
const [selectedTax, setselectedTax] = useState();
|
|
const [totalAmt, setTotalAmt] = useState(0);
|
|
const [gst_amount, setGst_amount] = useState(0);
|
|
|
|
const handleFileChange = (e) => {
|
|
const files = e.target.files;
|
|
|
|
// Check the total number of selected files
|
|
if (productImages.length + files.length > 4) {
|
|
setError("You can only upload up to 4 images.");
|
|
return;
|
|
}
|
|
|
|
// Check file types and append to selectedFiles
|
|
const allowedTypes = ["image/jpeg", "image/png", "image/jpg"];
|
|
const selected = [];
|
|
|
|
for (let i = 0; i < files.length; i++) {
|
|
if (productImages.length + selected.length >= 4) {
|
|
break; // Don't allow more than 4 images
|
|
}
|
|
|
|
if (allowedTypes.includes(files[i].type)) {
|
|
selected.push(files[i]);
|
|
}
|
|
}
|
|
|
|
if (selected.length === 0) {
|
|
setError("Please upload only PNG, JPEG, or JPG files.");
|
|
} else {
|
|
setError("");
|
|
setProductImages([...productImages, ...selected]);
|
|
}
|
|
};
|
|
|
|
const handelDelete = (image) => {
|
|
const filtered = productImages.filter((item) => item !== image);
|
|
setProductImages(filtered);
|
|
};
|
|
// get All categories
|
|
const getCategories = async () => {
|
|
try {
|
|
const response = await axios.get("/api/category/getCategories", {
|
|
headers: {
|
|
Authorization: `Bearer ${token}`,
|
|
},
|
|
});
|
|
|
|
if (response.status === 200) {
|
|
setCategoies(response?.data?.categories);
|
|
}
|
|
} catch (error) {
|
|
swal({
|
|
title: error,
|
|
text: " please login to access the resource ",
|
|
icon: "error",
|
|
button: "Retry",
|
|
dangerMode: true,
|
|
});
|
|
}
|
|
};
|
|
// Get all tax
|
|
const getAllTax = async () => {
|
|
const res = await axios.get(`/api/tax/view_tax`, {
|
|
headers: {
|
|
"Access-Control-Allow-Origin": "*",
|
|
Authorization: `Bearer ${token}`,
|
|
},
|
|
});
|
|
if (res.data) {
|
|
setAllTax(res.data);
|
|
}
|
|
};
|
|
useEffect(() => {
|
|
getAllTax();
|
|
getCategories();
|
|
}, [token]);
|
|
const TaxRatechange = async (e) => {
|
|
let m = JSON.parse(e.target.value);
|
|
if (m?.tax) {
|
|
let totalprice = Number(price) + Number((price * m?.tax) / 100);
|
|
setGst_amount(Number((price * m?.tax) / 100)?.toFixed(2));
|
|
setTotalAmt(totalprice?.toFixed(2));
|
|
setselectedTax(m?._id);
|
|
}
|
|
};
|
|
|
|
const handleSubmit = () => {
|
|
if (
|
|
name === "" ||
|
|
description === "" ||
|
|
productImages.length == 0 ||
|
|
category === "" ||
|
|
selectedTax === "" ||
|
|
gst_amount === "" ||
|
|
price === ""
|
|
) {
|
|
swal({
|
|
title: "Warning",
|
|
text: "Fill all mandatory fields",
|
|
icon: "error",
|
|
button: "Close",
|
|
dangerMode: true,
|
|
});
|
|
return;
|
|
}
|
|
setLoading(true);
|
|
const formData = new FormData();
|
|
formData.append("name", name);
|
|
|
|
formData.append("description", description);
|
|
formData.append("price", price);
|
|
formData.append("category", category);
|
|
formData.append("total_amount", totalAmt);
|
|
formData.append("gst_amount", gst_amount);
|
|
|
|
formData.append("gst", selectedTax);
|
|
|
|
productImages.forEach((Singleimage) => {
|
|
// console.log(Singleimage)
|
|
formData.append("image", Singleimage);
|
|
});
|
|
|
|
axios
|
|
.post(`/api/product/create/`, formData, {
|
|
headers: {
|
|
Authorization: `Bearer ${token}`,
|
|
"Content-Type": "multipart/formdata",
|
|
"Access-Control-Allow-Origin": "*",
|
|
},
|
|
})
|
|
.then((res) => {
|
|
swal({
|
|
title: "Added",
|
|
text: "Product added successfully!",
|
|
icon: "success",
|
|
button: "ok",
|
|
});
|
|
setLoading(false);
|
|
navigate("/products", { replace: true });
|
|
})
|
|
.catch((err) => {
|
|
setLoading(false);
|
|
const message = err.response?.data?.message
|
|
? err.response?.data?.message
|
|
: "Something went wrong!";
|
|
swal({
|
|
title: "Warning",
|
|
text: message,
|
|
icon: "error",
|
|
button: "Retry",
|
|
dangerMode: true,
|
|
});
|
|
});
|
|
};
|
|
const handlePriceChange = (e) => {
|
|
const newPrice = e.target.value;
|
|
setPrice(newPrice);
|
|
const selectedTaxObj = allTax.find((t) => t._id === selectedTax);
|
|
|
|
if (selectedTaxObj && !isNaN(newPrice)) {
|
|
const gstAmount = (newPrice * selectedTaxObj.tax) / 100;
|
|
const totalAmount = Number(newPrice) + gstAmount;
|
|
|
|
setGst_amount(gstAmount.toFixed(2));
|
|
setTotalAmt(totalAmount.toFixed(2));
|
|
}
|
|
};
|
|
// console.log(data);
|
|
// console.log(productImages);
|
|
return (
|
|
<div className="container">
|
|
<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">
|
|
Add Product
|
|
</div>
|
|
<div style={{ display: "flex", gap: "1rem" }}>
|
|
<h4 className="mb-0"></h4>
|
|
</div>
|
|
|
|
<div className="page-title-right">
|
|
<Button
|
|
variant="contained"
|
|
color="primary"
|
|
style={{
|
|
fontWeight: "bold",
|
|
marginBottom: "1rem",
|
|
textTransform: "capitalize",
|
|
marginRight: "5px",
|
|
}}
|
|
onClick={() => handleSubmit()}
|
|
disabled={loading}
|
|
>
|
|
{loading ? "Loading" : "Save"}
|
|
</Button>
|
|
<Link to="/products">
|
|
<Button
|
|
variant="contained"
|
|
color="secondary"
|
|
style={{
|
|
fontWeight: "bold",
|
|
marginBottom: "1rem",
|
|
textTransform: "capitalize",
|
|
}}
|
|
>
|
|
Back
|
|
</Button>
|
|
</Link>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div className="row">
|
|
<div className="col-lg-6 col-md-6 col-sm-12 my-1">
|
|
<div className="card h-100">
|
|
<div className="card-body px-5">
|
|
<div className="mb-3">
|
|
<label htmlFor="title" className="form-label">
|
|
Product Name*
|
|
</label>
|
|
<input
|
|
type="text"
|
|
className="form-control"
|
|
id="name"
|
|
value={name}
|
|
maxLength={35}
|
|
onChange={(e) => setName(e.target.value)}
|
|
/>
|
|
{name ? (
|
|
<>
|
|
<small className="charLeft mt-4 fst-italic">
|
|
{35 - name.length} characters left
|
|
</small>
|
|
</>
|
|
) : (
|
|
<></>
|
|
)}{" "}
|
|
</div>
|
|
|
|
<div className="mb-3">
|
|
<label htmlFor="title" className="form-label">
|
|
Description*
|
|
</label>
|
|
<textarea
|
|
type="text"
|
|
className="form-control"
|
|
id="description"
|
|
value={description}
|
|
rows={8}
|
|
maxLength="400"
|
|
onChange={(e) => setDescription(e.target.value)}
|
|
/>
|
|
{description ? (
|
|
<>
|
|
<small className="charLeft mt-4 fst-italic">
|
|
{400 - description.length} characters left
|
|
</small>
|
|
</>
|
|
) : (
|
|
<></>
|
|
)}
|
|
</div>
|
|
|
|
<div className="mb-3">
|
|
<label htmlFor="image" className="form-label">
|
|
Product Image*
|
|
</label>
|
|
<Box>
|
|
<label htmlFor="upload-Image">
|
|
<TextField
|
|
style={{
|
|
display: "none",
|
|
width: "350px",
|
|
height: "350px",
|
|
borderRadius: "10%",
|
|
}}
|
|
fullWidth
|
|
id="upload-Image"
|
|
type="file"
|
|
accept=".jpg , .png ,.jpeg"
|
|
label="file"
|
|
multiple
|
|
variant="outlined"
|
|
onChange={(e) => handleFileChange(e)}
|
|
/>
|
|
<Box
|
|
style={{ borderRadius: "10%" }}
|
|
sx={{
|
|
margin: "1rem 0rem",
|
|
cursor: "pointer",
|
|
width: "140px",
|
|
height: "140px",
|
|
border: "2px solid grey",
|
|
// borderRadius: '50%',
|
|
|
|
"&:hover": {
|
|
background: "rgba(112,112,112,0.5)",
|
|
},
|
|
}}
|
|
>
|
|
<CloudUploadIcon
|
|
style={{
|
|
color: "grey",
|
|
margin: "auto",
|
|
fontSize: "5rem",
|
|
}}
|
|
fontSize="large"
|
|
/>
|
|
</Box>
|
|
</label>
|
|
</Box>
|
|
|
|
{error && <p style={{ color: "red" }}>{error}</p>}
|
|
<p className="pt-1 pl-2 text-secondary">
|
|
Upload jpg, jpeg and png only*
|
|
</p>
|
|
<Box style={{ display: "flex" }}>
|
|
{productImages &&
|
|
productImages.map((image, i) => (
|
|
<Box marginRight={"2rem"}>
|
|
<img
|
|
src={URL.createObjectURL(image)}
|
|
alt="profileImage"
|
|
style={{
|
|
width: 70,
|
|
height: 70,
|
|
|
|
marginBottom: "1rem",
|
|
}}
|
|
/>
|
|
<DeleteSharpIcon
|
|
onClick={() => handelDelete(image)}
|
|
fontSize="small"
|
|
sx={{
|
|
color: "white",
|
|
position: "absolute",
|
|
cursor: "pointer",
|
|
padding: "0.2rem",
|
|
background: "black",
|
|
borderRadius: "50%",
|
|
}}
|
|
/>
|
|
{/* </IconButton> */}
|
|
</Box>
|
|
))}
|
|
</Box>
|
|
</div>
|
|
<div>
|
|
<strong className="fs-6 fst-italic">
|
|
*You cannot upload more than 4 images !!
|
|
</strong>
|
|
</div>
|
|
|
|
<div id="createProductFormImage" className="w-25 d-flex">
|
|
{imagesPreview.map((image, index) => (
|
|
<img
|
|
className=" w-50 p-1 "
|
|
key={index}
|
|
src={image}
|
|
alt="Product Preview"
|
|
/>
|
|
))}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div className="col-lg-6 col-md-6 col-sm-12 my-1">
|
|
<div className="card h-100">
|
|
<div className="card-body px-5">
|
|
<div className="mb-3 me-3">
|
|
<label htmlFor="title" className="form-label">
|
|
Price(Rs)*
|
|
</label>
|
|
<input
|
|
type="number"
|
|
className="form-control"
|
|
id="price"
|
|
value={price}
|
|
onChange={(e) => handlePriceChange(e)}
|
|
/>
|
|
</div>
|
|
<div className="">
|
|
<label htmlFor="categorySelect">Select a Category *:</label>
|
|
<select
|
|
id="category"
|
|
className="form-control"
|
|
style={{ width: "100%" }}
|
|
value={category}
|
|
onChange={(e) => setCategoryName(e.target.value)}
|
|
>
|
|
<option value={""}>None</option>
|
|
{categories.map((category, index) => (
|
|
<option key={index} value={category?._id}>
|
|
{category.categoryName}
|
|
</option>
|
|
))}
|
|
</select>
|
|
{/* <FormControl fullWidth>
|
|
<Select
|
|
labelId="demo-simple-select-label"
|
|
id="demo-simple-select"
|
|
value={categoryName}
|
|
onChange={(e) => setCategoryName(e.target.value)}
|
|
>
|
|
<MenuItem
|
|
style={{
|
|
width: "100%",
|
|
display: "flex",
|
|
justifyContent: "left",
|
|
textAlign: "left",
|
|
padding: "0.5rem",
|
|
}}
|
|
value={""}
|
|
>
|
|
None
|
|
</MenuItem>
|
|
{categories.map((category, i) => (
|
|
<MenuItem
|
|
style={{
|
|
width: "100%",
|
|
display: "flex",
|
|
justifyContent: "left",
|
|
textAlign: "left",
|
|
padding: "0.5rem",
|
|
}}
|
|
key={i}
|
|
value={category.categoryName}
|
|
>
|
|
{category.categoryName}
|
|
</MenuItem>
|
|
))}
|
|
</Select>
|
|
</FormControl> */}
|
|
</div>
|
|
{allTax.length > 0 && (
|
|
<div className=" mb-3">
|
|
<label htmlFor="title" className="form-label">
|
|
GST*
|
|
</label>{" "}
|
|
<select
|
|
className="form-control"
|
|
name="gst"
|
|
id="gst"
|
|
onChange={(e) => TaxRatechange(e)}
|
|
>
|
|
<option value="">--Select--</option>
|
|
|
|
{allTax.map((t, i) => (
|
|
<option key={i} value={JSON.stringify(t)}>
|
|
{t.tax}% {t.name}
|
|
</option>
|
|
))}
|
|
</select>
|
|
</div>
|
|
)}
|
|
|
|
<div className="mb-3 me-3">
|
|
<label htmlFor="title" className="form-label">
|
|
GST Amount (Rs) *
|
|
</label>
|
|
<input
|
|
disabled
|
|
type="number"
|
|
name="gst_amount"
|
|
className="form-control"
|
|
id="gst_amount"
|
|
value={gst_amount}
|
|
// onChange={(e) => setPrice(e.target.value)}
|
|
/>
|
|
</div>
|
|
<div className="mb-3 me-3">
|
|
<label htmlFor="title" className="form-label">
|
|
Total Amount(Rs)*
|
|
</label>
|
|
<input
|
|
disabled
|
|
type="number"
|
|
name="total_amount"
|
|
className="form-control"
|
|
id="total_amount"
|
|
value={totalAmt}
|
|
// onChange={(e) => setPrice(e.target.value)}
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default AddProduct;
|