Skip to content

Commit

Permalink
[#495] [책 상세] 책 상세 페이지 마크업 (#496)
Browse files Browse the repository at this point in the history
* feat: BookInfo 스켈레톤 작성

* feat: 책 상세 페이지 마크업

- 스켈레톤 구현

* style: text overflow 적용
  • Loading branch information
gxxrxn authored Mar 4, 2024
1 parent 3ae1b06 commit 77ea320
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 86 deletions.
139 changes: 55 additions & 84 deletions src/app/book/[bookId]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,99 +1,70 @@
'use client';

import { Box, Skeleton, SkeletonText, Text, VStack } from '@chakra-ui/react';
import { useRouter } from 'next/navigation';

import bookAPI from '@/apis/book';
import useBookInfoQuery from '@/queries/book/useBookInfoQuery';
import useBookUserInfoQuery from '@/queries/book/useBookUserInfoQuery';
import { APIBook } from '@/types/book';
import { BookCommentList, BookInfo } from '@/ui/BookDetail';
import TopNavigation from '@/ui/common/TopNavigation';
import debounce from '@/utils/debounce';
import { useBookTitle } from '@/queries/book/useBookInfoQuery';

import Skeleton from '@/v1/base/Skeleton';
import SSRSafeSuspense from '@/components/SSRSafeSuspense';
import TopNavigation from '@/v1/base/TopNavigation';
import BottomActionButton from '@/v1/base/BottomActionButton';
import BackButton from '@/v1/base/BackButton';
import BookInfo, { BookInfoSkeleton } from '@/v1/book/detail/BookInfo';
import BookCommentList from '@/v1/comment/BookCommentList';

const BookDetailPage = ({
params: { bookId },
}: {
params: { bookId: APIBook['bookId'] };
}) => {
const router = useRouter();

const bookQueryInfo = useBookInfoQuery(bookId, {
onError: () => {
/** @todo /404 페이지로 교체 */
router.replace('/');
},
});

const bookUserQueryInfo = useBookUserInfoQuery(bookId);

const updateBookmark = (isBookMarked: boolean) => {
if (!bookUserQueryInfo.isSuccess) {
return;
}
return (
<>
<BookTopNavigation bookId={bookId} />
<SSRSafeSuspense fallback={<BookPageSkeleton />}>
<div className="flex flex-col gap-[3rem] pb-[5rem] pt-[1rem]">
<BookInfo bookId={bookId} />
<div className="flex flex-col gap-[1rem]">
<Heading text="책 코멘트" />
<BookCommentList bookId={bookId} />
</div>
</div>
</SSRSafeSuspense>
<BottomActionButton>코멘트 작성하기</BottomActionButton>
</>
);
};

const { isInMyBookshelf } = bookUserQueryInfo.data;
export default BookDetailPage;

if (!isInMyBookshelf && isBookMarked) {
bookAPI.setBookMarked(bookId).then(() => {
bookUserQueryInfo.refetch();
});
} else if (isInMyBookshelf && !isBookMarked) {
bookAPI.unsetBookMarked(bookId).then(() => {
bookUserQueryInfo.refetch();
});
}
};
const BookPageSkeleton = () => (
<div className="pt-[1rem]">
<BookInfoSkeleton />
</div>
);

return (
<Box>
<TopNavigation pageTitle="책 상세 페이지" />
<VStack
w="100%"
bgColor="white"
p="2rem"
shadow="lg"
align="stretch"
borderLeftRadius={15}
gap="2rem"
>
{bookQueryInfo.isSuccess && bookUserQueryInfo.isSuccess && (
<BookInfo
title={bookQueryInfo.data.title}
author={bookQueryInfo.data.author}
imageUrl={bookQueryInfo.data.imageUrl}
contents={bookQueryInfo.data.contents}
url={bookQueryInfo.data.url}
onBookmarkClick={debounce(updateBookmark, 500)}
{...bookUserQueryInfo.data}
/>
)}
{bookQueryInfo.isLoading && (
<VStack spacing="2rem" align="stretch">
<Skeleton width="18rem" height="25rem" />
<SkeletonText
mt="4"
noOfLines={4}
spacing="4"
skeletonHeight="1.4rem"
/>
</VStack>
)}
</VStack>
const BookTopNavigation = ({ bookId }: { bookId: APIBook['bookId'] }) => (
<TopNavigation>
<TopNavigation.LeftItem>
<BackButton />
</TopNavigation.LeftItem>
<TopNavigation.CenterItem textAlign="left">
<SSRSafeSuspense fallback={<BookTitleSkeleton />}>
<BookTitle bookId={bookId} />
</SSRSafeSuspense>
</TopNavigation.CenterItem>
</TopNavigation>
);

<VStack align="stretch">
<Text pt="3rem" pb="1rem" fontSize="lg" fontWeight="bold">
책 코멘트
</Text>
{bookUserQueryInfo.isSuccess && (
<BookCommentList
bookId={bookId}
isInMyBookshelf={bookUserQueryInfo.data.isInMyBookshelf}
/>
)}
</VStack>
</Box>
);
const BookTitle = ({ bookId }: { bookId: APIBook['bookId'] }) => {
const { data: title } = useBookTitle(bookId);
return <p className="w-full truncate">{title}</p>;
};

export default BookDetailPage;
const Heading = ({ text }: { text: string }) => (
<p className="text-xl font-bold">{text}</p>
);

const BookTitleSkeleton = () => (
<Skeleton>
<Skeleton.Text fontSize="medium" width="20rem" />
</Skeleton>
);
5 changes: 5 additions & 0 deletions src/queries/book/useBookInfoQuery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,8 @@ export const useBookInfo = (bookId: APIBook['bookId']) =>
useBookInfoQuery(bookId, {
select: transformBookData,
});

export const useBookTitle = (bookId: APIBook['bookId']) =>
useBookInfoQuery(bookId, {
select: data => data.title,
});
28 changes: 26 additions & 2 deletions src/v1/book/detail/BookInfo.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { APIBook } from '@/types/book';
import { IconBookmark } from '@public/icons';
import { useBookInfo } from '@/queries/book/useBookInfoQuery';
import useBookUserInfoQuery from '@/queries/book/useBookUserInfoQuery';

import Avatar, { AvatarGroup } from '@/v1/base/Avatar';
import Skeleton from '@/v1/base/Skeleton';
import BookCover from '@/v1/book/BookCover';
import useBookUserInfoQuery from '@/queries/book/useBookUserInfoQuery';

const BookInfo = ({ bookId }: { bookId: APIBook['bookId'] }) => {
const { data } = useBookInfo(bookId);
Expand All @@ -15,7 +16,7 @@ const BookInfo = ({ bookId }: { bookId: APIBook['bookId'] }) => {
<div className="flex items-end gap-[2rem]">
<BookCover size="2xlarge" src={imageUrl} />

<div className="flex flex-col gap-[0.5rem]">
<div className="flex min-w-0 flex-col gap-[0.5rem]">
<BookmarkButton />
<BookTitle title={title} />
<BookAuthor author={author} />
Expand Down Expand Up @@ -101,3 +102,26 @@ const getBookmarkedUserCountText = (

return `외 ${otherCount}명이 이 책을 책장에 꽂았어요.`;
};

export const BookInfoSkeleton = () => (
<Skeleton>
<div className="flex flex-col gap-[2rem] rounded-l-[1.5rem] bg-white p-[2rem] shadow-bookcard">
<div className="flex items-end gap-[2rem]">
<div className="flex-shrink-0">
<Skeleton.Rect width="14rem" height="19.6rem" rounded="medium" />
</div>
<div className="flex flex-col gap-[1rem] overflow-x-clip">
<Skeleton.Text fontSize="xlarge" width="16rem" />
<Skeleton.Text fontSize="small" width="7rem" />
</div>
</div>
<div className="flex flex-col gap-[0.7rem]">
<Skeleton.Text width="100%" fontSize="medium" />
<Skeleton.Text width="100%" fontSize="medium" />
<Skeleton.Text width="100%" fontSize="medium" />
<Skeleton.Text width="60%" fontSize="medium" />
</div>
<Skeleton.Text width="75%" fontSize="large" />
</div>
</Skeleton>
);

0 comments on commit 77ea320

Please sign in to comment.