diff --git a/frontend/app/chat/[id]/page.tsx b/frontend/app/chat/[id]/page.tsx
index 8b59bb55..7eb01776 100644
--- a/frontend/app/chat/[id]/page.tsx
+++ b/frontend/app/chat/[id]/page.tsx
@@ -1,28 +1,20 @@
import { Separator } from "@/components/ui/separator";
-import { testData } from "../test-data";
import { Sidebar } from "../sidebar";
import MessageArea from "../message-area";
-import { getUserId } from "@/app/lib/session";
+import { getCurrentUserId } from "@/app/lib/session";
import { getUser, getUsers } from "@/app/lib/actions";
-//async function getUsers() {
-// return testData.users;
-//}
-
export default async function ChatPage({
params: { id },
}: {
params: { id: string };
}) {
- const [tmpUsers, currentUserId] = await Promise.all([
+ const [allUsers, currentUserId] = await Promise.all([
getUsers(),
- getUserId(),
+ getCurrentUserId(),
]);
- if (!currentUserId) {
- throw new Error("getUserId error");
- }
- const currentUser = await getUser(parseInt(currentUserId));
- const users = tmpUsers.filter((user) => user.id !== parseInt(currentUserId));
+ const currentUser = await getUser(currentUserId);
+ const users = allUsers.filter((user) => user.id !== currentUserId);
if (users.length === 0) {
console.error("No other users exist");
throw new Error("No other users exist");
diff --git a/frontend/app/chat/page.tsx b/frontend/app/chat/page.tsx
index 138f9b0e..ac82e573 100644
--- a/frontend/app/chat/page.tsx
+++ b/frontend/app/chat/page.tsx
@@ -1,23 +1,14 @@
import { Separator } from "@/components/ui/separator";
-//import { testData } from "./test-data";
import { Sidebar } from "./sidebar";
-import MessageArea from "./message-area";
-import { getUserId } from "@/app/lib/session";
import { getUsers } from "@/app/lib/actions";
-
-//async function getUsers() {
-// return testData.users;
-//}
+import { getCurrentUserId } from "@/app/lib/session";
export default async function ChatPage() {
- const [tmpUsers, currentUserId] = await Promise.all([
+ const [allUsers, currentUserId] = await Promise.all([
getUsers(),
- getUserId(),
+ getCurrentUserId(),
]);
- if (!currentUserId) {
- throw new Error("getUserId error");
- }
- const users = tmpUsers.filter((user) => user.id !== parseInt(currentUserId));
+ const users = allUsers.filter((user) => user.id !== currentUserId);
return (
<>
diff --git a/frontend/app/client-auth-provider.tsx b/frontend/app/client-auth-provider.tsx
new file mode 100644
index 00000000..ed491fba
--- /dev/null
+++ b/frontend/app/client-auth-provider.tsx
@@ -0,0 +1,26 @@
+"use client";
+
+import { AuthContext } from "@/app/lib/client-auth";
+
+type User = {
+ id: number;
+ name: string;
+ email: string;
+ avatarURL?: string;
+ createdAt: string;
+};
+
+export type AuthProviderProps = {
+ user?: User;
+ children: React.ReactNode;
+ isLoggedIn: boolean;
+};
+
+export default function AuthProvider({
+ children,
+ user,
+ isLoggedIn,
+}: AuthProviderProps) {
+ const auth = { currentUser: user, isLoggedIn };
+ return
{children};
+}
diff --git a/frontend/app/layout.tsx b/frontend/app/layout.tsx
index dc8ff107..9c1a1db5 100644
--- a/frontend/app/layout.tsx
+++ b/frontend/app/layout.tsx
@@ -2,6 +2,9 @@ import type { Metadata } from "next";
import { Inter } from "next/font/google";
import "./globals.css";
+import AuthProvider from "./client-auth-provider";
+import { getCurrentUser, isLoggedIn } from "@/app/lib/session";
+
// components
import { ThemeProvider } from "@/components/theme-provider";
import { Toaster } from "@/components/ui/toaster";
@@ -16,11 +19,14 @@ export const metadata: Metadata = {
description: "Classic Pong game",
};
-export default function RootLayout({
+export default async function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
+ const isAuthorized = await isLoggedIn(); // Not allow expired tokens
+ const user = await getCurrentUser(); // Allows expired tokens
+
return (
@@ -30,11 +36,13 @@ export default function RootLayout({
enableSystem
disableTransitionOnChange
>
-
-
- {children}
-
-
+
+
+
+ {children}
+
+
+
diff --git a/frontend/app/lib/actions.ts b/frontend/app/lib/actions.ts
index 70e530f0..920ed825 100644
--- a/frontend/app/lib/actions.ts
+++ b/frontend/app/lib/actions.ts
@@ -249,3 +249,10 @@ export async function deleteRoomUser(roomId: number, userId: number) {
return "Success";
}
}
+
+export async function signInAsTestUser() {
+ const email = "test@example.com";
+ const password = "password-test";
+ await signIn({ email, password });
+ redirect("/");
+}
diff --git a/frontend/app/lib/client-auth.tsx b/frontend/app/lib/client-auth.tsx
new file mode 100644
index 00000000..309394de
--- /dev/null
+++ b/frontend/app/lib/client-auth.tsx
@@ -0,0 +1,21 @@
+"use client";
+import { createContext, useContext } from "react";
+
+type User = {
+ id: number;
+ name: string;
+ email: string;
+ avatarURL?: string;
+ createdAt: string;
+};
+
+type AuthContextType = {
+ currentUser?: User;
+ isLoggedIn: boolean;
+};
+
+export const AuthContext = createContext
({
+ isLoggedIn: false,
+});
+
+export const useAuthContext = () => useContext(AuthContext);
diff --git a/frontend/app/lib/session.ts b/frontend/app/lib/session.ts
index 6f5c709c..ff0fed5e 100644
--- a/frontend/app/lib/session.ts
+++ b/frontend/app/lib/session.ts
@@ -1,5 +1,6 @@
import { cookies } from "next/headers";
import * as jose from "jose";
+import { getUser } from "./actions";
// TODO: add types
export type Session = {};
@@ -22,10 +23,30 @@ export async function isLoggedIn() {
return true;
}
-export async function getUserId(): Promise {
+export async function getCurrentUser(): Promise {
+ try {
+ const userId = await getCurrentUserId();
+ const user = getUser(userId);
+ return user;
+ } catch (e) {
+ console.log("getCurrentUser: ", e);
+ return null;
+ }
+}
+
+// Only use this function if you are sure that the user is logged in
+export async function getCurrentUserId(): Promise {
const payload = await getAccessTokenPayload({ ignoreExpiration: true });
- if (!payload) return null;
- return payload.userId as string;
+ const userId = payload?.userId?.toString();
+ // If userId is not set, then return null
+ if (!userId) {
+ throw new Error("userId is not set");
+ }
+ // If invalid userId, then return null
+ if (!userId.match(/^[0-9]+$/)) {
+ throw new Error("invalid userId");
+ }
+ return parseInt(userId);
}
async function getAccessTokenPayload(options: any) {
diff --git a/frontend/app/room/[id]/page.tsx b/frontend/app/room/[id]/page.tsx
index 9c23371e..79d7f6b5 100644
--- a/frontend/app/room/[id]/page.tsx
+++ b/frontend/app/room/[id]/page.tsx
@@ -25,7 +25,7 @@
// );
//}
-import { getUserId } from "@/app/lib/session";
+import { getCurrentUserId } from "@/app/lib/session";
import { Separator } from "@/components/ui/separator";
import { Sidebar } from "../sidebar";
import { getRoom, getUsers, getUser } from "@/app/lib/actions";
@@ -44,11 +44,7 @@ export default async function Page({
}: {
params: { id: number };
}) {
- const currentUserId = await getUserId();
- if (!currentUserId) {
- console.error("getUserId error");
- throw new Error("getUserId error");
- }
+ const currentUserId = await getCurrentUserId();
const roomInfo = await getRoom(id);
if (!roomInfo) {
notFound();
@@ -60,10 +56,9 @@ export default async function Page({
.sort((a: UserRole, b: UserRole) => a.id - b.id);
const myInfo = roomInfo.users.find((user: UserOnRoom) => {
- return user.userId === parseInt(currentUserId);
+ return user.userId === currentUserId;
});
if (!myInfo) {
- console.error("Not participating in room");
throw new Error("Not participating in room");
}
const allUsers = await getUsers();
@@ -76,7 +71,7 @@ export default async function Page({
role: usersRole[i].role,
}),
);
- const currentUser = await getUser(parseInt(currentUserId));
+ const currentUser = await getUser(currentUserId);
return (
<>
diff --git a/frontend/app/ui/direct-message/dm-sidebar.tsx b/frontend/app/ui/direct-message/dm-sidebar.tsx
index 584d9cb0..412580ee 100644
--- a/frontend/app/ui/direct-message/dm-sidebar.tsx
+++ b/frontend/app/ui/direct-message/dm-sidebar.tsx
@@ -2,7 +2,7 @@ import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card";
import { ScrollArea } from "@/components/ui/scroll-area";
import { Separator } from "@/components/ui/separator";
import { getUsers } from "@/app/lib/actions";
-import { getUserId } from "@/app/lib/session";
+import { getCurrentUserId } from "@/app/lib/session";
import { UserButton } from "@/app/ui/direct-message/user-button";
const DirectMessageSidebar = async () => {
@@ -11,12 +11,8 @@ const DirectMessageSidebar = async () => {
console.error("getUsers Error");
return null;
}
- const currentUserId = await getUserId();
- if (!currentUserId) {
- console.error("getUserId Error");
- return null;
- }
- const users = tmpUsers.filter((user) => parseInt(currentUserId) !== user.id);
+ const currentUserId = await getCurrentUserId();
+ const users = tmpUsers.filter((user) => currentUserId !== user.id);
return (
diff --git a/frontend/app/ui/nav.tsx b/frontend/app/ui/nav.tsx
index dd23f946..dddbb99b 100644
--- a/frontend/app/ui/nav.tsx
+++ b/frontend/app/ui/nav.tsx
@@ -1,9 +1,8 @@
import { ModeToggle } from "@/components/toggle-mode";
import { Button } from "@/components/ui/button";
import Link from "next/link";
-import { signIn, signOut } from "@/app/lib/actions";
+import { signInAsTestUser, signOut } from "@/app/lib/actions";
import { isLoggedIn } from "@/app/lib/session";
-import { redirect } from "next/navigation";
function AuthorizedMenu() {
return (
@@ -20,14 +19,6 @@ function AuthorizedMenu() {
);
}
-async function signInAsTestUser() {
- "use server";
- const email = "test@example.com";
- const password = "password-test";
- await signIn({ email, password });
- redirect("/");
-}
-
function UnauthorizedMenu() {
return (
diff --git a/frontend/app/ui/profile/profile-form.tsx b/frontend/app/ui/profile/profile-form.tsx
index 2f99c5ae..7aabd54e 100644
--- a/frontend/app/ui/profile/profile-form.tsx
+++ b/frontend/app/ui/profile/profile-form.tsx
@@ -1,9 +1,11 @@
+"use client";
import { Skeleton } from "@/components/ui/skeleton";
import { Separator } from "@/components/ui/separator";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Stack } from "@/app/ui/layout/stack";
import { Label } from "@/components/ui/label";
+import { useAuthContext } from "@/app/lib/client-auth";
function AvatarSkeleton() {
return ;
@@ -23,10 +25,11 @@ function ProfileItem({ type, title, value }: ProfileItemProps) {
export type ProfileItemProps = {
type: string;
title: string;
- value: string;
+ value?: string;
};
export default function ProfileForm() {
+ const { currentUser } = useAuthContext();
// Menu: min 100px
// Profile : the rest
return (
@@ -37,8 +40,8 @@ export default function ProfileForm() {
-
-
+
+