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 && ( + // 검색결과 없을 시 + + no result alert + )} - {isSuccess && !hasResult && ( - // 검색결과 없을 시 - - no result alert - - )} - {/* 로딩창 */} - {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 과는 다름) */