diff --git a/src/components/common/LoadingSpinner.tsx b/src/components/common/LoadingSpinner.tsx index cc69312c..99b4bf6a 100644 --- a/src/components/common/LoadingSpinner.tsx +++ b/src/components/common/LoadingSpinner.tsx @@ -24,6 +24,10 @@ const LoadingSpinner = ({ const Container = styled.div<{ fullHeight: boolean }>` display: flex; flex-direction: column; + width: 100%; + max-width: 767px; + min-width: 320px; + margin: 0 auto; justify-content: center; align-items: center; ${({ fullHeight }) => diff --git a/src/components/common/Post/PostBody.tsx b/src/components/common/Post/PostBody.tsx index 59f44074..383434b2 100644 --- a/src/components/common/Post/PostBody.tsx +++ b/src/components/common/Post/PostBody.tsx @@ -9,6 +9,7 @@ const Container = styled.div` flex-direction: column; width: 100%; gap: 16px; + cursor: pointer; `; const PostContent = styled.div<{ hasImage: boolean }>` @@ -82,9 +83,11 @@ const PostBody = ({ }, [contentBody]); return ( - - - handlePostClick(feedId)}> + handlePostClick(feedId)}> +
e.stopPropagation()}> + +
+
{contentBody}
diff --git a/src/components/common/Post/PostFooter.tsx b/src/components/common/Post/PostFooter.tsx index 7132ee41..418d9671 100644 --- a/src/components/common/Post/PostFooter.tsx +++ b/src/components/common/Post/PostFooter.tsx @@ -52,6 +52,7 @@ interface PostFooterProps { isLiked?: boolean; isPublic?: boolean; isDetail?: boolean; + onSaveToggle?: (feedId: number, newSaveState: boolean) => void; } const PostFooter = ({ @@ -63,6 +64,7 @@ const PostFooter = ({ isLiked = false, isPublic = true, isDetail = false, + onSaveToggle, }: PostFooterProps) => { const [liked, setLiked] = useState(isLiked); const [likeCount, setLikeCount] = useState(initialLikeCount); @@ -90,9 +92,15 @@ const PostFooter = ({ const response = await postSaveFeed(feedId, !saved); if (response.isSuccess) { + const newSaveState = response.data?.isSaved ?? !saved; // 성공 시 상태 업데이트 - setSaved(response.data?.isSaved ?? !saved); - console.log('저장 상태 변경 성공:', response.data?.isSaved); + setSaved(newSaveState); + console.log('저장 상태 변경 성공:', newSaveState); + + // 부모 컴포넌트에 알림 + if (onSaveToggle) { + onSaveToggle(feedId, newSaveState); + } } else { console.error('저장 상태 변경 실패:', response.message); } diff --git a/src/components/feed/FeedPost.tsx b/src/components/feed/FeedPost.tsx index 8d421eb0..28d3105a 100644 --- a/src/components/feed/FeedPost.tsx +++ b/src/components/feed/FeedPost.tsx @@ -26,13 +26,13 @@ const BorderBottom = styled.div` background: #1c1c1c; `; -const FeedPost = ({ showHeader, isLast, isMyFeed, ...postData }: FeedPostProps) => { +const FeedPost = ({ showHeader, isLast, isMyFeed, onSaveToggle, ...postData }: FeedPostProps) => { return ( <> {showHeader && } - + {!isLast && } diff --git a/src/components/feed/UserProfileItem.tsx b/src/components/feed/UserProfileItem.tsx index bc8694ba..50641d80 100644 --- a/src/components/feed/UserProfileItem.tsx +++ b/src/components/feed/UserProfileItem.tsx @@ -17,13 +17,18 @@ const UserProfileItem = ({ userId, isLast, type, + isMyself, }: UserProfileItemProps) => { const navigate = useNavigate(); const [followed, setFollowed] = useState(isFollowing); const { openPopup } = usePopupStore(); const handleProfileClick = () => { - navigate(`/otherfeed/${userId}`); + if (isMyself) { + navigate(`/myfeed/${userId}`); + } else { + navigate(`/otherfeed/${userId}`); + } }; const toggleFollow = async (e: React.MouseEvent) => { @@ -62,7 +67,7 @@ const UserProfileItem = ({ - {type === 'followlist' && ( + {type === 'followlist' && !isMyself && (
{followed ? '띱 취소' : '띱 하기'}
diff --git a/src/components/group/Modal.styles.ts b/src/components/group/Modal.styles.ts index 0d1665bd..84ce7760 100644 --- a/src/components/group/Modal.styles.ts +++ b/src/components/group/Modal.styles.ts @@ -4,11 +4,14 @@ import styled from '@emotion/styled'; export const Overlay = styled.div<{ $whiteBg?: boolean }>` display: flex; justify-content: center; - align-items: flex-start; + align-items: center; position: fixed; top: 0; - left: 0; - width: 100vw; + left: 50%; + transform: translateX(-50%); + width: 100%; + max-width: 767px; + min-width: 320px; height: 100vh; background: ${({ $whiteBg }) => ($whiteBg ? 'white' : colors.black.main)}; z-index: 110; diff --git a/src/pages/feed/FollowerListPage.tsx b/src/pages/feed/FollowerListPage.tsx index 69931a95..c4129f26 100644 --- a/src/pages/feed/FollowerListPage.tsx +++ b/src/pages/feed/FollowerListPage.tsx @@ -135,6 +135,7 @@ const FollowerListPage = () => { type={type as UserProfileType} isFollowing={user.isFollowing} isLast={index === userList.length - 1} + isMyself={user.isMyself} /> ))} @@ -156,7 +157,9 @@ const Wrapper = styled.div` const TotalBar = styled.div` position: fixed; top: 0; - width: 727px; + width: 94.8%; + max-width: 727px; + min-width: 320px; padding: 76px 0px 4px 0px; border-bottom: 1px solid var(--color-darkgrey-dark); background-color: var(--color-black-main); diff --git a/src/pages/mypage/SavePage.tsx b/src/pages/mypage/SavePage.tsx index 54ac2391..12530160 100644 --- a/src/pages/mypage/SavePage.tsx +++ b/src/pages/mypage/SavePage.tsx @@ -11,6 +11,7 @@ import { colors, typography } from '@/styles/global/global'; import { getSavedBooksInMy, type SavedBookInMy } from '@/api/books/getSavedBooksInMy'; import { getSavedFeedsInMy, type SavedFeedInMy } from '@/api/feeds/getSavedFeedsInMy'; import { postSaveBook } from '@/api/books/postSaveBook'; + import LoadingSpinner from '@/components/common/LoadingSpinner'; const tabs = ['피드', '책']; @@ -38,7 +39,17 @@ const SavePage = () => { navigate('/mypage'); }; - // 저장된 피드 로드 + // 저장된 책 목록 로드 함수 + const loadSavedBooks = useCallback(async () => { + try { + const response = await getSavedBooksInMy(); + setSavedBooks(response.data.bookList); + } catch (error) { + console.error('저장된 책 목록 로드 실패:', error); + } + }, []); + + // 저장된 피드 목록 로드 함수 const loadSavedFeeds = useCallback(async (cursor: string | null = null) => { try { setFeedLoading(true); @@ -61,7 +72,7 @@ const SavePage = () => { } }, []); - // 페이지 진입 시 모든 데이터 로드 + // 페이지 진입 시 모든 데이터 로드 (한 번만 실행) useEffect(() => { const loadAllData = async () => { try { @@ -88,7 +99,7 @@ const SavePage = () => { }; loadAllData(); - }, []); // 한 번만 실행 + }, []); // 빈 의존성 배열로 변경 // Intersection Observer 설정 (피드) useEffect(() => { @@ -122,10 +133,15 @@ const SavePage = () => { const newSaveState = !currentBook.isSaved; await postSaveBook(isbn, newSaveState); - // 로컬 상태 업데이트 - setSavedBooks(prev => - prev.map(book => (book.isbn === isbn ? { ...book, isSaved: newSaveState } : book)), - ); + // 저장 취소인 경우 저장된 책 목록을 다시 불러옴 + if (!newSaveState) { + await loadSavedBooks(); + } else { + // 저장인 경우 로컬 상태만 업데이트 + setSavedBooks(prev => + prev.map(book => (book.isbn === isbn ? { ...book, isSaved: newSaveState } : book)), + ); + } console.log('저장 토글:', isbn, newSaveState); } catch (error) { @@ -133,6 +149,19 @@ const SavePage = () => { } }; + // 피드 저장 토글 처리 + const handleFeedSaveToggle = async (feedId: number, newSaveState: boolean) => { + try { + if (!newSaveState) { + // 저장 취소인 경우 리스트에서 제거 + setSavedFeeds(prev => prev.filter(feed => feed.feedId !== feedId)); + console.log('피드 저장 취소 완료:', feedId); + } + } catch (error) { + console.error('피드 저장 상태 변경 실패:', error); + } + }; + return ( { showHeader={true} isMyFeed={false} isLast={index === savedFeeds.length - 1} + onSaveToggle={handleFeedSaveToggle} {...feed} /> ))} @@ -258,8 +288,9 @@ const EmptyState = styled.div` const BookList = styled.div` display: flex; flex-direction: column; + width: 100%; min-width: 320px; - max-width: 540px; + max-width: 767px; padding-top: 32px; margin: 0 auto; width: 100%; diff --git a/src/pages/searchBook/SearchBook.tsx b/src/pages/searchBook/SearchBook.tsx index f6b8e42a..ff362416 100644 --- a/src/pages/searchBook/SearchBook.tsx +++ b/src/pages/searchBook/SearchBook.tsx @@ -238,7 +238,7 @@ const SearchBook = () => { if (isLoading || error || !bookDetail) { if (isLoading) { - return ; + return ; } return ( diff --git a/src/types/follow.ts b/src/types/follow.ts index c1183b99..3fd5f735 100644 --- a/src/types/follow.ts +++ b/src/types/follow.ts @@ -6,4 +6,5 @@ export interface FollowData { aliasColor?: string; followerCount?: number; isFollowing?: boolean; + isMyself?: boolean; } diff --git a/src/types/post.ts b/src/types/post.ts index f275a192..a329791e 100644 --- a/src/types/post.ts +++ b/src/types/post.ts @@ -31,6 +31,7 @@ export interface FeedPostProps extends PostData { isMyFeed?: boolean; isTotalFeed?: boolean; isLast?: boolean; + onSaveToggle?: (feedId: number, newSaveState: boolean) => void; } export type PostBodyProps = Pick< diff --git a/src/types/user.ts b/src/types/user.ts index 5a05c8b6..dd08b47f 100644 --- a/src/types/user.ts +++ b/src/types/user.ts @@ -10,4 +10,5 @@ export interface UserProfileItemProps { userId: number; isLast?: boolean; type?: UserProfileType; + isMyself?: boolean; }