diff --git a/src/_nav.js b/src/_nav.js index e93a347..551ef77 100644 --- a/src/_nav.js +++ b/src/_nav.js @@ -27,6 +27,7 @@ import { cilLocationPin, cilSettings, cilMoney, + cilBell, } from "@coreui/icons"; import { CNavGroup, CNavItem, CNavTitle, CTabContent } from "@coreui/react"; @@ -196,6 +197,13 @@ const _nav = [ // }, ], }, + { + component: CNavItem, + name: "Announcement", + icon: , + to: "/announcement", + group: "Inventory", + }, { component: CNavGroup, name: "Settings", diff --git a/src/index.js b/src/index.js index 0ab534a..8a829f2 100644 --- a/src/index.js +++ b/src/index.js @@ -15,9 +15,9 @@ 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://cheminova-api-2.onrender.com"; - axios.defaults.baseURL = "https://api.cnapp.co.in"; + // axios.defaults.baseURL = "https://api.cnapp.co.in"; axios.defaults.headers = { "Cache-Control": "no-cache,no-store", diff --git a/src/routes.js b/src/routes.js index 12341ef..6b92d3f 100644 --- a/src/routes.js +++ b/src/routes.js @@ -159,6 +159,8 @@ import DistributorStocks from "./views/RetailDistributors/DistributorStock"; import AddMultiplerd from "./views/RetailDistributors/AddMultipleRD"; import AddMultipletm from "./views/TerritoryManager/AddMultipleTM"; import AddMultiplesc from "./views/SalesCoOrdinators/AddMultipleSC"; +import Announcements from "./views/Announcment/announcement"; +import CreateAnnouncement from "./views/Announcment/createAnnouncement"; const routes = [ //dashboard @@ -718,7 +720,19 @@ const routes = [ navName: "Orders", }, //-------------- End Order Management Routes--------------------------------------- - + // Announcement + { + path: "/announcement", + name: "Announcment", + element: Announcements, + navName: "Announcment", + }, + { + path: "/announcement/create", + name: "Announcment", + element: CreateAnnouncement, + navName: "Announcment", + }, //----------Point of sale orders Routes----------------------- // { path: "/order/:status/:id", name: "View Order", element: ViewOdr }, diff --git a/src/views/Announcment/announcement.js b/src/views/Announcment/announcement.js new file mode 100644 index 0000000..aaf14ab --- /dev/null +++ b/src/views/Announcment/announcement.js @@ -0,0 +1,162 @@ +import React, { useState, useEffect } from "react"; +import { + Table, + TableBody, + TableCell, + TableContainer, + TableHead, + TableRow, + TablePagination, + Paper, + Button, + Typography, + Skeleton, +} from "@mui/material"; +import axios from "axios"; +import { Box } from "@material-ui/core"; +import { useNavigate } from "react-router-dom"; +import { isAutheticated } from "src/auth"; + +const Announcements = () => { + const [announcements, setAnnouncements] = useState([]); + const [loading, setLoading] = useState(true); + const [page, setPage] = useState(0); + const [rowsPerPage, setRowsPerPage] = useState(5); + const [totalAnnouncements, setTotalAnnouncements] = useState(0); + const token = isAutheticated(); + + const fetchAnnouncements = async (page, rowsPerPage) => { + setLoading(true); + try { + const response = await axios.get("/api/announcement/get", { + params: { + page: page + 1, // backend uses 1-based index + rowsPerPage, + }, + headers: { + Authorization: `Bearer ${token}`, // if token is necessary for authorization + }, + }); + console.log(response); + const { announcements, totalAnnouncements } = response.data; + setAnnouncements(announcements); + setTotalAnnouncements(totalAnnouncements); + } catch (error) { + console.error("Error fetching announcements", error); + } finally { + setLoading(false); + } + }; + + useEffect(() => { + fetchAnnouncements(page, rowsPerPage); + }, [page, rowsPerPage]); + + const handleChangePage = (event, newPage) => { + setPage(newPage); + }; + + const handleChangeRowsPerPage = (event) => { + setRowsPerPage(parseInt(event.target.value, 10)); + setPage(0); // Reset page to 0 when changing rows per page + }; + + const formatAMPM = (dateString) => { + const date = new Date(dateString); + let hours = date.getHours(); + let minutes = date.getMinutes(); + const ampm = hours >= 12 ? "PM" : "AM"; + hours = hours % 12 || 12; + minutes = minutes < 10 ? "0" + minutes : minutes; + return `${hours}:${minutes} ${ampm}`; + }; + const navigate = useNavigate(); + + return ( + + + + Announcements + + + + + + + + + + ID + Time + Sent to + Message + {/* Action */} + + + + {loading ? ( + Array.from(new Array(rowsPerPage)).map((_, index) => ( + + + + + + )) + ) : announcements.length > 0 ? ( + announcements.map((announcement) => ( + + {announcement.uniqueId} + + {new Date(announcement.createdAt).toDateString()} + , {formatAMPM(announcement.createdAt)} + + {announcement.sentTo.join(", ")} + {announcement.message} + {/* + + */} + + )) + ) : ( + + + Data not found + + + )} + +
+ +
+
+ ); +}; + +export default Announcements; diff --git a/src/views/Announcment/createAnnouncement.js b/src/views/Announcment/createAnnouncement.js new file mode 100644 index 0000000..bfdbaa9 --- /dev/null +++ b/src/views/Announcment/createAnnouncement.js @@ -0,0 +1,168 @@ +import React, { useState } from "react"; +import { + Checkbox, + Button, + TextField, + Container, + FormControlLabel, + Typography, + Box, +} from "@mui/material"; +import axios from "axios"; +import Swal from "sweetalert2"; +import { useNavigate } from "react-router-dom"; +import { isAutheticated } from "src/auth"; +// import { createAnnouncement } from './api'; // Assume this is the API call + +const CreateAnnouncement = () => { + const [sendTo, setSendTo] = useState({ + PDs: false, + RDs: false, + SCs: false, + TMs: false, + }); + const [message, setMessage] = useState(""); + const [error, setError] = useState(""); + const token = isAutheticated(); + const handleCheckboxChange = (event) => { + setSendTo({ ...sendTo, [event.target.name]: event.target.checked }); + }; + const navigate = useNavigate(); + + const handleSendAnnouncement = async () => { + if (!message || message.length > 250) { + setError("Message is required and should not exceed 250 characters."); + return; + } + + const payload = { + sentTo: Object.keys(sendTo).filter((role) => sendTo[role]), + message, + }; + console.log("this is the send to and ", sendTo, message); + try { + const res = await axios.post( + "/api/announcement/create", // URL to your backend endpoint + { + sentTo: payload.sentTo, // assuming payload contains sentTo and message + message: payload.message, + }, + { + headers: { + Authorization: `Bearer ${token}`, // if token is necessary for authorization + }, + } + ); + if (res.status === 201) { + swal({ + title: "Added", + text: "Announcement added successfully!", + icon: "success", + button: "ok", + }); + navigate("/announcement"); + } else { + swal({ + text: "Something went wrong ", + icon: "error", + buttons: "ok", + }); + } + } catch (error) { + swal({ + text: "Something went wrong ", + icon: "error", + buttons: "ok", + }); + } + }; + + return ( + + + New Announcement + + + + } + label="PDs" + /> +
+ + } + label="RDs" + /> +
+ + } + label="SCs" + /> +
+ + } + label="TMs" + /> + +
+ + Messgae + + setMessage(e.target.value)} + multiline + rows={4} + fullWidth + variant="outlined" + inputProps={{ maxLength: 250 }} + helperText={`${message.length}/250`} + /> + {error && {error}} + + + + +
+
+ ); +}; + +export default CreateAnnouncement;