import React, { useEffect, useState } from "react"; import SurveyInfo from "../SurveyInfo/SurveyInfo.tsx"; import QuestionsList, { Question } from "../QuestionsList/QuestionsList.tsx"; import { ISurvey, updateSurvey } from "../../api/SurveyApi.ts"; import {useOutletContext} from "react-router-dom"; import { addNewQuestion, getListQuestions, updateQuestion, deleteQuestion } from "../../api/QuestionApi.ts"; import styles from "./SurveyPage.module.css"; import SaveButton from "../SaveButton/SaveButton.tsx"; import { addNewAnswerVariant, deleteAnswerVariant, getAnswerVariants, IAnswerVariant, updateAnswerVariant } from "../../api/AnswerVariantsApi.ts"; type ActionType = | 'update-survey' | 'create-question' | 'update-question' | 'delete-question' | 'create-answer' | 'update-answer' | 'delete-answer'; interface SurveyActionData { id: number; title: string; description: string; } interface QuestionActionData { surveyId: number; id?: number; title: string; questionType: 'SingleAnswerQuestion' | 'MultipleAnswerQuestion'; } interface AnswerActionData { surveyId: number; questionId: number; id?: number; text: string; } interface Action { type: ActionType; data: SurveyActionData | QuestionActionData | AnswerActionData; tempId?: number; } class ActionQueue { private actions: Action[] = []; private idMap: Record = {}; add(action: Action) { this.actions.push(action); } async execute() { for (const action of this.actions) { try { switch (action.type) { case 'update-survey': await this.handleUpdateSurvey(action.data as SurveyActionData); break; case 'create-question': { const createdQuestion = await this.handleCreateQuestion(action.data as QuestionActionData); if (action.tempId) { this.idMap[action.tempId] = createdQuestion.id; } break; } case 'update-question': await this.handleUpdateQuestion(action.data as QuestionActionData & { id: number }); break; case 'delete-question': await this.handleDeleteQuestion(action.data as QuestionActionData & { id: number }); break; case 'create-answer': { const answerData = action.data as AnswerActionData; await this.handleCreateAnswer({ ...answerData, questionId: this.idMap[answerData.questionId] || answerData.questionId }); break; } case 'update-answer': { const updateAnswerData = action.data as AnswerActionData & { id: number }; await this.handleUpdateAnswer({ ...updateAnswerData, questionId: this.idMap[updateAnswerData.questionId] || updateAnswerData.questionId }); break; } case 'delete-answer': { const deleteAnswerData = action.data as AnswerActionData & { id: number }; await this.handleDeleteAnswer({ ...deleteAnswerData, questionId: this.idMap[deleteAnswerData.questionId] || deleteAnswerData.questionId }); break; } } } catch (error) { console.error(`Failed to execute action ${action.type}:`, error); throw error; } } } private async handleUpdateSurvey(data: SurveyActionData) { return await updateSurvey(data.id, { title: data.title, description: data.description }); } private async handleCreateQuestion(data: QuestionActionData) { return await addNewQuestion(data.surveyId, { title: data.title, questionType: data.questionType }); } private async handleUpdateQuestion(data: QuestionActionData & { id: number }) { return await updateQuestion(data.id, { title: data.title, questionType: data.questionType }); } private async handleDeleteQuestion(data: QuestionActionData & { id: number }) { return await deleteQuestion(data.id); } private async handleCreateAnswer(data: AnswerActionData) { return await addNewAnswerVariant(data.surveyId, data.questionId, { text: data.text }); } private async handleUpdateAnswer(data: AnswerActionData & { id: number }) { try { const result = await updateAnswerVariant(data.id, { text: data.text }); return result; } catch (error) { console.error(error); throw error; } } private async handleDeleteAnswer(data: AnswerActionData & { id: number }) { return await deleteAnswerVariant(data.id); } } export const SurveyPage: React.FC = () => { const [questions, setQuestions] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [description, setDescription] = useState(''); const [title, setTitle] = useState(''); const { survey, setSurvey } = useOutletContext<{ survey: ISurvey; setSurvey: (survey: ISurvey) => void; }>(); useEffect(() => { if (!survey.id) { console.error('Survey ID is missing'); return; } const id = survey.id; if (isNaN(id)) { console.error('Invalid survey ID'); return; } const fetchData = async () => { try { setLoading(true); setSurvey(survey); setTitle(survey.title); setDescription(survey.description); const questionsData = await getListQuestions(id); const formattedQuestions = await Promise.all(questionsData.map(async q => { const answerVariants = await getAnswerVariants(id, q.id); return { id: q.id, text: q.title, questionType: q.questionType as 'SingleAnswerQuestion' | 'MultipleAnswerQuestion', answerVariants: answerVariants.map((a: IAnswerVariant) => ({ id: a.id, text: a.text })) }; })); setQuestions(formattedQuestions); } catch (error) { console.error('Ошибка:', error); setError('Не удалось загрузить опрос'); } finally { setLoading(false); } }; fetchData(); }, [survey.id]); const handleSave = async () => { if (!survey.id || !survey) return; try { setError(null); const id = survey.id; const actionQueue = new ActionQueue(); actionQueue.add({ type: 'update-survey', data: { id, title, description } as SurveyActionData }); const serverQuestions = await getListQuestions(id); questions.forEach(question => { const serverQuestion = serverQuestions.find(q => q.id === question.id); if (serverQuestion && (serverQuestion.title !== question.text || serverQuestion.questionType !== question.questionType)) { actionQueue.add({ type: 'update-question', data: { surveyId: id, id: question.id, title: question.text, questionType: question.questionType // Убедитесь, что передается новый тип } as QuestionActionData & { id: number } }); } }); questions.forEach(question => { question.answerVariants.forEach(answer => { if (!answer.id) { actionQueue.add({ type: 'create-answer', data: { surveyId: id, questionId: question.id, text: answer.text } as AnswerActionData }); } else { actionQueue.add({ type: 'update-answer', data: { surveyId: id, questionId: question.id, id: answer.id, text: answer.text } as AnswerActionData & { id: number } }); } }); }); serverQuestions.forEach(serverQuestion => { if (!questions.some(q => q.id === serverQuestion.id)) { actionQueue.add({ type: 'delete-question', data: { surveyId: id, id: serverQuestion.id } as QuestionActionData & { id: number } }); } }); await actionQueue.execute(); const updatedQuestions = await getListQuestions(id); const formattedQuestions = await Promise.all(updatedQuestions.map(async q => { const answerVariants = await getAnswerVariants(id, q.id); return { id: q.id, text: q.title, questionType: q.questionType as 'SingleAnswerQuestion' | 'MultipleAnswerQuestion', answerVariants: answerVariants.map((a: IAnswerVariant) => ({ id: a.id, text: a.text })) }; })); setQuestions(formattedQuestions); } catch (error) { console.error('Ошибка сохранения:', error); setError(`Ошибка сохранения: ${error instanceof Error ? error.message : 'Неизвестная ошибка'}`); } }; if (loading) return
Загрузка...
; if (!survey) return
Опрос не найден
; return (
{error &&
{error}
}
); };