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
29 changes: 26 additions & 3 deletions app/auth/callback/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,34 @@ function AuthCallbackContent() {
return;
}

// If no callback parameters, redirect to home
// For OAuth redirects (especially Apple), we might not get URL parameters
// Try to check if the user is actually authenticated after OAuth redirect
setMessage("Verifying authentication...");
const isUserAuthenticated = await AuthService.isAuthenticated();

if (isUserAuthenticated) {
setMessage("Authentication verified! Updating profile...");

// User is authenticated, refresh the auth context
await refreshUser();

// Trigger auth success event for listening components
window.dispatchEvent(new CustomEvent("auth_success"));
localStorage.setItem("auth_success", "true");

setStatus("success");
setMessage("Authentication successful! Redirecting...");
setTimeout(() => router.push("/"), 2000);
return;
}

// If no callback parameters and user is not authenticated, redirect to home
router.push("/");
} catch (error) {
setStatus("error");
setMessage("An error occurred during authentication");
setMessage(
"An error occurred during authentication. Please try again.",
);
setTimeout(() => router.push("/"), 3000);
}
};
Expand Down Expand Up @@ -105,7 +128,7 @@ function AuthCallbackContent() {

<button
onClick={() => router.push("/")}
className="bg-blue-600 text-white px-6 py-2 rounded-lg hover:bg-blue-700 transition-colors"
className="btn-primary text-white px-6 py-2 rounded-lg"
>
Go to Home
</button>
Expand Down
2 changes: 1 addition & 1 deletion app/exam/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ const Exam: NextPage<{ searchParams: { url: string; name: string } }> = ({
</div>
<button
onClick={() => (window.location.href = "/")}
className="bg-blue-600 text-white px-6 py-2 rounded-lg hover:bg-blue-700 transition-colors"
className="btn-primary text-white px-6 py-2 rounded-lg"
>
Go to Home
</button>
Expand Down
6 changes: 3 additions & 3 deletions app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { type ReactNode } from "react";
import { type Metadata, type Viewport } from "next";
import TopNav from "@azure-fundamentals/components/TopNav";
import Header from "@azure-fundamentals/components/Header";
import Footer from "@azure-fundamentals/components/Footer";
import ApolloProvider from "@azure-fundamentals/components/ApolloProvider";
import Cookie from "@azure-fundamentals/components/Cookie";
Expand Down Expand Up @@ -109,8 +109,8 @@ export default function RootLayout({ children }: RootLayoutProps) {
<body className="bg-slate-900">
<ApolloProvider>
<AuthProvider>
<TopNav />
<main className="flex flex-col justify-between md:h-[calc(100vh-2.5rem-64px)] h-full">
<Header />
<main className="flex flex-col justify-between min-h-[calc(100vh-4rem)]">
{children}
<Footer />
<Cookie />
Expand Down
2 changes: 1 addition & 1 deletion app/practice/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ const Practice: NextPage = () => {
</div>
<button
onClick={() => (window.location.href = "/")}
className="bg-blue-600 text-white px-6 py-2 rounded-lg hover:bg-blue-700 transition-colors"
className="btn-primary text-white px-6 py-2 rounded-lg"
>
Go to Home
</button>
Expand Down
50 changes: 44 additions & 6 deletions components/AuthModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export const AuthModal: React.FC<AuthModalProps> = ({
verifyOTPAndSignIn,
signInWithGoogle,
signInWithApple,
isAuthenticated,
} = useAuth();
const [email, setEmail] = useState("");
const [otp, setOtp] = useState("");
Expand Down Expand Up @@ -48,6 +49,24 @@ export const AuthModal: React.FC<AuthModalProps> = ({
}
}, [isOpen]);

// Auto-close modal when user becomes authenticated (especially for Apple OAuth redirects)
useEffect(() => {
if (isAuthenticated && isOpen) {
// Reset modal state
setStep("email");
setEmail("");
setOtp("");
setUserId(null);
setIsLoading(false);
setIsVerifying(false);
setIsRedirecting(false);
setMessage("");

// Close the modal
onClose();
}
}, [isAuthenticated, isOpen, onClose]);

if (!isOpen) return null;

const handleEmailSignIn = async (e: React.FormEvent) => {
Expand Down Expand Up @@ -124,14 +143,23 @@ 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));
await signInWithApple();

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.
} catch (error) {
setMessage("Failed to sign in with Apple");
setMessage("Failed to sign in with Apple. Please try again.");
setIsLoading(false);
}
};
Expand Down Expand Up @@ -211,7 +239,10 @@ export const AuthModal: React.FC<AuthModalProps> = ({
)}
{isLoading ? "Sending..." : "Continue with Email"}
{!isLoading && lastUsedMethod?.type === "email" && (
<span className="absolute -top-1 -right-1 bg-blue-500 text-white text-xs px-2 py-1 rounded-full">
<span
className="absolute -top-1 -right-1 text-white text-xs px-2 py-1 rounded-full"
style={{ backgroundColor: "#3f51b5" }}
>
Last Used
</span>
)}
Expand Down Expand Up @@ -318,7 +349,8 @@ export const AuthModal: React.FC<AuthModalProps> = ({
setIsVerifying(false);
setIsRedirecting(false);
}}
className="w-full text-center text-sm text-blue-400 hover:text-blue-300"
className="w-full text-center text-sm hover:opacity-80 transition-opacity"
style={{ color: "#3f51b5" }}
>
← Back
</button>
Expand Down Expand Up @@ -362,7 +394,10 @@ export const AuthModal: React.FC<AuthModalProps> = ({
</svg>
Continue with Google
{!isLoading && lastUsedMethod?.type === "google" && (
<span className="absolute -top-1 -right-1 bg-blue-500 text-white text-xs px-2 py-1 rounded-full">
<span
className="absolute -top-1 -right-1 text-white text-xs px-2 py-1 rounded-full"
style={{ backgroundColor: "#3f51b5" }}
>
Last Used
</span>
)}
Expand All @@ -384,7 +419,10 @@ export const AuthModal: React.FC<AuthModalProps> = ({
</svg>
Continue with Apple
{!isLoading && lastUsedMethod?.type === "apple" && (
<span className="absolute -top-1 -right-1 bg-blue-500 text-white text-xs px-2 py-1 rounded-full">
<span
className="absolute -top-1 -right-1 text-white text-xs px-2 py-1 rounded-full"
style={{ backgroundColor: "#3f51b5" }}
>
Last Used
</span>
)}
Expand Down
8 changes: 1 addition & 7 deletions components/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,7 @@ import React from "react";
const button = cva("button", {
variants: {
intent: {
primary: [
"bg-blue-600/50",
"border-blue-600",
"hover:bg-blue-600/60",
"focus:ring-blue-800",
"border-blue-600",
],
primary: ["btn-primary", "focus:ring-blue-800"],
secondary: [
"bg-emerald-600/50",
"border-emerald-600",
Expand Down
56 changes: 33 additions & 23 deletions components/Footer.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
"use client";

import {
SiDiscord,
SiEbay,
SiEtsy,
SiGithub,
SiGoogleplay,
SiFacebook,
SiInstagram,
SiLinkedin,
SiReddit,
SiMedium,
SiPatreon,
SiUdemy,
SiX,
SiYoutube,
} from "react-icons/si";
import GitHubButton from "react-github-btn";
import packageJson from "../package.json";
import "styles/footer.css";
const Footer = () => {
const currentYear = new Date().getFullYear();
Expand All @@ -21,26 +23,10 @@ const Footer = () => {
url: "https://discord.gg/RFjtXKfJy3",
icon: <SiDiscord className="discord" size={iconSize} />,
},
{
url: "https://ebay.com/usr/ditectrev",
icon: <SiEbay className="ebay" size={iconSize} />,
},
{
url: "https://ditectrev.etsy.com",
icon: <SiEtsy className="etsy" size={iconSize} />,
},
{
url: "https://facebook.com/ditectrev",
icon: <SiFacebook className="facebook" size={iconSize} />,
},
{
url: "https://github.com/ditectrev",
icon: <SiGithub className="github" size={iconSize} />,
},
{
url: "https://play.google.com/store/books/author?id=Daniel+Danielecki",
icon: <SiGoogleplay className="googleplay" size={iconSize} />,
},
{
url: "https://instagram.com/ditectrev",
icon: <SiInstagram className="instagram" size={iconSize} />,
Expand All @@ -50,8 +36,12 @@ const Footer = () => {
icon: <SiLinkedin className="linkedin" size={iconSize} />,
},
{
url: "https://reddit.com/user/Ditectrev",
icon: <SiReddit className="reddit" size={iconSize} />,
url: "https://medium.com/@ditectrev",
icon: <SiMedium className="medium" size={iconSize} />,
},
{
url: "https://patreon.com/Ditectrev",
icon: <SiPatreon className="patreon" size={iconSize} />,
},
{
url: "https://udemy.com/user/social-ditectrev",
Expand All @@ -61,6 +51,10 @@ const Footer = () => {
url: "https://x.com/ditectrev",
icon: <SiX className="x" size={iconSize} />,
},
{
url: "https://youtube.com/@Ditectrev",
icon: <SiYoutube className="youtube" size={iconSize} />,
},
];

return (
Expand All @@ -79,6 +73,22 @@ const Footer = () => {
</a>
))}
</div>

{/* GitHub Star and Version */}
<div className="flex flex-col sm:flex-row items-center justify-center gap-2 mb-4">
<GitHubButton
href="https://github.com/Ditectrev/Practice-Exams-Platform"
data-color-scheme="no-preference: dark; light: light; dark: dark;"
data-icon="octicon-star"
data-size="large"
data-show-count="true"
aria-label="Star Practice Exams Platform on GitHub"
>
Star
</GitHubButton>
<span className="text-slate-400 text-xs">v{packageJson.version}</span>
</div>

<p className="text-white text-sm flex justify-center">
&copy; {currentYear} Ditectrev
</p>
Expand Down
Loading
Loading