From 1e3084e9dd74056ad0a84bfbcea0860cad4f26d5 Mon Sep 17 00:00:00 2001 From: Ji Ho June <129824629+ho0010@users.noreply.github.com> Date: Sun, 2 Nov 2025 15:25:50 +0900 Subject: [PATCH 1/4] =?UTF-8?q?fix:=20Fragment=EC=97=90=20key=EA=B0=80=20?= =?UTF-8?q?=EC=97=86=EC=96=B4=EC=84=9C=20=EC=83=9D=EA=B8=B0=EB=8A=94=20?= =?UTF-8?q?=EC=98=A4=EB=A5=98=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/feed/TotalFeed.tsx | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/components/feed/TotalFeed.tsx b/src/components/feed/TotalFeed.tsx index b183a129..4d2dbf86 100644 --- a/src/components/feed/TotalFeed.tsx +++ b/src/components/feed/TotalFeed.tsx @@ -1,4 +1,5 @@ import styled from '@emotion/styled'; +import { Fragment } from 'react'; import FollowList from './FollowList'; import FeedPost from './FeedPost'; import RecommendedFeedSection from './RecommendedFeedSection'; @@ -14,19 +15,13 @@ const TotalFeed = ({ showHeader, posts = [], isTotalFeed }: FeedListProps) => { {hasPosts ? ( <> {posts.map((post, index) => ( - <> - + + {/* 10개마다 추천 섹션 반복 표시 */} {(index + 1) % 10 === 0 && ( )} - + ))} ) : ( From 03853b1e6896460677f6e1ce7f7f14d210cd9871 Mon Sep 17 00:00:00 2001 From: Ji Ho June <129824629+ho0010@users.noreply.github.com> Date: Sun, 2 Nov 2025 15:30:49 +0900 Subject: [PATCH 2/4] =?UTF-8?q?fix:=20=EC=99=84=EB=A3=8C=EB=90=9C=20?= =?UTF-8?q?=EB=AA=A8=EC=9E=84=EB=B0=A9=EC=9D=84=20=EB=82=B4=20=EB=AA=A8?= =?UTF-8?q?=EC=9E=84=EB=B0=A9=20=EC=98=B5=EC=85=98=EC=9C=BC=EB=A1=9C=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD=20=EB=AA=A8=EC=9E=84=20=EB=A9=94=EC=9D=B8=20?= =?UTF-8?q?=ED=8E=98=EC=9D=B4=EC=A7=80=20=EC=82=AC=EC=9A=A9=EC=84=B1=20?= =?UTF-8?q?=EA=B0=9C=EC=84=A0=202=EC=B0=A8=20=EC=9E=91=EC=97=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/common/MainHeader.tsx | 10 +- src/components/group/CompletedGroupModal.tsx | 195 ------------------- src/components/group/GroupCard.tsx | 16 +- src/components/group/MyGroupModal.tsx | 64 ++---- src/pages/group/Group.tsx | 8 +- 5 files changed, 38 insertions(+), 255 deletions(-) delete mode 100644 src/components/group/CompletedGroupModal.tsx diff --git a/src/components/common/MainHeader.tsx b/src/components/common/MainHeader.tsx index a2aaf386..29da8d20 100644 --- a/src/components/common/MainHeader.tsx +++ b/src/components/common/MainHeader.tsx @@ -1,6 +1,5 @@ import { useEffect, useState } from 'react'; import headerLogo from '../../assets/header/header-logo.svg'; -import groupDoneLogo from '../../assets/header/group-done.svg'; import findUserLogo from '../../assets/header/findUser.svg'; import bellLogo from '../../assets/header/bell.svg'; import bellExistLogo from '../../assets/header/exist-bell.svg'; @@ -40,11 +39,10 @@ const MainHeader = ({ type, leftButtonClick, rightButtonClick }: MainHeaderProps - + {type === 'home' && ( + + )} + void; -} - -const CompletedGroupModal = ({ onClose }: CompletedGroupModalProps) => { - const navigate = useNavigate(); - const [rooms, setRooms] = useState([]); - const [isLoading, setIsLoading] = useState(false); - const [error, setError] = useState(null); - const [nickname, setNickname] = useState(''); - - useEffect(() => { - document.body.style.overflow = 'hidden'; - return () => { - document.body.style.overflow = ''; - }; - }, []); - - const convertRoomToGroup = (room: Room): Group => { - return { - id: room.roomId.toString(), - title: room.roomName, - userName: '', - participants: room.memberCount, - maximumParticipants: room.recruitCount, - coverUrl: room.bookImageUrl, - deadLine: '', - isOnGoing: false, - type: room.type, - }; - }; - - const handleGroupCardClick = (group: Group) => { - navigate(`/group/detail/joined/${group.id}`); - }; - - useEffect(() => { - const fetchCompletedRooms = async () => { - try { - setIsLoading(true); - setError(null); - const response = await getMyRooms('expired', null); - if (response.isSuccess) { - setRooms(response.data.roomList); - } else { - setError(response.message); - } - } catch (error) { - console.error('완료된 방 목록 조회 실패:', error); - setError('완료된 방 목록을 불러오는데 실패했습니다.'); - } finally { - setIsLoading(false); - } - }; - - const fetchNickname = async () => { - try { - const profile = await getMyProfile(); - setNickname(profile.nickname); - } catch { - setNickname(''); - } - }; - - fetchCompletedRooms(); - fetchNickname(); - }, []); - - const convertedGroups = rooms.map(convertRoomToGroup); - return ( - - - } - onLeftClick={onClose} - /> - - {nickname - ? `${nickname}님이 참여했던 모임방들을 확인해보세요.` - : '참여했던 모임방들을 확인해보세요.'} - - - {isLoading ? ( - 로딩 중... - ) : error ? ( - {error} - ) : convertedGroups.length > 0 ? ( - convertedGroups.map(group => ( - handleGroupCardClick(group)} - /> - )) - ) : ( - - 완료된 모임방이 없어요 - 아직 완료된 모임방이 없습니다. - - )} - - - - ); -}; - -export default CompletedGroupModal; - -const Text = styled.p` - font-size: ${typography.fontSize.sm}; - font-weight: ${typography.fontWeight.regular}; - color: ${colors.white}; - margin: 20px; -`; - -const Content = styled.div<{ isEmpty?: boolean }>` - display: grid; - gap: 20px; - overflow-y: ${({ isEmpty }) => (isEmpty ? 'visible' : 'auto')}; - padding: 0 20px; - grid-template-columns: 1fr; - margin-bottom: 70px; - - @media (min-width: 584px) { - grid-template-columns: 1fr 1fr; - } - - & > *:only-child { - grid-column: 1 / -1; - } - &::-webkit-scrollbar { - display: none; - } - -ms-overflow-style: none; - scrollbar-width: none; -`; - -const LoadingMessage = styled.div` - display: flex; - justify-content: center; - align-items: center; - padding: 40px 20px; - color: ${colors.white}; - font-size: ${typography.fontSize.base}; -`; - -const ErrorMessage = styled.div` - display: flex; - justify-content: center; - align-items: center; - padding: 40px 20px; - color: #ff6b6b; - font-size: ${typography.fontSize.base}; -`; - -const EmptyState = styled.div` - display: flex; - flex-direction: column; - justify-content: center; - align-items: center; - padding: 40px 20px; - color: ${colors.grey[100]}; - text-align: center; - height: 70%; - position: absolute; - left: 50%; - transform: translateX(-50%); -`; - -const EmptyTitle = styled.p` - font-size: ${typography.fontSize.lg}; - font-weight: ${typography.fontWeight.semibold}; - margin-bottom: 8px; - color: ${colors.white}; -`; - -const EmptySubText = styled.p` - font-size: ${typography.fontSize.sm}; - font-weight: ${typography.fontWeight.regular}; - color: ${colors.grey[100]}; -`; diff --git a/src/components/group/GroupCard.tsx b/src/components/group/GroupCard.tsx index 79700a0a..797750b4 100644 --- a/src/components/group/GroupCard.tsx +++ b/src/components/group/GroupCard.tsx @@ -13,10 +13,14 @@ interface Props { onClick?: () => void; isFirstCard?: boolean; isPublic?: boolean; + isCompleted?: boolean; } export const GroupCard = forwardRef( - ({ group, isOngoing, type = 'main', isRecommend = false, onClick, isFirstCard }, ref) => { + ( + { group, isOngoing, type = 'main', isRecommend = false, onClick, isFirstCard, isCompleted }, + ref, + ) => { return ( @@ -33,9 +37,13 @@ export const GroupCard = forwardRef( people

{group.participants}

- / {group.maximumParticipants}명 + {!isCompleted && ( + / {group.maximumParticipants}명 + )} + {isCompleted && }
- {(type !== 'modal' || group.type !== 'expired') && + {!isCompleted && + (type !== 'modal' || group.type !== 'expired') && (isOngoing === true ? ( {group.deadLine} 종료 @@ -138,7 +146,7 @@ const Bottom = styled.div` const Participant = styled.div<{ isRecommend: boolean }>` display: flex; align-items: center; - gap: 6px; + gap: 4px; color: ${colors.white}; font-size: ${typography.fontSize.xs}; font-weight: ${typography.fontWeight.medium}; diff --git a/src/components/group/MyGroupModal.tsx b/src/components/group/MyGroupModal.tsx index 6605ece2..813b623a 100644 --- a/src/components/group/MyGroupModal.tsx +++ b/src/components/group/MyGroupModal.tsx @@ -21,7 +21,7 @@ export const MyGroupModal = ({ onClose }: MyGroupModalProps) => { }; }, []); const navigate = useNavigate(); - const [selected, setSelected] = useState<'진행중' | '모집중' | ''>(''); + const [selected, setSelected] = useState<'진행중' | '모집중' | '완료' | ''>(''); const [rooms, setRooms] = useState([]); const [isLoading, setIsLoading] = useState(false); const [error, setError] = useState(null); @@ -52,12 +52,14 @@ export const MyGroupModal = ({ onClose }: MyGroupModalProps) => { setNextCursor(null); setIsLast(false); - const roomType: RoomType = + const roomType: RoomType | 'expired' = selected === '진행중' ? 'playing' : selected === '모집중' ? 'recruiting' - : 'playingAndRecruiting'; + : selected === '완료' + ? 'expired' + : 'playingAndRecruiting'; const response = await getMyRooms(roomType, null); @@ -87,12 +89,14 @@ export const MyGroupModal = ({ onClose }: MyGroupModalProps) => { isFetchingRef.current = true; setIsLoading(true); try { - const roomType: RoomType = + const roomType: RoomType | 'expired' = selected === '진행중' ? 'playing' : selected === '모집중' ? 'recruiting' - : 'playingAndRecruiting'; + : selected === '완료' + ? 'expired' + : 'playingAndRecruiting'; const res = await getMyRooms(roomType, nextCursor); if (res.isSuccess) { @@ -119,40 +123,6 @@ export const MyGroupModal = ({ onClose }: MyGroupModalProps) => { } }; - useEffect(() => { - const fetchRooms = async () => { - try { - setIsLoading(true); - setError(null); - setNextCursor(null); - setIsLast(false); - - const roomType: RoomType = - selected === '진행중' - ? 'playing' - : selected === '모집중' - ? 'recruiting' - : 'playingAndRecruiting'; - - const res = await getMyRooms(roomType, null); - if (res.isSuccess) { - setRooms(res.data.roomList); - setNextCursor(res.data.nextCursor); - setIsLast(res.data.isLast); - } else { - setError(res.message); - } - } catch (e) { - console.log(e); - setError('방 목록을 불러오는데 실패했습니다.'); - } finally { - setIsLoading(false); - } - }; - - fetchRooms(); - }, [selected]); - useEffect(() => { const tryFill = async () => { if (!contentRef.current || isLast) return; @@ -169,6 +139,7 @@ export const MyGroupModal = ({ onClose }: MyGroupModalProps) => { } }; tryFill(); + // eslint-disable-next-line react-hooks/exhaustive-deps }, [rooms, nextCursor, isLast]); useEffect(() => { @@ -180,7 +151,9 @@ export const MyGroupModal = ({ onClose }: MyGroupModalProps) => { const convertedGroups = rooms.map(convertRoomToGroup); const handleGroupCardClick = (group: Group) => { - if (selected === '모집중') { + if (selected === '완료') { + navigate(`/group/detail/joined/${group.id}`); + } else if (selected === '모집중') { navigate(`/group/detail/${group.id}`); } else if (selected === '진행중') { navigate(`/group/detail/joined/${group.id}`); @@ -202,7 +175,7 @@ export const MyGroupModal = ({ onClose }: MyGroupModalProps) => { /> - {(['진행중', '모집중'] as const).map(tab => ( + {(['진행중', '모집중', '완료'] as const).map(tab => ( { group={group} isOngoing={group.isOnGoing} type="modal" + isCompleted={selected === '완료'} onClick={() => handleGroupCardClick(group)} /> ))} @@ -235,14 +209,18 @@ export const MyGroupModal = ({ onClose }: MyGroupModalProps) => { ? '진행중인 모임방이 없어요' : selected === '모집중' ? '모집중인 모임방이 없어요' - : '참여중인 모임방이 없어요'} + : selected === '완료' + ? '완료된 모임방이 없어요' + : '참여중인 모임방이 없어요'} {selected === '진행중' ? '진행중인 모임방에 참여해보세요!' : selected === '모집중' ? '모집중인 모임방에 참여해보세요!' - : '첫 번째 모임방에 참여해보세요!'} + : selected === '완료' + ? '아직 완료된 모임방이 없습니다.' + : '첫 번째 모임방에 참여해보세요!'} )} diff --git a/src/pages/group/Group.tsx b/src/pages/group/Group.tsx index 9c43a6f8..24bbc767 100644 --- a/src/pages/group/Group.tsx +++ b/src/pages/group/Group.tsx @@ -8,7 +8,6 @@ import styled from '@emotion/styled'; import { RecruitingGroupCarousel, type Section } from '@/components/group/RecruitingGroupCarousel'; import { useState, useEffect } from 'react'; import { MyGroupModal } from '@/components/group/MyGroupModal'; -import CompletedGroupModal from '@/components/group/CompletedGroupModal'; import { useNavigate } from 'react-router-dom'; import makegroupfab from '../../assets/common/makegroupfab.svg'; import searchChar from '../../assets/common/searchChar.svg'; @@ -32,7 +31,6 @@ const convertRoomItemToGroup = ( const Group = () => { const navigate = useNavigate(); const [isMyGroupModalOpen, setIsMyGroupModalOpen] = useState(false); - const [isCompletedGroupModalOpen, setIsCompletedGroupModalOpen] = useState(false); const [sections, setSections] = useState([ { title: '최근 생성된 독서 모임방', groups: [] }, { title: '마감 임박한 독서 모임방', groups: [] }, @@ -86,9 +84,6 @@ const Group = () => { const openMyGroupModal = () => setIsMyGroupModalOpen(true); const closeMyGroupModal = () => setIsMyGroupModalOpen(false); - const openCompletedGroupModal = () => setIsCompletedGroupModalOpen(true); - const closeCompletedGroupModal = () => setIsCompletedGroupModalOpen(false); - const handleSearchBarClick = () => { navigate('/group/search'); }; @@ -108,10 +103,9 @@ const Group = () => { return ( {isMyGroupModalOpen && } - {isCompletedGroupModalOpen && } From 967390cd3e3fdf86dc9bdb39b76ae7aa5711869e Mon Sep 17 00:00:00 2001 From: Ji Ho June <129824629+ho0010@users.noreply.github.com> Date: Sun, 2 Nov 2025 15:56:01 +0900 Subject: [PATCH 3/4] =?UTF-8?q?remove:=20=EB=B6=88=ED=95=84=EC=9A=94?= =?UTF-8?q?=ED=95=9C=20=EC=BD=94=EB=93=9C=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/group/MyGroupModal.tsx | 2 +- src/pages/group/Group.tsx | 6 +----- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/components/group/MyGroupModal.tsx b/src/components/group/MyGroupModal.tsx index 813b623a..c950e909 100644 --- a/src/components/group/MyGroupModal.tsx +++ b/src/components/group/MyGroupModal.tsx @@ -52,7 +52,7 @@ export const MyGroupModal = ({ onClose }: MyGroupModalProps) => { setNextCursor(null); setIsLast(false); - const roomType: RoomType | 'expired' = + const roomType: RoomType = selected === '진행중' ? 'playing' : selected === '모집중' diff --git a/src/pages/group/Group.tsx b/src/pages/group/Group.tsx index 24bbc767..43c3b4fb 100644 --- a/src/pages/group/Group.tsx +++ b/src/pages/group/Group.tsx @@ -103,11 +103,7 @@ const Group = () => { return ( {isMyGroupModalOpen && } - + From f4eb20b5ba21d1ffadd72b935a04cd44bbd74096 Mon Sep 17 00:00:00 2001 From: Ji Ho June <129824629+ho0010@users.noreply.github.com> Date: Sun, 2 Nov 2025 16:02:39 +0900 Subject: [PATCH 4/4] =?UTF-8?q?remove:=20=EC=A4=91=EB=B3=B5=EB=90=9C=20?= =?UTF-8?q?=ED=83=80=EC=9E=85=20=EC=84=A0=EC=96=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/group/MyGroupModal.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/group/MyGroupModal.tsx b/src/components/group/MyGroupModal.tsx index c950e909..75351bd9 100644 --- a/src/components/group/MyGroupModal.tsx +++ b/src/components/group/MyGroupModal.tsx @@ -89,7 +89,7 @@ export const MyGroupModal = ({ onClose }: MyGroupModalProps) => { isFetchingRef.current = true; setIsLoading(true); try { - const roomType: RoomType | 'expired' = + const roomType: RoomType = selected === '진행중' ? 'playing' : selected === '모집중'