Skip to content

Commit

Permalink
[frontend] display online status (#252)
Browse files Browse the repository at this point in the history
* [frontend] useState が client component でのみ利用できるので file を分けた

* [frontend] session.ts が client component として読まれ、 cookies を import するところでエラー

* [frontend] server component は 全て async にしなければならない

* [frontend] use context in UserList

* [frontend] display uesr's online status!!!
  • Loading branch information
kotto5 authored Feb 11, 2024
1 parent 1a6d9d4 commit 30041ba
Show file tree
Hide file tree
Showing 6 changed files with 56 additions and 17 deletions.
9 changes: 4 additions & 5 deletions frontend/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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"] });

Expand Down Expand Up @@ -45,12 +45,11 @@ export default async function RootLayout({
disableTransitionOnChange
>
<AuthProvider payload={payload as JwtPayload} user={user}>
<Toaster />
<div className="flex flex-col px-16 h-[100vh]">
<Nav />
{children}
<OnlineProviders>{children}</OnlineProviders>
</div>
<SocketProvider />
<Toaster />
</AuthProvider>
</ThemeProvider>
</body>
Expand Down
27 changes: 19 additions & 8 deletions frontend/app/lib/client-socket-provider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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<SetStateAction<{ [key: number]: number }>>;
}) {
const { toast } = useToast();
const { currentUser } = useAuthContext();
const pathName = usePathname();
Expand Down Expand Up @@ -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) => {
Expand Down
10 changes: 10 additions & 0 deletions frontend/app/lib/hooks/useOnlineStatus.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
"use client";

import { useState } from "react";

export function useOnlineStatus() {
const [onlineStatus, setOnlineStatus] = useState<{ [key: number]: number }>(
{},
);
return { onlineStatus, setOnlineStatus };
}
5 changes: 3 additions & 2 deletions frontend/app/lib/session.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
"use server";
import * as jose from "jose";
import { cookies } from "next/headers";
import { redirect } from "next/navigation";
Expand All @@ -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
Expand Down Expand Up @@ -112,7 +113,7 @@ export async function getSession(): Promise<Session | null> {
}
}

export function destroySession() {
export async function destroySession() {
console.log("destroySession");
cookies()?.delete("session");
}
16 changes: 16 additions & 0 deletions frontend/app/onlineProviders.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<>
<OnlineContext.Provider value={onlineStatus}>
{children}
<SocketProvider setOnlineStatus={setOnlineStatus} />
</OnlineContext.Provider>
</>
);
}
6 changes: 4 additions & 2 deletions frontend/app/ui/user/user-list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -12,6 +13,7 @@ export default function UserList({
users: PublicUserEntity[];
avatarSize: AvatarSize;
}) {
const onlineStatus = useContext(OnlineContext);
return (
<TooltipProvider delayDuration={0}>
<div className="flex flex-wrap gap-2">
Expand All @@ -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}
/>
))}
Expand Down

0 comments on commit 30041ba

Please sign in to comment.