Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 60 additions & 21 deletions src/app/dashboard/page.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import { redirect } from "next/navigation";
import Link from "next/link";
import { createClient as createServerClient } from "../../lib/supabase/server";
import { Cinzel } from "next/font/google"; // Import Cinzel font
import { Cinzel } from "next/font/google";
import checkUserCompletedQuizzes from "@/lib/checkUserCompletedQuizzes";

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

if (!user) {
redirect("/login");
}
if (!user) redirect("/login");

// Check which quizzes has the user completed
// Completed quizzes
const completedQuizzes = await checkUserCompletedQuizzes();

const isHelloWorldComplete = completedQuizzes.has("hello-world");
const isVariablesComplete = completedQuizzes.has("variables");
const isUserInputComplete = completedQuizzes.has("user-input");
const isConditionalsComplete = completedQuizzes.has("conditionals");
const isLoopsComplete = completedQuizzes.has("loops");
const isMathComplete = completedQuizzes.has("math");
const isFunctionsComplete = completedQuizzes.has("functions");
const isListsArraysComplete = completedQuizzes.has("lists-arrays");
const isDictionaryComplete = completedQuizzes.has("dictionary");
const isRecursionComplete = completedQuizzes.has("recursion");

const celestialButtonClasses =
"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";

const celestialButtonNoFullWidth =
"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";

const greyButtonClass =
"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";

const greenButtonClass =
"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";

// helper
const getButtonClass = (complete: boolean) =>
complete ? greenButtonClass : greyButtonClass;

return (
<main
className={`relative min-h-dvh p-8 text-white ${cinzel.className}`}
Expand All @@ -53,17 +65,18 @@ export default async function DashboardPage() {
>
<div className="flex justify-between items-start w-full">
<div className="flex flex-col gap-4 p-0 w-fit">
<h1 className="text-white text-5xl font-bold tracking-wider mb-4">Dashboard</h1>
<h1 className="text-white text-5xl font-bold tracking-wider mb-4">
Dashboard
</h1>
<div className="flex flex-col gap-4 w-32">
<Link href="/" className={celestialButtonClasses} aria-label="Go home">
<Link href="/" className={celestialButtonClasses}>
<span>Home</span>
</Link>
</div>
</div>

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

{/* tutorials */}
{/* Tutorials */}
<div className="absolute bottom-16 left-1/2 -translate-x-1/2">
<div className="flex flex-col gap-16">
<Link
href="tutorial-variables"
className={isVariablesComplete ? greenButtonClass : greyButtonClass}
>
<div className="flex flex-col gap-6 w-64 text-center">
<Link href="tutorial-hello-world" className={getButtonClass(isHelloWorldComplete)}>
Hello World
</Link>

<Link href="tutorial-variables" className={getButtonClass(isVariablesComplete)}>
Variables
</Link>

<Link
href="tutorial-hello-world"
className={isHelloWorldComplete ? greenButtonClass : greyButtonClass}
>
Hello World
<Link href="tutorial-user-input" className={getButtonClass(isUserInputComplete)}>
User Input
</Link>

<Link href="tutorial-conditionals" className={getButtonClass(isConditionalsComplete)}>
Conditionals
</Link>

<Link href="tutorial-loops" className={getButtonClass(isLoopsComplete)}>
Loops
</Link>

<Link href="tutorial-math" className={getButtonClass(isMathComplete)}>
Math
</Link>

<Link href="tutorial-functions" className={getButtonClass(isFunctionsComplete)}>
Functions
</Link>

<Link href="tutorial-lists-arrays" className={getButtonClass(isListsArraysComplete)}>
Lists & Arrays
</Link>

<Link href="tutorial-dictionary" className={getButtonClass(isDictionaryComplete)}>
Dictionary
</Link>

<Link href="tutorial-recursion" className={getButtonClass(isRecursionComplete)}>
Recursion
</Link>
</div>
</div>
Expand Down
2 changes: 1 addition & 1 deletion src/app/profile/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export default async function ProfilePage() {
}

// Fetch user profile from database
const { data: profile, error: profileError } = await supabase
const { data: profile } = await supabase
.from('profiles')
.select('class')
.eq('id', user.id)
Expand Down
130 changes: 130 additions & 0 deletions src/app/tutorial-conditionals/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
"use client";

import BackToDashBoardLink from "@/components/back-to-dashboard-link";
import Quiz from "@/components/tutorial-quiz";

import { Cinzel } from "next/font/google";
import { conditionalsQuiz } from "@/data/quizzes/04-conditionals";

const cinzel = Cinzel({
subsets: ["latin"],
weight: ["400", "700"],
});

// body text (Times New Roman = more readable)
const bodyFontClass = "font-serif text-amber-950";
// titles (Cinzel font)
const cinzelTitleClass = cinzel.className;

export default function TutorialConditionals() {
return (
// Background of scroll
<div
className="min-h-screen p-4 md:p-12"
style={{
backgroundImage: "url('/geminiblurred.png')",
backgroundSize: "cover",
backgroundPosition: "center",
backgroundColor: "#fef3c7",
}}
>
<div className="inline-block p-4" style={{ zIndex: 10 }}>
<BackToDashBoardLink />
</div>

{/* "scroll" */}
<article
className={`max-w-4xl mx-auto bg-amber-100 p-8 md:p-12 shadow-2xl shadow-amber-950/70 space-y-8
${bodyFontClass} border border-amber-800 transform rotate-[-0.5deg]
rounded-t-[4rem] rounded-b-lg`}
>
{/* title */}
<h1
className={`text-4xl md:text-5xl font-bold ${cinzelTitleClass}
border-b-4 border-amber-900 pb-4 mb-8 text-center uppercase`}
>
Quest: The Forking Path – Choosing Fate with If and Else
</h1>

<p className="text-xl italic text-amber-900">
Every adventure has moments of choice: fight or flee, open the chest or walk away.
In code, those decisions are made with <strong>conditionals</strong>—the <strong>if</strong>
and <strong>else</strong> spells that tell your program which path to follow.
</p>

<p className="text-lg">
This quest teaches your code the power to decide, not just blindly follow one script.
</p>

<hr className="my-8 border-amber-900/50" />

{/* section */}
<section className="space-y-4">
<h2 className={`text-3xl font-semibold ${cinzelTitleClass}`}>
What Are Conditionals?
</h2>
<p className="text-lg">
A conditional is a question about the world that leads to different outcomes. It looks like:
</p>
<p className="text-lg font-mono bg-amber-200 px-2 py-1 rounded border border-amber-800">
&quot;If this condition is true, do A; otherwise, do B.&quot;
</p>
<p className="text-lg">
The condition is usually a comparison—like checking if <strong>health ≤ 0</strong>
or if <strong>gold &gt; 100</strong>. True or false determines which branch of the story runs.
</p>
</section>

<hr className="my-8 border-amber-900/50" />

{/* section */}
<section className="space-y-4">
<h2 className={`text-3xl font-semibold ${cinzelTitleClass}`}>
Why These Choices Matter
</h2>
<ul className="list-disc list-inside space-y-3 text-lg pl-4">
<li>
<strong className="font-semibold text-amber-950">Logic:</strong> Real programs rarely do the same thing every time. They react.
</li>
<li>
<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;
</li>
<li>
<strong className="font-semibold text-amber-950">Complexity:</strong> By chaining conditions, you can describe rich behavior without writing separate programs.
</li>
</ul>
<p className="text-lg">
Conditionals are the difference between a straight hallway and a branching dungeon.
</p>
</section>

<hr className="my-8 border-amber-900/50" />

{/* section */}
<section className="space-y-4">
<h2 className={`text-3xl font-semibold ${cinzelTitleClass}`}>
Visualizing the Incantation (Conceptual Example)
</h2>

<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">
<code>{`// Check the hero's health
if health <= 0 then
Display: "You have fallen in battle..."
else
Display: "You still stand! Prepare your next move."
end`}</code>
</pre>

<p className="text-lg">
The program examines a condition and chooses which message to reveal, like a dungeon master reacting to the dice.
</p>
</section>

<hr className="my-8 border-amber-900/50" />

{/* Quiz */}
<Quiz quizData={conditionalsQuiz}></Quiz>
</article>
</div>
);
}
Loading