From cf74382448c44f5b49eea4ff67522267c7c24cba Mon Sep 17 00:00:00 2001 From: shunsei Date: Tue, 29 Oct 2024 20:44:23 +0900 Subject: [PATCH 1/4] Remove login & logout success notification (#105) --- .../header/HeaderLoginComponent.tsx | 2 +- frontend/app/routes/auth.login.tsx | 7 ++-- frontend/app/routes/home._index.tsx | 2 +- frontend/app/routes/home.mypage.tsx | 27 ++------------ frontend/app/routes/home.tsx | 36 ++++++++----------- frontend/app/services/session.server.ts | 6 ++-- 6 files changed, 27 insertions(+), 53 deletions(-) diff --git a/frontend/app/components/header/HeaderLoginComponent.tsx b/frontend/app/components/header/HeaderLoginComponent.tsx index f6f62c25..32bd77f3 100644 --- a/frontend/app/components/header/HeaderLoginComponent.tsx +++ b/frontend/app/components/header/HeaderLoginComponent.tsx @@ -20,7 +20,7 @@ const HeaderLoginComponent = () => { setUser(undefined); // モーダルを閉じる close(); - // home.tsx の action を呼び出す + // ログアウトのactionを呼び出す submit({}, { method: 'DELETE', action: '/home' }); }; diff --git a/frontend/app/routes/auth.login.tsx b/frontend/app/routes/auth.login.tsx index 475e702b..62c76216 100644 --- a/frontend/app/routes/auth.login.tsx +++ b/frontend/app/routes/auth.login.tsx @@ -49,9 +49,11 @@ export const action = async ({ request }: ActionFunctionArgs) => { // ログインに成功した場合 if (response.status === 200) { - session.flash('loginSuccess', 'ログインに成功しました'); session.set('userId', response.data.id.toString()); session.set('sessionToken', response.data.sessionToken!); + // FIXME: ログアウト時に表示できないのでログイン時も表示しない + // session.flash('loginSuccess', 'ログインに成功しました'); + return redirect('/home/mypage', { headers: { 'Set-Cookie': await commitSession(session), @@ -79,9 +81,10 @@ export const action = async ({ request }: ActionFunctionArgs) => { session.flash('loginError', 'エラーが発生しました'); } + const setCookie = await commitSession(session); return redirect('/auth/login', { headers: { - 'Set-Cookie': await commitSession(session), + 'Set-Cookie': setCookie, }, }); }; diff --git a/frontend/app/routes/home._index.tsx b/frontend/app/routes/home._index.tsx index 5ff91915..abdf47be 100644 --- a/frontend/app/routes/home._index.tsx +++ b/frontend/app/routes/home._index.tsx @@ -66,7 +66,7 @@ export const loader = async ({ request }: LoaderFunctionArgs) => { }, flash: { success: success, - error: success ? undefined : error, + error: error, }, }, { diff --git a/frontend/app/routes/home.mypage.tsx b/frontend/app/routes/home.mypage.tsx index ba86b5ec..6571ca5f 100644 --- a/frontend/app/routes/home.mypage.tsx +++ b/frontend/app/routes/home.mypage.tsx @@ -1,12 +1,5 @@ -import { json, LoaderFunctionArgs, redirect } from '@remix-run/cloudflare'; -import { useLoaderData } from '@remix-run/react'; -import { useEffect } from 'react'; -import { commitSession, getSession } from '~/services/session.server'; -import { successNotification } from '~/utils/notification'; - -interface LoaderData { - success?: string; -} +import { LoaderFunctionArgs, redirect } from '@remix-run/cloudflare'; +import { getSession } from '~/services/session.server'; export const loader = async ({ request }: LoaderFunctionArgs) => { const session = await getSession(request.headers.get('Cookie')); @@ -17,24 +10,10 @@ export const loader = async ({ request }: LoaderFunctionArgs) => { return redirect('/auth/login'); } - const data = { success: session.get('loginSuccess') }; - - return json(data, { - headers: { - 'Set-Cookie': await commitSession(session), - }, - }); + return null; }; const MyPage = () => { - const { success } = useLoaderData(); - - useEffect(() => { - if (success) { - successNotification(success); - } - }, []); - return
MyPage
; }; diff --git a/frontend/app/routes/home.tsx b/frontend/app/routes/home.tsx index 7fa009d9..07ee8677 100644 --- a/frontend/app/routes/home.tsx +++ b/frontend/app/routes/home.tsx @@ -10,28 +10,25 @@ import { getUser, logout } from 'client/client'; import { useAtom } from 'jotai'; import { useEffect } from 'react'; import HeaderComponent from '~/components/header/HeaderComponent'; -import { commitSession, getSession } from '~/services/session.server'; +import { + commitSession, + destroySession, + getSession, +} from '~/services/session.server'; import { userAtom } from '~/stores/userAtom'; -import { errorNotification, successNotification } from '~/utils/notification'; interface LoaderData { userId?: string; - success?: string; - error?: string; } export const loader = async ({ request }: LoaderFunctionArgs) => { const session = await getSession(request.headers.get('Cookie')); const userId = session.get('userId'); - const success = session.get('logoutSuccess'); - const error = session.get('logoutError'); return json( { userId: userId, - success: success, - error: success ? undefined : error, }, { headers: { @@ -54,24 +51,24 @@ export const action = async ({ request }: ActionFunctionArgs) => { if (response.status === 204) { session.unset('userId'); session.unset('sessionToken'); - session.flash('logoutSuccess', 'ログアウトに成功しました'); + // FIXME: loaderで読み出しても削除されない + // session.flash('logoutSuccess', 'ログアウトに成功しました'); + return redirect('/home', { headers: { - 'Set-Cookie': await commitSession(session), + 'Set-Cookie': await destroySession(session), }, }); } else { - session.flash('logoutError', 'ログアウトに失敗しました'); - return redirect('/home', { - headers: { - 'Set-Cookie': await commitSession(session), - }, - }); + // FIXME: loaderで読み出しても削除されない + // session.flash('logoutError', 'ログアウトに失敗しました'); + + return redirect('/home'); } }; const Home = () => { - const { userId, success, error } = useLoaderData(); + const { userId } = useLoaderData(); const [user, setUser] = useAtom(userAtom); const navigation = useNavigation(); @@ -92,11 +89,6 @@ const Home = () => { } else { setUser(undefined); } - if (success) { - successNotification(success); - } else if (error) { - errorNotification(error); - } } }, [navigation.state]); diff --git a/frontend/app/services/session.server.ts b/frontend/app/services/session.server.ts index b013fdb9..72150613 100644 --- a/frontend/app/services/session.server.ts +++ b/frontend/app/services/session.server.ts @@ -7,11 +7,11 @@ interface SessionData { interface SessionFlashData { // ログイン - loginSuccess: string; + // loginSuccess: string; loginError: string; // ログアウト - logoutSuccess: string; - logoutError: string; + // logoutSuccess: string; + // logoutError: string; // 書籍の削除 deleteBookSuccess: string; deleteBookError: string; From c05bc769e071c05245cd5854912501c96a7a8e7d Mon Sep 17 00:00:00 2001 From: shunsei Date: Tue, 29 Oct 2024 23:23:39 +0900 Subject: [PATCH 2/4] Show notification only once (#105) --- frontend/app/routes/_index.tsx | 2 +- frontend/app/routes/auth.login.tsx | 19 ++++---- frontend/app/routes/home._index.tsx | 53 +++++----------------- frontend/app/routes/home.books.$bookId.tsx | 10 ++-- frontend/app/routes/home.tsx | 43 ++++++++++++------ frontend/app/services/session.server.ts | 11 +---- 6 files changed, 58 insertions(+), 80 deletions(-) diff --git a/frontend/app/routes/_index.tsx b/frontend/app/routes/_index.tsx index 2eb33bec..bff60b90 100644 --- a/frontend/app/routes/_index.tsx +++ b/frontend/app/routes/_index.tsx @@ -8,5 +8,5 @@ export const meta: MetaFunction = () => { }; export async function loader() { - return redirect('home'); + return redirect('/home'); } diff --git a/frontend/app/routes/auth.login.tsx b/frontend/app/routes/auth.login.tsx index 62c76216..fe0fdc8d 100644 --- a/frontend/app/routes/auth.login.tsx +++ b/frontend/app/routes/auth.login.tsx @@ -28,7 +28,7 @@ export const loader = async ({ request }: LoaderFunctionArgs) => { // 未ログインの場合 // エラーメッセージを取得 - const data = { error: session.get('loginError') }; + const data = { error: session.get('error') }; return json(data, { headers: { @@ -51,8 +51,8 @@ export const action = async ({ request }: ActionFunctionArgs) => { if (response.status === 200) { session.set('userId', response.data.id.toString()); session.set('sessionToken', response.data.sessionToken!); - // FIXME: ログアウト時に表示できないのでログイン時も表示しない - // session.flash('loginSuccess', 'ログインに成功しました'); + // FIXME: homeのloaderで読み出してもCookieが削除されない + session.flash('success', 'ログインに成功しました'); return redirect('/home/mypage', { headers: { @@ -65,26 +65,25 @@ export const action = async ({ request }: ActionFunctionArgs) => { switch (response.status) { case 400: // prettier-ignore - session.flash('loginError', 'メールアドレスまたはパスワードが間違っています'); + session.flash('error', 'メールアドレスまたはパスワードが間違っています'); break; case 401: // prettier-ignore - session.flash('loginError', 'メールアドレスまたはパスワードが間違っています'); + session.flash('error', 'メールアドレスまたはパスワードが間違っています'); break; case 404: - session.flash('loginError', 'ユーザーが見つかりません'); + session.flash('error', 'ユーザーが見つかりません'); break; case 500: - session.flash('loginError', 'サーバーエラーが発生しました'); + session.flash('error', 'サーバーエラーが発生しました'); break; default: - session.flash('loginError', 'エラーが発生しました'); + session.flash('error', 'エラーが発生しました'); } - const setCookie = await commitSession(session); return redirect('/auth/login', { headers: { - 'Set-Cookie': setCookie, + 'Set-Cookie': await commitSession(session), }, }); }; diff --git a/frontend/app/routes/home._index.tsx b/frontend/app/routes/home._index.tsx index abdf47be..e69e1fef 100644 --- a/frontend/app/routes/home._index.tsx +++ b/frontend/app/routes/home._index.tsx @@ -8,9 +8,7 @@ import { GetBooksParams } from 'client/client.schemas'; import { useAtom } from 'jotai'; import { useEffect } from 'react'; import BookListComponent from '~/components/books/BookListComponent'; -import { commitSession, getSession } from '~/services/session.server'; import { selectedBooksAtom } from '~/stores/cartAtom'; -import { errorNotification, successNotification } from '~/utils/notification'; interface LoaderData { booksResponse: getBooksResponse; @@ -22,10 +20,6 @@ interface LoaderData { page?: string; limit?: string; }; - flash: { - success?: string; - error?: string; - }; } export const loader = async ({ request }: LoaderFunctionArgs) => { @@ -47,40 +41,22 @@ export const loader = async ({ request }: LoaderFunctionArgs) => { limit: limit, }); - const session = await getSession(request.headers.get('Cookie')); - - // flashメッセージを取得する - const success = session.get('deleteBookSuccess'); - const error = session.get('deleteBookError'); - - return json( - { - booksResponse: response, - condition: { - title: title, - author: auther, - publisher: publisher, - isbn: isbn, - page: page, - limit: limit, - }, - flash: { - success: success, - error: error, - }, - }, - { - headers: { - 'Set-Cookie': await commitSession(session), - }, + return json({ + booksResponse: response, + condition: { + title: title, + author: auther, + publisher: publisher, + isbn: isbn, + page: page, + limit: limit, }, - ); + }); }; const BooKListPage = () => { - const { booksResponse, condition, flash } = useLoaderData(); + const { booksResponse, condition } = useLoaderData(); const { title, author, publisher, isbn, page, limit } = condition; - const { success, error } = flash; const [opened, { open, close }] = useDisclosure(); const navigate = useNavigate(); @@ -96,13 +72,6 @@ const BooKListPage = () => { }); useEffect(() => { - // flashメッセージを表示する - if (success) { - successNotification(success); - } else if (error) { - errorNotification(error); - } - // 選択中の書籍をリセットする setSelectedBook([]); }, []); diff --git a/frontend/app/routes/home.books.$bookId.tsx b/frontend/app/routes/home.books.$bookId.tsx index 4f663837..4bd5385d 100644 --- a/frontend/app/routes/home.books.$bookId.tsx +++ b/frontend/app/routes/home.books.$bookId.tsx @@ -58,7 +58,7 @@ export const action = async ({ request }: ActionFunctionArgs) => { // 未ログインの場合 if (!session.has('userId')) { - session.flash('loginError', 'ログインしてください'); + session.flash('error', 'ログインしてください'); return redirect('/auth/login', { headers: { 'Set-Cookie': await commitSession(session), @@ -80,28 +80,28 @@ export const action = async ({ request }: ActionFunctionArgs) => { }); switch (response.status) { case 204: - session.flash('deleteBookSuccess', '削除しました'); + session.flash('success', '削除しました'); return redirect('/home', { headers: { 'Set-Cookie': await commitSession(session), }, }); case 401: - session.flash('loginError', 'ログインしてください'); + session.flash('error', 'ログインしてください'); return redirect('/auth/login', { headers: { 'Set-Cookie': await commitSession(session), }, }); case 404: - session.flash('deleteBookError', '書籍が見つかりませんでした'); + session.flash('error', '書籍が見つかりませんでした'); return redirect('/home', { headers: { 'Set-Cookie': await commitSession(session), }, }); case 500: - session.flash('deleteBookError', 'サーバーエラーが発生しました'); + session.flash('error', 'サーバーエラーが発生しました'); return json( { method: 'DELETE', status: 500 }, { diff --git a/frontend/app/routes/home.tsx b/frontend/app/routes/home.tsx index 07ee8677..469f90bd 100644 --- a/frontend/app/routes/home.tsx +++ b/frontend/app/routes/home.tsx @@ -10,25 +10,28 @@ import { getUser, logout } from 'client/client'; import { useAtom } from 'jotai'; import { useEffect } from 'react'; import HeaderComponent from '~/components/header/HeaderComponent'; -import { - commitSession, - destroySession, - getSession, -} from '~/services/session.server'; +import { commitSession, getSession } from '~/services/session.server'; import { userAtom } from '~/stores/userAtom'; +import { errorNotification, successNotification } from '~/utils/notification'; interface LoaderData { userId?: string; + success?: string; + error?: string; } export const loader = async ({ request }: LoaderFunctionArgs) => { const session = await getSession(request.headers.get('Cookie')); const userId = session.get('userId'); + const success = session.get('success'); + const error = session.get('error'); return json( { userId: userId, + success: success, + error: error, }, { headers: { @@ -51,24 +54,26 @@ export const action = async ({ request }: ActionFunctionArgs) => { if (response.status === 204) { session.unset('userId'); session.unset('sessionToken'); - // FIXME: loaderで読み出しても削除されない - // session.flash('logoutSuccess', 'ログアウトに成功しました'); + session.flash('success', 'ログアウトに成功しました'); return redirect('/home', { headers: { - 'Set-Cookie': await destroySession(session), + 'Set-Cookie': await commitSession(session), }, }); } else { - // FIXME: loaderで読み出しても削除されない - // session.flash('logoutError', 'ログアウトに失敗しました'); + session.flash('error', 'ログアウトに失敗しました'); - return redirect('/home'); + return redirect('/home', { + headers: { + 'Set-Cookie': await commitSession(session), + }, + }); } }; const Home = () => { - const { userId } = useLoaderData(); + const { userId, success, error } = useLoaderData(); const [user, setUser] = useAtom(userAtom); const navigation = useNavigation(); @@ -90,7 +95,19 @@ const Home = () => { setUser(undefined); } } - }, [navigation.state]); + }, [userId]); + + useEffect(() => { + if (success) { + successNotification(success); + } + }, [success]); + + useEffect(() => { + if (error) { + errorNotification(error); + } + }, [error]); return ( diff --git a/frontend/app/services/session.server.ts b/frontend/app/services/session.server.ts index 72150613..392baae1 100644 --- a/frontend/app/services/session.server.ts +++ b/frontend/app/services/session.server.ts @@ -6,15 +6,8 @@ interface SessionData { } interface SessionFlashData { - // ログイン - // loginSuccess: string; - loginError: string; - // ログアウト - // logoutSuccess: string; - // logoutError: string; - // 書籍の削除 - deleteBookSuccess: string; - deleteBookError: string; + success?: string; + error?: string; } const { getSession, commitSession, destroySession } = From 5c6ed03633977e81ccb7b053ec19cd7287923d8b Mon Sep 17 00:00:00 2001 From: shunsei Date: Thu, 31 Oct 2024 15:06:44 +0900 Subject: [PATCH 3/4] Remove FIXME comment (#105) --- frontend/app/routes/auth.login.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/frontend/app/routes/auth.login.tsx b/frontend/app/routes/auth.login.tsx index fe0fdc8d..2bf8d6f3 100644 --- a/frontend/app/routes/auth.login.tsx +++ b/frontend/app/routes/auth.login.tsx @@ -51,7 +51,6 @@ export const action = async ({ request }: ActionFunctionArgs) => { if (response.status === 200) { session.set('userId', response.data.id.toString()); session.set('sessionToken', response.data.sessionToken!); - // FIXME: homeのloaderで読み出してもCookieが削除されない session.flash('success', 'ログインに成功しました'); return redirect('/home/mypage', { From 892b13430e7602d313b31c22ade664617b0d62a6 Mon Sep 17 00:00:00 2001 From: shunsei Date: Thu, 31 Oct 2024 15:07:24 +0900 Subject: [PATCH 4/4] Revalidate after show notification (#105) --- frontend/app/routes/home.tsx | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/frontend/app/routes/home.tsx b/frontend/app/routes/home.tsx index 469f90bd..8180c61a 100644 --- a/frontend/app/routes/home.tsx +++ b/frontend/app/routes/home.tsx @@ -5,7 +5,12 @@ import { LoaderFunctionArgs, redirect, } from '@remix-run/cloudflare'; -import { Outlet, useLoaderData, useNavigation } from '@remix-run/react'; +import { + Outlet, + useLoaderData, + useNavigation, + useRevalidator, +} from '@remix-run/react'; import { getUser, logout } from 'client/client'; import { useAtom } from 'jotai'; import { useEffect } from 'react'; @@ -77,6 +82,7 @@ const Home = () => { const [user, setUser] = useAtom(userAtom); const navigation = useNavigation(); + const revalidator = useRevalidator(); useEffect(() => { if (navigation.state === 'idle') { @@ -100,12 +106,14 @@ const Home = () => { useEffect(() => { if (success) { successNotification(success); + revalidator.revalidate(); } }, [success]); useEffect(() => { if (error) { errorNotification(error); + revalidator.revalidate(); } }, [error]);