diff --git a/src/app/dashboard/page.tsx b/src/app/dashboard/page.tsx index 1f9e3bb..9fea6a4 100644 --- a/src/app/dashboard/page.tsx +++ b/src/app/dashboard/page.tsx @@ -1,8 +1,8 @@ import { redirect } from "next/navigation"; +import { revalidatePath } from "next/cache"; import Link from "next/link"; import { createClient as createServerClient } from "../../lib/supabase/server"; import { Cinzel } from "next/font/google"; -import checkUserCompletedQuizzes from "@/lib/checkUserCompletedQuizzes"; import { ArrowBigLeft, ArrowBigDown, ArrowBigRight } from "lucide-react"; const cinzel = Cinzel({ @@ -17,6 +17,36 @@ async function logout() { redirect("/"); } +async function resetQuestProgress() { + "use server"; + const supabase = await createServerClient(); + const { + data: { user }, + } = await supabase.auth.getUser(); + + if (!user) { + return; + } + + // Delete all quest completions for this user + // The trigger will automatically update quests_completed count to 0 + const { error: deleteError } = await supabase + .from("quest_completions") + .delete() + .eq("user_id", user.id); + + if (deleteError) { + console.error("Error deleting quest completions:", deleteError); + } + + // Revalidate the dashboard and profile pages to refresh data + revalidatePath("/dashboard"); + revalidatePath("/profile"); + + // Redirect to refresh the page + redirect("/dashboard"); +} + export default async function DashboardPage() { const supabase = await createServerClient(); const { @@ -25,19 +55,30 @@ export default async function DashboardPage() { if (!user) redirect("/login"); - // 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"); + // Fetch individual quest completions from quest_completions table + const { data: questCompletions, error: completionsError } = await supabase + .from("quest_completions") + .select("quest_id") + .eq("user_id", user.id); + + if (completionsError) { + console.error(`Error fetching quest completions: ${completionsError.message}`); + } + + // Create a Set of completed quest IDs for quick lookup + const completedQuestIds = new Set(questCompletions?.map((qc) => qc.quest_id) || []); + + // Check individual quest completion status + const isHelloWorldComplete = completedQuestIds.has("hello-world"); + const isVariablesComplete = completedQuestIds.has("variables"); + const isUserInputComplete = completedQuestIds.has("user-input"); + const isConditionalsComplete = completedQuestIds.has("conditionals"); + const isLoopsComplete = completedQuestIds.has("loops"); + const isMathComplete = completedQuestIds.has("math"); + const isFunctionsComplete = completedQuestIds.has("functions"); + const isListsArraysComplete = completedQuestIds.has("lists-arrays"); + const isDictionaryComplete = completedQuestIds.has("dictionary"); + const isRecursionComplete = completedQuestIds.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"; @@ -66,18 +107,23 @@ export default async function DashboardPage() { >
-

Dashboard

-
- - Home - -
+

+ Dashboard +

+ + Home + Profile +
+ +
@@ -167,7 +172,7 @@ export default async function ProfilePage() { Java - 72% + 0%
@@ -191,7 +196,7 @@ export default async function ProfilePage() { C++ - 68% + 0%
@@ -284,7 +289,7 @@ export default async function ProfilePage() { Quests - 0/8 + {profile?.quests_completed ?? 0}/10
diff --git a/src/components/tutorial-quiz.tsx b/src/components/tutorial-quiz.tsx index 43b79e6..b4df8de 100644 --- a/src/components/tutorial-quiz.tsx +++ b/src/components/tutorial-quiz.tsx @@ -56,9 +56,8 @@ export default function Quiz({ quizData }: QuizProps) { setIsCorrect(null); }; - // Updates database that user completed quiz, no score to keep things simple - // TODO: Update the insert with a upsert, and keep track of the user's most recent score on quiz - // Also another neat feature would be loading the quiz result instead of resetting the quiz each time + // Updates database that user completed quiz + // Inserts into quest_completions table (triggers will auto-update quests_completed count) const updateUserQuizProgress = async () => { const supabase = createClient(); @@ -72,13 +71,20 @@ export default function Quiz({ quizData }: QuizProps) { return; } - const { error: insertError } = await supabase.from("user_quiz_progress").insert({ - user_id: user.id, - quiz_id: quizData.id, - }); + // Insert into quest_completions table + // The unique constraint prevents duplicates, and the trigger auto-updates quests_completed count + const { error: insertError } = await supabase + .from("quest_completions") + .insert({ + user_id: user.id, + quest_id: quizData.id, + }); if (insertError) { - console.error(`Supabase insertion error: ${insertError}`); + // If it's a duplicate key error, the quest was already completed - that's okay + if (insertError.code !== "23505") { + console.error(`Error inserting quest completion: ${insertError.message}`); + } } }; diff --git a/src/lib/updateQuestCount.ts b/src/lib/updateQuestCount.ts new file mode 100644 index 0000000..39f10e7 --- /dev/null +++ b/src/lib/updateQuestCount.ts @@ -0,0 +1,45 @@ +import { createClient } from "./supabase/client"; + +/** + * Updates the quests_completed count in the profiles table + * by counting distinct quiz_ids completed by the user + */ +export async function updateQuestCount() { + const supabase = createClient(); + + // Get user + const { + data: { user }, + } = await supabase.auth.getUser(); + + if (!user) { + console.error("User not logged in, cannot update quest count."); + return; + } + + // Count distinct quiz_ids for this user + const { data: quizData, error: selectError } = await supabase + .from("user_quiz_progress") + .select("quiz_id") + .eq("user_id", user.id); + + if (selectError) { + console.error(`Error fetching quiz progress: ${selectError.message}`); + return; + } + + // Get unique quiz IDs + const uniqueQuizIds = new Set(quizData?.map((row) => row.quiz_id) || []); + const questsCompleted = uniqueQuizIds.size; + + // Update the profiles table + const { error: updateError } = await supabase + .from("profiles") + .update({ quests_completed: questsCompleted }) + .eq("id", user.id); + + if (updateError) { + console.error(`Error updating quest count: ${updateError.message}`); + } +} +