From 42a835d7e73cd4ab2cd690efdef3a2ad4fd884f0 Mon Sep 17 00:00:00 2001
From: Ji Ho June <129824629+ho0010@users.noreply.github.com>
Date: Thu, 21 Aug 2025 00:28:29 +0900
Subject: [PATCH 1/7] =?UTF-8?q?fix:=20mostSearchedBooks=20=EC=9D=B4?=
=?UTF-8?q?=EB=AF=B8=EC=A7=80=20=EB=B0=80=EB=A6=BC=20=EC=88=98=EC=A0=95?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/components/search/MostSearchedBooks.tsx | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/src/components/search/MostSearchedBooks.tsx b/src/components/search/MostSearchedBooks.tsx
index 2cb711cb..8f702499 100644
--- a/src/components/search/MostSearchedBooks.tsx
+++ b/src/components/search/MostSearchedBooks.tsx
@@ -143,7 +143,9 @@ const BookTitle = styled.span`
overflow: hidden;
text-overflow: ellipsis;
margin-left: 8px;
- flex-shrink: 1;
+ flex: 1 1 0%;
+ min-width: 0;
+ max-width: calc(100% - 77px);
`;
const EmptyMessage = styled.div`
From a4a8fc1b383156bdeb8bd36394aa3573b7c52d87 Mon Sep 17 00:00:00 2001
From: Ji Ho June <129824629+ho0010@users.noreply.github.com>
Date: Thu, 21 Aug 2025 00:47:45 +0900
Subject: [PATCH 2/7] =?UTF-8?q?fix:=20filledSaveIcon=20=EA=B5=90=EC=B2=B4?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/assets/common/filledSaveIcon.svg | 4 ++--
src/pages/searchBook/SearchBook.styled.ts | 4 ++--
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/assets/common/filledSaveIcon.svg b/src/assets/common/filledSaveIcon.svg
index 9fffb2da..5aee517d 100644
--- a/src/assets/common/filledSaveIcon.svg
+++ b/src/assets/common/filledSaveIcon.svg
@@ -1,4 +1,4 @@
diff --git a/src/pages/searchBook/SearchBook.styled.ts b/src/pages/searchBook/SearchBook.styled.ts
index a9baa3d4..d84cf29d 100644
--- a/src/pages/searchBook/SearchBook.styled.ts
+++ b/src/pages/searchBook/SearchBook.styled.ts
@@ -117,7 +117,7 @@ export const ButtonSection = styled.div`
export const RecruitingGroupButton = styled.button`
width: 100%;
- height: 48px;
+ height: 44px;
border: 1px solid ${colors.grey[200]};
border-radius: 12px;
background: transparent;
@@ -140,7 +140,7 @@ export const RightArea = styled.div`
export const WritePostButton = styled.button`
flex: 1;
- height: 48px;
+ height: 44px;
background-color: ${colors.purple.main};
color: ${colors.white};
font-size: ${typography.fontSize.base};
From a041efc459949c578894079a01de5a4bb8f87279 Mon Sep 17 00:00:00 2001
From: Ji Ho June <129824629+ho0010@users.noreply.github.com>
Date: Thu, 21 Aug 2025 00:55:34 +0900
Subject: [PATCH 3/7] =?UTF-8?q?design:=20searchBook=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/Filter.tsx | 1 -
src/pages/searchBook/SearchBook.styled.ts | 8 ++++----
2 files changed, 4 insertions(+), 5 deletions(-)
diff --git a/src/components/common/Filter.tsx b/src/components/common/Filter.tsx
index e3023c45..1fffdd8b 100644
--- a/src/components/common/Filter.tsx
+++ b/src/components/common/Filter.tsx
@@ -49,7 +49,6 @@ const Container = styled.div`
position: relative;
justify-content: center;
align-items: center;
- width: 85px;
`;
const Text = styled.p`
diff --git a/src/pages/searchBook/SearchBook.styled.ts b/src/pages/searchBook/SearchBook.styled.ts
index d84cf29d..a0113940 100644
--- a/src/pages/searchBook/SearchBook.styled.ts
+++ b/src/pages/searchBook/SearchBook.styled.ts
@@ -157,8 +157,8 @@ export const WritePostButton = styled.button`
`;
export const SaveButton = styled.button`
- width: 48px;
- height: 48px;
+ width: 44px;
+ height: 44px;
background: transparent;
border: none;
border-radius: 12px;
@@ -170,7 +170,7 @@ export const SaveButton = styled.button`
export const FeedSection = styled.section`
display: flex;
- width: 96%;
+ width: 100%;
flex-direction: column;
margin-top: 20px;
`;
@@ -179,7 +179,7 @@ export const FeedTitle = styled.h2`
color: ${colors.white};
font-size: ${typography.fontSize.lg};
font-weight: ${typography.fontWeight.semibold};
- padding: 20px;
+ padding: 24px 20px 8px 20px;
`;
export const FilterContainer = styled.div`
From db8ac2547a531bb6934f1374a88720515176be44 Mon Sep 17 00:00:00 2001
From: Ji Ho June <129824629+ho0010@users.noreply.github.com>
Date: Thu, 21 Aug 2025 01:02:43 +0900
Subject: [PATCH 4/7] =?UTF-8?q?design:=20GroupDetail=20header=20=EB=A7=90?=
=?UTF-8?q?=EC=A4=84=EC=9E=84=20=EC=B6=94=EA=B0=80?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/pages/groupDetail/GroupDetail.styled.ts | 18 +++++++++++++++++-
1 file changed, 17 insertions(+), 1 deletion(-)
diff --git a/src/pages/groupDetail/GroupDetail.styled.ts b/src/pages/groupDetail/GroupDetail.styled.ts
index f80a5cff..888119cd 100644
--- a/src/pages/groupDetail/GroupDetail.styled.ts
+++ b/src/pages/groupDetail/GroupDetail.styled.ts
@@ -152,11 +152,27 @@ export const BookSection = styled.section`
export const BookHeader = styled.div`
display: flex;
- justify-content: space-between;
+ flex-direction: row;
align-items: center;
color: ${colors.white};
font-size: ${typography.fontSize['base']};
font-weight: ${typography.fontWeight.medium};
+ width: 100%;
+ gap: 0;
+
+ h3 {
+ flex: 1 1 0%;
+ min-width: 0;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ margin: 0;
+ font-size: inherit;
+ font-weight: inherit;
+ }
+ img {
+ flex-shrink: 0;
+ }
`;
export const BookInfo = styled.div`
From 88b3e2b19fcb19eaf98bb5d7faecd5486c5eb5cf Mon Sep 17 00:00:00 2001
From: Ji Ho June <129824629+ho0010@users.noreply.github.com>
Date: Thu, 21 Aug 2025 02:16:19 +0900
Subject: [PATCH 5/7] =?UTF-8?q?feat:=20getMyRooms=20API=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/api/rooms/getMyRooms.ts | 1 +
src/components/group/GroupCard.tsx | 3 +-
src/components/group/MyGroupBox.tsx | 1 +
src/components/group/MyGroupModal.tsx | 161 ++++++++++++++++++++++----
4 files changed, 142 insertions(+), 24 deletions(-)
diff --git a/src/api/rooms/getMyRooms.ts b/src/api/rooms/getMyRooms.ts
index 445f0627..438ef95e 100644
--- a/src/api/rooms/getMyRooms.ts
+++ b/src/api/rooms/getMyRooms.ts
@@ -11,6 +11,7 @@ export interface Room {
memberCount: number;
endDate: string;
type: string;
+ isPublic: boolean;
}
// 내 방 조회 응답 타입
diff --git a/src/components/group/GroupCard.tsx b/src/components/group/GroupCard.tsx
index c77af0cc..e8d214dc 100644
--- a/src/components/group/GroupCard.tsx
+++ b/src/components/group/GroupCard.tsx
@@ -12,6 +12,7 @@ interface Props {
isRecommend?: boolean;
onClick?: () => void;
isFirstCard?: boolean;
+ isPublic?: boolean;
}
export const GroupCard = forwardRef(
@@ -20,7 +21,7 @@ export const GroupCard = forwardRef(
- {group.isOnGoing === false && (
+ {group.isPublic === false && (
diff --git a/src/components/group/MyGroupBox.tsx b/src/components/group/MyGroupBox.tsx
index 0cf2fc7e..05328dc2 100644
--- a/src/components/group/MyGroupBox.tsx
+++ b/src/components/group/MyGroupBox.tsx
@@ -19,6 +19,7 @@ export interface Group {
deadLine?: string;
genre?: string;
isOnGoing?: boolean;
+ isPublic?: boolean;
}
const convertJoinedRoomToGroup = (room: JoinedRoomItem): Group => ({
diff --git a/src/components/group/MyGroupModal.tsx b/src/components/group/MyGroupModal.tsx
index ec522758..29f80f7e 100644
--- a/src/components/group/MyGroupModal.tsx
+++ b/src/components/group/MyGroupModal.tsx
@@ -1,4 +1,4 @@
-import { useState, useEffect } from 'react';
+import { useState, useEffect, useRef } from 'react';
import styled from '@emotion/styled';
import TitleHeader from '../common/TitleHeader';
import leftArrow from '../../assets/common/leftArrow.svg';
@@ -14,11 +14,20 @@ interface MyGroupModalProps {
}
export const MyGroupModal = ({ onClose }: MyGroupModalProps) => {
+ useEffect(() => {
+ document.body.style.overflow = 'hidden';
+ return () => {
+ document.body.style.overflow = '';
+ };
+ }, []);
const navigate = useNavigate();
const [selected, setSelected] = useState<'진행중' | '모집중' | ''>('');
const [rooms, setRooms] = useState([]);
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState(null);
+ const [nextCursor, setNextCursor] = useState(null);
+ const [isLast, setIsLast] = useState(false);
+ const contentRef = useRef(null);
const convertRoomToGroup = (room: Room): Group => {
return {
@@ -31,6 +40,7 @@ export const MyGroupModal = ({ onClose }: MyGroupModalProps) => {
deadLine: room.endDate || '',
genre: '',
isOnGoing: room.type === 'playing' || room.type === 'playingAndRecruiting',
+ isPublic: room.isPublic,
};
};
@@ -39,6 +49,8 @@ export const MyGroupModal = ({ onClose }: MyGroupModalProps) => {
try {
setIsLoading(true);
setError(null);
+ setNextCursor(null);
+ setIsLast(false);
const roomType: RoomType =
selected === '진행중'
@@ -51,6 +63,8 @@ export const MyGroupModal = ({ onClose }: MyGroupModalProps) => {
if (response.isSuccess) {
setRooms(response.data.roomList);
+ setNextCursor(response.data.nextCursor);
+ setIsLast(response.data.isLast);
} else {
setError(response.message);
}
@@ -65,6 +79,104 @@ export const MyGroupModal = ({ onClose }: MyGroupModalProps) => {
fetchRooms();
}, [selected]);
+ const isFetchingRef = useRef(false);
+
+ const loadMore = async () => {
+ if (isFetchingRef.current || isLast || !nextCursor) return;
+
+ isFetchingRef.current = true;
+ setIsLoading(true);
+ try {
+ const roomType: RoomType =
+ selected === '진행중'
+ ? 'playing'
+ : selected === '모집중'
+ ? 'recruiting'
+ : 'playingAndRecruiting';
+
+ const res = await getMyRooms(roomType, nextCursor);
+ if (res.isSuccess) {
+ setRooms(prev => [...prev, ...res.data.roomList]);
+ setNextCursor(res.data.nextCursor);
+ setIsLast(res.data.isLast);
+ } else {
+ setError(res.message);
+ }
+ } catch (e) {
+ console.log(e);
+ setError('방 목록을 불러오는데 실패했습니다.');
+ } finally {
+ setIsLoading(false);
+ isFetchingRef.current = false;
+ }
+ };
+
+ const handleScroll = async (e: React.UIEvent) => {
+ const el = e.currentTarget;
+ const { scrollTop, scrollHeight, clientHeight } = el;
+ if (scrollHeight - scrollTop - clientHeight < 100) {
+ await loadMore();
+ }
+ };
+
+ 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;
+ let guard = 2; // 최대 3페이지까지 자동 프리로드(필요시 늘리기)
+ while (
+ guard-- > 0 &&
+ contentRef.current &&
+ contentRef.current.scrollHeight <= contentRef.current.clientHeight &&
+ !isLast &&
+ nextCursor
+ ) {
+ await loadMore();
+ await new Promise(requestAnimationFrame);
+ }
+ };
+ tryFill();
+ }, [rooms, nextCursor, isLast]);
+
+ useEffect(() => {
+ if (contentRef.current) {
+ contentRef.current.scrollTo({ top: 0, behavior: 'smooth' });
+ }
+ }, [selected]);
+
const convertedGroups = rooms.map(convertRoomToGroup);
const handleGroupCardClick = (group: Group) => {
@@ -101,22 +213,22 @@ export const MyGroupModal = ({ onClose }: MyGroupModalProps) => {
))}
-
- {isLoading ? (
- 로딩 중...
- ) : error ? (
- {error}
- ) : convertedGroups.length > 0 ? (
- convertedGroups.map(group => (
- handleGroupCardClick(group)}
- />
- ))
- ) : (
+
+ {error && {error}}
+
+ {convertedGroups.map(group => (
+ handleGroupCardClick(group)}
+ />
+ ))}
+
+ {isLoading && 불러오는 중…}
+
+ {!isLoading && convertedGroups.length === 0 && (
{selected === '진행중'
@@ -163,21 +275,24 @@ const Content = styled.div`
gap: 20px;
overflow-y: auto;
padding: 0 20px 20px 20px;
-
grid-template-columns: 1fr;
-
+ scrollbar-width: none;
+ -ms-overflow-style: none;
+ &::-webkit-scrollbar {
+ display: none;
+ }
@media (min-width: 584px) {
grid-template-columns: 1fr 1fr;
}
`;
-const LoadingMessage = styled.div`
+const BottomSpinner = styled.div`
display: flex;
justify-content: center;
align-items: center;
- padding: 40px 20px;
- color: #fff;
- font-size: ${typography.fontSize.base};
+ padding: 16px 0 24px;
+ color: ${colors.grey[100]};
+ font-size: ${typography.fontSize.sm};
`;
const ErrorMessage = styled.div`
From 17454a277df0c68dafdd28c8de4430b5653d1720 Mon Sep 17 00:00:00 2001
From: Ji Ho June <129824629+ho0010@users.noreply.github.com>
Date: Thu, 21 Aug 2025 02:35:39 +0900
Subject: [PATCH 6/7] =?UTF-8?q?design:=20=EC=A0=84=EC=97=AD=20var=20?=
=?UTF-8?q?=ED=98=95=EC=8B=9D=20=EB=B3=80=EA=B2=BD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/components/feed/BookInfoCard.tsx | 15 +++++++------
src/components/group/MyGroupCard.tsx | 25 +++++++++++----------
src/components/group/RecruitingGroupBox.tsx | 8 +++----
3 files changed, 25 insertions(+), 23 deletions(-)
diff --git a/src/components/feed/BookInfoCard.tsx b/src/components/feed/BookInfoCard.tsx
index a4c9563f..2255ce3e 100644
--- a/src/components/feed/BookInfoCard.tsx
+++ b/src/components/feed/BookInfoCard.tsx
@@ -1,6 +1,7 @@
import { useNavigate } from 'react-router-dom';
import styled from '@emotion/styled';
import rightArrow from '../../assets/common/rightArrow.svg';
+import { colors, typography } from '@/styles/global/global';
interface BookInfoCardProps {
bookTitle: string;
@@ -37,17 +38,17 @@ const BookContainer = styled.div`
align-items: center;
justify-content: space-between;
border-radius: 12px;
- background: var(--color-darkgrey-main);
+ background: ${colors.darkgrey.main};
cursor: pointer;
.left {
overflow: hidden;
width: 220px;
white-space: nowrap;
- color: var(--color-white);
+ color: ${colors.white};
text-overflow: ellipsis;
- font-size: var(--font-size-base);
- font-weight: var(--font-weight-semibold);
+ font-size: ${typography.fontSize.base};
+ font-weight: ${typography.fontWeight.semibold};
line-height: 24px;
}
@@ -56,12 +57,12 @@ const BookContainer = styled.div`
flex-direction: row;
gap: 4px;
overflow: hidden;
- color: var(--color-grey-100);
+ color: ${colors.grey[100]};
text-align: right;
text-overflow: ellipsis;
- font-size: var(--font-size-xs);
+ font-size: ${typography.fontSize.xs};
font-style: normal;
- font-weight: var(--font-weight-regular);
+ font-weight: ${typography.fontWeight.regular};
line-height: 24px;
.name {
diff --git a/src/components/group/MyGroupCard.tsx b/src/components/group/MyGroupCard.tsx
index ebbb1921..2aece52d 100644
--- a/src/components/group/MyGroupCard.tsx
+++ b/src/components/group/MyGroupCard.tsx
@@ -2,6 +2,7 @@ import { forwardRef } from 'react';
import styled from '@emotion/styled';
import peopleImg from '../../assets/common/people.svg';
import type { Group } from './MyGroupBox';
+import { colors, typography } from '@/styles/global/global';
interface MyGroupCardProps {
group: Group;
@@ -66,8 +67,8 @@ const Info = styled.div`
`;
const CardTitle = styled.h2`
- font-size: var(--font-size-large01);
- font-weight: var(--font-weight-semibold);
+ font-size: ${typography.fontSize.lg};
+ font-weight: ${typography.fontWeight.semibold};
color: #000;
margin: 0;
white-space: nowrap;
@@ -79,9 +80,9 @@ const Participants = styled.p`
display: flex;
align-items: center;
gap: 4px;
- font-size: var(--font-size-small03);
- font-weight: var(--font-weight-medium);
- color: var(--color-grey-300);
+ font-size: ${typography.fontSize.xs};
+ font-weight: ${typography.fontWeight.medium};
+ color: ${colors.grey[300]};
margin: 8px 0;
> span {
line-height: 20px;
@@ -89,21 +90,21 @@ const Participants = styled.p`
`;
const ProgressText = styled.p`
- font-size: var(--font-size-medium01);
- color: var(--color-grey-300);
+ font-size: ${typography.fontSize.sm};
+ color: ${colors.grey[300]};
margin: 12px 0;
`;
const Percent = styled.span`
- font-size: var(--font-size-medium02);
- color: var(--color-purple-main);
- font-weight: var(--font-weight-semibold);
+ font-size: ${typography.fontSize.base};
+ color: ${colors.purple.main};
+ font-weight: ${typography.fontWeight.semibold};
`;
const Bar = styled.div`
width: 100%;
height: 6px;
- background: var(--color-grey-300);
+ background: ${colors.grey[300]};
border-radius: 4px;
margin-top: 4px;
`;
@@ -111,6 +112,6 @@ const Bar = styled.div`
const Fill = styled.div<{ width: number }>`
width: ${({ width }) => width}%;
height: 100%;
- background-color: var(--color-purple-main);
+ background-color: ${colors.purple.main};
border-radius: 4px;
`;
diff --git a/src/components/group/RecruitingGroupBox.tsx b/src/components/group/RecruitingGroupBox.tsx
index cfa97b9a..ce08a528 100644
--- a/src/components/group/RecruitingGroupBox.tsx
+++ b/src/components/group/RecruitingGroupBox.tsx
@@ -88,8 +88,8 @@ const Container = styled.div`
const Title = styled.h2`
color: #fff;
- font-size: var(--font-size-large02);
- font-weight: var(--font-weight-bold);
+ font-size: ${typography.fontSize.lg};
+ font-weight: ${typography.fontWeight.bold};
margin-bottom: 32px;
text-align: center;
`;
@@ -105,8 +105,8 @@ const TabContainer = styled.div`
const Tab = styled.button<{ selected?: boolean }>`
white-space: nowrap;
padding: 8px 12px;
- font-size: var(--font-size-small03);
- font-weight: var(--font-weight-regular);
+ font-size: ${typography.fontSize.xs};
+ font-weight: ${typography.fontWeight.regular};
border: none;
border-radius: 16px;
background: ${({ selected }) =>
From 2cab5ef30f98c2153a9c691091f937b8dd1b9767 Mon Sep 17 00:00:00 2001
From: Ji Ho June <129824629+ho0010@users.noreply.github.com>
Date: Thu, 21 Aug 2025 02:41:06 +0900
Subject: [PATCH 7/7] =?UTF-8?q?feat:=20GroupDetail=20=EC=98=88=EC=99=B8?=
=?UTF-8?q?=EC=B2=98=EB=A6=AC=20=EC=B6=94=EA=B0=80?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/pages/groupDetail/GroupDetail.tsx | 32 ++++++++++++++-------------
1 file changed, 17 insertions(+), 15 deletions(-)
diff --git a/src/pages/groupDetail/GroupDetail.tsx b/src/pages/groupDetail/GroupDetail.tsx
index 4e66d783..4b7a106b 100644
--- a/src/pages/groupDetail/GroupDetail.tsx
+++ b/src/pages/groupDetail/GroupDetail.tsx
@@ -328,21 +328,23 @@ const GroupDetail = () => {
-
- 이런 모임방은 어때요?
-
- {recommendRooms.map(room => (
- handleRecommendGroupCardClick(room.roomId)}
- />
- ))}
-
-
+ {recommendRooms.length > 0 && (
+
+ 이런 모임방은 어때요?
+
+ {recommendRooms.map(room => (
+ handleRecommendGroupCardClick(room.roomId)}
+ />
+ ))}
+
+
+ )}
{roomData.isHost ? '모집 마감하기' : isJoining ? '참여 취소하기' : '참여하기'}