diff --git a/src/_nav.js b/src/_nav.js
index 4b49ef5..6eddd7e 100644
--- a/src/_nav.js
+++ b/src/_nav.js
@@ -22,6 +22,7 @@ import {
cilTennisBall,
cilText,
cilUser,
+ cilAlarm,
} from "@coreui/icons";
import { CNavGroup, CNavItem, CNavTitle, CTabContent } from "@coreui/react";
@@ -229,6 +230,25 @@ const _nav = [
],
},
//Affiliate end
+ {
+ component: CNavGroup,
+ name: "Customer Service",
+ icon: ,
+ items: [
+ {
+ component: CNavItem,
+ name: "Customer Support",
+ icon: ,
+ to: "/support/request",
+ },
+ {
+ component: CNavItem,
+ name: "Contact Requests",
+ icon: ,
+ to: "/contact/request",
+ },
+ ],
+ },
];
export default _nav;
diff --git a/src/routes.js b/src/routes.js
index 56e9c3b..c518abd 100644
--- a/src/routes.js
+++ b/src/routes.js
@@ -110,6 +110,10 @@ import EditCoupon from "./views/Affiliate/EditCoupon";
import PayAffiliate from "./views/Affiliate/PayAffiliate";
import AffiliateHistory from "./views/Affiliate/AffiliateHistory";
import CouponHistory from "./views/Affiliate/CouponHistory";
+import SupportRequest from "./views/CustomerSupport/SupportRequest";
+import SupportReply from "./views/CustomerSupport/SupportReply";
+import SupportRequestClosed from "./views/CustomerSupport/SupportRequestClosed";
+import CloseRequestView from "./views/CustomerSupport/CloseRequestView";
const routes = [
{ path: "/", exact: true, name: "Home" },
@@ -238,7 +242,28 @@ const routes = [
name: "AddContact Request",
element: AddContactRequest,
},
+ //Support Requests
+ {
+ path: "/support/request",
+ name: "CustomerSupport Requests",
+ element: SupportRequest,
+ },
+ {
+ path: "/support/request/closed",
+ name: "Closed CustomerSupport Requests",
+ element: SupportRequestClosed,
+ },
+ {
+ path: "/support/request/closed/:ticketID",
+ name: "Closed CustomerSupport Request view",
+ element: CloseRequestView,
+ },
+ {
+ path: "/support/request/reply/:ticketID",
+ name: "CustomerSupport Reply",
+ element: SupportReply,
+ },
// Content ---- >
{
diff --git a/src/views/CustomerSupport/CloseRequestView.js b/src/views/CustomerSupport/CloseRequestView.js
new file mode 100644
index 0000000..078346a
--- /dev/null
+++ b/src/views/CustomerSupport/CloseRequestView.js
@@ -0,0 +1,207 @@
+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 { Button, ImageList, InputLabel, ImageListItem } from "@mui/material";
+import MessageList from "./MessageList";
+import { useParams } from "react-router-dom";
+import { useDispatch, useSelector } from "react-redux";
+
+const CloseRequestView = () => {
+ // Assuming you have the following ticket details
+ const { ticketID } = useParams();
+ const token = isAutheticated();
+ const navigate = useNavigate();
+
+ const [loading, setLoading] = useState(false);
+ // error****************************please check
+ const [ticketDetails, setticketDetails] = useState(null);
+
+ // const dispatch = useDispatch();
+ // const tickets = useSelector((state) => state.ticket.ticket);
+ // useEffect(() => {
+ // dispatch(getTicketItem());
+ // }, [dispatch]);
+
+ // console.log(tickets);
+ // geting data from backend************
+
+ // const dispatch = useDispatch();
+ // const tickets = useSelector((state) => state.ticket.ticket);
+ // useEffect(() => {
+ // dispatch(getTicketItem());
+ // }, [dispatch]);
+
+ // console.log(tickets);
+ // useEffect(() => {
+ // const foundTicket = tickets.find((ticket) => ticket.ticketId === ticketID);
+ // // console.log(foundTicket);
+ // setticketDetails(foundTicket);
+ // }, [ticketID]);
+ // console.log(ticketID);
+ // *****************
+ // geting data from backend************
+ const getSupportTicketDetails = async () => {
+ // console.log(ticketID);
+ axios
+ .get(`/api/support/getOne/${ticketID}`, {
+ headers: {
+ "Access-Control-Allow-Origin": "*",
+ Authorization: `Bearer ${token}`,
+ },
+ })
+ .then((res) => {
+ // console.log(res?.data);
+ // setticketDetails(res.data?.support);
+ // setTicket(res.data?.support);
+ console.log(res.data?.support);
+ getuserName(res.data?.support);
+ // setLoading(false);
+ })
+ .catch((error) => {
+ swal({
+ title: error,
+ text: "please login to access the resource or refresh the page ",
+ icon: "error",
+ button: "Retry",
+ dangerMode: true,
+ });
+ // setLoading(false);
+ });
+ };
+ // ************************************
+ const getuserName = async (ticket) => {
+ try {
+ const userId = ticket.addedBy;
+ let resp = await axios.get(`/api/v1/admin/user/${userId}`, {
+ headers: {
+ Authorization: `Bearer ${token}`,
+ },
+ });
+ console.log(resp?.data?.user?.name);
+ const userName = resp?.data?.user?.name;
+ const userMailId = resp?.data?.user?.email;
+ // console.log(userName);
+ // Update support ticket with user name
+ const ticketWithUserName = {
+ ...ticket,
+ userName: userName,
+ userMailId: userMailId,
+ };
+ setticketDetails(ticketWithUserName);
+ } catch (error) {
+ // Handle errors
+ }
+ };
+
+ React.useEffect(() => {
+ getSupportTicketDetails();
+ }, []);
+ // *****************
+
+ return (
+
+
+
+
+
+ View Request
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Ticket ID: {ticketDetails?.ticketId}
+
+
+ User ID: {ticketDetails?.addedBy}
+
+
+ User Name: {ticketDetails?.userName}
+
+
+ User MailId: {ticketDetails?.userMailId}
+
+
+ Date and Time: {ticketDetails?.createdOn}
+
+
+ Subject: {ticketDetails?.subject}
+
+
+ Description:{" "}
+ {ticketDetails?.description
+ ? ticketDetails?.description
+ : "No Description"}
+
+
+
+ {ticketDetails?.image?.length > 0 && (
+
+
+ Image:
+
+
+ {ticketDetails?.image?.map((item) => (
+
+
+
+ ))}
+
+
+ )}
+
+
+ {ticketDetails && (
+
+ )}
+
+
+ {/* *************** */}
+
+
+
+
+
+ );
+};
+
+export default CloseRequestView;
diff --git a/src/views/CustomerSupport/MessageList.js b/src/views/CustomerSupport/MessageList.js
new file mode 100644
index 0000000..251473b
--- /dev/null
+++ b/src/views/CustomerSupport/MessageList.js
@@ -0,0 +1,32 @@
+
+import React from 'react';
+import { Paper } from '@material-ui/core';
+
+const MessageList = ({ messages }) => {
+ return (
+ <>
+ {messages.map((msg, index) => (
+
+
+
+ {msg.user === 'user' ? 'User' : 'Admin'}
+
+
+ {msg.replyDate}
+
+ {msg.message}
+
+
+ ))}
+ >
+ );
+};
+
+export default MessageList;
+
diff --git a/src/views/CustomerSupport/SupportReply.js b/src/views/CustomerSupport/SupportReply.js
new file mode 100644
index 0000000..1712a37
--- /dev/null
+++ b/src/views/CustomerSupport/SupportReply.js
@@ -0,0 +1,346 @@
+import React, { useEffect, useState } from "react";
+// import Button from "@material-ui/core/Button";
+import { Link, useNavigate, useParams } from "react-router-dom";
+import swal from "sweetalert";
+import axios from "axios";
+import { isAutheticated } from "src/auth";
+import { Button, ImageList, InputLabel, ImageListItem } from "@mui/material";
+import MessageList from "./MessageList";
+import { useDispatch, useSelector } from "react-redux";
+
+import toast from "react-hot-toast";
+const SupportReply = () => {
+ const token = isAutheticated();
+ const navigate = useNavigate();
+ const [data, setData] = useState({
+ user: "admin",
+ replyDate: "",
+ message: "",
+ });
+
+ const [loading, setLoading] = useState(false);
+
+ const handleChange = (e) => {
+ setData((prev) => ({ ...prev, [e.target.id]: e.target.value }));
+ };
+ const options = {
+ weekday: "short", // Abbreviated weekday (e.g., "Tue")
+ day: "numeric", // Numeric day (e.g., "5")
+ month: "short", // Abbreviated month (e.g., "Mar")
+ year: "numeric", // Numeric year (e.g., "2024")
+ hour: "numeric", // Numeric hour (e.g., "10")
+ minute: "2-digit", // Two-digit minute (e.g., "27")
+ hour12: true, // Use 12-hour clock (true/false)
+ };
+
+ const { ticketID } = useParams();
+
+
+ const [ticketDetails, setticketDetails] = useState(null);
+ const [fetchData, setFetchData] = useState(false);
+
+ const getSupportTicketDetails = async () => {
+ // console.log(ticketID);
+ axios
+ .get(`/api/support/getOne/${ticketID}`, {
+ headers: {
+ "Access-Control-Allow-Origin": "*",
+ Authorization: `Bearer ${token}`,
+ },
+ })
+ .then((res) => {
+ // console.log(res?.data);
+ // setticketDetails(res.data?.support);
+ // setTicket(res.data?.support);
+ console.log(res.data?.support);
+ getuserName(res.data?.support);
+ // setLoading(false);
+ })
+ .catch((error) => {
+ swal({
+ title: error,
+ text: "please login to access the resource or refresh the page ",
+ icon: "error",
+ button: "Retry",
+ dangerMode: true,
+ });
+ // setLoading(false);
+ });
+ };
+ // ************************************
+ // updating message in backend************
+ const handleSubmit = () => {
+ if (data.message.trim() === "") {
+ swal({
+ title: "Warning",
+ text: "Fill all mandatory fields",
+ icon: "error",
+ button: "Close",
+ dangerMode: true,
+ });
+ return;
+ }
+ setLoading(true);
+ const formData = {
+ message: data.message,
+ replyDate: new Date().toLocaleString("en-US", options),
+ user: "admin",
+ };
+ axios
+ .patch(
+ `/api/support/update/${ticketID}`,
+ {
+ message: formData,
+ },
+ {
+ headers: {
+ Authorization: `Bearer ${token}`,
+ },
+ }
+ )
+ .then((res) => {
+ toast.success("Message Sent successfully!");
+ setLoading(false);
+ setData({ message: "" });
+ setFetchData(true);
+ navigate("/support/request", { replace: true });
+ })
+ .catch((error) => {
+ swal({
+ title: "Error",
+ text: "Something went wrong",
+ icon: "error",
+ button: "Close",
+ });
+ });
+ };
+ // ************************************
+ const getuserName = async (ticket) => {
+ try {
+ const userId = ticket.addedBy;
+ let resp = await axios.get(`/api/v1/admin/user/${userId}`, {
+ headers: {
+ Authorization: `Bearer ${token}`,
+ },
+ });
+ console.log(resp?.data?.user?.name);
+ const userName = resp?.data?.user?.name;
+ const userMailId = resp?.data?.user?.email;
+ // console.log(userName);
+ // Update support ticket with user name
+ const ticketWithUserName = {
+ ...ticket,
+ userName: userName,
+ userMailId: userMailId,
+ };
+ setticketDetails(ticketWithUserName);
+ } catch (error) {
+ // Handle errors
+ }
+ };
+
+ React.useEffect(() => {
+ getSupportTicketDetails();
+ setFetchData(false);
+ }, [fetchData]);
+
+ // ************************************
+ return (
+
+
+
+
+
+ Support Chat
+
+
+
+
+
+ {/* */}
+ {/* */}
+
+
+
+
+
+
+
+
+
+
+ Ticket ID: {ticketDetails?.ticketId}
+
+
+ User ID: {ticketDetails?.addedBy}
+
+
+ User Name: {ticketDetails?.userName}
+
+
+ User MailId: {ticketDetails?.userMailId}
+
+
+ Date and Time: {ticketDetails?.createdOn}
+
+
+ Subject: {ticketDetails?.subject}
+
+
+ Description:{" "}
+ {ticketDetails?.description
+ ? ticketDetails?.description
+ : "No Description"}
+
+
+
+ {ticketDetails?.image?.length > 0 && (
+
+
+ Image:
+
+
+ {ticketDetails?.image?.map((item) => (
+
+
+
+ ))}
+
+
+ )}
+
+
+ {ticketDetails && (
+
+ )}
+
+
+
+
+
+
+ {data.message ? (
+ <>
+
+ {500 - data.message.length} characters left
+
+ >
+ ) : (
+ <>>
+ )}
+
+
+
+ {/* */}
+
+ {/* */}
+
+
+
+
+
+
+ );
+};
+
+export default SupportReply;
diff --git a/src/views/CustomerSupport/SupportRequest.js b/src/views/CustomerSupport/SupportRequest.js
new file mode 100644
index 0000000..93ccdbd
--- /dev/null
+++ b/src/views/CustomerSupport/SupportRequest.js
@@ -0,0 +1,428 @@
+import React, { useState, useEffect } from "react";
+import { Link } from "react-router-dom";
+import Button from "@material-ui/core/Button";
+import { useNavigate } from "react-router-dom";
+import axios from "axios";
+import { isAutheticated } from "src/auth";
+import { useDispatch, useSelector } from "react-redux";
+
+import { CircularProgress, TextField } from "@material-ui/core";
+import { cilSearch } from "@coreui/icons";
+import CIcon from "@coreui/icons-react";
+import Fuse from "fuse.js";
+const SupportRequest = () => {
+ const token = isAutheticated();
+ const navigate = useNavigate();
+ const [loading, setLoading] = useState(true);
+ const [SupportRequestsData, setSupportRequestsData] = useState([]);
+
+ const [currentPage, setCurrentPage] = useState(1);
+ const [itemPerPage, setItemPerPage] = useState(10);
+ const [showData, setShowData] = useState(SupportRequestsData);
+ const [searchTerm, setSearchTerm] = useState("");
+
+ useEffect(() => {
+ setTimeout(() => {
+ if (searchTerm !== "") {
+ let searchedResult = [];
+ searchedResult = SupportRequestsData.filter((item) =>
+ item.ticketId.toString().includes(searchTerm)
+ );
+
+ setShowData(searchedResult);
+ }
+ else{
+ getSupportTicketsData();
+ }
+ }, 100);
+ }, [searchTerm]);
+
+ const handleShowEntries = (e) => {
+ setCurrentPage(1);
+ setItemPerPage(e.target.value);
+ };
+ const getSupportTicketsData = async () => {
+ axios
+ .get(`/api/support/getAll/`, {
+ headers: {
+ Authorization: `Bearer ${token}`,
+ },
+ })
+ .then((res) => {
+
+ setSupportRequestsData(
+ res.data?.support.filter((ticket) => ticket.status === "Open")
+ );
+ // setLoading(false);
+ })
+ .catch((error) => {
+ swal({
+ title: error,
+ text: "please login to access the resource or refresh the page ",
+ icon: "error",
+ button: "Retry",
+ dangerMode: true,
+ });
+ setLoading(false);
+ });
+ };
+ React.useEffect(() => {
+ setLoading(true);
+ getSupportTicketsData();
+ }, [token]);
+ const statusupdate = (ticketId) => {
+ axios
+ .patch(
+ `/api/support/update/${ticketId}`,
+ {
+ status: "Close",
+ },
+ {
+ headers: {
+ Authorization: `Bearer ${token}`,
+ },
+ }
+ )
+ .then((res) => {
+ swal({
+ title: "Success",
+ text: "Ticket Closed Successfully",
+ icon: "success",
+ button: "Close",
+ });
+ getSupportTicketsData();
+ })
+ .catch((error) => {
+ swal({
+ title: "Error",
+ text: "Something went wrong",
+ icon: "error",
+ button: "Close",
+ });
+ });
+ };
+
+ useEffect(() => {
+ // const loadData = () => {
+ const indexOfLastPost = currentPage * itemPerPage;
+ const indexOfFirstPost = indexOfLastPost - itemPerPage;
+ setShowData(SupportRequestsData.slice(indexOfFirstPost, indexOfLastPost));
+ setLoading(false);
+ // };
+ // loadData();
+ }, [currentPage, itemPerPage, SupportRequestsData]);
+
+ return (
+
+
+
+
+
+
+
+ Customer Support Requests
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {/* ********* */}
+
+ setSearchTerm(e.target.value)}
+ />
+
+
+ {/* ********** */}
+
+
+
+
+
+
+ Ticket ID |
+ Subject |
+ Created On |
+ Last Reply |
+ Status |
+
+ Action
+ |
+
+
+
+ {!loading && showData.length === 0 && (
+
+
+ No Open Tickets Available
+ |
+
+ )}
+ {loading ? (
+
+
+ {/* Loading... */}
+
+ |
+
+ ) : (
+ showData.map((ticket, i) => {
+ return (
+
+ {ticket.ticketId} |
+ {ticket.subject} |
+ {ticket.createdOn} |
+ {ticket.lastreply} |
+ {ticket.status} |
+
+
+
+ |
+
+ );})
+ )}
+
+
+
+
+
+
+
+ Showing {currentPage * itemPerPage - itemPerPage + 1} to{" "}
+ {Math.min(
+ currentPage * itemPerPage,
+ SupportRequestsData.length
+ )}{" "}
+ of {SupportRequestsData.length} entries
+
+
+
+
+
+
+ -
+ setCurrentPage((prev) => prev - 1)}
+ >
+ Previous
+
+
+
+ {!(currentPage - 1 < 1) && (
+ -
+
+ setCurrentPage((prev) => prev - 1)
+ }
+ >
+ {currentPage - 1}
+
+
+ )}
+
+ -
+
+ {currentPage}
+
+
+
+ {!(
+ (currentPage + 1) * itemPerPage - itemPerPage >
+ SupportRequestsData.length - 1
+ ) && (
+ -
+ {
+ setCurrentPage((prev) => prev + 1);
+ }}
+ >
+ {currentPage + 1}
+
+
+ )}
+
+ -
+ SupportRequestsData.length - 1
+ )
+ ? "paginate_button page-item next"
+ : "paginate_button page-item next disabled"
+ }
+ >
+ setCurrentPage((prev) => prev + 1)}
+ >
+ Next
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
+
+export default SupportRequest;
diff --git a/src/views/CustomerSupport/SupportRequestClosed.js b/src/views/CustomerSupport/SupportRequestClosed.js
new file mode 100644
index 0000000..6453642
--- /dev/null
+++ b/src/views/CustomerSupport/SupportRequestClosed.js
@@ -0,0 +1,379 @@
+import React, { useState, useEffect } from "react";
+import { Link } from "react-router-dom";
+import Button from "@material-ui/core/Button";
+import { useNavigate } from "react-router-dom";
+import axios from "axios";
+import { isAutheticated } from "src/auth";
+import { useDispatch, useSelector } from "react-redux";
+import { CircularProgress, TextField } from "@material-ui/core";
+import { cilSearch } from "@coreui/icons";
+import CIcon from "@coreui/icons-react";
+import Fuse from "fuse.js";
+const SupportRequestClosed = () => {
+ const token = isAutheticated();
+ const navigate = useNavigate();
+ const [loading, setLoading] = useState(false);
+ const [success, setSuccess] = useState(true);
+ const [status, setStatus] = useState("");
+ const [SupportRequestsData, setSupportRequestsData] = useState([]);
+
+ const [currentPage, setCurrentPage] = useState(1);
+ const [itemPerPage, setItemPerPage] = useState(10);
+ const [showData, setShowData] = useState(SupportRequestsData);
+ const [searchTerm, setSearchTerm] = useState("");
+
+ useEffect(() => {
+ setTimeout(() => {
+ if (searchTerm !== "") {
+ let searchedResult = [];
+ searchedResult = SupportRequestsData.filter((item) =>
+ item.ticketId.toString().includes(searchTerm)
+ );
+
+ setShowData(searchedResult);
+ } else {
+ getSupportTicketsData();
+ }
+ }, 100);
+ }, [searchTerm]);
+
+ const handleShowEntries = (e) => {
+ setCurrentPage(1);
+ setItemPerPage(e.target.value);
+ };
+ const [ticketsData, setticketsData] = React.useState([]);
+ const getSupportTicketsData = async () => {
+ axios
+ .get(`/api/support/getAll/`, {
+ headers: {
+ Authorization: `Bearer ${token}`,
+ },
+ })
+ .then((res) => {
+ setSupportRequestsData(
+ res.data?.support.filter((ticket) => ticket.status === "Close")
+ );
+ setLoading(false);
+ })
+ .catch((error) => {
+ swal({
+ title: error,
+ text: "please login to access the resource or refresh the page ",
+ icon: "error",
+ button: "Retry",
+ dangerMode: true,
+ });
+ setLoading(false);
+ });
+ };
+ React.useEffect(() => {
+ setLoading(true);
+ getSupportTicketsData();
+ }, [token]);
+
+ // console.log(showData);
+
+ //********************************* */
+ useEffect(() => {
+ const loadData = () => {
+ const indexOfLastPost = currentPage * itemPerPage;
+ const indexOfFirstPost = indexOfLastPost - itemPerPage;
+ setShowData(SupportRequestsData.slice(indexOfFirstPost, indexOfLastPost));
+ };
+ loadData();
+ }, [currentPage, itemPerPage, SupportRequestsData]);
+
+ return (
+
+
+
+
+
+
+
+ Closed Customer Support Requests
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {/* ********* */}
+
+ setSearchTerm(e.target.value)}
+ />
+ handleSearch(searchTerm)}
+ />
+
+ {/* ********** */}
+
+
+
+
+
+
+ Ticket ID |
+ Subject |
+ Created On |
+ Last Reply |
+ Status |
+
+ Action
+ |
+ {/* Action | */}
+
+
+
+
+ {!loading && showData.length === 0 && (
+
+
+ No Close Tickets Available
+ |
+
+ )}
+ {loading ? (
+
+
+ {/* Loading... */}
+
+ |
+
+ ) : (
+ showData.map((ticket, i) => {
+ return (
+
+
+ {ticket.ticketId}
+ |
+ {ticket.subject} |
+
+ {ticket.createdOn}
+ |
+
+ {ticket.lastreply}
+ |
+ {ticket.status} |
+
+
+
+
+ |
+
+ );
+ })
+ )}
+
+
+
+
+
+
+
+ Showing {currentPage * itemPerPage - itemPerPage + 1} to{" "}
+ {Math.min(
+ currentPage * itemPerPage,
+ SupportRequestsData.length
+ )}{" "}
+ of {SupportRequestsData.length} entries
+
+
+
+
+
+
+ -
+ setCurrentPage((prev) => prev - 1)}
+ >
+ Previous
+
+
+
+ {!(currentPage - 1 < 1) && (
+ -
+
+ setCurrentPage((prev) => prev - 1)
+ }
+ >
+ {currentPage - 1}
+
+
+ )}
+
+ -
+
+ {currentPage}
+
+
+
+ {!(
+ (currentPage + 1) * itemPerPage - itemPerPage >
+ SupportRequestsData.length - 1
+ ) && (
+ -
+ {
+ setCurrentPage((prev) => prev + 1);
+ }}
+ >
+ {currentPage + 1}
+
+
+ )}
+
+ -
+ SupportRequestsData.length - 1
+ )
+ ? "paginate_button page-item next"
+ : "paginate_button page-item next disabled"
+ }
+ >
+ setCurrentPage((prev) => prev + 1)}
+ >
+ Next
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
+
+export default SupportRequestClosed;