Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
43c2235
✨[Feat] 인원수 필터링 구현 #264
wynter24 Jan 1, 2025
c1b7b3c
✨[Feat] 인원수 필터링 구현 #264
wynter24 Jan 1, 2025
0c3f695
Merge branch '264-feature-모임-메인-페이지-인원수-필터링' of https://github.com/co…
wynter24 Jan 2, 2025
17e4ef8
💄[Design] 지난 모임 및 취소된 모임 표시 #264
wynter24 Jan 2, 2025
62289d8
🐛[Fix] 인원수 전체일 때 파라미터 설정 #264
wynter24 Jan 2, 2025
a2d5009
✨[Feat] 신청 가능 필터 기능 구현 #264
wynter24 Jan 3, 2025
5f73226
✨[Feat] 인원수 필터링 구현 #264
wynter24 Jan 1, 2025
9648124
💄[Design] 지난 모임 및 취소된 모임 표시 #264
wynter24 Jan 2, 2025
28277c8
🐛[Fix] 인원수 전체일 때 파라미터 설정 #264
wynter24 Jan 2, 2025
8306b0f
✨[Feat] 신청 가능 필터 기능 구현 #264
wynter24 Jan 3, 2025
a0c79a1
Merge branch '264-feature-모임-메인-페이지-인원수-필터링' of https://github.com/co…
wynter24 Jan 3, 2025
e3694e2
✨[Feat] 좋아요 기능 구현 #264
wynter24 Jan 3, 2025
9d40f09
♻️[Refactor] 모임 목록 조회 쿼리키 사용 #264
wynter24 Jan 3, 2025
03091fb
✨[Feat] 인원수 필터링 구현 #264
wynter24 Jan 1, 2025
65cef5b
💄[Design] 지난 모임 및 취소된 모임 표시 #264
wynter24 Jan 2, 2025
fbdd76f
🐛[Fix] 인원수 전체일 때 파라미터 설정 #264
wynter24 Jan 2, 2025
f84af88
✨[Feat] 신청 가능 필터 기능 구현 #264
wynter24 Jan 3, 2025
b4ad6bd
✨[Feat] 좋아요 기능 구현 #264
wynter24 Jan 3, 2025
8701596
♻️[Refactor] 모임 목록 조회 쿼리키 사용 #264
wynter24 Jan 3, 2025
07ea93f
Merge branch '264-feature-모임-메인-페이지-인원수-필터링' of https://github.com/co…
wynter24 Jan 3, 2025
014b2d8
🐛[Fix] 찜 페이지 FilterBar 누락 속성 추가 #264
wynter24 Jan 3, 2025
f63322e
Merge branch 'develop' of https://github.com/codeit-team3/FE into 264…
wynter24 Jan 3, 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/book-club/bookClubMainAPI.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export const bookClubMainAPI = {

//북클럽 목록 조회
getBookClubs: async (params?: BookClubParams) => {
await apiClient.get('/book-clubs', { params });
return await apiClient.get('/book-clubs', { params });
},

//단일 북클럽 조회
Expand Down
3 changes: 3 additions & 0 deletions src/components/common-layout/FilterBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,15 @@ interface FilterBarProps {
filters: BookClubParams;
handleFilterChange: (newFilter: Partial<BookClubParams>) => void;
bookClubs: BookClub[];
initialBookClubs: BookClub[];
setBookClubs: Dispatch<SetStateAction<BookClub[]>>;
}

function FilterBar({
filters,
handleFilterChange,
bookClubs,
initialBookClubs,
setBookClubs,
}: FilterBarProps) {
return (
Expand All @@ -30,6 +32,7 @@ function FilterBar({
/>
<FilterSection
bookClubs={bookClubs}
initialBookClubs={initialBookClubs}
setBookClubs={setBookClubs}
onFilterChange={handleFilterChange}
/>
Expand Down
36 changes: 31 additions & 5 deletions src/components/common-layout/FilterSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,39 +2,65 @@

import DropDown from '@/components/drop-down/DropDown';
import FilterCheckbox from '@/components/filter-checkbox/FilterCheckbox';
import { ChangeEvent, Dispatch, SetStateAction, useState } from 'react';
import {
ChangeEvent,
Dispatch,
SetStateAction,
// useEffect,
useState,
} from 'react';
import SortingButton from '@/components/sorting-button/SortingButton';
import { BookClub, BookClubParams } from '../../types/bookclubs';
import { getMeetingType, getMemberLimit } from '@/lib/utils/filterUtils';
import { clubStatus } from '@/lib/utils/clubUtils';

interface CategoryTabsProps {
bookClubs: BookClub[];
initialBookClubs: BookClub[];
setBookClubs: Dispatch<SetStateAction<BookClub[]>>;
onFilterChange: (newFilters: Partial<BookClubParams>) => void;
}

function FilterSection({
bookClubs,
initialBookClubs,
setBookClubs,
onFilterChange,
}: CategoryTabsProps) {
const [showAvailableOnly, setShowAvailableOnly] = useState(false); // 신청가능

// useEffect(() => {
// console.log('체크 상태: ', showAvailableOnly);
// console.log('신청 가능 모임: ', bookClubs);
// });

const toggleAvailableOnly = (e: ChangeEvent<HTMLInputElement>) => {
const isChecked = e.target.checked;
setShowAvailableOnly(isChecked);

const filteredBookClubs = isChecked
? bookClubs.filter((club) => club.memberCount < club.memberLimit)
: bookClubs;
? bookClubs.filter(
(club) =>
club.memberCount < club.memberLimit &&
clubStatus(
club.memberCount,
club.memberLimit,
club.endDate,
new Date(),
) !== 'closed',
)
: initialBookClubs;

setBookClubs(filteredBookClubs);
};

const updateMemberLimitFilter = (selectedValue: string | undefined) => {
const memberLimit = getMemberLimit(selectedValue);
if (selectedValue !== undefined) {
onFilterChange({ memberLimit });
if (memberLimit) {
onFilterChange({
memberLimitMin: memberLimit.min,
memberLimitMax: memberLimit.max,
});
}
};

Expand Down
24 changes: 19 additions & 5 deletions src/features/bookclub/components/BookClubMainPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,17 @@ import { useAuthStore } from '@/store/authStore';
import ClubListSection from './ClubListSection';
import Button from '@/components/button/Button';
import { useRouter } from 'next/navigation';
import Loading from '@/components/loading/Loading';

function BookClubMainPage() {
// 커스텀 훅에서 상태와 핸들러 가져오기
const { bookClubs, setBookClubs, filters, updateFilters } = useBookClubList();
const {
clubList,
initialBookClubs,
setClubList,
isLoading,
filters,
updateFilters,
} = useBookClubList();

const router = useRouter();

Expand Down Expand Up @@ -44,10 +51,17 @@ function BookClubMainPage() {
<FilterBar
filters={filters}
handleFilterChange={handleFilterChange}
bookClubs={bookClubs}
setBookClubs={setBookClubs}
bookClubs={clubList}
initialBookClubs={initialBookClubs}
setBookClubs={setClubList}
/>
<ClubListSection bookClubs={bookClubs} />
{isLoading ? (
<div className="flex h-[400px] justify-center">
<Loading />
</div>
) : (
<ClubListSection bookClubs={clubList} />
)}
</>
);
}
Expand Down
14 changes: 10 additions & 4 deletions src/features/bookclub/components/ClubListSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,23 @@ import { useMemo } from 'react';
import EmptyState from '@/components/common-layout/EmptyState';
import { clubStatus } from '@/lib/utils/clubUtils';
import { BookClub } from '@/types/bookclubs';
import { useLikeClub, useUnLikeClub } from '@/lib/hooks';

interface ClubListSectionProps {
bookClubs: BookClub[];
}

function ClubListSection({ bookClubs = [] }: ClubListSectionProps) {
const router = useRouter();
const { onConfirmUnLike } = useUnLikeClub();
const { onConfirmLike } = useLikeClub();

const today = useMemo(() => new Date(), []);

const handleLikeClub = (isLiked: boolean, id: number) => {
isLiked ? onConfirmUnLike(id) : onConfirmLike(id);
};

return (
<main className="flex w-full min-w-[336px] flex-1 flex-col items-center gap-y-[26px] bg-gray-light-01 px-[20px] pt-[18px] sm:justify-between md:px-[24px] lg:px-[102px]">
{bookClubs?.length > 0 ? (
Expand All @@ -32,8 +39,8 @@ function ClubListSection({ bookClubs = [] }: ClubListSectionProps) {
isLiked={club.isLiked}
current={club.memberCount}
max={club.memberLimit}
isPast={isPastDate(club.endDate, today)} // 지난 모임 여부
isCanceled={false} // 모임 취소 여부 (API 값에 따라 변경 가능)
isPast={isPastDate(club.targetDate, today)} // 지난 모임 여부
isCanceled={club.isInactive} // 모임 취소 여부
bookClubType={club.bookClubType}
meetingType={club.meetingType}
clubStatus={clubStatus(
Expand All @@ -42,9 +49,8 @@ function ClubListSection({ bookClubs = [] }: ClubListSectionProps) {
club.endDate,
today,
)}
onLikeClick={() => console.log(`${club.title} 좋아요 클릭`)}
onLikeClick={() => handleLikeClub(club.isLiked, club.id)}
onClick={() => router.push(`/bookclub/${club.id}`)}
onDelete={() => console.log(`${club.title} 삭제 클릭`)}
/>
))
) : (
Expand Down
43 changes: 21 additions & 22 deletions src/features/bookclub/hooks/useFetchBookClubList.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { useState, useEffect, useCallback } from 'react';
import { getBookClubs } from '../api/bookclubApi';
import { useState, useEffect } from 'react';
import { BookClub, BookClubParams } from '@/types/bookclubs';
import { useQuery } from '@tanstack/react-query';
import { bookClubs } from '@/api/book-club/react-query';

const useBookClubList = () => {
const [bookClubs, setBookClubs] = useState<BookClub[]>([]);
const [loading, setLoading] = useState(false);
const [error, setError] = useState<Error | null>(null);
// TODO: 신청 가능 필터 param 추가시 clubList, initialBookClubs 상태 관리x
const [clubList, setClubList] = useState<BookClub[]>([]);
const [initialBookClubs, setInitialBookClubs] = useState<BookClub[]>([]);
const [filters, setFilters] = useState<BookClubParams>({
bookClubType: 'ALL',
meetingType: 'ALL',
Expand All @@ -15,31 +16,29 @@ const useBookClubList = () => {
searchKeyword: '',
});

const fetchData = useCallback(async () => {
setLoading(true);
setError(null);
try {
const data = await getBookClubs(filters); // API 호출
setBookClubs(data);
} catch (err) {
setError(err as Error);
} finally {
setLoading(false);
}
}, [filters]);
const { data, isLoading, error } = useQuery({
...bookClubs.all(filters),
});

const clubInfo = data?.data.bookClubs;

// TODO: param 추가시, useEffect 대신 clubInfo 직접 사용
useEffect(() => {
fetchData();
}, [fetchData]);
if (clubInfo) {
setClubList(clubInfo);
setInitialBookClubs(clubInfo); // 초기 데이터 설정
}
}, [clubInfo]);

const updateFilters = (newFilters: Partial<BookClubParams>) => {
setFilters((prevFilters) => ({ ...prevFilters, ...newFilters }));
};

return {
bookClubs,
setBookClubs,
loading,
clubList,
initialBookClubs,
setClubList,
isLoading,
error,
filters,
updateFilters,
Expand Down
1 change: 1 addition & 0 deletions src/features/club-wish/components/WishPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ function WishPage() {
handleFilterChange={() => {}}
bookClubs={mockBookClubs}
setBookClubs={() => {}}
initialBookClubs={[]}
/>
<ClubWishList bookClubs={mockBookClubs} />
</>
Expand Down
18 changes: 9 additions & 9 deletions src/lib/utils/filterUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,16 @@ import { BookClubParams } from '@/types/bookclubs';

export const getMemberLimit = (selectedValue: string | undefined) => {
switch (selectedValue) {
case 'TWO_FOUR':
return 4;
case 'FIVE_SEVEN':
return 7;
case 'EIGHT_TEN':
return 10;
case 'OVER_ELEVEN':
return 11;
case 'THREE_FIVE':
return { min: 3, max: 5 };
case 'SIX_EIGHT':
return { min: 6, max: 8 };
case 'NINE_ELEVEN':
return { min: 9, max: 11 };
case 'TWELVE':
return { min: 12, max: 20 };
default:
return undefined;
return { min: 3, max: 20 };
}
};

Expand Down
2 changes: 2 additions & 0 deletions src/types/bookclubs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ export interface BookClubParams {
page?: number;
size?: number;
searchKeyword?: string;
memberLimitMin?: number;
memberLimitMax?: number;
}

export interface MyProfileParams {
Expand Down
Loading