Skip to content

Commit 97da48f

Browse files
Merge pull request #76 from Ditectrev/feature/header-elements
Feature/header elements
2 parents 4521a37 + 3ac4002 commit 97da48f

File tree

16 files changed

+476
-295
lines changed

16 files changed

+476
-295
lines changed

app/auth/callback/page.tsx

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,34 @@ function AuthCallbackContent() {
3838
return;
3939
}
4040

41-
// If no callback parameters, redirect to home
41+
// For OAuth redirects (especially Apple), we might not get URL parameters
42+
// Try to check if the user is actually authenticated after OAuth redirect
43+
setMessage("Verifying authentication...");
44+
const isUserAuthenticated = await AuthService.isAuthenticated();
45+
46+
if (isUserAuthenticated) {
47+
setMessage("Authentication verified! Updating profile...");
48+
49+
// User is authenticated, refresh the auth context
50+
await refreshUser();
51+
52+
// Trigger auth success event for listening components
53+
window.dispatchEvent(new CustomEvent("auth_success"));
54+
localStorage.setItem("auth_success", "true");
55+
56+
setStatus("success");
57+
setMessage("Authentication successful! Redirecting...");
58+
setTimeout(() => router.push("/"), 2000);
59+
return;
60+
}
61+
62+
// If no callback parameters and user is not authenticated, redirect to home
4263
router.push("/");
4364
} catch (error) {
4465
setStatus("error");
45-
setMessage("An error occurred during authentication");
66+
setMessage(
67+
"An error occurred during authentication. Please try again.",
68+
);
4669
setTimeout(() => router.push("/"), 3000);
4770
}
4871
};
@@ -105,7 +128,7 @@ function AuthCallbackContent() {
105128

106129
<button
107130
onClick={() => router.push("/")}
108-
className="bg-blue-600 text-white px-6 py-2 rounded-lg hover:bg-blue-700 transition-colors"
131+
className="btn-primary text-white px-6 py-2 rounded-lg"
109132
>
110133
Go to Home
111134
</button>

app/exam/page.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ const Exam: NextPage<{ searchParams: { url: string; name: string } }> = ({
103103
</div>
104104
<button
105105
onClick={() => (window.location.href = "/")}
106-
className="bg-blue-600 text-white px-6 py-2 rounded-lg hover:bg-blue-700 transition-colors"
106+
className="btn-primary text-white px-6 py-2 rounded-lg"
107107
>
108108
Go to Home
109109
</button>

app/layout.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { type ReactNode } from "react";
22
import { type Metadata, type Viewport } from "next";
3-
import TopNav from "@azure-fundamentals/components/TopNav";
3+
import Header from "@azure-fundamentals/components/Header";
44
import Footer from "@azure-fundamentals/components/Footer";
55
import ApolloProvider from "@azure-fundamentals/components/ApolloProvider";
66
import Cookie from "@azure-fundamentals/components/Cookie";
@@ -109,8 +109,8 @@ export default function RootLayout({ children }: RootLayoutProps) {
109109
<body className="bg-slate-900">
110110
<ApolloProvider>
111111
<AuthProvider>
112-
<TopNav />
113-
<main className="flex flex-col justify-between md:h-[calc(100vh-2.5rem-64px)] h-full">
112+
<Header />
113+
<main className="flex flex-col justify-between min-h-[calc(100vh-4rem)]">
114114
{children}
115115
<Footer />
116116
<Cookie />

app/practice/page.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ const Practice: NextPage = () => {
9292
</div>
9393
<button
9494
onClick={() => (window.location.href = "/")}
95-
className="bg-blue-600 text-white px-6 py-2 rounded-lg hover:bg-blue-700 transition-colors"
95+
className="btn-primary text-white px-6 py-2 rounded-lg"
9696
>
9797
Go to Home
9898
</button>

components/AuthModal.tsx

Lines changed: 44 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ export const AuthModal: React.FC<AuthModalProps> = ({
2020
verifyOTPAndSignIn,
2121
signInWithGoogle,
2222
signInWithApple,
23+
isAuthenticated,
2324
} = useAuth();
2425
const [email, setEmail] = useState("");
2526
const [otp, setOtp] = useState("");
@@ -48,6 +49,24 @@ export const AuthModal: React.FC<AuthModalProps> = ({
4849
}
4950
}, [isOpen]);
5051

52+
// Auto-close modal when user becomes authenticated (especially for Apple OAuth redirects)
53+
useEffect(() => {
54+
if (isAuthenticated && isOpen) {
55+
// Reset modal state
56+
setStep("email");
57+
setEmail("");
58+
setOtp("");
59+
setUserId(null);
60+
setIsLoading(false);
61+
setIsVerifying(false);
62+
setIsRedirecting(false);
63+
setMessage("");
64+
65+
// Close the modal
66+
onClose();
67+
}
68+
}, [isAuthenticated, isOpen, onClose]);
69+
5170
if (!isOpen) return null;
5271

5372
const handleEmailSignIn = async (e: React.FormEvent) => {
@@ -124,14 +143,23 @@ export const AuthModal: React.FC<AuthModalProps> = ({
124143

125144
const handleAppleSignIn = async () => {
126145
setIsLoading(true);
146+
setMessage("Redirecting to Apple..."); // User feedback
127147
try {
128148
// Save last used method
129149
const method = { type: "apple", value: "Apple" };
130150
setLastUsedMethod(method);
131151
localStorage.setItem("lastUsedAuthMethod", JSON.stringify(method));
132-
await signInWithApple();
152+
153+
const result = await signInWithApple();
154+
155+
if (!result.success && result.error) {
156+
setMessage(result.error);
157+
setIsLoading(false);
158+
}
159+
// Note: For Apple OAuth, loading state will be reset when the modal auto-closes
160+
// or when the page redirects. Don't reset here for successful redirects.
133161
} catch (error) {
134-
setMessage("Failed to sign in with Apple");
162+
setMessage("Failed to sign in with Apple. Please try again.");
135163
setIsLoading(false);
136164
}
137165
};
@@ -211,7 +239,10 @@ export const AuthModal: React.FC<AuthModalProps> = ({
211239
)}
212240
{isLoading ? "Sending..." : "Continue with Email"}
213241
{!isLoading && lastUsedMethod?.type === "email" && (
214-
<span className="absolute -top-1 -right-1 bg-blue-500 text-white text-xs px-2 py-1 rounded-full">
242+
<span
243+
className="absolute -top-1 -right-1 text-white text-xs px-2 py-1 rounded-full"
244+
style={{ backgroundColor: "#3f51b5" }}
245+
>
215246
Last Used
216247
</span>
217248
)}
@@ -318,7 +349,8 @@ export const AuthModal: React.FC<AuthModalProps> = ({
318349
setIsVerifying(false);
319350
setIsRedirecting(false);
320351
}}
321-
className="w-full text-center text-sm text-blue-400 hover:text-blue-300"
352+
className="w-full text-center text-sm hover:opacity-80 transition-opacity"
353+
style={{ color: "#3f51b5" }}
322354
>
323355
← Back
324356
</button>
@@ -362,7 +394,10 @@ export const AuthModal: React.FC<AuthModalProps> = ({
362394
</svg>
363395
Continue with Google
364396
{!isLoading && lastUsedMethod?.type === "google" && (
365-
<span className="absolute -top-1 -right-1 bg-blue-500 text-white text-xs px-2 py-1 rounded-full">
397+
<span
398+
className="absolute -top-1 -right-1 text-white text-xs px-2 py-1 rounded-full"
399+
style={{ backgroundColor: "#3f51b5" }}
400+
>
366401
Last Used
367402
</span>
368403
)}
@@ -384,7 +419,10 @@ export const AuthModal: React.FC<AuthModalProps> = ({
384419
</svg>
385420
Continue with Apple
386421
{!isLoading && lastUsedMethod?.type === "apple" && (
387-
<span className="absolute -top-1 -right-1 bg-blue-500 text-white text-xs px-2 py-1 rounded-full">
422+
<span
423+
className="absolute -top-1 -right-1 text-white text-xs px-2 py-1 rounded-full"
424+
style={{ backgroundColor: "#3f51b5" }}
425+
>
388426
Last Used
389427
</span>
390428
)}

components/Button.tsx

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,7 @@ import React from "react";
44
const button = cva("button", {
55
variants: {
66
intent: {
7-
primary: [
8-
"bg-blue-600/50",
9-
"border-blue-600",
10-
"hover:bg-blue-600/60",
11-
"focus:ring-blue-800",
12-
"border-blue-600",
13-
],
7+
primary: ["btn-primary", "focus:ring-blue-800"],
148
secondary: [
159
"bg-emerald-600/50",
1610
"border-emerald-600",

components/Footer.tsx

Lines changed: 33 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,18 @@
1+
"use client";
2+
13
import {
24
SiDiscord,
3-
SiEbay,
4-
SiEtsy,
55
SiGithub,
6-
SiGoogleplay,
7-
SiFacebook,
86
SiInstagram,
97
SiLinkedin,
10-
SiReddit,
8+
SiMedium,
9+
SiPatreon,
1110
SiUdemy,
1211
SiX,
12+
SiYoutube,
1313
} from "react-icons/si";
14+
import GitHubButton from "react-github-btn";
15+
import packageJson from "../package.json";
1416
import "styles/footer.css";
1517
const Footer = () => {
1618
const currentYear = new Date().getFullYear();
@@ -21,26 +23,10 @@ const Footer = () => {
2123
url: "https://discord.gg/RFjtXKfJy3",
2224
icon: <SiDiscord className="discord" size={iconSize} />,
2325
},
24-
{
25-
url: "https://ebay.com/usr/ditectrev",
26-
icon: <SiEbay className="ebay" size={iconSize} />,
27-
},
28-
{
29-
url: "https://ditectrev.etsy.com",
30-
icon: <SiEtsy className="etsy" size={iconSize} />,
31-
},
32-
{
33-
url: "https://facebook.com/ditectrev",
34-
icon: <SiFacebook className="facebook" size={iconSize} />,
35-
},
3626
{
3727
url: "https://github.com/ditectrev",
3828
icon: <SiGithub className="github" size={iconSize} />,
3929
},
40-
{
41-
url: "https://play.google.com/store/books/author?id=Daniel+Danielecki",
42-
icon: <SiGoogleplay className="googleplay" size={iconSize} />,
43-
},
4430
{
4531
url: "https://instagram.com/ditectrev",
4632
icon: <SiInstagram className="instagram" size={iconSize} />,
@@ -50,8 +36,12 @@ const Footer = () => {
5036
icon: <SiLinkedin className="linkedin" size={iconSize} />,
5137
},
5238
{
53-
url: "https://reddit.com/user/Ditectrev",
54-
icon: <SiReddit className="reddit" size={iconSize} />,
39+
url: "https://medium.com/@ditectrev",
40+
icon: <SiMedium className="medium" size={iconSize} />,
41+
},
42+
{
43+
url: "https://patreon.com/Ditectrev",
44+
icon: <SiPatreon className="patreon" size={iconSize} />,
5545
},
5646
{
5747
url: "https://udemy.com/user/social-ditectrev",
@@ -61,6 +51,10 @@ const Footer = () => {
6151
url: "https://x.com/ditectrev",
6252
icon: <SiX className="x" size={iconSize} />,
6353
},
54+
{
55+
url: "https://youtube.com/@Ditectrev",
56+
icon: <SiYoutube className="youtube" size={iconSize} />,
57+
},
6458
];
6559

6660
return (
@@ -79,6 +73,22 @@ const Footer = () => {
7973
</a>
8074
))}
8175
</div>
76+
77+
{/* GitHub Star and Version */}
78+
<div className="flex flex-col sm:flex-row items-center justify-center gap-2 mb-4">
79+
<GitHubButton
80+
href="https://github.com/Ditectrev/Practice-Exams-Platform"
81+
data-color-scheme="no-preference: dark; light: light; dark: dark;"
82+
data-icon="octicon-star"
83+
data-size="large"
84+
data-show-count="true"
85+
aria-label="Star Practice Exams Platform on GitHub"
86+
>
87+
Star
88+
</GitHubButton>
89+
<span className="text-slate-400 text-xs">v{packageJson.version}</span>
90+
</div>
91+
8292
<p className="text-white text-sm flex justify-center">
8393
&copy; {currentYear} Ditectrev
8494
</p>

0 commit comments

Comments
 (0)