Skip to content

Commit

Permalink
Merge pull request #46 from gunganghaljido/feature/조혜진
Browse files Browse the repository at this point in the history
Feat: 인기페이지 정렬 추가
  • Loading branch information
MEGUMMY1 authored Dec 2, 2024
2 parents c8adbda + 9ed2a2f commit 3a4597b
Show file tree
Hide file tree
Showing 11 changed files with 164 additions and 27 deletions.
3 changes: 3 additions & 0 deletions public/icon/custom/average-icon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions public/icon/custom/like-icon.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/apis/get/getPopular.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ export interface NomalPopular {
owner: string;
totalParticipantCount: number;
items: string[];
averageScore: number;
reviewCount: number;
favoriteCount: number;
}

export interface getNomalPopularParams {
Expand Down Expand Up @@ -54,6 +57,9 @@ export interface SpecialPopular {
detailAddress: string;
totalParticipantCount: number;
items: string[];
averageScore: number;
reviewCount: number;
favoriteCount: number;
}

export interface getSpecialPopularParams {
Expand Down
16 changes: 16 additions & 0 deletions src/components/Button/Chips/Chips.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
4 changes: 3 additions & 1 deletion src/components/Button/Chips/Chips.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ export type ChipState =
| 'label'
| 'sports'
| 'count'
| 'top';
| 'top'
| 'like'
| 'average';

export interface ChipsProps {
text: string | number | undefined;
Expand Down
11 changes: 11 additions & 0 deletions src/components/Button/Chips/index.tsx
Original file line number Diff line number Diff line change
@@ -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) => {
Expand All @@ -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; // 기본 라벨 칩
Expand All @@ -23,6 +28,12 @@ export default function Chips({ chipState, text, serialNumber }: ChipsProps) {

return (
<div className={`${styles.container} ${getChipClass(chipState)}`}>
{chipState === 'like' && (
<IconComponent name="like" width={14} height={14} />
)}
{chipState === 'average' && (
<IconComponent name="average" width={12} height={12} />
)}
{chipState === 'count' ? `누적 수강 ${formatCurrency(text)}` : text}
</div>
);
Expand Down
29 changes: 20 additions & 9 deletions src/components/Lesson/Popular/Popular.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}

Expand Down
101 changes: 85 additions & 16 deletions src/components/Lesson/Popular/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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<
Expand All @@ -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<HTMLDivElement>(null);
const toggle = useRecoilValue(toggleState);
const [specialFilterValue, setSpecialFilterValue] = useState<string>('');
const router = useRouter();

const handleSpecialFilterChange = (type: string) => {
setSpecialFilterValue(type);
Expand Down Expand Up @@ -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);
Expand All @@ -148,11 +199,6 @@ export default function Popular() {
setIsDropdownOpen(prevState => !prevState);
};

const handleSelectSort = (sort: string) => {
setSelectedSort(sort);
setIsDropdownOpen(false);
};

useOutsideClick(dropdownRef, toggleDropdown);

return (
Expand Down Expand Up @@ -261,28 +307,51 @@ export default function Popular() {
</div>
</div>
<div className={styles.sortContainer}>
<div className={styles.sort} onClick={toggleDropdown}>
<span className={styles.selectedSort}>{selectedSort}</span>
<div
className={styles.selectedSort}
onClick={toggleDropdown}
ref={dropdownRef}
>
<span>{selectedSortName}</span>
<IconComponent
name={isDropdownOpen ? 'up' : 'down'}
size="s"
alt="sort arrow"
/>
</div>
{isDropdownOpen && (
<div
className={styles.dropdown}
onClick={() => handleSelectSort('인기순')}
ref={dropdownRef}
>
<div className={styles.sort}>인기순</div>
<div className={styles.sortOptions} ref={dropdownRef}>
<div
className={styles.sortOption}
onClick={() => handleSelectSort('total')}
>
누적 수강 수
</div>
<div
className={styles.sortOption}
onClick={() => handleSelectSort('average')}
>
별점 순
</div>
<div
className={styles.sortOption}
onClick={() => handleSelectSort('review')}
>
후기 개수
</div>
<div
className={styles.sortOption}
onClick={() => handleSelectSort('favorite')}
>
찜 개수
</div>
</div>
)}
</div>
</div>
{filteredFacilities.length > 0 ? (
{sortedFacilities.length > 0 ? (
<div className={styles.listContainer}>
{filteredFacilities.map(facility => (
{sortedFacilities.map(facility => (
<Link
key={`${facility.businessId}-${'serialNumber' in facility ? `/${facility.serialNumber}` : ''}`}
href={`/details/${facility.businessId}${'serialNumber' in facility ? `/${facility.serialNumber}` : ''}`}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,9 @@
.count {
margin-right: 4px;
}

.chipsContainer {
display: flex;
align-items: center;
gap: 5px;
}
10 changes: 9 additions & 1 deletion src/components/Schedule/PopularSchedule/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,15 @@ export default function PopularSchedule({ facility }: PopularScheduleProps) {
return (
<div className={styles.container}>
<div>
<h2 className={styles.storeName}>{facility.name}</h2>
<div className={styles.chipsContainer}>
<h2 className={styles.storeName}>{facility.name}</h2>
<Chips text={facility.favoriteCount} chipState="like" serialNumber />
<Chips
text={`${facility.averageScore}(${facility.reviewCount})`}
chipState="average"
serialNumber
/>
</div>
<div className={styles.information}>
<p
className={
Expand Down
2 changes: 2 additions & 0 deletions src/constants/asset.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,8 @@ export const ICONS = {
starFull: '/icon/custom/star-full.svg',
starHalfSP: '/icon/custom/star-half-sp.svg',
starFullSP: '/icon/custom/star-full-sp.svg',
like: '/icon/custom/like-icon.svg',
average: '/icon/custom/average-icon.svg',
};

export const IMAGES = {
Expand Down

0 comments on commit 3a4597b

Please sign in to comment.