Compare commits

...

2 Commits

Author SHA1 Message Date
MikanD
48ec88df74 SurveyPage [AI] 2025-05-31 22:12:25 +03:00
MikanD
7555757ca3 pre AI 2025-05-31 18:15:52 +03:00
3 changed files with 177 additions and 36 deletions

View File

@@ -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>

View File

@@ -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;
}
} }

View File

@@ -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;
} }