From 34f7d99becd86fcb066295406b18233059976581 Mon Sep 17 00:00:00 2001 From: fr0gydev Date: Sat, 13 Sep 2025 21:18:59 +0900 Subject: [PATCH 01/20] =?UTF-8?q?fix:=20=EC=B2=A0=ED=95=99=EC=9E=90=20?= =?UTF-8?q?=EC=B9=AD=ED=98=B8=20=ED=95=98=EB=8A=98=EC=83=89=EC=9C=BC?= =?UTF-8?q?=EB=A1=9C=20=ED=91=9C=EC=8B=9C=ED=95=98=EB=8F=84=EB=A1=9D=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/members/MemberList.styled.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/members/MemberList.styled.ts b/src/components/members/MemberList.styled.ts index d354167e..f6735159 100644 --- a/src/components/members/MemberList.styled.ts +++ b/src/components/members/MemberList.styled.ts @@ -65,13 +65,13 @@ export const MemberName = styled.div` export const MemberRole = styled.div<{ roleType?: string }>` color: ${({ roleType }) => { if (!roleType) return semanticColors.text.point.green; - + const role = roleType.toLowerCase(); - + if (role.includes('예술') || role.includes('art')) { return semanticColors.text.character.pink; } - if (role.includes('문학') || role.includes('literature')) { + if (role.includes('인문') || role.includes('humanities') || role.includes('철학')) { return semanticColors.text.character.mint; } if (role.includes('사회') || role.includes('sociology')) { @@ -83,7 +83,7 @@ export const MemberRole = styled.div<{ roleType?: string }>` if (role.includes('과학') || role.includes('science')) { return semanticColors.text.character.lavender; } - + return semanticColors.text.point.green; }}; font-size: ${typography.fontSize.xs}; From 1c833673d4932577d73e973534fcfb2f63662985 Mon Sep 17 00:00:00 2001 From: fr0gydev Date: Sat, 13 Sep 2025 21:21:51 +0900 Subject: [PATCH 02/20] =?UTF-8?q?refactor:=20=EA=B8=B0=EB=A1=9D=EC=9E=A5?= =?UTF-8?q?=20=EB=B8=94=EB=9D=BC=EC=9D=B8=EB=93=9C=20=EC=B2=98=EB=A6=AC=20?= =?UTF-8?q?3px=EB=A1=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/memory/RecordItem/RecordItem.styled.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/memory/RecordItem/RecordItem.styled.ts b/src/components/memory/RecordItem/RecordItem.styled.ts index 10b52443..52d2efce 100644 --- a/src/components/memory/RecordItem/RecordItem.styled.ts +++ b/src/components/memory/RecordItem/RecordItem.styled.ts @@ -3,7 +3,7 @@ import { colors, typography, semanticColors } from '../../../styles/global/globa export const Container = styled.div<{ shouldBlur?: boolean }>` background-color: none; - filter: ${({ shouldBlur }) => (shouldBlur ? 'blur(2px)' : 'none')}; + filter: ${({ shouldBlur }) => (shouldBlur ? 'blur(3px)' : 'none')}; transition: filter 0.3s ease; position: relative; `; From a78d6ab0f646a443031033ffde6f2320f824cc3c Mon Sep 17 00:00:00 2001 From: fr0gydev Date: Tue, 16 Sep 2025 09:16:00 +0900 Subject: [PATCH 03/20] =?UTF-8?q?fix:=20=EB=8F=85=EC=84=9C=EB=A9=94?= =?UTF-8?q?=EC=9D=B4=ED=8A=B8=20=ED=94=84=EB=A1=9C=ED=95=84=20=EC=82=AC?= =?UTF-8?q?=EC=A7=84=EC=97=90=20=ED=85=8C=EB=91=90=EB=A6=AC=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/members/MemberList.styled.ts | 1 + src/components/members/MemberList.tsx | 1 + 2 files changed, 2 insertions(+) diff --git a/src/components/members/MemberList.styled.ts b/src/components/members/MemberList.styled.ts index f6735159..ea324211 100644 --- a/src/components/members/MemberList.styled.ts +++ b/src/components/members/MemberList.styled.ts @@ -47,6 +47,7 @@ export const ProfileImage = styled.div` height: 36px; border-radius: 50%; background-color: ${colors.grey['400']}; + border: 1px solid #888; flex-shrink: 0; `; diff --git a/src/components/members/MemberList.tsx b/src/components/members/MemberList.tsx index 9a1e5cdd..e9e6935a 100644 --- a/src/components/members/MemberList.tsx +++ b/src/components/members/MemberList.tsx @@ -78,6 +78,7 @@ const ProfileImageWithSrc = styled.img` height: 36px; border-radius: 50%; background-color: var(--color-grey-400); + border: 1px solid #888; flex-shrink: 0; object-fit: cover; `; From b715160bb7497ce3ff237ec8369e18c9fb28dfc8 Mon Sep 17 00:00:00 2001 From: fr0gydev Date: Tue, 16 Sep 2025 09:48:23 +0900 Subject: [PATCH 04/20] =?UTF-8?q?fix:=20=EA=B8=B0=EB=A1=9D=EC=9E=A5=20?= =?UTF-8?q?=ED=88=AC=ED=91=9C=20=EC=A0=95=EB=B3=B4=20=ED=8D=BC=EC=84=BC?= =?UTF-8?q?=ED=8A=B8=EA=B0=80=20=EC=95=84=EB=8B=8C=20=EB=93=9D=ED=91=9C?= =?UTF-8?q?=EC=88=98=EB=A1=9C=20=ED=91=9C=EC=8B=9C=EB=90=98=EB=8F=84?= =?UTF-8?q?=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../memory/RecordItem/PollRecord.tsx | 20 ++++++++++++++----- src/pages/memory/Memory.tsx | 20 +++++++++++-------- src/types/memory.ts | 2 ++ src/types/record.ts | 1 + 4 files changed, 30 insertions(+), 13 deletions(-) diff --git a/src/components/memory/RecordItem/PollRecord.tsx b/src/components/memory/RecordItem/PollRecord.tsx index 5058606a..54b08d97 100644 --- a/src/components/memory/RecordItem/PollRecord.tsx +++ b/src/components/memory/RecordItem/PollRecord.tsx @@ -91,8 +91,9 @@ const PollRecord = ({ content, pollOptions, postId, shouldBlur = false, onVoteUp return { ...opt, percentage: updatedItem.percentage, + count: updatedItem.count, isVoted: updatedItem.isVoted, - isHighest: updatedItem.percentage === Math.max(...response.data.voteItems.map(item => item.percentage)) + isHighest: updatedItem.count === Math.max(...response.data.voteItems.map(item => item.count)) }; } return opt; @@ -142,8 +143,17 @@ const PollRecord = ({ content, pollOptions, postId, shouldBlur = false, onVoteUp } }; - // 아무도 투표하지 않았는지 확인 (모든 옵션이 0%인지 확인) - const hasVotes = currentOptions.some(option => option.percentage > 0); + // 아무도 투표하지 않았는지 확인 (모든 옵션이 0표인지 확인) + const hasVotes = currentOptions.some(option => option.count > 0); + + // 전체 투표수 계산 + const totalVotes = currentOptions.reduce((sum, option) => sum + option.count, 0); + + // 각 옵션의 퍼센트 계산 (애니메이션용) + const getPercentage = (count: number) => { + if (totalVotes === 0) return 0; + return (count / totalVotes) * 100; + }; return ( @@ -162,7 +172,7 @@ const PollRecord = ({ content, pollOptions, postId, shouldBlur = false, onVoteUp > {hasVotes && ( - {option.percentage}% + {option.count}표 )} diff --git a/src/pages/memory/Memory.tsx b/src/pages/memory/Memory.tsx index fd413215..3f429032 100644 --- a/src/pages/memory/Memory.tsx +++ b/src/pages/memory/Memory.tsx @@ -31,14 +31,18 @@ const convertPostToRecord = (post: Post): Record => { isWriter: post.isWriter, isLiked: post.isLiked, isLocked: post.isLocked, // 블러 처리 여부 추가 - pollOptions: post.voteItems.map((item, index) => ({ - id: item.voteItemId.toString(), - text: item.itemName, - percentage: item.percentage, - isHighest: index === 0, - voteItemId: item.voteItemId, - isVoted: item.isVoted, - })), + pollOptions: post.voteItems.map((item) => { + const maxCount = Math.max(...post.voteItems.map(v => v.count || 0)); + return { + id: item.voteItemId.toString(), + text: item.itemName, + percentage: item.percentage, + count: item.count || 0, + isHighest: (item.count || 0) === maxCount && maxCount > 0, + voteItemId: item.voteItemId, + isVoted: item.isVoted, + }; + }), }; }; diff --git a/src/types/memory.ts b/src/types/memory.ts index f8041c31..44639d85 100644 --- a/src/types/memory.ts +++ b/src/types/memory.ts @@ -3,6 +3,7 @@ export interface VoteItem { voteItemId: number; itemName: string; percentage: number; + count: number; isVoted: boolean; } @@ -82,6 +83,7 @@ export interface PollOption { id: string; text: string; percentage: number; + count: number; isHighest: boolean; voteItemId: number; // 투표 API에 필요한 ID isVoted: boolean; // 현재 사용자가 투표했는지 여부 diff --git a/src/types/record.ts b/src/types/record.ts index 878e68a9..db0c0995 100644 --- a/src/types/record.ts +++ b/src/types/record.ts @@ -35,6 +35,7 @@ export interface VoteItemResult { voteItemId: number; // 투표 아이템 ID itemName: string; // 투표 옵션 이름 percentage: number; // 득표율 + count: number; // 득표수 isVoted: boolean; // 현재 사용자가 투표했는지 여부 } From 1226f534362241fd4b5d08fea23fd1ddb9c02da6 Mon Sep 17 00:00:00 2001 From: Ji Ho June <129824629+ho0010@users.noreply.github.com> Date: Sat, 20 Sep 2025 14:24:08 +0900 Subject: [PATCH 05/20] =?UTF-8?q?feat:=20=EB=AA=A8=EC=9E=84=EB=B0=A9=20?= =?UTF-8?q?=EC=B0=B8=EC=97=AC=ED=95=98=EA=B8=B0=20=EB=B2=84=ED=8A=BC=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20=EB=AA=A8=EC=9E=84=EB=B0=A9=20=EC=9D=B8?= =?UTF-8?q?=EC=9B=90=20=EB=8B=A4=20=EC=B0=BC=EC=9D=84=20=EB=95=8C,=20?= =?UTF-8?q?=EC=B0=B8=EC=97=AC=ED=95=98=EA=B8=B0=20=EB=B2=84=ED=8A=BC=20?= =?UTF-8?q?=EC=83=81=ED=83=9C=20=EB=B9=84=ED=99=9C=EC=84=B1=ED=99=94?= =?UTF-8?q?=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/groupDetail/GroupDetail.tsx | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/pages/groupDetail/GroupDetail.tsx b/src/pages/groupDetail/GroupDetail.tsx index 806cb12d..94a2e7f5 100644 --- a/src/pages/groupDetail/GroupDetail.tsx +++ b/src/pages/groupDetail/GroupDetail.tsx @@ -99,19 +99,17 @@ const GroupDetail = () => { } } catch (error: unknown) { console.error('방 상세 정보 조회 실패:', error); - - // 모집기간이 만료된 방인 경우 - 진행중인 방으로 리다이렉트 + if (error instanceof Error && error.message === '모집기간이 만료된 방입니다.') { navigate(`/group/detail/joined/${roomId}`, { replace: true }); return; } - - // 방 접근 권한이 없는 경우 - 모임 홈으로 리다이렉트 + if (error instanceof Error && error.message === '방 접근 권한이 없습니다.') { navigate('/group', { replace: true }); return; } - + setError('방 정보를 불러오는데 실패했습니다.'); } finally { setIsLoading(false); @@ -359,7 +357,10 @@ const GroupDetail = () => { )} - + = recruitCount)} + > {roomData.isHost ? '모집 마감하기' : isJoining ? '참여 취소하기' : '참여하기'} From 6130ae74afc8d3b50e157724b897a3e842e31727 Mon Sep 17 00:00:00 2001 From: Ji Ho June <129824629+ho0010@users.noreply.github.com> Date: Sat, 20 Sep 2025 15:07:53 +0900 Subject: [PATCH 06/20] =?UTF-8?q?feat:=20group=20search=20tab=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20=EA=B8=B0=ED=9A=8D=20=EB=94=94=EC=9E=90=EC=9D=B8=20?= =?UTF-8?q?=EC=9A=94=EA=B5=AC=EC=82=AC=ED=95=AD=EC=97=90=20=EB=94=B0?= =?UTF-8?q?=EB=9D=BC=20=EC=A0=84=EC=B2=B4=20tab=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/search/GroupSearchResult.tsx | 6 +-- src/pages/groupSearch/GroupSearch.tsx | 51 ++++++++++++++++----- 2 files changed, 42 insertions(+), 15 deletions(-) diff --git a/src/components/search/GroupSearchResult.tsx b/src/components/search/GroupSearchResult.tsx index 62696737..4861ba66 100644 --- a/src/components/search/GroupSearchResult.tsx +++ b/src/components/search/GroupSearchResult.tsx @@ -6,7 +6,7 @@ import { Filter } from '../common/Filter'; import type { SearchRoomItem } from '@/api/rooms/getSearchRooms'; const FILTER = ['마감임박순', '인기순']; -const CATEGORIES = ['문학', '과학·IT', '사회과학', '인문학', '예술'] as const; +const CATEGORIES = ['전체', '문학', '과학·IT', '사회과학', '인문학', '예술'] as const; type ResultType = 'searching' | 'searched'; @@ -60,12 +60,12 @@ const GroupSearchResult = ({ {showTabs && ( {CATEGORIES.map(tab => { - const selected = tab === currentCategory; + const selected = tab === currentCategory || (tab === '전체' && currentCategory === ''); return ( onChangeCategory(selected ? '' : tab)} + onClick={() => onChangeCategory(tab === '전체' ? '' : tab)} aria-pressed={selected} > {tab} diff --git a/src/pages/groupSearch/GroupSearch.tsx b/src/pages/groupSearch/GroupSearch.tsx index 064987e4..82a1d9f6 100644 --- a/src/pages/groupSearch/GroupSearch.tsx +++ b/src/pages/groupSearch/GroupSearch.tsx @@ -2,6 +2,7 @@ import TitleHeader from '@/components/common/TitleHeader'; import { Modal, Overlay } from '@/components/group/Modal.styles'; import leftArrow from '../../assets/common/leftArrow.svg'; import SearchBar from '@/components/search/SearchBar'; +import rightChevron from '../../assets/common/right-Chevron.svg'; import { useState, useEffect, useCallback, useRef } from 'react'; import RecentSearchTabs from '@/components/search/RecentSearchTabs'; import GroupSearchResult from '@/components/search/GroupSearchResult'; @@ -54,6 +55,13 @@ const GroupSearch = () => { })(); }, []); + // 검색 완료 시 전체 탭 선택 + useEffect(() => { + if (showTabs && searchStatus === 'searched') { + setCategory(''); + } + }, [showTabs, searchStatus]); + // searchStatus가 'idle'로 변경될 때 최근 검색어 새로고침 useEffect(() => { if (searchStatus === 'idle') { @@ -241,6 +249,8 @@ const GroupSearch = () => { } }; + const handleAllRoomsClick = () => {}; + useEffect(() => { return () => { if (searchTimeoutId) clearTimeout(searchTimeoutId); @@ -288,18 +298,24 @@ const GroupSearch = () => { )} ) : ( - i.searchTerm)} - handleDelete={async (term: string) => { - const x = recentSearches.find(i => i.searchTerm === term); - if (!x) return; - const res = await deleteRecentSearch(x.recentSearchId); - if (res.isSuccess) { - await fetchRecentSearches(); - } - }} - handleRecentSearchClick={handleRecentSearchClick} - /> + <> + i.searchTerm)} + handleDelete={async (term: string) => { + const x = recentSearches.find(i => i.searchTerm === term); + if (!x) return; + const res = await deleteRecentSearch(x.recentSearchId); + if (res.isSuccess) { + await fetchRecentSearches(); + } + }} + handleRecentSearchClick={handleRecentSearchClick} + /> + +

전체 모임방 둘러보기

+ 전체 모임방 버튼 +
+ )} @@ -316,3 +332,14 @@ const LoadingMessage = styled.div` color: ${colors.white}; font-size: ${typography.fontSize.base}; `; + +const AllRoomsButton = styled.div` + display: flex; + justify-content: space-between; + padding: 30px 20px; + background-color: transparent; + color: ${colors.grey[100]}; + font-size: ${typography.fontSize.lg}; + font-weight: ${typography.fontWeight.semibold}; + cursor: pointer; +`; From 1f15b584a1a891cb34039e47714bac8e63dac2d1 Mon Sep 17 00:00:00 2001 From: Ji Ho June <129824629+ho0010@users.noreply.github.com> Date: Sat, 20 Sep 2025 15:25:41 +0900 Subject: [PATCH 07/20] =?UTF-8?q?feat:=20=EB=AA=A8=EC=9E=84=EB=B0=A9=20?= =?UTF-8?q?=EA=B2=80=EC=83=89=20API=20isAllcategory=20=ED=8C=8C=EB=9D=BC?= =?UTF-8?q?=EB=AF=B8=ED=84=B0=20=EC=B6=94=EA=B0=80=EC=99=80=20=EC=A0=81?= =?UTF-8?q?=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/rooms/getSearchRooms.ts | 6 ++- src/pages/groupSearch/GroupSearch.tsx | 70 ++++++++++++++++++++++----- 2 files changed, 63 insertions(+), 13 deletions(-) diff --git a/src/api/rooms/getSearchRooms.ts b/src/api/rooms/getSearchRooms.ts index b0a81245..52cd052f 100644 --- a/src/api/rooms/getSearchRooms.ts +++ b/src/api/rooms/getSearchRooms.ts @@ -29,14 +29,18 @@ export const getSearchRooms = async ( cursor?: string, isFinalized: boolean = false, category: string = '', + isAllCategory: boolean = false, ): Promise => { try { const params = new URLSearchParams(); - params.append('keyword', keyword); + if (!isAllCategory && keyword) { + params.append('keyword', keyword); + } params.append('sort', sort); params.append('isFinalized', String(isFinalized)); if (cursor) params.append('cursor', cursor); if (category) params.append('category', category); + if (isAllCategory) params.append('isAllCategory', 'true'); const url = `/rooms/search?${params.toString()}`; const response = await apiClient.get(url); diff --git a/src/pages/groupSearch/GroupSearch.tsx b/src/pages/groupSearch/GroupSearch.tsx index 82a1d9f6..45daf0da 100644 --- a/src/pages/groupSearch/GroupSearch.tsx +++ b/src/pages/groupSearch/GroupSearch.tsx @@ -55,14 +55,12 @@ const GroupSearch = () => { })(); }, []); - // 검색 완료 시 전체 탭 선택 useEffect(() => { if (showTabs && searchStatus === 'searched') { setCategory(''); } }, [showTabs, searchStatus]); - // searchStatus가 'idle'로 변경될 때 최근 검색어 새로고침 useEffect(() => { if (searchStatus === 'idle') { fetchRecentSearches(); @@ -79,9 +77,12 @@ const GroupSearch = () => { }; const searchFirstPage = useCallback( - async (term: string, sortKey: SortKey, status: 'searching' | 'searched') => { - if (!term.trim()) return; - + async ( + term: string, + sortKey: SortKey, + status: 'searching' | 'searched', + isAllCategory: boolean = false, + ) => { setIsLoading(true); setError(null); setRooms([]); @@ -90,7 +91,14 @@ const GroupSearch = () => { try { const isFinalized = status === 'searched'; - const res = await getSearchRooms(term.trim(), sortKey, undefined, isFinalized, category); + const res = await getSearchRooms( + term.trim(), + sortKey, + undefined, + isFinalized, + category, + isAllCategory, + ); if (res.isSuccess) { const { roomList, nextCursor: nc, isLast: last } = res.data; @@ -157,29 +165,69 @@ const GroupSearch = () => { searchFirstPage(recent.trim(), toSortKey(selectedFilter), 'searched'); }; + const handleAllRoomsClick = () => { + if (searchTimeoutId) { + clearTimeout(searchTimeoutId); + setSearchTimeoutId(null); + } + setSearchTerm(''); + setSearchStatus('searched'); + setShowTabs(true); + setCategory(''); + searchFirstPage('', toSortKey(selectedFilter), 'searched', true); + }; + useEffect(() => { + if (searchStatus !== 'searched') return; + const term = searchTerm.trim(); - if (!term) return; + const isAllCategory = !term && category === ''; if (searchTimeoutId) { clearTimeout(searchTimeoutId); setSearchTimeoutId(null); } - setSearchStatus('searching'); - searchFirstPage(term, toSortKey(selectedFilter), 'searching'); - }, [selectedFilter, category, searchTerm, searchFirstPage, toSortKey, searchTimeoutId]); + + searchFirstPage(term, toSortKey(selectedFilter), 'searched', isAllCategory); + }, [ + selectedFilter, + category, + searchFirstPage, + toSortKey, + searchStatus, + searchTerm, + searchTimeoutId, + ]); + + // 입력 중일 때만 디바운싱 처리 + useEffect(() => { + const term = searchTerm.trim(); + if (!term || searchStatus !== 'searching') return; + + if (searchTimeoutId) { + clearTimeout(searchTimeoutId); + setSearchTimeoutId(null); + } + + const id = setTimeout(() => { + searchFirstPage(term, toSortKey(selectedFilter), 'searching'); + }, 300); + setSearchTimeoutId(id); + }, [searchTerm, searchFirstPage, toSortKey, selectedFilter, searchStatus, searchTimeoutId]); const loadMore = useCallback(async () => { if (!searchTerm.trim() || !nextCursor || isLast || isLoadingMore) return; try { setIsLoadingMore(true); const isFinalized = searchStatus === 'searched'; + const isAllCategory = !searchTerm.trim() && category === ''; const res = await getSearchRooms( searchTerm.trim(), toSortKey(selectedFilter), nextCursor, isFinalized, category, + isAllCategory, ); if (res.isSuccess) { const { roomList, nextCursor: nc, isLast: last } = res.data; @@ -249,8 +297,6 @@ const GroupSearch = () => { } }; - const handleAllRoomsClick = () => {}; - useEffect(() => { return () => { if (searchTimeoutId) clearTimeout(searchTimeoutId); From 1c14f5b800926c0d0f7038630a1a4821cf01fe30 Mon Sep 17 00:00:00 2001 From: Ji Ho June <129824629+ho0010@users.noreply.github.com> Date: Sat, 20 Sep 2025 16:01:09 +0900 Subject: [PATCH 08/20] feat: --- src/assets/common/searchChar.svg | 6 +++ src/pages/group/Group.tsx | 35 +++++++++++++- src/pages/groupSearch/GroupSearch.tsx | 69 ++++++++++++++------------- 3 files changed, 77 insertions(+), 33 deletions(-) create mode 100644 src/assets/common/searchChar.svg diff --git a/src/assets/common/searchChar.svg b/src/assets/common/searchChar.svg new file mode 100644 index 00000000..36253b39 --- /dev/null +++ b/src/assets/common/searchChar.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/pages/group/Group.tsx b/src/pages/group/Group.tsx index 5757722b..1419d217 100644 --- a/src/pages/group/Group.tsx +++ b/src/pages/group/Group.tsx @@ -11,7 +11,9 @@ 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'; import { getRoomsByCategory, type RoomItem } from '@/api/rooms/getRoomsByCategory'; +import { colors, typography } from '@/styles/global/global'; const convertRoomItemToGroup = ( room: RoomItem, @@ -83,6 +85,14 @@ const Group = () => { navigate('/group/search'); }; + const handleAllRoomsClick = () => { + navigate('/group/search', { + state: { + allRooms: true, + }, + }); + }; + return ( {isMyGroupModalOpen && } @@ -91,6 +101,10 @@ const Group = () => { + + 전체 모임방을 한 눈에 들러보세요! + 검색 캐릭터 이미지 + @@ -110,5 +124,24 @@ const Wrapper = styled.div` min-height: 100vh; margin: 0 auto; padding-top: 56px; - background-color: #121212; + background-color: ${colors.black.main}; +`; + +const AllRoomsButton = styled.div` + display: flex; + position: relative; + font-size: ${typography.fontSize.sm}; + font-weight: ${typography.fontWeight.medium}; + width: 83%; + border-radius: 12px; + padding: 14px 12px; + margin-bottom: 12px; + color: ${colors.white}; + background-color: ${colors.darkgrey.main}; + cursor: pointer; + > img { + position: absolute; + right: 5%; + top: -2px; + } `; diff --git a/src/pages/groupSearch/GroupSearch.tsx b/src/pages/groupSearch/GroupSearch.tsx index 45daf0da..8a5e26d1 100644 --- a/src/pages/groupSearch/GroupSearch.tsx +++ b/src/pages/groupSearch/GroupSearch.tsx @@ -11,13 +11,14 @@ import { deleteRecentSearch } from '@/api/recentsearch/deleteRecentSearch'; import { getSearchRooms, type SearchRoomItem } from '@/api/rooms/getSearchRooms'; import styled from '@emotion/styled'; import { colors, typography } from '@/styles/global/global'; -import { useNavigate } from 'react-router-dom'; +import { useNavigate, useLocation } from 'react-router-dom'; type SortKey = 'deadline' | 'memberCount'; type SearchStatus = 'idle' | 'searching' | 'searched'; const GroupSearch = () => { const navigate = useNavigate(); + const location = useLocation(); const [searchTerm, setSearchTerm] = useState(''); const [searchStatus, setSearchStatus] = useState('idle'); @@ -55,12 +56,6 @@ const GroupSearch = () => { })(); }, []); - useEffect(() => { - if (showTabs && searchStatus === 'searched') { - setCategory(''); - } - }, [showTabs, searchStatus]); - useEffect(() => { if (searchStatus === 'idle') { fetchRecentSearches(); @@ -81,6 +76,7 @@ const GroupSearch = () => { term: string, sortKey: SortKey, status: 'searching' | 'searched', + categoryParam: string, isAllCategory: boolean = false, ) => { setIsLoading(true); @@ -96,7 +92,7 @@ const GroupSearch = () => { sortKey, undefined, isFinalized, - category, + categoryParam, isAllCategory, ); if (res.isSuccess) { @@ -114,9 +110,19 @@ const GroupSearch = () => { setIsLoading(false); } }, - [category], + [], ); + useEffect(() => { + if (location.state?.allRooms) { + setSearchTerm(''); + setSearchStatus('searched'); + setShowTabs(true); + setCategory(''); + searchFirstPage('', toSortKey(selectedFilter), 'searched', '', true); + } + }, [location.state?.allRooms, searchFirstPage, selectedFilter, toSortKey]); + const handleChange = (value: string) => { setSearchTerm(value); if (searchTimeoutId) clearTimeout(searchTimeoutId); @@ -136,7 +142,7 @@ const GroupSearch = () => { setSearchStatus('searching'); setShowTabs(false); const id = setTimeout(() => { - searchFirstPage(trimmed, toSortKey(selectedFilter), 'searching'); + searchFirstPage(trimmed, toSortKey(selectedFilter), 'searching', category); }, 300); setSearchTimeoutId(id); }; @@ -151,7 +157,7 @@ const GroupSearch = () => { setSearchStatus('searched'); setShowTabs(true); - searchFirstPage(term, toSortKey(selectedFilter), 'searched'); + searchFirstPage(term, toSortKey(selectedFilter), 'searched', category); }; const handleRecentSearchClick = (recent: string) => { @@ -162,7 +168,7 @@ const GroupSearch = () => { setSearchTerm(recent); setSearchStatus('searched'); setShowTabs(true); - searchFirstPage(recent.trim(), toSortKey(selectedFilter), 'searched'); + searchFirstPage(recent.trim(), toSortKey(selectedFilter), 'searched', category); }; const handleAllRoomsClick = () => { @@ -174,32 +180,30 @@ const GroupSearch = () => { setSearchStatus('searched'); setShowTabs(true); setCategory(''); - searchFirstPage('', toSortKey(selectedFilter), 'searched', true); + searchFirstPage('', toSortKey(selectedFilter), 'searched', '', true); }; + const searchStatusRef = useRef(searchStatus); + const categoryRef = useRef(category); + const selectedFilterRef = useRef(selectedFilter); + const searchTermRef = useRef(searchTerm); + + useEffect(() => { + searchStatusRef.current = searchStatus; + categoryRef.current = category; + selectedFilterRef.current = selectedFilter; + searchTermRef.current = searchTerm; + }); + useEffect(() => { if (searchStatus !== 'searched') return; - const term = searchTerm.trim(); + const term = searchTermRef.current.trim(); const isAllCategory = !term && category === ''; - if (searchTimeoutId) { - clearTimeout(searchTimeoutId); - setSearchTimeoutId(null); - } - - searchFirstPage(term, toSortKey(selectedFilter), 'searched', isAllCategory); - }, [ - selectedFilter, - category, - searchFirstPage, - toSortKey, - searchStatus, - searchTerm, - searchTimeoutId, - ]); + searchFirstPage(term, toSortKey(selectedFilter), 'searched', category, isAllCategory); + }, [selectedFilter, category, searchFirstPage, searchStatus, toSortKey]); - // 입력 중일 때만 디바운싱 처리 useEffect(() => { const term = searchTerm.trim(); if (!term || searchStatus !== 'searching') return; @@ -210,10 +214,11 @@ const GroupSearch = () => { } const id = setTimeout(() => { - searchFirstPage(term, toSortKey(selectedFilter), 'searching'); + const currentCategory = categoryRef.current; + searchFirstPage(term, toSortKey(selectedFilter), 'searching', currentCategory); }, 300); setSearchTimeoutId(id); - }, [searchTerm, searchFirstPage, toSortKey, selectedFilter, searchStatus, searchTimeoutId]); + }, [searchTerm, searchStatus, searchFirstPage, searchTimeoutId, selectedFilter, toSortKey]); const loadMore = useCallback(async () => { if (!searchTerm.trim() || !nextCursor || isLast || isLoadingMore) return; From 8bb9bd9665476ec5c644243464907f0a57f41df8 Mon Sep 17 00:00:00 2001 From: Ji Ho June <129824629+ho0010@users.noreply.github.com> Date: Sat, 20 Sep 2025 16:10:17 +0900 Subject: [PATCH 09/20] =?UTF-8?q?design:=20=EB=AA=A8=EC=9E=84=20=EC=83=81?= =?UTF-8?q?=EC=84=B8=20=ED=8E=98=EC=9D=B4=EC=A7=80=20=EC=B0=B8=EC=97=AC?= =?UTF-8?q?=ED=95=98=EA=B8=B0=20=EB=B2=84=ED=8A=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/groupDetail/GroupDetail.styled.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/pages/groupDetail/GroupDetail.styled.ts b/src/pages/groupDetail/GroupDetail.styled.ts index dd576b5b..b2d8f54c 100644 --- a/src/pages/groupDetail/GroupDetail.styled.ts +++ b/src/pages/groupDetail/GroupDetail.styled.ts @@ -276,4 +276,9 @@ export const BottomButton = styled.button` border: none; z-index: 10; cursor: pointer; + + &:disabled { + background-color: ${colors.grey[300]}; + cursor: not-allowed; + } `; From cff12535dd3c52aa272672511288159c5b9ce1ed Mon Sep 17 00:00:00 2001 From: Ji Ho June <129824629+ho0010@users.noreply.github.com> Date: Sat, 20 Sep 2025 16:13:18 +0900 Subject: [PATCH 10/20] =?UTF-8?q?design:=20modal=20=ED=97=A4=EB=8D=94?= =?UTF-8?q?=EC=99=80=20=EB=B3=B8=EB=AC=B8=20=EA=B0=84=EA=B2=A9=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/group/CompletedGroupModal.tsx | 2 +- src/components/group/MyGroupModal.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/group/CompletedGroupModal.tsx b/src/components/group/CompletedGroupModal.tsx index 6c222d54..afa624ab 100644 --- a/src/components/group/CompletedGroupModal.tsx +++ b/src/components/group/CompletedGroupModal.tsx @@ -103,7 +103,7 @@ const Text = styled.p` font-size: ${typography.fontSize.sm}; font-weight: ${typography.fontWeight.regular}; color: ${colors.white}; - margin: 96px 20px 20px 20px; + margin: 20px; `; const Content = styled.div<{ isEmpty?: boolean }>` diff --git a/src/components/group/MyGroupModal.tsx b/src/components/group/MyGroupModal.tsx index 097c7092..caa763c6 100644 --- a/src/components/group/MyGroupModal.tsx +++ b/src/components/group/MyGroupModal.tsx @@ -255,7 +255,7 @@ export const MyGroupModal = ({ onClose }: MyGroupModalProps) => { const TabContainer = styled.div` display: flex; gap: 8px; - margin: 76px 20px 20px 20px; + margin: 20px; `; const Tab = styled.button<{ selected: boolean }>` From 2c8a0eb47100188d5d8c4bd6d94edca9ca61b9f0 Mon Sep 17 00:00:00 2001 From: Ji Ho June <129824629+ho0010@users.noreply.github.com> Date: Sat, 20 Sep 2025 16:56:20 +0900 Subject: [PATCH 11/20] =?UTF-8?q?design:=20MyGroupCard=20=EC=B0=B8?= =?UTF-8?q?=EC=97=AC=20=EC=9D=B8=EC=9B=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/group/MyGroupCard.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/group/MyGroupCard.tsx b/src/components/group/MyGroupCard.tsx index 573a6070..f1e388a4 100644 --- a/src/components/group/MyGroupCard.tsx +++ b/src/components/group/MyGroupCard.tsx @@ -20,7 +20,7 @@ export const MyGroupCard = forwardRef((props, {group.title} - {group.participants}명 참여 + {group.participants}명
@@ -80,7 +80,7 @@ const Participants = styled.p` display: flex; align-items: center; gap: 4px; - font-size: ${typography.fontSize.xs}; + font-size: ${typography.fontSize.sm}; font-weight: ${typography.fontWeight.medium}; color: ${colors.grey[300]}; margin: 8px 0; From dc1444f69d890c4b946fae6eec5b58aac706f214 Mon Sep 17 00:00:00 2001 From: Ji Ho June <129824629+ho0010@users.noreply.github.com> Date: Sat, 20 Sep 2025 17:13:22 +0900 Subject: [PATCH 12/20] =?UTF-8?q?feat:=20MyGroupCard=20=EB=B6=84=EA=B8=B0?= =?UTF-8?q?=EC=B2=98=EB=A6=AC=20=EA=B8=B0=ED=9A=8D=20=EB=94=94=EC=9E=90?= =?UTF-8?q?=EC=9D=B8=20=EC=9A=94=EA=B5=AC=EC=82=AC=ED=95=AD=EC=97=90=20?= =?UTF-8?q?=EB=94=B0=EB=9D=BC=20=EB=AA=A8=EC=A7=91=EC=A4=91=EC=9D=B8=20?= =?UTF-8?q?=EB=AA=A8=EC=9E=84=EB=B0=A9=EB=8F=84=20=ED=91=9C=EA=B8=B0?= =?UTF-8?q?=ED=95=98=EB=8F=84=EB=A1=9D=20=EB=B3=80=EA=B2=BD=20=EB=90=98?= =?UTF-8?q?=EC=97=88=EA=B3=A0=20=EA=B7=B8=EC=97=90=20=EB=94=B0=EB=A5=B8=20?= =?UTF-8?q?=EB=B6=84=EA=B8=B0=EC=B2=98=EB=A6=AC=20=EB=A1=9C=EC=A7=81=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/rooms/getJoinedRooms.ts | 2 +- src/components/group/MyGroupBox.tsx | 1 + src/components/group/MyGroupCard.tsx | 37 ++++++++++++++++++++++------ 3 files changed, 32 insertions(+), 8 deletions(-) diff --git a/src/api/rooms/getJoinedRooms.ts b/src/api/rooms/getJoinedRooms.ts index fb104d1b..175df941 100644 --- a/src/api/rooms/getJoinedRooms.ts +++ b/src/api/rooms/getJoinedRooms.ts @@ -1,12 +1,12 @@ import { apiClient } from '../index'; -// 가입한 방 목록 응답 데이터 타입 export interface JoinedRoomItem { roomId: number; bookImageUrl: string; roomTitle: string; memberCount: number; userPercentage: number; + deadlineDate?: string | null; } export interface JoinedRoomsResponse { diff --git a/src/components/group/MyGroupBox.tsx b/src/components/group/MyGroupBox.tsx index 05328dc2..2640a387 100644 --- a/src/components/group/MyGroupBox.tsx +++ b/src/components/group/MyGroupBox.tsx @@ -28,6 +28,7 @@ const convertJoinedRoomToGroup = (room: JoinedRoomItem): Group => ({ participants: room.memberCount, coverUrl: room.bookImageUrl, progress: room.userPercentage, + deadLine: room.deadlineDate || undefined, }); interface MyGroupProps { diff --git a/src/components/group/MyGroupCard.tsx b/src/components/group/MyGroupCard.tsx index f1e388a4..c9cdde8c 100644 --- a/src/components/group/MyGroupCard.tsx +++ b/src/components/group/MyGroupCard.tsx @@ -12,6 +12,8 @@ interface MyGroupCardProps { export const MyGroupCard = forwardRef((props, ref) => { const { group, onClick, isMine } = props; + const hasDeadline = group.deadLine != null; + return ( @@ -24,13 +26,21 @@ export const MyGroupCard = forwardRef((props,
- - {isMine ? '내 진행도' : `${group.userName}님의 진행도`}{' '} - {Math.floor(group.progress || 0)}% - - - - + {hasDeadline ? ( + + 시작까지 {group.deadLine} + + ) : ( + <> + + {isMine ? '내 진행도' : `${group.userName}님의 진행도`}{' '} + {Math.floor(group.progress || 0)}% + + + + + + )}
@@ -101,6 +111,19 @@ const Percent = styled.span` font-weight: ${typography.fontWeight.semibold}; `; +const DeadlineText = styled.p` + font-size: ${typography.fontSize.sm}; + color: ${colors.grey[300]}; + margin: 12px 0; +`; + +const DeadlineValue = styled.span` + font-size: ${typography.fontSize.base}; + color: ${colors.purple.main}; + font-weight: ${typography.fontWeight.semibold}; + margin-left: 4px; +`; + const Bar = styled.div` width: 100%; height: 6px; From 5a4776470a040b0dd31dc8302c127621d2ed2fbd Mon Sep 17 00:00:00 2001 From: Ji Ho June <129824629+ho0010@users.noreply.github.com> Date: Sat, 20 Sep 2025 17:23:24 +0900 Subject: [PATCH 13/20] =?UTF-8?q?feat:=20group=20=EB=AA=A8=EC=9E=84?= =?UTF-8?q?=EB=B0=A9=20=EC=B6=94=EC=B2=9C=20=EC=BA=90=EB=9F=AC=EC=85=80=20?= =?UTF-8?q?=ED=95=AD=EB=AA=A9=20=EB=B3=80=EA=B2=BD=20=EC=B5=9C=EA=B7=BC=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1=EB=90=9C=20=EB=8F=85=EC=84=9C=20=EB=AA=A8?= =?UTF-8?q?=EC=9E=84=EB=B0=A9=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/rooms/getRoomsByCategory.ts | 1 + src/components/group/RecruitingGroupCarousel.tsx | 1 - src/pages/group/Group.tsx | 10 +++++++++- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/api/rooms/getRoomsByCategory.ts b/src/api/rooms/getRoomsByCategory.ts index b2c55583..55db5df3 100644 --- a/src/api/rooms/getRoomsByCategory.ts +++ b/src/api/rooms/getRoomsByCategory.ts @@ -17,6 +17,7 @@ export interface RoomsResponse { data: { deadlineRoomList: RoomItem[]; popularRoomList: RoomItem[]; + recentRoomList: RoomItem[]; }; } diff --git a/src/components/group/RecruitingGroupCarousel.tsx b/src/components/group/RecruitingGroupCarousel.tsx index ba16b701..8d63f97e 100644 --- a/src/components/group/RecruitingGroupCarousel.tsx +++ b/src/components/group/RecruitingGroupCarousel.tsx @@ -112,5 +112,4 @@ const Item = styled.div` max-width: 640px; scroll-snap-align: center; transition: transform 0.2s; - /* height: 800px; */ `; diff --git a/src/pages/group/Group.tsx b/src/pages/group/Group.tsx index 1419d217..21d1b4bd 100644 --- a/src/pages/group/Group.tsx +++ b/src/pages/group/Group.tsx @@ -18,7 +18,7 @@ import { colors, typography } from '@/styles/global/global'; const convertRoomItemToGroup = ( room: RoomItem, category: string, - listType: 'deadline' | 'popular', + listType: 'deadline' | 'popular' | 'recent', ): GroupType => ({ id: `${room.roomId}-${category}-${listType}`, title: room.roomName, @@ -34,6 +34,7 @@ const Group = () => { const [isMyGroupModalOpen, setIsMyGroupModalOpen] = useState(false); const [isCompletedGroupModalOpen, setIsCompletedGroupModalOpen] = useState(false); const [sections, setSections] = useState([ + { title: '최근 생성된 독서 모임방', groups: [] }, { title: '마감 임박한 독서 모임방', groups: [] }, { title: '인기 있는 독서 모임방', groups: [] }, ]); @@ -43,6 +44,7 @@ const Group = () => { const categories = ['문학', '인문학', '사회과학', '과학·IT', '예술']; const deadlineRoomsData: GroupType[] = []; const popularRoomsData: GroupType[] = []; + const recentRoomsData: GroupType[] = []; for (const category of categories) { const response = await getRoomsByCategory(category); @@ -53,18 +55,24 @@ const Group = () => { const popularGroups = response.data.popularRoomList.map(room => convertRoomItemToGroup(room, category, 'popular'), ); + const recentGroups = response.data.recentRoomList.map(room => + convertRoomItemToGroup(room, category, 'recent'), + ); deadlineRoomsData.push(...deadlineGroups); popularRoomsData.push(...popularGroups); + recentRoomsData.push(...recentGroups); } } setSections([ + { title: '최근 생성된 독서 모임방', groups: recentRoomsData }, { title: '마감 임박한 독서 모임방', groups: deadlineRoomsData }, { title: '인기 있는 독서 모임방', groups: popularRoomsData }, ]); } catch (error) { console.error('방 목록 조회 오류:', error); setSections([ + { title: '최근 생성된 독서 모임방', groups: [] }, { title: '마감 임박한 독서 모임방', groups: [] }, { title: '인기 있는 독서 모임방', groups: [] }, ]); From 4177fd91ebeba1e1727e193c778f70965a007d88 Mon Sep 17 00:00:00 2001 From: Ji Ho June <129824629+ho0010@users.noreply.github.com> Date: Sat, 20 Sep 2025 17:28:55 +0900 Subject: [PATCH 14/20] =?UTF-8?q?feat:=20group=20=ED=95=98=EB=8B=A8=20?= =?UTF-8?q?=EC=BA=90=EB=9F=AC=EC=85=80=20=EB=A6=AC=EC=82=AC=EC=9D=B4?= =?UTF-8?q?=EC=A6=88=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/group/RecruitingGroupCarousel.tsx | 10 ++++++++++ src/hooks/useInfiniteCarousel.ts | 9 ++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/components/group/RecruitingGroupCarousel.tsx b/src/components/group/RecruitingGroupCarousel.tsx index 8d63f97e..b983bd82 100644 --- a/src/components/group/RecruitingGroupCarousel.tsx +++ b/src/components/group/RecruitingGroupCarousel.tsx @@ -105,11 +105,21 @@ const ScrollWrapper = styled.div` &::-webkit-scrollbar { display: none; } + + @media (max-width: 480px) { + padding: 15px 10px; + } `; const Item = styled.div` flex: 0 0 90%; max-width: 640px; + min-width: 280px; scroll-snap-align: center; transition: transform 0.2s; + + @media (max-width: 480px) { + flex: 0 0 85%; + min-width: 260px; + } `; diff --git a/src/hooks/useInfiniteCarousel.ts b/src/hooks/useInfiniteCarousel.ts index 47c04504..fa53ed14 100644 --- a/src/hooks/useInfiniteCarousel.ts +++ b/src/hooks/useInfiniteCarousel.ts @@ -68,12 +68,19 @@ export function useInfiniteCarousel(groups: Group[], options?: { scaleAmount?: n handleScroll(); }; - const timer = setTimeout(initializeScroll, 0); + const timer = setTimeout(initializeScroll, 100); + + const handleResize = () => { + setTimeout(initializeScroll, 50); + }; + container.addEventListener('scroll', handleScroll, { passive: true }); + window.addEventListener('resize', handleResize); return () => { clearTimeout(timer); container.removeEventListener('scroll', handleScroll); + window.removeEventListener('resize', handleResize); }; }, [infiniteGroups.length, handleScroll, middleIndex]); From 92e455ddafa9fc5c49284372f29b4d8034ceff74 Mon Sep 17 00:00:00 2001 From: Ji Ho June <129824629+ho0010@users.noreply.github.com> Date: Sat, 20 Sep 2025 17:59:21 +0900 Subject: [PATCH 15/20] =?UTF-8?q?design:=20=EB=AA=A8=EC=A7=91=EC=A4=91?= =?UTF-8?q?=EC=9D=B8=20=EA=B7=B8=EB=A3=B9=20=EC=BA=90=EB=9F=AC=EC=85=80=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=20=EB=94=94=EC=9E=90=EC=9D=B8=20=EC=9A=94?= =?UTF-8?q?=EA=B5=AC=EC=82=AC=ED=95=AD=EC=97=90=20=EB=94=B0=EB=9D=BC=20Tab?= =?UTF-8?q?=20=EC=9A=94=EC=86=8C=20=EB=B0=B0=EC=B9=98=20=EA=B0=9C=EC=88=98?= =?UTF-8?q?=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/group/RecruitingGroupBox.tsx | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/components/group/RecruitingGroupBox.tsx b/src/components/group/RecruitingGroupBox.tsx index b46a6fac..bc988d75 100644 --- a/src/components/group/RecruitingGroupBox.tsx +++ b/src/components/group/RecruitingGroupBox.tsx @@ -98,9 +98,15 @@ const Title = styled.h2` const TabContainer = styled.div` display: flex; flex-wrap: wrap; - gap: 4px; + gap: 8px; justify-content: center; margin-bottom: 24px; + + @media (max-width: 373px) { + max-width: 240px; + margin-left: auto; + margin-right: auto; + } `; const Tab = styled.button<{ selected?: boolean }>` From e8b6d97fdc51100e4889009e2264ce3f0f214e50 Mon Sep 17 00:00:00 2001 From: Ji Ho June <129824629+ho0010@users.noreply.github.com> Date: Sun, 21 Sep 2025 16:39:11 +0900 Subject: [PATCH 16/20] =?UTF-8?q?feat:=20=EB=AA=A8=EC=A7=91=EC=A4=91?= =?UTF-8?q?=EC=9D=B8=20=EB=AA=A8=EC=9E=84=EB=B0=A9=20=EC=BA=90=EB=9F=AC?= =?UTF-8?q?=EC=85=80=20=EB=B2=84=ED=8A=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/assets/common/back.svg | 4 ++ src/assets/common/next.svg | 4 ++ .../group/RecruitingGroupCarousel.tsx | 59 +++++++++++++++++++ 3 files changed, 67 insertions(+) create mode 100644 src/assets/common/back.svg create mode 100644 src/assets/common/next.svg diff --git a/src/assets/common/back.svg b/src/assets/common/back.svg new file mode 100644 index 00000000..7ae15c91 --- /dev/null +++ b/src/assets/common/back.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/assets/common/next.svg b/src/assets/common/next.svg new file mode 100644 index 00000000..643f06ca --- /dev/null +++ b/src/assets/common/next.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/components/group/RecruitingGroupCarousel.tsx b/src/components/group/RecruitingGroupCarousel.tsx index b983bd82..718ede42 100644 --- a/src/components/group/RecruitingGroupCarousel.tsx +++ b/src/components/group/RecruitingGroupCarousel.tsx @@ -2,6 +2,8 @@ import styled from '@emotion/styled'; import type { Group } from './MyGroupBox'; import { RecruitingGroupBox } from './RecruitingGroupBox'; import { useInfiniteCarousel } from '@/hooks/useInfiniteCarousel'; +import backIcon from '@/assets/common/back.svg'; +import nextIcon from '@/assets/common/next.svg'; export interface Section { title: string; @@ -61,8 +63,30 @@ export function RecruitingGroupCarousel({ sections }: Props) { isDragging = false; }; + const handlePrevClick = () => { + if (scrollRef.current) { + const container = scrollRef.current; + const cardWidth = cardRefs.current[0]?.offsetWidth || 0; + container.scrollLeft -= cardWidth + 20; + } + }; + + const handleNextClick = () => { + if (scrollRef.current) { + const container = scrollRef.current; + const cardWidth = cardRefs.current[0]?.offsetWidth || 0; + container.scrollLeft += cardWidth + 20; + } + }; + return ( + + 이전 + + + 다음 + Date: Sun, 21 Sep 2025 16:48:53 +0900 Subject: [PATCH 17/20] =?UTF-8?q?feat:=20group=20=EB=82=B4=20=EB=AA=A8?= =?UTF-8?q?=EC=9E=84=EB=B0=A9=20=EC=BA=90=EB=9F=AC=EC=85=80=20=EB=B2=84?= =?UTF-8?q?=ED=8A=BC=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/group/MyGroupBox.tsx | 71 ++++++++++++++++++++++++++++- 1 file changed, 69 insertions(+), 2 deletions(-) diff --git a/src/components/group/MyGroupBox.tsx b/src/components/group/MyGroupBox.tsx index 2640a387..5dc9659e 100644 --- a/src/components/group/MyGroupBox.tsx +++ b/src/components/group/MyGroupBox.tsx @@ -2,6 +2,8 @@ import { MyGroupCard } from './MyGroupCard'; import { useInfiniteCarousel } from '../../hooks/useInfiniteCarousel'; import styled from '@emotion/styled'; import rightChevron from '../../assets/common/right-Chevron.svg'; +import backIcon from '@/assets/common/back.svg'; +import nextIcon from '@/assets/common/next.svg'; import { useState, useEffect } from 'react'; import { useNavigate } from 'react-router-dom'; import { getJoinedRooms, type JoinedRoomItem } from '@/api/rooms/getJoinedRooms'; @@ -109,6 +111,22 @@ export function MyGroupBox({ onMyGroupsClick }: MyGroupProps) { isDragging = false; }; + const handlePrevClick = () => { + if (scrollRef.current) { + const container = scrollRef.current; + const cardWidth = cardRefs.current[0]?.offsetWidth || 0; + container.scrollLeft -= cardWidth + 12; + } + }; + + const handleNextClick = () => { + if (scrollRef.current) { + const container = scrollRef.current; + const cardWidth = cardRefs.current[0]?.offsetWidth || 0; + container.scrollLeft += cardWidth + 12; + } + }; + return (
@@ -126,7 +144,17 @@ export function MyGroupBox({ onMyGroupsClick }: MyGroupProps) { {error} ) : groups.length > 0 ? ( - <> + + {!isSingle && ( + <> + + 이전 + + + 다음 + + + )} {isSingle ? ( )} - + ) : ( @@ -209,6 +237,45 @@ const MoreButton = styled.button` } `; +const CarouselContainer = styled.div` + position: relative; + width: 100%; + + &:hover .nav-button { + opacity: 1; + visibility: visible; + } +`; + +const NavButton = styled.button` + position: absolute; + top: 50%; + transform: translateY(-50%); + z-index: 10; + border-radius: 50%; + border: none; + background: transparent; + cursor: pointer; + visibility: hidden; + transition: all 0.1s ease; + + &.prev { + left: 4%; + } + + &.next { + right: 4%; + } + + img { + filter: invert(1); + } + + @media (max-width: 768px) { + display: none; + } +`; + const Carousel = styled.div` display: flex; padding: 0; From bdb69d17b126093728755484a32508a5ff3164b6 Mon Sep 17 00:00:00 2001 From: Ji Ho June <129824629+ho0010@users.noreply.github.com> Date: Sun, 21 Sep 2025 23:23:03 +0900 Subject: [PATCH 18/20] =?UTF-8?q?fix:=20=EB=B0=A9=20=EC=83=81=EC=84=B8?= =?UTF-8?q?=EB=B3=B4=EA=B8=B0=20=EC=97=94=EB=93=9C=ED=8F=AC=EC=9D=B8?= =?UTF-8?q?=ED=8A=B8=20=EB=B3=80=EA=B2=BD=20=EC=A0=81=EC=9A=A9=20BE=20API?= =?UTF-8?q?=20=EC=88=98=EC=A0=95=EC=82=AC=ED=95=AD=EC=97=90=20=EB=94=B0?= =?UTF-8?q?=EB=9D=BC=20=EC=97=94=EB=93=9C=ED=8F=AC=EC=9D=B8=ED=8A=B8?= =?UTF-8?q?=EB=A5=BC=20=EB=B3=80=EA=B2=BD=ED=96=88=EC=8A=B5=EB=8B=88?= =?UTF-8?q?=EB=8B=A4.=20=EB=98=90=ED=95=9C,=20=ED=81=B4=EB=A6=AD=EC=9D=B4?= =?UTF-8?q?=EB=B2=A4=ED=8A=B8=20=EB=B6=84=EA=B8=B0=EC=B2=98=EB=A6=AC=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=EC=9D=84=20=EC=B6=94=EA=B0=80=ED=96=88?= =?UTF-8?q?=EC=8A=B5=EB=8B=88=EB=8B=A4.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/rooms/getRoomDetail.ts | 6 +++--- src/api/rooms/getRoomPlaying.ts | 6 +++--- src/components/group/MyGroupCard.tsx | 12 +++++++++++- 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/api/rooms/getRoomDetail.ts b/src/api/rooms/getRoomDetail.ts index 079a862f..fa3567c1 100644 --- a/src/api/rooms/getRoomDetail.ts +++ b/src/api/rooms/getRoomDetail.ts @@ -45,19 +45,19 @@ export const getRoomDetail = async (roomId: number): Promise return response.data; } catch (error: unknown) { console.error('방 상세 정보 조회 API 오류:', error); - + if (error instanceof AxiosError) { // 모집기간이 만료된 방인 경우 if (error.response?.data?.code === 100004) { throw new Error('모집기간이 만료된 방입니다.'); } - + // 방 접근 권한이 없는 경우 if (error.response?.data?.code === 140011) { throw new Error('방 접근 권한이 없습니다.'); } } - + throw error; } }; diff --git a/src/api/rooms/getRoomPlaying.ts b/src/api/rooms/getRoomPlaying.ts index d21d0c72..1cd00281 100644 --- a/src/api/rooms/getRoomPlaying.ts +++ b/src/api/rooms/getRoomPlaying.ts @@ -64,16 +64,16 @@ export const convertVotesToPolls = (currentVotes: CurrentVote[]): Poll[] => { export const getRoomPlaying = async (roomId: number): Promise => { try { - const response = await apiClient.get(`/rooms/${roomId}/playing`); + const response = await apiClient.get(`/rooms/${roomId}`); return response.data; } catch (error: unknown) { console.error('진행중인 방 상세 정보 조회 API 오류:', error); - + // 방 접근 권한이 없는 경우 if (error instanceof AxiosError && error.response?.data?.code === 140011) { throw new Error('방 접근 권한이 없습니다.'); } - + throw error; } }; diff --git a/src/components/group/MyGroupCard.tsx b/src/components/group/MyGroupCard.tsx index c9cdde8c..46e9490b 100644 --- a/src/components/group/MyGroupCard.tsx +++ b/src/components/group/MyGroupCard.tsx @@ -3,6 +3,7 @@ import styled from '@emotion/styled'; import peopleImg from '../../assets/common/people.svg'; import type { Group } from './MyGroupBox'; import { colors, typography } from '@/styles/global/global'; +import { useNavigate } from 'react-router-dom'; interface MyGroupCardProps { group: Group; @@ -12,10 +13,19 @@ interface MyGroupCardProps { export const MyGroupCard = forwardRef((props, ref) => { const { group, onClick, isMine } = props; + const navigate = useNavigate(); const hasDeadline = group.deadLine != null; + const handleClick = () => { + if (hasDeadline) { + navigate(`/group/detail/${group.id}`); + } else { + onClick?.(); + } + }; + return ( - +
From 5eff73b76d268a2e8a8e8862c9aec7ee427509a2 Mon Sep 17 00:00:00 2001 From: Ji Ho June <129824629+ho0010@users.noreply.github.com> Date: Sun, 21 Sep 2025 23:33:49 +0900 Subject: [PATCH 19/20] =?UTF-8?q?fix:=20=EA=B7=B8=EB=A3=B9=20=EA=B2=80?= =?UTF-8?q?=EC=83=89=20=EB=B2=84=EA=B7=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/groupSearch/GroupSearch.tsx | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/src/pages/groupSearch/GroupSearch.tsx b/src/pages/groupSearch/GroupSearch.tsx index 8a5e26d1..054a5007 100644 --- a/src/pages/groupSearch/GroupSearch.tsx +++ b/src/pages/groupSearch/GroupSearch.tsx @@ -202,7 +202,8 @@ const GroupSearch = () => { const isAllCategory = !term && category === ''; searchFirstPage(term, toSortKey(selectedFilter), 'searched', category, isAllCategory); - }, [selectedFilter, category, searchFirstPage, searchStatus, toSortKey]); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [selectedFilter, category, searchStatus]); useEffect(() => { const term = searchTerm.trim(); @@ -218,7 +219,8 @@ const GroupSearch = () => { searchFirstPage(term, toSortKey(selectedFilter), 'searching', currentCategory); }, 300); setSearchTimeoutId(id); - }, [searchTerm, searchStatus, searchFirstPage, searchTimeoutId, selectedFilter, toSortKey]); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [searchTerm, searchStatus, selectedFilter]); const loadMore = useCallback(async () => { if (!searchTerm.trim() || !nextCursor || isLast || isLoadingMore) return; @@ -248,16 +250,8 @@ const GroupSearch = () => { } finally { setIsLoadingMore(false); } - }, [ - searchTerm, - nextCursor, - isLast, - isLoadingMore, - selectedFilter, - toSortKey, - searchStatus, - category, - ]); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [searchTerm, nextCursor, isLast, isLoadingMore, selectedFilter, searchStatus, category]); const lastRoomElementCallback = useCallback( (node: HTMLDivElement | null) => { From 64720d0227a7686d02ed7cd2f5df38ae6a6b8a02 Mon Sep 17 00:00:00 2001 From: Ji Ho June <129824629+ho0010@users.noreply.github.com> Date: Mon, 22 Sep 2025 10:49:42 +0900 Subject: [PATCH 20/20] =?UTF-8?q?fix:=20=EC=A4=91=EB=B3=B5=20=EA=B2=80?= =?UTF-8?q?=EC=83=89=20=EC=9A=94=EC=B2=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/groupSearch/GroupSearch.tsx | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/pages/groupSearch/GroupSearch.tsx b/src/pages/groupSearch/GroupSearch.tsx index 054a5007..ce8199a2 100644 --- a/src/pages/groupSearch/GroupSearch.tsx +++ b/src/pages/groupSearch/GroupSearch.tsx @@ -115,13 +115,14 @@ const GroupSearch = () => { useEffect(() => { if (location.state?.allRooms) { + navigate(location.pathname, { replace: true }); + setSearchTerm(''); setSearchStatus('searched'); setShowTabs(true); setCategory(''); - searchFirstPage('', toSortKey(selectedFilter), 'searched', '', true); } - }, [location.state?.allRooms, searchFirstPage, selectedFilter, toSortKey]); + }, [location.state?.allRooms, navigate, location.pathname]); const handleChange = (value: string) => { setSearchTerm(value); @@ -157,7 +158,6 @@ const GroupSearch = () => { setSearchStatus('searched'); setShowTabs(true); - searchFirstPage(term, toSortKey(selectedFilter), 'searched', category); }; const handleRecentSearchClick = (recent: string) => { @@ -168,7 +168,6 @@ const GroupSearch = () => { setSearchTerm(recent); setSearchStatus('searched'); setShowTabs(true); - searchFirstPage(recent.trim(), toSortKey(selectedFilter), 'searched', category); }; const handleAllRoomsClick = () => { @@ -180,7 +179,6 @@ const GroupSearch = () => { setSearchStatus('searched'); setShowTabs(true); setCategory(''); - searchFirstPage('', toSortKey(selectedFilter), 'searched', '', true); }; const searchStatusRef = useRef(searchStatus); @@ -198,12 +196,12 @@ const GroupSearch = () => { useEffect(() => { if (searchStatus !== 'searched') return; - const term = searchTermRef.current.trim(); + const term = searchTerm.trim(); const isAllCategory = !term && category === ''; searchFirstPage(term, toSortKey(selectedFilter), 'searched', category, isAllCategory); // eslint-disable-next-line react-hooks/exhaustive-deps - }, [selectedFilter, category, searchStatus]); + }, [selectedFilter, category, searchStatus, searchTerm]); useEffect(() => { const term = searchTerm.trim();