I want to move the generatePDF function to a new component file so that it can be used in another component also, how to accomplish that:

import React, { useState, useEffect, useCallback, useRef } from "react";
import "./mathQuiz.css";
import jsPDF from "jspdf";
import html2canvas from "html2canvas";
import LatexRenderer from "./LatexRenderer";
import Calculator from "./components/Calculator";
import { Calculator as CalculatorIcon } from "lucide-react";
import { db } from "./firebase";
import {
  collection,
  query,
  where,
  getDocs,
  doc,
  setDoc,
  getDoc,
  deleteDoc,
} from "firebase/firestore";
import { getAuth, onAuthStateChanged } from "firebase/auth";

const MathQuiz = () => {
  const [randomizedQuestions, setRandomizedQuestions] = useState([]);
  const [currentQuestion, setCurrentQuestion] = useState(0);
  const [selectedAnswers, setSelectedAnswers] = useState([]);
  const [showExplanation, setShowExplanation] = useState(false);
  const [answerStatus, setAnswerStatus] = useState(null);
  const [correctAnswers, setCorrectAnswers] = useState(0);
  const [showScore, setShowScore] = useState(false);
  const [quizSummary, setQuizSummary] = useState([]);
  const [shuffledOptions, setShuffledOptions] = useState([]);
  const [isAnswerSubmitted, setIsAnswerSubmitted] = useState(false);
  const [showWelcome, setShowWelcome] = useState(true);
  const [showCalculator, setShowCalculator] = useState(false);
  const [hasResumableQuiz, setHasResumableQuiz] = useState(false);
  const [savedQuizState, setSavedQuizState] = useState(null);
  const [isLoading, setIsLoading] = useState(true);
  const [userId, setUserId] = useState(null);

  const summaryRef = useRef(null);

  useEffect(() => {
    document.title = "Math Quiz";
    return () => {
      document.title = "Campus Goals";
    };
  }, []);

  useEffect(() => {
    const auth = getAuth();
    const unsubscribe = onAuthStateChanged(auth, (user) => {
      if (user) {
        setUserId(user.uid);
      } else {
        setUserId(null);
      }
    });

    return () => unsubscribe();
  }, []);

  const getRandomQuestions = useCallback(async () => {
    try {
      const q = query(collection(db, "users"), where("quiztype", "==", "math"));
      const querySnapshot = await getDocs(q);
      const questions = querySnapshot.docs.map((doc) => doc.data());
      return questions.sort(() => Math.random() - 0.5).slice(0, 20);
    } catch (error) {
      console.error("Error fetching questions:", error);
      return [];
    }
  }, []);

  const shuffleOptions = useCallback((options) => {
    return [...options].sort(() => Math.random() - 0.5);
  }, []);

  const saveQuizState = useCallback(async (state) => {
    if (!userId) return;
    try {
      const stateToSave = {
        ...state,
        shuffledOptionsForQuestions: state.randomizedQuestions.map(
          (q, index) => ({
            questionIndex: index,
            shuffledOptions:
              index === state.currentQuestion
                ? state.shuffledOptions
                : q.options,
          })
        ),
      };
      await setDoc(doc(db, "mathquizStates", userId), stateToSave);
    } catch (error) {
      console.error("Error saving quiz state: ", error);
    }
  }, [userId]);

  const loadQuizState = useCallback(async () => {
    if (!userId) return;
    try {
      const quizStateRef = doc(db, "mathquizStates", userId);
      const quizStateSnap = await getDoc(quizStateRef);

      if (quizStateSnap.exists()) {
        const state = quizStateSnap.data();
        setSavedQuizState(state);
        setHasResumableQuiz(true);
      } else {
        setHasResumableQuiz(false);
        setSavedQuizState(null);
      }
    } catch (error) {
      console.error("Error loading quiz state: ", error);
    }
  }, [userId]);

  const deleteQuizState = useCallback(async () => {
    if (!userId) return;
    try {
      await deleteDoc(doc(db, "mathquizStates", userId));
      setHasResumableQuiz(false);
      setSavedQuizState(null);
    } catch (error) {
      console.error("Error deleting quiz state: ", error);
    }
  }, [userId]);

  const startNewQuiz = useCallback(async () => {
    setIsLoading(true);
    try {
      await deleteQuizState();
      const newQuestions = await getRandomQuestions();
      const shuffledOptionsForQuestions = newQuestions.map((q) => ({
        questionIndex: newQuestions.indexOf(q),
        shuffledOptions: shuffleOptions(q.options),
      }));
      setRandomizedQuestions(newQuestions);
      setCurrentQuestion(0);
      setSelectedAnswers([]);
      setShowExplanation(false);
      setAnswerStatus(null);
      setCorrectAnswers(0);
      setShowScore(false);
      setQuizSummary([]);
      setIsAnswerSubmitted(false);
      setShowWelcome(false);
      if (newQuestions.length > 0) {
        setShuffledOptions(shuffledOptionsForQuestions[0].shuffledOptions);
      }
      saveQuizState({
        randomizedQuestions: newQuestions,
        currentQuestion: 0,
        selectedAnswers: [],
        showExplanation: false,
        answerStatus: null,
        correctAnswers: 0,
        showScore: false,
        quizSummary: [],
        shuffledOptions: shuffledOptionsForQuestions[0].shuffledOptions,
        isAnswerSubmitted: false,
        shuffledOptionsForQuestions,
      });
    } catch (error) {
      console.error("Error starting new quiz:", error);
    } finally {
      setIsLoading(false);
    }
  }, [getRandomQuestions, shuffleOptions, deleteQuizState, saveQuizState]);

  const resumeQuiz = useCallback(async () => {
    setIsLoading(true);
    try {
      if (savedQuizState) {
        setRandomizedQuestions(savedQuizState.randomizedQuestions);
        setCurrentQuestion(savedQuizState.currentQuestion);
        setSelectedAnswers(savedQuizState.selectedAnswers || []);
        setShowExplanation(savedQuizState.showExplanation || false);
        setAnswerStatus(savedQuizState.answerStatus || null);
        setCorrectAnswers(savedQuizState.correctAnswers || 0);
        setShowScore(savedQuizState.showScore || false);
        setQuizSummary(savedQuizState.quizSummary || []);
        setIsAnswerSubmitted(savedQuizState.isAnswerSubmitted || false);

        const currentShuffledOptions =
          savedQuizState.shuffledOptionsForQuestions.find(
            (so) => so.questionIndex === savedQuizState.currentQuestion
          )?.shuffledOptions || [];
        setShuffledOptions(currentShuffledOptions);

        setShowWelcome(false);
      } else {
        console.error("No saved quiz state found or invalid state");
        await startNewQuiz();
      }
    } catch (error) {
      console.error("Error resuming quiz:", error);
      await startNewQuiz();
    } finally {
      setIsLoading(false);
    }
  }, [savedQuizState, startNewQuiz]);

  useEffect(() => {
    if (!showWelcome && randomizedQuestions.length > 0) {
      const currentQuestionData = randomizedQuestions[currentQuestion];
      if (currentQuestionData && !isAnswerSubmitted) {
        const currentShuffledOptions =
          savedQuizState?.shuffledOptionsForQuestions.find(
            (so) => so.questionIndex === currentQuestion
          )?.shuffledOptions || shuffleOptions(currentQuestionData.options);
        setShuffledOptions(currentShuffledOptions);
      }

      if (isAnswerSubmitted) {
        setShowExplanation(true);
      }
    }
  }, [
    showWelcome,
    randomizedQuestions,
    currentQuestion,
    shuffleOptions,
    savedQuizState,
  ]);

  useEffect(() => {
    const initializeQuiz = async () => {
      setIsLoading(true);
      try {
        await loadQuizState();
        if (randomizedQuestions.length === 0) {
          const newQuestions = await getRandomQuestions();
          setRandomizedQuestions(newQuestions);
        }
      } catch (error) {
        console.error("Error initializing quiz:", error);
      } finally {
        setIsLoading(false);
      }
    };
    initializeQuiz();
  }, [loadQuizState, getRandomQuestions, randomizedQuestions.length]);

  const handleAnswerClick = useCallback(
    (answer) => {
      if (isAnswerSubmitted) return;
      const currentQuestionType = randomizedQuestions[currentQuestion].type;
      if (currentQuestionType === "multiple-choice-single-answer") {
        setSelectedAnswers([answer]);
      } else if (currentQuestionType === "multiple-choice-multiple-answer") {
        setSelectedAnswers((prev) => {
          if (prev.includes(answer)) {
            return prev.filter((a) => a !== answer);
          } else {
            return [...prev, answer];
          }
        });
      }
    },
    [randomizedQuestions, currentQuestion, isAnswerSubmitted]
  );

  const handleSubmit = () => {
    const currentQuestionData = randomizedQuestions[currentQuestion];
    let isCorrect;
    if (currentQuestionData.type === "multiple-choice-single-answer") {
      isCorrect = selectedAnswers[0] === currentQuestionData.correctAnswer;
    } else if (currentQuestionData.type === "multiple-choice-multiple-answer") {
      isCorrect =
        selectedAnswers.length === currentQuestionData.correctAnswers.length &&
        selectedAnswers.every((answer) =>
          currentQuestionData.correctAnswers.includes(answer)
        );
    }

    const userAnswerText = selectedAnswers
      .map(
        (answer) =>
          currentQuestionData.options.find(
            (option) => option.id === String(answer)
          )?.text || "Not found"
      )
      .join(", ");

    const correctAnswerText = (
      currentQuestionData.type === "multiple-choice-single-answer"
        ? [currentQuestionData.correctAnswer]
        : currentQuestionData.correctAnswers
    )
      .map(
        (answer) =>
          currentQuestionData.options.find(
            (option) => option.id === String(answer)
          )?.text || "Not found"
      )
      .join(", ");

    const newQuizSummary = [
      ...quizSummary,
      {
        question: currentQuestionData.text,
        userAnswer: userAnswerText,
        correctAnswer: correctAnswerText,
        isCorrect: isCorrect,
        explanation: isCorrect ? "" : currentQuestionData.explanation,
      },
    ];

    const newCorrectAnswers = isCorrect ? correctAnswers + 1 : correctAnswers;

    const newState = {
      randomizedQuestions,
      currentQuestion,
      selectedAnswers,
      showExplanation: true,
      answerStatus: isCorrect ? "correct" : "incorrect",
      correctAnswers: newCorrectAnswers,
      showScore,
      quizSummary: newQuizSummary,
      shuffledOptions,
      isAnswerSubmitted: true,
    };

    setQuizSummary(newQuizSummary);
    setShowExplanation(true);
    setIsAnswerSubmitted(true);
    setAnswerStatus(isCorrect ? "correct" : "incorrect");
    setCorrectAnswers(newCorrectAnswers);

    saveQuizState(newState);
  };

  const handleNextQuestion = () => {
    const nextQuestion = currentQuestion + 1;
    if (nextQuestion < randomizedQuestions.length) {
      setCurrentQuestion(nextQuestion);
      setSelectedAnswers([]);
      setShowExplanation(false);
      setAnswerStatus(null);
      setIsAnswerSubmitted(false);

      const nextShuffledOptions =
        savedQuizState?.shuffledOptionsForQuestions.find(
          (so) => so.questionIndex === nextQuestion
        )?.shuffledOptions || randomizedQuestions[nextQuestion].options;

      setShuffledOptions(nextShuffledOptions);

      const newState = {
        randomizedQuestions,
        currentQuestion: nextQuestion,
        selectedAnswers: [],
        showExplanation: false,
        answerStatus: null,
        correctAnswers,
        showScore: false,
        quizSummary,
        shuffledOptions: nextShuffledOptions,
        isAnswerSubmitted: false,
      };

      saveQuizState(newState);
    } else {
      setShowScore(true);
      const finalState = {
        randomizedQuestions,
        currentQuestion: nextQuestion,
        selectedAnswers,
        showExplanation,
        answerStatus,
        correctAnswers,
        showScore: true,
        quizSummary,
        shuffledOptions,
        isAnswerSubmitted,
      };
      saveQuizState(finalState);
    }
  };

  const renderOptions = () => {
    const currentQuestionType = randomizedQuestions[currentQuestion].type;
    return shuffledOptions.map((option) => (
      <label
        key={option.id}
        className={`
math-option-label
${selectedAnswers.includes(option.id) ? "selected" : ""}
${
  showExplanation &&
  (currentQuestionType === "multiple-choice-single-answer"
    ? randomizedQuestions[currentQuestion].correctAnswer === option.id
    : randomizedQuestions[currentQuestion].correctAnswers.includes(option.id))
    ? "correct"
    : ""
}
${
  showExplanation &&
  selectedAnswers.includes(option.id) &&
  (currentQuestionType === "multiple-choice-single-answer"
    ? randomizedQuestions[currentQuestion].correctAnswer !== option.id
    : !randomizedQuestions[currentQuestion].correctAnswers.includes(option.id))
    ? "incorrect"
    : ""
}
`}
      >
        <input
          type={
            currentQuestionType === "multiple-choice-single-answer"
              ? "radio"
              : "checkbox"
          }
          name="math-option"
          value={option.id}
          checked={selectedAnswers.includes(option.id)}
          onChange={() => handleAnswerClick(option.id)}
          disabled={isAnswerSubmitted || showExplanation}
        />
        <span className="math-option-text">{option.text}</span>
      </label>
    ));
  };

  const generatePDF = useCallback(() => {
    if (summaryRef.current) {
      const input = summaryRef.current;
      const originalHeight = input.style.maxHeight;
      const originalOverflow = input.style.overflow;
      const originalPadding = input.style.padding;

      input.style.maxHeight = "none";
      input.style.overflow = "visible";
      input.style.padding = "20px";

      html2canvas(input, {
        scrollY: -window.scrollY,
        scale: 1,
        height: input.scrollHeight + 40,
        windowHeight: input.scrollHeight + 40,
      }).then((canvas) => {
        input.style.maxHeight = originalHeight;
        input.style.overflow = originalOverflow;
        input.style.padding = originalPadding;

        const imgData = canvas.toDataURL("image/png");
        const pdf = new jsPDF("p", "px", [canvas.width, canvas.height]);

        pdf.addImage(imgData, "PNG", 0, 0, canvas.width, canvas.height);
        pdf.save("quiz_summary.pdf");
      });
    }
  }, []);

  const QuizSummary = ({ summary }) => (
    <div className="math-quiz-summary" ref={summaryRef}>
      <h3>Quiz Summary</h3>
      {summary.map((item, index) => (
        <div
          key={index}
          className={`math-summary-item ${
            item.isCorrect ? "correct" : "incorrect"
          }`}
        >
          <p>
            <strong>Q{index + 1}:</strong>
          </p>
          <p className="math-question">
            <LatexRenderer text={item.question} />
          </p>
          <p>Your answer: {item.userAnswer}</p>
          <p>Correct answer: {item.correctAnswer}</p>
          {!item.isCorrect && (
            <>
              <p>Explanation:</p>
              <div
                className="math-explanation"
                dangerouslySetInnerHTML={{ __html: item.explanation }}
              />
            </>
          )}
        </div>
      ))}
    </div>
  );

  const restartQuiz = async () => {
    setCurrentQuestion(0);
    setCorrectAnswers(0);
    setShowScore(false);
    setSelectedAnswers([]);
    setShowExplanation(false);
    setAnswerStatus(null);
    setQuizSummary([]);
    setIsAnswerSubmitted(false);
    setShowWelcome(true);

    try {
      await deleteQuizState();
      setHasResumableQuiz(false);

      const newQuestions = await getRandomQuestions();
      setRandomizedQuestions(newQuestions);
    } catch (error) {
      console.error("Error restarting quiz: ", error);
    }
  };

  if (isLoading) {
    return <div className="math-quiz-container">Loading...</div>;
  }

  if (randomizedQuestions.length === 0) {
    return (
      <div className="math-quiz-container">
        No questions available. Please try again later.
      </div>
    );
  }

  return (
    <>
      <div className="math-quiz-container">
        {showWelcome ? (
          <div className="math-welcome-screen">
            <h2 className="math-welcome-header">Welcome to Math Quiz</h2>
            <div className="math-quiz-instructions">
              <p>
                This quiz is designed to test your mathematical skills with
                various problems.
              </p>
              <p>
                Each question will present you with a mathematical problem and
                multiple-choice answers.
              </p>
              <p>
                Some questions may have multiple correct answers. Select all
                that apply when instructed.
              </p>
              <p>The quiz consists of 20 questions.</p>
              <p>Good luck!</p>
            </div>
            {hasResumableQuiz && savedQuizState && (
              <div className="math-saved-quiz-info">
                <p>You have a saved quiz. Would you like to resume?</p>
                <p>
                  Progress: {savedQuizState.currentQuestion + 1} /{" "}
                  {savedQuizState.randomizedQuestions.length} questions
                </p>
                <p>Current Score: {savedQuizState.correctAnswers}</p>
                <button onClick={resumeQuiz} className="math-resume-button">
                  Resume Quiz
                </button>
              </div>
            )}
            <div className="math-welcome-button-container">
              <button className="math-welcome-button" onClick={startNewQuiz}>
                Start New Quiz
              </button>
            </div>
          </div>
        ) : showScore ? (
          <div className="math-quiz-completion">
            <h2>Quiz Completed!</h2>
            <h3>
              You scored {correctAnswers} out of {randomizedQuestions.length}
            </h3>
            <QuizSummary summary={quizSummary} />
            <div className="math-new-quiz-button-container">
              <button className="math-new-quiz-button" onClick={restartQuiz}>
                Start New Quiz
              </button>
              <button
                className="math-download-pdf-button"
                onClick={generatePDF}
              >
                Download Summary PDF
              </button>
            </div>
          </div>
        ) : (
          <>
            <h2>Math Quiz</h2>
            <h3>
              Question {currentQuestion + 1} of {randomizedQuestions.length}
            </h3>
            <p className="math-question">
              <LatexRenderer text={randomizedQuestions[currentQuestion].text} />
            </p>
            <p className="math-question-instruction">
              {randomizedQuestions[currentQuestion].type ===
              "multiple-choice-single-answer"
                ? "Select one option:"
                : "Select all valid options:"}
            </p>
            <div className="math-options-list">{renderOptions()}</div>
            {!isAnswerSubmitted ? (
              <div className="math-button-container">
                <button
                  onClick={handleSubmit}
                  disabled={selectedAnswers.length === 0}
                >
                  Submit
                </button>
              </div>
            ) : (
              <div className="math-button-container">
                <button onClick={handleNextQuestion}>
                  {currentQuestion < randomizedQuestions.length - 1
                    ? "Next Question"
                    : "Finish Quiz"}
                </button>
              </div>
            )}
            {showExplanation && (
              <div className="math-explanation">
                <p className={`math-answer-status ${answerStatus}`}>
                  {answerStatus === "correct" ? "Correct!" : "Incorrect!"}
                </p>
                {answerStatus === "incorrect" && (
                  <>
                    <p className="correct-answer">
                      The correct answer is:{" "}
                      {randomizedQuestions[currentQuestion].type ===
                      "multiple-choice-single-answer"
                        ? randomizedQuestions[currentQuestion].options.find(
                            (option) =>
                              option.id ===
                              randomizedQuestions[currentQuestion].correctAnswer
                          )?.text || "Not found"
                        : randomizedQuestions[currentQuestion].correctAnswers
                            .map(
                              (answerId) =>
                                randomizedQuestions[
                                  currentQuestion
                                ].options.find(
                                  (option) => option.id === String(answerId)
                                )?.text || "Not found"
                            )
                            .join(", ")}
                    </p>
                    <p>Explanation:</p>
                    <div
                      className="math-explanation-text"
                      dangerouslySetInnerHTML={{
                        __html:
                          randomizedQuestions[currentQuestion].explanation,
                      }}
                    />
                  </>
                )}
              </div>
            )}
          </>
        )}
        {!showWelcome && (
          <button
            className="calculator-icon"
            onClick={() => setShowCalculator(!showCalculator)}
            title={`Click to ${
              showCalculator ? "hide" : "show"
            } the calculator`}
          >
            <CalculatorIcon />
          </button>
        )}
      </div>
      {showCalculator && <Calculator />}
    </>
  );
};

export default MathQuiz;