SurveyPage [AI]
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import {ReactElement} from "react";
|
||||
import {Link} from "react-router-dom";
|
||||
|
||||
export function LoadingData({data, children}: {data: object|null|undefined, children: ReactElement}) {
|
||||
export function LoadingData({data, children}: {data: object|null|undefined, children: (ReactElement | null | undefined | boolean)[]}) {
|
||||
|
||||
if (data === null){
|
||||
return <div className={"loading"}>Идёт загрузка...</div>
|
||||
|
||||
@@ -1,109 +1,167 @@
|
||||
import {LoadingList} from "../components/LoadingList.tsx";
|
||||
import {AgreementQuestion, Question, QuestionPair, QuestionType, Survey} from "../types/survey.ts";
|
||||
import {Link, useParams} from "react-router-dom";
|
||||
import React, { useState } from "react";
|
||||
import {useData, useDataPage} from "../API/common.ts";
|
||||
import {LoadingData} from "../components/LoadingData.tsx";
|
||||
|
||||
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { Navigate, useNavigate, useParams } from "react-router-dom";
|
||||
import {
|
||||
Survey,
|
||||
Question,
|
||||
QuestionPair,
|
||||
AgreementQuestion,
|
||||
QuestionType,
|
||||
ScoreVariable,
|
||||
} from "../types/survey";
|
||||
import { useData, useDataPage } from "../API/common";
|
||||
import { LoadingData } from "../components/LoadingData";
|
||||
import { LoadingList } from "../components/LoadingList";
|
||||
|
||||
export function SurveyPage() {
|
||||
const { surveyId } = useParams<{ surveyId: string }>();
|
||||
const navigate = useNavigate();
|
||||
|
||||
const {surveyId} = useParams();
|
||||
// Загрузка теста
|
||||
const survey = useData<Survey>("surveys", "surveys", surveyId || 0);
|
||||
|
||||
const survey = useData<Survey>("surveys", "surveys", surveyId);
|
||||
// Загрузка вопросов
|
||||
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 });
|
||||
|
||||
// Загрузка score variables
|
||||
const scoreVariables = useDataPage<ScoreVariable>("surveys", "score-variables");
|
||||
|
||||
// Состояние для ответов
|
||||
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]);
|
||||
|
||||
// Обработка ответов
|
||||
const handleAnswer = (questionKey: string, answerValue: number) => {
|
||||
setAnswers((prev) => ({ ...prev, [questionKey]: answerValue }));
|
||||
};
|
||||
|
||||
// Вычисление итогового score_variable
|
||||
const calculateResults = () => {
|
||||
if (!questions || !scoreVariables.items) return;
|
||||
|
||||
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}`);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="survey-page">
|
||||
<LoadingData data={survey}>
|
||||
<h1>
|
||||
{survey?.title}
|
||||
</h1>
|
||||
<div>
|
||||
{survey?.description}
|
||||
</div>
|
||||
<h1>{survey?.title}</h1>
|
||||
<div>{survey?.description}</div>
|
||||
|
||||
<SurveyQuestions survey={survey}/>
|
||||
<LoadingList data={questions} listElement={(question: Question) => (
|
||||
<QuestionBlock
|
||||
key={`${question.questionType}_${question.id}`} // Используем тип вопроса и id для уникальности
|
||||
question={question}
|
||||
onAnswer={handleAnswer}
|
||||
answered={answers[`${question.questionType}_${question.id}`]} // Учитываем тип вопроса в ключе
|
||||
/>
|
||||
)} />
|
||||
|
||||
{isCompleted && (
|
||||
<button onClick={calculateResults}>Завершить тест</button>
|
||||
)}
|
||||
</LoadingData>
|
||||
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
function SurveyQuestions({survey}: { survey: Survey | null | undefined }) {
|
||||
|
||||
const _survey = survey as Survey;
|
||||
|
||||
const [questions, setQuestions] = useState<Question[]|null>(null);
|
||||
|
||||
const questionsPairs = useDataPage<QuestionPair>("surveys", "question-pairs", {survey:_survey.id});
|
||||
const questionsAgreement = useDataPage<AgreementQuestion>("surveys", "agreement-questions", {survey:_survey.id});
|
||||
|
||||
if (questions === null && questionsPairs.items !== null && questionsAgreement.items !== null){
|
||||
|
||||
function setQuestionType(question: Question, questionType: QuestionType) {
|
||||
question.questionType = questionType;
|
||||
return question;
|
||||
}
|
||||
|
||||
var _questions = [...questionsPairs.items.map(q=>setQuestionType(q, QuestionType.QuestionPair)), ...questionsAgreement.items.map(q=>setQuestionType(q, QuestionType.AgreementQuestion))];
|
||||
_questions.sort(()=>Math.random() - .5);
|
||||
console.log(questionsPairs.items.map(q=>setQuestionType(q, QuestionType.QuestionPair)));
|
||||
|
||||
setQuestions(_questions);
|
||||
}
|
||||
|
||||
//console.log(questions);
|
||||
|
||||
|
||||
return (
|
||||
<>
|
||||
<LoadingList data={questions} listElement={(question=>(
|
||||
<QuestionBlock key={(question as Question).questionType+"#"+question.id} question={question as Question}/>
|
||||
|
||||
))}/>
|
||||
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
function QuestionBlock({question}:{question: Question}) {
|
||||
|
||||
function QuestionBlock({
|
||||
question,
|
||||
onAnswer,
|
||||
answered,
|
||||
}: {
|
||||
question: Question;
|
||||
onAnswer: (questionId: string, answerValue: number) => void;
|
||||
answered?: number;
|
||||
}) {
|
||||
switch (question.questionType) {
|
||||
case QuestionType.AgreementQuestion:
|
||||
const qa = question as AgreementQuestion;
|
||||
const agreementQuestion = question as AgreementQuestion;
|
||||
return (
|
||||
<div className={"question agreement"}>
|
||||
(Вы согласны с утверждением?)
|
||||
{qa.question}
|
||||
<button>
|
||||
Согласен
|
||||
</button>
|
||||
<button>
|
||||
Несогласен
|
||||
</button>
|
||||
<div className={`question agreement ${answered !== undefined ? "answered" : "unanswered"}`}>
|
||||
{agreementQuestion.question}
|
||||
<button
|
||||
className={answered === 1 ? "selected" : ""}
|
||||
disabled={answered===1}
|
||||
onClick={() => onAnswer(`${question.questionType}_${question.id}`, 1)}>Согласен</button>
|
||||
<button
|
||||
className={answered === 0 ? "selected" : ""}
|
||||
disabled={answered === 0}
|
||||
onClick={() => onAnswer(`${question.questionType}_${question.id}`, 0)}>Не согласен</button>
|
||||
|
||||
</div>
|
||||
);
|
||||
|
||||
case QuestionType.QuestionPair:
|
||||
|
||||
const qp = question as QuestionPair;
|
||||
const pairQuestion = question as QuestionPair;
|
||||
return (
|
||||
<div className={"question pair"}>
|
||||
(Выберите подходящий ответ)
|
||||
{qp.statements.map(s=>(<button>{s.text}</button>))}
|
||||
|
||||
<div className={`question pair ${answered !== undefined ? "answered" : "unanswered"}`}>
|
||||
{pairQuestion.statements.map((statement) => (
|
||||
<button
|
||||
className={answered === statement.id ? "selected" : ""}
|
||||
disabled={answered === statement.id}
|
||||
key={statement.id}
|
||||
onClick={() => onAnswer(`${question.questionType}_${question.id}`, statement.id)}
|
||||
>
|
||||
{statement.text}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
|
||||
default:
|
||||
break;
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -32,3 +32,12 @@ export interface AgreementQuestion extends Question{
|
||||
question: string;
|
||||
score_variable: number;
|
||||
}
|
||||
|
||||
|
||||
export interface ScoreVariable {
|
||||
id: string;
|
||||
name: string;
|
||||
title: string;
|
||||
description: string;
|
||||
survey: string;
|
||||
}
|
||||
Reference in New Issue
Block a user