-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* style: BookCover 책 상세 페이지 2xlarge 사이즈 수정 * feat: AvatarGroup 컴포넌트 작성 * feat: 책 상세 페이지 BookInfo 컴포넌트 작성 * refactor: 책 상세 query hook 이름 수정, 공백 제거 * chore: 불필요한 useBookTitle hook 제거
- Loading branch information
Showing
9 changed files
with
189 additions
and
23 deletions.
There are no files selected for viewing
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
import { Meta, StoryObj } from '@storybook/react'; | ||
import BookInfo from '@/v1/book/detail/BookInfo'; | ||
|
||
const meta: Meta<typeof BookInfo> = { | ||
title: 'book/detail/BookInfo', | ||
component: BookInfo, | ||
}; | ||
|
||
export default meta; | ||
|
||
type Story = StoryObj<typeof BookInfo>; | ||
|
||
export const Default: Story = { | ||
args: { bookId: 22 }, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
import { APIBook } from '@/types/book'; | ||
import { IconBookmark } from '@public/icons'; | ||
import { useBookInfo } from '@/queries/book/useBookInfoQuery'; | ||
|
||
import Avatar, { AvatarGroup } from '@/v1/base/Avatar'; | ||
import BookCover from '@/v1/book/BookCover'; | ||
import useBookUserInfoQuery from '@/queries/book/useBookUserInfoQuery'; | ||
|
||
const BookInfo = ({ bookId }: { bookId: APIBook['bookId'] }) => { | ||
const { data } = useBookInfo(bookId); | ||
const { title, author, imageUrl, summary, bookUrl } = data; | ||
|
||
return ( | ||
<div className="flex flex-col gap-[2rem] rounded-l-[1.5rem] bg-white p-[2rem] shadow-bookcard"> | ||
<div className="flex items-end gap-[2rem]"> | ||
<BookCover size="2xlarge" src={imageUrl} /> | ||
|
||
<div className="flex flex-col gap-[0.5rem]"> | ||
<BookmarkButton /> | ||
<BookTitle title={title} /> | ||
<BookAuthor author={author} /> | ||
</div> | ||
</div> | ||
|
||
<BookSummary summary={summary} bookUrl={bookUrl} /> | ||
<BookmarkUserInfo bookId={bookId} /> | ||
</div> | ||
); | ||
}; | ||
|
||
export default BookInfo; | ||
|
||
const BookTitle = ({ title }: { title: string }) => ( | ||
<p className="text-lg font-bold">{title}</p> | ||
); | ||
|
||
const BookAuthor = ({ author }: { author: string }) => ( | ||
<p className="text-sm">{author}</p> | ||
); | ||
|
||
const BookmarkButton = () => { | ||
return ( | ||
<IconBookmark | ||
className="mb-[0.5rem] h-[2.4rem] w-[2.4rem] cursor-pointer stroke-main-900 stroke-[0.15rem]" | ||
fill="white" | ||
/> | ||
); | ||
}; | ||
|
||
const BookSummary = ({ | ||
summary, | ||
bookUrl, | ||
}: { | ||
summary: string; | ||
bookUrl: string; | ||
}) => ( | ||
<p className="text-md"> | ||
{summary} ... | ||
{bookUrl && ( | ||
<a target="_blank" href={bookUrl}> | ||
<span className="cursor-pointer text-main-900">더보기</span> | ||
</a> | ||
)} | ||
</p> | ||
); | ||
|
||
const BookmarkUserInfo = ({ bookId }: { bookId: APIBook['bookId'] }) => { | ||
const { data } = useBookUserInfoQuery(bookId); | ||
const { totalCount, users } = data; | ||
const avatarCount = users.length; | ||
|
||
return ( | ||
<div className="flex items-center gap-[0.5rem]"> | ||
{avatarCount !== 0 && ( | ||
<AvatarGroup> | ||
{users.map(({ userId, profileImage }) => ( | ||
<a key={userId} href={`/profile/${userId}`}> | ||
<Avatar src={profileImage} border /> | ||
</a> | ||
))} | ||
</AvatarGroup> | ||
)} | ||
<p className="text-sm"> | ||
{getBookmarkedUserCountText(totalCount, avatarCount)} | ||
</p> | ||
</div> | ||
); | ||
}; | ||
|
||
const getBookmarkedUserCountText = ( | ||
totalCount: number, | ||
avatarCount: number | ||
) => { | ||
const otherCount = totalCount - avatarCount; | ||
|
||
if (otherCount === 0 && totalCount === 0) { | ||
return '아직 이 책을 책장에 꽂은 사람이 없어요.'; | ||
} else if (otherCount === 0) { | ||
return '님이 이 책을 책장에 꽂았어요.'; | ||
} | ||
|
||
return `외 ${otherCount}명이 이 책을 책장에 꽂았어요.`; | ||
}; |