diff --git a/src/app.js b/src/app.js index aac260f..9ba2080 100644 --- a/src/app.js +++ b/src/app.js @@ -149,7 +149,6 @@ const elements = { expectedOverlay: document.getElementById("expected-overlay"), previewWrapper: document.querySelector(".preview-wrapper"), previewSection: document.querySelector(".preview-section"), - backBtn: document.getElementById("back-btn"), prevBtn: document.getElementById("prev-btn"), nextBtn: document.getElementById("next-btn"), gameControls: document.querySelector(".game-controls"), @@ -751,13 +750,18 @@ function updateNavigationButtons() { const engineState = lessonEngine.getCurrentState(); const isPlayground = engineState.lesson?.mode === "playground"; - // Hide nav buttons and center controls in playground mode, show back button - elements.backBtn?.classList.toggle("hidden", !isPlayground); - elements.prevBtn.classList.toggle("hidden", isPlayground); + // In playground mode: hide next button, repurpose prev as back button elements.nextBtn.classList.toggle("hidden", isPlayground); elements.gameControls?.classList.toggle("centered", isPlayground); - if (!isPlayground) { + if (isPlayground) { + // Change prev button to "Back" in playground mode + elements.prevBtn.textContent = t("back"); + elements.prevBtn.disabled = false; + elements.prevBtn.classList.remove("btn-disabled"); + } else { + // Normal mode: prev/next navigation + elements.prevBtn.textContent = t("previous"); elements.prevBtn.disabled = !engineState.canGoPrev; elements.nextBtn.disabled = !engineState.canGoNext; @@ -788,7 +792,16 @@ function nextLesson() { } function prevLesson() { - const prevModuleId = lessonEngine.getCurrentState().module?.id; + const engineState = lessonEngine.getCurrentState(); + const isPlayground = engineState.lesson?.mode === "playground"; + + // In playground mode, "Back" navigates to home + if (isPlayground) { + navigateTo("#"); + return; + } + + const prevModuleId = engineState.module?.id; const success = lessonEngine.previousLesson(); if (success) { const newState = lessonEngine.getCurrentState(); @@ -2455,12 +2468,12 @@ function init() { // Set timeout to show fallback if loading takes too long loadingTimeout = setTimeout(showLoadingFallback, 3000); - // Load modules after editor is ready - initializeModules(); - - // Handle OAuth callback BEFORE router (tokens are in URL hash) + // Handle OAuth callback FIRST (tokens are in URL hash, must run before router) handleOAuthCallback().then(() => { - // Initialize URL router for shareable links + // Load modules (this also calls handleRoute inside) + initializeModules(); + + // Initialize URL router for browser back/forward initRouter(); // Initialize authentication diff --git a/src/auth.js b/src/auth.js index f8ba584..d229249 100644 --- a/src/auth.js +++ b/src/auth.js @@ -17,6 +17,7 @@ export async function handleOAuthCallback() { // Check if hash contains OAuth tokens (access_token, error, etc.) if (!hash.includes("access_token") && !hash.includes("error_description") && !hash.includes("refresh_token")) { + console.log("[Auth] No OAuth tokens in hash"); return false; } @@ -25,20 +26,33 @@ export async function handleOAuthCallback() { try { const supabaseModule = await import("./supabase.js"); if (!supabaseModule.isConfigured) { + console.log("[Auth] Supabase not configured"); return false; } - // Let Supabase process the OAuth tokens - const { data, error } = await supabaseModule.auth.getSession(); + // Parse tokens from hash + const params = new URLSearchParams(hash.substring(1)); + const accessToken = params.get("access_token"); + const refreshToken = params.get("refresh_token"); - if (error) { - console.error("[Auth] OAuth callback error:", error.message); - } else if (data?.session) { - console.log("[Auth] OAuth login successful:", data.session.user?.email); - oauthHandled = true; + console.log("[Auth] Tokens found:", { accessToken: !!accessToken, refreshToken: !!refreshToken }); + + if (accessToken && refreshToken) { + // Explicitly set the session with tokens from URL + const { data, error } = await supabaseModule.auth.setSession({ + access_token: accessToken, + refresh_token: refreshToken + }); + + if (error) { + console.error("[Auth] OAuth setSession error:", error.message); + } else if (data?.session) { + console.log("[Auth] OAuth login successful:", data.session.user?.email); + oauthHandled = true; + } } - // Clear the hash after processing (will be replaced by router) + // Clear the hash after processing window.history.replaceState(null, "", window.location.pathname); return true; diff --git a/src/index.html b/src/index.html index 37e8fd6..fa5469f 100644 --- a/src/index.html +++ b/src/index.html @@ -434,7 +434,6 @@
- diff --git a/src/supabase.js b/src/supabase.js index cfee362..a231968 100644 --- a/src/supabase.js +++ b/src/supabase.js @@ -45,6 +45,10 @@ export const auth = { supabase?.auth.getSession() ?? Promise.resolve({ data: { session: null }, error: null }), + setSession: ({ access_token, refresh_token }) => + supabase?.auth.setSession({ access_token, refresh_token }) ?? + Promise.resolve({ data: { session: null }, error: { message: "Not configured" } }), + onAuthStateChange: (callback) => supabase?.auth.onAuthStateChange(callback) ?? { data: { subscription: { unsubscribe: () => {} } } },