feat: add SubmitPage
This commit is contained in:
parent
0be3286bb3
commit
9274b3314d
@ -2,3 +2,5 @@ node_modules/
|
||||
/dist/
|
||||
/pnpm-lock.yaml
|
||||
/postcss.config.cjs
|
||||
|
||||
src/components/Languages.tsx
|
||||
|
38
src/app/services/submission.ts
Normal file
38
src/app/services/submission.ts
Normal file
@ -0,0 +1,38 @@
|
||||
import type { Meta, Wrap } from "./base";
|
||||
import type { UserProfile } from "./user";
|
||||
import type { ProblemInfo } from "./problem";
|
||||
import { api } from "./api";
|
||||
|
||||
export interface SubmissionInfo {
|
||||
meta: Meta;
|
||||
problem: ProblemInfo;
|
||||
user: UserProfile;
|
||||
language: string;
|
||||
code: string;
|
||||
}
|
||||
|
||||
export interface SubmitRequest {
|
||||
pid: number;
|
||||
language: string;
|
||||
code: string;
|
||||
}
|
||||
|
||||
export interface ReJudgeResponse {
|
||||
sid: number;
|
||||
}
|
||||
|
||||
export const submissionApi = api.injectEndpoints({
|
||||
endpoints: (builder) => ({
|
||||
submit: builder.mutation<Wrap<string>, SubmitRequest>({
|
||||
query: (data: SubmitRequest) => ({
|
||||
url: "/submission/create",
|
||||
method: "POST",
|
||||
body: data,
|
||||
}),
|
||||
invalidatesTags: [{ type: "Status", id: "Search" }],
|
||||
}),
|
||||
}),
|
||||
// TODO: admin endpoints: rejudge
|
||||
});
|
||||
|
||||
export const { useSubmitMutation } = submissionApi;
|
10
src/components/Languages.tsx
Normal file
10
src/components/Languages.tsx
Normal file
@ -0,0 +1,10 @@
|
||||
/* eslint-disable prettier/prettier */
|
||||
export const LanguageMap: { [lang: string]: { label: string; mode: string; prism: string } } = {
|
||||
c: { label: "C", mode: "c_cpp", prism: "cpp" },
|
||||
cpp: { label: "C++", mode: "c_cpp", prism: "cpp" },
|
||||
python3: { label: "Python3", mode: "python", prism: "python" },
|
||||
pypy3: { label: "PyPy3", mode: "python", prism: "python" },
|
||||
rust: { label: "Rust", mode: "rust", prism: "rust" },
|
||||
go: { label: "Go", mode: "golang", prism: "go" },
|
||||
};
|
||||
/* eslint-enable prettier/prettier */
|
@ -85,7 +85,7 @@ export default function LoginPage() {
|
||||
|
||||
try {
|
||||
// authSlice will automatically handle the response
|
||||
await login(formState).unwrap();
|
||||
await login(formState);
|
||||
navigate("/");
|
||||
} catch (err) {
|
||||
const errTyped = err as { status: number | string; data: Wrap<void> };
|
||||
|
65
src/pages/SubmitPage.tsx
Normal file
65
src/pages/SubmitPage.tsx
Normal file
@ -0,0 +1,65 @@
|
||||
import { lazy, useEffect, useState } from "react";
|
||||
import { Box, Button, Stack, useToast } from "@chakra-ui/react";
|
||||
import { useNavigate, useParams } from "react-router-dom";
|
||||
import { MdPlayCircleOutline } from "react-icons/md";
|
||||
|
||||
import { LanguageMap } from "../components/Languages";
|
||||
import { useDetailQuery } from "../app/services/problem";
|
||||
import { useSubmitMutation } from "../app/services/submission";
|
||||
|
||||
const Editor = lazy(() => import("../components/Editor"));
|
||||
const ProblemInfoMenu = lazy(() => import("../components/ProblemInfoMenu"));
|
||||
|
||||
export default function SubmitPage() {
|
||||
const { id } = useParams();
|
||||
const toast = useToast();
|
||||
const navigate = useNavigate();
|
||||
const { data: details } = useDetailQuery({ pid: Number(id) || 0 });
|
||||
const [submit, result] = useSubmitMutation();
|
||||
|
||||
const [lang, setLang] = useState("c");
|
||||
const [code, setCode] = useState("");
|
||||
|
||||
const submitCode = () => {
|
||||
void submit({ pid: Number(id) || 0, language: lang, code: code });
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (result.isSuccess) {
|
||||
navigate(`/problem/${id}/status`);
|
||||
} else if (result.isError) {
|
||||
toast({
|
||||
status: "error",
|
||||
title: "Oops...",
|
||||
description: "Submit Failed",
|
||||
isClosable: true,
|
||||
});
|
||||
}
|
||||
}, [id, navigate, result, toast]);
|
||||
|
||||
const actionBtn = (
|
||||
<Button
|
||||
variant="solid"
|
||||
size="sm"
|
||||
colorScheme="green"
|
||||
leftIcon={<MdPlayCircleOutline />}
|
||||
isLoading={result.isLoading}
|
||||
onClick={submitCode}
|
||||
>
|
||||
Submit
|
||||
</Button>
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Stack direction={{ base: "column", md: "row" }}>
|
||||
<Box w="100%">
|
||||
<Editor mode={LanguageMap[lang].mode} onChange={setCode} />
|
||||
</Box>
|
||||
<Box w="480px">
|
||||
<ProblemInfoMenu data={details?.body} onLanguageSelect={setLang} action={actionBtn} />
|
||||
</Box>
|
||||
</Stack>
|
||||
</>
|
||||
);
|
||||
}
|
@ -3,13 +3,14 @@ import type { RouteObject } from "react-router-dom";
|
||||
|
||||
import { Root } from "./pages/Root";
|
||||
import { ErrorPage } from "./pages/ErrorPage";
|
||||
// import { RequireAuth } from "./components/RequireAuth";
|
||||
import { RequireAuth } from "./components/RequireAuth";
|
||||
|
||||
const HomePage = lazy(() => import("./pages/HomePage"));
|
||||
const LoginPage = lazy(() => import("./pages/LoginPage"));
|
||||
const LogoutPage = lazy(() => import("./pages/LogoutPage"));
|
||||
const ProblemListPage = lazy(() => import("./pages/ProblemListPage"));
|
||||
const ProblemDetailPage = lazy(() => import("./pages/ProblemDetailPage"));
|
||||
const SubmitPage = lazy(() => import("./pages/SubmitPage"));
|
||||
|
||||
export const router: RouteObject[] = [
|
||||
{
|
||||
@ -41,6 +42,14 @@ export const router: RouteObject[] = [
|
||||
path: "problem/:id",
|
||||
element: <ProblemDetailPage />,
|
||||
},
|
||||
{
|
||||
path: "problem/:id/submit",
|
||||
element: (
|
||||
<RequireAuth>
|
||||
<SubmitPage />
|
||||
</RequireAuth>
|
||||
),
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
Loading…
Reference in New Issue
Block a user