From 9b01752d9934c9c25a966fb6dcb0a5dadb2a3a95 Mon Sep 17 00:00:00 2001
From: Shivam Gaur <128178418+shivamgaur99@users.noreply.github.com>
Date: Mon, 5 Aug 2024 20:42:44 +0530
Subject: [PATCH] =?UTF-8?q?=F0=9F=8D=81=20[Frontend]=20Improve=20the=20Man?=
=?UTF-8?q?age=20Q&A=20UI=20(#1105)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* [Frontend] Improve the Manage Q&A UI
* removing redundant code
---
frontend/src/pages/Admin/Admin.jsx | 3 -
.../Faq/Q&A/ManageQ&A/ManageQ&A.jsx | 199 ----------------
.../Components/Faq/Q&A/ManageQ&A/index.js | 1 -
.../Faq/Q&A/ManageQ&A/manage.module.scss | 146 ------------
.../pages/Admin/Components/Faq/Q&A/QandA.jsx | 216 ++++++++++++++++--
.../Components/Faq/Q&A/qanda.module.scss | 146 ++++++++++--
6 files changed, 317 insertions(+), 394 deletions(-)
delete mode 100644 frontend/src/pages/Admin/Components/Faq/Q&A/ManageQ&A/ManageQ&A.jsx
delete mode 100644 frontend/src/pages/Admin/Components/Faq/Q&A/ManageQ&A/index.js
delete mode 100644 frontend/src/pages/Admin/Components/Faq/Q&A/ManageQ&A/manage.module.scss
diff --git a/frontend/src/pages/Admin/Admin.jsx b/frontend/src/pages/Admin/Admin.jsx
index 312af9f5..1c649dee 100644
--- a/frontend/src/pages/Admin/Admin.jsx
+++ b/frontend/src/pages/Admin/Admin.jsx
@@ -24,7 +24,6 @@ import { END_POINT } from "../../config/api";
import { useDispatch } from "react-redux";
import { ManageFaq } from "./Components/Faq/ManageFaq";
import { QandA } from "./Components/Faq/Q&A/QandA";
-import { Manageqa } from "./Components/Faq/Q&A/ManageQ&A/ManageQ&A";
import { Testimonial } from "./Components/Testimonial";
import { AddTestimonial } from "./Components/Testimonial/AddTestimonial";
import { ManageTestimonial } from "./Components/Testimonial/ManageTestimonial";
@@ -261,8 +260,6 @@ export const Admin = (props) => {
) : tab === 18 ? (
- ) : tab === 19 ? (
-
) : tab === 20 ? (
) : tab === 21 ? (
diff --git a/frontend/src/pages/Admin/Components/Faq/Q&A/ManageQ&A/ManageQ&A.jsx b/frontend/src/pages/Admin/Components/Faq/Q&A/ManageQ&A/ManageQ&A.jsx
deleted file mode 100644
index 4ba23be3..00000000
--- a/frontend/src/pages/Admin/Components/Faq/Q&A/ManageQ&A/ManageQ&A.jsx
+++ /dev/null
@@ -1,199 +0,0 @@
-import { useEffect, useState } from "react";
-import style from "./manage.module.scss";
-import { makeStyles } from "@material-ui/core/styles";
-import Modal from "@material-ui/core/Modal";
-import Button from "@material-ui/core/Button";
-import Typography from "@material-ui/core/Typography";
-import { AiOutlineArrowLeft } from "react-icons/ai";
-import { SimpleToast } from "../../../../../../components/util/Toast/Toast";
-import Loader from "../../../../../../components/util/Loader";
-import { getQuestionById, deleteAnswer, deleteQuestion, updateQuestionStatus, updateAnswerStatus, getAnswers } from "../../../../../../service/Faq";
-import { hideToast, showToast } from "../../../../../../service/toastService";
-
-const useStyles = makeStyles((theme) => ({
- modal: {
- display: "flex",
- alignItems: "center",
- justifyContent: "center",
- },
- paper: {
- backgroundColor: theme.palette.background.paper,
- border: "2px solid #000",
- boxShadow: theme.shadows[5],
- padding: theme.spacing(2, 4, 3),
- },
- buttons: {
- display: "flex",
- marginTop: "10px",
- justifyContent: "center",
- gap: "10px",
- },
-}));
-
-export function Manageqa({ setTab, qId }) {
- const [ans, setAns] = useState([]);
- const [qns, setQns] = useState();
- const [toggle, setToggle] = useState(false);
- const [isLoaded, setIsLoaded] = useState(false);
- const [toast, setToast] = useState({
- toastStatus: false,
- toastType: "",
- toastMessage: "",
- });
- const [confirmDelete, setConfirmDelete] = useState(false);
- const [questionToDelete, setQuestionToDelete] = useState(null);
- const classes = useStyles();
-
- const getQuestion = async (id) => {
- setIsLoaded(true);
- const qRes = await getQuestionById(id, setToast);
- setQns(qRes);
- setIsLoaded(false);
- };
-
- const handleOpenConfirmModal = (id) => {
- setConfirmDelete(true);
- setQuestionToDelete(id);
- };
-
- const handleCloseConfirmModal = () => {
- setConfirmDelete(false);
- };
-
- const handleDeleteAnswer = async (answerId) => {
- await deleteAnswer(answerId, setToast);
- setToggle(!toggle);
- };
-
- const handleDeleteQuestion = async () => {
- await deleteQuestion(questionToDelete, setToast);
- setConfirmDelete(false);
- setTab(18);
- setToggle(!toggle);
- };
-
- const updateQuestion = async (id, status) => {
- await updateQuestionStatus(id, status, setToast);
- setToggle(!toggle);
- };
-
- const getAnswer = async (questionId) => {
- setIsLoaded(true);
- const aRes = await getAnswers(questionId, setToast);
- setAns(aRes);
- setIsLoaded(false);
- };
-
- const updateAnswer = async (id, status) => {
- await updateAnswerStatus(id, status, setToast);
- setToggle(!toggle);
- };
-
- const handleCloseToast = (event, reason) => {
- if (reason === "clickaway") {
- return;
- }
- hideToast(setToast);
- };
-
- useEffect(() => {
- getQuestion(qId);
- getAnswer(qId);
- }, [toggle]);
-
- return (
-
-
Manage Q&A
-
-
{isLoaded && }
- {!isLoaded && (
- <>
-
Question
-
-
-
-
{qns?.title}
-
-
{qns?.description}
-
-
-
-
-
- {qns?.tags?.map((tag) => (
-
{tag}
- ))}
-
-
-
-
-
- >
- )}
-
Answers
- {ans?.length === 0 ? (
-
No answers Found
- ) : (
-
- {ans?.map((a) => (
-
-
-
-
{a.answer}
-
-
-
-
-
-
-
- ))}
-
- )}
-
-
-
Confirm Delete
-
Are you sure you want to delete this question and all its answers?
-
-
-
-
-
-
- {toast.toastStatus && (
-
- )}
-
- );
-}
diff --git a/frontend/src/pages/Admin/Components/Faq/Q&A/ManageQ&A/index.js b/frontend/src/pages/Admin/Components/Faq/Q&A/ManageQ&A/index.js
deleted file mode 100644
index 747c2843..00000000
--- a/frontend/src/pages/Admin/Components/Faq/Q&A/ManageQ&A/index.js
+++ /dev/null
@@ -1 +0,0 @@
-export * from "./ManageQ&A";
diff --git a/frontend/src/pages/Admin/Components/Faq/Q&A/ManageQ&A/manage.module.scss b/frontend/src/pages/Admin/Components/Faq/Q&A/ManageQ&A/manage.module.scss
deleted file mode 100644
index 11c431d3..00000000
--- a/frontend/src/pages/Admin/Components/Faq/Q&A/ManageQ&A/manage.module.scss
+++ /dev/null
@@ -1,146 +0,0 @@
-.card-item {
- text-align: center;
- font-size: 1.5rem;
- border-radius: 1em;
- height: auto;
- width: 90%;
- margin: 10px auto 30px auto;
- display: inline-block;
- background-position: left center;
- transition: all 0.5s ease-in;
- background-color: #016795;
- box-shadow: 0.5em 0.5em 0.5em rgb(54, 53, 53);
- max-width: 400px;
-}
-
-.card-title {
- font-size: 1.8rem;
- margin-bottom: 1.5rem;
- line-height: 1.9rem;
- font-weight: bold;
- color: white;
-}
-.question{
- display: flex;
- justify-content: center;
-}
-.card-question {
- font-weight: bold;
- text-align: left;
- font-size: 1.3rem;
- width: 100%;
- margin: 2px;
-}
-
-.card-answer {
- font-weight: 600;
- text-align: left;
- font-size: 1.2rem;
- width: 100%;
- margin: 2px;
-}
-
-.questionBox{
- display: grid;
- justify-content: center;
- margin: 5px;
- gap: 10px;
-}
-
-.answerBox{
- display: grid;
- justify-content: center;
- margin: 5px;
- gap: 10px;
-}
-
-.card-info {
- color: white;
- margin-top: 10px;
- margin-bottom: 20px;
- display: flex;
- flex-direction: column;
- padding: 14px;
-}
-
-.head {
- text-align: center;
-}
-
-.button-group {
- display: flex;
- width: 100%;
- align-items: center;
- justify-content: center;
- gap: 10px;
- margin: 5px 2px 2px 2px;
-}
-
-.button-approve {
- padding: 10px;
- border: none;
- outline: none;
- border-radius: 5px;
- background-color: rgb(6, 158, 41);
- margin: 5px;
- color: #fff;
- width: 120px;
- font-size: medium;
- font-weight: bold;
- transition: background-color 200ms;
-}
-
-.answer{
- display: grid;
- grid-template-columns: auto auto;
-}
-
-.button-edit:hover {
- background-color: rgb(10, 205, 53);
-}
-
-.button-delete {
- padding: 10px;
- border: none;
- outline: none;
- border-radius: 5px;
- background-color: #fc0254;
- margin: 5px;
- color: #fff;
- width: 120px;
- font-size: medium;
- font-weight: bold;
- transition: background-color 200ms;
- text-align: center;
-}
-
-.button-delete:hover {
- background-color: #fc3779;
-}
-
-.tags{
- background-color: gray;
- color: black;
- padding: 0px 4px;
- display: flex;
- justify-content: center;
- align-items: center;
- margin: 4px;
- height: 25px;
- margin-top: 0;
- border-radius: 10px;
- font-size: small;
-}
-@media (max-width:"900px") {
- .answerBox{
- display: block;
- }
- .questionBox{
- display: block;
- }
- .answer{
- display: flex;
- justify-content: center;
- flex-direction: column;
- }
-}
\ No newline at end of file
diff --git a/frontend/src/pages/Admin/Components/Faq/Q&A/QandA.jsx b/frontend/src/pages/Admin/Components/Faq/Q&A/QandA.jsx
index 8df877bb..8d4eb61d 100644
--- a/frontend/src/pages/Admin/Components/Faq/Q&A/QandA.jsx
+++ b/frontend/src/pages/Admin/Components/Faq/Q&A/QandA.jsx
@@ -1,26 +1,140 @@
import React, { useEffect, useState } from "react";
import style from "./qanda.module.scss";
-import { getAllQuestions } from "../../../../../service/Faq";
+import {
+ getAllQuestions,
+ deleteAnswer,
+ deleteQuestion,
+ updateQuestionStatus,
+ updateAnswerStatus,
+ getAnswers,
+} from "../../../../../service/Faq";
import { SimpleToast } from "../../../../../components/util/Toast/Toast";
import Loader from "../../../../../components/util/Loader";
-import { hideToast } from "../../../../../service/toastService";
+import { hideToast, showToast } from "../../../../../service/toastService";
+import Modal from "@material-ui/core/Modal";
+import Button from "@material-ui/core/Button";
+import Typography from "@material-ui/core/Typography";
+import { makeStyles } from "@material-ui/core/styles";
+import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
+import ExpandLessIcon from '@material-ui/icons/ExpandLess';
-export function QandA({ setTab, setQId, tab }) {
+const useStyles = makeStyles((theme) => ({
+ modal: {
+ display: "flex",
+ alignItems: "center",
+ justifyContent: "center",
+ },
+ paper: {
+ backgroundColor: theme.palette.background.paper,
+ border: "2px solid #000",
+ boxShadow: theme.shadows[5],
+ padding: theme.spacing(2, 4, 3),
+ },
+ buttons: {
+ display: "flex",
+ marginTop: "10px",
+ justifyContent: "center",
+ gap: "10px",
+ },
+}));
+
+export function QandA() {
const [cards, setCards] = useState([]);
+ const [expandedCards, setExpandedCards] = useState({});
const [isLoaded, setIsLoaded] = useState(false);
const [toast, setToast] = useState({
toastStatus: false,
toastType: "",
toastMessage: "",
});
+ const [confirmDelete, setConfirmDelete] = useState(false);
+ const [questionToDelete, setQuestionToDelete] = useState(null);
+ const classes = useStyles();
- const getdata = async () => {
+ const getQuestions = async () => {
setIsLoaded(true);
const data = await getAllQuestions(setToast, toast);
setCards(data);
setIsLoaded(false);
};
+ const handleOpenConfirmModal = (id) => {
+ setConfirmDelete(true);
+ setQuestionToDelete(id);
+ };
+
+ const handleCloseConfirmModal = () => {
+ setConfirmDelete(false);
+ setQuestionToDelete(null);
+ };
+
+ const handleDeleteQuestion = async () => {
+ await deleteQuestion(questionToDelete, setToast);
+ setCards(cards.filter(card => card._id !== questionToDelete));
+ setConfirmDelete(false);
+ };
+
+ const updateQuestion = async (id, status) => {
+ setCards(cards.map(card =>
+ card._id === id ? { ...card, isApproved: status } : card
+ ));
+
+ await updateQuestionStatus(id, status, setToast);
+ };
+
+ const handleDeleteAnswer = async (answerId) => {
+ const questionId = Object.keys(expandedCards)[0];
+ const prevAnswers = expandedCards[questionId]?.answers || [];
+
+ setExpandedCards((prev) => ({
+ ...prev,
+ [questionId]: {
+ ...prev[questionId],
+ answers: prevAnswers.filter(answer => answer._id !== answerId),
+ },
+ }));
+
+ await deleteAnswer(answerId, setToast);
+ };
+
+ const updateAnswer = async (id, status) => {
+ const questionId = Object.keys(expandedCards)[0];
+ const prevAnswers = expandedCards[questionId]?.answers || [];
+
+ setExpandedCards((prev) => ({
+ ...prev,
+ [questionId]: {
+ ...prev[questionId],
+ answers: prevAnswers.map(answer =>
+ answer._id === id ? { ...answer, isApproved: status } : answer
+ ),
+ },
+ }));
+
+ await updateAnswerStatus(id, status, setToast);
+ };
+
+ const handleToggleExpand = async (id) => {
+ if (expandedCards[id]) {
+ setExpandedCards((prev) => {
+ const newExpanded = { ...prev };
+ delete newExpanded[id];
+ return newExpanded;
+ });
+ } else {
+ setIsLoaded(true);
+ const aRes = await getAnswers(id, setToast);
+ setExpandedCards((prev) => ({
+ ...prev,
+ [id]: {
+ answers: aRes,
+ },
+ }));
+ setIsLoaded(false);
+ }
+ };
+
+
const handleCloseToast = (event, reason) => {
if (reason === "clickaway") {
return;
@@ -29,43 +143,97 @@ export function QandA({ setTab, setQId, tab }) {
};
useEffect(() => {
- getdata();
- }, [tab]);
+ getQuestions();
+ }, []);
return (
Manage Q&A
-
{isLoaded ? : null}
+
{isLoaded && }
- {cards?.map((d, index) => (
+ {cards?.map((qns, index) => (
-
{d.title}
-
-
{d.description}
-
+
{qns.title}
-
Status
{`${d.isApproved ? "Approved" : "Not Approved"}`}
+ {qns.description}
- {d.tags.map((tag, idx) => (
-
- {tag.value || tag}
-
- ))}
+
+ {qns?.tags?.map((tag) => (
+
{tag}
+ ))}
+
+
+
+
+
+ {expandedCards[qns._id] && (
+
+ {expandedCards[qns._id].answers?.length === 0 ? (
+
No answers Found
+ ) : (
+ expandedCards[qns._id].answers.map((a) => (
+
+
+
+
{a.answer}
+
+
+
+
+
+
+
+ ))
+ )}
+
+ )}
))}
+
+
+
Confirm Delete
+
Are you sure you want to delete this question and all its answers?
+
+
+
+
+
+
{toast.toastStatus && (
div > .tags {
- background-color: gray;
+.manage {
+ width: 120px;
+ background-color: white;
color: black;
- padding: 0px 4px;
- display: flex;
+ margin-bottom: 20px;
+ margin-top: 15px;
+ padding: 10px;
+ border: none;
+ border-radius: 5px;
+}
+
+.card-item {
+ text-align: center;
+ font-size: 1.5rem;
+ border-radius: 1em;
+ height: auto;
+ width: 90%;
+ margin: 10px auto 30px auto;
+ display: block;
+ background-position: left center;
+ transition: all 0.5s ease-in;
+ background-color: #016795;
+ box-shadow: 0.5em 0.5em 0.5em rgb(54, 53, 53);
+ max-width: 400px;
+}
+
+.card-answer {
+ font-weight: 600;
+ text-align: left;
+ font-size: 1.2rem;
+ width: 100%;
+ margin: 2px;
+}
+
+.questionBox {
+ display: grid;
+ justify-content: center;
+ margin: 5px;
+ gap: 10px;
+}
+
+.answerBox {
+ display: grid;
justify-content: center;
+ margin: 5px;
+ gap: 10px;
+}
+
+.card-info {
+ color: white;
+ margin-top: 10px;
+ margin-bottom: 20px;
+ display: flex;
+ flex-direction: column;
+ padding: 14px;
+}
+
+.button-group {
+ display: flex;
+ width: 100%;
align-items: center;
- margin: 4px;
- height: 18px;
- margin-top: 0;
- border-radius: 10px;
- font-size: x-small;
+ justify-content: center;
+ gap: 10px;
+ margin: 5px 2px 2px 2px;
}
-.manage{
+.button-approve {
+ padding: 10px;
+ border: none;
+ outline: none;
+ border-radius: 5px;
+ background-color: rgb(6, 158, 41);
+ margin: 5px;
+ color: #fff;
width: 120px;
- background-color: white;
- color: black;
- margin-bottom: 20px;
- margin-top: 15px;
+ font-size: medium;
+ font-weight: bold;
+ transition: background-color 200ms;
+}
+
+.button-delete {
padding: 10px;
border: none;
+ outline: none;
border-radius: 5px;
+ background-color: #fc0254;
+ margin: 5px;
+ color: #fff;
+ width: 120px;
+ font-size: medium;
+ font-weight: bold;
+ transition: background-color 200ms;
+ text-align: center;
+}
+
+.button-delete:hover {
+ background-color: #fc3779;
+}
+
+.tags {
+ background-color: gainsboro;
+ color: black;
+ padding: 0px 4px;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ margin: 4px;
+ height: 25px;
+ margin-top: 0;
+ border-radius: 4px;
+ font-size: small;
+}
+
+@media (max-width: 900px) {
+ .answerBox {
+ display: block;
+ }
+ .questionBox {
+ display: block;
+ }
+ .answer {
+ display: flex;
+ justify-content: center;
+ flex-direction: column;
+ }
}