-
Notifications
You must be signed in to change notification settings - Fork 0
feat: 검색 메인 페이지 #44
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: 검색 메인 페이지 #44
Changes from all commits
9c7ed5e
3dfddc9
e5f09be
1b613bd
3d32081
bac8c32
a1f8a8e
8bae229
0ea3aec
a1f2109
fadab91
10f6347
8b70c02
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,132 @@ | ||
| import type { SearchedBook } from '@/pages/search/Search'; | ||
| import styled from '@emotion/styled'; | ||
| import { colors, typography } from '@/styles/global/global'; | ||
| import { useNavigate } from 'react-router-dom'; | ||
|
|
||
| interface BookSearchResultProps { | ||
| type: 'searching' | 'searched'; | ||
| searchedBookList: SearchedBook[]; | ||
| } | ||
|
|
||
| export function BookSearchResult({ type, searchedBookList }: BookSearchResultProps) { | ||
| const navigate = useNavigate(); | ||
| const isEmptySearchedBookList = () => { | ||
| if (searchedBookList.length === 0) return true; | ||
| else return false; | ||
| }; | ||
|
|
||
| const handleApplyBook = () => { | ||
| navigate('/search/applybook'); | ||
| }; | ||
| return ( | ||
| <Wrapper> | ||
| <List> | ||
| {type === 'searching' ? <></> : <ResultHeader>전체 {searchedBookList.length}</ResultHeader>} | ||
|
|
||
| {isEmptySearchedBookList() ? ( | ||
| <EmptyWrapper> | ||
| <MainText>현재 등록된 책이 없어요.</MainText> | ||
| <SubText>원하는 책을 신청해주세요!</SubText> | ||
| <RequestButton onClick={handleApplyBook}>책 신청하기</RequestButton> | ||
| </EmptyWrapper> | ||
| ) : ( | ||
| searchedBookList.map(book => ( | ||
| <BookItem key={book.id}> | ||
| <Cover src={book.coverUrl} alt={`${book.title} 커버`} /> | ||
| <BookInfo> | ||
| <Title>{book.title}</Title> | ||
| <Subtitle> | ||
| {book.author} 저 · {book.publisher} | ||
| </Subtitle> | ||
| </BookInfo> | ||
| </BookItem> | ||
| )) | ||
| )} | ||
| </List> | ||
| </Wrapper> | ||
| ); | ||
| } | ||
|
|
||
| const Wrapper = styled.div` | ||
| display: flex; | ||
| flex-direction: column; | ||
| padding: 0 20px; | ||
| margin-bottom: 72px; | ||
| `; | ||
|
|
||
| const List = styled.div` | ||
| display: flex; | ||
| flex-direction: column; | ||
| `; | ||
|
|
||
| const BookItem = styled.div` | ||
| display: flex; | ||
| border-bottom: 1px solid ${colors.darkgrey.dark}; | ||
| padding: 12px 0; | ||
| `; | ||
|
|
||
| const ResultHeader = styled.div` | ||
| font-size: ${typography.fontSize.sm}; | ||
| font-weight: ${typography.fontWeight.medium}; | ||
| color: ${colors.white}; | ||
| padding-bottom: 8px; | ||
| border-bottom: 1px solid ${colors.darkgrey.dark}; | ||
| `; | ||
|
|
||
| const Cover = styled.img` | ||
| width: 80px; | ||
| height: 107px; | ||
| object-fit: cover; | ||
| `; | ||
|
|
||
| const BookInfo = styled.div` | ||
| display: flex; | ||
| flex-direction: column; | ||
| margin-left: 12px; | ||
| `; | ||
|
|
||
| const Title = styled.h3` | ||
| font-size: ${typography.fontSize.base}; | ||
| font-weight: ${typography.fontWeight.semibold}; | ||
| color: ${colors.white}; | ||
| `; | ||
|
|
||
| const Subtitle = styled.span` | ||
| font-size: ${typography.fontSize.xs}; | ||
| font-weight: ${typography.fontWeight.medium}; | ||
| color: ${colors.grey[200]}; | ||
| margin-top: 8px; | ||
| `; | ||
|
|
||
| const EmptyWrapper = styled.div` | ||
| display: flex; | ||
| flex-direction: column; | ||
| align-items: center; | ||
| justify-content: center; | ||
| height: 60vh; | ||
| `; | ||
|
|
||
| const MainText = styled.p` | ||
| color: ${colors.white}; | ||
| font-size: ${typography.fontSize.lg}; | ||
| font-weight: ${typography.fontWeight.semibold}; | ||
| margin-bottom: 8px; | ||
| `; | ||
|
|
||
| const SubText = styled.p` | ||
| color: ${colors.grey[100]}; | ||
| font-size: ${typography.fontSize.sm}; | ||
| font-weight: ${typography.fontWeight.regular}; | ||
| margin-bottom: 20px; | ||
| `; | ||
|
|
||
| const RequestButton = styled.button` | ||
| background-color: ${colors.purple.main}; | ||
| color: ${colors.white}; | ||
| padding: 10px 12px; | ||
| font-size: ${typography.fontSize.base}; | ||
| border: none; | ||
| border-radius: 12px; | ||
| font-weight: ${typography.fontWeight.semibold}; | ||
| cursor: pointer; | ||
| `; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,153 @@ | ||
| import { colors, typography } from '@/styles/global/global'; | ||
| import styled from '@emotion/styled'; | ||
|
|
||
| interface Book { | ||
| id: number; | ||
| title: string; | ||
| coverUrl: string; | ||
| } | ||
|
|
||
| const dummyBooks: Book[] = [ | ||
| { | ||
| id: 1, | ||
| title: '토마토 컵라면', | ||
| coverUrl: 'https://cdn.imweb.me/upload/S20230204e049098f5e744/e6fd3d849546d.jpg', | ||
| }, | ||
| { | ||
| id: 2, | ||
| title: '사슴', | ||
| coverUrl: 'https://cdn.imweb.me/upload/S20230204e049098f5e744/e6fd3d849546d.jpg', | ||
| }, | ||
| { | ||
| id: 3, | ||
| title: '호르몬 체인지지', | ||
| coverUrl: 'https://cdn.imweb.me/upload/S20230204e049098f5e744/e6fd3d849546d.jpg', | ||
| }, | ||
| { | ||
| id: 4, | ||
| title: '호르몬 체인지지', | ||
| coverUrl: 'https://cdn.imweb.me/upload/S20230204e049098f5e744/e6fd3d849546d.jpg', | ||
| }, | ||
| { | ||
| id: 5, | ||
| title: '호르몬 체인지지', | ||
| coverUrl: 'https://cdn.imweb.me/upload/S20230204e049098f5e744/e6fd3d849546d.jpg', | ||
| }, | ||
| { | ||
| id: 6, | ||
| title: '호르몬 체인지지', | ||
| coverUrl: 'https://cdn.imweb.me/upload/S20230204e049098f5e744/e6fd3d849546d.jpg', | ||
| }, | ||
| ]; | ||
|
|
||
| export default function MostSearchedBooks() { | ||
| return ( | ||
| <Container> | ||
| <Header> | ||
| <Title>가장 많이 검색된 책</Title> | ||
| {/* 서버 응답 포맷을 모르기에 우선 하드 코딩 */} | ||
| <DateText>01.12. 기준</DateText> | ||
|
Comment on lines
+48
to
+49
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion 하드코딩된 날짜를 동적으로 처리하도록 개선이 필요합니다. 현재 하드코딩된 날짜는 임시 구현으로 보입니다. 프로덕션에서는 서버에서 받은 데이터를 기반으로 동적으로 표시되어야 합니다. 다음과 같이 개선하는 것을 권장합니다: - {/* 서버 응답 포맷을 모르기에 우선 하드 코딩 */}
- <DateText>01.12. 기준</DateText>
+ <DateText>{formatDate(lastUpdated)} 기준</DateText>
🤖 Prompt for AI Agents |
||
| </Header> | ||
| {dummyBooks.length === 0 ? ( | ||
| <EmptyMessage> | ||
| <MainText>아직 순위가 집계되지 않았어요.</MainText> | ||
| <SubText>조금만 기다려주세요!</SubText> | ||
| </EmptyMessage> | ||
| ) : ( | ||
| <BookList> | ||
| {dummyBooks.map((book, index) => ( | ||
| <BookItem key={book.id}> | ||
| <Rank>{index + 1}.</Rank> | ||
| <Cover src={book.coverUrl} alt={`${book.title} 커버`} /> | ||
| <BookTitle>{book.title}</BookTitle> | ||
| </BookItem> | ||
| ))} | ||
| </BookList> | ||
| )} | ||
| </Container> | ||
| ); | ||
| } | ||
|
|
||
| const Container = styled.div` | ||
| display: flex; | ||
| flex-direction: column; | ||
| padding: 36px 20px 0 20px; | ||
| background-color: var(--color-black-main); | ||
| margin-bottom: 72px; | ||
| `; | ||
|
|
||
| const Header = styled.div` | ||
| display: flex; | ||
| justify-content: space-between; | ||
| align-items: center; | ||
| margin-bottom: 16px; | ||
| `; | ||
|
|
||
| const Title = styled.h2` | ||
| font-size: ${typography.fontSize.lg}; | ||
| color: ${colors.white}; | ||
| font-weight: ${typography.fontWeight.semibold}; | ||
| `; | ||
|
|
||
| const DateText = styled.span` | ||
| font-size: ${typography.fontSize.xs}; | ||
| color: ${colors.grey[300]}; | ||
| font-weight: ${typography.fontWeight.regular}; | ||
| `; | ||
|
|
||
| const BookList = styled.ul` | ||
| display: flex; | ||
| flex-direction: column; | ||
| margin-top: 4px; | ||
| `; | ||
|
|
||
| const BookItem = styled.li` | ||
| display: flex; | ||
| align-items: center; | ||
| padding: 12px 0; | ||
| border-bottom: 1px solid ${colors.darkgrey.dark}; | ||
| `; | ||
|
|
||
| const Rank = styled.span` | ||
| font-size: ${typography.fontSize.base}; | ||
| color: ${colors.white}; | ||
| font-weight: ${typography.fontWeight.medium}; | ||
| width: 24px; | ||
| `; | ||
|
|
||
| const Cover = styled.img` | ||
| width: 45px; | ||
| height: 60px; | ||
| object-fit: cover; | ||
| `; | ||
|
Comment on lines
+118
to
+122
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion 이미지 로딩 실패 처리를 추가해야 합니다. 외부 이미지 URL 사용 시 로딩 실패에 대한 fallback 처리가 필요합니다. 다음과 같이 개선하는 것을 권장합니다: const Cover = styled.img`
width: 45px;
height: 60px;
object-fit: cover;
+ background-color: ${colors.grey[400]};
`;그리고 컴포넌트에서 onError 핸들러를 추가: <Cover
src={book.coverUrl}
alt={`${book.title} 커버`}
onError={(e) => {
e.currentTarget.src = '/images/book-placeholder.jpg';
}}
/>🤖 Prompt for AI Agents |
||
|
|
||
| const BookTitle = styled.span` | ||
| font-size: ${typography.fontSize.sm}; | ||
| color: ${colors.white}; | ||
| font-weight: ${typography.fontWeight.regular}; | ||
| white-space: nowrap; | ||
| overflow: hidden; | ||
| text-overflow: ellipsis; | ||
| margin-left: 8px; | ||
| `; | ||
|
|
||
| const EmptyMessage = styled.div` | ||
| display: flex; | ||
| flex-direction: column; | ||
| justify-content: center; | ||
| height: 60vh; | ||
| text-align: center; | ||
| `; | ||
|
|
||
| const MainText = styled.div` | ||
| font-size: ${typography.fontSize.lg}; | ||
| color: ${colors.white}; | ||
| font-weight: ${typography.fontWeight.semibold}; | ||
| margin-bottom: 8px; | ||
| `; | ||
|
|
||
| const SubText = styled.div` | ||
| font-size: ${typography.fontSize.sm}; | ||
| color: ${colors.grey[100]}; | ||
| font-weight: ${typography.fontWeight.regular}; | ||
| `; | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
더미 데이터에서 보안 및 데이터 품질 문제가 있습니다.
다음과 같이 개선하는 것을 권장합니다:
const dummyBooks: Book[] = [ { id: 1, title: '토마토 컵라면', - coverUrl: 'https://cdn.imweb.me/upload/S20230204e049098f5e744/e6fd3d849546d.jpg', + coverUrl: '/images/book-placeholder.jpg', }, { id: 2, - title: '사슴', - coverUrl: 'https://cdn.imweb.me/upload/S20230204e049098f5e744/e6fd3d849546d.jpg', + title: '어린 왕자', + coverUrl: '/images/book-placeholder-2.jpg', }, { id: 3, - title: '호르몬 체인지지', - coverUrl: 'https://cdn.imweb.me/upload/S20230204e049098f5e744/e6fd3d849546d.jpg', + title: '1984', + coverUrl: '/images/book-placeholder-3.jpg', }, // 각각 다른 책 정보로 수정 ];🤖 Prompt for AI Agents