From 7604fe20042d5ad732dc0659002596a93064e8f2 Mon Sep 17 00:00:00 2001 From: Dmitry Date: Wed, 7 Jan 2026 16:59:18 +0300 Subject: [PATCH] admin --- admin/src/pages/PacksPage.tsx | 96 +++++++++++++++++++++++++++++++---- src/pages/RoomPage.jsx | 7 ++- 2 files changed, 91 insertions(+), 12 deletions(-) diff --git a/admin/src/pages/PacksPage.tsx b/admin/src/pages/PacksPage.tsx index b2f4e2d..ac1a61f 100644 --- a/admin/src/pages/PacksPage.tsx +++ b/admin/src/pages/PacksPage.tsx @@ -3,7 +3,9 @@ import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query' import { toast } from 'sonner' import { packsApi, isPacksApiError } from '@/api/packs' import { formatApiError, getDetailedErrorMessage } from '@/lib/error-utils' -import type { EditCardPackDto, CardPackPreviewDto, PaginatedResponse, Question } from '@/types/models' +import type { EditCardPackDto, CardPackPreviewDto, PaginatedResponse } from '@/types/models' +import type { Question } from '@/types/questions' +import { questionFromJson, questionToJson } from '@/types/questions' import { Button } from '@/components/ui/button' import { Input } from '@/components/ui/input' import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card' @@ -37,6 +39,8 @@ import { Label } from '@/components/ui/label' import { Textarea } from '@/components/ui/textarea' import { Checkbox } from '@/components/ui/checkbox' import { Plus, Search, Edit, Trash2, ChevronLeft, ChevronRight } from 'lucide-react' +import { TestQuestionsManager } from '@/components/TestQuestionsManager' +import { QuestionEditorDialog } from '@/components/QuestionEditorDialog' export default function PacksPage() { const queryClient = useQueryClient() @@ -48,6 +52,13 @@ export default function PacksPage() { const [isDeleteDialogOpen, setIsDeleteDialogOpen] = useState(false) const [packToDelete, setPackToDelete] = useState(null) + // Question editor state + const [isQuestionEditorOpen, setIsQuestionEditorOpen] = useState(false) + const [editingQuestion, setEditingQuestion] = useState<{ + question: Question | null + index: number + } | null>(null) + // Form state const [formData, setFormData] = useState({ name: '', @@ -139,12 +150,18 @@ export default function PacksPage() { try { const fullPack = await packsApi.getPack(pack.id) setSelectedPack(fullPack) + + // Convert questions from backend format to frontend format + const questions: Question[] = Array.isArray(fullPack.questions) + ? fullPack.questions.map((q: unknown) => questionFromJson(q)) + : [] + setFormData({ name: fullPack.name || '', description: fullPack.description || '', category: fullPack.category || '', isPublic: fullPack.isPublic ?? true, - questions: fullPack.questions || [], + questions, }) setIsDialogOpen(true) @@ -180,6 +197,9 @@ export default function PacksPage() { return } + // Convert questions to backend format + const questionsForBackend = formData.questions.map(q => questionToJson(q)) + const packData: EditCardPackDto = { // Only include id for updates, not for new packs ...(selectedPack && { id: selectedPack.id }), @@ -187,7 +207,7 @@ export default function PacksPage() { description: formData.description.trim(), category: formData.category.trim(), isPublic: formData.isPublic, - questions: formData.questions, + questions: questionsForBackend as any, // Backend expects different format } if (selectedPack) { @@ -197,6 +217,42 @@ export default function PacksPage() { } } + // Question editor handlers + const handleAddQuestion = () => { + setEditingQuestion({ question: null, index: -1 }) + setIsQuestionEditorOpen(true) + } + + const handleEditQuestion = (question: Question, index: number) => { + setEditingQuestion({ question, index }) + setIsQuestionEditorOpen(true) + } + + const handleSaveQuestion = (question: Question) => { + if (editingQuestion) { + const newQuestions = [...formData.questions] + if (editingQuestion.index >= 0) { + // Update existing question + newQuestions[editingQuestion.index] = question + } else { + // Add new question + newQuestions.push(question) + } + setFormData(prev => ({ ...prev, questions: newQuestions })) + } + setIsQuestionEditorOpen(false) + setEditingQuestion(null) + } + + const handleCloseQuestionEditor = () => { + setIsQuestionEditorOpen(false) + setEditingQuestion(null) + } + + const handleQuestionsChange = (questions: Question[]) => { + setFormData(prev => ({ ...prev, questions })) + } + const handleDelete = (pack: CardPackPreviewDto) => { setPackToDelete(pack) setIsDeleteDialogOpen(true) @@ -384,7 +440,7 @@ export default function PacksPage() { {/* Create/Edit Dialog */} - + {selectedPack ? 'Edit Pack' : 'Create New Pack'} @@ -439,13 +495,23 @@ export default function PacksPage() {
- -

- {formData.questions.length} question(s) in this pack -

-

- Questions can be managed through the question editor -

+
+ + +
+
@@ -461,6 +527,14 @@ export default function PacksPage() {
+ {/* Question Editor Dialog */} + + {/* Delete Confirmation Dialog */} diff --git a/src/pages/RoomPage.jsx b/src/pages/RoomPage.jsx index 7f9f9a9..688591f 100644 --- a/src/pages/RoomPage.jsx +++ b/src/pages/RoomPage.jsx @@ -251,7 +251,12 @@ const RoomPage = () => { > Показать QR-код - {isHost && room.status === 'WAITING' && ( + {isHost && + (room.status === 'WAITING' || + (room.status === 'PLAYING' && + (!room.questionPack || + room.questionPack.questionCount === 0 || + room.currentQuestionIndex === 0))) && (