1+ 'use client' ;
2+
3+ import { useEffect } from 'react' ;
14import { Header , EventCard } from '@/shared/components' ;
25import DateTag from '@/pages/events/components/DateTag' ;
36import { cn } from '@/shared/lib' ;
4- import { eventData } from '@/shared/constants/events/eventsData' ;
57import Image from 'next/image' ;
68import { useRouter } from 'next/router' ;
9+ import { useEventDetail } from '@/shared/hooks/events/useEventDetail' ;
10+ import { buildNextEventList } from '@/shared/utils/buildNextEventList' ;
11+ import type { RelatedEventOrEmpty } from '@/shared/types/eventtypes' ;
12+
13+ const isEmptyItem = ( item : RelatedEventOrEmpty ) : item is { isEmpty : true } =>
14+ 'isEmpty' in item ;
715
816const EventDetailPage = ( ) => {
917 const router = useRouter ( ) ;
10- const { id } = router . query ;
18+ const { id, date } = router . query ;
19+
20+ const eventId = Number ( id ) ;
21+ const { data : eventDetail , isLoading, isError } = useEventDetail ( eventId ) ;
22+
23+ useEffect ( ( ) => {
24+ if ( ! isLoading && ( isError || ! eventDetail ) ) {
25+ router . replace ( '/events' ) ;
26+ }
27+ } , [ isLoading , isError , eventDetail , router ] ) ;
1128
12- const event = eventData . find ( ( e ) => e . id === Number ( id ) ) ;
13- if ( ! event ) return null ;
29+ if ( ! eventId ) return null ;
30+ if ( isError || ! eventDetail ) return null ;
31+ if ( ! router . isReady ) return null ;
1432
15- const { name, address, description, startDate, endDate, imageSrc } = event ;
33+ const { title, body, address, startDate, endDate, imageUrl, nextEvents } =
34+ eventDetail ;
1635
17- return (
18- < div
19- className = { cn (
20- 'relative w-full min-h-[100vh] overflow-auto' ,
21- ) }
22- >
36+ const nextList = buildNextEventList ( nextEvents ) ;
37+
38+ return (
39+ < div className = { cn ( 'relative w-full min-h-[100vh] overflow-auto' ) } >
2340 < Header
2441 title = '행사명'
25- onClick = { ( ) => router . back ( ) }
42+ onClick = { ( ) => router . push ( `/events ${ date ? `?date= ${ date } ` : '' } ` ) }
2643 className = { cn ( 'fixed top-0 left-0 right-0 z-50' ) }
2744 />
2845
2946 < main
3047 className = { cn (
3148 'flex flex-col items-center justify-start' ,
32- 'px-[2.4rem] pt-[calc(10rem+1.4rem)]'
49+ 'px-[2.4rem] pt-[calc(10rem+1.4rem)]' ,
3350 ) }
3451 >
3552 { /* 행사 기간 */ }
36- < div aria-label = "행사 기간" className = { cn ( 'flex justify-center w-[18.4rem] mt-[1.3rem]' ) } >
53+ < div
54+ aria-label = '행사 기간'
55+ className = { cn ( 'flex justify-center w-[18.4rem] mt-[1.3rem]' ) }
56+ >
3757 < DateTag startDate = { startDate } endDate = { endDate } />
3858 </ div >
3959
4060 { /* 대표 이미지 */ }
4161 < section
42- aria-label = " 행사 대표 이미지"
62+ aria-label = ' 행사 대표 이미지'
4363 className = { cn (
44- 'relative w-full flex justify-center max-w-[35.4rem]' ,
45- 'mt-[1rem]'
64+ 'relative w-full flex justify-center max-w-[35.4rem] h-[43rem] ' ,
65+ 'mt-[1rem]' ,
4666 ) }
4767 >
48- { imageSrc ? (
68+ { imageUrl ? (
4969 < Image
50- src = { imageSrc }
51- alt = { `${ name } 이미지` }
52- width = { 354 }
53- height = { 430 }
54- className = { cn ( 'w-full h-auto object-cover rounded-[2rem]' ) }
70+ src = { imageUrl }
71+ alt = { `${ title } 이미지` }
72+ fill
73+ className = { cn ( 'object-cover rounded-[2rem]' ) }
5574 />
5675 ) : (
5776 < div
58- className = { cn ( 'w-full h-[43.6rem] bg-gray-200 rounded-[2rem]' ) }
59- role = " img"
60- aria-label = { `${ name } 이미지가 제공되지 않습니다.` }
77+ className = { cn ( 'w-full h-full bg-gray-200 rounded-[2rem]' ) }
78+ role = ' img'
79+ aria-label = { `${ title } 이미지가 제공되지 않습니다.` }
6180 />
6281 ) }
6382 </ section >
6483
6584 { /* 행사 카드 */ }
6685 < div
67- aria-label = " 행사 정보"
86+ aria-label = ' 행사 정보'
6887 className = { cn (
6988 'flex flex-col items-center w-full gap-[0.8rem]' ,
70- 'mt-[0.8rem]'
89+ 'mt-[0.8rem]' ,
7190 ) }
7291 >
7392 < EventCard
74- name = { name }
75- address = { address }
76- description = { description }
93+ eventId = { eventId }
94+ name = { title }
95+ address = { address ?? '' }
96+ description = { body ?? '' }
7797 variant = 'gray'
7898 size = 'large'
99+ imageSrc = { imageUrl ?? '' }
100+ liked = { eventDetail . isBookmarked ?? false }
79101 />
80-
81102 { /* 관련 행사 */ }
82103 < div
83- aria-label = " 관련 행사 목록"
104+ aria-label = ' 관련 행사 목록'
84105 className = { cn (
85- 'grid grid-cols-2 gap-[1.2rem] justify-items-center w-full max-w-[35.4rem]'
106+ 'grid grid-cols-2 gap-[1.2rem] justify-items-center w-full max-w-[35.4rem]' ,
86107 ) }
87108 >
88- < div className = { cn ( 'w-[17rem]' ) } >
89- < EventCard
90- name = '관련 행사'
91- address = ''
92- description = ''
93- variant = 'gray'
94- size = 'small'
95- />
96- </ div >
97- < div className = { cn ( 'w-[17rem]' ) } >
98- < EventCard
99- name = '관련 행사'
100- address = ''
101- description = ''
102- variant = 'gray'
103- size = 'small'
104- />
105- </ div >
109+ { nextList . map ( ( item : RelatedEventOrEmpty , idx ) => (
110+ < div key = { idx } className = { cn ( 'w-[17rem]' ) } >
111+ { isEmptyItem ( item ) ? (
112+ < EventCard
113+ eventId = { 0 }
114+ name = '행사 없음'
115+ address = ''
116+ description = ''
117+ imageSrc = ''
118+ variant = 'gray'
119+ size = 'small'
120+ liked = { false }
121+ onClick = { ( ) => null }
122+ />
123+ ) : (
124+ < EventCard
125+ eventId = { item . eventId }
126+ name = { item . title }
127+ address = ''
128+ description = ''
129+ imageSrc = { item . imageUrl }
130+ variant = 'gray'
131+ size = 'small'
132+ liked = { false }
133+ onClick = { ( ) => router . push ( `/events/${ item . eventId } ` ) }
134+ />
135+ ) }
136+ </ div >
137+ ) ) }
106138 </ div >
107139 </ div >
108140 </ main >
109141 </ div >
110142 ) ;
111143} ;
112144
113- export default EventDetailPage ;
145+ export default EventDetailPage ;
0 commit comments