diff --git a/src/views/Brands/BrandModal.js b/src/views/Brands/BrandModal.js
new file mode 100644
index 0000000..91460fa
--- /dev/null
+++ b/src/views/Brands/BrandModal.js
@@ -0,0 +1,252 @@
+import React, { useState } from "react";
+import { Modal, Box, Typography, IconButton, TextField } from "@mui/material";
+import CloseIcon from "@mui/icons-material/Close";
+import { ClipLoader } from "react-spinners";
+import { isAutheticated } from "src/auth";
+import { toast } from "react-hot-toast";
+import axios from "axios";
+const style = {
+ position: "absolute",
+ top: "50%",
+ left: "50%",
+ transform: "translate(-50%, -50%)",
+ bgcolor: "background.paper",
+ borderRadius: "0.5rem",
+ boxShadow: 24,
+ width: "500px",
+};
+const BrandModal = ({
+ open,
+ setOpen,
+ brandName,
+ setBrandName,
+ edit,
+ handleSaveBrand,
+ handleUpdate,
+ saveLoading,
+ updating,
+ existingImage,
+ setExistingImage,
+ handleClose,
+ getBrands,
+}) => {
+ const [selectedImage, setSelectedImage] = useState(null);
+
+ const handleFileChange = (event) => {
+ const file = event.target.files[0];
+ if (file) {
+ setSelectedImage(file);
+ }
+ };
+ const handleDeleteImage = (url, public_id) => {
+ if (public_id) {
+ // Retrieve the authentication token
+ const token = isAutheticated(); // Ensure this function
+ const encodedPublicId = encodeURIComponent(public_id);
+ // console.log("public_id:", public_id); // Log to debug
+ // console.log("encodedPublicId:", encodedPublicId); // Log to debug
+ // Delete image from Cloudinary
+ axios
+ .delete(`/api/brand/deleteImage/${encodedPublicId}`, {
+ headers: {
+ Authorization: `Bearer ${token}`, // Include the token in the headers
+ },
+ })
+ .then(() => {
+ setExistingImage(null);
+ getBrands();
+ toast.success("Image deleted successfully");
+ })
+ .catch((err) => {
+ console.error(err.response?.data);
+ });
+ }
+ };
+ const handleRemoveImage = () => {
+ if (existingImage) {
+ handleDeleteImage(existingImage.url, existingImage.public_id);
+ } else {
+ setSelectedImage(null);
+ }
+ };
+ return (
+
+
+
+
+ Brand Name
+
+ {
+ handleClose();
+ setSelectedImage(null);
+ }}
+ >
+
+
+
+
+
+ setBrandName(
+ e.target.value.charAt(0).toUpperCase() + e.target.value.slice(1)
+ )
+ }
+ />
+ {brandName ? (
+ <>
+
+ {25 - brandName.length} characters left
+
+ >
+ ) : (
+ <>>
+ )}
+ {/* Image Upload Section */}
+
+ {existingImage ? (
+
+
+
+
+ ) : selectedImage ? (
+
+
+
+
+ ) : (
+
+ )}
+
+
+
+ {!edit && (
+
+ )}
+ {edit && (
+
+ )}
+
+
+
+
+ );
+};
+
+export default BrandModal;
diff --git a/src/views/Brands/Brands.js b/src/views/Brands/Brands.js
index dcfd0f3..8d8ff9e 100644
--- a/src/views/Brands/Brands.js
+++ b/src/views/Brands/Brands.js
@@ -15,24 +15,14 @@ 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",
-};
+import BrandModal from "./BrandModal";
const Brands = () => {
const token = isAutheticated();
const nameRef = useRef();
const [loading, setLoading] = useState(true);
- const [updating, setUpdating] = useState(true);
- const [saveLoading, setSaveLoading] = useState(true);
+ const [updating, setUpdating] = useState(false);
+ const [saveLoading, setSaveLoading] = useState(false);
const [edit, setEdit] = useState(false);
const [brandName, setBrandName] = useState("");
const [brandId, setBrandId] = useState("");
@@ -41,13 +31,19 @@ const Brands = () => {
const [page, setPage] = useState(1);
const [open, setOpen] = useState(false);
const [olderBrandName, setOlderBrandName] = useState("");
+ const [existingImage, setExistingImage] = useState(null);
+
+ const handleOpen = () => {
+ setOpen(true);
+ setBrandName("");
+ };
- const handleOpen = () => setOpen(true);
const handleClose = () => {
setOpen(false);
setEdit(false);
setBrandName("");
setBrandId("");
+ setExistingImage(null);
};
const getBrands = async () => {
@@ -72,17 +68,22 @@ const Brands = () => {
useEffect(() => {
getBrands();
- }, []);
+ }, []);
- const handleEditClick = (_id, brandName) => {
+ const handleEditClick = (_id, brandName, image) => {
setOpen(true);
setBrandName(brandName);
setBrandId(_id);
setOlderBrandName(brandName);
setEdit(true);
+ if (image?.length > 0) {
+ setExistingImage({ url: image[0].url, public_id: image[0].public_id });
+ }
};
- const handleUpdate = async () => {
+ const handleUpdate = async (brandName, image, callback) => {
+ setUpdating(true);
+
const filteredBrandNames = brands
.filter(
(brand) =>
@@ -92,29 +93,39 @@ const Brands = () => {
if (filteredBrandNames.includes(brandName.toLowerCase())) {
swal("Warning", "Brand already exists", "error");
+ setUpdating(false);
return;
}
if (!brandName) {
swal("Warning", "Please fill all the required fields!", "error");
+ setUpdating(false);
return;
}
- setUpdating(false);
const formData = new FormData();
formData.append("brandName", brandName);
+ if (image) {
+ formData.append("image", image); // Append image only if provided
+ }
+
try {
await axios.patch(`/api/brand/update/${brandId}`, formData, {
- headers: { Authorization: `Bearer ${token}` },
+ headers: {
+ Authorization: `Bearer ${token}`,
+ "Content-Type": "multipart/form-data", // Ensure proper form data handling
+ },
});
+
handleClose();
toast.success("Brand updated successfully");
getBrands();
} catch (err) {
swal("Error", "Failed to update brand", "error");
} finally {
- setUpdating(true);
+ setUpdating(false);
+ callback();
}
};
@@ -141,7 +152,7 @@ const Brands = () => {
});
};
- const handleSaveBrand = async () => {
+ const handleSaveBrand = async (brandName, image, callback) => {
if (
brands.some(
(brand) => brand.brandName.toLowerCase() === brandName.toLowerCase()
@@ -156,10 +167,15 @@ const Brands = () => {
return;
}
- setSaveLoading(false);
+ setSaveLoading(true); // Set loading state before API call
+
const formData = new FormData();
formData.append("brandName", brandName);
+ if (image) {
+ formData.append("image", image); // Append image if provided
+ }
+
try {
await axios.post("/api/brand/add", formData, {
headers: {
@@ -167,17 +183,20 @@ const Brands = () => {
"Content-Type": "multipart/form-data",
},
});
+
handleClose();
swal("Success", "New brand added successfully!", "success");
getBrands();
} catch (error) {
swal("Error", "Failed to add brand", "error");
} finally {
- setSaveLoading(true);
+ setSaveLoading(false); // Reset loading state after API call
+ callback();
}
};
- const getPageCount = () => Math.max(1, Math.ceil(brands?.length / itemPerPage));
+ const getPageCount = () =>
+ Math.max(1, Math.ceil(brands?.length / itemPerPage));
const debouncedSearch = useCallback(
debounce(() => {
setPage(1);
@@ -228,7 +247,7 @@ const Brands = () => {
>
Add New brand
- {
-
+ */}
+
@@ -397,8 +431,8 @@ const Brands = () => {
style={{ background: "rgb(140, 213, 213)" }}
>
+ Brand Image |
Brand Name |
-
Action |
@@ -419,56 +453,72 @@ const Brands = () => {
) : (
brands &&
brands
- .slice(
- (`${page}` - 1) * itemPerPage,
- `${page}` * itemPerPage
- )
- .map((item, i) => (
-
-
- {item.brandName}
- |
-
-
+ ) : (
+ "No Image Uploaded!"
+ )}
+ |
+
+ {item.brandName}
+ |
+
+
-
- |
-
- ))
+ onClick={() => handleDelete(item._id)}
+ >
+ Delete
+
+
+
+ ))
)}
diff --git a/src/views/Products/AddProduct.js b/src/views/Products/AddProduct.js
index 87569bc..49c0193 100644
--- a/src/views/Products/AddProduct.js
+++ b/src/views/Products/AddProduct.js
@@ -119,7 +119,7 @@ const AddProduct = () => {
-
+ {/*
@@ -142,7 +142,7 @@ const AddProduct = () => {
-
+ */}
);
diff --git a/src/views/Products/EditProduct.js b/src/views/Products/EditProduct.js
index ab56f36..6cd5d78 100644
--- a/src/views/Products/EditProduct.js
+++ b/src/views/Products/EditProduct.js
@@ -166,7 +166,7 @@ const EditProduct = () => {
-
+ {/*
@@ -197,7 +197,7 @@ const EditProduct = () => {
-
+ */}
);
diff --git a/src/views/Products/Products.js b/src/views/Products/Products.js
index 43ff905..4014b60 100644
--- a/src/views/Products/Products.js
+++ b/src/views/Products/Products.js
@@ -379,7 +379,7 @@ const Products = () => {
productsData?.map((product, i) => (
- {product?.image &&
+ {/* {product?.image &&
product?.image?.length !== 0 ? (
{
alt="preview"
style={{ borderRadius: "5px" }}
/>
- ) : (
+ ) */}
+ {product?.brand &&
+ product?.brand?.image?.length !== 0 ? (
+
+ )
+ : (
No
image
diff --git a/src/views/Products/ViewProduct.js b/src/views/Products/ViewProduct.js
index 74c01dd..02052d1 100644
--- a/src/views/Products/ViewProduct.js
+++ b/src/views/Products/ViewProduct.js
@@ -85,7 +85,7 @@ const ViewProduct = () => {
Images |
- {productData?.image &&
+ {/* {productData?.image &&
productData?.image?.length !== 0
? productData?.image.map((e, i) => (
{
alt="preview"
key={i}
/>
- ))
+ )) */}
+ {productData?.brand?.image && productData?.brand?.image?.length !==0 ? (
+
+ )
: "No Images Uploaded!"}
|
diff --git a/src/views/RetailDistributors/DistributorStock.js b/src/views/RetailDistributors/DistributorStock.js
index d6c60fa..11c9813 100644
--- a/src/views/RetailDistributors/DistributorStock.js
+++ b/src/views/RetailDistributors/DistributorStock.js
@@ -326,12 +326,13 @@ const DistributorStocks = () => {
return (
- {product?.image &&
- product?.image?.length !== 0 ? (
+ {product?.brandImage &&
+ product?.brandImage?.length !== 0 ? (
<>
>
| |