handleOption(item)}
- onBlur={() => setActive('')}
className={`mb-1.5 cursor-pointer font-semibold md:mb-2 ${
item === active ? `border-b text-blue-500` : `text-gray-500`
} ${item === '카테고리' && 'md:hidden'}`}
@@ -117,94 +106,21 @@ export default function FilterOption({
{isFilter && (
{active === '모집기준' && (
-
-
- setOption((prev) => ({ ...prev, recruit: [] }))
- }
- key={`recruit-option_all`}
- >
-
-
- {['모집 마감', '모집 중', '모집 예정'].map((recruitType) => (
-
filterRecruitPeriod(recruitType)}
- key={`recruit-option_${recruitType}`}
- >
-
-
- ))}
-
+
)}
{active === '정렬' && (
-
-
- setOption((prev) => ({ ...prev, sort: false }))
- }
- className={`cursor-pointer rounded-xl p-2 px-5 ${
- option.sort ? `opacity-50` : `bg-gray-100 opacity-100`
- }`}
- >
- 동아리명으로 정렬
-
-
setOption((prev) => ({ ...prev, sort: true }))}
- className={`cursor-pointer rounded-xl p-2 px-5 ${
- option.sort ? `bg-gray-100 opacity-100` : `opacity-50`
- }`}
- >
- 카테고리로 정렬
-
-
+
)}
-
{active === '카테고리' && (
-
-
- setOption((prev) => ({ ...prev, category: [] }))
- }
- key={`category-option_all`}
- >
-
-
- {CatogoryColor.map((categoryItem) => (
-
filterCategory(categoryItem.title)}
- key={`category-option_${categoryItem.title}`}
- >
-
-
- ))}
-
+
)}
)}
diff --git a/src/components/modal/filter/Category.tsx b/src/components/modal/filter/Category.tsx
new file mode 100644
index 00000000..6e05c581
--- /dev/null
+++ b/src/components/modal/filter/Category.tsx
@@ -0,0 +1,61 @@
+import React, { Dispatch, SetStateAction } from 'react';
+import Image from 'next/image';
+import CheckboxImg from '@/assets/checkbox.svg';
+import { CatogoryColor } from '@/constants/color';
+import CheckBox from '../../home/CheckBox';
+
+interface Props {
+ setOption: Dispatch<
+ SetStateAction<{ category: string[]; recruit: string[]; sort: boolean }>
+ >;
+ option: { category: string[]; recruit: string[]; sort: boolean };
+ filterOption: (
+ item: string,
+ option: string[],
+ setOptionCallback: (updatedOption: string[]) => void,
+ ) => void;
+}
+
+function Category({ setOption, option, filterOption }: Props) {
+ const { category } = option;
+
+ function fillCheckBox() {
+ if (category.length === 0) {
+ return
;
+ }
+ return
;
+ }
+
+ function handleClickOption(title: string) {
+ filterOption(title, category, (updatedCategory) => {
+ setOption((prev) => ({
+ ...prev,
+ category: updatedCategory,
+ }));
+ });
+ }
+
+ return (
+
+
setOption((prev) => ({ ...prev, category: [] }))}
+ key={`category-option_all`}
+ >
+
+
+ {CatogoryColor.map((categoryItem) => (
+
handleClickOption(categoryItem.title)}
+ key={`category-option_${categoryItem.title}`}
+ >
+
+
+ ))}
+
+ );
+}
+
+export default Category;
diff --git a/src/components/modal/filter/RecruitStatus.tsx b/src/components/modal/filter/RecruitStatus.tsx
new file mode 100644
index 00000000..2f693f01
--- /dev/null
+++ b/src/components/modal/filter/RecruitStatus.tsx
@@ -0,0 +1,61 @@
+import React, { Dispatch, SetStateAction } from 'react';
+import Image from 'next/image';
+import CheckboxImg from '@/assets/checkbox.svg';
+import CheckBox from '../../home/CheckBox';
+
+interface Props {
+ setOption: Dispatch<
+ SetStateAction<{ category: string[]; recruit: string[]; sort: boolean }>
+ >;
+ option: { category: string[]; recruit: string[]; sort: boolean };
+ filterOption: (
+ item: string,
+ option: string[],
+ setOptionCallback: (updatedOption: string[]) => void,
+ ) => void;
+}
+
+function RecruitStatus({ setOption, option, filterOption }: Props) {
+ const { recruit } = option;
+ const recruitList = ['모집 마감', '모집 중', '모집 예정'];
+
+ function fillCheckBox() {
+ if (recruit.length === 0) {
+ return
;
+ }
+ return
;
+ }
+
+ function handleClickOption(recruitType: string) {
+ filterOption(recruitType, recruit, (updatedRecruit) => {
+ setOption((prev) => ({
+ ...prev,
+ recruit: updatedRecruit,
+ }));
+ });
+ }
+
+ return (
+ <>
+
setOption((prev) => ({ ...prev, recruit: [] }))}
+ key={`recruit-option_all`}
+ >
+
+
+ {recruitList.map((recruitType) => (
+
handleClickOption(recruitType)}
+ key={`recruit-option_${recruitType}`}
+ >
+
+
+ ))}
+ >
+ );
+}
+
+export default RecruitStatus;
diff --git a/src/components/modal/filter/Sort.tsx b/src/components/modal/filter/Sort.tsx
new file mode 100644
index 00000000..5e2dc6e9
--- /dev/null
+++ b/src/components/modal/filter/Sort.tsx
@@ -0,0 +1,37 @@
+import React, { Dispatch, SetStateAction } from 'react';
+
+interface Props {
+ setOption: Dispatch<
+ SetStateAction<{ category: string[]; recruit: string[]; sort: boolean }>
+ >;
+ option: { category: string[]; recruit: string[]; sort: boolean };
+}
+
+function Sort({ setOption, option }: Props) {
+ function handleClickOption(isCategory: boolean) {
+ setOption((prev) => ({ ...prev, sort: isCategory }));
+ }
+
+ return (
+ <>
+
handleClickOption(false)}
+ className={`cursor-pointer rounded-xl p-2 px-5 ${
+ option.sort ? `opacity-50` : `bg-gray-100 opacity-100`
+ }`}
+ >
+ 동아리명으로 정렬
+
+
handleClickOption(true)}
+ className={`cursor-pointer rounded-xl p-2 px-5 ${
+ option.sort ? `bg-gray-100 opacity-100` : `opacity-50`
+ }`}
+ >
+ 카테고리로 정렬
+
+ >
+ );
+}
+
+export default Sort;
diff --git a/src/pages/index.tsx b/src/pages/index.tsx
index b00eb9c1..3fa76ff0 100644
--- a/src/pages/index.tsx
+++ b/src/pages/index.tsx
@@ -1,10 +1,9 @@
import { useEffect, useState } from 'react';
-
import Slider from '@/components/common/Slider';
import ClubCard from '@/components/home/ClubCard';
+import FilterCategory from '@/components/home/FilterCategory';
import SearchBar from '@/components/home/SearchBar';
import FilterOption from '@/components/modal/FilterOption';
-import { CatogoryColor } from '@/constants/color';
import { useAllClubs } from '@/hooks/api/club/useAllClubs';
import type { Club } from '@/types/club';
@@ -29,38 +28,34 @@ export default function Home() {
(a, b) =>
a.category.localeCompare(b.category) || a.name.localeCompare(b.name),
);
- const semiClubs = sortedClubs.filter(
- (club) => club.category === '준동아리',
- );
- sortedClubs = sortedClubs.filter((club) => club.category !== '준동아리');
- sortedClubs = [...sortedClubs, ...semiClubs];
+ sortedClubs = resortSemiClub(sortedClubs);
setClubs(sortedClubs);
setFilteredClubs(sortedClubs);
}, [data]);
useEffect(() => {
- const timeout = setTimeout(() => {
- setFilteredClubs(
- clubs.filter(
- (club) =>
- club.name.includes(keyword.toUpperCase()) ||
- club.tag.includes(keyword.toUpperCase()) ||
- club.category === keyword,
+ const filterClubs = () => {
+ return clubs.filter((club) =>
+ [club.name, club.tag, club.category].some((property) =>
+ property.includes(keyword.toUpperCase()),
),
);
- }, 300);
+ };
- return () => clearTimeout(timeout);
+ setFilteredClubs(filterClubs());
}, [clubs, keyword]);
- if (isError) {
- return
error
;
+
+ function resortSemiClub(sortedClubs: Club[]) {
+ const semiClubs = sortedClubs.filter(
+ (club) => club.category === '준동아리',
+ );
+ sortedClubs = sortedClubs.filter((club) => club.category !== '준동아리');
+ sortedClubs = [...sortedClubs, ...semiClubs];
+ return sortedClubs;
}
- function filterCategory(item: string) {
- const updatedCategory = filterOption.category.includes(item)
- ? filterOption.category.filter((club) => club !== item)
- : [...filterOption.category, item];
- setFilterOption((prev) => ({ ...prev, category: updatedCategory }));
+ if (isError) {
+ return
error
;
}
return (
@@ -81,29 +76,7 @@ export default function Home() {
setOption={setFilterOption}
/>