From 4d12827ccfb042845987acea2b6f7c686b0b065b Mon Sep 17 00:00:00 2001 From: heeyongKim <166043860+heeeeyong@users.noreply.github.com> Date: Thu, 28 Aug 2025 23:11:08 +0900 Subject: [PATCH 1/3] =?UTF-8?q?fix:=20=EB=A7=88=EC=9D=B4=ED=8E=98=EC=9D=B4?= =?UTF-8?q?=EC=A7=80=20=ED=94=84=EB=A1=9C=ED=95=84=20=ED=8F=B0=ED=8A=B8=20?= =?UTF-8?q?=EC=82=AC=EC=9D=B4=EC=A6=88=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/common/Post/PostBody.tsx | 1 + src/pages/mypage/Mypage.tsx | 14 +++++++------- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/components/common/Post/PostBody.tsx b/src/components/common/Post/PostBody.tsx index f8d0a0d4..8ec5f050 100644 --- a/src/components/common/Post/PostBody.tsx +++ b/src/components/common/Post/PostBody.tsx @@ -55,6 +55,7 @@ const ImageContainer = styled.div` width: 100px; height: 100px; flex-shrink: 0; //고정사이즈 + object-fit: cover; } `; diff --git a/src/pages/mypage/Mypage.tsx b/src/pages/mypage/Mypage.tsx index 1f42d7be..9f5e1bfb 100644 --- a/src/pages/mypage/Mypage.tsx +++ b/src/pages/mypage/Mypage.tsx @@ -219,17 +219,17 @@ const UserProfile = styled.div` gap: 4px; .username { - color: var(--color-white); - font-size: var(--font-size-xs); - font-weight: var(--font-weight-medium); - line-height: normal; + color: var(--color-text-primary_white, #fefefe); + font-size: var(--string-size-large01, 18px); + font-weight: var(--string-weight-semibold, 600); + line-height: var(--string-lineheight-height24, 24px); /* 133.333% */ + letter-spacing: 0.018px; } .usertitle { - color: var(--color-text-humanities_skyblue, #a1d5ff); - font-size: var(--font-size-xs); + font-size: var(--string-size-medium01, 14px); font-weight: var(--string-weight-regular, 400); - line-height: normal; + line-height: var(--string-lineheight-feedcontent_height20, 20px); /* 142.857% */ } } } From 5a8fcf6ebdc4892a3043ad7796e9ff11b4a7264f Mon Sep 17 00:00:00 2001 From: heeyongKim <166043860+heeeeyong@users.noreply.github.com> Date: Thu, 28 Aug 2025 23:29:29 +0900 Subject: [PATCH 2/3] =?UTF-8?q?fix:=20=EC=B1=85=20=EC=A0=80=EC=9E=A5=20las?= =?UTF-8?q?t-child=20border-bottom=20=EC=97=86=EC=95=A0=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/mypage/SavePage.tsx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/pages/mypage/SavePage.tsx b/src/pages/mypage/SavePage.tsx index 12530160..0af91198 100644 --- a/src/pages/mypage/SavePage.tsx +++ b/src/pages/mypage/SavePage.tsx @@ -297,9 +297,15 @@ const BookList = styled.div` `; const BookItem = styled.div` + width: 94.8%; + margin: 0 auto; display: flex; border-bottom: 1px solid ${colors.darkgrey.dark}; padding: 12px 20px; + + &:last-child { + border-bottom: none; + } justify-content: space-between; `; From 36b92ee5ff22341a1c5d8a6ea0ed8d0a297d2be9 Mon Sep 17 00:00:00 2001 From: heeyongKim <166043860+heeeeyong@users.noreply.github.com> Date: Sun, 31 Aug 2025 23:30:23 +0900 Subject: [PATCH 3/3] =?UTF-8?q?fix:=20=EC=A0=80=EC=9E=A5=EB=90=9C=20?= =?UTF-8?q?=EC=B1=85=20=EB=AC=B4=ED=95=9C=EC=8A=A4=ED=81=AC=EB=A1=A4=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/books/getSavedBooksInMy.ts | 15 +++++-- src/pages/mypage/SavePage.tsx | 69 +++++++++++++++++++++++++++--- 2 files changed, 75 insertions(+), 9 deletions(-) diff --git a/src/api/books/getSavedBooksInMy.ts b/src/api/books/getSavedBooksInMy.ts index 007eeaa7..1f60f62b 100644 --- a/src/api/books/getSavedBooksInMy.ts +++ b/src/api/books/getSavedBooksInMy.ts @@ -14,6 +14,8 @@ export interface SavedBookInMy { // API 응답 데이터 타입 export interface SavedBooksInMyData { bookList: SavedBookInMy[]; + nextCursor: string; + isLast: boolean; } // API 응답 타입 @@ -24,10 +26,17 @@ export interface SavedBooksInMyResponse { data: SavedBooksInMyData; } -// 개인적으로 저장한 책 목록 조회 API 함수 -export const getSavedBooksInMy = async () => { +// 개인적으로 저장한 책 목록 조회 API 함수 (무한스크롤) +export const getSavedBooksInMy = async (cursor: string | null = null) => { try { - const response = await apiClient.get('/books/saved'); + const params: { cursor?: string | null } = {}; + if (cursor !== null) { + params.cursor = cursor; + } + + const response = await apiClient.get('/books/saved', { + params, + }); return response.data; } catch (error) { console.error('개인 저장 책 조회 API 오류:', error); diff --git a/src/pages/mypage/SavePage.tsx b/src/pages/mypage/SavePage.tsx index 0af91198..82022c2d 100644 --- a/src/pages/mypage/SavePage.tsx +++ b/src/pages/mypage/SavePage.tsx @@ -28,24 +28,41 @@ const SavePage = () => { // 책 관련 상태 const [savedBooks, setSavedBooks] = useState([]); + const [bookNextCursor, setBookNextCursor] = useState(null); + const [bookIsLast, setBookIsLast] = useState(false); + const [bookLoading, setBookLoading] = useState(false); // 초기 로딩 상태 const [initialLoading, setInitialLoading] = useState(true); // Intersection Observer ref const feedObserverRef = useRef(null); + const bookObserverRef = useRef(null); const handleBack = () => { navigate('/mypage'); }; - // 저장된 책 목록 로드 함수 - const loadSavedBooks = useCallback(async () => { + // 저장된 책 목록 로드 함수 (무한스크롤) + const loadSavedBooks = useCallback(async (cursor: string | null = null) => { try { - const response = await getSavedBooksInMy(); - setSavedBooks(response.data.bookList); + setBookLoading(true); + const response = await getSavedBooksInMy(cursor); + + if (cursor === null) { + // 첫 로드 + setSavedBooks(response.data.bookList); + } else { + // 추가 로드 + setSavedBooks(prev => [...prev, ...response.data.bookList]); + } + + setBookNextCursor(response.data.nextCursor); + setBookIsLast(response.data.isLast); } catch (error) { console.error('저장된 책 목록 로드 실패:', error); + } finally { + setBookLoading(false); } }, []); @@ -72,6 +89,35 @@ const SavePage = () => { } }, []); + // 저장된 책 목록 로드 함수 + const loadMoreBooks = useCallback(async () => { + if (!bookNextCursor || bookIsLast || bookLoading) return; + + try { + await loadSavedBooks(bookNextCursor); + } catch (error) { + console.error('책 추가 로드 실패:', error); + } + }, [bookNextCursor, bookIsLast, bookLoading, loadSavedBooks]); + + // 책 Intersection Observer 콜백 + const lastBookElementCallback = useCallback( + (node: HTMLDivElement | null) => { + if (bookLoading || bookIsLast) return; + + if (node) { + const observer = new IntersectionObserver(entries => { + if (entries[0].isIntersecting && !bookLoading && !bookIsLast) { + loadMoreBooks(); + } + }); + + observer.observe(node); + } + }, + [bookLoading, bookIsLast, loadMoreBooks], + ); + // 페이지 진입 시 모든 데이터 로드 (한 번만 실행) useEffect(() => { const loadAllData = async () => { @@ -91,6 +137,8 @@ const SavePage = () => { // 책 데이터 설정 setSavedBooks(booksResponse.data.bookList); + setBookNextCursor(booksResponse.data.nextCursor); + setBookIsLast(booksResponse.data.isLast); } catch (error) { console.error('초기 데이터 로드 실패:', error); } finally { @@ -203,8 +251,11 @@ const SavePage = () => { ) : savedBooks.length > 0 ? ( <> - {savedBooks.map(book => ( - + {savedBooks.map((book, index) => ( + @@ -222,6 +273,12 @@ const SavePage = () => { ))} + {/* 무한스크롤을 위한 observer 요소 */} + {!bookIsLast && ( +
+ {bookLoading && } +
+ )}
) : (