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' && ( + + )} + { {hasPosts ? ( <> {posts.map((post, index) => ( - <> - + + {/* 10개마다 추천 섹션 반복 표시 */} {(index + 1) % 10 === 0 && ( )} - + ))} ) : ( diff --git a/src/components/group/CompletedGroupModal.tsx b/src/components/group/CompletedGroupModal.tsx deleted file mode 100644 index adb7740a..00000000 --- a/src/components/group/CompletedGroupModal.tsx +++ /dev/null @@ -1,195 +0,0 @@ -import { useState, useEffect } from 'react'; -import styled from '@emotion/styled'; -import leftArrow from '../../assets/common/leftArrow.svg'; -import type { Group } from './MyGroupBox'; -import { GroupCard } from './GroupCard'; -import TitleHeader from '../common/TitleHeader'; -import { Modal, Overlay } from './Modal.styles'; -import { getMyRooms, type Room } from '@/api/rooms/getMyRooms'; -import { getMyProfile } from '@/api/users/getMyProfile'; -import { colors, typography } from '@/styles/global/global'; -import { useNavigate } from 'react-router-dom'; - -interface CompletedGroupModalProps { - onClose: () => 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..75351bd9 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); @@ -57,7 +57,9 @@ export const MyGroupModal = ({ onClose }: MyGroupModalProps) => { ? 'playing' : selected === '모집중' ? 'recruiting' - : 'playingAndRecruiting'; + : selected === '완료' + ? 'expired' + : 'playingAndRecruiting'; const response = await getMyRooms(roomType, null); @@ -92,7 +94,9 @@ export const MyGroupModal = ({ onClose }: MyGroupModalProps) => { ? '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..43c3b4fb 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,12 +103,7 @@ const Group = () => { return ( {isMyGroupModalOpen && } - {isCompletedGroupModalOpen && } - +