diff --git a/services/frontend/src/pages/Competition/index.tsx b/services/frontend/src/pages/Competition/index.tsx index 290e979..fe37509 100644 --- a/services/frontend/src/pages/Competition/index.tsx +++ b/services/frontend/src/pages/Competition/index.tsx @@ -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 ; } - 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 (
{
-
- {competition.title} -
+ {competition.image_url && ( +
+ {competition.title} +
+ )}
@@ -65,8 +84,12 @@ const CompetitionPage = () => {
-
@@ -75,4 +98,4 @@ const CompetitionPage = () => { ); }; -export default CompetitionPage; +export default CompetitionPage; \ No newline at end of file diff --git a/services/frontend/src/shared/api/competitions.ts b/services/frontend/src/shared/api/competitions.ts index 5a5eba0..8c47564 100644 --- a/services/frontend/src/shared/api/competitions.ts +++ b/services/frontend/src/shared/api/competitions.ts @@ -12,3 +12,9 @@ export const getCompetitions = async (participating?: boolean) => { export const getCompetition = async (id: string) => { return await userFetch(`/competition/${id}`); }; + +export const startCompetition = async (competitionId: string) => { + return await userFetch(`/competitions/${competitionId}/start`, { + method: 'POST' + }); +}; \ No newline at end of file diff --git a/services/frontend/src/shared/api/session.ts b/services/frontend/src/shared/api/session.ts index 564e91a..0cc6383 100644 --- a/services/frontend/src/shared/api/session.ts +++ b/services/frontend/src/shared/api/session.ts @@ -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 => { - 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(`/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 => { -// 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 => { -// const response = await apiFetch(`/api/v1/competitions/${competitionId}/tasks/${taskId}/status`); -// return response.status; -// }; \ No newline at end of file + return await userFetch(endpoint, { + method: 'POST', + body: formData + }); + } +}; \ No newline at end of file