diff --git a/services/frontend/src/pages/CompetitionSession/modules/TaskSolution/components/FileSolution/index.tsx b/services/frontend/src/pages/CompetitionSession/modules/TaskSolution/components/FileSolution/index.tsx index ed1a191..cd2b1d4 100644 --- a/services/frontend/src/pages/CompetitionSession/modules/TaskSolution/components/FileSolution/index.tsx +++ b/services/frontend/src/pages/CompetitionSession/modules/TaskSolution/components/FileSolution/index.tsx @@ -6,14 +6,14 @@ interface FileSolutionProps { selectedFile: File | null; setSelectedFile: (file: File | null) => void; fileInputRef: React.RefObject; - fileUrl?: string | null; + existingFileUrl?: string | null; } const FileSolution: React.FC = ({ selectedFile, setSelectedFile, fileInputRef, - fileUrl = null + existingFileUrl = null }) => { const handleFileChange = (event: React.ChangeEvent) => { if (event.target.files && event.target.files[0]) { @@ -44,7 +44,13 @@ const FileSolution: React.FC = ({ } }; - const fileName = selectedFile ? selectedFile.name : fileUrl ? fileUrl.split('/').pop() || 'file' : ''; + const fileName = selectedFile + ? selectedFile.name + : existingFileUrl + ? existingFileUrl.split('/').pop() || 'file' + : ''; + + const hasFile = !!selectedFile || !!existingFileUrl; return ( <> @@ -56,16 +62,16 @@ const FileSolution: React.FC = ({ accept=".jpg,.jpeg,.png,.pptx,.docx,.pdf,.xlsx,.txt" /> - {(selectedFile || fileUrl) ? ( + {hasFile ? (
diff --git a/services/frontend/src/pages/CompetitionSession/modules/TaskSolution/index.tsx b/services/frontend/src/pages/CompetitionSession/modules/TaskSolution/index.tsx index cd2b1d4..d78f313 100644 --- a/services/frontend/src/pages/CompetitionSession/modules/TaskSolution/index.tsx +++ b/services/frontend/src/pages/CompetitionSession/modules/TaskSolution/index.tsx @@ -1,115 +1,111 @@ -import React from 'react'; -import { FileIcon, Download } from 'lucide-react'; -import { Button } from "@/components/ui/button"; +import React, { useState, useRef } from 'react'; +import { useParams } from 'react-router-dom'; +import { Task, TaskType, Solution } from '@/shared/types/task'; +import { useQuery } from '@tanstack/react-query'; +import { getTaskSolutionHistory } from '@/shared/api/session'; +import SolutionStatus from './components/SolutionStatus'; +import InputSolution from './components/InputSolution'; +import FileSolution from './components/FileSolution'; +import CodeSolution from './components/CodeSolution'; +import ActionButtons from './components/ActionButtons'; +import SolutionHistorySheet from './components/SolutionHistorySheet'; -interface FileSolutionProps { +interface TaskSolutionProps { + task: Task; + answer: string; + setAnswer: (value: string) => void; selectedFile: File | null; setSelectedFile: (file: File | null) => void; - fileInputRef: React.RefObject; - existingFileUrl?: string | null; + onSubmit: () => void; } -const FileSolution: React.FC = ({ - selectedFile, +const TaskSolution: React.FC = ({ + task, + answer, + setAnswer, + selectedFile, setSelectedFile, - fileInputRef, - existingFileUrl = null + onSubmit, }) => { - const handleFileChange = (event: React.ChangeEvent) => { - if (event.target.files && event.target.files[0]) { - setSelectedFile(event.target.files[0]); - } + const fileInputRef = useRef(null); + const [isHistoryOpen, setIsHistoryOpen] = useState(false); + const [selectedSolutionUrl, setSelectedSolutionUrl] = useState(null); + const { id: competitionId } = useParams<{ id: string }>(); + + const solutionsQuery = useQuery({ + queryKey: ['solutionHistory', competitionId, task.id], + queryFn: () => getTaskSolutionHistory(competitionId || '', task.id), + enabled: !!(competitionId && task.id), + }); + + const solutionHistory = solutionsQuery.data || []; + + const handleOpenHistory = () => { + setIsHistoryOpen(true); }; - const handleFileUploadClick = () => { - fileInputRef.current?.click(); - }; + const latestSolution = solutionHistory && solutionHistory.length > 0 ? solutionHistory[solutionHistory.length - 1] : null; - const handleDragOver = (e: React.DragEvent) => { - e.preventDefault(); - e.currentTarget.classList.add('bg-gray-50'); - }; - - const handleDragLeave = (e: React.DragEvent) => { - e.preventDefault(); - e.currentTarget.classList.remove('bg-gray-50'); - }; - - const handleDrop = (e: React.DragEvent) => { - e.preventDefault(); - e.currentTarget.classList.remove('bg-gray-50'); + const handleSolutionSelect = async (solution: Solution) => { + if (!solution.content) return; - if (e.dataTransfer.files && e.dataTransfer.files[0]) { - setSelectedFile(e.dataTransfer.files[0]); - } + setSelectedSolutionUrl(solution.content); + + try { + if (task.type !== TaskType.FILE) { + const response = await fetch(solution.content); + if (!response.ok) { + throw new Error(`Failed to fetch solution content: ${response.status}`); + } + const text = await response.text(); + setAnswer(text); + } + } catch (error) { + console.error('Error loading solution content:', error); + } }; - const fileName = selectedFile - ? selectedFile.name - : existingFileUrl - ? existingFileUrl.split('/').pop() || 'file' - : ''; - - const hasFile = !!selectedFile || !!existingFileUrl; - return ( - <> - - - {hasFile ? ( -
-
- - {fileName} - -
- {existingFileUrl && !selectedFile && ( - - - Скачать - - )} - -
-
-
+
+ {latestSolution ? ( + ) : ( -
- - - Загрузить файл - -

- Доступные форматы: jpg, jpeg, png, pptx, docx, pdf, xlsx, txt -

+
+ Решение еще не отправлено
)} - + + {task.type === TaskType.INPUT && ( + + )} + + {task.type === TaskType.FILE && ( + + )} + + {task.type === TaskType.CODE && ( + + )} + + + + +
); }; -export default FileSolution; \ No newline at end of file +export default TaskSolution; \ No newline at end of file