From 42d98be3d86cf12dd213b74d407b3891eac4c98d Mon Sep 17 00:00:00 2001 From: pawan-dot <71133473+pawan-dot@users.noreply.github.com> Date: Fri, 5 Apr 2024 17:38:48 +0530 Subject: [PATCH 1/3] product status and send mail if change status --- src/index.js | 2 +- src/views/Products/AddProduct.js | 20 ++++ src/views/Products/EditProduct.js | 22 +++- src/views/Products/ViewProduct.js | 4 + src/views/orders/CancelledOrders.js | 2 +- src/views/orders/DispatchedOrders.js | 2 +- src/views/orders/NewOrders.js | 2 +- src/views/orders/ProcessingOrders.js | 2 +- src/views/orders/ViewOrders.js | 150 ++++++++++++++++++++++++--- 9 files changed, 187 insertions(+), 19 deletions(-) diff --git a/src/index.js b/src/index.js index 3e4516a..466639c 100644 --- a/src/index.js +++ b/src/index.js @@ -14,7 +14,7 @@ import { cibGmail } from "@coreui/icons"; import { createRoot } from "react-dom/client"; const setupAxios = () => { - // axios.defaults.baseURL = "http://localhost:5000"; + //axios.defaults.baseURL = "http://localhost:5000"; axios.defaults.baseURL = "https://api.smellika.com"; axios.defaults.headers = { diff --git a/src/views/Products/AddProduct.js b/src/views/Products/AddProduct.js index 96270c5..aac06b3 100644 --- a/src/views/Products/AddProduct.js +++ b/src/views/Products/AddProduct.js @@ -33,6 +33,7 @@ const AddProduct = () => { const [category, setCategoryName] = useState(""); const [error, setError] = useState(""); const [selectedTax, setselectedTax] = useState(); + const [product_Status, setproduct_Status] = useState(""); const [totalAmt, setTotalAmt] = useState(0); const [gst_amount, setGst_amount] = useState(0); @@ -127,6 +128,7 @@ const AddProduct = () => { category === "" || selectedTax === "" || gst_amount === "" || + product_Status === "" || price === "" ) { swal({ @@ -147,6 +149,7 @@ const AddProduct = () => { formData.append("category", category); formData.append("total_amount", totalAmt); formData.append("gst_amount", gst_amount); + formData.append("product_Status", product_Status); formData.append("gst", selectedTax); @@ -525,6 +528,23 @@ const AddProduct = () => { // onChange={(e) => setPrice(e.target.value)} /> + +
+ {" "} + +
diff --git a/src/views/Products/EditProduct.js b/src/views/Products/EditProduct.js index f40f626..a407fb7 100644 --- a/src/views/Products/EditProduct.js +++ b/src/views/Products/EditProduct.js @@ -35,6 +35,8 @@ const EditProduct = () => { const [error, setError] = useState(""); const [initTax, setInitTax] = useState(); const [selectedTax, setselectedTax] = useState(); + const [product_Status, setproduct_Status] = useState(""); + const [totalAmt, setTotalAmt] = useState(0); const [gst_amount, setGst_amount] = useState(0); const [newUpdatedImages, setNewUpdatedImages] = useState([]); @@ -49,7 +51,6 @@ const EditProduct = () => { }, }) .then((res) => { - // console.log(res?.data?.product?.gst?._id); setName(res?.data?.product.name); setDescription(res.data.product.description); setProductImages(res.data.product.image); @@ -59,6 +60,7 @@ const EditProduct = () => { setInitTax(res.data.product?.gst?._id); setTotalAmt(res.data.product?.total_amount); setGst_amount(res.data.product?.gst_amount); + setproduct_Status(res.data.product?.product_Status); }) .catch((err) => { swal({ @@ -153,6 +155,7 @@ const EditProduct = () => { selectedTax === "" || gst_amount === "" || price === "" || + product_Status === "" || totalAmt === "" || gst_amount === "" || (productImages.length == 0 && newUpdatedImages.length == 0) @@ -175,6 +178,7 @@ const EditProduct = () => { formData.append("category", category); formData.append("total_amount", totalAmt); formData.append("gst_amount", gst_amount); + formData.append("product_Status", product_Status); formData.append("gst", initTax === "" ? selectedTax : initTax); @@ -583,6 +587,22 @@ const EditProduct = () => { // onChange={(e) => setPrice(e.target.value)} /> +
+ {" "} + +
diff --git a/src/views/Products/ViewProduct.js b/src/views/Products/ViewProduct.js index caabefe..de5ad60 100644 --- a/src/views/Products/ViewProduct.js +++ b/src/views/Products/ViewProduct.js @@ -135,6 +135,10 @@ function ViewProduct() { {/* Product Time{product?.time} Location{product?.location} */} + + Product Status + {product?.product_Status} + Created On diff --git a/src/views/orders/CancelledOrders.js b/src/views/orders/CancelledOrders.js index a44ea6e..81a9dd1 100644 --- a/src/views/orders/CancelledOrders.js +++ b/src/views/orders/CancelledOrders.js @@ -155,7 +155,7 @@ function CancelledOrders() { )} - + {order?.orderStatus} diff --git a/src/views/orders/DispatchedOrders.js b/src/views/orders/DispatchedOrders.js index be8f26d..c158e73 100644 --- a/src/views/orders/DispatchedOrders.js +++ b/src/views/orders/DispatchedOrders.js @@ -158,7 +158,7 @@ function DispatchedOrders() { )} - + {order?.orderStatus} diff --git a/src/views/orders/NewOrders.js b/src/views/orders/NewOrders.js index 11a4ae1..43c2621 100644 --- a/src/views/orders/NewOrders.js +++ b/src/views/orders/NewOrders.js @@ -210,7 +210,7 @@ function NewOrders() { )} - + {order?.orderStatus} diff --git a/src/views/orders/ProcessingOrders.js b/src/views/orders/ProcessingOrders.js index 19d9aeb..4c10d21 100644 --- a/src/views/orders/ProcessingOrders.js +++ b/src/views/orders/ProcessingOrders.js @@ -159,7 +159,7 @@ function ProcessingOrders() { )} - + {order?.orderStatus} diff --git a/src/views/orders/ViewOrders.js b/src/views/orders/ViewOrders.js index d7cbf6c..81a6f8a 100644 --- a/src/views/orders/ViewOrders.js +++ b/src/views/orders/ViewOrders.js @@ -171,6 +171,77 @@ function ViewOrders() { // swal.close(); // Close the popup if canceled // } }); + } else if (orderStatus === "cancelled") { + swal({ + title: `Are you sure for ${orderStatus}?`, + icon: "warning", + content: { + element: "div", + attributes: { + innerHTML: + '

Reson for cancellation.?

', + }, + }, + buttons: { + Yes: { text: "Submit", value: true }, + + Cancel: { text: "Cancel", value: "cancel" }, + }, + }).then((result) => { + if (result === true) { + // You have the input values, you can use them in your API call + const ReasonforCancellation = document + .getElementById("input1") + .value.trim(); + + // Check if values are entered + if (ReasonforCancellation === "") { + swal({ + title: "Warning", + text: "Please enter Reason for Cancellation", + icon: "warning", + button: "Ok", + dangerMode: true, + }); + } else { + axios + .patch( + `/api/order/change/status/${id}`, + { + status: orderStatus, + ReasonforCancellation, + }, + { + headers: { + "Access-Control-Allow-Origin": "*", + Authorization: `Bearer ${token}`, + }, + } + ) + .then((res) => { + console.log("status"); + toast.success( + `Order status change ${status} to ${orderStatus}` + ); + // setSuccess((prev) => !prev); + }) + .catch((err) => { + swal({ + title: "Warning", + text: err.response.data.message + ? err.response.data.message + : "Something went wrong!", + icon: "error", + button: "Retry", + dangerMode: true, + }); + }); + } + } + // else { + // swal.close(); // Close the popup if canceled + // } + }); } else if (orderStatus === "delivered") { swal({ title: `Are you sure for ${orderStatus}?`, @@ -451,9 +522,9 @@ function ViewOrders() {

- Total Price: ₹ + Subtotal: ₹ {productDetails?.quantity * - productDetails?.price} + productDetails?.total_Amount}

@@ -461,6 +532,10 @@ function ViewOrders() { Price: ₹ {productDetails?.price}

+

+ GST: ₹ + {productDetails?.gst_amount} +

@@ -629,9 +704,22 @@ function ViewOrders() {
-
- Order Status: {orderDetails?.orderStatus} -
+ {orderDetails?.orderStatus !== "cancelled" ? ( +
+ Order Status: {orderDetails?.orderStatus} +
+ ) : ( + <> +
+ Order Status: {orderDetails?.orderStatus} +
+

+ {" "} + Order Cancelled Reason:{" "} + {orderDetails?.order_Cancelled_Reason} +

+ + )} {/* order status change */}{" "}
{" "} @@ -712,7 +800,6 @@ function ViewOrders() {
*/}
- {orderDetails?.shipingInfo !== null && (
@@ -775,7 +862,39 @@ function ViewOrders() { )}
-
+
+ +
+ +
+ +
+
- -
+
From ab89359b8007d69ef68372f0166c9bfba92058fa Mon Sep 17 00:00:00 2001 From: syedmujahidahmed Date: Wed, 10 Apr 2024 17:05:37 +0530 Subject: [PATCH 2/3] added home page panels --- src/_nav.js | 7 + src/routes.js | 37 +++ src/views/Content/editPrivacyPolicy.js | 1 - src/views/Home/editPanel1.js | 403 ++++++++++++++++++++++++ src/views/Home/editPanel2.js | 409 +++++++++++++++++++++++++ src/views/Home/editPanel3.js | 407 ++++++++++++++++++++++++ src/views/Home/editPanel4.js | 409 +++++++++++++++++++++++++ src/views/Home/home.js | 165 ++++++++++ 8 files changed, 1837 insertions(+), 1 deletion(-) create mode 100644 src/views/Home/editPanel1.js create mode 100644 src/views/Home/editPanel2.js create mode 100644 src/views/Home/editPanel3.js create mode 100644 src/views/Home/editPanel4.js create mode 100644 src/views/Home/home.js diff --git a/src/_nav.js b/src/_nav.js index db9cefb..f5a8186 100644 --- a/src/_nav.js +++ b/src/_nav.js @@ -23,6 +23,7 @@ import { cilText, cilUser, cilAlarm, + cilFeaturedPlaylist, } from "@coreui/icons"; import { CNavGroup, CNavItem, CNavTitle, CTabContent } from "@coreui/react"; @@ -169,6 +170,12 @@ const _nav = [ icon: , to: "/content", }, + { + component: CNavItem, + name: "Home", + icon: , + to: "/home", + }, ], }, { diff --git a/src/routes.js b/src/routes.js index 80a1c1d..b097012 100644 --- a/src/routes.js +++ b/src/routes.js @@ -122,6 +122,11 @@ import CreateBlog from "./views/Blog/CreateBlog"; import users from "./views/Users/users"; import UpdateBlog from "./views/Blog/EditBlog"; import ViewBlog from "./views/Blog/ViewBlog"; +import Home from "./views/Home/home"; +import EditPanel1 from "./views/Home/editPanel1"; +import EditPanel2 from "./views/Home/editPanel2"; +import EditPanel3 from "./views/Home/editPanel3"; +import Editpanel4 from "./views/Home/editPanel4"; const routes = [ { path: "/", exact: true, name: "Home" }, { @@ -304,6 +309,38 @@ const routes = [ element: EditAboutUs, }, + // Home + { + path: "/home", + name: "Home", + element: Home, + }, + { + path: "/home/panel-1", + name: "EditPanel1", + element: EditPanel1, + }, + { + path: "/home/panel-2", + name: "EditPanel2", + element: EditPanel2, + }, + { + path: "/home/panel-3", + name: "EditPanel3", + element: EditPanel3, + }, + { + path: "/home/panel-4", + name: "EditPanel4", + element: Editpanel4, + }, + + + + + + // { path: '/complaint/view/:id', name: 'view Complain', element: ViewComplaint }, //Complaints { diff --git a/src/views/Content/editPrivacyPolicy.js b/src/views/Content/editPrivacyPolicy.js index 0bd944b..e6295e2 100644 --- a/src/views/Content/editPrivacyPolicy.js +++ b/src/views/Content/editPrivacyPolicy.js @@ -36,7 +36,6 @@ export default function EditPrivacyPolicy() { }); if (response.status === 200) { // console.log(response); - setContent(response?.data?.privacyAndPolicy[0]?.privacyAndPolicyContent); setId(response?.data?.privacyAndPolicy[0]?._id); setOlderContent( diff --git a/src/views/Home/editPanel1.js b/src/views/Home/editPanel1.js new file mode 100644 index 0000000..449f630 --- /dev/null +++ b/src/views/Home/editPanel1.js @@ -0,0 +1,403 @@ +import { useEffect, useState } from "react"; +import Button from "@material-ui/core/Button"; +import { Link } from "react-router-dom"; +import ReactQuill from "react-quill"; +import "react-quill/dist/quill.snow.css"; +import axios from "axios"; +import { isAutheticated } from "src/auth"; +const TOOLBAR_OPTIONS = [ + [{ header: [1, 2, 3, 4, 5, 6, false] }], + [{ font: [] }], + [{ list: "ordered" }, { list: "bullet" }], + ["bold", "italic", "underline", "strike"], + [{ color: [] }, { background: [] }], + [{ align: [] }], + [{ script: "super" }, { script: "sub" }], + ["undo", "redo"], +]; +import CloudUploadIcon from "@mui/icons-material/CloudUpload"; +import DeleteSharpIcon from "@mui/icons-material/DeleteSharp"; +import { + Box, + TextField, + Checkbox, + FormControlLabel +} from "@mui/material"; + +const EditPanel1 = () => { + const token = isAutheticated(); + const [loading, setLoading] = useState(false); + const [displayPanel, setDisplayPanel] = useState(false); + const [content, setContent] = useState(""); + const [olderContent, setOlderContent] = useState(""); + const [image, setimage] = useState(null); + const [title, setTitle] = useState(""); + const [error, setError] = useState(""); + const [newUpdatedImages, setNewUpdatedImages] = useState(null); + const [Img, setImg] = useState(true); + const [id, setId] = useState(null); + + const handleContentChange = (content, delta, source, editor) => { + setContent(editor.getHTML()); + }; + //get Blogdata + const getPanel = async () => { + try { + const res = await axios.get(`/api/panel/panel1/get`, { + headers: { + "Access-Control-Allow-Origin": "*", + Authorization: `Bearer ${token}`, + }, + }); + setTitle(res?.data?.panel1[0]?.title); + setimage(res?.data?.panel1[0]?.image); + setContent(res?.data?.panel1[0]?.content); + setOlderContent(res?.data?.panel1[0]?.content); + setDisplayPanel(res?.data?.panel1[0]?.displayPanel); + setId(res?.data?.panel1[0]?._id); + setImg(false); + } catch (err) { + swal({ + title: "Error", + text: "Unable to fetch the panel content", + icon: "error", + button: "Retry", + dangerMode: true, + }); + } + }; + + useEffect(() => { + getPanel(); + }, []); + + const handleFileChange = (e) => { + const files = e.target.files; + // Reset error state + setError(""); + + // Check if more than one image is selected + if (files.length > 1 || Img === false || newUpdatedImages !== null) { + setError("You can only upload one image."); + return; + } + + // Check file types and append to selectedFiles + const allowedTypes = ["image/jpeg", "image/png", "image/jpg"]; + const file = files[0]; // Only one file is selected, so we get the first one + + if (allowedTypes.includes(file.type)) { + setNewUpdatedImages(file); + setimage(file); + + } else { + setError("Please upload only PNG, JPEG, or JPG files."); + } + }; + + const handelDelete = async (public_id) => { + const ary = public_id.split("/"); + setNewUpdatedImages(null); + + const res = await axios.delete( + `/api/v1/blog/deleteImage/jatinMor/Blog/${ary[2]}`, + { + headers: { + "Access-Control-Allow-Origin": "*", + Authorization: `Bearer ${token}`, + }, + } + ); + if (res) { + setimage(null); + setImg(true); + } + }; + + + const addContent = async () => { + + const formData = new FormData(); + formData.append("title", title); + formData.append("content", content); + formData.append("displayPanel", displayPanel); + formData.append("image", image); + + + const response = await axios.post( + "/api/panel/panel1/add", + formData, + { + headers: { + Authorization: `Bearer ${token}`, + }, + } + ); + if (response.status == 201) { + swal({ + title: "Congratulations!!", + text: "Panel 1 added successfully!", + icon: "success", + button: "OK", + }); + } + }; + + const updateContent = () => { + if (title === "" || content === "") { + swal({ + title: "Warning", + text: "Fill all mandatory fields", + icon: "error", + button: "Close", + dangerMode: true, + }); + return; + } + setLoading(true); + + + const formData = new FormData(); + formData.append("title", title); + formData.append("content", content); + formData.append("displayPanel", displayPanel); + + if (newUpdatedImages !== null) { + formData.append("image", newUpdatedImages); + } + + axios + .patch(`/api/panel/panel1/update/${id}`, formData, { + headers: { + Authorization: `Bearer ${token}`, + "Content-Type": "multipart/form-data", + "Access-Control-Allow-Origin": "*", + }, + }) + .then((res) => { + swal({ + title: "Updated", + text: " Updated successfully!", + icon: "success", + button: "ok", + }); + setLoading(false); + }) + .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 handleSaveClick = async () => { + if (olderContent.length === 0) { + addContent(); + } else { + updateContent(); + } + // // Reload terms and conditions + // await getPrivacyPolicy(); + }; + + const handleChange = (event) => { + setDisplayPanel(event.target.checked); + }; + return ( +
+
+
+
+
+ Panel 1 +
+
+

+
+ +
+ + } + label="Display Panel" + /> + + + + + + +
+
+
+
+
+
+
+
+
+ + setTitle(e.target.value)} + /> +
+
+ + + + + {error &&

{error}

} +
+ + *You cannot upload more than 1 image + +
+ + + { image !== null ? ( + + Panel Image + handelDelete(image?.public_id)} + fontSize="small" + sx={{ + color: "white", + position: "absolute", + cursor: "pointer", + padding: "0.2rem", + background: "black", + borderRadius: "50%", + }} + /> + + ) : null} + + +
+
+
+
+
+
+
+ + +
+
+
+
+
+ ); +}; + +export default EditPanel1; diff --git a/src/views/Home/editPanel2.js b/src/views/Home/editPanel2.js new file mode 100644 index 0000000..1d5848e --- /dev/null +++ b/src/views/Home/editPanel2.js @@ -0,0 +1,409 @@ +import { useEffect, useState } from "react"; +import Button from "@material-ui/core/Button"; +import { Link } from "react-router-dom"; +import ReactQuill from "react-quill"; +import "react-quill/dist/quill.snow.css"; +import axios from "axios"; +import { isAutheticated } from "src/auth"; +const TOOLBAR_OPTIONS = [ + [{ header: [1, 2, 3, 4, 5, 6, false] }], + [{ font: [] }], + [{ list: "ordered" }, { list: "bullet" }], + ["bold", "italic", "underline", "strike"], + [{ color: [] }, { background: [] }], + [{ align: [] }], + [{ script: "super" }, { script: "sub" }], + ["undo", "redo"], +]; +import CloudUploadIcon from "@mui/icons-material/CloudUpload"; +import DeleteSharpIcon from "@mui/icons-material/DeleteSharp"; +import { + Box, + TextField, + Checkbox, + FormControlLabel +} from "@mui/material"; + +const EditPanel2 = () => { + const token = isAutheticated(); + const [loading, setLoading] = useState(false); + const [displayPanel, setDisplayPanel] = useState(false); + const [content, setContent] = useState(""); + const [olderContent, setOlderContent] = useState(""); + const [image, setimage] = useState(""); + const [title, setTitle] = useState(""); + const [error, setError] = useState(""); + const [newUpdatedImages, setNewUpdatedImages] = useState(null); + const [Img, setImg] = useState(true); + const [id, setId] = useState(null); + + const handleContentChange = (content, delta, source, editor) => { + setContent(editor.getHTML()); + }; + //get panel data + const getPanel = async () => { + try { + const res = await axios.get(`/api/panel/panel2/get`, { + headers: { + "Access-Control-Allow-Origin": "*", + Authorization: `Bearer ${token}`, + }, + }); + if (res?.status === 200) { + setTitle(res?.data?.panel2[0]?.title); + setimage(res?.data?.panel2[0]?.image); + setContent(res?.data?.panel2[0]?.content); + setOlderContent(res?.data?.panel2[0]?.content); + setDisplayPanel(res?.data?.panel2[0]?.displayPanel); + setId(res?.data?.panel2[0]?._id); + setImg(false); + + } + + } catch (err) { + console.error(err) + swal({ + title: "Error", + text: "Unable to fetch the panel content", + icon: "error", + button: "Retry", + dangerMode: true, + }); + } + }; + + useEffect(() => { + getPanel(); + }, []); + + const handleFileChange = (e) => { + const files = e.target.files; + // Reset error state + setError(""); + + // Check if more than one image is selected + if (files.length > 1 || newUpdatedImages !== null) { + setError("You can only upload one image."); + return; + } + + // Check file types and append to selectedFiles + const allowedTypes = ["image/jpeg", "image/png", "image/jpg"]; + const file = files[0]; // Only one file is selected, so we get the first one + + if (allowedTypes.includes(file.type)) { + setNewUpdatedImages(file); + setimage(file); + + } else { + setError("Please upload only PNG, JPEG, or JPG files."); + } + }; + + const handelDelete = async (public_id) => { + const ary = public_id.split("/"); + setNewUpdatedImages(null); + + const res = await axios.delete( + `/api/v1/blog/deleteImage/jatinMor/Blog/${ary[2]}`, + { + headers: { + "Access-Control-Allow-Origin": "*", + Authorization: `Bearer ${token}`, + }, + } + ); + if (res) { + setimage(null); + setImg(true); + } + }; + + + const addContent = async () => { + + const formData = new FormData(); + formData.append("title", title); + formData.append("content", content); + formData.append("displayPanel", displayPanel); + formData.append("image", image); + + + const response = await axios.post( + "/api/panel/panel2/add", + formData, + { + headers: { + Authorization: `Bearer ${token}`, + }, + } + ); + if (response.status == 201) { + swal({ + title: "Congratulations!!", + text: "Panel 2 added successfully!", + icon: "success", + button: "OK", + }); + } + }; + + const updateContent = () => { + if (title === "" || content === "") { + swal({ + title: "Warning", + text: "Fill all mandatory fields", + icon: "error", + button: "Close", + dangerMode: true, + }); + return; + } + setLoading(true); + + + const formData = new FormData(); + formData.append("title", title); + formData.append("content", content); + formData.append("displayPanel", displayPanel); + + if (newUpdatedImages !== null) { + formData.append("image", newUpdatedImages); + } + + axios + .patch(`/api/panel/panel2/update/${id}`, formData, { + headers: { + Authorization: `Bearer ${token}`, + "Content-Type": "multipart/form-data", + "Access-Control-Allow-Origin": "*", + }, + }) + .then((res) => { + swal({ + title: "Updated", + text: " Updated successfully!", + icon: "success", + button: "ok", + }); + setLoading(false); + }) + .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 handleSaveClick = async () => { + console.log(olderContent) + if (olderContent?.length === 0 || olderContent===undefined) { + addContent(); + } else { + updateContent(); + } + // // Reload terms and conditions + // await getPrivacyPolicy(); + }; + + const handleChange = (event) => { + setDisplayPanel(event.target.checked); + }; + return ( +
+
+
+
+
+ Panel 2 +
+
+

+
+ +
+ + } + label="Display Panel" + /> + + + + + + +
+
+
+
+
+
+
+
+
+ + setTitle(e.target.value)} + /> +
+
+ + + + + {error &&

{error}

} +
+ + *You cannot upload more than 1 image + +
+ + + {image && ( + + Panel Image + handelDelete(image?.public_id)} + fontSize="small" + sx={{ + color: "white", + position: "absolute", + cursor: "pointer", + padding: "0.2rem", + background: "black", + borderRadius: "50%", + }} + /> + + )} + + +
+
+
+
+
+
+
+ + +
+
+
+
+
+ ); +}; + +export default EditPanel2; diff --git a/src/views/Home/editPanel3.js b/src/views/Home/editPanel3.js new file mode 100644 index 0000000..3235e2e --- /dev/null +++ b/src/views/Home/editPanel3.js @@ -0,0 +1,407 @@ +import { useEffect, useState } from "react"; +import Button from "@material-ui/core/Button"; +import { Link } from "react-router-dom"; +import ReactQuill from "react-quill"; +import "react-quill/dist/quill.snow.css"; +import axios from "axios"; +import { isAutheticated } from "src/auth"; +const TOOLBAR_OPTIONS = [ + [{ header: [1, 2, 3, 4, 5, 6, false] }], + [{ font: [] }], + [{ list: "ordered" }, { list: "bullet" }], + ["bold", "italic", "underline", "strike"], + [{ color: [] }, { background: [] }], + [{ align: [] }], + [{ script: "super" }, { script: "sub" }], + ["undo", "redo"], +]; +import CloudUploadIcon from "@mui/icons-material/CloudUpload"; +import DeleteSharpIcon from "@mui/icons-material/DeleteSharp"; +import { + Box, + TextField, + Checkbox, + FormControlLabel +} from "@mui/material"; + +const EditPanel3 = () => { + const token = isAutheticated(); + const [loading, setLoading] = useState(false); + const [displayPanel, setDisplayPanel] = useState(false); + const [content, setContent] = useState(""); + const [olderContent, setOlderContent] = useState(""); + const [image, setimage] = useState(""); + const [title, setTitle] = useState(""); + const [error, setError] = useState(""); + const [newUpdatedImages, setNewUpdatedImages] = useState(null); + const [Img, setImg] = useState(true); + const [id, setId] = useState(null); + + const handleContentChange = (content, delta, source, editor) => { + setContent(editor.getHTML()); + }; + //get Blogdata + const getPanel = async () => { + try { + const res = await axios.get(`/api/panel/panel3/get`, { + headers: { + "Access-Control-Allow-Origin": "*", + Authorization: `Bearer ${token}`, + }, + }); + if (res?.status === 200) { + setTitle(res?.data?.panel3[0]?.title); + setimage(res?.data?.panel3[0]?.image); + setContent(res?.data?.panel3[0]?.content); + setOlderContent(res?.data?.panel3[0]?.content); + setDisplayPanel(res?.data?.panel3[0]?.displayPanel); + setId(res?.data?.panel3[0]?._id); + setImg(false); + + } + + } catch (err) { + console.error(err) + swal({ + title: "Error", + text: "Unable to fetch the panel content", + icon: "error", + button: "Retry", + dangerMode: true, + }); + } + }; + + useEffect(() => { + getPanel(); + }, []); + + const handleFileChange = (e) => { + const files = e.target.files; + // Reset error state + setError(""); + + // Check if more than one image is selected + if (files.length > 1 || Img === false || newUpdatedImages !== null) { + setError("You can only upload one image."); + return; + } + + // Check file types and append to selectedFiles + const allowedTypes = ["image/jpeg", "image/png", "image/jpg"]; + const file = files[0]; // Only one file is selected, so we get the first one + + if (allowedTypes.includes(file.type)) { + setNewUpdatedImages(file); + setimage(file); + + } else { + setError("Please upload only PNG, JPEG, or JPG files."); + } + }; + + const handelDelete = async (public_id) => { + const ary = public_id.split("/"); + setNewUpdatedImages(null); + + const res = await axios.delete( + `/api/v1/blog/deleteImage/jatinMor/Blog/${ary[2]}`, + { + headers: { + "Access-Control-Allow-Origin": "*", + Authorization: `Bearer ${token}`, + }, + } + ); + if (res) { + setimage(null); + setImg(true); + } + }; + + const addContent = async () => { + + const formData = new FormData(); + formData.append("title", title); + formData.append("content", content); + formData.append("displayPanel", displayPanel); + formData.append("image", image); + + + const response = await axios.post( + "/api/panel/panel3/add", + formData, + { + headers: { + Authorization: `Bearer ${token}`, + }, + } + ); + if (response.status == 201) { + swal({ + title: "Congratulations!!", + text: "Panel 3 added successfully!", + icon: "success", + button: "OK", + }); + } + }; + + const updateContent = () => { + if (title === "" || content === "") { + swal({ + title: "Warning", + text: "Fill all mandatory fields", + icon: "error", + button: "Close", + dangerMode: true, + }); + return; + } + setLoading(true); + + + const formData = new FormData(); + formData.append("title", title); + formData.append("content", content); + formData.append("displayPanel", displayPanel); + + if (newUpdatedImages !== null) { + formData.append("image", newUpdatedImages); + } + + axios + .patch(`/api/panel/panel3/update/${id}`, formData, { + headers: { + Authorization: `Bearer ${token}`, + "Content-Type": "multipart/form-data", + "Access-Control-Allow-Origin": "*", + }, + }) + .then((res) => { + swal({ + title: "Updated", + text: " Updated successfully!", + icon: "success", + button: "ok", + }); + setLoading(false); + }) + .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 handleSaveClick = async () => { + if (olderContent.length === 0) { + addContent(); + } else { + updateContent(); + } + // // Reload terms and conditions + // await getPrivacyPolicy(); + }; + + const handleChange = (event) => { + setDisplayPanel(event.target.checked); + }; + return ( +
+
+
+
+
+ Panel 3 +
+
+

+
+ +
+ + } + label="Display Panel" + /> + + + + + + +
+
+
+
+
+
+
+
+
+ + setTitle(e.target.value)} + /> +
+
+ + + + + {error &&

{error}

} +
+ + *You cannot upload more than 1 image + +
+ + + {image && ( + + Panel Image + handelDelete(image?.public_id)} + fontSize="small" + sx={{ + color: "white", + position: "absolute", + cursor: "pointer", + padding: "0.2rem", + background: "black", + borderRadius: "50%", + }} + /> + + )} + + +
+
+
+
+
+
+
+ + +
+
+
+
+
+ ); +}; + +export default EditPanel3; diff --git a/src/views/Home/editPanel4.js b/src/views/Home/editPanel4.js new file mode 100644 index 0000000..3410c72 --- /dev/null +++ b/src/views/Home/editPanel4.js @@ -0,0 +1,409 @@ +import { useEffect, useState } from "react"; +import Button from "@material-ui/core/Button"; +import { Link } from "react-router-dom"; +import ReactQuill from "react-quill"; +import "react-quill/dist/quill.snow.css"; +import axios from "axios"; +import { isAutheticated } from "src/auth"; +const TOOLBAR_OPTIONS = [ + [{ header: [1, 2, 3, 4, 5, 6, false] }], + [{ font: [] }], + [{ list: "ordered" }, { list: "bullet" }], + ["bold", "italic", "underline", "strike"], + [{ color: [] }, { background: [] }], + [{ align: [] }], + [{ script: "super" }, { script: "sub" }], + ["undo", "redo"], +]; +import CloudUploadIcon from "@mui/icons-material/CloudUpload"; +import DeleteSharpIcon from "@mui/icons-material/DeleteSharp"; +import { + Box, + TextField, + Checkbox, + FormControlLabel +} from "@mui/material"; + +const Editpanel4 = () => { + const token = isAutheticated(); + const [loading, setLoading] = useState(false); + const [displayPanel, setDisplayPanel] = useState(false); + const [content, setContent] = useState(""); + const [olderContent, setOlderContent] = useState(""); + const [image, setimage] = useState(""); + const [title, setTitle] = useState(""); + const [error, setError] = useState(""); + const [newUpdatedImages, setNewUpdatedImages] = useState(null); + const [Img, setImg] = useState(true); + const [id, setId] = useState(null); + + const handleContentChange = (content, delta, source, editor) => { + setContent(editor.getHTML()); + }; + //get Blogdata + const getPanel = async () => { + try { + const res = await axios.get(`/api/panel/panel4/get`, { + headers: { + "Access-Control-Allow-Origin": "*", + Authorization: `Bearer ${token}`, + }, + }); + if (res?.status === 200) { + setTitle(res?.data?.panel4[0]?.title); + if(res?.data?.panel4[0]?.image!==undefined && res?.data?.panel4[0]?.image!==null){ + setimage(res?.data?.panel4[0]?.image); + } + setContent(res?.data?.panel4[0]?.content); + setOlderContent(res?.data?.panel4[0]?.content); + setDisplayPanel(res?.data?.panel4[0]?.displayPanel); + setId(res?.data?.panel4[0]?._id); + setImg(false); + + } + + } catch (err) { + console.error(err) + swal({ + title: "Error", + text: "Unable to fetch the panel content", + icon: "error", + button: "Retry", + dangerMode: true, + }); + } + }; + + useEffect(() => { + getPanel(); + }, []); + + const handleFileChange = (e) => { + const files = e.target.files; + // Reset error state + setError(""); + + // Check if more than one image is selected + if (files.length > 1 || newUpdatedImages !== null) { + setError("You can only upload one image."); + return; + } + + // Check file types and append to selectedFiles + const allowedTypes = ["image/jpeg", "image/png", "image/jpg"]; + const file = files[0]; // Only one file is selected, so we get the first one + + if (allowedTypes.includes(file.type)) { + setNewUpdatedImages(file); + setimage(file); + + } else { + setError("Please upload only PNG, JPEG, or JPG files."); + } + }; + + const handelDelete = async (public_id) => { + const ary = public_id.split("/"); + setNewUpdatedImages(null); + + const res = await axios.delete( + `/api/v1/blog/deleteImage/jatinMor/Blog/${ary[2]}`, + { + headers: { + "Access-Control-Allow-Origin": "*", + Authorization: `Bearer ${token}`, + }, + } + ); + if (res) { + setimage(null); + setImg(true); + } + }; + + + const addContent = async () => { + + const formData = new FormData(); + formData.append("title", title); + formData.append("content", content); + formData.append("displayPanel", displayPanel); + formData.append("image", image); + + const response = await axios.post( + "/api/panel/panel4/add", + formData, + { + headers: { + Authorization: `Bearer ${token}`, + }, + } + ); + if (response.status == 201) { + swal({ + title: "Congratulations!!", + text: "Panel 4 added successfully!", + icon: "success", + button: "OK", + }); + } + }; + + const updateContent = () => { + if (title === "" || content === "") { + swal({ + title: "Warning", + text: "Fill all mandatory fields", + icon: "error", + button: "Close", + dangerMode: true, + }); + return; + } + setLoading(true); + + + const formData = new FormData(); + formData.append("title", title); + formData.append("content", content); + formData.append("displayPanel", displayPanel); + + if (newUpdatedImages !== null) { + formData.append("image", newUpdatedImages); + } + + axios + .patch(`/api/panel/panel4/update/${id}`, formData, { + headers: { + Authorization: `Bearer ${token}`, + "Content-Type": "multipart/form-data", + "Access-Control-Allow-Origin": "*", + }, + }) + .then((res) => { + swal({ + title: "Updated", + text: " Updated successfully!", + icon: "success", + button: "ok", + }); + setLoading(false); + }) + .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 handleSaveClick = async () => { + if (!olderContent) { + addContent(); + } else { + updateContent(); + } + // // Reload terms and conditions + // await getPrivacyPolicy(); + }; + + const handleChange = (event) => { + setDisplayPanel(event.target.checked); + }; + return ( +
+
+
+
+
+ Panel 4 +
+
+

+
+ +
+ + } + label="Display Panel" + /> + + + + + + +
+
+
+
+
+
+
+
+
+ + setTitle(e.target.value)} + /> +
+
+ + + + + {error &&

{error}

} +
+ + *You cannot upload more than 1 image + +
+ + + {image && ( + + Panel Image + handelDelete(image?.public_id)} + fontSize="small" + sx={{ + color: "white", + position: "absolute", + cursor: "pointer", + padding: "0.2rem", + background: "black", + borderRadius: "50%", + }} + /> + + )} + + +
+
+
+
+
+
+
+ + +
+
+
+
+
+ ); +}; + +export default Editpanel4; diff --git a/src/views/Home/home.js b/src/views/Home/home.js new file mode 100644 index 0000000..1562859 --- /dev/null +++ b/src/views/Home/home.js @@ -0,0 +1,165 @@ +import { + Paper, + Table, + TableBody, + TableCell, + TableContainer, + TableHead, + TableRow, + Typography, + } from "@mui/material"; +import axios from "axios"; +import React, { useEffect, useState } from "react"; +import { Link } from "react-router-dom"; +import { isAutheticated } from "src/auth"; + + export default function Home() { + const [displayPanel1,setDisplayPanel1] = useState("Not Displayed"); + const [displayPanel2,setDisplayPanel2] = useState("Not Displayed"); + const [displayPanel3,setDisplayPanel3] = useState("Not Displayed"); + const [displayPanel4,setDisplayPanel4] = useState("Not Displayed"); + const [loading, setLoading] = useState(false); + let token = isAutheticated(); + + async function getPanelStatus(){ + try { + setLoading(true) + let response1 = await axios.get('/api/panel/panel1/get', { + headers: { + "Access-Control-Allow-Origin": "*", + Authorization: `Bearer ${token}`, + } + }) + + let response2 = await axios.get('/api/panel/panel2/get', { + headers: { + "Access-Control-Allow-Origin": "*", + Authorization: `Bearer ${token}`, + } + }); + let response3 = await axios.get('/api/panel/panel3/get', { + headers: { + "Access-Control-Allow-Origin": "*", + Authorization: `Bearer ${token}`, + } + }); + let response4 = await axios.get('/api/panel/panel4/get', { + headers: { + "Access-Control-Allow-Origin": "*", + Authorization: `Bearer ${token}`, + } + }); + if(response1 && response2 && response3 && response4){ + if(response1?.data?.panel1[0]?.displayPanel){ + setDisplayPanel1("Displayed") + } + if(response2?.data?.panel2[0]?.displayPanel){ + setDisplayPanel2("Displayed"); + } + if(response3?.data?.panel3[0]?.displayPanel){ + setDisplayPanel3("Displayed"); + } + if(response4?.data?.panel4[0]?.displayPanel){ + setDisplayPanel4("Displayed"); + } + setLoading(false); + } + } catch (error) { + console.error(error); + } + } + useEffect(()=>{ + getPanelStatus() + },[]) + + const pages = [ + { + name: "Panel 1", + action: "Edit", + path: "/home/panel-1", + status:displayPanel1 + }, + { + name: "Panel 2", + action: "Edit", + path: "/home/panel-2", + status:displayPanel2 + }, + { + name: "Panel 3", + action: "Edit", + path: "/home/panel-3", + status:displayPanel3 + }, + { + name: "Panel 4", + action: "Edit", + path: "/home/panel-4", + status:displayPanel4 + }, + + ]; + + return ( +
+ + Home + + + + + + Page + + Display Status + + + Action + + + + + + {pages.map((row) => ( + + + {row.name} + + + {loading ? "loading" : `${row.status}`} + + + + {" "} + + + + + + + ))} + +
+
+
+ ); + } + \ No newline at end of file From 296df28cac4bdf757cbd1f4ae2f6f1fa21fe5523 Mon Sep 17 00:00:00 2001 From: Sibunnayak Date: Thu, 11 Apr 2024 11:24:52 +0530 Subject: [PATCH 3/3] Dynamic Chart Updated --- package.json | 3 + src/views/Charts/CityRevenue.js | 211 ++++++++++++++++++++++++--- src/views/Charts/OrderDaywise.js | 204 +++++++++++++++++++++++--- src/views/Charts/ProductRevenue.js | 222 ++++++++++++++++++++++++++--- src/views/Charts/RevenueCharts.js | 208 ++++++++++++++++++++++++--- src/views/Charts/Staterevenue.js | 211 ++++++++++++++++++++++++--- src/views/Charts/UserChart.js | 209 ++++++++++++++++++++++++--- 7 files changed, 1158 insertions(+), 110 deletions(-) diff --git a/package.json b/package.json index 0cee480..497456f 100644 --- a/package.json +++ b/package.json @@ -45,6 +45,7 @@ "@reduxjs/toolkit": "^1.9.2", "axios": "^0.25.0", "bootstrap": "^5.1.3", + "chart.js": "^4.4.2", "country-state-city": "^3.2.1", "draft-js": "^0.11.7", "draft-js-export-html": "^1.4.1", @@ -55,6 +56,7 @@ "quill": "^1.3.7", "react": "18.0.0", "react-bootstrap": "^2.7.0", + "react-chartjs-2": "^5.2.0", "react-datepicker": "^4.8.0", "react-dom": "^18.0.0", "react-draft-wysiwyg": "^1.15.0", @@ -66,6 +68,7 @@ "react-spinners": "^0.11.0", "react-tag-input-component": "^2.0.2", "react-to-print": "^2.14.11", + "recharts": "^2.12.4", "redux": "4.1.2", "serve": "^13.0.2", "simplebar-react": "^2.3.6", diff --git a/src/views/Charts/CityRevenue.js b/src/views/Charts/CityRevenue.js index 6cf4db2..27ea992 100644 --- a/src/views/Charts/CityRevenue.js +++ b/src/views/Charts/CityRevenue.js @@ -1,27 +1,200 @@ -import { isAutheticated } from "../../auth.js"; +import React, { useEffect, useState } from "react"; +import { isAutheticated } from "src/auth"; +import axios from "axios"; +import { Bar } from "react-chartjs-2"; +import { + Chart as ChartJS, + CategoryScale, + LinearScale, + BarElement, + Title, + Tooltip, + Legend, +} from "chart.js"; + +ChartJS.register( + CategoryScale, + LinearScale, + BarElement, + Title, + Tooltip, + Legend +); const CityRevenueCharts = () => { const token = isAutheticated(); + const [ordersData, setOrdersData] = useState([]); + const [filteredOrders, setFilteredOrders] = useState([]); + const [selectedYear, setSelectedYear] = useState(new Date().getFullYear()); + const [selectedMonth, setSelectedMonth] = useState(new Date().getMonth() + 1); + + useEffect(() => { + function getOrder() { + axios + .get(`/api/order/getAll/`, { + headers: { + "Access-Control-Allow-Origin": "*", + Authorization: `Bearer ${token}`, + }, + }) + .then((res) => { + setOrdersData(res.data.order); + // console.log(res.data.order); + }) + .catch((err) => { + console.log(err); + }); + } + getOrder(); + }, []); + + useEffect(() => { + // Filter orders based on selected year and month + const filtered = ordersData.filter((order) => { + const createdAt = new Date(order.createdAt); + return ( + createdAt.getFullYear() === selectedYear && + createdAt.getMonth() + 1 === selectedMonth + ); + }); + // Sort filtered orders by date in ascending order + filtered.sort((a, b) => { + const dateA = new Date(a.createdAt); + const dateB = new Date(b.createdAt); + return dateA - dateB; + }); + setFilteredOrders(filtered); + }, [ordersData, selectedYear, selectedMonth]); // Update filtered orders when orders data, year, or month changes + + const uniquecity = [ + ...new Set( + filteredOrders.map((item) => item.shippingInfo.city) + ), + ]; +// console.log(uniquecity); +// console.log(filteredOrders); + // Prepare data for chart + const data = { + labels: uniquecity, // Use unique product names as labels + datasets: [ + { + label: "Total Amount", + data: uniquecity.map((city) => { + // Sum total amounts for each date + return filteredOrders + .filter((order) => order.shippingInfo.city.includes(city)) + .reduce((total, order) => total + order.total_amount, 0); + }), + backgroundColor: "rgba(43, 63, 229, 0.8)", + borderRadius: 5, + }, + ], + }; + + const options = { + responsive: true, + plugins: { + legend: { + display: false, + }, + title: { + display: true, + text: "Revenue Chart", + }, + }, + scales: { + x: { + title: { + display: true, + text: "City", + }, + }, + y: { + beginAtZero: true, + title: { + display: true, + text: "Total Amount", + }, + ticks: { + stepSize: 1, // Adjust step size as needed + }, + }, + }, + }; + + // Convert month number to string + const monthToString = (monthNumber) => { + const months = [ + "January", + "February", + "March", + "April", + "May", + "June", + "July", + "August", + "September", + "October", + "November", + "December", + ]; + return months[monthNumber - 1]; + }; + + // Determine the lowest year found in the ordersData + const lowestYear = Math.min( + ...ordersData.map((order) => new Date(order.createdAt).getFullYear()) + ); + + // Generate an array of years from the lowest year to the current year + const years = Array.from( + { length: new Date().getFullYear() - lowestYear + 1 }, + (_, index) => lowestYear + index + ); return ( -
- {token ? ( - - ) : ( -

No charts available

- )} -
+ <> +
+
+ + +
+
+ + +
+
+
+ {filteredOrders.length === 0 ? ( +

No data available

+ ) : ( +
+ +
+ )} +
+ ); }; -export default CityRevenueCharts; \ No newline at end of file +export default CityRevenueCharts; diff --git a/src/views/Charts/OrderDaywise.js b/src/views/Charts/OrderDaywise.js index 08f4373..26b048c 100644 --- a/src/views/Charts/OrderDaywise.js +++ b/src/views/Charts/OrderDaywise.js @@ -1,26 +1,194 @@ -import { isAutheticated } from "../../auth.js"; +import React, { useEffect, useState } from "react"; +import { isAutheticated } from "src/auth"; +import axios from "axios"; +import { Bar } from "react-chartjs-2"; +import { + Chart as ChartJS, + CategoryScale, + LinearScale, + BarElement, + Title, + Tooltip, + Legend, +} from "chart.js"; + +ChartJS.register( + CategoryScale, + LinearScale, + BarElement, + Title, + Tooltip, + Legend +); const OrderdayChart = () => { const token = isAutheticated(); + const [ordersData, setOrdersData] = useState([]); + const [filteredOrders, setFilteredOrders] = useState([]); + const [selectedYear, setSelectedYear] = useState(new Date().getFullYear()); + const [selectedMonth, setSelectedMonth] = useState(new Date().getMonth() + 1); + + useEffect(() => { + function getOrder() { + axios + .get(`/api/order/getAll/`, { + headers: { + "Access-Control-Allow-Origin": "*", + Authorization: `Bearer ${token}`, + }, + }) + .then((res) => { + setOrdersData(res.data.order); + }) + .catch((err) => { + console.log(err); + }); + } + getOrder(); + }, [token]); + + useEffect(() => { + // Filter orders based on selected year and month + const filtered = ordersData.filter((order) => { + const createdAt = new Date(order.createdAt); + return ( + createdAt.getFullYear() === selectedYear && + createdAt.getMonth() + 1 === selectedMonth + ); + }); + // Sort filtered orders by date in ascending order + filtered.sort((a, b) => { + const dateA = new Date(a.createdAt); + const dateB = new Date(b.createdAt); + return dateA - dateB; + }); + setFilteredOrders(filtered); + }, [ordersData, selectedYear, selectedMonth]); // Update filtered orders when orders data, year, or month changes + + // Extract unique dates from filtered orders + const uniqueDates = Array.from( + new Set(filteredOrders.map((order) => order.createdAt.split("T")[0])) + ); + + // Prepare data for chart + const data = { + labels: uniqueDates, + datasets: [ + { + label: "Total Orders", + data: uniqueDates.map((date) => { + // Count total orders for each date + return filteredOrders.filter((order) => order.createdAt.includes(date)).length; + }), + backgroundColor: "rgba(43, 63, 229, 0.8)", + borderRadius: 5, + }, + ], + }; + + const options = { + responsive: true, + plugins: { + legend: { + display: false, + }, + title: { + display: true, + text: "Revenue Order", + }, + }, + scales: { + x: { + title: { + display: true, + text: "Date", + }, + }, + y: { + beginAtZero: true, + title: { + display: true, + text: "Orders", + }, + ticks: { + stepSize: 1, // Adjust step size as needed + }, + }, + }, + }; + + // Convert month number to string + const monthToString = (monthNumber) => { + const months = [ + "January", + "February", + "March", + "April", + "May", + "June", + "July", + "August", + "September", + "October", + "November", + "December", + ]; + return months[monthNumber - 1]; + }; + + // Determine the lowest year found in the ordersData + const lowestYear = Math.min( + ...ordersData.map((order) => new Date(order.createdAt).getFullYear()) + ); + + // Generate an array of years from the lowest year to the current year + const years = Array.from( + { length: new Date().getFullYear() - lowestYear + 1 }, + (_, index) => lowestYear + index + ); return ( -
- {token ? ( - - ) : ( -

No charts available

- )} -
+ <> +
+
+ + +
+
+ + +
+
+
+ {filteredOrders.length === 0 ? ( +

No data available

+ ) : ( +
+ +
+ )} +
+ ); }; diff --git a/src/views/Charts/ProductRevenue.js b/src/views/Charts/ProductRevenue.js index d6bb0c5..dcf8e0e 100644 --- a/src/views/Charts/ProductRevenue.js +++ b/src/views/Charts/ProductRevenue.js @@ -1,26 +1,212 @@ -import { isAutheticated } from "../../auth.js"; +import React, { useEffect, useState } from "react"; +import { isAutheticated } from "src/auth"; +import axios from "axios"; +import { Bar } from "react-chartjs-2"; +import { + Chart as ChartJS, + CategoryScale, + LinearScale, + BarElement, + Title, + Tooltip, + Legend, +} from "chart.js"; + +ChartJS.register( + CategoryScale, + LinearScale, + BarElement, + Title, + Tooltip, + Legend +); const ProductrevenueCharts = () => { const token = isAutheticated(); + const [ordersData, setOrdersData] = useState([]); + const [filteredOrders, setFilteredOrders] = useState([]); + const [selectedYear, setSelectedYear] = useState(new Date().getFullYear()); + const [selectedMonth, setSelectedMonth] = useState(new Date().getMonth() + 1); + + useEffect(() => { + function getOrder() { + axios + .get(`/api/order/getAll/`, { + headers: { + "Access-Control-Allow-Origin": "*", + Authorization: `Bearer ${token}`, + }, + }) + .then((res) => { + setOrdersData(res.data.order); + // console.log(res.data.order); + }) + .catch((err) => { + console.log(err); + }); + } + getOrder(); + }, []); + + useEffect(() => { + // Filter orders based on selected year and month + const filtered = ordersData.filter((order) => { + const createdAt = new Date(order.createdAt); + return ( + createdAt.getFullYear() === selectedYear && + createdAt.getMonth() + 1 === selectedMonth + ); + }); + // Sort filtered orders by date in ascending order + filtered.sort((a, b) => { + const dateA = new Date(a.createdAt); + const dateB = new Date(b.createdAt); + return dateA - dateB; + }); + setFilteredOrders(filtered); + }, [ordersData, selectedYear, selectedMonth]); // Update filtered orders when orders data, year, or month changes + + // Extract unique products from filtered orders + const uniqueProducts = [ + ...new Set( + filteredOrders.flatMap((order) => + order.orderItems.map((item) => item.name) + ) + ), + ]; +// console.log(uniqueProducts); +// console.log(filteredOrders); + // Prepare data for chart + const data = { + labels: uniqueProducts, // Use unique product names as labels + datasets: [ + { + label: "Total Amount", + data: uniqueProducts.map((product) => + filteredOrders.reduce((total, order) => { + // Find the order item for the current product + const orderItem = order.orderItems.find( + (item) => item.name === product + ); + if (orderItem) { + // If the order item exists, add its total amount to the total for this product + return total + orderItem. + product_Subtotal; + } else { + // If the order item does not exist, return the current total + return total; + } + }, 0) + ), + backgroundColor: "rgba(43, 63, 229, 0.8)", + borderRadius: 5, + }, + ], + }; + + const options = { + responsive: true, + plugins: { + legend: { + display: false, + }, + title: { + display: true, + text: "Revenue Chart", + }, + }, + scales: { + x: { + title: { + display: true, + text: "Product", + }, + }, + y: { + beginAtZero: true, + title: { + display: true, + text: "Total Amount", + }, + ticks: { + stepSize: 1, // Adjust step size as needed + }, + }, + }, + }; + + // Convert month number to string + const monthToString = (monthNumber) => { + const months = [ + "January", + "February", + "March", + "April", + "May", + "June", + "July", + "August", + "September", + "October", + "November", + "December", + ]; + return months[monthNumber - 1]; + }; + + // Determine the lowest year found in the ordersData + const lowestYear = Math.min( + ...ordersData.map((order) => new Date(order.createdAt).getFullYear()) + ); + + // Generate an array of years from the lowest year to the current year + const years = Array.from( + { length: new Date().getFullYear() - lowestYear + 1 }, + (_, index) => lowestYear + index + ); return ( -
- {token ? ( - - ) : ( -

No charts available

- )} -
+ <> +
+
+ + +
+
+ + +
+
+
+ {filteredOrders.length === 0 ? ( +

No data available

+ ) : ( +
+ +
+ )} +
+ ); }; diff --git a/src/views/Charts/RevenueCharts.js b/src/views/Charts/RevenueCharts.js index 40a9cf6..4a4a88f 100644 --- a/src/views/Charts/RevenueCharts.js +++ b/src/views/Charts/RevenueCharts.js @@ -1,26 +1,198 @@ -import { isAutheticated } from "../../auth.js"; +import React, { useEffect, useState } from "react"; +import { isAutheticated } from "src/auth"; +import axios from "axios"; +import { Bar } from "react-chartjs-2"; +import { + Chart as ChartJS, + CategoryScale, + LinearScale, + BarElement, + Title, + Tooltip, + Legend, +} from "chart.js"; + +ChartJS.register( + CategoryScale, + LinearScale, + BarElement, + Title, + Tooltip, + Legend +); const RevenueCharts = () => { const token = isAutheticated(); + const [ordersData, setOrdersData] = useState([]); + const [filteredOrders, setFilteredOrders] = useState([]); + const [selectedYear, setSelectedYear] = useState(new Date().getFullYear()); + const [selectedMonth, setSelectedMonth] = useState(new Date().getMonth() + 1); + + useEffect(() => { + function getOrder() { + axios + .get(`/api/order/getAll/`, { + headers: { + "Access-Control-Allow-Origin": "*", + Authorization: `Bearer ${token}`, + }, + }) + .then((res) => { + setOrdersData(res.data.order); + // console.log(res.data.order); + }) + .catch((err) => { + console.log(err); + }); + } + getOrder(); + }, []); + + useEffect(() => { + // Filter orders based on selected year and month + const filtered = ordersData.filter((order) => { + const createdAt = new Date(order.createdAt); + return ( + createdAt.getFullYear() === selectedYear && + createdAt.getMonth() + 1 === selectedMonth + ); + }); + // Sort filtered orders by date in ascending order + filtered.sort((a, b) => { + const dateA = new Date(a.createdAt); + const dateB = new Date(b.createdAt); + return dateA - dateB; + }); + setFilteredOrders(filtered); + }, [ordersData, selectedYear, selectedMonth]); // Update filtered orders when orders data, year, or month changes + + // Extract unique dates from filtered orders + const uniqueDates = Array.from( + new Set(filteredOrders.map((order) => order.createdAt.split("T")[0])) + ); + // console.log(uniqueDates); + // console.log(filteredOrders); + // Prepare data for chart + const data = { + labels: uniqueDates, + datasets: [ + { + label: "Total Amount", + data: uniqueDates.map((date) => { + // Sum total amounts for each date + return filteredOrders + .filter((order) => order.createdAt.includes(date)) + .reduce((total, order) => total + order.total_amount, 0); + }), + backgroundColor: "rgba(43, 63, 229, 0.8)", + borderRadius: 5, + }, + ], + }; + + const options = { + responsive: true, + plugins: { + legend: { + display: false, + }, + title: { + display: true, + text: "Revenue Chart", + }, + }, + scales: { + x: { + title: { + display: true, + text: "Date", + }, + }, + y: { + beginAtZero: true, + title: { + display: true, + text: "Total Amount", + }, + ticks: { + stepSize: 1000, // Adjust step size as needed + }, + }, + }, + }; + + // Convert month number to string + const monthToString = (monthNumber) => { + const months = [ + "January", + "February", + "March", + "April", + "May", + "June", + "July", + "August", + "September", + "October", + "November", + "December", + ]; + return months[monthNumber - 1]; + }; + + // Determine the lowest year found in the ordersData + const lowestYear = Math.min( + ...ordersData.map((order) => new Date(order.createdAt).getFullYear()) + ); + + // Generate an array of years from the lowest year to the current year + const years = Array.from( + { length: new Date().getFullYear() - lowestYear + 1 }, + (_, index) => lowestYear + index + ); return ( -
- {token ? ( - - ) : ( -

No charts available

- )} -
+ <> +
+
+ + +
+
+ + +
+
+
+ {filteredOrders.length === 0 ? ( +

No data available

+ ) : ( +
+ +
+ )} +
+ ); }; diff --git a/src/views/Charts/Staterevenue.js b/src/views/Charts/Staterevenue.js index c584d5b..3becaf4 100644 --- a/src/views/Charts/Staterevenue.js +++ b/src/views/Charts/Staterevenue.js @@ -1,27 +1,200 @@ -import { isAutheticated } from "../../auth.js"; +import React, { useEffect, useState } from "react"; +import { isAutheticated } from "src/auth"; +import axios from "axios"; +import { Bar } from "react-chartjs-2"; +import { + Chart as ChartJS, + CategoryScale, + LinearScale, + BarElement, + Title, + Tooltip, + Legend, +} from "chart.js"; + +ChartJS.register( + CategoryScale, + LinearScale, + BarElement, + Title, + Tooltip, + Legend +); const StateRevenueCharts = () => { const token = isAutheticated(); + const [ordersData, setOrdersData] = useState([]); + const [filteredOrders, setFilteredOrders] = useState([]); + const [selectedYear, setSelectedYear] = useState(new Date().getFullYear()); + const [selectedMonth, setSelectedMonth] = useState(new Date().getMonth() + 1); + + useEffect(() => { + function getOrder() { + axios + .get(`/api/order/getAll/`, { + headers: { + "Access-Control-Allow-Origin": "*", + Authorization: `Bearer ${token}`, + }, + }) + .then((res) => { + setOrdersData(res.data.order); + // console.log(res.data.order); + }) + .catch((err) => { + console.log(err); + }); + } + getOrder(); + }, []); + + useEffect(() => { + // Filter orders based on selected year and month + const filtered = ordersData.filter((order) => { + const createdAt = new Date(order.createdAt); + return ( + createdAt.getFullYear() === selectedYear && + createdAt.getMonth() + 1 === selectedMonth + ); + }); + // Sort filtered orders by date in ascending order + filtered.sort((a, b) => { + const dateA = new Date(a.createdAt); + const dateB = new Date(b.createdAt); + return dateA - dateB; + }); + setFilteredOrders(filtered); + }, [ordersData, selectedYear, selectedMonth]); // Update filtered orders when orders data, year, or month changes + + const uniquestate = [ + ...new Set( + filteredOrders.map((item) => item.shippingInfo.state) + ), + ]; +// console.log(uniquestate); +// console.log(filteredOrders); + // Prepare data for chart + const data = { + labels: uniquestate, // Use unique product names as labels + datasets: [ + { + label: "Total Amount", + data: uniquestate.map((state) => { + // Sum total amounts for each date + return filteredOrders + .filter((order) => order.shippingInfo.state.includes(state)) + .reduce((total, order) => total + order.total_amount, 0); + }), + backgroundColor: "rgba(43, 63, 229, 0.8)", + borderRadius: 5, + }, + ], + }; + + const options = { + responsive: true, + plugins: { + legend: { + display: false, + }, + title: { + display: true, + text: "Revenue Chart", + }, + }, + scales: { + x: { + title: { + display: true, + text: "State", + }, + }, + y: { + beginAtZero: true, + title: { + display: true, + text: "Total Amount", + }, + ticks: { + stepSize: 1, // Adjust step size as needed + }, + }, + }, + }; + + // Convert month number to string + const monthToString = (monthNumber) => { + const months = [ + "January", + "February", + "March", + "April", + "May", + "June", + "July", + "August", + "September", + "October", + "November", + "December", + ]; + return months[monthNumber - 1]; + }; + + // Determine the lowest year found in the ordersData + const lowestYear = Math.min( + ...ordersData.map((order) => new Date(order.createdAt).getFullYear()) + ); + + // Generate an array of years from the lowest year to the current year + const years = Array.from( + { length: new Date().getFullYear() - lowestYear + 1 }, + (_, index) => lowestYear + index + ); return ( -
- {token ? ( - - ) : ( -

No charts available

- )} -
+ <> +
+
+ + +
+
+ + +
+
+
+ {filteredOrders.length === 0 ? ( +

No data available

+ ) : ( +
+ +
+ )} +
+ ); }; -export default StateRevenueCharts; \ No newline at end of file +export default StateRevenueCharts; diff --git a/src/views/Charts/UserChart.js b/src/views/Charts/UserChart.js index e99dcfc..60fbcc9 100644 --- a/src/views/Charts/UserChart.js +++ b/src/views/Charts/UserChart.js @@ -1,27 +1,200 @@ -import { isAutheticated } from "../../auth.js"; +import React, { useEffect, useState } from "react"; +import { isAutheticated } from "src/auth"; +import axios from "axios"; +import { Bar } from "react-chartjs-2"; +import { + Chart as ChartJS, + CategoryScale, + LinearScale, + BarElement, + Title, + Tooltip, + Legend, +} from "chart.js"; + +ChartJS.register( + CategoryScale, + LinearScale, + BarElement, + Title, + Tooltip, + Legend +); const UserCharts = () => { const token = isAutheticated(); + const [userData, setUsers] = useState([]); + const [filteredUsers, setfilteredUsers] = useState([]); + const [selectedYear, setSelectedYear] = useState(new Date().getFullYear()); + const [selectedMonth, setSelectedMonth] = useState(new Date().getMonth() + 1); + + useEffect(() => { + function getOrder() { + axios + .get(`/api/v1/admin/users`, { + headers: { + "Access-Control-Allow-Origin": "*", + Authorization: `Bearer ${token}`, + }, + }) + .then((res) => { + setUsers(res.data.users); + // console.log(res.data.users); + }) + .catch((err) => { + console.log(err); + }); + } + getOrder(); + }, []); + + useEffect(() => { + // Filter orders based on selected year and month + const filtered = userData.filter((order) => { + const createdAt = new Date(order.createdAt); + return ( + createdAt.getFullYear() === selectedYear && + createdAt.getMonth() + 1 === selectedMonth + ); + }); + // Sort filtered orders by date in ascending order + filtered.sort((a, b) => { + const dateA = new Date(a.createdAt); + const dateB = new Date(b.createdAt); + return dateA - dateB; + }); + setfilteredUsers(filtered); + }, [userData, selectedYear, selectedMonth]); // Update filtered orders when orders data, year, or month changes + + // Extract unique dates from filtered orders + const uniqueDates = Array.from( + new Set(filteredUsers.map((order) => order.createdAt.split("T")[0])) + ); + // console.log(uniqueDates); + // console.log(filteredUsers); + // Prepare data for chart + const data = { + labels: uniqueDates, + datasets: [ + { + label: "No of Amounts", + data: uniqueDates.map((date) => { + // Sum total amounts for each date + return filteredUsers + .filter((order) => order.createdAt.includes(date)) + .length; + }), + backgroundColor: "rgba(43, 63, 229, 0.8)", + borderRadius: 5, + }, + ], + }; + + const options = { + responsive: true, + plugins: { + legend: { + display: false, + }, + title: { + display: true, + text: "User Chart", + }, + }, + scales: { + x: { + title: { + display: true, + text: "Date", + }, + }, + y: { + beginAtZero: true, + title: { + display: true, + text: "No of Users", + }, + ticks: { + stepSize: 1, // Adjust step size as needed + }, + }, + }, + }; + + // Convert month number to string + const monthToString = (monthNumber) => { + const months = [ + "January", + "February", + "March", + "April", + "May", + "June", + "July", + "August", + "September", + "October", + "November", + "December", + ]; + return months[monthNumber - 1]; + }; + + // Determine the lowest year found in the userData + const lowestYear = Math.min( + ...userData.map((order) => new Date(order.createdAt).getFullYear()) + ); + + // Generate an array of years from the lowest year to the current year + const years = Array.from( + { length: new Date().getFullYear() - lowestYear + 1 }, + (_, index) => lowestYear + index + ); return ( -
- {token ? ( - - ) : ( -

No charts available

- )} -
+ <> +
+
+ + +
+
+ + +
+
+
+ {filteredUsers.length === 0 ? ( +

No data available

+ ) : ( +
+ +
+ )} +
+ ); }; export default UserCharts; +