From 02885716060adda4b998e6056c397bd909805dc2 Mon Sep 17 00:00:00 2001
From: Jungu Lee <100949102+jobkaeHenry@users.noreply.github.com>
Date: Wed, 29 Nov 2023 03:41:24 +0900
Subject: [PATCH] =?UTF-8?q?=ED=94=84=EB=A1=9C=ED=95=84-=EC=84=B8=ED=8C=85?=
=?UTF-8?q?=ED=8E=98=EC=9D=B4=EC=A7=80-=ED=8D=BC=EB=B8=94=EB=A6=AC?=
=?UTF-8?q?=EC=8B=B1=20(#59)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* New : 술 태그 클릭시 해당 술정보로 이동
* Refactor : userInfo 카드 스켈레톤 추가
* New : 유저정보 페이지 URL 추가
* New : 로그아웃 (쿠키삭제) BFF URL추가
* New : 술 태그 클릭시 해당 술정보로 이동
* Minor : Wrapper 컴포넌트 추가
* New : 로그아웃 (쿠키삭제) route 추가
* New : 술 디테일 페이지 임시추가
* New : 프로필수정 모달 컨텍스트 추가
* Minor : App bar Sementic tag 추가
* Minor : 서버 응답 인터페이스 변경
* New : 프로필 세팅페이지 퍼블리싱
---
.../(protectedRoute)/user/setting/layout.tsx | 21 ++++
.../(protectedRoute)/user/setting/page.tsx | 100 ++++++++++++++++++
.../src/app/api/auth/logout-internal/route.ts | 17 +++
client/src/app/user/[userId]/layout.tsx | 21 ++--
client/src/app/wiki/[alcoholNo]/page.tsx | 11 ++
client/src/app/wiki/layout.tsx | 4 +-
client/src/components/CustomAppbar.tsx | 9 +-
client/src/components/post/PostCard.tsx | 9 +-
client/src/components/post/PostCardList.tsx | 42 ++++----
.../src/components/user/info/UserInfoCard.tsx | 22 +++-
.../user/info/UserInfoCardSkeleton.tsx | 23 ++++
client/src/components/wiki/AlcoholList.tsx | 10 +-
client/src/components/wiki/AlcoholNameTag.tsx | 18 +++-
client/src/const/clientPath.ts | 20 +++-
client/src/const/serverPath.ts | 4 +
client/src/store/user/UserPageContext.ts | 13 +++
client/src/types/post/PostInterface.ts | 4 +
17 files changed, 293 insertions(+), 55 deletions(-)
create mode 100644 client/src/app/(protectedRoute)/user/setting/layout.tsx
create mode 100644 client/src/app/(protectedRoute)/user/setting/page.tsx
create mode 100644 client/src/app/api/auth/logout-internal/route.ts
create mode 100644 client/src/app/wiki/[alcoholNo]/page.tsx
create mode 100644 client/src/components/user/info/UserInfoCardSkeleton.tsx
create mode 100644 client/src/store/user/UserPageContext.ts
diff --git a/client/src/app/(protectedRoute)/user/setting/layout.tsx b/client/src/app/(protectedRoute)/user/setting/layout.tsx
new file mode 100644
index 0000000..14fd8a7
--- /dev/null
+++ b/client/src/app/(protectedRoute)/user/setting/layout.tsx
@@ -0,0 +1,21 @@
+"use client";
+import CustomAppbar from "@/components/CustomAppbar";
+import { Container, Stack } from "@mui/material";
+import { ReactNode } from "react";
+
+type Props = {
+ children: ReactNode;
+};
+
+const UserInfoPageLayout = ({ children }: Props) => {
+ return (
+ <>
+
+
+ {children}
+
+ >
+ );
+};
+
+export default UserInfoPageLayout;
diff --git a/client/src/app/(protectedRoute)/user/setting/page.tsx b/client/src/app/(protectedRoute)/user/setting/page.tsx
new file mode 100644
index 0000000..528016b
--- /dev/null
+++ b/client/src/app/(protectedRoute)/user/setting/page.tsx
@@ -0,0 +1,100 @@
+"use client";
+
+import UserInfoCard from "@/components/user/info/UserInfoCard";
+import UserInfoCardSkeleton from "@/components/user/info/UserInfoCardSkeleton";
+import { useMyInfoQuery } from "@/queries/auth/useMyInfoQuery";
+import {
+ Button,
+ ButtonBase,
+ Paper,
+ Stack,
+ Typography,
+ styled,
+} from "@mui/material";
+import PostSeeMoreIcon from "@/assets/icons/PostSeeMoreIcon.svg";
+import { axiosBff } from "@/libs/axios";
+import { LOGOUT_BFF } from "@/const/serverPath";
+
+const SettingPage = () => {
+ const { data: myInfo } = useMyInfoQuery();
+
+ return (
+ <>
+
+ {myInfo ? (
+
+ ) : (
+
+ )}
+
+
+
+ 정보
+
+
+ 개인정보
+
+
+
+
+
+ 고객센터
+
+
+ 고객센터
+
+
+
+
+
+ Q&A
+
+
+
+
+
+ 사용자 의견 남기기
+
+
+
+
+
+ 투파이아
+
+ 버전
+ 1.0.0
+
+
+
+ 계정
+
+
+ >
+ );
+};
+const PaddingPaper = styled(Paper)(() => ({
+ padding: 16,
+ display: "flex",
+ flexDirection: "column",
+ gap: "16px",
+}));
+
+const RowStack = styled(Stack)(() => ({
+ width: "100%",
+ flexDirection: "row",
+ justifyContent: "space-between",
+ alignItems: "center",
+}));
+
+export default SettingPage;
diff --git a/client/src/app/api/auth/logout-internal/route.ts b/client/src/app/api/auth/logout-internal/route.ts
new file mode 100644
index 0000000..33d57c3
--- /dev/null
+++ b/client/src/app/api/auth/logout-internal/route.ts
@@ -0,0 +1,17 @@
+import { cookies } from "next/headers";
+import { NextRequest, NextResponse } from "next/server";
+
+export async function POST(request: NextRequest) {
+ cookies().delete("accessToken");
+ return NextResponse.json(
+ { message:'success'},
+ {
+ headers: {
+ "Access-Control-Allow-Origin": "*",
+ "Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS",
+ "Access-Control-Allow-Headers": "Content-Type, Authorization",
+ "Access-Control-Allow-Credentials": "true",
+ },
+ }
+ );
+}
\ No newline at end of file
diff --git a/client/src/app/user/[userId]/layout.tsx b/client/src/app/user/[userId]/layout.tsx
index 450b783..ad78e1f 100644
--- a/client/src/app/user/[userId]/layout.tsx
+++ b/client/src/app/user/[userId]/layout.tsx
@@ -1,8 +1,11 @@
"use client";
import CustomAppbar from "@/components/CustomAppbar";
+import { SETTING_PAGE } from "@/const/clientPath";
import { useMyInfoQuery } from "@/queries/auth/useMyInfoQuery";
+import UserPageContext from "@/store/user/UserPageContext";
import { Container, Paper } from "@mui/material";
-import React, { useMemo } from "react";
+import { useRouter } from "next/navigation";
+import React, { useMemo, useState } from "react";
type Props = {
children: React.ReactNode;
@@ -13,21 +16,23 @@ const UserInfoPageLayout = ({ children, params }: Props) => {
const { data: userInfo } = useMyInfoQuery();
const isMyProfile = useMemo(
() => String(userInfo?.userNo) === String(params.userId),
- [userInfo,params.userId]
+ [userInfo, params.userId]
);
+ const [isEditing, setIsEditing] = useState(false);
+ const router = useRouter()
return (
-
+
{
- if(!isMyProfile){
- return
+ if (!isMyProfile) {
+ return;
}
- console.log("눌림");
+ router.push(SETTING_PAGE)
}}
/>
-
+
{
{children}
-
+
);
};
diff --git a/client/src/app/wiki/[alcoholNo]/page.tsx b/client/src/app/wiki/[alcoholNo]/page.tsx
new file mode 100644
index 0000000..8005927
--- /dev/null
+++ b/client/src/app/wiki/[alcoholNo]/page.tsx
@@ -0,0 +1,11 @@
+import React from 'react'
+
+type Props = {}
+
+const AlcoholDetailPage = (props: Props) => {
+ return (
+
AlcoholDetailPage
+ )
+}
+
+export default AlcoholDetailPage
\ No newline at end of file
diff --git a/client/src/app/wiki/layout.tsx b/client/src/app/wiki/layout.tsx
index 3f89e4d..870083d 100644
--- a/client/src/app/wiki/layout.tsx
+++ b/client/src/app/wiki/layout.tsx
@@ -10,9 +10,8 @@ const layout = ({ children }: { children: ReactNode }) => {
return (
-
-
+
{
{children}
-
);
};
diff --git a/client/src/components/CustomAppbar.tsx b/client/src/components/CustomAppbar.tsx
index 611abc4..1b3638e 100644
--- a/client/src/components/CustomAppbar.tsx
+++ b/client/src/components/CustomAppbar.tsx
@@ -11,7 +11,6 @@ interface CustomAppbarInterface {
onClickButton?: MouseEventHandler;
}
-
const CustomAppbar = ({
title,
buttonComponent,
@@ -24,12 +23,12 @@ const CustomAppbar = ({
router.back()}>
-
+
-
+
{title}
- {buttonComponent && (
+ {buttonComponent ? (
+ ) : (
+
)}
diff --git a/client/src/components/post/PostCard.tsx b/client/src/components/post/PostCard.tsx
index 17fcee4..62b9a15 100644
--- a/client/src/components/post/PostCard.tsx
+++ b/client/src/components/post/PostCard.tsx
@@ -19,7 +19,7 @@ import ShareIcon from "@/assets/icons/ShareIcon.svg";
import LikeIcon from "@/assets/icons/LikeIcon.svg";
import CommentIcon from "@/assets/icons/CommentIcon.svg";
import QuoteIcon from "@/assets/icons/QuoteIcon.svg";
-import AlcoleNameTag from "@/components/wiki/AlcoholNameTag";
+import AlcoholNameTag from "@/components/wiki/AlcoholNameTag";
import dayjs from "dayjs";
import useLikePostMutation from "@/queries/post/useLikePostMutation";
import useUnLikePostMutation from "@/queries/post/useUnLikePostMutation";
@@ -48,6 +48,7 @@ const PostCard = ({
commentCount,
likedByMe,
quoteCount,
+ alcoholNo,
}: PostInterface) => {
const openPostDetailPage = useOpenPostDetailPage();
const hasImage = useMemo(() => postAttachUrls.length !== 0, [postAttachUrls]);
@@ -106,7 +107,11 @@ const PostCard = ({
{alcoholName && (
-
+
)}
diff --git a/client/src/components/post/PostCardList.tsx b/client/src/components/post/PostCardList.tsx
index a98e341..0fd8999 100644
--- a/client/src/components/post/PostCardList.tsx
+++ b/client/src/components/post/PostCardList.tsx
@@ -40,27 +40,29 @@ function PostCardList(props: UseGetPostListQueryInterface) {
return (
- {hasResult &&
- isSuccess &&
- // 검색결과가 있을시
- data?.pages.map((page) =>
- page.list.map((post) => )
+
+ {hasResult &&
+ isSuccess &&
+ // 검색결과가 있을시
+ data?.pages.map((page) =>
+ page.list.map((post) =>
)
+ )}
+ {isSuccess && !hasResult && (
+ // 검색결과 없을 시
+
+
+
)}
- {isSuccess && !hasResult && (
- // 검색결과 없을 시
-
-
-
- )}
- {/* 로딩창 */}
- {isFetchingNextPage || isLoading ? (
-
-
-
- ) : (
- // 인터섹션옵저버
-
- )}
+ {/* 로딩창 */}
+ {isFetchingNextPage || isLoading ? (
+
+
+
+ ) : (
+ // 인터섹션옵저버
+
+ )}
+
);
}
diff --git a/client/src/components/user/info/UserInfoCard.tsx b/client/src/components/user/info/UserInfoCard.tsx
index 7f82e8d..4b6b363 100644
--- a/client/src/components/user/info/UserInfoCard.tsx
+++ b/client/src/components/user/info/UserInfoCard.tsx
@@ -6,7 +6,9 @@ import { UserInfoInterface } from "@/types/user/userInfoInterface";
import useUserInfoQuery from "@/queries/user/useUserInfoQuery";
import getTokenFromLocalStorage from "@/utils/getTokenFromLocalStorage";
import { useMyInfoQuery } from "@/queries/auth/useMyInfoQuery";
-import { useMemo } from "react";
+import { useContext, useMemo } from "react";
+import UserPageContext from "@/store/user/UserPageContext";
+import UserInfoCardSkeleton from "./UserInfoCardSkeleton";
type Props = {
initialData?: UserInfoInterface;
@@ -22,14 +24,16 @@ const UserInfo = ({ initialData, userId }: Props) => {
);
const token = getTokenFromLocalStorage();
+ const { setIsEditing } = useContext(UserPageContext);
const { data } = useUserInfoQuery({
userId,
initialData,
config: { headers: { Authorization: token } },
});
+
if (!data) {
- return <>>;
+ return ;
}
const {
@@ -67,7 +71,19 @@ const UserInfo = ({ initialData, userId }: Props) => {
팔로잉
{isMyProfile ? (
-
+
) : (
)}
diff --git a/client/src/components/user/info/UserInfoCardSkeleton.tsx b/client/src/components/user/info/UserInfoCardSkeleton.tsx
new file mode 100644
index 0000000..d06cec0
--- /dev/null
+++ b/client/src/components/user/info/UserInfoCardSkeleton.tsx
@@ -0,0 +1,23 @@
+import { Avatar, Box, Skeleton, Stack } from "@mui/material";
+
+const UserInfoCardSkeleton = () => {
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
+
+export default UserInfoCardSkeleton;
diff --git a/client/src/components/wiki/AlcoholList.tsx b/client/src/components/wiki/AlcoholList.tsx
index 298a1b9..dc6bb3f 100644
--- a/client/src/components/wiki/AlcoholList.tsx
+++ b/client/src/components/wiki/AlcoholList.tsx
@@ -12,11 +12,12 @@ const AlcoholList = ({
return (
<>
{alcohols?.length > 0 ? (
- alcohols.map((alcohol) => (
+ alcohols.map(({ alcoholName, alcoholNo, alcoholType }) => (
))
) : (
@@ -26,4 +27,3 @@ const AlcoholList = ({
);
};
export default memo(AlcoholList);
-
diff --git a/client/src/components/wiki/AlcoholNameTag.tsx b/client/src/components/wiki/AlcoholNameTag.tsx
index ec2cc35..58bac47 100644
--- a/client/src/components/wiki/AlcoholNameTag.tsx
+++ b/client/src/components/wiki/AlcoholNameTag.tsx
@@ -1,11 +1,14 @@
import { Box, BoxProps, Chip, IconButton, Typography } from "@mui/material";
import PostSeeMoreIcon from "@/assets/icons/PostSeeMoreIcon.svg";
-import { PostInterface } from "@/types/post/PostInterface";
+import { AlcoholDetailInterface } from "@/types/alcohol/AlcoholInterface";
import XIcon from "@/assets/icons/XIcon.svg";
+import { useRouter } from "next/navigation";
+import { WIKI_DETAIL } from "@/const/clientPath";
interface AlcoholNameTagInterface extends BoxProps {
- alcoholName: PostInterface["alcoholName"];
- alcoholType: PostInterface["alcoholType"];
+ alcoholName: AlcoholDetailInterface["alcoholName"];
+ alcoholType: AlcoholDetailInterface["alcoholType"];
+ alcoholNo: AlcoholDetailInterface["alcoholNo"];
removable?: boolean;
onClickRemove?: () => void;
}
@@ -14,9 +17,11 @@ const AlcoholNameTag = ({
alcoholName,
alcoholType,
removable = false,
+ alcoholNo,
onClickRemove,
...others
}: AlcoholNameTagInterface) => {
+ const router = useRouter();
return (
) : (
-
+ router.push(WIKI_DETAIL(String(alcoholNo)))}
+ >
)}
@@ -55,7 +63,7 @@ const AlcoholNameTag = ({
};
const WrapperStyle = {
- width: '100%',
+ width: "100%",
border: "1px solid",
borderColor: "gray.secondary",
backgroundColor: "gray.primary",
diff --git a/client/src/const/clientPath.ts b/client/src/const/clientPath.ts
index 255107d..f920467 100644
--- a/client/src/const/clientPath.ts
+++ b/client/src/const/clientPath.ts
@@ -18,20 +18,31 @@ export const MY_PROFILE = "/user" as const;
/**
* 유저의 PK를 입력받아 해당유저의 프로필 페이지로 이동하는 URL
*/
-export const USER_PAGE = (pk:string|number)=>`/user/${pk}`
+export const USER_PAGE = (pk: string | number) => `/user/${pk}`;
+
+/**
+ * 유저정보 세팅 페이지로 이동하는 라우트
+ */
+export const SETTING_PAGE = '/user/setting' as const
/**
* 술과사전 페이지 라우트
*/
export const WIKI = "/wiki" as const;
+/**
+ * 술 PK 를 입력받아 술의 상세페이지로 이동하는 라우트
+ * @param alcoholNo 술 PK
+ */
+export const WIKI_DETAIL = (alcoholNo: string) =>
+ `${WIKI}/${alcoholNo}` as const;
/**
* 검색 페이지 라우트
*/
export const SEARCH = "/search" as const;
/**
* 키워드를 인자로 받아 쿼리스트링이 추가된 검색페이지 라우트
- * @param keyword
- * @returns
+ * @param keyword
+ * @returns
*/
export const SEARCH_BY_KEYWORD = (keyword: string) =>
`${SEARCH}?keyword=${keyword}`;
@@ -51,7 +62,6 @@ export const POST_DETAIL = (userId: string, postId: string) => {
/**
* 새로운 포스트를 작성하는 페이지
*/
-export const NEW_POST = '/new-post'
-
+export const NEW_POST = "/new-post";
export default HOME;
diff --git a/client/src/const/serverPath.ts b/client/src/const/serverPath.ts
index b18fd99..1460064 100644
--- a/client/src/const/serverPath.ts
+++ b/client/src/const/serverPath.ts
@@ -16,6 +16,10 @@ export const MY_INFO = "/user/me" as const;
* 쿠키를 심어주는 로그인 BFF
*/
export const LOGIN_BFF = "/api/auth/login" as const;
+/**
+ * 클라이언트단 로그인을 행하는 라우트
+ */
+export const LOGOUT_BFF = "/api/auth/logout-internal" as const;
/**
* 게시물리스트를 받아오거나, 작성하는 Path
diff --git a/client/src/store/user/UserPageContext.ts b/client/src/store/user/UserPageContext.ts
new file mode 100644
index 0000000..2f376ac
--- /dev/null
+++ b/client/src/store/user/UserPageContext.ts
@@ -0,0 +1,13 @@
+import { Dispatch, SetStateAction, createContext } from "react";
+
+interface UserPageContextInterface {
+ isEditing: boolean;
+ setIsEditing: Dispatch>;
+}
+
+const UserPageContext = createContext({
+ isEditing: true,
+ setIsEditing: () => {},
+});
+
+export default UserPageContext;
diff --git a/client/src/types/post/PostInterface.ts b/client/src/types/post/PostInterface.ts
index 52d33a0..5da6169 100644
--- a/client/src/types/post/PostInterface.ts
+++ b/client/src/types/post/PostInterface.ts
@@ -34,6 +34,10 @@ export interface PostInterface {
* 마신 술의 종류 (주종)
*/
alcoholType: string;
+ /**
+ * 마신 술의 PK
+ */
+ alcoholNo:number;
/**
* 유저의 ID (로그인용 Email 과는 다름)
*/