Skip to content

Commit

Permalink
Basic challenges page
Browse files Browse the repository at this point in the history
  • Loading branch information
ethanlaj committed Mar 10, 2024
1 parent 35ede7d commit 2e19d24
Show file tree
Hide file tree
Showing 6 changed files with 89 additions and 5 deletions.
4 changes: 3 additions & 1 deletion client/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import Leaderboard from "./pages/Leaderboard";
import Badges from "./pages/Badges";
import AdminLayout from "./pages/admin/Admin";
import UserRouteLayout from "./components/UserRouteLayout";
import Challenges from "./pages/admin/Challenges";

const { Content } = Layout;

Expand Down Expand Up @@ -45,7 +46,8 @@ const App = () => {
<Route path="/admin" element={<AdminLayout />}>
<Route index element={<Navigate replace to="users" />} />
<Route path="users" element={<div>Users</div>} />
<Route path="challenges" element={<div>Challenges</div>} />
<Route path="challenges" element={<Challenges />} />
<Route path="challenges/create" element={<div>CREATE</div>} />
<Route
path="submissions/*"
element={
Expand Down
2 changes: 1 addition & 1 deletion client/src/pages/ChallengesView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ function ChallengesView() {
useEffect(() => {
async function getChallenges() {
try {
const response = await ChallengeService.getChallenges();
const response = await ChallengeService.getChallenges(false);
const categories = _.groupBy(response, "category");

const categoriesArray: Category[] = [];
Expand Down
69 changes: 69 additions & 0 deletions client/src/pages/admin/Challenges.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import { useState, useEffect } from "react";
import { Button, Table } from "antd";
import { PlusOutlined } from "@ant-design/icons";
import { Challenge } from "@/types/Challenge";
import { ChallengeService } from "@/services/challengeService";
import { useNavigate } from "react-router-dom";
import { ColumnsType } from "antd/es/table";

const Challenges = () => {
const [challenges, setChallenges] = useState<Challenge[]>([]);
const navigate = useNavigate();

useEffect(() => {
async function getChallenges() {
const data = await ChallengeService.getChallenges(true);
setChallenges(data);
}

getChallenges();
}, []);

function handleCreateChallenge() {
navigate("/admin/challenges/create");
}

const columns: ColumnsType<Challenge> = [
{
title: "Title",
dataIndex: "title",
key: "title",
},
{
title: "Category",
dataIndex: "category",
key: "category",
},
{
title: "Type",
dataIndex: "type",
key: "type",
render: (type: string) => {
switch (type) {
case "multiple-choice":
return "Multiple Choice";
case "short-answer":
return "Short Answer";
default:
return "Unknown";
}
},
},
];

return (
<div className="p-4">
<Button
type="primary"
icon={<PlusOutlined />}
className="mb-4"
onClick={() => handleCreateChallenge()}
>
Create
</Button>
<Table pagination={false} dataSource={challenges} columns={columns} rowKey="id" />
</div>
);
};

export default Challenges;
5 changes: 3 additions & 2 deletions client/src/services/challengeService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@ import axios from 'axios';
import { baseUrl } from '.';

const url = baseUrl + '/challenges';
const adminUrl = url + '/admin';

export class ChallengeService {
static async getChallenges(): Promise<Challenge[]> {
const response = await axios.get(url);
static async getChallenges(isAdmin: boolean): Promise<Challenge[]> {
const response = await axios.get(isAdmin ? adminUrl : url);
return response.data;
}
}
5 changes: 5 additions & 0 deletions server/src/controllers/challenges.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,9 @@ router.get("/", verifyAccess, errorHandler(async (req: Request, res: Response) =
return res.json(challenges);
}));

router.get("/admin", verifyAccess, errorHandler(async (_req: Request, res: Response) => {
const challenges = await Challenge.findAll();
return res.json(challenges);
}));

export default router;
9 changes: 8 additions & 1 deletion server/src/database/models/challenge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,12 +75,15 @@ class Challenge extends Model {

@Column(DataType.VIRTUAL)
get isSolved(): boolean {
if (!this.attempts) {
return false;
}
return this.attempts.some(attempt => attempt.isCorrect);
}

@Column(DataType.VIRTUAL)
get isExhausted(): boolean {
if (this.maxAttempts === 0) {
if (!this.attempts || this.maxAttempts === 0) {
return false;
}

Expand All @@ -94,6 +97,10 @@ class Challenge extends Model {

@Column(DataType.VIRTUAL)
get attemptsLeft(): number {
if (!this.attempts) {
return 0;
}

return this.maxAttempts - this.attempts.length;
}

Expand Down

0 comments on commit 2e19d24

Please sign in to comment.