From e66d5dbeaaac7af900989654f51dcff8c202a91c Mon Sep 17 00:00:00 2001 From: Hemu21 Date: Fri, 17 May 2024 00:10:46 +0530 Subject: [PATCH 1/6] Frontend Admin Q&A completed --- backend/app/routes/Q&A/answers/index.js | 2 +- frontend/src/pages/Admin/Admin.jsx | 8 +- .../src/pages/Admin/Components/Faq/Faq.jsx | 13 ++ .../Faq/Q&A/ManageQ&A/ManageQ&A.jsx | 131 ++++++++++++++++++ .../Components/Faq/Q&A/ManageQ&A/index.js | 1 + .../Faq/Q&A/ManageQ&A/manage.module.scss | 125 +++++++++++++++++ .../pages/Admin/Components/Faq/Q&A/QandA.jsx | 60 ++++++++ .../pages/Admin/Components/Faq/Q&A/index.js | 1 + .../Components/Faq/Q&A/qanda.module.scss | 104 ++++++++++++++ 9 files changed, 443 insertions(+), 2 deletions(-) create mode 100644 frontend/src/pages/Admin/Components/Faq/Q&A/ManageQ&A/ManageQ&A.jsx create mode 100644 frontend/src/pages/Admin/Components/Faq/Q&A/ManageQ&A/index.js create mode 100644 frontend/src/pages/Admin/Components/Faq/Q&A/ManageQ&A/manage.module.scss create mode 100644 frontend/src/pages/Admin/Components/Faq/Q&A/QandA.jsx create mode 100644 frontend/src/pages/Admin/Components/Faq/Q&A/index.js create mode 100644 frontend/src/pages/Admin/Components/Faq/Q&A/qanda.module.scss diff --git a/backend/app/routes/Q&A/answers/index.js b/backend/app/routes/Q&A/answers/index.js index 104cece4..0984a1ba 100644 --- a/backend/app/routes/Q&A/answers/index.js +++ b/backend/app/routes/Q&A/answers/index.js @@ -12,7 +12,7 @@ const updateAnswerStatus = require('./updateAnswerStatus'); router.post('/', validation(answerValidationSchema), postAnswer); // GET API FOR ANSWERS -router.get('/:questionId', validation(getAnswerValidationSchema), getAnswers); +router.get('/:questionId', getAnswers); // INCREASE UPVOTE FOR ANSWERS router.patch('/upvote', upvoteAnswer); diff --git a/frontend/src/pages/Admin/Admin.jsx b/frontend/src/pages/Admin/Admin.jsx index 1769f666..ceeefd0d 100644 --- a/frontend/src/pages/Admin/Admin.jsx +++ b/frontend/src/pages/Admin/Admin.jsx @@ -23,6 +23,8 @@ import decode from "jwt-decode"; 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"; export const Admin = (props) => { const [tab, setTab] = useState(1); @@ -31,7 +33,7 @@ export const Admin = (props) => { const closeMobileMenu = () => setIsMenuOpen(false); const dispatch = useDispatch(); const firstName = localStorage.getItem("firstName"); - + const [qId,setQId] = useState("") useEffect(() => { const token = localStorage.getItem("token"); try { @@ -223,6 +225,10 @@ export const Admin = (props) => { ) : tab === 16 ? ( + ) : tab === 18 ? ( + + ) : tab === 19 ? ( + ) : null} diff --git a/frontend/src/pages/Admin/Components/Faq/Faq.jsx b/frontend/src/pages/Admin/Components/Faq/Faq.jsx index 38650129..0738778d 100644 --- a/frontend/src/pages/Admin/Components/Faq/Faq.jsx +++ b/frontend/src/pages/Admin/Components/Faq/Faq.jsx @@ -40,6 +40,19 @@ export function Faq(props) { +
+
+
+ MANAGE Q&A + +
+
+
props.setTab(18)} className={style["main-btn"]}> + Manage here +
+
+
+
); 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 new file mode 100644 index 00000000..f4b793ca --- /dev/null +++ b/frontend/src/pages/Admin/Components/Faq/Q&A/ManageQ&A/ManageQ&A.jsx @@ -0,0 +1,131 @@ +import { useEffect, useState } from "react"; +import { END_POINT } from "../../../../../../config/api"; +import style from "./manage.module.scss"; +import { AiOutlineArrowLeft } from "react-icons/ai"; + +export function Manageqa({ setTab, qId }) { + const [ans, setAns] = useState([]); + const [qns, setQns] = useState(); + const [toogle, setToogle] = useState(false); + const getQuestion = async (id) => { + try { + const qUrl = `${END_POINT}/question/getQuestionById/${id}`; + const qResponse = await fetch(qUrl); + const qRes = await qResponse.json(); + setQns(qRes); + } catch (error) { + console.log(error); + } + }; + const updateQuestion = async (id, status) => { + try { + const qUrl = `${END_POINT}/question/updateStatus`; + const qResponse = await fetch(qUrl, { + method: "PATCH", + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${localStorage.getItem("token")}`, + }, + body: JSON.stringify({ id: id, status: status }), + }); + const qRes = await qResponse.json(); + setToogle(!toogle); + } catch (error) { + console.log(error); + } + }; + const getAnswer = async (questionId) => { + try { + const aUrl = `${END_POINT}/answers/${questionId}`; + const aResponse = await fetch(aUrl); + const aRes = await aResponse.json(); + setAns(aRes.data); + } catch (error) { + console.log(error); + alert("Failed to fetch!"); + } + }; + const updateAnswer = async (id, status) => { + try { + const aUrl = `${END_POINT}/answers/updateStatus`; + const aResponse = await fetch(aUrl, { + method: "PATCH", + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${localStorage.getItem("token")}`, + }, + body: JSON.stringify({ id: id, status: status }), + }); + const aRes = await aResponse.json(); + setToogle(!toogle); + } catch (error) { + console.log(error); + alert("Failed to fetch!"); + } + }; + useEffect(() => { + getQuestion(qId); + getAnswer(qId); + }, [toogle]); + return ( +
+
+ setTab(18)} /> +
+
+
+

{qns?.title}

+
+

{qns?.description}

+
+ + +
+
+ + {ans?.map((a) => ( +
+

{a.answer}

+
+ + +
+
+ ))} + +
+ {qns?.tags?.map((tag) => ( +

{tag}

+ ))} +
+
+
+
+ ); +} 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 new file mode 100644 index 00000000..747c2843 --- /dev/null +++ b/frontend/src/pages/Admin/Components/Faq/Q&A/ManageQ&A/index.js @@ -0,0 +1 @@ +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 new file mode 100644 index 00000000..b64c1e6a --- /dev/null +++ b/frontend/src/pages/Admin/Components/Faq/Q&A/ManageQ&A/manage.module.scss @@ -0,0 +1,125 @@ +.card-item { + text-align: center; + font-size: 1.5rem; + border-radius: 1em; + height: auto; + width: 90%; + margin: 10px auto 30px 4%; + 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); +} + +.card-title { + font-size: 1.8rem; + margin-bottom: 1.5rem; + line-height: 1.9rem; + font-weight: bold; + color: white; +} + +.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: flex; + margin: 5px; +} + +.answerBox{ + display: flex; + margin: 5px; +} + +.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; + justify-content: center; + gap: 10px; + margin: 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; +} + +.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; + } +} \ 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 new file mode 100644 index 00000000..8e0129b6 --- /dev/null +++ b/frontend/src/pages/Admin/Components/Faq/Q&A/QandA.jsx @@ -0,0 +1,60 @@ +import React, { useEffect, useState } from "react"; +import style from "./qanda.module.scss"; +import { END_POINT } from "../../../../../config/api"; + +export function QandA({ setTab, setQId, tab }) { + const [cards, setCards] = useState([]); + const getdata = async () => { + try { + const url = `${END_POINT}/question/getallquestions`; + const response = await fetch(url, { + method: "GET", + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${localStorage.getItem("token")}`, + }, + }); + const res = await response.json(); + setCards(res); + } catch (error) { + console.log(error); + alert("Failed to fetch!"); + } + }; + useEffect(() => { + getdata(); + }, [tab]); + return ( +
+

Question

+
+ {cards?.map((d, index) => ( +
+

{d.title}

+
+

{d.description}

+
+
+
Status
{`${d.isApproved ? "Approved" : "Not Approved"}`} +
+
+ {d.tags.map((tag) => ( +

{tag}

+ ))} +
+ +
+ ))} +
+
+ ); +} diff --git a/frontend/src/pages/Admin/Components/Faq/Q&A/index.js b/frontend/src/pages/Admin/Components/Faq/Q&A/index.js new file mode 100644 index 00000000..1e295fa6 --- /dev/null +++ b/frontend/src/pages/Admin/Components/Faq/Q&A/index.js @@ -0,0 +1 @@ +export * from "./QandA"; diff --git a/frontend/src/pages/Admin/Components/Faq/Q&A/qanda.module.scss b/frontend/src/pages/Admin/Components/Faq/Q&A/qanda.module.scss new file mode 100644 index 00000000..3310ea36 --- /dev/null +++ b/frontend/src/pages/Admin/Components/Faq/Q&A/qanda.module.scss @@ -0,0 +1,104 @@ +.head { + text-align: center; +} + +.manage-qas { + display: grid; + grid-template-columns: auto auto; + gap: 20px; + margin: 2em; + height: auto; +} + +.content { + overflow: hidden; + padding: 10px 20px; + font-size: 18px; + line-height: 1.2; + text-align: center; +} + +.crd { + min-width: 100px; + max-width: 470px; + min-height: 12em; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + background-color: #016795; + box-shadow: rgba(141, 113, 113, 0.24) 0px 3px 8px; + cursor: pointer; + color: white; + border-radius: 20px; +} + +.crd:hover { + color: white; + background: #1b2431; +} + +.crd > .head1 { + display: flex; + justify-content: center; + align-items: center; + font-size: 1em; + margin: 0.5em; +} + +.crd > .head1 > h4 { + margin: 0 1em; + font-size: 24px; + font-weight: bold; +} + +@media (max-width: 983px) { + .manage-teams { + grid-template-columns: auto; + margin: 1em 0; + justify-content: center; + } + + .conts { + width: 90%; + } + .crd{ + max-width: 400px; + } + .content { + overflow-wrap: break-word; + padding: 1rem 1.2rem; + } +} + +@media screen and (min-width: 600px) and (max-width: 1050px) { + .content { + overflow: hidden; + padding: 1.5rem 3.5rem; + } +} + +.crd > div > .tags { + background-color: gray; + color: black; + padding: 0px 4px; + display: flex; + justify-content: center; + align-items: center; + margin: 4px; + height: 18px; + margin-top: 0; + border-radius: 10px; + font-size: x-small; +} + +.manage{ + width: 120px; + background-color: white; + color: black; + margin-bottom: 20px; + margin-top: 15px; + padding: 10px; + border: none; + border-radius: 5px; +} From be9db8f54ca0d26f0442d4381d807d34c2e910c0 Mon Sep 17 00:00:00 2001 From: Hemu21 Date: Fri, 17 May 2024 14:06:12 +0530 Subject: [PATCH 2/6] changes --- frontend/src/pages/Admin/Admin.jsx | 6 - .../src/pages/Admin/Components/Faq/Faq.jsx | 2 +- .../Faq/Q&A/ManageQ&A/ManageQ&A.jsx | 131 -------------- .../Components/Faq/Q&A/ManageQ&A/index.js | 1 - .../Faq/Q&A/ManageQ&A/manage.module.scss | 125 -------------- .../pages/Admin/Components/Faq/Q&A/QandA.jsx | 161 +++++++++++++++--- .../Components/Faq/Q&A/qanda.module.scss | 51 +++++- 7 files changed, 190 insertions(+), 287 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 ceeefd0d..980e381a 100644 --- a/frontend/src/pages/Admin/Admin.jsx +++ b/frontend/src/pages/Admin/Admin.jsx @@ -23,8 +23,6 @@ import decode from "jwt-decode"; 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"; export const Admin = (props) => { const [tab, setTab] = useState(1); @@ -225,10 +223,6 @@ export const Admin = (props) => { ) : tab === 16 ? ( - ) : tab === 18 ? ( - - ) : tab === 19 ? ( - ) : null} diff --git a/frontend/src/pages/Admin/Components/Faq/Faq.jsx b/frontend/src/pages/Admin/Components/Faq/Faq.jsx index 0738778d..8c17f678 100644 --- a/frontend/src/pages/Admin/Components/Faq/Faq.jsx +++ b/frontend/src/pages/Admin/Components/Faq/Faq.jsx @@ -7,7 +7,7 @@ import { Link } from "react-router-dom"; export function Faq(props) { return (
-

FAQS

+

FAQs and Q&As

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 f4b793ca..00000000 --- a/frontend/src/pages/Admin/Components/Faq/Q&A/ManageQ&A/ManageQ&A.jsx +++ /dev/null @@ -1,131 +0,0 @@ -import { useEffect, useState } from "react"; -import { END_POINT } from "../../../../../../config/api"; -import style from "./manage.module.scss"; -import { AiOutlineArrowLeft } from "react-icons/ai"; - -export function Manageqa({ setTab, qId }) { - const [ans, setAns] = useState([]); - const [qns, setQns] = useState(); - const [toogle, setToogle] = useState(false); - const getQuestion = async (id) => { - try { - const qUrl = `${END_POINT}/question/getQuestionById/${id}`; - const qResponse = await fetch(qUrl); - const qRes = await qResponse.json(); - setQns(qRes); - } catch (error) { - console.log(error); - } - }; - const updateQuestion = async (id, status) => { - try { - const qUrl = `${END_POINT}/question/updateStatus`; - const qResponse = await fetch(qUrl, { - method: "PATCH", - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${localStorage.getItem("token")}`, - }, - body: JSON.stringify({ id: id, status: status }), - }); - const qRes = await qResponse.json(); - setToogle(!toogle); - } catch (error) { - console.log(error); - } - }; - const getAnswer = async (questionId) => { - try { - const aUrl = `${END_POINT}/answers/${questionId}`; - const aResponse = await fetch(aUrl); - const aRes = await aResponse.json(); - setAns(aRes.data); - } catch (error) { - console.log(error); - alert("Failed to fetch!"); - } - }; - const updateAnswer = async (id, status) => { - try { - const aUrl = `${END_POINT}/answers/updateStatus`; - const aResponse = await fetch(aUrl, { - method: "PATCH", - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${localStorage.getItem("token")}`, - }, - body: JSON.stringify({ id: id, status: status }), - }); - const aRes = await aResponse.json(); - setToogle(!toogle); - } catch (error) { - console.log(error); - alert("Failed to fetch!"); - } - }; - useEffect(() => { - getQuestion(qId); - getAnswer(qId); - }, [toogle]); - return ( -
-
- setTab(18)} /> -
-
-
-

{qns?.title}

-
-

{qns?.description}

-
- - -
-
- - {ans?.map((a) => ( -
-

{a.answer}

-
- - -
-
- ))} - -
- {qns?.tags?.map((tag) => ( -

{tag}

- ))} -
-
-
-
- ); -} 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 b64c1e6a..00000000 --- a/frontend/src/pages/Admin/Components/Faq/Q&A/ManageQ&A/manage.module.scss +++ /dev/null @@ -1,125 +0,0 @@ -.card-item { - text-align: center; - font-size: 1.5rem; - border-radius: 1em; - height: auto; - width: 90%; - margin: 10px auto 30px 4%; - 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); -} - -.card-title { - font-size: 1.8rem; - margin-bottom: 1.5rem; - line-height: 1.9rem; - font-weight: bold; - color: white; -} - -.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: flex; - margin: 5px; -} - -.answerBox{ - display: flex; - margin: 5px; -} - -.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; - justify-content: center; - gap: 10px; - margin: 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; -} - -.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; - } -} \ 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 8e0129b6..1ca5e0f9 100644 --- a/frontend/src/pages/Admin/Components/Faq/Q&A/QandA.jsx +++ b/frontend/src/pages/Admin/Components/Faq/Q&A/QandA.jsx @@ -1,60 +1,177 @@ import React, { useEffect, useState } from "react"; import style from "./qanda.module.scss"; import { END_POINT } from "../../../../../config/api"; +import Loader from "../../../../../components/util/Loader"; +import { SimpleToast } from "../../../../../components/util/Toast/Toast"; export function QandA({ setTab, setQId, tab }) { const [cards, setCards] = useState([]); + const [questions, setQuestions] = useState([]); + const [isLoaded, setIsLoaded] = useState(false); + const [toogle, setToogle] = useState(false); + const [toast, setToast] = useState({ + toastStatus: false, + toastType: "", + toastMessage: "", + }); + const getdata = async () => { + setIsLoaded(true); try { const url = `${END_POINT}/question/getallquestions`; - const response = await fetch(url, { - method: "GET", + const response = await fetch(url); + const res = await response?.json(); + setQuestions(res); + } catch (error) { + console.log(error); + toast({ + ...toast, + toastMessage: "Check network failed to fetch", + toastStatus: true, + toastType: "error", + }); + } + }; + + useEffect(() => { + getdata(); + }, [toogle]); + + useEffect(() => { + const getData = async () => { + try { + let answer = []; + for (let index = 0; index < questions.length; index++) { + const element = questions[index]; + const res = await getAnswer(element); + res.map((item) => answer.push(item)); + } + setIsLoaded(false); + setCards([...questions, ...answer]); + } catch (error) { + console.log(error); + } + }; + + if (questions.length) { + getData(); + } + }, [questions]); + const updateQA = async (id, status) => { + try { + const aUrl = `${END_POINT}/answers/updateStatus`; + const aResponse = await fetch(aUrl, { + method: "PATCH", headers: { "Content-Type": "application/json", Authorization: `Bearer ${localStorage.getItem("token")}`, }, + body: JSON.stringify({ id: id, status: status }), + }); + const aRes = await aResponse.json(); + setToogle(!toogle); + setToast({ + ...toast, + toastMessage: "Successfully Updated!", + toastStatus: true, + toastType: "success", }); - const res = await response.json(); - setCards(res); + } catch (error) { + try { + const aUrl = `${END_POINT}/question/updateStatus`; + const aResponse = await fetch(aUrl, { + method: "PATCH", + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${localStorage.getItem("token")}`, + }, + body: JSON.stringify({ id: id, status: status }), + }); + const aRes = await aResponse.json(); + setToogle(!toogle); + setToast({ + ...toast, + toastMessage: "Successfully Updated!", + toastStatus: true, + toastType: "success", + }); + } catch (error) { + setToast({ + ...toast, + toastMessage: "Failed to Update!", + toastStatus: true, + toastType: "error", + }); + } + } + }; + + const getAnswer = async (data) => { + try { + const url = `${END_POINT}/answers/${data._id}`; + const res = await fetch(url); + const _res = await res.json(); + return _res.data; } catch (error) { console.log(error); - alert("Failed to fetch!"); } }; - useEffect(() => { - getdata(); - }, [tab]); + + const handleCloseToast = (event, reason) => { + if (reason === "clickaway") { + return; + } + setToast({ ...toast, toastStatus: false }); + }; + return (
-

Question

+

Manage Q&A

+
{isLoaded ? : null}
{cards?.map((d, index) => (
-

{d.title}

+

{d?.title}

-

{d.description}

+

+ {d?.description || d?.answer} +

Status
{`${d.isApproved ? "Approved" : "Not Approved"}`}
- {d.tags.map((tag) => ( + {d?.tags?.map((tag) => (

{tag}

))}
- +
+ + +
))}
+ {toast.toastStatus && ( + + )}
); } diff --git a/frontend/src/pages/Admin/Components/Faq/Q&A/qanda.module.scss b/frontend/src/pages/Admin/Components/Faq/Q&A/qanda.module.scss index 3310ea36..d819ce15 100644 --- a/frontend/src/pages/Admin/Components/Faq/Q&A/qanda.module.scss +++ b/frontend/src/pages/Admin/Components/Faq/Q&A/qanda.module.scss @@ -51,14 +51,63 @@ font-size: 24px; font-weight: bold; } +.button-group { + display: flex; + width: 100%; + align-items: center; + justify-content: center; + gap: 10px; + margin: 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; +} + +.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; +} @media (max-width: 983px) { .manage-teams { grid-template-columns: auto; margin: 1em 0; justify-content: center; } - + .answerBox{ + display: block; + } + .questionBox{ + display: block; + } .conts { width: 90%; } From b8639bb5b626d7ab540ac1ab204a2cf1f9ad9a3a Mon Sep 17 00:00:00 2001 From: Hemu21 Date: Fri, 17 May 2024 14:08:44 +0530 Subject: [PATCH 3/6] changed as per guidence --- frontend/src/pages/Admin/Admin.jsx | 3 +++ frontend/src/pages/Admin/Components/Faq/Q&A/QandA.jsx | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/frontend/src/pages/Admin/Admin.jsx b/frontend/src/pages/Admin/Admin.jsx index 63f2699d..dd6b6e93 100644 --- a/frontend/src/pages/Admin/Admin.jsx +++ b/frontend/src/pages/Admin/Admin.jsx @@ -24,6 +24,7 @@ import axios from "axios"; 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"; export const Admin = (props) => { const [tab, setTab] = useState(1); @@ -245,6 +246,8 @@ export const Admin = (props) => { ) : tab === 16 ? ( + ) : tab === 18 ? ( + ) : null}
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 1ca5e0f9..b91684c8 100644 --- a/frontend/src/pages/Admin/Components/Faq/Q&A/QandA.jsx +++ b/frontend/src/pages/Admin/Components/Faq/Q&A/QandA.jsx @@ -4,7 +4,7 @@ import { END_POINT } from "../../../../../config/api"; import Loader from "../../../../../components/util/Loader"; import { SimpleToast } from "../../../../../components/util/Toast/Toast"; -export function QandA({ setTab, setQId, tab }) { +export function QandA() { const [cards, setCards] = useState([]); const [questions, setQuestions] = useState([]); const [isLoaded, setIsLoaded] = useState(false); From 8eda3709b086610ed1676ceb22d48510c06cf692 Mon Sep 17 00:00:00 2001 From: Hemu21 Date: Fri, 17 May 2024 14:36:35 +0530 Subject: [PATCH 4/6] changed as per guidence --- .../src/pages/Admin/Components/Faq/Q&A/QandA.jsx | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) 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 b91684c8..099f6da8 100644 --- a/frontend/src/pages/Admin/Components/Faq/Q&A/QandA.jsx +++ b/frontend/src/pages/Admin/Components/Faq/Q&A/QandA.jsx @@ -44,16 +44,24 @@ export function QandA() { for (let index = 0; index < questions.length; index++) { const element = questions[index]; const res = await getAnswer(element); - res.map((item) => answer.push(item)); + if(res!=undefined){ + res?.map((item) => answer.push(item)); + } } setIsLoaded(false); - setCards([...questions, ...answer]); + if(answer.length){ + setCards([...questions, ...answer]); + }else{ + setCards(questions); + } + } catch (error) { console.log(error); + setIsLoaded(false) } }; - if (questions.length) { + if (questions?.length) { getData(); } }, [questions]); From c21381af4607839cb2410bf62f1fbb5560d73b86 Mon Sep 17 00:00:00 2001 From: Hemu21 Date: Fri, 17 May 2024 18:32:33 +0530 Subject: [PATCH 5/6] back --- frontend/src/pages/Admin/Admin.jsx | 7 +- .../Faq/Q&A/ManageQ&A/ManageQ&A.jsx | 193 ++++++++++++++++++ .../Components/Faq/Q&A/ManageQ&A/index.js | 1 + .../Faq/Q&A/ManageQ&A/manage.module.scss | 128 ++++++++++++ .../pages/Admin/Components/Faq/Q&A/QandA.jsx | 150 +++----------- .../Components/Faq/Q&A/qanda.module.scss | 51 +---- 6 files changed, 353 insertions(+), 177 deletions(-) create mode 100644 frontend/src/pages/Admin/Components/Faq/Q&A/ManageQ&A/ManageQ&A.jsx create mode 100644 frontend/src/pages/Admin/Components/Faq/Q&A/ManageQ&A/index.js create 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 dd6b6e93..cf26fab2 100644 --- a/frontend/src/pages/Admin/Admin.jsx +++ b/frontend/src/pages/Admin/Admin.jsx @@ -25,6 +25,7 @@ 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"; export const Admin = (props) => { const [tab, setTab] = useState(1); @@ -176,7 +177,7 @@ export const Admin = (props) => { className="fas fa-question fa-fw fa-lg" aria-hidden="true" > -
FAQs
+
FAQs and Q&As
  • @@ -247,7 +248,9 @@ export const Admin = (props) => { ) : tab === 16 ? ( ) : tab === 18 ? ( - + + ) : tab === 19 ? ( + ) : null}
  • 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 new file mode 100644 index 00000000..d9bf7ed8 --- /dev/null +++ b/frontend/src/pages/Admin/Components/Faq/Q&A/ManageQ&A/ManageQ&A.jsx @@ -0,0 +1,193 @@ +import { useEffect, useState } from "react"; +import { END_POINT } from "../../../../../../config/api"; +import style from "./manage.module.scss"; +import { AiOutlineArrowLeft } from "react-icons/ai"; +import { SimpleToast } from "../../../../../../components/util/Toast/Toast"; +import Loader from "../../../../../../components/util/Loader"; + +export function Manageqa({ setTab, qId }) { + const [ans, setAns] = useState([]); + const [qns, setQns] = useState(); + const [toogle, setToogle] = useState(false); + const [isLoaded,setIsLoaded] = useState(false); + const [toast, setToast] = useState({ + toastStatus: false, + toastType: "", + toastMessage: "", + }); + const getQuestion = async (id) => { + setIsLoaded(true) + try { + const qUrl = `${END_POINT}/question/getQuestionById/${id}`; + const qResponse = await fetch(qUrl); + const qRes = await qResponse.json(); + setQns(qRes); + } catch (error) { + console.log(error); + setIsLoaded(false) + setToast({ + ...toast, + toastMessage: "Check network failed to fetch", + toastStatus: true, + toastType: "error", + }); + } + }; + const updateQuestion = async (id, status) => { + try { + const qUrl = `${END_POINT}/question/updateStatus`; + const qResponse = await fetch(qUrl, { + method: "PATCH", + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${localStorage.getItem("token")}`, + }, + body: JSON.stringify({ id: id, status: status }), + }); + const qRes = await qResponse.json(); + setToogle(!toogle); + setToast({ + ...toast, + toastMessage: "Updated Successfully!", + toastStatus: true, + toastType: "success", + }); + } catch (error) { + console.log(error); + setToast({ + ...toast, + toastMessage: "Check network failed to update", + toastStatus: true, + toastType: "error", + }); + } + }; + const getAnswer = async (questionId) => { + try { + const aUrl = `${END_POINT}/answers/${questionId}`; + const aResponse = await fetch(aUrl); + const aRes = await aResponse.json(); + setAns(aRes.data); + setIsLoaded(false) + } catch (error) { + console.log(error); + setIsLoaded(false) + setToast({ + ...toast, + toastMessage: "Check network failed to fetch", + toastStatus: true, + toastType: "error", + }); + } + }; + const updateAnswer = async (id, status) => { + try { + const aUrl = `${END_POINT}/answers/updateStatus`; + const aResponse = await fetch(aUrl, { + method: "PATCH", + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${localStorage.getItem("token")}`, + }, + body: JSON.stringify({ id: id, status: status }), + }); + const aRes = await aResponse.json(); + setToogle(!toogle); + setToast({ + ...toast, + toastMessage: "Updated successfully", + toastStatus: true, + toastType: "success", + }); + } catch (error) { + console.log(error); + setToast({ + ...toast, + toastMessage: "Check network failed to Update", + toastStatus: true, + toastType: "error", + }); + } + }; + const handleCloseToast = (event, reason) => { + if (reason === "clickaway") { + return; + } + setToast({ ...toast, toastStatus: false }); + }; + useEffect(() => { + getQuestion(qId); + getAnswer(qId); + }, [toogle]); + return ( +
    +

    Manage Q&A

    +
    + setTab(18)} /> +
    +
    {isLoaded ? : null}
    + {isLoaded ||
    +
    +

    {qns?.title}

    +
    +

    {qns?.description}

    +
    + + +
    +
    + + {ans?.map((a) => ( +
    +

    {a.answer}

    +
    + + +
    +
    + ))} + +
    + {qns?.tags?.map((tag) => ( +

    {tag}

    + ))} +
    +
    +
    } + {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 new file mode 100644 index 00000000..747c2843 --- /dev/null +++ b/frontend/src/pages/Admin/Components/Faq/Q&A/ManageQ&A/index.js @@ -0,0 +1 @@ +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 new file mode 100644 index 00000000..ee02bb11 --- /dev/null +++ b/frontend/src/pages/Admin/Components/Faq/Q&A/ManageQ&A/manage.module.scss @@ -0,0 +1,128 @@ +.card-item { + text-align: center; + font-size: 1.5rem; + border-radius: 1em; + height: auto; + width: 90%; + margin: 10px auto 30px 4%; + 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); +} + +.card-title { + font-size: 1.8rem; + margin-bottom: 1.5rem; + line-height: 1.9rem; + font-weight: bold; + color: white; +} + +.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: flex; + margin: 5px; +} + +.answerBox{ + display: flex; + margin: 5px; +} + +.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: 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; +} + +.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; + } +} \ 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 099f6da8..0c0fef96 100644 --- a/frontend/src/pages/Admin/Components/Faq/Q&A/QandA.jsx +++ b/frontend/src/pages/Admin/Components/Faq/Q&A/QandA.jsx @@ -1,137 +1,45 @@ import React, { useEffect, useState } from "react"; import style from "./qanda.module.scss"; import { END_POINT } from "../../../../../config/api"; -import Loader from "../../../../../components/util/Loader"; import { SimpleToast } from "../../../../../components/util/Toast/Toast"; +import Loader from "../../../../../components/util/Loader"; -export function QandA() { +export function QandA({ setTab, setQId, tab }) { const [cards, setCards] = useState([]); - const [questions, setQuestions] = useState([]); - const [isLoaded, setIsLoaded] = useState(false); - const [toogle, setToogle] = useState(false); + const [isLoaded,setIsLoaded] = useState(false) const [toast, setToast] = useState({ toastStatus: false, toastType: "", toastMessage: "", }); - const getdata = async () => { - setIsLoaded(true); + setIsLoaded(true) try { const url = `${END_POINT}/question/getallquestions`; const response = await fetch(url); - const res = await response?.json(); - setQuestions(res); + const res = await response.json(); + setCards(res); } catch (error) { console.log(error); - toast({ + setToast({ ...toast, toastMessage: "Check network failed to fetch", toastStatus: true, toastType: "error", }); + } + setIsLoaded(false) }; - - useEffect(() => { - getdata(); - }, [toogle]); - - useEffect(() => { - const getData = async () => { - try { - let answer = []; - for (let index = 0; index < questions.length; index++) { - const element = questions[index]; - const res = await getAnswer(element); - if(res!=undefined){ - res?.map((item) => answer.push(item)); - } - } - setIsLoaded(false); - if(answer.length){ - setCards([...questions, ...answer]); - }else{ - setCards(questions); - } - - } catch (error) { - console.log(error); - setIsLoaded(false) - } - }; - - if (questions?.length) { - getData(); - } - }, [questions]); - const updateQA = async (id, status) => { - try { - const aUrl = `${END_POINT}/answers/updateStatus`; - const aResponse = await fetch(aUrl, { - method: "PATCH", - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${localStorage.getItem("token")}`, - }, - body: JSON.stringify({ id: id, status: status }), - }); - const aRes = await aResponse.json(); - setToogle(!toogle); - setToast({ - ...toast, - toastMessage: "Successfully Updated!", - toastStatus: true, - toastType: "success", - }); - } catch (error) { - try { - const aUrl = `${END_POINT}/question/updateStatus`; - const aResponse = await fetch(aUrl, { - method: "PATCH", - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${localStorage.getItem("token")}`, - }, - body: JSON.stringify({ id: id, status: status }), - }); - const aRes = await aResponse.json(); - setToogle(!toogle); - setToast({ - ...toast, - toastMessage: "Successfully Updated!", - toastStatus: true, - toastType: "success", - }); - } catch (error) { - setToast({ - ...toast, - toastMessage: "Failed to Update!", - toastStatus: true, - toastType: "error", - }); - } - } - }; - - const getAnswer = async (data) => { - try { - const url = `${END_POINT}/answers/${data._id}`; - const res = await fetch(url); - const _res = await res.json(); - return _res.data; - } catch (error) { - console.log(error); - } - }; - const handleCloseToast = (event, reason) => { if (reason === "clickaway") { return; } setToast({ ...toast, toastStatus: false }); }; - + useEffect(() => { + getdata(); + }, [tab]); return (

    Manage Q&A

    @@ -139,36 +47,28 @@ export function QandA() {
    {cards?.map((d, index) => (
    -

    {d?.title}

    +

    {d.title}

    -

    - {d?.description || d?.answer} -

    +

    {d.description}

    Status
    {`${d.isApproved ? "Approved" : "Not Approved"}`}
    - {d?.tags?.map((tag) => ( + {d.tags.map((tag) => (

    {tag}

    ))}
    -
    - - -
    +
    ))}
    diff --git a/frontend/src/pages/Admin/Components/Faq/Q&A/qanda.module.scss b/frontend/src/pages/Admin/Components/Faq/Q&A/qanda.module.scss index d819ce15..3310ea36 100644 --- a/frontend/src/pages/Admin/Components/Faq/Q&A/qanda.module.scss +++ b/frontend/src/pages/Admin/Components/Faq/Q&A/qanda.module.scss @@ -51,63 +51,14 @@ font-size: 24px; font-weight: bold; } -.button-group { - display: flex; - width: 100%; - align-items: center; - justify-content: center; - gap: 10px; - margin: 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; -} - -.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; -} @media (max-width: 983px) { .manage-teams { grid-template-columns: auto; margin: 1em 0; justify-content: center; } - .answerBox{ - display: block; - } - .questionBox{ - display: block; - } + .conts { width: 90%; } From d25be9f988c79cb7bd1def3b0a2619c137aaa7fb Mon Sep 17 00:00:00 2001 From: Hemu21 Date: Fri, 17 May 2024 20:23:46 +0530 Subject: [PATCH 6/6] toast --- .../Faq/Q&A/ManageQ&A/ManageQ&A.jsx | 106 +++++++++++------- 1 file changed, 63 insertions(+), 43 deletions(-) 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 index d9bf7ed8..b9305fd1 100644 --- 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 @@ -9,22 +9,28 @@ export function Manageqa({ setTab, qId }) { const [ans, setAns] = useState([]); const [qns, setQns] = useState(); const [toogle, setToogle] = useState(false); - const [isLoaded,setIsLoaded] = useState(false); + const [isLoaded, setIsLoaded] = useState(false); const [toast, setToast] = useState({ toastStatus: false, toastType: "", toastMessage: "", }); const getQuestion = async (id) => { - setIsLoaded(true) + setIsLoaded(true); try { const qUrl = `${END_POINT}/question/getQuestionById/${id}`; const qResponse = await fetch(qUrl); const qRes = await qResponse.json(); setQns(qRes); + setToast({ + ...toast, + toastMessage: "Successfully get Question", + toastStatus: true, + toastType: "success", + }); } catch (error) { console.log(error); - setIsLoaded(false) + setIsLoaded(false); setToast({ ...toast, toastMessage: "Check network failed to fetch", @@ -68,10 +74,16 @@ export function Manageqa({ setTab, qId }) { const aResponse = await fetch(aUrl); const aRes = await aResponse.json(); setAns(aRes.data); - setIsLoaded(false) + setIsLoaded(false); + setToast({ + ...toast, + toastMessage: "Successfully get answers", + toastStatus: true, + toastType: "success", + }); } catch (error) { console.log(error); - setIsLoaded(false) + setIsLoaded(false); setToast({ ...toast, toastMessage: "Check network failed to fetch", @@ -126,60 +138,68 @@ export function Manageqa({ setTab, qId }) { setTab(18)} />
    {isLoaded ? : null}
    - {isLoaded ||
    -
    -

    {qns?.title}

    -
    -

    {qns?.description}

    -
    - - -
    -
    - - {ans?.map((a) => ( -
    -

    {a.answer}

    + {isLoaded || ( +
    +
    +

    {qns?.title}

    +

    Question

    +
    +

    {qns?.description}

    - ))} -
    - {qns?.tags?.map((tag) => ( -

    {tag}

    - ))} + {ans?.length !== 0 ? ( + No answers Found + ) : ( + ans?.map((a) => ( + <> +

    Answers

    +
    +

    {a.answer}

    +
    + + +
    +
    + + )) + )} + +
    + {qns?.tags?.map((tag) => ( +

    {tag}

    + ))} +
    -
    } + )} {toast.toastStatus && (