Preview:
import React, { useState, useEffect } from "react";
import { FaMedal } from "react-icons/fa";
import axios from "axios";
import Apis from "../../APIs";
import { useAuth } from "../Auth/AuthContext";
import { useNavigate } from "react-router-dom";
import { toast } from "react-toastify";
import ToastWrapper from "../../../ToastWrapper";
import "react-toastify/dist/ReactToastify.css";

const See360Assessment = () => {
  const { user, setUser } = useAuth();
  const navigate = useNavigate();
  const [questions, setQuestions] = useState([]);
  const [answers, setAnswers] = useState([]);
  const [currentQuestionIndex, setCurrentQuestionIndex] = useState(0);
  const [result, setResult] = useState(false);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);
  const [assessmentId, setAssessmentId] = useState(null);
  const [redirectPage, setRedirectPage] = useState(null);

  useEffect(() => {
    const fetchQuestions = async () => {
      try {
        const response = await axios.get(Apis.See360_QUESTION_API);
        const fetchedQuestions = response.data;

        const savedProgress = JSON.parse(localStorage.getItem("assessmentProgress")) || {};
        const { savedAnswers = [], savedQuestionIndex = 0 } = savedProgress;

        setQuestions(fetchedQuestions);
        setAnswers(savedAnswers.length ? savedAnswers : fetchedQuestions.map(() => null));
        setCurrentQuestionIndex(savedQuestionIndex);
        setLoading(false);
      } catch (err) {
        console.error("Error fetching questions:", err);
        setError("Failed to load questions. Please try again later.");
        setLoading(false);
      }
    };

    fetchQuestions();
  }, []);

  const saveProgress = (newAnswers, newQuestionIndex) => {
    const progress = {
      savedAnswers: newAnswers,
      savedQuestionIndex: newQuestionIndex,
    };
    localStorage.setItem("assessmentProgress", JSON.stringify(progress));
  };

  const handleOptionSelect = (oIndex) => {
    const qIndex = currentQuestionIndex;
    const optionId = questions[qIndex].options[oIndex]._id;
    const newAnswers = [...answers];
    newAnswers[qIndex] = optionId;
    setAnswers(newAnswers);
    saveProgress(newAnswers, qIndex);
  };

  const handleNextQuestion = () => {
    if (!answers[currentQuestionIndex]) {
      toast.error("Please select an option before moving to the next question.");
      return;
    }

    const nextIndex = currentQuestionIndex + 1;
    if (nextIndex < questions.length) {
      setCurrentQuestionIndex(nextIndex);
      saveProgress(answers, nextIndex);
    } else {
      handleSubmit();
    }
  };

  const handleSubmit = async () => {
    setLoading(true);

    const formattedResponses = questions.map((question, qIndex) => ({
      questionId: question._id,
      answered: {
        optionId: answers[qIndex],
      },
    }));

    const payload = {
      userId: user._id,
      responses: formattedResponses,
    };

    try {
      const response = await axios.post(Apis.See360_ASSESSMENT_API, payload);
      const recordId = response.data._id;
      setAssessmentId(recordId);

      let calculatedRedirectPage = "/Pdf";
      setRedirectPage(calculatedRedirectPage);

      if (user.feedbackStatus === "newUser") {
        const updatedUserData = { feedbackStatus: "feedbackPending" };
        await axios.put(`${Apis.See360_USER_API}/${user._id}`, updatedUserData);
      }

      const pdfName = calculatedRedirectPage.replace("/", "");
      const updatedPdfAccess = [...user.pdfAccess, pdfName];
      setUser({ ...user, pdfAccess: updatedPdfAccess });
      await axios.put(
        `${Apis.See360_USER_API}/${user._id}`,
        { pdfAccess: updatedPdfAccess },
        {
          headers: {
            Authorization: `Bearer ${localStorage.getItem("token")}`,
          },
        }
      );

      localStorage.removeItem("assessmentProgress");
    } catch (error) {
      console.error("Error during assessment submission process:", error);
      toast.error("An error occurred while submitting the assessment. Please try again.");
    } finally {
      setResult(true);
      setLoading(false);
    }
  };

  const handleOkClick = async () => {
    const getUser = await axios.get(`${Apis.See360_USER_API}/${user._id}`, {
      headers: {
        Authorization: `Bearer ${localStorage.getItem("token")}`,
      },
    });
    const latestUserData = getUser.data;

    setUser(latestUserData);
    if (redirectPage) {
      navigate(redirectPage, { state: { assessmentId } });
    } else {
      toast.error("PDF page could not be determined.");
    }
  };

  if (loading) {
    return (
      <div className="min-h-screen w-full flex items-center justify-center bg-primary-gradient">
        <l-infinity
          size="200"
          stroke="4"
          stroke-length="0.15"
          bg-opacity="0.1"
          speed="1.3"
          color="white"
        ></l-infinity>
      </div>
    );
  }

  if (error) {
    return (
      <section className="min-h-screen w-full bg-primary-gradient flex items-center justify-center">
        <div className="text-white text-2xl">{error}</div>
      </section>
    );
  }

  return (
    <>
      <section className="min-h-screen w-full bg-primary-gradient flex flex-col items-center justify-center p-5">
        {result ? (
          <div className="min-h-[400px] w-80 md:w-[400px] rounded-lg bg-secondary p-5 flex items-center justify-center flex-col gap-5">
            <h2 className="text-3xl text-center">
              Thank you for giving the assessment
            </h2>
            <h2 className="text-3xl text-center">To See Your Result Click Ok</h2>
            <FaMedal className="text-4xl text-yellow-400" />
            <button
              onClick={handleOkClick}
              className="h-10 w-full rounded-lg bg-green-500 text-white hover:bg-green-700"
            >
              Ok
            </button>
          </div>
        ) : (
          <>
            <div className="w-screen max-w-[90%] md:max-w-[900px] rounded-lg bg-secondary p-5">
              <h2 className="font-bold text-xl flex items-center justify-center">
                SEE 360 Biz Scan Assessment
              </h2>
            </div>
            <div className="w-screen max-w-[90%] md:max-w-[900px] mt-5 rounded-lg bg-secondary p-5">
              <div className="text-lg text-black font-bold mb-3 flex items-center justify-center">
                {currentQuestionIndex + 1} / {questions.length}
              </div>
              <h3 className="font-semibold text-lg mb-3">
                {currentQuestionIndex + 1}. {questions[currentQuestionIndex].mainQuestion}
              </h3>
              <div className="flex flex-col gap-3">
                {questions[currentQuestionIndex].options.map((option, oIndex) => (
                  <div
                    key={option._id}
                    className={`cursor-pointer p-3 border rounded-lg ${
                      answers[currentQuestionIndex] === option._id
                        ? "bg-green-500 text-white"
                        : "hover:bg-gray-100"
                    }`}
                    onClick={() => handleOptionSelect(oIndex)}
                  >
                    {option.option}
                  </div>
                ))}
              </div>
              <div className="mt-5 flex justify-end">
                <button
                  onClick={handleNextQuestion}
                  className="h-10 w-32 rounded-lg bg-green-500 text-white hover:bg-green-700"
                >
                  Next
                </button>
              </div>
            </div>
          </>
        )}
      </section>
      <ToastWrapper />
    </>
  );
};

export default See360Assessment;
downloadDownload PNG downloadDownload JPEG downloadDownload SVG

Tip: You can change the style, width & colours of the snippet with the inspect tool before clicking Download!

Click to optimize width for Twitter