diff --git a/client/public/mockServiceWorker.js b/client/public/mockServiceWorker.js index 7898a62..78933b6 100644 --- a/client/public/mockServiceWorker.js +++ b/client/public/mockServiceWorker.js @@ -2,7 +2,7 @@ /* tslint:disable */ /** - * Mock Service Worker (2.0.3). + * Mock Service Worker (2.0.4). * @see https://github.com/mswjs/msw * - Please do NOT modify this file. * - Please do NOT serve this file on production. diff --git a/client/src/app/@Modal/(.)post/[userId]/[postId]/page.tsx b/client/src/app/@Modal/(.)post/[userId]/[postId]/page.tsx index 58560f7..182539e 100644 --- a/client/src/app/@Modal/(.)post/[userId]/[postId]/page.tsx +++ b/client/src/app/@Modal/(.)post/[userId]/[postId]/page.tsx @@ -1,22 +1,13 @@ import ModalWrapper from "@/components/ModalWrapper"; import PostDetail from "@/components/post/PostDetail"; - -const mockData = { - id: "123458", - createdAt: "Mon Nov 06 2023 00:13:07", - nickname: "testNick", - userId: "userID", - userImage: "https://source.unsplash.com/random?wallpapers", - content: - "Lorem ipsum dolor, sit amet consectetur adipisicing elit. Eos ullam aut minus aliquam quis officia, non dolore omnis, magnam totam tenetur ad harum? Mollitia omnis odit atque blanditiis exercitationem! Voluptatum.", - image: ["https://source.unsplash.com/random?wallpapers"], - tags: ["해시태그1", "해시태그2"], -}; +import { Suspense } from "react"; const page = () => { return ( - + 로딩}> + + ); }; diff --git a/client/src/app/layout.tsx b/client/src/app/layout.tsx index dc527ac..4eaccf4 100644 --- a/client/src/app/layout.tsx +++ b/client/src/app/layout.tsx @@ -7,6 +7,7 @@ import Pretendard from "~/assets/font/Pretendard"; import NavigationBar from "~/components/NavigationBar"; import "./globals.css"; import MSWInit from "@/components/mock/MSWInit"; +import CustomQueryClientProvider from "@/components/queryClient/CustomQueryClientProvider"; export const metadata: Metadata = { title: `${nameOfApp} | ${oneLineMessage}`, @@ -27,7 +28,7 @@ export default function RootLayout({ return ( - + {Modal} @@ -37,11 +38,11 @@ export default function RootLayout({ overflow: "auto", }} > - {children} + {children} - + ); diff --git a/client/src/app/page.tsx b/client/src/app/page.tsx index d75255b..051987a 100644 --- a/client/src/app/page.tsx +++ b/client/src/app/page.tsx @@ -1,10 +1,19 @@ +"use client"; import PostCardList from "@/components/post/PostCardList"; +// import { getPostListQueryFn } from "@/queries/post/useGetPostListQuery"; import { Container } from "@mui/material"; +import { Suspense } from "react"; export default function Home() { + // const initialData = await getPostListQueryFn(); return ( - + 로딩중}> + {/* FIXME */}{/* @ts-ignore*/} + + ); } diff --git a/client/src/components/post/PostCard.tsx b/client/src/components/post/PostCard.tsx index 92c16e5..f6373fe 100644 --- a/client/src/components/post/PostCard.tsx +++ b/client/src/components/post/PostCard.tsx @@ -17,7 +17,6 @@ import { CardMedia, Typography, ButtonBase, - Button, } from "@mui/material"; import PostHashTagList from "./PostHashtagList"; import { useOpenPostDetailPage } from "@/hooks/useOpenPostDetailPage"; @@ -32,10 +31,9 @@ const PostCard = ({ tagList, postNo, likeCount, + profileImgUrls }: PostInterface) => { const openPostDetailPage = useOpenPostDetailPage(); - // FIXME 유저이미지가 오지 않음 - const userImage = undefined; const hasImage = useMemo(() => postAttachUrl.length !== 0, [postAttachUrl]); return ( @@ -43,10 +41,10 @@ const PostCard = ({ - {userImage || id[0].toUpperCase()} + {profileImgUrls || id[0].toUpperCase()} {/* Header */} diff --git a/client/src/components/post/PostCardList.tsx b/client/src/components/post/PostCardList.tsx index 59bedff..0a62745 100644 --- a/client/src/components/post/PostCardList.tsx +++ b/client/src/components/post/PostCardList.tsx @@ -1,20 +1,19 @@ "use client"; + import PostCard from "@/components/post/PostCard"; import { PostInterface } from "@/types/post/PostInterface"; -import axios from "@/libs/axios"; -import { useEffect, useState } from "react"; +import useGetPostListQuery from "@/queries/post/useGetPostListQuery"; + +interface PostCardListProps { + initialData: { content: PostInterface[] }; +} -const PostCardList = () => { - const [data, setData] = useState<{ content: PostInterface[] }>(); - useEffect(() => { - axios.get<{ content: PostInterface[] }>("/posts").then(({ data }) => { - setData(data); - }); - }, []); +const PostCardList = ({ initialData }: PostCardListProps) => { + const { data } = useGetPostListQuery(initialData); return ( <> - {data?.content.map((post) => ( + {data.content.map((post) => ( ))} diff --git a/client/src/components/post/PostDetail.tsx b/client/src/components/post/PostDetail.tsx index b722855..89de4ce 100644 --- a/client/src/components/post/PostDetail.tsx +++ b/client/src/components/post/PostDetail.tsx @@ -1,3 +1,5 @@ +// FIXME 실제 서버연결시 바꿔야함 +"use client"; import { PostInterface } from "@/types/post/PostInterface"; import { Avatar, @@ -11,53 +13,59 @@ import { Typography, } from "@mui/material"; import PostHashTagList from "./PostHashtagList"; +import { FavoriteBorder, ShareOutlined } from "@mui/icons-material"; +import useGetPostDetailQuery from "@/queries/post/useGetPostDetailQuery"; -const PostDetail = ({ - image, - createdAt, - userId, - nickname, - content, - userImage, - tags, - id, -}: PostInterface) => { +const PostDetail = () => { + const { data } = useGetPostDetailQuery('1'); + const { + postAttachUrl, + createdAt, + id, + nickname, + postContent, + tagList, + likeCount, + profileImgUrls, + }: PostInterface = data return ( - {userImage || userId[0].toUpperCase()} + {profileImgUrls || id[0].toUpperCase()} } - title={`${userId} ${nickname}`} + title={`${id} ${nickname}`} subheader={createdAt} sx={{ p: 0 }} /> - {content} - + {postContent} + {/* 이미지 */} - {image.length !== 0 && ( + {postAttachUrl.length !== 0 && ( )} - 좋아요 + + {likeCount} + 공유하기 diff --git a/client/src/components/queryClient/CustomQueryClientProvider.tsx b/client/src/components/queryClient/CustomQueryClientProvider.tsx new file mode 100644 index 0000000..e1aaea9 --- /dev/null +++ b/client/src/components/queryClient/CustomQueryClientProvider.tsx @@ -0,0 +1,16 @@ +"use client"; + +import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; +import { ReactNode, useState } from "react"; + +export default function CustomQueryClientProvider({ + children, +}: { + children?: ReactNode; +}) { + const [queryClient] = useState(() => new QueryClient()); + + return ( + {children} + ); +} diff --git a/client/src/mocks/handlers.ts b/client/src/mocks/handlers.ts index b7062a3..97e450a 100644 --- a/client/src/mocks/handlers.ts +++ b/client/src/mocks/handlers.ts @@ -1,38 +1,6 @@ -import { HttpResponse, http } from "msw"; -import { randomNumber, randomSelect } from "./utils/random"; -import { PostInterface } from "@/types/post/PostInterface"; +import getPostList from "./handlers/getPostList"; +import getPostDetail from "./handlers/getPostDetail"; export const handlers = [ - http.get(`${process.env.NEXT_PUBLIC_BASE_URL}/posts`, () => { - return HttpResponse.json({ - content: Array.from(new Array(5)).map((_data, i):PostInterface => { - return { - nickname: "testNick", - id: "userID", - updateDt: "2023-11-08T13:05:09.531Z", - createdAt: "2023-11-08T13:05:09.531Z", - edited: randomSelect(true, false), - postNo: i, - postContent: - "Lorem ipsum dolor, sit amet consectetur adipisicing elit. Eos ullam aut minus aliquam quis officia, non dolore omnis, magnam totam tenetur ad harum? Mollitia omnis odit atque blanditiis exercitationem! Voluptatum.", - positionInfo: "울릉도 동남쪽 뱃길따라 200리", - alcoholName: "string", - postAttachUrl: ["https://source.unsplash.com/random?wallpapers"], - tagList: randomSelect(["tag1", "tag2"], []), - quoteInfo: randomSelect( - [ - { - quoteNo: 1, - quoteContent: "1", - }, - ], - [] - ), - likeCount: randomNumber(), - quoteCount: randomNumber(), - followedByMe: randomSelect(true, false), - }; - }), - }); - }), + getPostList,getPostDetail ]; diff --git a/client/src/mocks/handlers/getPostDetail.ts b/client/src/mocks/handlers/getPostDetail.ts new file mode 100644 index 0000000..bfcda67 --- /dev/null +++ b/client/src/mocks/handlers/getPostDetail.ts @@ -0,0 +1,42 @@ +import { PostInterface } from "@/types/post/PostInterface"; +import { HttpResponse, http } from "msw"; +import { randomBoolean, randomNumber, randomSelect } from "../utils/random"; +/** + * 포스트 상세보기 정보를 받아오는 핸들러 + */ +export default http.get(`${process.env.NEXT_PUBLIC_BASE_URL}/posts/1`, () => { + return HttpResponse.json({ + nickname: "testNick", + id: "userID", + updateDt: "2023-11-08T13:05:09.531Z", + createdAt: "2023-11-08T13:05:09.531Z", + edited: randomBoolean(), + postNo: 135, + postContent: + "Lorem ipsum dolor, sit amet consectetur adipisicing elit. Eos ullam aut minus aliquam quis officia, non dolore omnis, magnam totam tenetur ad harum? Mollitia omnis odit atque blanditiis exercitationem! Voluptatum.", + positionInfo: "울릉도 동남쪽 뱃길따라 200리", + alcoholName: "string", + postAttachUrl: randomSelect( + ["https://source.unsplash.com/random?wallpapers"], + [] + ), + tagList: randomSelect(["tag1", "tag2"], []), + quoteInfo: randomSelect( + [ + { + quoteNo: 1, + quoteContent: "1", + }, + ], + [] + ), + likeCount: randomNumber(), + quoteCount: randomNumber(), + followedByMe: randomBoolean(), + likedByme: randomBoolean(), + profileImgUrls: randomSelect( + "https://source.unsplash.com/random?wallpapers", + "" + ), + }); + }); diff --git a/client/src/mocks/handlers/getPostList.ts b/client/src/mocks/handlers/getPostList.ts new file mode 100644 index 0000000..989b929 --- /dev/null +++ b/client/src/mocks/handlers/getPostList.ts @@ -0,0 +1,47 @@ +import { PostInterface } from "@/types/post/PostInterface"; +import { HttpResponse, http } from "msw"; +import { randomBoolean, randomNumber, randomSelect } from "../utils/random"; +/** + * 포스트 리스트를 받아오는 핸들러 + */ +export default http.get(`${process.env.NEXT_PUBLIC_BASE_URL}/posts`, () => { + return HttpResponse.json({ + content: Array.from(new Array(5)).map((_data, i): PostInterface => { + return { + nickname: "testNick", + id: "userID", + updateDt: "2023-11-08T13:05:09.531Z", + createdAt: "2023-11-08T13:05:09.531Z", + edited: randomBoolean(), + postNo: i, + postContent: + "Lorem ipsum dolor, sit amet consectetur adipisicing elit. Eos ullam aut minus aliquam quis officia, non dolore omnis, magnam totam tenetur ad harum? Mollitia omnis odit atque blanditiis exercitationem! Voluptatum.", + positionInfo: "울릉도 동남쪽 뱃길따라 200리", + alcoholName: "string", + postAttachUrl: randomSelect( + ["https://source.unsplash.com/random?wallpapers"], + [] + ), + tagList: randomSelect(["tag1", "tag2"], []), + quoteInfo: randomSelect( + [ + { + quoteNo: 1, + quoteContent: "1", + }, + ], + [] + ), + likeCount: randomNumber(), + quoteCount: randomNumber(), + followedByMe: randomBoolean(), + likedByme: randomBoolean(), + profileImgUrls: randomSelect( + "https://source.unsplash.com/random?wallpapers", + "" + ), + }; + }), + }); + }); + diff --git a/client/src/queries/post/useGetPostDetailQuery.tsx b/client/src/queries/post/useGetPostDetailQuery.tsx new file mode 100644 index 0000000..e268127 --- /dev/null +++ b/client/src/queries/post/useGetPostDetailQuery.tsx @@ -0,0 +1,20 @@ +import { useSuspenseQuery } from "@tanstack/react-query"; +import axios from "@/libs/axios"; +import { PostInterface } from "@/types/post/PostInterface"; + +const useGetPostDetailQuery = (postId: string) => { + return useSuspenseQuery({ + queryKey: ["post", postId], + queryFn: () => getPostListQueryFn(postId), + // initialData: initialData, + }); +}; + +export const getPostListQueryFn = async (postId: string) => { + const { data } = await axios.get( + `/posts/${postId}` + ); + return data; +}; + +export default useGetPostDetailQuery; diff --git a/client/src/queries/post/useGetPostListQuery.tsx b/client/src/queries/post/useGetPostListQuery.tsx new file mode 100644 index 0000000..1e3b49a --- /dev/null +++ b/client/src/queries/post/useGetPostListQuery.tsx @@ -0,0 +1,18 @@ +import { useSuspenseQuery } from "@tanstack/react-query"; +import axios from "@/libs/axios"; +import { PostInterface } from "@/types/post/PostInterface"; + +const useGetPostListQuery = (initialData: { content: PostInterface[] }) => { + return useSuspenseQuery({ + queryKey: ["posts"], + queryFn: getPostListQueryFn, + initialData: initialData, + }); +}; + +export const getPostListQueryFn = async () => { + const { data } = await axios.get<{ content: PostInterface[] }>("/posts"); + return data; +}; + +export default useGetPostListQuery; diff --git a/client/src/types/post/PostInterface.ts b/client/src/types/post/PostInterface.ts index 213e0b0..bc0e2b4 100644 --- a/client/src/types/post/PostInterface.ts +++ b/client/src/types/post/PostInterface.ts @@ -25,7 +25,7 @@ export interface PostInterface { /** * 게시글 내 위치 정보 */ - positionInfo:string; + positionInfo: string; /** * 마신 술 정보 */ @@ -38,6 +38,10 @@ export interface PostInterface { * 유저가 설정한 닉네임 */ nickname: string; + /** + * 유저가 설정한 프로필 이미지 + */ + profileImgUrls: string; /** * 이미지 Href 배열 */ @@ -62,6 +66,10 @@ export interface PostInterface { * 내가 팔로우 하는지 여부 */ followedByMe: boolean; + /** + * 내가 좋아요를 눌렀는지 여부 + */ + likedByme :boolean; } type QuoteInfoType = {