Skip to content

Commit 618eb0f

Browse files
committed
Merge branch 'main' of https://github.com/codersforcauses/game-dev into issue-47-Add_explosions_to_committee_page
2 parents 92667dd + 8c53a22 commit 618eb0f

6 files changed

Lines changed: 626 additions & 6 deletions

File tree

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
## Member Profiles
2+
3+
Profiles of club members can be added and edited at the row 'Member' of the GAME_DEV section on the main admin page.
4+
5+
### Fields
6+
7+
**Name:** Required field for the member's name. A character field (includes letters, numbers and symbols) of maximum length 200 characters.
8+
9+
**Active:** Checkbox to represent whether a member is an active participant in the club. If the checkbox is not ticked then the member's profile will not be displayed on the website.
10+
11+
**Profile Picture:** Optional field to upload a profile picture. Must be an image file, and will display best if the image is at least 128 by 128 px in size. If no profile picture is provided then the member's initials will be displayed instead.
12+
13+
**About:** Optional field for a bio. A character field of maximum length 256 characters.
14+
15+
**Pronouns:** Optional field for the member's pronouns. A character field of maximum length 20 characters.
16+
17+
**Social media links:** Optional section to display links to the member's social media profiles. Requires a link to the profile (character field of maximum length 2083) and, optionally, the profile username (character field of maximum length 200). If a username is not supplied then only a social media icon will be displayed with the link attached, otherwise the username will be placed next to the relevant icon. The type of icon to be displayed (e.g. instagram, linkedin, generic link) is inferred from the social media link provided.

client/src/pages/404.tsx

Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
"use client";
2+
3+
import Link from "next/link";
4+
import { useEffect, useState } from "react";
5+
6+
import { Button } from "@/components/ui/button";
7+
import TRIVIA from "@/trivia.json";
8+
9+
interface Trivia {
10+
question: string;
11+
answer: string;
12+
}
13+
14+
export default function Custom404() {
15+
const [gameQuestions, setGameQuestions] = useState<Trivia[]>([]);
16+
const [currentQuestionIndex, setCurrentQuestionIndex] = useState(0);
17+
const [score, setScore] = useState(0);
18+
const [gameActive, setGameActive] = useState(false);
19+
const [timeLeft, setTimeLeft] = useState(30);
20+
const [answered, setAnswered] = useState(false);
21+
const [selectedAnswer, setSelectedAnswer] = useState<string | null>(null);
22+
const [options, setOptions] = useState<string[]>([]);
23+
24+
const currentTrivia = gameQuestions[currentQuestionIndex];
25+
26+
const generateQuestions = () => {
27+
const shuffled = TRIVIA.sort(() => Math.random() - 0.5).slice(0, 10);
28+
setGameQuestions(shuffled);
29+
};
30+
31+
useEffect(() => {
32+
if (!currentTrivia) return;
33+
34+
const wrongAnswers = TRIVIA.filter((t) => t.answer !== currentTrivia.answer)
35+
.sort(() => Math.random() - 0.5)
36+
.slice(0, 3)
37+
.map((t) => t.answer);
38+
39+
const allOptions = [currentTrivia.answer, ...wrongAnswers].sort(
40+
() => Math.random() - 0.5,
41+
);
42+
setOptions(allOptions);
43+
}, [currentQuestionIndex, currentTrivia]);
44+
45+
useEffect(() => {
46+
if (!gameActive || timeLeft <= 0) return;
47+
48+
const timer = setInterval(() => {
49+
setTimeLeft((prev) => {
50+
if (prev <= 1) {
51+
setGameActive(false);
52+
return 0;
53+
}
54+
return prev - 1;
55+
});
56+
}, 1000);
57+
58+
return () => clearInterval(timer);
59+
}, [gameActive, timeLeft]);
60+
61+
const startGame = () => {
62+
generateQuestions();
63+
setGameActive(true);
64+
setCurrentQuestionIndex(0);
65+
setScore(0);
66+
setTimeLeft(30);
67+
setAnswered(false);
68+
setSelectedAnswer(null);
69+
};
70+
71+
const handleAnswer = (answer: string) => {
72+
if (answered) return;
73+
74+
setSelectedAnswer(answer);
75+
setAnswered(true);
76+
77+
if (answer === currentTrivia.answer) {
78+
setScore((prev) => prev + 1);
79+
}
80+
81+
setTimeout(() => {
82+
if (currentQuestionIndex < gameQuestions.length - 1) {
83+
setCurrentQuestionIndex((prev) => prev + 1);
84+
setAnswered(false);
85+
setSelectedAnswer(null);
86+
} else {
87+
setGameActive(false);
88+
}
89+
}, 1000);
90+
};
91+
92+
const getButtonClass = (option: string) => {
93+
const baseClass =
94+
"w-full rounded border p-2.5 text-left text-sm transition-all cursor-pointer md:p-3 md:text-base";
95+
96+
if (!answered) {
97+
return `${baseClass} bg-card border-border text-foreground hover:border-accent`;
98+
}
99+
100+
if (option === currentTrivia.answer) {
101+
return `${baseClass} bg-primary border-accent text-accent-foreground font-semibold`;
102+
}
103+
104+
if (option === selectedAnswer && option !== currentTrivia.answer) {
105+
return `${baseClass} bg-accent border-secondary text-secondary-foreground`;
106+
}
107+
108+
return `${baseClass} bg-muted border-border text-muted-foreground`;
109+
};
110+
111+
return (
112+
<main className="mx-auto flex h-dvh max-w-6xl items-center overflow-hidden px-4 py-4 sm:px-6 sm:py-6 md:px-16 md:py-8 lg:px-20 lg:py-10">
113+
<div className="mx-auto w-full max-w-2xl">
114+
<h1 className="mb-4 text-center font-jersey10 text-5xl text-primary md:mb-5 md:text-[3.25rem]">
115+
404
116+
</h1>
117+
<h2 className="mb-2 text-center font-jersey10 text-xl text-foreground md:mb-3 md:text-[1.4rem]">
118+
Page Not Found
119+
</h2>
120+
121+
<p className="mb-4 text-center text-sm text-foreground md:mb-5 md:text-base">
122+
Test your game knowledge with some rapid-fire trivia instead!!!
123+
</p>
124+
125+
{!gameActive ? (
126+
<div className="mb-4 space-y-3 md:mb-5 md:space-y-3.5">
127+
{gameQuestions.length === 0 ? (
128+
<>
129+
<p className="mb-3 text-sm text-muted-foreground md:mb-3 md:text-base">
130+
Answer 10 random gaming trivia questions in 30 seconds!
131+
</p>
132+
<Button onClick={startGame} className="w-full">
133+
Start Trivia
134+
</Button>
135+
</>
136+
) : (
137+
<>
138+
<p className="mb-3 text-center font-jersey10 text-2xl font-bold text-primary md:mb-3">
139+
Game Over!
140+
</p>
141+
<p className="mb-3 text-center text-sm text-foreground md:mb-3 md:text-base">
142+
Final Score:
143+
<span className="text-xl font-bold text-primary">
144+
{score}
145+
</span>{" "}
146+
/ 10
147+
</p>
148+
<Button onClick={startGame} className="w-full">
149+
Play Again
150+
</Button>
151+
</>
152+
)}
153+
</div>
154+
) : (
155+
<div className="md:space-y-4.5 mb-4 space-y-4 md:mb-5">
156+
<div className="mb-2 flex items-center justify-between md:mb-3">
157+
<p className="text-xs text-muted-foreground md:text-sm">
158+
Question {currentQuestionIndex + 1} / 10
159+
</p>
160+
<div
161+
className={`font-jersey10 text-2xl font-bold md:text-[1.9rem] ${
162+
timeLeft <= 10 ? "text-destructive" : "text-primary"
163+
}`}
164+
>
165+
{timeLeft}s
166+
</div>
167+
</div>
168+
169+
<div className="md:space-y-4.5 space-y-4 rounded border border-border bg-card p-4 md:p-5">
170+
<p className="text-base leading-snug text-foreground md:text-[1.05rem]">
171+
{currentTrivia.question}
172+
</p>
173+
174+
<div className="space-y-2.5 md:space-y-3">
175+
{options.map((option, idx) => (
176+
<button
177+
key={idx}
178+
onClick={() => handleAnswer(option)}
179+
className={getButtonClass(option)}
180+
disabled={answered}
181+
>
182+
{option}
183+
</button>
184+
))}
185+
</div>
186+
187+
<p className="text-xs text-foreground md:text-sm">
188+
Score:{" "}
189+
<span className="font-jersey10 font-bold text-primary">
190+
{score} / 10
191+
</span>
192+
</p>
193+
</div>
194+
</div>
195+
)}
196+
197+
<Link href="/">
198+
<Button variant="outline" className="w-full">
199+
Go Home
200+
</Button>
201+
</Link>
202+
</div>
203+
</main>
204+
);
205+
}

client/src/pages/index.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -215,10 +215,10 @@ export default function Landing() {
215215
</div>
216216

217217
<div className="flex flex-col items-end gap-4">
218-
<Link href="/">
218+
<Link href="/games">
219219
<Button>See more games by our members</Button>
220220
</Link>
221-
<Link href="/">
221+
<Link href="/artwork">
222222
<Button variant={"outline"}>
223223
See other cool stuff our members have created
224224
</Button>

0 commit comments

Comments
 (0)