-
Notifications
You must be signed in to change notification settings - Fork 1
πAPI & β¨Feat : μ΄λ²€νΈ νμ΄μ§ api μ°κ²° #123
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
b001f51
dc661e4
aa595f2
2ad0b18
ac01835
b1fe18a
cc14c8e
a1badcd
118f98c
0ae7073
921aa3f
99bab3f
e97ecf6
2119aa6
0969058
13eed95
7359e55
389e160
e730c25
b2de4d1
5c8cf5d
bc38265
2a5017a
0d34fb2
c46fc31
6098283
1b116df
7a954e9
27e232b
dc6070d
fcbaee2
cdc4f5c
a28d795
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,113 +1,145 @@ | ||
| 'use client'; | ||
|
|
||
| import { useEffect } from 'react'; | ||
| import { Header, EventCard } from '@/shared/components'; | ||
| import DateTag from '@/pages/events/components/DateTag'; | ||
| import { cn } from '@/shared/lib'; | ||
| import { eventData } from '@/shared/constants/events/eventsData'; | ||
| import Image from 'next/image'; | ||
| import { useRouter } from 'next/router'; | ||
| import { useEventDetail } from '@/shared/hooks/events/useEventDetail'; | ||
| import { buildNextEventList } from '@/shared/utils/buildNextEventList'; | ||
| import type { RelatedEventOrEmpty } from '@/shared/types/eventtypes'; | ||
|
|
||
| const isEmptyItem = (item: RelatedEventOrEmpty): item is { isEmpty: true } => | ||
| 'isEmpty' in item; | ||
|
|
||
| const EventDetailPage = () => { | ||
| const router = useRouter(); | ||
| const { id } = router.query; | ||
| const { id, date } = router.query; | ||
|
|
||
| const eventId = Number(id); | ||
| const { data: eventDetail, isLoading, isError } = useEventDetail(eventId); | ||
|
|
||
| useEffect(() => { | ||
| if (!isLoading && (isError || !eventDetail)) { | ||
| router.replace('/events'); | ||
| } | ||
| }, [isLoading, isError, eventDetail, router]); | ||
|
|
||
| const event = eventData.find((e) => e.id === Number(id)); | ||
| if (!event) return null; | ||
| if (!eventId) return null; | ||
| if (isError || !eventDetail) return null; | ||
| if (!router.isReady) return null; | ||
|
|
||
| const { name, address, description, startDate, endDate, imageSrc } = event; | ||
| const { title, body, address, startDate, endDate, imageUrl, nextEvents } = | ||
| eventDetail; | ||
|
|
||
| return ( | ||
| <div | ||
| className={cn( | ||
| 'relative w-full min-h-[100vh] overflow-auto', | ||
| )} | ||
| > | ||
| const nextList = buildNextEventList(nextEvents); | ||
|
|
||
| return ( | ||
| <div className={cn('relative w-full min-h-[100vh] overflow-auto')}> | ||
| <Header | ||
| title='νμ¬λͺ ' | ||
| onClick={() => router.back()} | ||
| onClick={() => router.push(`/events${date ? `?date=${date}` : ''}`)} | ||
| className={cn('fixed top-0 left-0 right-0 z-50')} | ||
| /> | ||
|
|
||
| <main | ||
| className={cn( | ||
| 'flex flex-col items-center justify-start', | ||
| 'px-[2.4rem] pt-[calc(10rem+1.4rem)]' | ||
| 'px-[2.4rem] pt-[calc(10rem+1.4rem)]', | ||
| )} | ||
| > | ||
| {/* νμ¬ κΈ°κ° */} | ||
| <div aria-label="νμ¬ κΈ°κ°" className={cn('flex justify-center w-[18.4rem] mt-[1.3rem]')}> | ||
| <div | ||
| aria-label='νμ¬ κΈ°κ°' | ||
| className={cn('flex justify-center w-[18.4rem] mt-[1.3rem]')} | ||
| > | ||
| <DateTag startDate={startDate} endDate={endDate} /> | ||
| </div> | ||
|
|
||
| {/* λν μ΄λ―Έμ§ */} | ||
| <section | ||
| aria-label="νμ¬ λν μ΄λ―Έμ§" | ||
| aria-label='νμ¬ λν μ΄λ―Έμ§' | ||
| className={cn( | ||
| 'relative w-full flex justify-center max-w-[35.4rem]', | ||
| 'mt-[1rem]' | ||
| 'relative w-full flex justify-center max-w-[35.4rem] h-[43rem]', | ||
| 'mt-[1rem]', | ||
| )} | ||
| > | ||
| {imageSrc ? ( | ||
| {imageUrl ? ( | ||
| <Image | ||
| src={imageSrc} | ||
| alt={`${name} μ΄λ―Έμ§`} | ||
| width={354} | ||
| height={430} | ||
| className={cn('w-full h-auto object-cover rounded-[2rem]')} | ||
| src={imageUrl} | ||
| alt={`${title} μ΄λ―Έμ§`} | ||
| fill | ||
| className={cn('object-cover rounded-[2rem]')} | ||
| /> | ||
| ) : ( | ||
| <div | ||
| className={cn('w-full h-[43.6rem] bg-gray-200 rounded-[2rem]')} | ||
| role="img" | ||
| aria-label={`${name} μ΄λ―Έμ§κ° μ 곡λμ§ μμ΅λλ€.`} | ||
| className={cn('w-full h-full bg-gray-200 rounded-[2rem]')} | ||
| role='img' | ||
| aria-label={`${title} μ΄λ―Έμ§κ° μ 곡λμ§ μμ΅λλ€.`} | ||
| /> | ||
| )} | ||
| </section> | ||
|
|
||
| {/* νμ¬ μΉ΄λ */} | ||
| <div | ||
| aria-label="νμ¬ μ 보" | ||
| aria-label='νμ¬ μ 보' | ||
| className={cn( | ||
| 'flex flex-col items-center w-full gap-[0.8rem]', | ||
| 'mt-[0.8rem]' | ||
| 'mt-[0.8rem]', | ||
| )} | ||
| > | ||
| <EventCard | ||
| name={name} | ||
| address={address} | ||
| description={description} | ||
| eventId={eventId} | ||
| name={title} | ||
| address={address ?? ''} | ||
| description={body ?? ''} | ||
| variant='gray' | ||
| size='large' | ||
| imageSrc={imageUrl ?? ''} | ||
| liked={eventDetail.isBookmarked ?? false} | ||
| /> | ||
|
|
||
| {/* κ΄λ ¨ νμ¬ */} | ||
| <div | ||
| aria-label="κ΄λ ¨ νμ¬ λͺ©λ‘" | ||
| aria-label='κ΄λ ¨ νμ¬ λͺ©λ‘' | ||
| className={cn( | ||
| 'grid grid-cols-2 gap-[1.2rem] justify-items-center w-full max-w-[35.4rem]' | ||
| 'grid grid-cols-2 gap-[1.2rem] justify-items-center w-full max-w-[35.4rem]', | ||
| )} | ||
| > | ||
| <div className={cn('w-[17rem]')}> | ||
| <EventCard | ||
| name='κ΄λ ¨ νμ¬' | ||
| address='' | ||
| description='' | ||
| variant='gray' | ||
| size='small' | ||
| /> | ||
| </div> | ||
| <div className={cn('w-[17rem]')}> | ||
| <EventCard | ||
| name='κ΄λ ¨ νμ¬' | ||
| address='' | ||
| description='' | ||
| variant='gray' | ||
| size='small' | ||
| /> | ||
| </div> | ||
| {nextList.map((item: RelatedEventOrEmpty, idx) => ( | ||
| <div key={idx} className={cn('w-[17rem]')}> | ||
| {isEmptyItem(item) ? ( | ||
| <EventCard | ||
| eventId={0} | ||
| name='νμ¬ μμ' | ||
| address='' | ||
| description='' | ||
| imageSrc='' | ||
| variant='gray' | ||
| size='small' | ||
| liked={false} | ||
| onClick={() => null} | ||
| /> | ||
| ) : ( | ||
| <EventCard | ||
| eventId={item.eventId} | ||
| name={item.title} | ||
| address='' | ||
| description='' | ||
| imageSrc={item.imageUrl} | ||
| variant='gray' | ||
| size='small' | ||
| liked={false} | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. π§© Analysis chainκ΄λ ¨ νμ¬μ λΆλ§ν¬ μν νμΈμ΄ νμν©λλ€. κ΄λ ¨ νμ¬μ νμ¬ π Script executed: #!/bin/bash
# RelatedEvent νμ
μ μ νμΈ
ast-grep --pattern $'interface RelatedEvent {
$$$
}'Length of output: 259 π Script executed: #!/bin/bash
# Check the actual code context around line 123 in [id].tsx
sed -n '115,130p' src/pages/events/[id].tsxLength of output: 445 π Script executed: #!/bin/bash
# Search for RelatedEvent component usage and bookmark-related props
rg -n "liked\s*=" src/pages/events/[id].tsx -A 2 -B 2Length of output: 313 π Script executed: #!/bin/bash
# Check if there's an Event type with bookmark state that should be mapped to RelatedEvent
rg -n "interface Event|type Event" src/shared/types/ -A 10Length of output: 1937
κ²μ¦ κ²°κ³Ό:
νμν μμ :
μ΄λ PR λͺ©νμΈ "λΆλ§ν¬ UI λκΈ°ν νμΈ (todo)"λ₯Ό μλ£νλ λ° νμμ λλ€. π€ Prompt for AI Agents |
||
| onClick={() => router.push(`/events/${item.eventId}`)} | ||
| /> | ||
| )} | ||
| </div> | ||
| ))} | ||
| </div> | ||
| </div> | ||
| </main> | ||
| </div> | ||
| ); | ||
| }; | ||
|
|
||
| export default EventDetailPage; | ||
| export default EventDetailPage; | ||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -1,6 +1,6 @@ | ||||||
| 'use client'; | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Pages Routerμμλ 'use client' μ§μμ΄κ° νμνμ§ μμ΅λλ€. νμ¬ νλ‘μ νΈλ Next.js Pages Routerλ₯Ό μ¬μ©νκ³ μλλ°, λ€μκ³Ό κ°μ΄ μ κ±°ν΄ μ£ΌμΈμ: -'use client';
-
import { useState, useEffect } from 'react';Based on learnings π Committable suggestion
Suggested change
π€ Prompt for AI Agents |
||||||
|
|
||||||
| import { useState } from 'react'; | ||||||
| import { useState, useEffect } from 'react'; | ||||||
| import { useRouter } from 'next/router'; | ||||||
| import { Icon } from '@/shared/icons'; | ||||||
| import { cn } from '@/shared/lib'; | ||||||
|
|
@@ -10,22 +10,24 @@ import { | |||||
| BottomNav, | ||||||
| EventCard, | ||||||
| } from '@/shared/components'; | ||||||
| import { eventData } from '@/shared/constants/events/eventsData'; | ||||||
| import { formatDateToISO, isDateWithinRange } from '@/shared/utils/date'; | ||||||
| import { useEvents } from '@/shared/hooks/events/useEvents'; | ||||||
| import type { EventData } from '@/shared/types/eventtypes'; | ||||||
| import { formatDateToISO } from '@/shared/utils/date'; | ||||||
|
|
||||||
| export default function EventPage() { | ||||||
| const router = useRouter(); | ||||||
| const [date, setDate] = useState<Date>(); | ||||||
| const { date: dateQuery } = router.query; | ||||||
| const [date, setDate] = useState<Date | undefined>(undefined); | ||||||
| const { events } = useEvents(date); | ||||||
KongMezu marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
|
|
||||||
| const selectedDate = formatDateToISO(date); | ||||||
| const filteredEvents = events; | ||||||
| useEffect(() => { | ||||||
| if (router.isReady && dateQuery) { | ||||||
| setDate(new Date(String(dateQuery))); | ||||||
| } | ||||||
| }, [router.isReady, dateQuery]); | ||||||
|
|
||||||
| const filteredEvents = eventData.filter((event) => | ||||||
| isDateWithinRange(selectedDate, event.startDate, event.endDate), | ||||||
| ); | ||||||
|
|
||||||
| const handleCardClick = (id: number) => { | ||||||
| router.push(`/events/${id}`); | ||||||
| }; | ||||||
| const selectedDateString = date ? formatDateToISO(date) : ''; | ||||||
|
|
||||||
| return ( | ||||||
| <div | ||||||
|
|
@@ -34,47 +36,55 @@ export default function EventPage() { | |||||
| )} | ||||||
| > | ||||||
| {/* ν€λ */} | ||||||
| <ControlBar className="fixed top-[1rem] left-0 right-0 z-50 px-[2rem]" /> | ||||||
| <ControlBar className='fixed top-[1rem] left-0 right-0 z-50 px-[2rem]' /> | ||||||
|
|
||||||
| {/* λ³Έλ¬Έ μ½ν μΈ */} | ||||||
| <main className='w-full pt-[6.3rem] flex flex-col items-center'> | ||||||
| {/* λ μ§ μ ν */} | ||||||
| <div className='w-full mt-[3.7rem] flex justify-start'> | ||||||
| {/* μ€ν¬λ¦°λ¦¬λκ° βλ μ§ μ νβμΌλ‘ μ½νλλ‘ μΆκ° */} | ||||||
| <label htmlFor="event-date" className="sr-only"> | ||||||
| <label htmlFor='event-date' className='sr-only'> | ||||||
| νμ¬ λ μ§ μ ν | ||||||
| </label> | ||||||
| <DatePicker ariaLabel="νμ¬ λ μ§ μ ν" value={date} onChange={setDate} /> | ||||||
| <DatePicker | ||||||
| ariaLabel='νμ¬ λ μ§ μ ν' | ||||||
| value={date} | ||||||
| onChange={setDate} | ||||||
| /> | ||||||
KongMezu marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
| </div> | ||||||
|
|
||||||
| {/* νμ¬μΉ΄λ & λΉνλ©΄ */} | ||||||
| {filteredEvents.length > 0 ? ( | ||||||
| <section | ||||||
| aria-label="μ΄λ²€νΈ λͺ©λ‘" | ||||||
| aria-label='μ΄λ²€νΈ λͺ©λ‘' | ||||||
| className={cn( | ||||||
| 'grid w-full mt-[1.4rem]', | ||||||
| 'grid-cols-2 gap-x-[1.4rem] gap-y-[1.4rem]', | ||||||
| )} | ||||||
| > | ||||||
| {filteredEvents.map((event) => ( | ||||||
| {filteredEvents.map((event: EventData) => ( | ||||||
| <div | ||||||
| key={event.id} | ||||||
| onClick={() => handleCardClick(event.id)} | ||||||
| onClick={() => | ||||||
| router.push(`/events/${event.id}?date=${selectedDateString}`) | ||||||
| } | ||||||
| className='cursor-pointer' | ||||||
| > | ||||||
| <EventCard | ||||||
| eventId={event.id} | ||||||
| name={event.name} | ||||||
| address={event.address} | ||||||
| description={event.description} | ||||||
| variant='gray' | ||||||
| size='medium' | ||||||
| imageSrc={event.imageSrc ?? ''} | ||||||
| imageSrc={event.imageSrc} | ||||||
| liked={event.liked} | ||||||
| /> | ||||||
| </div> | ||||||
| ))} | ||||||
| </section> | ||||||
| ) : ( | ||||||
| <div | ||||||
| <div | ||||||
| className='flex flex-col items-center justify-center text-center mt-[15rem]' | ||||||
| role='status' | ||||||
| aria-live='polite' | ||||||
|
|
||||||
Uh oh!
There was an error while loading. Please reload this page.