feat: add ProblemDetailPage
This commit is contained in:
parent
df7f87d6bf
commit
afbf796208
157
src/components/ProblemInfoMenu.tsx
Normal file
157
src/components/ProblemInfoMenu.tsx
Normal file
@ -0,0 +1,157 @@
|
||||
import type React from "react";
|
||||
import { useEffect, useState } from "react";
|
||||
import {
|
||||
Accordion,
|
||||
AccordionButton,
|
||||
AccordionIcon,
|
||||
AccordionItem,
|
||||
AccordionPanel,
|
||||
Box,
|
||||
Link,
|
||||
Select,
|
||||
Table,
|
||||
Tag,
|
||||
Tbody,
|
||||
Td,
|
||||
Tr,
|
||||
Wrap,
|
||||
WrapItem,
|
||||
} from "@chakra-ui/react";
|
||||
import { Link as ReactRouterLink } from "react-router-dom";
|
||||
import type { DetailResponse, RuntimeInfo } from "../app/services/problem";
|
||||
|
||||
const TitleItem = ({ word }: { word: string }) => (
|
||||
<h2>
|
||||
<AccordionButton>
|
||||
<Box as="span" flex="1" textAlign="left">
|
||||
{word}
|
||||
</Box>
|
||||
<AccordionIcon />
|
||||
</AccordionButton>
|
||||
</h2>
|
||||
);
|
||||
|
||||
interface ProblemInfoMenuProps {
|
||||
data?: DetailResponse;
|
||||
onLanguageSelect?: (lang: string) => void;
|
||||
action?: React.ReactNode;
|
||||
}
|
||||
|
||||
const EmptyRuntime: RuntimeInfo = {
|
||||
TimeLimit: 0,
|
||||
MemoryLimit: 0,
|
||||
NProcLimit: 0,
|
||||
};
|
||||
|
||||
export default function ProblemInfoMenu(props: ProblemInfoMenuProps) {
|
||||
const [lang, setLang] = useState(props.data?.context.Languages[0]?.Lang || "c");
|
||||
const runtime = props.data?.context.Languages.find((x) => x.Lang === lang)?.Runtime.Run || EmptyRuntime;
|
||||
useEffect(() => {
|
||||
props.onLanguageSelect && props.onLanguageSelect(lang);
|
||||
}, [lang, props]);
|
||||
|
||||
const problemInfo = (
|
||||
<Table variant="striped" size="sm">
|
||||
<Tbody>
|
||||
<Tr>
|
||||
<Td>Title</Td>
|
||||
<Td>{props.data?.problem.title || "..."}</Td>
|
||||
</Tr>
|
||||
<Tr>
|
||||
<Td>Author</Td>
|
||||
<Td>
|
||||
<Link
|
||||
as={ReactRouterLink}
|
||||
color="blue.500"
|
||||
to={`/profile/${props.data?.problem.provider.meta.ID || 0}`}
|
||||
>
|
||||
{props.data?.problem.provider.nick_name || "..."}
|
||||
</Link>
|
||||
</Td>
|
||||
</Tr>
|
||||
<Tr>
|
||||
<Td>Languages</Td>
|
||||
<Td>
|
||||
<Wrap>
|
||||
{props.data?.context.Languages.map((l) => (
|
||||
<WrapItem key={l.Lang}>
|
||||
<Tag variant="outline" size="sm" colorScheme="pink">
|
||||
{l.Lang}
|
||||
</Tag>
|
||||
</WrapItem>
|
||||
))}
|
||||
</Wrap>
|
||||
</Td>
|
||||
</Tr>
|
||||
<Tr>
|
||||
<Td>Tags</Td>
|
||||
<Td>
|
||||
<Wrap>
|
||||
{props.data?.problem.tags.Elements.map((t) => (
|
||||
<WrapItem key={t}>
|
||||
<Tag variant="outline" size="sm" colorScheme="orange">
|
||||
{t}
|
||||
</Tag>
|
||||
</WrapItem>
|
||||
))}
|
||||
</Wrap>
|
||||
</Td>
|
||||
</Tr>
|
||||
</Tbody>
|
||||
</Table>
|
||||
);
|
||||
|
||||
const taskInfo = (
|
||||
<Table variant="striped" size="sm">
|
||||
<Tbody>
|
||||
<Tr>
|
||||
<Td>Time Limit</Td>
|
||||
<Td>{runtime.TimeLimit} ms</Td>
|
||||
</Tr>
|
||||
<Tr>
|
||||
<Td>Memory Limit</Td>
|
||||
<Td>{runtime.MemoryLimit} MB</Td>
|
||||
</Tr>
|
||||
<Tr>
|
||||
<Td>Process Limit</Td>
|
||||
<Td>{runtime.NProcLimit}</Td>
|
||||
</Tr>
|
||||
<Tr>
|
||||
<Td>Select</Td>
|
||||
<Td>
|
||||
<Select size="sm" onChange={(e) => setLang(e.target.value)} value={lang}>
|
||||
{props.data?.context.Languages.map((l) => (
|
||||
<option key={l.Lang} value={l.Lang}>
|
||||
{l.Lang}
|
||||
</option>
|
||||
))}
|
||||
</Select>
|
||||
</Td>
|
||||
</Tr>
|
||||
</Tbody>
|
||||
</Table>
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Accordion defaultIndex={[0, 1, ...(props.action ? [2] : [])]} allowMultiple>
|
||||
<AccordionItem>
|
||||
<TitleItem word="Problem Info" />
|
||||
<AccordionPanel pb={4}>{problemInfo}</AccordionPanel>
|
||||
</AccordionItem>
|
||||
|
||||
<AccordionItem>
|
||||
<TitleItem word="Task Info" />
|
||||
<AccordionPanel pb={4}>{taskInfo}</AccordionPanel>
|
||||
</AccordionItem>
|
||||
|
||||
{props.action && (
|
||||
<AccordionItem>
|
||||
<TitleItem word="Action" />
|
||||
<AccordionPanel pb={4}>{props.action}</AccordionPanel>
|
||||
</AccordionItem>
|
||||
)}
|
||||
</Accordion>
|
||||
</>
|
||||
);
|
||||
}
|
52
src/pages/ProblemDetailPage.tsx
Normal file
52
src/pages/ProblemDetailPage.tsx
Normal file
@ -0,0 +1,52 @@
|
||||
import { useNavigate, useParams } from "react-router-dom";
|
||||
import { Box, Button, Stack, Wrap, WrapItem } from "@chakra-ui/react";
|
||||
import { MdPlayCircleOutline, MdSearch } from "react-icons/md";
|
||||
|
||||
import { useDetailQuery } from "../app/services/problem";
|
||||
import Markdown from "../components/Markdown";
|
||||
import ProblemInfoMenu from "../components/ProblemInfoMenu";
|
||||
|
||||
export default function ProblemDetailPage() {
|
||||
const { id } = useParams();
|
||||
const navigate = useNavigate();
|
||||
|
||||
const { data: details } = useDetailQuery({ pid: Number(id) || 0 });
|
||||
|
||||
const actionBtn = (
|
||||
<Wrap>
|
||||
<WrapItem>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
leftIcon={<MdPlayCircleOutline />}
|
||||
onClick={() => navigate(`/problem/${id}/submit`)}
|
||||
>
|
||||
Submit
|
||||
</Button>
|
||||
</WrapItem>
|
||||
<WrapItem>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
leftIcon={<MdSearch />}
|
||||
onClick={() => navigate(`/problem/${id}/status`)}
|
||||
>
|
||||
Status
|
||||
</Button>
|
||||
</WrapItem>
|
||||
</Wrap>
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Stack direction={{ base: "column", md: "row" }}>
|
||||
<Box w="100%">
|
||||
<Markdown markdown={details?.body.problem.statement || ""} />
|
||||
</Box>
|
||||
<Box w="480px">
|
||||
<ProblemInfoMenu data={details?.body} action={actionBtn} />
|
||||
</Box>
|
||||
</Stack>
|
||||
</>
|
||||
);
|
||||
}
|
@ -9,6 +9,7 @@ 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"));
|
||||
|
||||
export const router: RouteObject[] = [
|
||||
{
|
||||
@ -36,6 +37,10 @@ export const router: RouteObject[] = [
|
||||
path: "problem",
|
||||
element: <ProblemListPage />,
|
||||
},
|
||||
{
|
||||
path: "problem/:id",
|
||||
element: <ProblemDetailPage />,
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
Loading…
Reference in New Issue
Block a user