From 182d86eef2379861216de5bf1b6f8b9118f61544 Mon Sep 17 00:00:00 2001
From: Jeongmin Lee
Date: Mon, 7 Oct 2024 06:01:33 +0900
Subject: [PATCH 1/6] =?UTF-8?q?=E2=9C=A8=20feat:=20=EB=B6=81=EB=A7=88?=
=?UTF-8?q?=ED=81=AC=20=EA=B4=80=EB=A0=A8=20api,=20type,=20keys=20?=
=?UTF-8?q?=EC=BD=94=EB=93=9C=20=EA=B5=AC=ED=98=84=20#52?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/apis/user/bookmarks/bookmarks.ts | 24 +++++++++++++++++++++
src/apis/user/bookmarks/bookmarksKeys.ts | 7 ++++++
src/apis/user/bookmarks/bookmarksType.ts | 27 ++++++++++++++++++++++++
3 files changed, 58 insertions(+)
create mode 100644 src/apis/user/bookmarks/bookmarks.ts
create mode 100644 src/apis/user/bookmarks/bookmarksKeys.ts
create mode 100644 src/apis/user/bookmarks/bookmarksType.ts
diff --git a/src/apis/user/bookmarks/bookmarks.ts b/src/apis/user/bookmarks/bookmarks.ts
new file mode 100644
index 0000000..d51e7ed
--- /dev/null
+++ b/src/apis/user/bookmarks/bookmarks.ts
@@ -0,0 +1,24 @@
+import instance from "@/apis/instance";
+import { FIESTA_ENDPOINTS } from "@/config";
+import { generateUrlWithParams } from "@/utils";
+
+import { BookmarkFestivalParameter, BookmarksResponse } from "./bookmarksType";
+
+const defaultParameter: BookmarkFestivalParameter = {
+ page: 0,
+ size: 6,
+};
+
+export const getBookmarkedFestival = async (
+ params: BookmarkFestivalParameter = defaultParameter,
+) => {
+ const endpoint = FIESTA_ENDPOINTS.users.bookmarks;
+ const { data } = await instance.get(
+ generateUrlWithParams(endpoint, params),
+ {
+ cache: "no-store",
+ },
+ );
+
+ return data;
+};
diff --git a/src/apis/user/bookmarks/bookmarksKeys.ts b/src/apis/user/bookmarks/bookmarksKeys.ts
new file mode 100644
index 0000000..cb4fbdb
--- /dev/null
+++ b/src/apis/user/bookmarks/bookmarksKeys.ts
@@ -0,0 +1,7 @@
+import { BookmarkFestivalParameter } from "./bookmarksType";
+
+export const bookmarksKeys = {
+ all: ["bookmarks"] as const,
+ list: (params: BookmarkFestivalParameter) =>
+ [...bookmarksKeys.all, params] as const,
+};
diff --git a/src/apis/user/bookmarks/bookmarksType.ts b/src/apis/user/bookmarks/bookmarksType.ts
new file mode 100644
index 0000000..8994b18
--- /dev/null
+++ b/src/apis/user/bookmarks/bookmarksType.ts
@@ -0,0 +1,27 @@
+import { SortOption } from "@/apis/review/reviews/reviewsType";
+
+export type BookmarksResponse = {
+ content: Array;
+ offset: number;
+ pageNumber: number;
+ pageSize: number;
+ totalElements: number;
+ totalPages: number;
+};
+
+export type BookmarkFestivalParameter = {
+ page?: number;
+ size?: number;
+ sort?: SortOption;
+};
+
+export type BookmarkedFestival = {
+ festivalId: number;
+ name: string;
+ thumbnailImage: string;
+ sido: string;
+ sigungu: string;
+ startDate: string;
+ endDate: string;
+ isBookmarked: boolean;
+};
From 40dc2c2d888e585e00b3a49befb5796ee182412a Mon Sep 17 00:00:00 2001
From: Jeongmin Lee
Date: Mon, 7 Oct 2024 06:18:38 +0900
Subject: [PATCH 2/6] =?UTF-8?q?=E2=9C=A8=20feat:=20mypage=20=EB=B6=81?=
=?UTF-8?q?=EB=A7=88=ED=81=AC=20API=20=EC=97=B0=EB=8F=99=20=EB=B0=8F=20use?=
=?UTF-8?q?OptimisticMutation=20=EA=B5=AC=ED=98=84=20#52?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/apis/review/reviews/reviewsType.ts | 3 +-
.../TotalReviews/TotalReviewListItem.tsx | 2 +-
.../_components/Bookmark/MyPageScrab.tsx | 106 ++++++++++++++++++
.../MypageBookmarkFallback.tsx} | 6 +-
.../Bookmark/MypageBookmarkSkeleton.tsx | 19 ++++
src/app/mypage/_components/MypageTab.tsx | 10 +-
src/hooks/useOptimisticMutation.ts | 64 +++++++++++
7 files changed, 199 insertions(+), 11 deletions(-)
create mode 100644 src/app/mypage/_components/Bookmark/MyPageScrab.tsx
rename src/app/mypage/_components/{MypageFallback.tsx => Bookmark/MypageBookmarkFallback.tsx} (57%)
create mode 100644 src/app/mypage/_components/Bookmark/MypageBookmarkSkeleton.tsx
create mode 100644 src/hooks/useOptimisticMutation.ts
diff --git a/src/apis/review/reviews/reviewsType.ts b/src/apis/review/reviews/reviewsType.ts
index 1ba3260..ab0a3ad 100644
--- a/src/apis/review/reviews/reviewsType.ts
+++ b/src/apis/review/reviews/reviewsType.ts
@@ -1,6 +1,6 @@
export type FestivalReviewsParameters = {
festivalId?: number | string;
- sort?: "createdAt" | "likeCount";
+ sort?: SortOption;
page?: number;
size?: number;
};
@@ -47,6 +47,7 @@ export interface Keyword {
export enum SortOption {
createdAt = "createdAt",
likeCount = "likeCount",
+ desc = "desc",
}
export type PostReviewResponse = {
diff --git a/src/app/(home)/festivals/[festivalId]/_components/DetailFestivalTab/Review/_components/TotalReviews/TotalReviewListItem.tsx b/src/app/(home)/festivals/[festivalId]/_components/DetailFestivalTab/Review/_components/TotalReviews/TotalReviewListItem.tsx
index 599e14d..51266ba 100644
--- a/src/app/(home)/festivals/[festivalId]/_components/DetailFestivalTab/Review/_components/TotalReviews/TotalReviewListItem.tsx
+++ b/src/app/(home)/festivals/[festivalId]/_components/DetailFestivalTab/Review/_components/TotalReviews/TotalReviewListItem.tsx
@@ -128,7 +128,7 @@ const TotalReviewListItem: FC = ({ review }) => {
- {review.keywords.splice(0, 2).map((keyword) => (
+ {review.keywords.map((keyword) => (
))}
diff --git a/src/app/mypage/_components/Bookmark/MyPageScrab.tsx b/src/app/mypage/_components/Bookmark/MyPageScrab.tsx
new file mode 100644
index 0000000..5d20c90
--- /dev/null
+++ b/src/app/mypage/_components/Bookmark/MyPageScrab.tsx
@@ -0,0 +1,106 @@
+import { useQuery, useQueryClient } from "@tanstack/react-query";
+import { FC, useRef, useState } from "react";
+
+import { patchBookmarkFestival } from "@/apis/festivals/bookmarkFestival/bookmarkFestival";
+import { SortOption } from "@/apis/review/reviews/reviewsType";
+import { getBookmarkedFestival } from "@/apis/user/bookmarks/bookmarks";
+import { bookmarksKeys } from "@/apis/user/bookmarks/bookmarksKeys";
+import {
+ BookmarkFestivalParameter,
+ BookmarksResponse,
+} from "@/apis/user/bookmarks/bookmarksType";
+import { TrendFestivalCard } from "@/components/core/Card";
+import ClientPagination from "@/components/Pagination/ClientPagination";
+import { useOptimisticMutation } from "@/hooks/useOptimisticMutation";
+
+import MypageBookmarkFallback from "./MypageBookmarkFallback";
+import MypageBookmarkSkeleton from "./MypageBookmarkSkeleton";
+
+interface Props {}
+
+const MypageBookmark: FC
= ({}) => {
+ const containerRef = useRef(null);
+ const queryClient = useQueryClient();
+
+ const [params, setParams] = useState({
+ sort: SortOption.createdAt,
+ page: 0,
+ size: 6,
+ });
+
+ const { data, isLoading } = useQuery({
+ queryKey: bookmarksKeys.list(params),
+ queryFn: () => getBookmarkedFestival(params),
+ });
+
+ const { mutate: toggleBookmark } = useOptimisticMutation({
+ mutationFn: patchBookmarkFestival,
+ queryKey: bookmarksKeys.list(params),
+ onMutate: async (festivalId) => {
+ await queryClient.cancelQueries({
+ queryKey: bookmarksKeys.list(params),
+ });
+
+ const previousBookmarkData = queryClient.getQueryData(
+ bookmarksKeys.list(params),
+ );
+
+ queryClient.setQueryData(
+ bookmarksKeys.list(params),
+ (oldQueryData: BookmarksResponse) => ({
+ ...oldQueryData,
+ content: oldQueryData.content.filter(
+ (c: { festivalId: number }) => c.festivalId !== festivalId,
+ ),
+ }),
+ );
+ return previousBookmarkData;
+ },
+ });
+
+ const handlePage = (page: number) => {
+ setParams((prev) => ({ ...prev, page }));
+
+ if (containerRef.current) {
+ containerRef.current.scrollIntoView({ behavior: "smooth" });
+ }
+ };
+
+ if (isLoading) {
+ return ;
+ }
+
+ if (data?.content.length === 0 || !data) {
+ return ;
+ }
+
+ return (
+
+
+ {data.totalElements}개의 페스티벌
+
+
+
+ {data.content?.map((festival, index) => (
+ toggleBookmark(festival.festivalId)}
+ />
+ ))}
+
+
+
+
+ );
+};
+
+export default MypageBookmark;
diff --git a/src/app/mypage/_components/MypageFallback.tsx b/src/app/mypage/_components/Bookmark/MypageBookmarkFallback.tsx
similarity index 57%
rename from src/app/mypage/_components/MypageFallback.tsx
rename to src/app/mypage/_components/Bookmark/MypageBookmarkFallback.tsx
index f349be2..4c48b43 100644
--- a/src/app/mypage/_components/MypageFallback.tsx
+++ b/src/app/mypage/_components/Bookmark/MypageBookmarkFallback.tsx
@@ -1,8 +1,8 @@
import Image from "next/image";
-const MypageFallback = () => {
+const MypageBookmarkFallback = () => {
return (
-
+
{
);
};
-export default MypageFallback;
+export default MypageBookmarkFallback;
diff --git a/src/app/mypage/_components/Bookmark/MypageBookmarkSkeleton.tsx b/src/app/mypage/_components/Bookmark/MypageBookmarkSkeleton.tsx
new file mode 100644
index 0000000..449531f
--- /dev/null
+++ b/src/app/mypage/_components/Bookmark/MypageBookmarkSkeleton.tsx
@@ -0,0 +1,19 @@
+const MypageBookmarkSkeleton = () => {
+ return (
+
+
+
+ {Array.from({ length: 6 }).map((_, idx) => (
+
+ ))}
+
+
+
Loading...
+
+ );
+};
+
+export default MypageBookmarkSkeleton;
diff --git a/src/app/mypage/_components/MypageTab.tsx b/src/app/mypage/_components/MypageTab.tsx
index 913e129..f537904 100644
--- a/src/app/mypage/_components/MypageTab.tsx
+++ b/src/app/mypage/_components/MypageTab.tsx
@@ -3,13 +3,15 @@
import * as Tabs from "@radix-ui/react-tabs";
import { FC } from "react";
+import MypageBookmark from "./Bookmark/MyPageScrab";
+
interface Props {}
const MypageTab: FC = ({}) => {
const TabList = [
{
name: "스크랩",
- contentComponent: 스크랩
,
+ contentComponent: ,
},
{
name: "활동뱃지",
@@ -26,11 +28,7 @@ const MypageTab: FC = ({}) => {
return (
-
+
{TabList.map(({ name }, index) => (
{
+ mutationFn: (variables: TVariables) => Promise;
+ queryKey: QueryKey;
+ onMutate?: (variables: TVariables) => Promise;
+ setQueryData?: (data: TData) => void;
+ onError?: (error: DefaultError, variables: TVariables) => void;
+ onSettled?: (
+ data: TData | undefined,
+ error: DefaultError | null,
+ variables: TVariables,
+ context: { context: unknown } | undefined,
+ ) => void;
+}
+
+export const useOptimisticMutation = ({
+ mutationFn,
+ queryKey,
+ onMutate,
+ setQueryData,
+ onError,
+ onSettled,
+}: UseOptimisticMutationProps) => {
+ const queryClient = useQueryClient();
+
+ const { mutate } = useMutation({
+ mutationFn,
+ onMutate: async (variables) => {
+ await queryClient.cancelQueries({ queryKey });
+ const context = queryClient.getQueryData(queryKey);
+
+ if (onMutate) {
+ const newData = await onMutate(variables);
+ queryClient.setQueryData(queryKey, newData);
+ } else {
+ queryClient.setQueryData(queryKey, setQueryData);
+ }
+
+ return { context };
+ },
+ onError: (error, variables, context) => {
+ if (onError) {
+ onError(error, variables);
+ }
+ queryClient.setQueryData(queryKey, context?.context);
+ },
+ onSettled: (data, error, variables, context) => {
+ if (onSettled) {
+ onSettled(data, error, variables, context);
+ }
+ queryClient.invalidateQueries({ queryKey });
+ },
+ });
+
+ return {
+ mutate,
+ };
+};
From 69c0eb6f810723cefc810a5114cf2c2fe49c0e1c Mon Sep 17 00:00:00 2001
From: Jeongmin Lee
Date: Mon, 7 Oct 2024 06:19:47 +0900
Subject: [PATCH 3/6] =?UTF-8?q?=E2=9C=A8=20feat:=20=EC=84=B8=EC=85=98=20?=
=?UTF-8?q?=EA=B4=80=EB=A0=A8=20=EB=A1=9C=EC=A7=81=20=EC=88=98=EC=A0=95=20?=
=?UTF-8?q?#52?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
auth.ts | 2 +
src/apis/instance.ts | 8 +-
src/app/layout.tsx | 7 +-
.../core/Button/BookingButton/ScrabButton.tsx | 51 ++++-------
.../TrendFestivalCard/TrendFestivalCard.tsx | 90 ++++++++++++-------
.../session/useInitializeUserProfile.tsx | 19 ++--
src/hooks/session/useUpdateUserSession.tsx | 11 +--
src/lib/Providers/SessionProvider.tsx | 8 +-
src/lib/session.ts | 6 ++
src/middleware.ts | 30 ++++++-
10 files changed, 132 insertions(+), 100 deletions(-)
create mode 100644 src/lib/session.ts
diff --git a/auth.ts b/auth.ts
index 8cea58d..df3c19b 100644
--- a/auth.ts
+++ b/auth.ts
@@ -64,6 +64,8 @@ export const { handlers, auth, signIn, signOut, unstable_update } = NextAuth({
if (params.trigger === "update") {
params.token = {
...params.token,
+ userTypeId: params.session.user.userTypeId,
+ isProfileRegistered: params.session.user.isProfileRegistered,
};
}
diff --git a/src/apis/instance.ts b/src/apis/instance.ts
index 8e55e66..6b1d7cd 100644
--- a/src/apis/instance.ts
+++ b/src/apis/instance.ts
@@ -1,5 +1,6 @@
import { Session } from "next-auth";
-import { getSession } from "next-auth/react";
+
+import { getClientSideSession } from "@/lib/session";
import { env } from "../env";
import { getServerSideSession } from "./auth/auth";
@@ -22,11 +23,6 @@ export interface FiestaResponse {
data: T;
}
-export async function getClientSideSession() {
- const session = await getSession();
- return session;
-}
-
export type FiestaFetchOptions = Omit;
export class CreateFiestaFetch {
diff --git a/src/app/layout.tsx b/src/app/layout.tsx
index 5483d5e..5f1fc3f 100644
--- a/src/app/layout.tsx
+++ b/src/app/layout.tsx
@@ -5,6 +5,7 @@ import type { Metadata } from "next";
import Script from "next/script";
import { ReactNode } from "react";
+import { auth } from "@/auth";
import { env } from "@/env";
import MobileLayout from "@/layout/Mobile/MobileLayout";
import {
@@ -21,15 +22,17 @@ export const metadata: Metadata = {
description: "Generated by create next app",
};
-export default function RootLayout({
+export default async function RootLayout({
children,
}: Readonly<{
children: ReactNode;
}>) {
+ const session = await auth();
+
return (
-
+
diff --git a/src/components/core/Button/BookingButton/ScrabButton.tsx b/src/components/core/Button/BookingButton/ScrabButton.tsx
index 38d3cbf..754bb26 100644
--- a/src/components/core/Button/BookingButton/ScrabButton.tsx
+++ b/src/components/core/Button/BookingButton/ScrabButton.tsx
@@ -1,6 +1,6 @@
"use client";
-import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
+import { useQuery, useQueryClient } from "@tanstack/react-query";
import { Session } from "next-auth";
import { FC, useState } from "react";
@@ -8,8 +8,10 @@ import { getFestivalBookmark } from "@/apis/festivals/bookmarkCountFestival/book
import { BookmarkCountFestivalKeys } from "@/apis/festivals/bookmarkCountFestival/bookmarkCountFestivalKeys";
import { patchBookmarkFestival } from "@/apis/festivals/bookmarkFestival/bookmarkFestival";
import { DetailFestivalResponse } from "@/apis/festivals/detailFestival/detailFestivalType";
+import { bookmarksKeys } from "@/apis/user/bookmarks/bookmarksKeys";
import LoginRequiredDialog from "@/components/Dialog/LoginRequiredDialog/LoginRequiredDialog";
import { ScrabIcon } from "@/components/icons";
+import { useOptimisticMutation } from "@/hooks/useOptimisticMutation";
interface Props {
festival: DetailFestivalResponse;
@@ -24,44 +26,23 @@ const ScrabButton: FC = ({ festival, session }) => {
const queryClient = useQueryClient();
- const { mutate: toggleScrab } = useMutation({
+ const { mutate: toggleScrab } = useOptimisticMutation({
mutationFn: patchBookmarkFestival,
- onMutate: async (festivalId) => {
- await queryClient.cancelQueries({
- queryKey: BookmarkCountFestivalKeys.byId(festival.festivalId),
- });
-
- const previousBookmarkData = queryClient.getQueryData(
- BookmarkCountFestivalKeys.byId(festival.festivalId),
- );
-
- queryClient.setQueryData(
- BookmarkCountFestivalKeys.byId(festival.festivalId),
- (
- oldQueryData: Pick<
- DetailFestivalResponse,
- "bookmarkCount" | "isBookmarked"
- >,
- ) => {
- return {
- isBookmarked: !oldQueryData.isBookmarked,
- bookmarkCount: !oldQueryData.isBookmarked
- ? oldQueryData.bookmarkCount + 1
- : oldQueryData.bookmarkCount - 1,
- };
- },
- );
- return previousBookmarkData;
- },
- onError: (_error, _toggle, context) =>
- queryClient.setQueryData(
- BookmarkCountFestivalKeys.byId(festival.festivalId),
- context,
- ),
- onSettled: () =>
+ queryKey: BookmarkCountFestivalKeys.byId(festival.festivalId),
+ setQueryData: (data) => ({
+ isBookmarked: !data.isBookmarked,
+ bookmarkCount: !data.isBookmarked
+ ? data.bookmarkCount + 1
+ : data.bookmarkCount - 1,
+ }),
+ onSettled: () => {
queryClient.invalidateQueries({
queryKey: BookmarkCountFestivalKeys.byId(festival.festivalId),
}),
+ queryClient.invalidateQueries({
+ queryKey: bookmarksKeys.all,
+ });
+ },
});
const [isOpen, setIsOpen] = useState(false);
diff --git a/src/components/core/Card/TrendFestivalCard/TrendFestivalCard.tsx b/src/components/core/Card/TrendFestivalCard/TrendFestivalCard.tsx
index f153083..092a02b 100644
--- a/src/components/core/Card/TrendFestivalCard/TrendFestivalCard.tsx
+++ b/src/components/core/Card/TrendFestivalCard/TrendFestivalCard.tsx
@@ -1,51 +1,79 @@
import Image from "next/image";
import Link, { LinkProps } from "next/link";
-import { FC } from "react";
+import { FC, MouseEvent } from "react";
import { FestivalListModel } from "@/apis/festivals/hotFestival/hotFestivalType";
import { DateTag } from "@/components/core/Tag";
+import { ScrabIcon } from "@/components/icons";
import { formatToKoreanDate, getDday } from "@/lib/dayjs";
+import { cn } from "@/utils";
+
+import { IconButton } from "../../Button";
export interface TrendFestivalCardProps extends LinkProps {
festival: FestivalListModel;
+ isBookmarkAvailable?: boolean;
+ isBookmarked?: boolean;
+ onToggle?: () => void;
}
const TrendFestivalCard: FC = ({
festival,
+ isBookmarkAvailable,
+ isBookmarked,
+ onToggle,
...props
}) => {
+ const handleIconButtonClick = (event: MouseEvent) => {
+ event.stopPropagation();
+ onToggle && onToggle();
+ };
return (
-
-
-
-
-
+
+
+
+
+
+
-
-
- {festival.sido + festival.sigungu}
-
-
- {festival.name}
-
-
- {`${formatToKoreanDate(festival.startDate)} - ${formatToKoreanDate(festival.endDate)}`}
-
-
-
+
+
+ {festival.sido + festival.sigungu}
+
+
+ {festival.name}
+
+
+ {`${formatToKoreanDate(festival.startDate)} - ${formatToKoreanDate(festival.endDate)}`}
+
+
+
+ {isBookmarkAvailable && (
+
+
+
+ )}
+
);
};
diff --git a/src/hooks/session/useInitializeUserProfile.tsx b/src/hooks/session/useInitializeUserProfile.tsx
index 86fbabe..4e2c992 100644
--- a/src/hooks/session/useInitializeUserProfile.tsx
+++ b/src/hooks/session/useInitializeUserProfile.tsx
@@ -1,24 +1,17 @@
+import { Session } from "next-auth";
import { useEffect } from "react";
-import { getClientSideSession } from "@/apis/instance";
import { useUserStore } from "@/store/user";
-import { log } from "@/utils";
-const useInitializeUserProfile = () => {
+const useInitializeUserProfile = (session: Session | null) => {
const setUser = useUserStore((state) => state.updateUser);
const initializeUserProfile = async () => {
- try {
- const session = await getClientSideSession();
-
- if (session) {
- const { user } = session;
- return setUser(user);
- }
- setUser(null);
- } catch (error) {
- log(error);
+ if (session) {
+ const { user } = session;
+ return setUser(user);
}
+ setUser(null);
};
useEffect(() => {
diff --git a/src/hooks/session/useUpdateUserSession.tsx b/src/hooks/session/useUpdateUserSession.tsx
index 8540341..c80c9e0 100644
--- a/src/hooks/session/useUpdateUserSession.tsx
+++ b/src/hooks/session/useUpdateUserSession.tsx
@@ -1,26 +1,23 @@
"use client";
import { useSearchParams } from "next/navigation";
+import { useSession } from "next-auth/react";
import { useEffect } from "react";
-import { getClientSideSession } from "@/apis/instance";
-import { updateAuthSession } from "@/lib/updateAuthSession";
import { useUserStore } from "@/store/user";
const useUpdateUserSession = () => {
const searchParams = useSearchParams();
const setUser = useUserStore((state) => state.updateUser);
+ const { data: session, update } = useSession();
const handleSessionUpdate = async () => {
try {
- const session = await getClientSideSession();
-
if (session) {
session.user.userTypeId = Number(searchParams.get("userTypeId"));
session.user.isProfileRegistered = true;
- const newSession = await updateAuthSession(session);
-
- setUser(newSession.user);
+ await update(session);
+ setUser(session.user ?? null);
}
} catch (error) {
console.error("Failed to update session:", error);
diff --git a/src/lib/Providers/SessionProvider.tsx b/src/lib/Providers/SessionProvider.tsx
index 1fc8479..7fb1099 100644
--- a/src/lib/Providers/SessionProvider.tsx
+++ b/src/lib/Providers/SessionProvider.tsx
@@ -1,5 +1,6 @@
"use client";
+import { Session } from "next-auth";
import { SessionProvider as AuthProvider } from "next-auth/react";
import { FC } from "react";
@@ -7,11 +8,12 @@ import useInitializeUserProfile from "@/hooks/session/useInitializeUserProfile";
interface Props {
children: React.ReactNode;
+ session: Session | null;
}
-const SessionProvider: FC = ({ children }) => {
- useInitializeUserProfile();
- return {children};
+const SessionProvider: FC = ({ children, session }) => {
+ useInitializeUserProfile(session);
+ return {children};
};
export default SessionProvider;
diff --git a/src/lib/session.ts b/src/lib/session.ts
new file mode 100644
index 0000000..80a6c92
--- /dev/null
+++ b/src/lib/session.ts
@@ -0,0 +1,6 @@
+import { getSession } from "next-auth/react";
+
+export async function getClientSideSession() {
+ const session = await getSession();
+ return session;
+}
diff --git a/src/middleware.ts b/src/middleware.ts
index 1df27ab..00a3644 100644
--- a/src/middleware.ts
+++ b/src/middleware.ts
@@ -2,7 +2,10 @@ import type { NextRequest } from "next/server";
import { NextResponse } from "next/server";
import { match } from "path-to-regexp";
-import { getServerSideSession } from "./apis/auth/auth";
+import { getRefreshToken, getServerSideSession } from "./apis/auth/auth";
+import { decodeToken } from "./lib/jwt";
+import { updateAuthSession } from "./lib/updateAuthSession";
+import { log } from "./utils";
const serviceReadyRoute = ["/chat", "/map", "/calander"];
const matchersForAuth = ["/mypage"];
@@ -14,10 +17,31 @@ export async function middleware(request: NextRequest) {
return NextResponse.redirect(new URL("/", request.url));
}
+ const session = await getServerSideSession();
+
+ if (session) {
+ if (
+ session.refreshToken &&
+ session.exp &&
+ session.exp * 1000 < Date.now()
+ ) {
+ log("******** token Expired ....");
+ const { accessToken, refreshToken } = await getRefreshToken(
+ session.refreshToken,
+ );
+
+ const decodedJWT = decodeToken(accessToken);
+
+ session.accessToken = accessToken;
+ session.refreshToken = refreshToken;
+ session.exp = decodedJWT?.exp;
+ await updateAuthSession(session);
+ log("******** token updated ....");
+ }
+ }
+
// * 인증이 필요한 페이지 접근 제어!
if (isMatch(request.nextUrl.pathname, matchersForAuth)) {
- const session = await getServerSideSession();
-
if (!!session && !session.user.isProfileRegistered) {
return NextResponse.redirect(new URL("/onboarding", request.url));
}
From bd678fce02b1b0d8765e91ba3e30d07ca05e3243 Mon Sep 17 00:00:00 2001
From: Jeongmin Lee
Date: Mon, 7 Oct 2024 06:24:20 +0900
Subject: [PATCH 4/6] =?UTF-8?q?=F0=9F=90=9B=20fix:=20=EB=B9=8C=EB=93=9C?=
=?UTF-8?q?=EC=97=90=EB=9F=AC=EC=88=98=EC=A0=95=20#52?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../festivals/new/_components/CreateFestivalSecondStep.tsx | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/src/app/(home)/festivals/new/_components/CreateFestivalSecondStep.tsx b/src/app/(home)/festivals/new/_components/CreateFestivalSecondStep.tsx
index 9a82723..10780e4 100644
--- a/src/app/(home)/festivals/new/_components/CreateFestivalSecondStep.tsx
+++ b/src/app/(home)/festivals/new/_components/CreateFestivalSecondStep.tsx
@@ -120,8 +120,9 @@ const CreateFestivalSecondStep: FC = ({ moods, categories }) => {
name="categoryIds"
render={({ field: { onChange, value } }) => (
)}
From c828740fb8e8ca5c6b38e11ac26a91aed76aee87 Mon Sep 17 00:00:00 2001
From: Jeongmin Lee
Date: Tue, 8 Oct 2024 02:28:17 +0900
Subject: [PATCH 5/6] =?UTF-8?q?=F0=9F=94=A7=20chore:=20refreshToken=20?=
=?UTF-8?q?=EC=A3=BC=EC=84=9D=20=EC=B2=98=EB=A6=AC?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/middleware.ts | 39 +++++++++++++++++----------------------
1 file changed, 17 insertions(+), 22 deletions(-)
diff --git a/src/middleware.ts b/src/middleware.ts
index 00a3644..b52b96f 100644
--- a/src/middleware.ts
+++ b/src/middleware.ts
@@ -2,10 +2,7 @@ import type { NextRequest } from "next/server";
import { NextResponse } from "next/server";
import { match } from "path-to-regexp";
-import { getRefreshToken, getServerSideSession } from "./apis/auth/auth";
-import { decodeToken } from "./lib/jwt";
-import { updateAuthSession } from "./lib/updateAuthSession";
-import { log } from "./utils";
+import { getServerSideSession } from "./apis/auth/auth";
const serviceReadyRoute = ["/chat", "/map", "/calander"];
const matchersForAuth = ["/mypage"];
@@ -19,26 +16,24 @@ export async function middleware(request: NextRequest) {
const session = await getServerSideSession();
- if (session) {
- if (
- session.refreshToken &&
- session.exp &&
- session.exp * 1000 < Date.now()
- ) {
- log("******** token Expired ....");
- const { accessToken, refreshToken } = await getRefreshToken(
- session.refreshToken,
- );
+ // if (session) {
+ // if (
+ // session.refreshToken &&
+ // session.exp &&
+ // session.exp * 1000 < Date.now()
+ // ) {
+ // const { accessToken, refreshToken } = await getRefreshToken(
+ // session.refreshToken,
+ // );
- const decodedJWT = decodeToken(accessToken);
+ // const decodedJWT = decodeToken(accessToken);
- session.accessToken = accessToken;
- session.refreshToken = refreshToken;
- session.exp = decodedJWT?.exp;
- await updateAuthSession(session);
- log("******** token updated ....");
- }
- }
+ // session.accessToken = accessToken;
+ // session.refreshToken = refreshToken;
+ // session.exp = decodedJWT?.exp;
+ // await updateAuthSession(session);
+ // }
+ // }
// * 인증이 필요한 페이지 접근 제어!
if (isMatch(request.nextUrl.pathname, matchersForAuth)) {
From 04f0bf7d925dfbd87414c77a64468ee0d4b06e59 Mon Sep 17 00:00:00 2001
From: Jeongmin Lee
Date: Tue, 8 Oct 2024 02:41:45 +0900
Subject: [PATCH 6/6] =?UTF-8?q?=E2=9C=A8=20feat:=20add=20error=20route=20o?=
=?UTF-8?q?n=20auth.ts?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
auth.ts | 1 +
1 file changed, 1 insertion(+)
diff --git a/auth.ts b/auth.ts
index df3c19b..1bf5db0 100644
--- a/auth.ts
+++ b/auth.ts
@@ -20,6 +20,7 @@ export const { handlers, auth, signIn, signOut, unstable_update } = NextAuth({
pages: {
signIn: "/auth/sign-in",
signOut: "/auth/sign-in",
+ error: "/auth/sign-in",
},
callbacks: {
async signIn() {