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
2 changes: 1 addition & 1 deletion .env.example
Original file line number Diff line number Diff line change
@@ -1 +1 @@
NEXT_PUBLIC_BACKEND_URL="http://127.0.0.1:9000/api/v1"
NEXT_PUBLIC_BACKEND_URL="http://127.0.0.1:9000/woc/api/v1"
46 changes: 18 additions & 28 deletions app/auth/callback/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,45 +2,33 @@

import { useAuthStore } from '@/app/store/useAuthStore';
import { useRouter, useSearchParams } from 'next/navigation';
import { useEffect } from 'react';
import { Suspense } from 'react';
import { Suspense, useEffect } from 'react';
import toast from 'react-hot-toast';

function AuthCallbackContent() {
const router = useRouter();
const CallbackContent = () => {
const searchParams = useSearchParams();
const { setUser } = useAuthStore();
const router = useRouter();
const { setTokens } = useAuthStore();

useEffect(() => {
const accessToken = searchParams.get('access_token');
const refreshToken = searchParams.get('refresh_token');
const githubUsername = searchParams.get('github_username');
const email = searchParams.get('email');
const bountyStr = searchParams.get('bounty');
const error = searchParams.get('error');

if (error) {
toast.error('Authentication Error');
router.push('/');
return;
}

if (accessToken && refreshToken && githubUsername && email) {
// update the auth store with the new data
setUser({
access_token: accessToken,
refresh_token: refreshToken,
github_username: githubUsername,
email: email,
bounty: bountyStr ? Number.parseInt(bountyStr) : 0,
setTokens({
accessToken,
refreshToken,
githubUsername,
email,
bounty: 0,
});

toast.success('GitHub account linked successfully!');
router.push('/');
} else {
router.push('/');
router.push('/login');
}
}, [searchParams, setUser, router]);
}, [searchParams, router, setTokens]);
return (
<div className="flex min-h-[calc(100vh-5rem)] w-full items-center justify-center bg-transparent text-white">
<div className="flex flex-col items-center gap-4">
Expand All @@ -49,9 +37,9 @@ function AuthCallbackContent() {
</div>
</div>
);
}
};

export default function AuthCallback() {
const AuthCallbackPage = () => {
return (
<Suspense
fallback={
Expand All @@ -63,7 +51,9 @@ export default function AuthCallback() {
</div>
}
>
<AuthCallbackContent />
<CallbackContent />
</Suspense>
);
}
};

export default AuthCallbackPage;
30 changes: 14 additions & 16 deletions app/components/Navbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ const Navbar = () => {
const router = useRouter();
const user = useAuthStore((state) => state.user);
const clearUser = useAuthStore((state) => state.clearUser);
const github_username = user?.github_username || '';
const githubUsername = user?.githubUsername || '';
const { classes } = useTheme();

useEffect(() => {
Expand Down Expand Up @@ -162,8 +162,8 @@ const Navbar = () => {
<button
type="button"
onClick={() => {
if (user.github_username) {
router.push(`/profile/${github_username}`);
if (user.githubUsername) {
router.push(`/profile/${githubUsername}`);
} else {
toast.error('Please link your GitHub account.');
}
Expand All @@ -172,16 +172,16 @@ const Navbar = () => {
>
<img
src={
user.github_username
? `https://github.com/${user.github_username}.png`
user.githubUsername
? `https://github.com/${user.githubUsername}.png`
: '/default-avatar.png'
}
alt={user.github_username || 'default avatar'}
alt={user.githubUsername || 'default avatar'}
className="h-8 w-8 rounded-full border border-gray-200"
/>
{user.github_username && (
{user.githubUsername && (
<span className="font-semibold lg:block hidden">
{user.github_username}
{user.githubUsername}
</span>
)}
</button>
Expand Down Expand Up @@ -235,8 +235,8 @@ const Navbar = () => {
<button
type="button"
onClick={() => {
if (user.github_username) {
router.push(`/profile/${github_username}`);
if (user.githubUsername) {
router.push(`/profile/${githubUsername}`);
} else {
toast.error('Please link your GitHub account.');
}
Expand All @@ -245,16 +245,14 @@ const Navbar = () => {
>
<img
src={
user.github_username
? `https://github.com/${user.github_username}.png`
user.githubUsername
? `https://github.com/${user.githubUsername}.png`
: '/default-avatar.png'
}
alt={user.github_username || 'default avatar'}
alt={user.githubUsername || 'default avatar'}
className="h-7 w-7 rounded-full border"
/>
{user.github_username && (
<span>{user.github_username}</span>
)}
{user.githubUsername && <span>{user.githubUsername}</span>}
</button>

<button
Expand Down
6 changes: 3 additions & 3 deletions app/components/dashboard-components/leaderboard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ const Leaderboard = ({ user }: { user: AuthUser | null }) => {
url: `${process.env.NEXT_PUBLIC_BACKEND_URL}/registrations`,
method: 'GET',
headers: {
Authorization: `Bearer ${user?.access_token}`,
Authorization: `Bearer ${user?.accessToken}`,
},
});

Expand Down Expand Up @@ -88,7 +88,7 @@ const Leaderboard = ({ user }: { user: AuthUser | null }) => {
};

fetchLeaderboard();
}, [setUser, user?.access_token]);
}, [setUser, user?.accessToken]);

const fetchRegistrations = async () => {
if (participantsData.length > 0) return;
Expand All @@ -106,7 +106,7 @@ const Leaderboard = ({ user }: { user: AuthUser | null }) => {
url: `${process.env.NEXT_PUBLIC_BACKEND_URL}/registrations`,
method: 'GET',
headers: {
Authorization: `Bearer ${user?.access_token}`,
Authorization: `Bearer ${user?.accessToken}`,
},
});

Expand Down
2 changes: 1 addition & 1 deletion app/components/profile-components/GameAchivementSystem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ function GameAchievementSystem({ badges }: GameAchievementSystemProps) {
const [achievements, setAchievements] = useState<Badge[]>([]);

// Check if viewing own profile
const isOwnProfile = user?.github_username === github_username;
const isOwnProfile = user?.githubUsername === github_username;

useEffect(() => {
const loadData = async () => {
Expand Down
10 changes: 5 additions & 5 deletions app/lib/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export async function make_api_call<T = unknown>({
data: T | null;
error: string | null;
}> {
const { user, setUser, clearUser } = useAuthStore.getState();
const { user, setTokens, clearUser } = useAuthStore.getState();

try {
let finalUrl = url;
Expand Down Expand Up @@ -54,13 +54,13 @@ export async function make_api_call<T = unknown>({
}

// TOKEN EXPIRED 401
if (response.status === 401 && retry && user?.refresh_token) {
if (response.status === 401 && retry && user?.refreshToken) {
const refreshRes = await fetch(
`${process.env.NEXT_PUBLIC_BACKEND_URL}/auth/refresh`,
{
method: 'GET',
headers: {
Authorization: `Bearer ${user.refresh_token}`,
Authorization: `Bearer ${user.refreshToken}`,
},
},
);
Expand All @@ -69,9 +69,9 @@ export async function make_api_call<T = unknown>({
const refreshData = await refreshRes.json();
const newAccessToken = refreshData.accessKey;

setUser({
setTokens({
...user,
access_token: newAccessToken,
accessToken: newAccessToken,
});

const newHeaders = {
Expand Down
11 changes: 6 additions & 5 deletions app/login/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ type FormData = z.infer<typeof formSchema>;
export default function LoginPage() {
const router = useRouter();
const { classes, theme } = useTheme();
const { setUser } = useAuthStore();
const { setTokens } = useAuthStore();

const [isSubmitting, setIsSubmitting] = useState(false);
const [formData, setFormData] = useState<FormData>({
Expand Down Expand Up @@ -96,6 +96,7 @@ export default function LoginPage() {
const result = await make_api_call<{
accessToken: string;
refreshToken: string;
ghUsername: string;
message: string;
}>({
url: `${process.env.NEXT_PUBLIC_BACKEND_URL}/auth/login`,
Expand All @@ -109,10 +110,10 @@ export default function LoginPage() {

// console.log('Login successful:', result.data);

setUser({
access_token: result.data.accessToken,
refresh_token: result.data.refreshToken,
github_username: '',
setTokens({
accessToken: result.data.accessToken,
refreshToken: result.data.refreshToken,
githubUsername: result.data.ghUsername,
email: validatedData.email,
bounty: 0,
});
Expand Down
16 changes: 8 additions & 8 deletions app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,12 @@ const Dashboard = () => {
const { classes } = useTheme();

const user = useAuthStore((state) => state.user);

const handleOAuth = async () => {
// Get the latest state directly
const currentUser = useAuthStore.getState().user;

// If no user or no token, redirect to login
if (!currentUser || !currentUser.access_token) {
if (!currentUser || !currentUser.accessToken) {
console.error('No access token found. User might not be logged in.');
toast.error('You must be logged in first.');
router.push('/login');
Expand All @@ -43,7 +42,8 @@ const Dashboard = () => {
url: `${process.env.NEXT_PUBLIC_BACKEND_URL}/github`,
method: 'GET',
headers: {
Authorization: `Bearer ${currentUser.access_token}`,
Authorization: `Bearer ${currentUser.accessToken}`,
'Content-Type': 'application/json',
},
});

Expand Down Expand Up @@ -121,8 +121,8 @@ const Dashboard = () => {
</>
) : (
<>
{/* show only if github_username is empty */}
{!user.github_username ? (
{/* show only if githubUsername is empty */}
{!user.githubUsername ? (
<button
type="button"
onClick={handleOAuth}
Expand All @@ -145,13 +145,13 @@ const Dashboard = () => {
<button
type="button"
onClick={() =>
router.push(`/profile/${user.github_username}`)
router.push(`/profile/${user.githubUsername}`)
}
className="w-fit flex cursor-pointer transform items-center justify-start gap-3 rounded-3xl bg-gray-800 px-3 py-2 text-sm font-medium sm:font-semibold text-white shadow-lg transition duration-300 ease-in-out hover:scale-102 hover:bg-gray-700 focus:outline-none focus:ring-1 focus:ring-gray-500 focus:ring-offset-1 focus:ring-offset-slate-900 sm:gap-3"
>
<img
src={`https://github.com/${user.github_username}.png`}
alt={user.github_username}
src={`https://github.com/${user.githubUsername}.png`}
alt={user.githubUsername}
className="h-8 w-8 rounded-full border border-gray-300 shadow-sm"
/>
<span className="font-semibold text-lg lg:text-base whitespace-nowrap">
Expand Down
6 changes: 3 additions & 3 deletions app/profile/[github_username]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ const ProfilePage = () => {
if (!hydrated) return;

// Redirect to login if not authenticated
if (!user || !user.access_token) {
// console.log('Redirecting to home due to missing user or access_token');
if (!user || !user.accessToken) {
console.log('Redirecting to home due to missing user or accessToken');
router.push('/');
return;
}
Expand All @@ -39,7 +39,7 @@ const ProfilePage = () => {
const result = await make_api_call<ProfileResponse>({
url: `${process.env.NEXT_PUBLIC_BACKEND_URL}/profile?user=${github_username}`,
method: 'GET',
headers: { Authorization: `Bearer ${user.access_token}` },
headers: { Authorization: `Bearer ${user.accessToken}` },
});

if (result.success && result.data) {
Expand Down
31 changes: 26 additions & 5 deletions app/store/useAuthStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,45 @@ import { create } from 'zustand';
import { persist } from 'zustand/middleware';

export interface AuthUser {
access_token: string;
refresh_token: string;
github_username: string;
accessToken: string;
refreshToken: string;
githubUsername: string;
email: string;
bounty: number;
}

export interface AuthState {
user: AuthUser | null;
setUser: (user: AuthUser) => void;
setTokens: (tokens: {
accessToken: string;
refreshToken: string;
githubUsername: string;
email: string;
bounty: number;
}) => void;
clearUser: () => void;
}

export const useAuthStore = create<AuthState>()(
persist(
(set) => ({
user: null,
setUser: (user) => set({ user }),
setTokens: ({
accessToken,
refreshToken,
githubUsername,
email,
bounty,
}) =>
set(() => ({
user: {
accessToken,
refreshToken,
githubUsername,
email,
bounty,
},
})),
clearUser: () => set({ user: null }),
}),
{
Expand Down