Skip to content

Commit 475a06a

Browse files
authored
Merge pull request #79 from geulDa/feat/#61/eventpage
✨Feat : 행사 페이지 작업
2 parents 1803a39 + 8e0e4ec commit 475a06a

File tree

4 files changed

+235
-9
lines changed

4 files changed

+235
-9
lines changed

src/pages/events/index.tsx

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
'use client';
2+
3+
import { useState } from 'react';
4+
import { useRouter } from 'next/router';
5+
import { Icon } from '@/shared/icons';
6+
import { cn } from '@/shared/lib';
7+
import {
8+
ControlBar,
9+
DatePicker,
10+
BottomNav,
11+
EventCard,
12+
} from '@/shared/components';
13+
import { eventData } from '@/shared/constants/events/eventsData';
14+
15+
export default function EventPage() {
16+
const router = useRouter();
17+
const [date, setDate] = useState<Date>();
18+
19+
const selectedDate = date
20+
? new Date(date.getTime() - date.getTimezoneOffset() * 60000)
21+
.toISOString()
22+
.split('T')[0]
23+
: undefined;
24+
25+
const filteredEvents = eventData.filter((event) => {
26+
if (!selectedDate) return false;
27+
const start = new Date(event.startDate);
28+
const end = new Date(event.endDate);
29+
const selected = new Date(selectedDate);
30+
return selected >= start && selected <= end;
31+
});
32+
33+
const handleCardClick = (id: number) => {
34+
router.push(`/events/${id}`);
35+
};
36+
37+
return (
38+
<div
39+
className={cn(
40+
'px-[2.4rem] bg-white flex flex-col gap-[1rem] h-full pt-[1.3rem] overflow-hidden',
41+
)}
42+
>
43+
{/* 헤더 */}
44+
<ControlBar
45+
isLoggedIn={true}
46+
userName='홍길동'
47+
onLogin={() => {}}
48+
className='fixed top-[1rem] left-0 right-0 z-50 px-[2rem]'
49+
/>
50+
51+
{/* 본문 콘텐츠 */}
52+
<main className='w-full pt-[6.3rem] flex flex-col items-center'>
53+
{/* 날짜 선택 */}
54+
<div className='w-full mt-[3.7rem] flex justify-start'>
55+
<DatePicker value={date} onChange={setDate} />
56+
</div>
57+
58+
{/* 행사카드 & 빈화면 */}
59+
{filteredEvents.length > 0 ? (
60+
<section
61+
className={cn(
62+
'grid w-full mt-[1.4rem]',
63+
'grid-cols-2 gap-x-[1.4rem] gap-y-[1.4rem]',
64+
)}
65+
>
66+
{filteredEvents.map((event) => (
67+
<div
68+
key={event.id}
69+
onClick={() => handleCardClick(event.id)}
70+
className='cursor-pointer'
71+
>
72+
<EventCard
73+
name={event.name}
74+
address={event.address}
75+
description={event.description}
76+
variant='gray'
77+
size='medium'
78+
imageSrc={event.imageSrc ?? ''}
79+
/>
80+
</div>
81+
))}
82+
</section>
83+
) : (
84+
<div className='flex flex-col items-center justify-center text-center mt-[15rem]'>
85+
<Icon name='Stamp' size={120} color='gray-200' />
86+
<h2 className='text-headline-lg-serif text-gray-700 mt-[5rem]'>
87+
Ooops!
88+
</h2>
89+
<p className='text-label-serif text-gray-500 mt-[2.4rem]'>
90+
선택하신 날은
91+
<br />
92+
행사가 없어요!
93+
</p>
94+
</div>
95+
)}
96+
</main>
97+
98+
<BottomNav />
99+
</div>
100+
);
101+
}

src/shared/components/container/EventCard.tsx

Lines changed: 58 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { useState } from 'react';
12
import { Icon } from '@/shared/icons';
23
import { Card } from '@/shared/components/container/Card';
34
import { cn } from '@/shared/lib';
@@ -7,8 +8,10 @@ interface EventCardProps {
78
name: string;
89
address: string;
910
description: string;
11+
startDate?: string;
12+
endDate?: string;
1013
variant?: 'gray' | 'mint';
11-
size?: 'medium' | 'large';
14+
size?: 'small' | 'medium' | 'large';
1215
imageSrc?: string;
1316
}
1417

@@ -20,14 +23,47 @@ const EventCard = ({
2023
size = 'medium',
2124
imageSrc = '',
2225
}: EventCardProps) => {
26+
const [liked, setLiked] = useState(false);
27+
28+
const handleLikeClick = () => {
29+
setLiked((prev) => !prev);
30+
};
2331
return (
2432
<Card
2533
variant={variant}
26-
size={size}
27-
customHeight={size === 'large' ? '13rem' : undefined}
34+
size={size === 'small' ? undefined : size}
35+
customHeight={
36+
size === 'large' ? '13rem' : size === 'small' ? '8rem' : undefined
37+
}
2838
>
29-
{/* Medium 카드 */}
30-
{size === 'medium' ? (
39+
{size === 'small' ? (
40+
<div className='flex w-[17rem] h-[8rem] p-[0.9rem_1rem] justify-center items-center flex-shrink-0 gap-[2rem]'>
41+
{/* 행사 사진 */}
42+
<div className='relative w-[7rem] h-full rounded-[0.8rem] flex-shrink-0 overflow-hidden'>
43+
{imageSrc ? (
44+
<Image
45+
src={imageSrc}
46+
alt={name}
47+
fill
48+
className='object-cover'
49+
sizes='7rem'
50+
loading='lazy'
51+
/>
52+
) : (
53+
<div className='absolute inset-0 bg-gray-200 rounded-[0.8rem]' />
54+
)}
55+
</div>
56+
{/* 행사 이름*/}
57+
<span
58+
className={cn(
59+
'text-label-md truncate mb-[3rem]',
60+
variant === 'mint' ? 'text-mint-800' : 'text-gray-600',
61+
)}
62+
>
63+
{name}
64+
</span>
65+
</div>
66+
) : size === 'medium' ? (
3167
<div className='flex flex-col justify-between w-full'>
3268
{/* 행사 사진 */}
3369
<div className='relative w-full h-[9rem] rounded-[2rem] mb-[1rem] overflow-hidden'>
@@ -59,7 +95,12 @@ const EventCard = ({
5995
<Icon
6096
name='HeartStraight'
6197
size={20}
62-
color={variant === 'mint' ? 'mint-400' : 'gray-300'}
98+
color={
99+
liked ? 'red-400' : variant === 'mint' ? 'mint-400' : 'gray-300'
100+
}
101+
fillColor={liked ? 'red-300' : undefined}
102+
onClick={handleLikeClick}
103+
className='cursor-pointer'
63104
/>
64105
</div>
65106
{/* 행사 주소 */}
@@ -105,7 +146,16 @@ const EventCard = ({
105146
<Icon
106147
name='HeartStraight'
107148
size={20}
108-
color={variant === 'mint' ? 'mint-400' : 'gray-300'}
149+
color={
150+
liked
151+
? 'red-400'
152+
: variant === 'mint'
153+
? 'mint-400'
154+
: 'gray-300'
155+
}
156+
fillColor={liked ? 'red-300' : undefined}
157+
onClick={handleLikeClick}
158+
className='cursor-pointer'
109159
/>
110160
</div>
111161

@@ -125,4 +175,4 @@ const EventCard = ({
125175
);
126176
};
127177

128-
export default EventCard;
178+
export default EventCard;
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
export interface EventData {
2+
id: number;
3+
name: string;
4+
address: string;
5+
description: string;
6+
startDate: string;
7+
endDate: string;
8+
imageSrc?: string;
9+
}
10+
11+
export const eventData: EventData[] = [
12+
{
13+
id: 1,
14+
name: 'ICPC',
15+
address: '다솔관',
16+
description: '야르',
17+
startDate: '2025-11-01',
18+
endDate: '2025-11-03',
19+
imageSrc: '',
20+
},
21+
{
22+
id: 2,
23+
name: '아우름제',
24+
address: '울학교',
25+
description: '야르',
26+
startDate: '2025-11-01',
27+
endDate: '2025-11-02',
28+
imageSrc: '',
29+
},
30+
{
31+
id: 3,
32+
name: '졸업식',
33+
address: '가톨릭대학교',
34+
description: '야르',
35+
startDate: '2025-10-31',
36+
endDate: '2025-10-31',
37+
imageSrc: '',
38+
},
39+
{
40+
id: 4,
41+
name: '학술제',
42+
address: '가톨릭대학교',
43+
description: '야르',
44+
startDate: '2025-10-30',
45+
endDate: '2025-10-31',
46+
imageSrc: '',
47+
},
48+
{
49+
id: 5,
50+
name: '둡둗다다',
51+
address: '부천시청',
52+
description: '야르',
53+
startDate: '2025-10-30',
54+
endDate: '2025-10-31',
55+
imageSrc: '',
56+
},
57+
{
58+
id: 6,
59+
name: '배고파요',
60+
address: '부천역',
61+
description: '야르',
62+
startDate: '2025-10-31',
63+
endDate: '2025-11-01',
64+
imageSrc: '',
65+
},
66+
{
67+
id: 7,
68+
name: '마짐막 테스트',
69+
address: '가톨릭대학교',
70+
description: '야르',
71+
startDate: '2025-10-31',
72+
endDate: '2025-11-01',
73+
imageSrc: '',
74+
},
75+
];

0 commit comments

Comments
 (0)