From 9ed2a2fb7bb978c1c2e123e96f3644eaef64e19f Mon Sep 17 00:00:00 2001 From: MEGUMMY1 Date: Mon, 2 Dec 2024 22:49:42 +0900 Subject: [PATCH] =?UTF-8?q?Feat:=20=EC=9D=B8=EA=B8=B0=ED=8E=98=EC=9D=B4?= =?UTF-8?q?=EC=A7=80=20=EC=A0=95=EB=A0=AC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/icon/custom/average-icon.svg | 3 + public/icon/custom/like-icon.svg | 3 + src/apis/get/getPopular.ts | 6 ++ src/components/Button/Chips/Chips.module.scss | 16 +++ src/components/Button/Chips/Chips.types.ts | 4 +- src/components/Button/Chips/index.tsx | 11 ++ .../Lesson/Popular/Popular.module.scss | 29 +++-- src/components/Lesson/Popular/index.tsx | 101 +++++++++++++++--- .../PopularSchedule.module.scss | 6 ++ .../Schedule/PopularSchedule/index.tsx | 10 +- src/constants/asset.tsx | 2 + 11 files changed, 164 insertions(+), 27 deletions(-) create mode 100644 public/icon/custom/average-icon.svg create mode 100644 public/icon/custom/like-icon.svg diff --git a/public/icon/custom/average-icon.svg b/public/icon/custom/average-icon.svg new file mode 100644 index 0000000..9869bc7 --- /dev/null +++ b/public/icon/custom/average-icon.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/public/icon/custom/like-icon.svg b/public/icon/custom/like-icon.svg new file mode 100644 index 0000000..651cc75 --- /dev/null +++ b/public/icon/custom/like-icon.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/apis/get/getPopular.ts b/src/apis/get/getPopular.ts index d47c37e..da1950e 100644 --- a/src/apis/get/getPopular.ts +++ b/src/apis/get/getPopular.ts @@ -14,6 +14,9 @@ export interface NomalPopular { owner: string; totalParticipantCount: number; items: string[]; + averageScore: number; + reviewCount: number; + favoriteCount: number; } export interface getNomalPopularParams { @@ -54,6 +57,9 @@ export interface SpecialPopular { detailAddress: string; totalParticipantCount: number; items: string[]; + averageScore: number; + reviewCount: number; + favoriteCount: number; } export interface getSpecialPopularParams { diff --git a/src/components/Button/Chips/Chips.module.scss b/src/components/Button/Chips/Chips.module.scss index 495a4fd..77ffabf 100644 --- a/src/components/Button/Chips/Chips.module.scss +++ b/src/components/Button/Chips/Chips.module.scss @@ -85,3 +85,19 @@ @include C10B; color: $green80; } + +.like { + display: flex; + align-items: center; + gap: 1px; + @include C10M; + color: $gray70; +} + +.average { + display: flex; + align-items: center; + gap: 1px; + @include C10M; + color: $gray70; +} diff --git a/src/components/Button/Chips/Chips.types.ts b/src/components/Button/Chips/Chips.types.ts index 2a38f25..47f2cd1 100644 --- a/src/components/Button/Chips/Chips.types.ts +++ b/src/components/Button/Chips/Chips.types.ts @@ -4,7 +4,9 @@ export type ChipState = | 'label' | 'sports' | 'count' - | 'top'; + | 'top' + | 'like' + | 'average'; export interface ChipsProps { text: string | number | undefined; diff --git a/src/components/Button/Chips/index.tsx b/src/components/Button/Chips/index.tsx index b9c4f3d..29ac8c0 100644 --- a/src/components/Button/Chips/index.tsx +++ b/src/components/Button/Chips/index.tsx @@ -1,6 +1,7 @@ import { ChipsProps, ChipState } from './Chips.types'; import styles from './Chips.module.scss'; import { formatCurrency } from '@/utils/formatCurrency'; +import IconComponent from '@/components/Asset/Icon'; export default function Chips({ chipState, text, serialNumber }: ChipsProps) { const getChipClass = (state: ChipState) => { @@ -15,6 +16,10 @@ export default function Chips({ chipState, text, serialNumber }: ChipsProps) { return styles.count; // 누적 수강 수 case 'top': return serialNumber ? styles.top : styles.topSP; // top5 누적 수강 수 + case 'like': + return styles.like; // 찜 개수 + case 'average': + return styles.average; // 평점 case 'label': default: return styles.label; // 기본 라벨 칩 @@ -23,6 +28,12 @@ export default function Chips({ chipState, text, serialNumber }: ChipsProps) { return (
+ {chipState === 'like' && ( + + )} + {chipState === 'average' && ( + + )} {chipState === 'count' ? `누적 수강 ${formatCurrency(text)}` : text}
); diff --git a/src/components/Lesson/Popular/Popular.module.scss b/src/components/Lesson/Popular/Popular.module.scss index 4939b16..b3108a3 100644 --- a/src/components/Lesson/Popular/Popular.module.scss +++ b/src/components/Lesson/Popular/Popular.module.scss @@ -112,28 +112,39 @@ } } -.sort { +.selectedSort { @include C12M; color: $gray70; + cursor: pointer; display: flex; align-items: center; - gap: 2px; - cursor: pointer; + gap: 4px; } -.dropdown { - cursor: pointer; +.sortOptions { + display: flex; + flex-direction: column; + align-items: flex-start; + background-color: $white; position: absolute; margin-right: 20px; - right: 0; margin-top: 10px; - padding: 10px 15px; - background-color: $white; + right: 0; + border: 1px solid $gray30; border-radius: 5px; - border: 1px solid $gray40; +} + +.sortOption { + @include C12M; + color: $gray70; + cursor: pointer; + width: 100%; + gap: 2px; + padding: 10px 15px; &:hover { background-color: $gray20; + border-radius: 5px; } } diff --git a/src/components/Lesson/Popular/index.tsx b/src/components/Lesson/Popular/index.tsx index ab8e98f..06cc298 100644 --- a/src/components/Lesson/Popular/index.tsx +++ b/src/components/Lesson/Popular/index.tsx @@ -30,6 +30,7 @@ import PopularSchedule from '@/components/Schedule/PopularSchedule'; import { specialTypeList } from '@/constants/specialList'; import Tooltip from '@/components/Tooltip/Tooltip'; import SpecialFilterForPopular from './SpecialFilterForPopular'; +import { useRouter } from 'next/router'; export default function Popular() { const [facilities, setFacilities] = useState< @@ -42,10 +43,12 @@ export default function Popular() { const [selectedLocalCode] = useRecoilState(selectedLocalCodeState); const [selectedSport, setSelectedSport] = useRecoilState(selectedSportState); const [isDropdownOpen, setIsDropdownOpen] = useState(false); - const [selectedSort, setSelectedSort] = useState('인기순'); + const [selectedSort, setSelectedSort] = useState('total'); + const [selectedSortName, setSelectedSortName] = useState('누적 수강 수'); const dropdownRef = useRef(null); const toggle = useRecoilValue(toggleState); const [specialFilterValue, setSpecialFilterValue] = useState(''); + const router = useRouter(); const handleSpecialFilterChange = (type: string) => { setSpecialFilterValue(type); @@ -121,7 +124,55 @@ export default function Popular() { ); }; + const sortFacilities = ( + facilities: NomalPopular[] | SpecialPopular[], + sort: string + ): NomalPopular[] | SpecialPopular[] => { + switch (sort) { + case 'total': + return [...facilities].sort( + (a, b) => b.totalParticipantCount - a.totalParticipantCount + ); + case 'average': + return [...facilities].sort((a, b) => b.averageScore - a.averageScore); + case 'review': + return [...facilities].sort((a, b) => b.reviewCount - a.reviewCount); + case 'favorite': + return [...facilities].sort( + (a, b) => b.favoriteCount - a.favoriteCount + ); + default: + return facilities; + } + }; + + const handleSelectSort = (sort: string) => { + setSelectedSort(sort); + setIsDropdownOpen(false); + if (sort === 'total') { + setSelectedSortName('누적 수강 수'); + } else if (sort === 'average') { + setSelectedSortName('별점 순'); + } else if (sort === 'review') { + setSelectedSortName('후기 개수'); + } else if (sort === 'favorite') { + setSelectedSortName('찜 개수'); + } + + const query = { ...router.query, sort }; + router.push({ pathname: router.pathname, query }, undefined, { + shallow: true, + }); + }; + + useEffect(() => { + if (router.query.sort) { + setSelectedSort(router.query.sort as string); + } + }, [router.query.sort]); + const filteredFacilities = filterFacilitiesBySport(facilities, selectedSport); + const sortedFacilities = sortFacilities(filteredFacilities, selectedSort); const parseLocalCode = (localCode: string): string => { const cityCode = localCode.slice(0, 2); @@ -148,11 +199,6 @@ export default function Popular() { setIsDropdownOpen(prevState => !prevState); }; - const handleSelectSort = (sort: string) => { - setSelectedSort(sort); - setIsDropdownOpen(false); - }; - useOutsideClick(dropdownRef, toggleDropdown); return ( @@ -261,8 +307,12 @@ export default function Popular() {
-
- {selectedSort} +
+ {selectedSortName}
{isDropdownOpen && ( -
handleSelectSort('인기순')} - ref={dropdownRef} - > -
인기순
+
+
handleSelectSort('total')} + > + 누적 수강 수 +
+
handleSelectSort('average')} + > + 별점 순 +
+
handleSelectSort('review')} + > + 후기 개수 +
+
handleSelectSort('favorite')} + > + 찜 개수 +
)}
- {filteredFacilities.length > 0 ? ( + {sortedFacilities.length > 0 ? (
- {filteredFacilities.map(facility => ( + {sortedFacilities.map(facility => (
-

{facility.name}

+
+

{facility.name}

+ + +