input fix

This commit is contained in:
rngsurrounded
2025-03-03 05:28:27 +09:00
parent 8ecc380c01
commit 93e26431ca
2 changed files with 104 additions and 102 deletions
@@ -6,14 +6,14 @@ interface FileSolutionProps {
selectedFile: File | null;
setSelectedFile: (file: File | null) => void;
fileInputRef: React.RefObject<HTMLInputElement>;
fileUrl?: string | null;
existingFileUrl?: string | null;
}
const FileSolution: React.FC<FileSolutionProps> = ({
selectedFile,
setSelectedFile,
fileInputRef,
fileUrl = null
existingFileUrl = null
}) => {
const handleFileChange = (event: React.ChangeEvent<HTMLInputElement>) => {
if (event.target.files && event.target.files[0]) {
@@ -44,7 +44,13 @@ const FileSolution: React.FC<FileSolutionProps> = ({
}
};
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<FileSolutionProps> = ({
accept=".jpg,.jpeg,.png,.pptx,.docx,.pdf,.xlsx,.txt"
/>
{(selectedFile || fileUrl) ? (
{hasFile ? (
<div className="bg-white rounded-lg p-6 flex flex-col items-center justify-center min-h-[180px]">
<div className="flex flex-col items-center">
<FileIcon size={28} className="text-black mb-2" />
<span className="text-sm text-gray-700 font-medium mb-1 font-hse-sans">{fileName}</span>
<div className="flex items-center mt-2">
{fileUrl && (
{existingFileUrl && !selectedFile && (
<a
href={fileUrl}
href={existingFileUrl}
download
className="flex items-center text-blue-500 text-sm mr-3 hover:text-blue-600"
>
@@ -78,7 +84,7 @@ const FileSolution: React.FC<FileSolutionProps> = ({
className="text-blue-500 text-sm p-0 h-auto hover:bg-transparent hover:text-blue-600 font-hse-sans"
onClick={() => setSelectedFile(null)}
>
{fileUrl ? "Выбрать другой файл" : "Очистить"}
{!selectedFile && existingFileUrl ? "Выбрать другой файл" : "Очистить"}
</Button>
</div>
</div>
@@ -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<HTMLInputElement>;
existingFileUrl?: string | null;
onSubmit: () => void;
}
const FileSolution: React.FC<FileSolutionProps> = ({
const TaskSolution: React.FC<TaskSolutionProps> = ({
task,
answer,
setAnswer,
selectedFile,
setSelectedFile,
fileInputRef,
existingFileUrl = null
onSubmit,
}) => {
const handleFileChange = (event: React.ChangeEvent<HTMLInputElement>) => {
if (event.target.files && event.target.files[0]) {
setSelectedFile(event.target.files[0]);
const fileInputRef = useRef<HTMLInputElement>(null);
const [isHistoryOpen, setIsHistoryOpen] = useState(false);
const [selectedSolutionUrl, setSelectedSolutionUrl] = useState<string | null>(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 latestSolution = solutionHistory && solutionHistory.length > 0 ? solutionHistory[solutionHistory.length - 1] : null;
const handleSolutionSelect = async (solution: Solution) => {
if (!solution.content) return;
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 handleFileUploadClick = () => {
fileInputRef.current?.click();
};
const handleDragOver = (e: React.DragEvent<HTMLDivElement>) => {
e.preventDefault();
e.currentTarget.classList.add('bg-gray-50');
};
const handleDragLeave = (e: React.DragEvent<HTMLDivElement>) => {
e.preventDefault();
e.currentTarget.classList.remove('bg-gray-50');
};
const handleDrop = (e: React.DragEvent<HTMLDivElement>) => {
e.preventDefault();
e.currentTarget.classList.remove('bg-gray-50');
if (e.dataTransfer.files && e.dataTransfer.files[0]) {
setSelectedFile(e.dataTransfer.files[0]);
}
};
const fileName = selectedFile
? selectedFile.name
: existingFileUrl
? existingFileUrl.split('/').pop() || 'file'
: '';
const hasFile = !!selectedFile || !!existingFileUrl;
return (
<>
<input
type="file"
ref={fileInputRef}
className="hidden"
onChange={handleFileChange}
accept=".jpg,.jpeg,.png,.pptx,.docx,.pdf,.xlsx,.txt"
/>
{hasFile ? (
<div className="bg-white rounded-lg p-6 flex flex-col items-center justify-center min-h-[180px]">
<div className="flex flex-col items-center">
<FileIcon size={28} className="text-black mb-2" />
<span className="text-sm text-gray-700 font-medium mb-1 font-hse-sans">{fileName}</span>
<div className="flex items-center mt-2">
{existingFileUrl && !selectedFile && (
<a
href={existingFileUrl}
download
className="flex items-center text-blue-500 text-sm mr-3 hover:text-blue-600"
>
<Download size={16} className="mr-1" />
Скачать
</a>
)}
<Button
variant="ghost"
className="text-blue-500 text-sm p-0 h-auto hover:bg-transparent hover:text-blue-600 font-hse-sans"
onClick={() => setSelectedFile(null)}
>
{!selectedFile && existingFileUrl ? "Выбрать другой файл" : "Очистить"}
</Button>
</div>
</div>
</div>
<div className="md:w-[500px] flex flex-col gap-4">
{latestSolution ? (
<SolutionStatus solution={latestSolution} maxPoints={task.points}/>
) : (
<div
className="bg-white rounded-lg p-6 flex flex-col items-center justify-center min-h-[180px] cursor-pointer transition-colors"
onClick={handleFileUploadClick}
onDragOver={handleDragOver}
onDragLeave={handleDragLeave}
onDrop={handleDrop}
>
<FileIcon size={28} className="text-black mb-3" />
<span
className="bg-[var(--color-yellow-standard)] text-black font-medium rounded-full px-4 py-1.5 text-sm mb-2 font-hse-sans inline-block"
>
Загрузить файл
</span>
<p className="text-xs text-gray-500 text-center font-hse-sans">
Доступные форматы: jpg, jpeg, png, pptx, docx, pdf, xlsx, txt
</p>
<div className="bg-gray-100 rounded-lg p-4 text-gray-600 font-hse-sans">
Решение еще не отправлено
</div>
)}
</>
{task.type === TaskType.INPUT && (
<InputSolution answer={answer} setAnswer={setAnswer} />
)}
{task.type === TaskType.FILE && (
<FileSolution
selectedFile={selectedFile}
setSelectedFile={setSelectedFile}
fileInputRef={fileInputRef}
existingFileUrl={selectedSolutionUrl}
/>
)}
{task.type === TaskType.CODE && (
<CodeSolution answer={answer} setAnswer={setAnswer} />
)}
<ActionButtons
onSubmit={onSubmit}
onHistoryClick={handleOpenHistory}
/>
<SolutionHistorySheet
isOpen={isHistoryOpen}
onOpenChange={setIsHistoryOpen}
solutions={solutionHistory}
maxPoints={task.points}
onSolutionSelect={handleSolutionSelect}
/>
</div>
);
};
export default FileSolution;
export default TaskSolution;