mirror of
https://gitlab.com/megazordpobeda/DataRush.git
synced 2026-05-23 15:37:10 +00:00
feat: history sheet
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import { useState } from "react";
|
||||
import { useParams, Navigate } from "react-router-dom";
|
||||
import { Task } from "@/shared/types";
|
||||
import { mockTasks } from "@/shared/mocks/mocks";
|
||||
import { mockSolutions, mockTasks } from "@/shared/mocks/mocks";
|
||||
import CompetitionHeader from "./components/CompetitionHeader";
|
||||
import TaskContent from "./components/TaskContent";
|
||||
import TaskSolution from "./modules/TaskSolution";
|
||||
@@ -40,6 +40,7 @@ const CompetitionSessionPage = () => {
|
||||
<TaskContent task={currentTask} />
|
||||
<TaskSolution
|
||||
task={currentTask}
|
||||
solutions={mockSolutions}
|
||||
answer={answer}
|
||||
setAnswer={setAnswer}
|
||||
onSubmit={handleSubmit}
|
||||
|
||||
+40
-17
@@ -1,28 +1,51 @@
|
||||
import React from 'react';
|
||||
import React, { useState } from 'react';
|
||||
import { Button } from "@/components/ui/button";
|
||||
import SolutionHistorySheet from '../SolutionHistorySheet';
|
||||
import { Solution } from "@/shared/types";
|
||||
import { mockSolutions } from '@/shared/mocks/mocks';
|
||||
|
||||
interface ActionButtonsProps {
|
||||
onHistoryClick: () => void;
|
||||
onSubmit: () => void;
|
||||
solutionHistory?: Solution[];
|
||||
}
|
||||
|
||||
const ActionButtons: React.FC<ActionButtonsProps> = ({ onHistoryClick, onSubmit }) => {
|
||||
const ActionButtons: React.FC<ActionButtonsProps> = ({
|
||||
onHistoryClick,
|
||||
onSubmit,
|
||||
solutionHistory = mockSolutions
|
||||
}) => {
|
||||
const [isHistoryOpen, setIsHistoryOpen] = useState(false);
|
||||
|
||||
const handleHistoryClick = () => {
|
||||
setIsHistoryOpen(true);
|
||||
onHistoryClick();
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex gap-3 justify-between">
|
||||
<Button
|
||||
variant="ghost"
|
||||
className="font-hse-sans bg-white hover:bg-gray-100"
|
||||
onClick={onHistoryClick}
|
||||
>
|
||||
История
|
||||
</Button>
|
||||
<Button
|
||||
onClick={onSubmit}
|
||||
className="font-hse-sans"
|
||||
>
|
||||
Отправить решение
|
||||
</Button>
|
||||
</div>
|
||||
<>
|
||||
<div className="flex gap-8">
|
||||
<Button
|
||||
variant="ghost"
|
||||
className="font-hse-sans bg-white hover:bg-gray-100"
|
||||
onClick={handleHistoryClick}
|
||||
>
|
||||
История
|
||||
</Button>
|
||||
<Button
|
||||
onClick={onSubmit}
|
||||
className="font-hse-sans flex-grow"
|
||||
>
|
||||
Отправить решение
|
||||
</Button>
|
||||
</div>
|
||||
{/* чуть-чуть рак */}
|
||||
<SolutionHistorySheet
|
||||
isOpen={isHistoryOpen}
|
||||
onOpenChange={setIsHistoryOpen}
|
||||
solutions={solutionHistory}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
import React from 'react';
|
||||
import { Sheet, SheetClose, SheetContent, SheetHeader, SheetTitle } from "@/components/ui/sheet";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { X } from "lucide-react";
|
||||
import SolutionStatus from '../SolutionStatus';
|
||||
import { Solution } from "@/shared/types";
|
||||
|
||||
interface SolutionHistorySheetProps {
|
||||
isOpen: boolean;
|
||||
onOpenChange: (open: boolean) => void;
|
||||
solutions: Solution[];
|
||||
}
|
||||
|
||||
const SolutionHistorySheet: React.FC<SolutionHistorySheetProps> = ({
|
||||
isOpen,
|
||||
onOpenChange,
|
||||
solutions
|
||||
}) => {
|
||||
return (
|
||||
<Sheet open={isOpen} onOpenChange={onOpenChange}>
|
||||
<SheetContent className="w-[350px] sm:w-[450px] p-0">
|
||||
<SheetHeader className="border-b py-3 px-4">
|
||||
<div className="flex justify-between items-center">
|
||||
<SheetTitle className="text-lg font-medium">История решений</SheetTitle>
|
||||
<SheetClose asChild>
|
||||
<Button variant="ghost" size="icon" className="h-8 w-8">
|
||||
<X className="h-4 w-4" />
|
||||
</Button>
|
||||
</SheetClose>
|
||||
</div>
|
||||
</SheetHeader>
|
||||
|
||||
<div className="flex flex-col mt-3 space-y-2.5 overflow-y-auto max-h-[calc(100vh-80px)] px-4">
|
||||
{solutions.length > 0 ? (
|
||||
solutions.map((solution, index) => (
|
||||
<div key={index} className="w-full">
|
||||
<SolutionStatus solution={solution} />
|
||||
</div>
|
||||
))
|
||||
) : (
|
||||
<div className="text-center py-8 text-gray-500">
|
||||
У вас пока нет истории решений для этой задачи
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</SheetContent>
|
||||
</Sheet>
|
||||
);
|
||||
};
|
||||
|
||||
export default SolutionHistorySheet;
|
||||
+27
-10
@@ -1,24 +1,41 @@
|
||||
import React from 'react';
|
||||
import { Task } from "@/shared/types";
|
||||
import { Solution, TaskStatus } from "@/shared/types";
|
||||
import { getTaskBgColor, getTaskTextColor } from '@/pages/CompetitionSession/utils/utils';
|
||||
|
||||
interface SolutionStatusProps {
|
||||
task: Task;
|
||||
solution: Solution;
|
||||
}
|
||||
|
||||
const SolutionStatus: React.FC<SolutionStatusProps> = ({ task }) => {
|
||||
const SolutionStatus: React.FC<SolutionStatusProps> = ({ solution }) => {
|
||||
const getStatusText = (status: TaskStatus, score?: number, maxScore?: number) => {
|
||||
switch (status) {
|
||||
case 'checking':
|
||||
return 'На проверке';
|
||||
case 'wrong':
|
||||
return 'Неверный ответ';
|
||||
case 'correct':
|
||||
return `Зачтено ${maxScore}/${maxScore} баллов`;
|
||||
case 'partial':
|
||||
return `Зачтено ${score}/${maxScore} баллов`;
|
||||
case 'uncleared':
|
||||
return 'Не решено';
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={`${getTaskBgColor(task.status)} rounded-lg p-4 relative`}>
|
||||
<div className={`${getTaskBgColor(solution.status)} rounded-lg p-4 relative`}>
|
||||
<div className="flex flex-col">
|
||||
<span className={`${getTaskTextColor(task.status)} font-medium`}>
|
||||
Решение 12345
|
||||
<span className={`${getTaskTextColor(solution.status)} font-medium`}>
|
||||
Решение {solution.id}
|
||||
</span>
|
||||
<span className={`${getTaskTextColor(task.status)} mt-1`}>
|
||||
Зачтено 5/10 баллов
|
||||
<span className={`${getTaskTextColor(solution.status)} mt-1`}>
|
||||
{getStatusText(solution.status, solution.score, solution.maxScore)}
|
||||
</span>
|
||||
</div>
|
||||
<div className={`absolute bottom-2 right-3 text-xs ${getTaskTextColor(task.status)}`}>
|
||||
1 марта, 08:41
|
||||
<div className={`absolute bottom-2 right-3 text-xs ${getTaskTextColor(solution.status)}`}>
|
||||
{solution.date}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, { useState, useRef } from 'react';
|
||||
import { Task } from "@/shared/types";
|
||||
import { Solution, Task } from "@/shared/types";
|
||||
import SolutionStatus from './components/SolutionStatus';
|
||||
import InputSolution from './components/InputSolution';
|
||||
import FileSolution from './components/FileSolution';
|
||||
@@ -8,6 +8,7 @@ import ActionButtons from './components/ActionButtons';
|
||||
|
||||
interface TaskSolutionProps {
|
||||
task: Task;
|
||||
solutions: Solution[];
|
||||
answer: string;
|
||||
setAnswer: (value: string) => void;
|
||||
onSubmit: () => void;
|
||||
@@ -16,6 +17,7 @@ interface TaskSolutionProps {
|
||||
|
||||
const TaskSolution: React.FC<TaskSolutionProps> = ({
|
||||
task,
|
||||
solutions,
|
||||
answer,
|
||||
setAnswer,
|
||||
onSubmit,
|
||||
@@ -26,7 +28,7 @@ const TaskSolution: React.FC<TaskSolutionProps> = ({
|
||||
|
||||
return (
|
||||
<div className="md:w-[500px] flex flex-col gap-4">
|
||||
<SolutionStatus task={task} />
|
||||
<SolutionStatus solution={solutions[0]} />
|
||||
|
||||
{task.solutionType === 'input' && (
|
||||
<InputSolution answer={answer} setAnswer={setAnswer} />
|
||||
|
||||
Reference in New Issue
Block a user