Compare commits
2 Commits
master
...
48ec88df74
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
48ec88df74 | ||
|
|
7555757ca3 |
@@ -1,7 +1,7 @@
|
|||||||
import {ReactElement} from "react";
|
import {ReactElement} from "react";
|
||||||
import {Link} from "react-router-dom";
|
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){
|
if (data === null){
|
||||||
return <div className={"loading"}>Идёт загрузка...</div>
|
return <div className={"loading"}>Идёт загрузка...</div>
|
||||||
|
|||||||
@@ -1,53 +1,167 @@
|
|||||||
import {LoadingList} from "../components/LoadingList.tsx";
|
import React, { useState, useEffect } from "react";
|
||||||
import {Survey} from "../types/survey.ts";
|
import { Navigate, useNavigate, useParams } from "react-router-dom";
|
||||||
import {Link, useParams} from "react-router-dom";
|
import {
|
||||||
import React from "react";
|
Survey,
|
||||||
import {useData, useDataPage} from "../API/common.ts";
|
Question,
|
||||||
import {LoadingData} from "../components/LoadingData.tsx";
|
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() {
|
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 (
|
return (
|
||||||
<div className="survey-page">
|
<div className="survey-page">
|
||||||
<LoadingData data={survey}>
|
<LoadingData data={survey}>
|
||||||
<h1>
|
<h1>{survey?.title}</h1>
|
||||||
{survey?.title}
|
<div>{survey?.description}</div>
|
||||||
</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>
|
</LoadingData>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function QuestionBlock({
|
||||||
function SurveyQuestions({survey}: { survey: Survey | null | undefined }) {
|
question,
|
||||||
|
onAnswer,
|
||||||
const _survey = survey as Survey;
|
answered,
|
||||||
|
}: {
|
||||||
const questionsPairs = useDataPage("surveys", "question-pairs", {survey:_survey.id});
|
question: Question;
|
||||||
const questionsAgreement = useDataPage("surveys", "question-pairs", {survey:_survey.id});
|
onAnswer: (questionId: string, answerValue: number) => void;
|
||||||
|
answered?: number;
|
||||||
//const questions =
|
}) {
|
||||||
|
switch (question.questionType) {
|
||||||
|
case QuestionType.AgreementQuestion:
|
||||||
|
const agreementQuestion = question as AgreementQuestion;
|
||||||
return (
|
return (
|
||||||
<>
|
<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 pairQuestion = question as QuestionPair;
|
||||||
|
return (
|
||||||
|
<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:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,33 @@ interface Statement extends UniqueItem{
|
|||||||
score_variable: number;
|
score_variable: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface QuestionPair extends UniqueItem{
|
export enum QuestionType{
|
||||||
|
QuestionPair,
|
||||||
|
AgreementQuestion
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Question extends UniqueItem{
|
||||||
|
questionType: QuestionType,
|
||||||
|
answer?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export interface QuestionPair extends Question{
|
||||||
|
statements: Statement[]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
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