diff --git a/frontend/app/layout.tsx b/frontend/app/layout.tsx index c4812626..2378ae03 100644 --- a/frontend/app/layout.tsx +++ b/frontend/app/layout.tsx @@ -3,7 +3,6 @@ import type { Metadata } from "next"; import { Inter } from "next/font/google"; import AuthProvider from "@/app/lib/client-auth-provider"; -import SocketProvider from "@/app/lib/client-socket-provider"; import { getAccessTokenPayload } from "@/app/lib/session"; // components @@ -13,7 +12,8 @@ import { Toaster } from "@/components/ui/toaster"; // ui import { getMe } from "@/app/lib/actions"; import { JwtPayload } from "@/app/lib/dtos"; -import Nav from "@/app/ui/nav"; +import { OnlineProviders } from "./onlineProviders"; +import Nav from "./ui/nav"; const inter = Inter({ subsets: ["latin"] }); @@ -45,12 +45,11 @@ export default async function RootLayout({ disableTransitionOnChange > +
- -
diff --git a/frontend/app/lib/client-socket-provider.tsx b/frontend/app/lib/client-socket-provider.tsx index 4324cc25..90b2b8aa 100644 --- a/frontend/app/lib/client-socket-provider.tsx +++ b/frontend/app/lib/client-socket-provider.tsx @@ -3,7 +3,14 @@ import { ToastAction } from "@/components/ui/toast"; import { useToast } from "@/components/ui/use-toast"; import { chatSocket } from "@/socket"; import Link from "next/link"; -import { useCallback, useEffect, useState } from "react"; +import { + Dispatch, + SetStateAction, + createContext, + useCallback, + useEffect, + useState, +} from "react"; import { useAuthContext } from "./client-auth"; import { DenyEvent, @@ -19,7 +26,13 @@ import { chatSocket as socket } from "@/socket"; import { useRouter } from "next/navigation"; import { usePathname } from "next/navigation"; -export default function SocketProvider() { +export const OnlineContext = createContext<{ [key: number]: number }>({}); + +export default function SocketProvider({ + setOnlineStatus, +}: { + setOnlineStatus: Dispatch>; +}) { const { toast } = useToast(); const { currentUser } = useAuthContext(); const pathName = usePathname(); @@ -117,16 +130,14 @@ export default function SocketProvider() { }); }; - const [onlineStatus, setOnlineStatus] = useState<{ [key: number]: number }>( - {}, - ); const handleOnlineStatus = (users: { userId: number; status: number }[]) => { - console.log("users", users); users.forEach((u) => { - console.log("FOO! u", u); setOnlineStatus((prev) => ({ ...prev, [u.userId]: u.status })); }); - console.log("online-status", onlineStatus); // TODO: この時点では変更されていない? + toast({ + title: "online-status", + description: JSON.stringify(users), + }); }; const showMessageToast = (message: MessageEvent) => { diff --git a/frontend/app/lib/hooks/useOnlineStatus.ts b/frontend/app/lib/hooks/useOnlineStatus.ts new file mode 100644 index 00000000..3758080d --- /dev/null +++ b/frontend/app/lib/hooks/useOnlineStatus.ts @@ -0,0 +1,10 @@ +"use client"; + +import { useState } from "react"; + +export function useOnlineStatus() { + const [onlineStatus, setOnlineStatus] = useState<{ [key: number]: number }>( + {}, + ); + return { onlineStatus, setOnlineStatus }; +} diff --git a/frontend/app/lib/session.ts b/frontend/app/lib/session.ts index 50f56ba2..ff04d688 100644 --- a/frontend/app/lib/session.ts +++ b/frontend/app/lib/session.ts @@ -1,3 +1,4 @@ +"use server"; import * as jose from "jose"; import { cookies } from "next/headers"; import { redirect } from "next/navigation"; @@ -10,7 +11,7 @@ export type Session = {}; const secret = jose.base64url.decode(process.env.JWT_SECRET!); const spki = process.env.JWT_PUBLIC_KEY!; -export function setAccessToken(token: string) { +export async function setAccessToken(token: string) { cookies()?.set("token", token, { httpOnly: true, // JS cannot access secure: process.env.NODE_ENV === "production", // HTTPS only @@ -112,7 +113,7 @@ export async function getSession(): Promise { } } -export function destroySession() { +export async function destroySession() { console.log("destroySession"); cookies()?.delete("session"); } diff --git a/frontend/app/onlineProviders.tsx b/frontend/app/onlineProviders.tsx new file mode 100644 index 00000000..11d64384 --- /dev/null +++ b/frontend/app/onlineProviders.tsx @@ -0,0 +1,16 @@ +"use client"; + +import { useOnlineStatus } from "./lib/hooks/useOnlineStatus"; +import SocketProvider, { OnlineContext } from "./lib/client-socket-provider"; + +export function OnlineProviders({ children }: { children: React.ReactNode }) { + const { onlineStatus, setOnlineStatus } = useOnlineStatus(); + return ( + <> + + {children} + + + + ); +} diff --git a/frontend/app/ui/user/user-list.tsx b/frontend/app/ui/user/user-list.tsx index 8619adb4..6f37de49 100644 --- a/frontend/app/ui/user/user-list.tsx +++ b/frontend/app/ui/user/user-list.tsx @@ -3,7 +3,8 @@ import type { PublicUserEntity } from "@/app/lib/dtos"; import { TooltipProvider } from "@/components/ui/tooltip"; import { Avatar, AvatarSize } from "./avatar"; -import { useEffect, useState } from "react"; +import { OnlineContext } from "@/app/lib/client-socket-provider"; +import { useContext } from "react"; export default function UserList({ users, @@ -12,6 +13,7 @@ export default function UserList({ users: PublicUserEntity[]; avatarSize: AvatarSize; }) { + const onlineStatus = useContext(OnlineContext); return (
@@ -22,7 +24,7 @@ export default function UserList({ size={avatarSize} href={`/user/${u.id}`} alt={u.name} - online={true} + online={onlineStatus[u.id] === 1} key={u.id} /> ))}