Skip to content

Commit 47f93a7

Browse files
authored
Merge pull request #48 from Eric-Zhang-Developer/add-all-quests
Add all new tutorial lessons and quizzes
2 parents 0c8c598 + 0848336 commit 47f93a7

File tree

21 files changed

+1936
-34
lines changed

21 files changed

+1936
-34
lines changed

src/app/dashboard/page.tsx

Lines changed: 60 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
import { redirect } from "next/navigation";
22
import Link from "next/link";
33
import { createClient as createServerClient } from "../../lib/supabase/server";
4-
import { Cinzel } from "next/font/google"; // Import Cinzel font
4+
import { Cinzel } from "next/font/google";
55
import checkUserCompletedQuizzes from "@/lib/checkUserCompletedQuizzes";
66

7-
//font for words
87
const cinzel = Cinzel({
98
subsets: ["latin"],
109
weight: ["400", "700"],
@@ -23,25 +22,38 @@ export default async function DashboardPage() {
2322
data: { user },
2423
} = await supabase.auth.getUser();
2524

26-
if (!user) {
27-
redirect("/login");
28-
}
25+
if (!user) redirect("/login");
2926

30-
// Check which quizzes has the user completed
27+
// Completed quizzes
3128
const completedQuizzes = await checkUserCompletedQuizzes();
3229

3330
const isHelloWorldComplete = completedQuizzes.has("hello-world");
3431
const isVariablesComplete = completedQuizzes.has("variables");
32+
const isUserInputComplete = completedQuizzes.has("user-input");
33+
const isConditionalsComplete = completedQuizzes.has("conditionals");
34+
const isLoopsComplete = completedQuizzes.has("loops");
35+
const isMathComplete = completedQuizzes.has("math");
36+
const isFunctionsComplete = completedQuizzes.has("functions");
37+
const isListsArraysComplete = completedQuizzes.has("lists-arrays");
38+
const isDictionaryComplete = completedQuizzes.has("dictionary");
39+
const isRecursionComplete = completedQuizzes.has("recursion");
3540

3641
const celestialButtonClasses =
3742
"btn border-2 border-cyan-400 text-cyan-400 bg-transparent hover:bg-cyan-900/50 hover:border-cyan-200 hover:text-cyan-200 shadow-lg shadow-cyan-500/50 transition duration-300 ease-in-out w-full";
43+
3844
const celestialButtonNoFullWidth =
3945
"btn border-2 border-cyan-400 text-cyan-400 bg-transparent hover:bg-cyan-900/50 hover:border-cyan-200 hover:text-cyan-200 shadow-lg shadow-cyan-500/50 transition duration-300 ease-in-out";
46+
4047
const greyButtonClass =
4148
"btn border-2 border-gray-400 text-gray-400 bg-transparent hover:bg-gray-900/50 hover:border-gray-200 hover:text-gray-200 shadow-lg shadow-gray-500/50 transition duration-300 ease-in-out";
49+
4250
const greenButtonClass =
4351
"btn border-2 border-emerald-400 text-emerald-400 bg-transparent hover:bg-emerald-900/50 hover:border-emerald-200 hover:text-emerald-200 shadow-lg shadow-emerald-500/50 transition duration-300 ease-in-out";
4452

53+
// helper
54+
const getButtonClass = (complete: boolean) =>
55+
complete ? greenButtonClass : greyButtonClass;
56+
4557
return (
4658
<main
4759
className={`relative min-h-dvh p-8 text-white ${cinzel.className}`}
@@ -53,17 +65,18 @@ export default async function DashboardPage() {
5365
>
5466
<div className="flex justify-between items-start w-full">
5567
<div className="flex flex-col gap-4 p-0 w-fit">
56-
<h1 className="text-white text-5xl font-bold tracking-wider mb-4">Dashboard</h1>
68+
<h1 className="text-white text-5xl font-bold tracking-wider mb-4">
69+
Dashboard
70+
</h1>
5771
<div className="flex flex-col gap-4 w-32">
58-
<Link href="/" className={celestialButtonClasses} aria-label="Go home">
72+
<Link href="/" className={celestialButtonClasses}>
5973
<span>Home</span>
6074
</Link>
6175
</div>
6276
</div>
6377

64-
{/* profile & logout */}
6578
<div className="flex items-center gap-4 p-0 w-fit">
66-
<Link href="/profile" className={celestialButtonNoFullWidth} aria-label="Go to profile">
79+
<Link href="/profile" className={celestialButtonNoFullWidth}>
6780
<span>Profile</span>
6881
</Link>
6982
<form action={logout}>
@@ -74,21 +87,47 @@ export default async function DashboardPage() {
7487
</div>
7588
</div>
7689

77-
{/* tutorials */}
90+
{/* Tutorials */}
7891
<div className="absolute bottom-16 left-1/2 -translate-x-1/2">
79-
<div className="flex flex-col gap-16">
80-
<Link
81-
href="tutorial-variables"
82-
className={isVariablesComplete ? greenButtonClass : greyButtonClass}
83-
>
92+
<div className="flex flex-col gap-6 w-64 text-center">
93+
<Link href="tutorial-hello-world" className={getButtonClass(isHelloWorldComplete)}>
94+
Hello World
95+
</Link>
96+
97+
<Link href="tutorial-variables" className={getButtonClass(isVariablesComplete)}>
8498
Variables
8599
</Link>
86100

87-
<Link
88-
href="tutorial-hello-world"
89-
className={isHelloWorldComplete ? greenButtonClass : greyButtonClass}
90-
>
91-
Hello World
101+
<Link href="tutorial-user-input" className={getButtonClass(isUserInputComplete)}>
102+
User Input
103+
</Link>
104+
105+
<Link href="tutorial-conditionals" className={getButtonClass(isConditionalsComplete)}>
106+
Conditionals
107+
</Link>
108+
109+
<Link href="tutorial-loops" className={getButtonClass(isLoopsComplete)}>
110+
Loops
111+
</Link>
112+
113+
<Link href="tutorial-math" className={getButtonClass(isMathComplete)}>
114+
Math
115+
</Link>
116+
117+
<Link href="tutorial-functions" className={getButtonClass(isFunctionsComplete)}>
118+
Functions
119+
</Link>
120+
121+
<Link href="tutorial-lists-arrays" className={getButtonClass(isListsArraysComplete)}>
122+
Lists & Arrays
123+
</Link>
124+
125+
<Link href="tutorial-dictionary" className={getButtonClass(isDictionaryComplete)}>
126+
Dictionary
127+
</Link>
128+
129+
<Link href="tutorial-recursion" className={getButtonClass(isRecursionComplete)}>
130+
Recursion
92131
</Link>
93132
</div>
94133
</div>

src/app/profile/page.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ export default async function ProfilePage() {
2222
}
2323

2424
// Fetch user profile from database
25-
const { data: profile, error: profileError } = await supabase
25+
const { data: profile } = await supabase
2626
.from('profiles')
2727
.select('class')
2828
.eq('id', user.id)
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
"use client";
2+
3+
import BackToDashBoardLink from "@/components/back-to-dashboard-link";
4+
import Quiz from "@/components/tutorial-quiz";
5+
6+
import { Cinzel } from "next/font/google";
7+
import { conditionalsQuiz } from "@/data/quizzes/04-conditionals";
8+
9+
const cinzel = Cinzel({
10+
subsets: ["latin"],
11+
weight: ["400", "700"],
12+
});
13+
14+
// body text (Times New Roman = more readable)
15+
const bodyFontClass = "font-serif text-amber-950";
16+
// titles (Cinzel font)
17+
const cinzelTitleClass = cinzel.className;
18+
19+
export default function TutorialConditionals() {
20+
return (
21+
// Background of scroll
22+
<div
23+
className="min-h-screen p-4 md:p-12"
24+
style={{
25+
backgroundImage: "url('/geminiblurred.png')",
26+
backgroundSize: "cover",
27+
backgroundPosition: "center",
28+
backgroundColor: "#fef3c7",
29+
}}
30+
>
31+
<div className="inline-block p-4" style={{ zIndex: 10 }}>
32+
<BackToDashBoardLink />
33+
</div>
34+
35+
{/* "scroll" */}
36+
<article
37+
className={`max-w-4xl mx-auto bg-amber-100 p-8 md:p-12 shadow-2xl shadow-amber-950/70 space-y-8
38+
${bodyFontClass} border border-amber-800 transform rotate-[-0.5deg]
39+
rounded-t-[4rem] rounded-b-lg`}
40+
>
41+
{/* title */}
42+
<h1
43+
className={`text-4xl md:text-5xl font-bold ${cinzelTitleClass}
44+
border-b-4 border-amber-900 pb-4 mb-8 text-center uppercase`}
45+
>
46+
Quest: The Forking Path – Choosing Fate with If and Else
47+
</h1>
48+
49+
<p className="text-xl italic text-amber-900">
50+
Every adventure has moments of choice: fight or flee, open the chest or walk away.
51+
In code, those decisions are made with <strong>conditionals</strong>—the <strong>if</strong>
52+
and <strong>else</strong> spells that tell your program which path to follow.
53+
</p>
54+
55+
<p className="text-lg">
56+
This quest teaches your code the power to decide, not just blindly follow one script.
57+
</p>
58+
59+
<hr className="my-8 border-amber-900/50" />
60+
61+
{/* section */}
62+
<section className="space-y-4">
63+
<h2 className={`text-3xl font-semibold ${cinzelTitleClass}`}>
64+
What Are Conditionals?
65+
</h2>
66+
<p className="text-lg">
67+
A conditional is a question about the world that leads to different outcomes. It looks like:
68+
</p>
69+
<p className="text-lg font-mono bg-amber-200 px-2 py-1 rounded border border-amber-800">
70+
&quot;If this condition is true, do A; otherwise, do B.&quot;
71+
</p>
72+
<p className="text-lg">
73+
The condition is usually a comparison—like checking if <strong>health ≤ 0</strong>
74+
or if <strong>gold &gt; 100</strong>. True or false determines which branch of the story runs.
75+
</p>
76+
</section>
77+
78+
<hr className="my-8 border-amber-900/50" />
79+
80+
{/* section */}
81+
<section className="space-y-4">
82+
<h2 className={`text-3xl font-semibold ${cinzelTitleClass}`}>
83+
Why These Choices Matter
84+
</h2>
85+
<ul className="list-disc list-inside space-y-3 text-lg pl-4">
86+
<li>
87+
<strong className="font-semibold text-amber-950">Logic:</strong> Real programs rarely do the same thing every time. They react.
88+
</li>
89+
<li>
90+
<strong className="font-semibold text-amber-950">Safety:</strong> You can prevent bad actions, e.g., &quot;Only open the gate if the password is correct.&quot;
91+
</li>
92+
<li>
93+
<strong className="font-semibold text-amber-950">Complexity:</strong> By chaining conditions, you can describe rich behavior without writing separate programs.
94+
</li>
95+
</ul>
96+
<p className="text-lg">
97+
Conditionals are the difference between a straight hallway and a branching dungeon.
98+
</p>
99+
</section>
100+
101+
<hr className="my-8 border-amber-900/50" />
102+
103+
{/* section */}
104+
<section className="space-y-4">
105+
<h2 className={`text-3xl font-semibold ${cinzelTitleClass}`}>
106+
Visualizing the Incantation (Conceptual Example)
107+
</h2>
108+
109+
<pre className="bg-amber-200 p-6 rounded-md font-mono text-sm text-amber-950 border-2 border-amber-800/50 overflow-x-auto shadow-inner shadow-amber-900/30">
110+
<code>{`// Check the hero's health
111+
if health <= 0 then
112+
Display: "You have fallen in battle..."
113+
else
114+
Display: "You still stand! Prepare your next move."
115+
end`}</code>
116+
</pre>
117+
118+
<p className="text-lg">
119+
The program examines a condition and chooses which message to reveal, like a dungeon master reacting to the dice.
120+
</p>
121+
</section>
122+
123+
<hr className="my-8 border-amber-900/50" />
124+
125+
{/* Quiz */}
126+
<Quiz quizData={conditionalsQuiz}></Quiz>
127+
</article>
128+
</div>
129+
);
130+
}

0 commit comments

Comments
 (0)