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
10 changes: 9 additions & 1 deletion app/auth/callback/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,14 @@ function AuthCallbackContent() {
"loading",
);
const [message, setMessage] = useState("");
const [isProcessing, setIsProcessing] = useState(false);

useEffect(() => {
const handleCallback = async () => {
// Prevent multiple simultaneous executions
if (isProcessing) return;
setIsProcessing(true);

try {
// Check if this is an OAuth callback
const success = searchParams.get("success");
Expand Down Expand Up @@ -67,11 +72,14 @@ function AuthCallbackContent() {
"An error occurred during authentication. Please try again.",
);
setTimeout(() => router.push("/"), 3000);
} finally {
setIsProcessing(false);
}
};

handleCallback();
}, [router, searchParams, refreshUser]);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [searchParams]);

if (status === "loading") {
return (
Expand Down
13 changes: 2 additions & 11 deletions components/AuthModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -143,23 +143,14 @@ export const AuthModal: React.FC<AuthModalProps> = ({

const handleAppleSignIn = async () => {
setIsLoading(true);
setMessage("Redirecting to Apple..."); // User feedback
try {
// Save last used method
const method = { type: "apple", value: "Apple" };
setLastUsedMethod(method);
localStorage.setItem("lastUsedAuthMethod", JSON.stringify(method));

const result = await signInWithApple();

if (!result.success && result.error) {
setMessage(result.error);
setIsLoading(false);
}
// Note: For Apple OAuth, loading state will be reset when the modal auto-closes
// or when the page redirects. Don't reset here for successful redirects.
await signInWithApple();
} catch (error) {
setMessage("Failed to sign in with Apple. Please try again.");
setMessage("Failed to sign in with Apple");
setIsLoading(false);
}
};
Expand Down
33 changes: 7 additions & 26 deletions components/Header.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
"use client";

import React, { useEffect, useState } from "react";
import HomeButton from "./HomeButton";
import Image from "next/image";
import { usePathname, useRouter } from "next/navigation";
import { useAuth } from "../contexts/AuthContext";
Expand Down Expand Up @@ -60,39 +59,21 @@ const Header = () => {
<header className="sticky top-0 z-40 bg-slate-900/95 backdrop-blur supports-[backdrop-filter]:bg-slate-900/60 border-b border-slate-700">
<div className="mx-auto max-w-7xl">
<div className="flex h-16 items-center justify-between px-4 sm:px-6 lg:px-8">
{/* Left section - Home button or logo */}
{/* Left section - Logo */}
<div className="flex items-center">
{pathname !== "/" ? (
<HomeButton
handleReturnToMainPage={() => {
router.push("/");
}}
/>
) : (
<div className="flex items-center">
<Image
src="/logo.svg"
alt="Ditectrev Logo"
className="h-8 w-auto"
height={32}
width={120}
/>
</div>
)}
</div>

{/* Center section - Logo on non-home pages */}
{pathname !== "/" && (
<div className="flex items-center absolute left-1/2 transform -translate-x-1/2 md:relative md:left-auto md:transform-none">
<button
onClick={() => router.push("/")}
className="flex items-center cursor-pointer"
>
<Image
src="/logo.svg"
alt="Ditectrev Logo"
className="h-8 w-auto"
height={32}
width={120}
/>
</div>
)}
</button>
</div>

{/* Right section - Navigation and Auth */}
<div className="flex items-center space-x-4">
Expand Down
23 changes: 0 additions & 23 deletions components/HomeButton.tsx

This file was deleted.

67 changes: 40 additions & 27 deletions components/QuizForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -325,33 +325,46 @@ const QuizForm: FC<Props> = ({
{isThinking ? "Thinking..." : "Explain"}
</Button>
)}
<Button
type="button"
intent="primary"
size="medium"
disabled={currentQuestionIndex < lastIndex}
onClick={() => {
if (!showCorrectAnswer) {
setSavedAnswers((prev) => ({
...prev,
[currentQuestionIndex]: watchInput,
}));
}
setShowCorrectAnswer(false);
setExplanation(null);
if (currentQuestionIndex === totalQuestions) {
handleNextQuestion(1);
setLastIndex(1);
} else {
handleNextQuestion(currentQuestionIndex + 1);
setLastIndex(currentQuestionIndex + 1);
}
setCanGoBack(false);
reset();
}}
>
Next Question
</Button>
{currentQuestionIndex < totalQuestions ? (
<Button
type="button"
intent="primary"
size="medium"
disabled={currentQuestionIndex < lastIndex}
onClick={() => {
if (!showCorrectAnswer) {
setSavedAnswers((prev) => ({
...prev,
[currentQuestionIndex]: watchInput,
}));
}
setShowCorrectAnswer(false);
setExplanation(null);
if (currentQuestionIndex === totalQuestions) {
handleNextQuestion(1);
setLastIndex(1);
} else {
handleNextQuestion(currentQuestionIndex + 1);
setLastIndex(currentQuestionIndex + 1);
}
setCanGoBack(false);
reset();
}}
>
Next Question
</Button>
) : (
<Button
type="button"
intent="primary"
size="medium"
onClick={() => {
window.location.href = "/";
}}
>
Go Home
</Button>
)}
</div>
</form>
);
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "practice-exams-platform",
"version": "1.4.3",
"version": "1.4.4",
"private": true,
"engines": {
"node": "20.x"
Expand Down
66 changes: 32 additions & 34 deletions styles/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -30,41 +30,39 @@ a[target="_blank"]:hover .external-link-icon {
}

.loading-container {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
z-index: 9999;
}
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
z-index: 9999;
}

.spinner {
border: 8px solid rgba(255, 255, 255, 0.3);
border-top: 8px solid #1E293B;
border-radius: 50%;
width: 60px;
height: 60px;
-webkit-animation: spin 1s linear infinite;
animation: spin 1s linear infinite;
.spinner {
border: 8px solid rgba(255, 255, 255, 0.3);
border-top: 8px solid #1E293B;
border-radius: 50%;
width: 60px;
height: 60px;
-webkit-animation: spin 1s linear infinite;
animation: spin 1s linear infinite;
}
@-webkit-keyframes spin {
0% {
transform: rotate(0deg);
}

@-webkit-keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
100% {
transform: rotate(360deg);
}

@keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
@keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
Loading