Files
profi-frontend/src/pages/surveys/SurveyPage.tsx

168 lines
6.6 KiB
TypeScript
Raw Normal View History

2025-05-31 22:12:25 +03:00
import React, { useState, useEffect } from "react";
2025-06-02 17:30:35 +03:00
import { useNavigate, useParams } from "react-router-dom";
2025-05-31 22:12:25 +03:00
import {
Survey,
Question,
QuestionPair,
AgreementQuestion,
QuestionType,
2025-06-02 17:30:35 +03:00
2025-06-02 19:39:54 +03:00
} from "../../types/survey.ts";
import { LoadingData } from "../../components/LoadingData.tsx";
import { LoadingList } from "../../components/LoadingList.tsx";
import {useData, useDataPage} from "../../API/hooks.ts";
2025-05-31 10:57:27 +03:00
export function SurveyPage() {
2025-05-31 22:12:25 +03:00
const { surveyId } = useParams<{ surveyId: string }>();
const navigate = useNavigate();
// Загрузка теста
const survey = useData<Survey>("surveys", "surveys", surveyId || 0);
// Загрузка вопросов
const [questions, setQuestions] = useState<Question[] | null>(null);
const questionsPairs = useDataPage<QuestionPair>("surveys", "question-pairs", { survey: surveyId || 0 });
const questionsAgreement = useDataPage<AgreementQuestion>("surveys", "agreement-questions", { survey: surveyId || 0 });
// Состояние для ответов
const [answers, setAnswers] = useState<Record<string, number>>({});
const [isCompleted, setIsCompleted] = useState(false);
// Объединение вопросов после загрузки
useEffect(() => {
if (
questions === null &&
questionsPairs.items !== null &&
questionsAgreement.items !== null
) {
const mergedQuestions = [
...questionsPairs.items.map((q:Question) => ({ ...q, questionType: QuestionType.QuestionPair })),
...questionsAgreement.items.map((q:Question) => ({ ...q, questionType: QuestionType.AgreementQuestion })),
];
mergedQuestions.sort(() => Math.random() - 0.5); // Перемешивание
setQuestions(mergedQuestions);
}
}, [questions, questionsPairs.items, questionsAgreement.items]);
// Проверка завершения теста
useEffect(() => {
if (questions && Object.keys(answers).length === questions.length) {
setIsCompleted(true);
} else {
setIsCompleted(false);
}
}, [questions, answers]);
2025-05-31 10:57:27 +03:00
2025-05-31 22:12:25 +03:00
// Обработка ответов
const handleAnswer = (questionKey: string, answerValue: number) => {
setAnswers((prev) => ({ ...prev, [questionKey]: answerValue }));
};
2025-05-31 10:57:27 +03:00
2025-05-31 22:12:25 +03:00
// Вычисление итогового score_variable
const calculateResults = () => {
2025-06-01 16:17:09 +03:00
if (!questions) return;
2025-05-31 22:12:25 +03:00
const scoreCounts: Record<string, number> = {};
questions.forEach((question) => {
const questionKey = `${question.questionType}_${question.id}`;
const answer = answers[questionKey];
if (answer !== undefined) {
if (question.questionType === QuestionType.QuestionPair) {
const selectedStatement = (question as QuestionPair).statements.find(
(s) => s.id === answer
);
if (selectedStatement) {
scoreCounts[selectedStatement.score_variable] =
(scoreCounts[selectedStatement.score_variable] || 0) + 1;
}
} else if (question.questionType === QuestionType.AgreementQuestion) {
const scoreVariable = (question as AgreementQuestion).score_variable;
scoreCounts[scoreVariable] = (scoreCounts[scoreVariable] || 0) + answer;
}
}
});
const maxScoreVariable = Object.keys(scoreCounts).reduce((a, b) =>
scoreCounts[a] > scoreCounts[b] ? a : b
);
navigate(`/surveys/results/${maxScoreVariable}`);
};
2025-05-31 10:57:27 +03:00
return (
<div className="survey-page">
<LoadingData data={survey}>
2025-05-31 22:12:25 +03:00
<h1>{survey?.title}</h1>
<div>{survey?.description}</div>
<LoadingList data={questions} listElement={(question: Question) => (
<QuestionBlock
key={`${question.questionType}_${question.id}`} // Используем тип вопроса и id для уникальности
question={question}
onAnswer={handleAnswer}
answered={answers[`${question.questionType}_${question.id}`]} // Учитываем тип вопроса в ключе
/>
)} />
2025-06-01 20:55:44 +03:00
<>
{isCompleted && (
<button onClick={calculateResults}>Завершить тест</button>
)}
</>
2025-05-31 10:57:27 +03:00
</LoadingData>
</div>
);
}
2025-05-31 22:12:25 +03:00
function QuestionBlock({
question,
onAnswer,
answered,
}: {
question: Question;
onAnswer: (questionId: string, answerValue: number) => void;
answered?: number;
}) {
2025-05-31 18:15:52 +03:00
switch (question.questionType) {
case QuestionType.AgreementQuestion:
2025-06-01 20:55:44 +03:00
{ const agreementQuestion = question as AgreementQuestion;
2025-05-31 18:15:52 +03:00
return (
2025-05-31 22:12:25 +03:00
<div className={`question agreement ${answered !== undefined ? "answered" : "unanswered"}`}>
{agreementQuestion.question}
<button
2025-06-01 00:52:20 +03:00
className={`answer ${answered === 1 ? "selected" : "idle"}`}
2025-05-31 22:12:25 +03:00
disabled={answered===1}
onClick={() => onAnswer(`${question.questionType}_${question.id}`, 1)}>Согласен</button>
<button
2025-06-01 00:52:20 +03:00
className={`answer ${answered === 0 ? "selected" : "idle"}`}
2025-05-31 22:12:25 +03:00
disabled={answered === 0}
onClick={() => onAnswer(`${question.questionType}_${question.id}`, 0)}>Не согласен</button>
2025-05-31 18:15:52 +03:00
</div>
2025-06-01 20:55:44 +03:00
); }
2025-05-31 22:12:25 +03:00
2025-05-31 18:15:52 +03:00
case QuestionType.QuestionPair:
2025-06-01 20:55:44 +03:00
{ const pairQuestion = question as QuestionPair;
2025-05-31 18:15:52 +03:00
return (
2025-05-31 22:12:25 +03:00
<div className={`question pair ${answered !== undefined ? "answered" : "unanswered"}`}>
{pairQuestion.statements.map((statement) => (
<button
2025-06-01 00:52:20 +03:00
className={`answer ${answered === statement.id ? "selected" : "idle"}`}
2025-05-31 22:12:25 +03:00
disabled={answered === statement.id}
key={statement.id}
onClick={() => onAnswer(`${question.questionType}_${question.id}`, statement.id)}
>
{statement.text}
</button>
))}
2025-05-31 18:15:52 +03:00
</div>
2025-06-01 20:55:44 +03:00
); }
2025-05-31 22:12:25 +03:00
2025-05-31 18:15:52 +03:00
default:
2025-05-31 22:12:25 +03:00
return null;
2025-05-31 18:15:52 +03:00
}
}