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 f27b2f02..cf26fab2 100644 --- a/frontend/src/pages/Admin/Admin.jsx +++ b/frontend/src/pages/Admin/Admin.jsx @@ -24,6 +24,8 @@ 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"; +import { Manageqa } from "./Components/Faq/Q&A/ManageQ&A/ManageQ&A"; export const Admin = (props) => { const [tab, setTab] = useState(1); @@ -31,6 +33,8 @@ export const Admin = (props) => { const toggleNav = () => setIsMenuOpen(!isMenuOpen); const closeMobileMenu = () => setIsMenuOpen(false); const dispatch = useDispatch(); + const firstName = localStorage.getItem("firstName"); + const [qId,setQId] = useState("") const [adminData, setAdminData] = useState({}); const FetchAdminData = async () => { try { @@ -50,7 +54,6 @@ export const Admin = (props) => { console.error("There was a problem with the fetch operation:", error); } }; - useEffect(() => { const token = localStorage.getItem("token"); try { @@ -174,7 +177,7 @@ export const Admin = (props) => { className="fas fa-question fa-fw fa-lg" aria-hidden="true" > -
FAQs
+
FAQs and Q&As
  • @@ -244,6 +247,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..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

    @@ -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..b9305fd1 --- /dev/null +++ b/frontend/src/pages/Admin/Components/Faq/Q&A/ManageQ&A/ManageQ&A.jsx @@ -0,0 +1,213 @@ +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); + setToast({ + ...toast, + toastMessage: "Successfully get Question", + toastStatus: true, + toastType: "success", + }); + } 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); + setToast({ + ...toast, + toastMessage: "Successfully get answers", + toastStatus: true, + toastType: "success", + }); + } 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}

    +

    Question

    +
    +

    {qns?.description}

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

    Answers

    +
    +

    {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 new file mode 100644 index 00000000..0c0fef96 --- /dev/null +++ b/frontend/src/pages/Admin/Components/Faq/Q&A/QandA.jsx @@ -0,0 +1,85 @@ +import React, { useEffect, useState } from "react"; +import style from "./qanda.module.scss"; +import { END_POINT } from "../../../../../config/api"; +import { SimpleToast } from "../../../../../components/util/Toast/Toast"; +import Loader from "../../../../../components/util/Loader"; + +export function QandA({ setTab, setQId, tab }) { + const [cards, setCards] = useState([]); + const [isLoaded,setIsLoaded] = 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); + const res = await response.json(); + setCards(res); + } catch (error) { + console.log(error); + setToast({ + ...toast, + toastMessage: "Check network failed to fetch", + toastStatus: true, + toastType: "error", + }); + + } + setIsLoaded(false) + }; + const handleCloseToast = (event, reason) => { + if (reason === "clickaway") { + return; + } + setToast({ ...toast, toastStatus: false }); + }; + useEffect(() => { + getdata(); + }, [tab]); + return ( +
    +

    Manage Q&A

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

    {d.title}

    +
    +

    {d.description}

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

    {tag}

    + ))} +
    + +
    + ))} +
    + {toast.toastStatus && ( + + )} +
    + ); +} 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; +}