feat: history sheet

This commit is contained in:
rngsurrounded
2025-03-01 23:48:12 +09:00
parent 3a879dc466
commit 01e775605e
10 changed files with 428 additions and 34 deletions
@@ -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}
/>
</>
);
};
@@ -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;
@@ -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} />