diff --git a/frontend/src/lib/api.ts b/frontend/src/lib/api.ts index 528ac63..bd58112 100644 --- a/frontend/src/lib/api.ts +++ b/frontend/src/lib/api.ts @@ -5,10 +5,23 @@ import type { QuestionDetail, QuestionListResponse, Stats, + SubmissionRequest, + SubmissionResponse, } from "@/types"; const API_BASE_URL = process.env.NEXT_PUBLIC_API_URL || "http://localhost:8000"; +export class ApiError extends Error { + constructor( + public status: number, + public statusText: string, + public detail?: string + ) { + super(detail || `API error: ${status} ${statusText}`); + this.name = "ApiError"; + } +} + async function fetchApi( endpoint: string, options?: RequestInit @@ -23,7 +36,14 @@ async function fetchApi( }); if (!response.ok) { - throw new Error(`API error: ${response.status} ${response.statusText}`); + let detail: string | undefined; + try { + const errorBody = await response.json(); + detail = errorBody.detail; + } catch { + // Ignore JSON parse errors + } + throw new ApiError(response.status, response.statusText, detail); } return response.json(); @@ -77,3 +97,13 @@ export async function getPattern(slug: string): Promise { export async function getStats(): Promise { return fetchApi("/api/stats"); } + +export async function submitSolution( + slug: string, + submission: SubmissionRequest +): Promise { + return fetchApi(`/api/questions/${slug}/submit`, { + method: "POST", + body: JSON.stringify(submission), + }); +} diff --git a/frontend/src/types/index.ts b/frontend/src/types/index.ts index 444bb90..322d94f 100644 --- a/frontend/src/types/index.ts +++ b/frontend/src/types/index.ts @@ -61,6 +61,17 @@ export interface Solution { explanation: string | null; } +export interface VisibleTestCase { + id: number; + input: Record; + expected: unknown; +} + +export interface HiddenTestInput { + id: number; + input: Record; +} + export interface QuestionDetail extends QuestionListItem { description: string; constraints: string | null; @@ -69,6 +80,9 @@ export interface QuestionDetail extends QuestionListItem { output: string; explanation?: string; }> | null; + function_signature: string | null; + visible_test_cases: VisibleTestCase[] | null; + hidden_test_inputs: HiddenTestInput[] | null; explanation: Explanation | null; solutions: Solution[]; updated_at: string; @@ -114,3 +128,30 @@ export interface Stats { by_category: CategoryCount[]; by_pattern: PatternCount[]; } + +export interface HiddenTestOutput { + test_id: number; + output: unknown; +} + +export interface SubmissionRequest { + code: string; + hidden_outputs: HiddenTestOutput[]; +} + +export interface TestResult { + test_id: number; + passed: boolean; + input?: Record; + expected?: unknown; + actual: unknown; + error?: string; +} + +export interface SubmissionResponse { + passed: boolean; + visible_results: TestResult[]; + hidden_results: TestResult[]; + total_passed: number; + total_tests: number; +}