test: competition start

This commit is contained in:
rngsurrounded
2025-03-02 21:12:53 +09:00
parent 2d961ea4e2
commit 4e8f931e7d
3 changed files with 82 additions and 106 deletions
@@ -2,40 +2,57 @@ import { useParams, Link, useNavigate } from "react-router-dom";
import { Button } from "@/components/ui/button";
import { ArrowLeft } from "lucide-react";
import ReactMarkdown from "react-markdown";
import { mockTasks } from "@/shared/mocks/mocks";
import { useQuery } from "@tanstack/react-query";
import { getCompetition } from "@/shared/api/competitions";
import { useQuery, useMutation } from "@tanstack/react-query";
import { getCompetition, startCompetition } from "@/shared/api/competitions";
import { getCompetitionTasks } from "@/shared/api/session";
import { Loading } from "@/components/ui/loading";
const CompetitionPage = () => {
const { id } = useParams<{ id: string }>();
const navigate = useNavigate();
const competitionId = id || "";
const { data: competition, isLoading } = useQuery({
queryKey: ["competition", id],
queryFn: async () => getCompetition(id || ""),
const competitionQuery = useQuery({
queryKey: ["competition", competitionId],
queryFn: () => getCompetition(competitionId),
enabled: !!competitionId,
});
if (isLoading) {
const startMutation = useMutation({
mutationFn: () => startCompetition(competitionId),
onSuccess: async () => {
try {
const tasks = await getCompetitionTasks(competitionId);
if (tasks && tasks.length > 0) {
navigate(`/competition/${competitionId}/tasks/${tasks[0].id}`);
} else {
navigate(`/competition/${competitionId}/tasks`);
}
} catch (error) {
console.error("Failed to fetch tasks:", error);
navigate(`/competition/${competitionId}/tasks`);
}
},
onError: (error) => {
console.error("Failed to start competition:", error);
}
});
const handleStart = () => {
startMutation.mutate();
};
if (competitionQuery.isLoading) {
return <Loading />;
}
if (!id || !competition) {
if (!competitionId || !competitionQuery.data) {
return <></>;
}
const handleContinue = () => {
if (competition?.id) {
if (mockTasks && mockTasks.length > 0) {
const firstTaskId = mockTasks[0].id;
navigate(`/competition/${competition.id}/tasks/${firstTaskId}`);
} else {
navigate(`/competition/${competition.id}/tasks`);
}
}
};
const competition = competitionQuery.data;
console.log(competition)
return (
<div className="flex flex-col gap-4">
<Link
@@ -47,13 +64,15 @@ const CompetitionPage = () => {
</Link>
<div className="flex flex-col gap-6">
<div className="aspect-2 h-auto w-full overflow-hidden rounded-xl">
<img
src={competition.image_url ? competition.image_url : '/DANO.png'}
alt={competition.title}
className="h-full w-full object-cover object-center"
/>
</div>
{competition.image_url && (
<div className="aspect-2 h-auto w-full overflow-hidden rounded-xl">
<img
src={competition.image_url}
alt={competition.title}
className="h-full w-full object-cover object-center"
/>
</div>
)}
<div className="flex flex-col-reverse gap-8 md:flex-row">
<div className="flex flex-1 flex-col gap-5">
@@ -65,8 +84,12 @@ const CompetitionPage = () => {
</div>
</div>
<div className="w-full *:w-full md:w-96">
<Button size={"lg"} onClick={handleContinue}>
Приступить к выполнению
<Button
size={"lg"}
onClick={handleStart}
disabled={startMutation.isPending}
>
{startMutation.isPending ? "Загрузка..." : "Начать"}
</Button>
</div>
</div>
@@ -75,4 +98,4 @@ const CompetitionPage = () => {
);
};
export default CompetitionPage;
export default CompetitionPage;
@@ -12,3 +12,9 @@ export const getCompetitions = async (participating?: boolean) => {
export const getCompetition = async (id: string) => {
return await userFetch<Competition>(`/competition/${id}`);
};
export const startCompetition = async (competitionId: string) => {
return await userFetch(`/competitions/${competitionId}/start`, {
method: 'POST'
});
};
+24 -77
View File
@@ -1,82 +1,29 @@
import { apiFetch } from './index';
import { Task, TaskStatus } from '@/shared/types';
import { userFetch } from ".";
import { Task } from "../types/task";
interface ApiTask {
id: string;
title: string;
description: string;
type: 'input' | 'file' | 'code';
in_competition_position: number;
points: number;
status?: TaskStatus;
}
/**
* Fetches tasks for a specific competition
* @param competitionId - The ID of the competition
* @returns Promise with an array of tasks in the application's format
*/
export const getCompetitionTasks = async (competitionId: string): Promise<Task[]> => {
try {
const apiTasks: ApiTask[] = await apiFetch(`/api/v1/competitions/${competitionId}/tasks`);
// Transform API tasks to application Task format
return apiTasks.map(apiTask => transformApiTask(apiTask));
} catch (error) {
console.error('Failed to fetch competition tasks:', error);
throw error;
}
export const getCompetitionTasks = async (competitionId: string) => {
return await userFetch<Task[]>(`/competitions/${competitionId}/tasks`);
};
/**
* Transforms an API task to the application's Task format
*/
const transformApiTask = (apiTask: ApiTask): Task => {
return {
id: apiTask.id,
number: String(apiTask.in_competition_position),
status: apiTask.status || TaskStatus.Uncleared,
solutionType: apiTask.type,
description: apiTask.description,
maxScore: apiTask.points
};
};
// export const submitTaskSolution = async (
// competitionId: string,
// taskId: string,
// solution: string | File
// ): Promise<void> => {
// const endpoint = `/api/v1/competitions/${competitionId}/tasks/${taskId}/submit`;
export const submitTaskSolution = async (
competitionId: string,
taskId: string,
solution: string | File
) => {
const endpoint = `/competitions/${competitionId}/tasks/${taskId}/submit`;
// // Handle different solution types
// if (typeof solution === 'string') {
// // Text or code solution
// await apiFetch(endpoint, {
// method: 'POST',
// body: { answer: solution }
// });
// } else {
// // File solution
// const formData = new FormData();
// formData.append('file', solution);
if (typeof solution === 'string') {
return await userFetch(endpoint, {
method: 'POST',
body: { answer: solution }
});
} else {
const formData = new FormData();
formData.append('file', solution);
// await apiFetch(endpoint, {
// method: 'POST',
// body: formData
// });
// }
// };
/**
* Gets the status of a task submission
* This would be used to poll for updates after submission
*/
// export const getTaskSubmissionStatus = async (
// competitionId: string,
// taskId: string
// ): Promise<TaskStatus> => {
// const response = await apiFetch(`/api/v1/competitions/${competitionId}/tasks/${taskId}/status`);
// return response.status;
// };
return await userFetch(endpoint, {
method: 'POST',
body: formData
});
}
};