Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
34f7d99
fix: 철학자 칭호 하늘색으로 표시하도록 수정
ljh130334 Sep 13, 2025
1c83367
refactor: 기록장 블라인드 처리 3px로 수정
ljh130334 Sep 13, 2025
a78d6ab
fix: 독서메이트 프로필 사진에 테두리 추가
ljh130334 Sep 16, 2025
201c98e
Merge pull request #245 from THIP-TextHip/hotfix/name
ljh130334 Sep 16, 2025
b715160
fix: 기록장 투표 정보 퍼센트가 아닌 득표수로 표시되도록 수정
ljh130334 Sep 16, 2025
aba2121
Merge pull request #247 from THIP-TextHip/hotfix/vote
ljh130334 Sep 16, 2025
1226f53
feat: 모임방 참여하기 버튼 로직
ho0010 Sep 20, 2025
6130ae7
feat: group search tab 추가
ho0010 Sep 20, 2025
1f15b58
feat: 모임방 검색 API
ho0010 Sep 20, 2025
1c14f5b
feat:
ho0010 Sep 20, 2025
8bb9bd9
design: 모임 상세 페이지 참여하기 버튼
ho0010 Sep 20, 2025
cff1253
design: modal 헤더와 본문 간격 수정
ho0010 Sep 20, 2025
2c8a0eb
design: MyGroupCard 참여 인원
ho0010 Sep 20, 2025
dc1444f
feat: MyGroupCard 분기처리
ho0010 Sep 20, 2025
5a47764
feat: group 모임방 추천 캐러셀 항목 변경
ho0010 Sep 20, 2025
4177fd9
feat: group 하단 캐러셀 리사이즈 구현
ho0010 Sep 20, 2025
92e455d
design: 모집중인 그룹 캐러셀 수정
ho0010 Sep 20, 2025
e8b6d97
feat: 모집중인 모임방 캐러셀 버튼
ho0010 Sep 21, 2025
76faa17
feat: group 내 모임방 캐러셀 버튼 적용
ho0010 Sep 21, 2025
bdb69d1
fix: 방 상세보기 엔드포인트 변경 적용
ho0010 Sep 21, 2025
5eff73b
fix: 그룹 검색 버그
ho0010 Sep 21, 2025
64720d0
fix: 중복 검색 요청
ho0010 Sep 22, 2025
d62d4b4
Merge pull request #249 from THIP-TextHip/fix/QA9-3
ho0010 Sep 22, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/api/rooms/getJoinedRooms.ts
Original file line number Diff line number Diff line change
@@ -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 {
Expand Down
6 changes: 3 additions & 3 deletions src/api/rooms/getRoomDetail.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,19 +45,19 @@ export const getRoomDetail = async (roomId: number): Promise<RoomDetailResponse>
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;
}
};
6 changes: 3 additions & 3 deletions src/api/rooms/getRoomPlaying.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,16 +64,16 @@ export const convertVotesToPolls = (currentVotes: CurrentVote[]): Poll[] => {

export const getRoomPlaying = async (roomId: number): Promise<RoomPlayingResponse> => {
try {
const response = await apiClient.get<RoomPlayingResponse>(`/rooms/${roomId}/playing`);
const response = await apiClient.get<RoomPlayingResponse>(`/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;
}
};
1 change: 1 addition & 0 deletions src/api/rooms/getRoomsByCategory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export interface RoomsResponse {
data: {
deadlineRoomList: RoomItem[];
popularRoomList: RoomItem[];
recentRoomList: RoomItem[];
};
}

Expand Down
6 changes: 5 additions & 1 deletion src/api/rooms/getSearchRooms.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,18 @@ export const getSearchRooms = async (
cursor?: string,
isFinalized: boolean = false,
category: string = '',
isAllCategory: boolean = false,
): Promise<SearchRoomsResponse> => {
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<SearchRoomsResponse>(url);
Expand Down
4 changes: 4 additions & 0 deletions src/assets/common/back.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions src/assets/common/next.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 6 additions & 0 deletions src/assets/common/searchChar.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion src/components/group/CompletedGroupModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 }>`
Expand Down
72 changes: 70 additions & 2 deletions src/components/group/MyGroupBox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -28,6 +30,7 @@ const convertJoinedRoomToGroup = (room: JoinedRoomItem): Group => ({
participants: room.memberCount,
coverUrl: room.bookImageUrl,
progress: room.userPercentage,
deadLine: room.deadlineDate || undefined,
});

interface MyGroupProps {
Expand Down Expand Up @@ -108,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 (
<Container>
<Header>
Expand All @@ -125,7 +144,17 @@ export function MyGroupBox({ onMyGroupsClick }: MyGroupProps) {
<ErrorText>{error}</ErrorText>
</ErrorContainer>
) : groups.length > 0 ? (
<>
<CarouselContainer>
{!isSingle && (
<>
<NavButton className="nav-button prev" onClick={handlePrevClick}>
<img src={backIcon} alt="이전" />
</NavButton>
<NavButton className="nav-button next" onClick={handleNextClick}>
<img src={nextIcon} alt="다음" />
</NavButton>
</>
)}
{isSingle ? (
<Carousel>
<MyGroupCard
Expand Down Expand Up @@ -158,7 +187,7 @@ export function MyGroupBox({ onMyGroupsClick }: MyGroupProps) {
))}
</Carousel>
)}
</>
</CarouselContainer>
) : (
<EmptyContainer>
<EmptyCard role="status" aria-live="polite">
Expand Down Expand Up @@ -208,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;
Expand Down
53 changes: 43 additions & 10 deletions src/components/group/MyGroupCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -12,25 +13,44 @@ interface MyGroupCardProps {

export const MyGroupCard = forwardRef<HTMLDivElement, MyGroupCardProps>((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 (
<Card ref={ref} onClick={onClick}>
<Card ref={ref} onClick={handleClick}>
<Thumbnail src={group.coverUrl} alt="책 표지" />
<Info>
<div>
<CardTitle>{group.title}</CardTitle>
<Participants>
<img src={peopleImg} alt="" />
<span>{group.participants}명 참여</span>
<span>{group.participants}명</span>
</Participants>
</div>
<div>
<ProgressText>
{isMine ? '내 진행도' : `${group.userName}님의 진행도`}{' '}
<Percent>{Math.floor(group.progress || 0)}%</Percent>
</ProgressText>
<Bar>
<Fill width={group.progress || 0} />
</Bar>
{hasDeadline ? (
<DeadlineText>
시작까지 <DeadlineValue>{group.deadLine}</DeadlineValue>
</DeadlineText>
) : (
<>
<ProgressText>
{isMine ? '내 진행도' : `${group.userName}님의 진행도`}{' '}
<Percent>{Math.floor(group.progress || 0)}%</Percent>
</ProgressText>
<Bar>
<Fill width={group.progress || 0} />
</Bar>
</>
)}
</div>
</Info>
</Card>
Expand Down Expand Up @@ -80,7 +100,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;
Expand All @@ -101,6 +121,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;
Expand Down
2 changes: 1 addition & 1 deletion src/components/group/MyGroupModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 }>`
Expand Down
8 changes: 7 additions & 1 deletion src/components/group/RecruitingGroupBox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 }>`
Expand Down
Loading