Skip to content

Commit

Permalink
Prepare problem operations
Browse files Browse the repository at this point in the history
  • Loading branch information
slhmy committed Feb 7, 2024
1 parent ad4865a commit f22747b
Show file tree
Hide file tree
Showing 8 changed files with 105 additions and 31 deletions.
12 changes: 12 additions & 0 deletions src/api/problem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,18 @@ export namespace ProblemService {
return res.data;
}

export async function putProblem(problem: ProblemServiceModel.Problem) {
let res = await client.put<ProblemServiceModel.Problem>(
`/api/v1/problem`,
problem,
);

if (res.status !== 200) {
throw Error("failed to put problem");
}
return res.data;
}

export async function getProblemInfoList() {
let res = await client.get<{
total: number;
Expand Down
61 changes: 50 additions & 11 deletions src/components/ProblemTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export interface ProblemTableProps {
showActions?: boolean;
enableNavigation?: boolean;
className?: string;
enableRouting?: boolean;
}

const ProblemTable: React.FC<ProblemTableProps> = (props) => {
Expand All @@ -38,15 +39,17 @@ const ProblemTable: React.FC<ProblemTableProps> = (props) => {
<tr
key={problemInfo.slug}
className="hover"
onClick={() => navigate(problemInfo.slug)}
onClick={() => {
if (props.enableRouting) navigate(problemInfo.slug);
}}
>
<th>{problemInfo.slug}</th>
<td>{problemInfo.title}</td>
<td>
<div className="space-x-2">
{problemInfo.tags.map((tag) => (
<div key={tag.slug} className="badge badge-outline">
{tag.name}
<div key={tag} className="badge badge-outline">
{tag}
</div>
))}
</div>
Expand All @@ -60,20 +63,56 @@ const ProblemTable: React.FC<ProblemTableProps> = (props) => {
))}
</tbody>
</table>
<dialog id="delete_confirm_modal" className="modal">
<div className="modal-box">
<h3 className="text-lg font-bold">Confirm</h3>
<p className="py-4">Are you sure to delete this problem</p>
<div className="modal-action">
<form method="dialog">
{/* if there is a button in form, it will close the modal */}
<button className="btn btn-sm">cancel</button>
</form>
<button
className="btn btn-error btn-sm"
onClick={() => {
// delete problem
}}
>
delete
</button>
</div>
</div>
<form method="dialog" className="modal-backdrop">
<button>close</button>
</form>
</dialog>
</div>
);
};

const Actions: React.FC = () => {
return (
<div className="flex space-x-2">
<button className="btn btn-square btn-outline btn-primary btn-xs">
<PencilSquareIcon className="h-4 w-4" />
</button>
<button className="btn btn-square btn-outline btn-error btn-xs">
<TrashIcon className="h-4 w-4" />
</button>
</div>
<>
<div className="flex space-x-2">
<button className="btn btn-square btn-outline btn-primary btn-xs">
<PencilSquareIcon className="h-4 w-4" />
</button>
<button
className="btn btn-square btn-outline btn-error btn-xs"
onClick={(e) => {
e.preventDefault();
e.stopPropagation();

const modal = document.getElementById(
"delete_confirm_modal",
) as HTMLDialogElement;
modal?.showModal();
}}
>
<TrashIcon className="h-4 w-4" />
</button>
</div>
</>
);
};

Expand Down
3 changes: 2 additions & 1 deletion src/mocks/handlers.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { postJudge } from "./rest/judge";
import { getProblemInfo, getProblemInfoList } from "./rest/problem";
import { getProblemInfo, getProblemInfoList, putProblem } from "./rest/problem";
import { getSubmissionInfoList } from "./rest/submission";
import { getCurrentUser, postLogin } from "./rest/user";

export const restHandlers = [
getCurrentUser,
postLogin,
putProblem,
getProblemInfo,
getProblemInfoList,
getSubmissionInfoList,
Expand Down
16 changes: 10 additions & 6 deletions src/mocks/rest/problem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ Hello! world!
\`\`\`
`,
tags: [{ slug: "primer", name: "Primer" }],
tags: ["Primer"],
};

return HttpResponse.json(response);
Expand All @@ -53,19 +53,23 @@ export const getProblemInfoList = http.get("/api/v1/problem", (info) => {
{
slug: "hello-world",
title: "Hello World",
tags: [{ slug: "primer", name: "Primer" }],
tags: ["Pimer"],
},
{
slug: "a-plus-b-problem",
title: "A+B Problem",
tags: [
{ slug: "primer", name: "Primer" },
{ slug: "math", name: "Math" },
],
tags: ["Primer", "Math"],
},
],
};
return new Response(JSON.stringify(response), {
status: 200,
});
});

export const putProblem = http.put("/api/v1/problem", async (info) => {
let requestBody: ProblemServiceModel.Problem =
(await info.request.json()) as ProblemServiceModel.Problem;

return HttpResponse.json(requestBody);
});
4 changes: 2 additions & 2 deletions src/mocks/rest/submission.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export const getSubmissionInfoList = http.get("/api/v1/submission", (info) => {
problem: {
slug: "hello-world",
title: "Hello World",
tags: [{ slug: "primer", name: "Primer" }],
tags: ["Primer"],
},
language: "C++",
status: "finished",
Expand All @@ -31,7 +31,7 @@ export const getSubmissionInfoList = http.get("/api/v1/submission", (info) => {
problem: {
slug: "a-plus-b-problem",
title: "A + B Problem",
tags: [{ slug: "primer", name: "Primer" }],
tags: ["Primer"],
},
language: "C++",
status: "wrong answer",
Expand Down
1 change: 1 addition & 0 deletions src/pages/ProblemList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ const ProblemList: React.FC = () => {
data={getProblemInfoList()}
showActions={false}
enableNavigation
enableRouting
className="h-fit w-full"
/>
<div className="w-full sm:w-1/3">
Expand Down
30 changes: 26 additions & 4 deletions src/pages/admin-dashboard/CreateProblem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import { useTranslation } from "react-i18next";
import { PlusIcon } from "@heroicons/react/24/outline";
import { CheckCircleIcon, XCircleIcon } from "@heroicons/react/20/solid";
import MarkdownRender from "@/components/markdown/MarkdownRender";
import { ProblemService } from "@/api/problem";
import { useNavigate } from "react-router-dom";

// eslint-disable-next-line @typescript-eslint/no-unused-vars
const descriptionPlaceholder = `Output a string with format: \`Hello! %s\`.
Expand Down Expand Up @@ -41,6 +43,7 @@ const CreateProblem: React.FC = () => {
const [addingTag, setAddingTag] = useState<string>("");

const { t } = useTranslation();
const navigate = useNavigate();

const handleRemoveTag = (tagToRemove: string) => {
setTags(tags.filter((tag) => tag !== tagToRemove));
Expand All @@ -60,7 +63,19 @@ const CreateProblem: React.FC = () => {
>
{t("Cancel")}
</button>
<button className="btn btn-primary btn-sm text-base-100">
<button
className="btn btn-primary btn-sm text-base-100"
onClick={() => {
ProblemService.putProblem({
slug,
title,
description,
tags,
}).then((_) => {
navigate("/admin/problem");
});
}}
>
{t("Create")}
</button>
</div>
Expand Down Expand Up @@ -138,7 +153,7 @@ const CreateProblem: React.FC = () => {
role="tab"
className="tab"
aria-label="Raw"
checked
defaultChecked
/>
<div
role="tabpanel"
Expand Down Expand Up @@ -175,6 +190,7 @@ const CreateProblem: React.FC = () => {
<div className="flex gap-2">
{tags.map((tag) => (
<div
key={tag}
className="badge badge-neutral cursor-pointer gap-2"
onClick={() => {
handleRemoveTag(tag);
Expand Down Expand Up @@ -204,8 +220,14 @@ const CreateProblem: React.FC = () => {
className="btn btn-circle btn-primary btn-sm"
onClick={() => {
if (addingTag) {
setTags([...tags, addingTag]);
setAddingTag("");
let isDuplicate = false;
tags.forEach((tag) => {
if (tag === addingTag) isDuplicate = true;
});
if (!isDuplicate) {
setTags([...tags, addingTag]);
setAddingTag("");
}
}
}}
>
Expand Down
9 changes: 2 additions & 7 deletions src/typings/problem.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,14 @@
export namespace ProblemServiceModel {
export interface AlgorithmTag {
slug: string;
name: string;
}

export interface Problem {
slug: string;
title: string;
description: string;
tags: AlgorithmTag[];
tags: string[];
}

export interface ProblemInfo {
slug: string;
title: string;
tags: AlgorithmTag[];
tags: string[];
}
}

0 comments on commit f22747b

Please sign in to comment.