Skip to content
Merged
2 changes: 1 addition & 1 deletion apps/web/app/_apis/schemas/request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export const RequestDetailSchema = PlaceDetailSchema.omit({
isLiked: true,
}).extend({
registerStatus,
rejectedReason: z.optional(z.string()),
rejectedReason: z.nullable(z.string()),
})

export type Request = z.infer<typeof RequestSchema>
Expand Down
55 changes: 55 additions & 0 deletions apps/web/app/_components/EmptyFallback/EmptyFallback.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { Column } from '@repo/ui/components/Layout'
import { Text } from '@repo/ui/components/Text'
import { ReactNode } from 'react'

type Props = {
/** 데이터가 비어있는지 여부 (true면 Fallback, false면 children 렌더링) */
isEmpty: boolean
/** 데이터가 비어있을 때 보여줄 제목 (예: "검색 결과가 없습니다") */
fallbackTitle?: string
/** 데이터가 비어있을 때 보여줄 상세 설명 */
fallbackDescription?: string
/** 데이터가 존재할 때 렌더링할 실제 콘텐츠 */
children: ReactNode
}

/**
* 데이터 유무(`isEmpty`)에 따라 Fallback UI 또는 실제 콘텐츠를 조건부 렌더링하는 래퍼 컴포넌트입니다.
*
* @example
* ```tsx
* <EmptyFallback
* isEmpty={feeds.length === 0}
* fallbackTitle="작성된 일기가 없습니다."
* fallbackDescription="첫 번째 일기를 작성해보세요!"
* >
* <FeedList data={feeds} />
* </EmptyFallback>
* ```
*/
export const EmptyFallback = ({
isEmpty,
fallbackTitle,
fallbackDescription,
children,
}: Props) => {
if (!isEmpty) return <>{children}</>

return (
<Column className='h-full flex-1 items-center justify-center gap-1 p-10 text-center'>
{fallbackTitle && (
<Text variant='title3' className='text-gray-300'>
{fallbackTitle}
</Text>
)}
{fallbackDescription && (
<Text
variant='body1'
className='whitespace-pre-wrap break-words text-gray-300'
>
{fallbackDescription}
</Text>
)}
</Column>
)
}
1 change: 1 addition & 0 deletions apps/web/app/_components/EmptyFallback/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { EmptyFallback } from './EmptyFallback'
42 changes: 16 additions & 26 deletions apps/web/app/likes/_components/LikePlacesList/LikePlacesList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,36 +3,26 @@
import { useSuspenseQuery } from '@tanstack/react-query'
import { usePlaceQueries } from '@/_apis/queries/place'
import { PlaceListItem } from '@/_components/PlaceListItem'
import { Text } from '@repo/ui/components/Text'
import { Column } from '@repo/ui/components/Layout'
import { EmptyFallback } from '@/_components/EmptyFallback'

export const LikePlacesList = () => {
const { data: places = [] } = useSuspenseQuery(usePlaceQueries.byLike())

if (places.length === 0) {
return (
<Column className={'my-auto h-full items-center justify-center'}>
<Text variant={'title3'} className={'text-gray-300'}>
{/*아직 찜한 맛집이 없어요*/}
나만의 맛집 리스트를 만들어보세요!
</Text>
<Text variant={'body1'} className={'text-gray-300'}>
{/*하트를 눌러 나만의 맛집을 저장해보세요!*/}
자주 가는 식당을 찜해두면 편하게 볼 수 있어요.
</Text>
</Column>
)
}

return (
<ul className={'px-3'}>
{places.map((place, index) => (
<PlaceListItem
key={place.placeId}
{...place}
showBorder={index !== places.length - 1}
/>
))}
</ul>
<EmptyFallback
isEmpty={places.length === 0}
fallbackTitle={'나만의 맛집 리스트를 만들어보세요!'}
fallbackDescription={'자주 가는 식당을 찜해두면 편하게 볼 수 있어요.'}
>
<ul className={'px-3'}>
{places.map((place, index) => (
<PlaceListItem
key={place.placeId}
{...place}
showBorder={index !== places.length - 1}
/>
))}
</ul>
</EmptyFallback>
)
}
17 changes: 6 additions & 11 deletions apps/web/app/map/_components/PlaceList/PlaceList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { useRef } from 'react'
import { BottomSheet, type BottomSheetRef } from 'react-spring-bottom-sheet'
import type { PlaceByMap } from '@/_apis/schemas/place'
import { PlaceListItem } from '@/_components/PlaceListItem'
import { Text } from '@repo/ui/components/Text'
import { EmptyFallback } from '@/_components/EmptyFallback'

export const PlaceList = ({ places }: { places: PlaceByMap[] }) => {
const sheetRef = useRef<BottomSheetRef | null>(null)
Expand All @@ -23,21 +23,16 @@ export const PlaceList = ({ places }: { places: PlaceByMap[] }) => {
]}
expandOnContentDrag
>
{places.length > 0 ? (
<EmptyFallback
isEmpty={places.length === 0}
fallbackDescription={'주위 검색된 맛집이 없습니다'}
>
<ul className={'pb-15 px-5'}>
{places.map((place) => (
<PlaceListItem key={place.placeId} {...place} />
))}
</ul>
) : (
<Text
fontSize={'sm'}
fontWeight={'semibold'}
className={'pt-3 text-center text-gray-300'}
>
주위 검색된 맛집이 없습니다
</Text>
)}
</EmptyFallback>
</BottomSheet>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { StatusChip } from '../StatusChip'
import type { Request } from '@/_apis/schemas/request'

export const PlaceListItem = ({
// placeId,
placeId,
placeName,
categories,
requestDate,
Expand All @@ -21,7 +21,7 @@ export const PlaceListItem = ({
<JustifyBetween
as={Link}
prefetch={false}
href={CLIENT_PATH.REQUEST_DETAIL('1')}
href={CLIENT_PATH.REQUEST_DETAIL(placeId)}
className={cn('gap-1', 'py-3.5', 'border-b-1 border-gray-50')}
>
<Column as={'div'}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,22 @@
import { useSuspenseQuery } from '@tanstack/react-query'
import { useRequestQueries } from '@/_apis/queries/request'
import { PlaceListItem } from '../PlaceListItem'
import { EmptyFallback } from '@/_components/EmptyFallback'

export const RequestPlacesList = () => {
const { data } = useSuspenseQuery(useRequestQueries.list())

return (
<ul className={'p-5'}>
{data.map((place) => (
<PlaceListItem key={place.placeId} {...place} />
))}
</ul>
<EmptyFallback
isEmpty={data.length === 0}
fallbackTitle={'아직 신청한 내역이 없어요!'}
fallbackDescription={'나만 알기 아까운 맛집, 직접 제보해보는 건 어때요?'}
>
<ul className={'p-5'}>
{data.map((place) => (
<PlaceListItem key={place.placeId} {...place} />
))}
</ul>
</EmptyFallback>
)
}
16 changes: 9 additions & 7 deletions apps/web/app/requests/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,7 @@ export const dynamic = 'force-dynamic'

const Page = async () => {
return (
<HydrationBoundaryPage
prefetch={async (queryClient) => {
await queryClient.prefetchQuery(useRequestQueries.list())
}}
>
<>
<Header
left={<HeaderBackButton />}
center={
Expand All @@ -26,8 +22,14 @@ const Page = async () => {
</Flex>
}
/>
<RequestPlacesList />
</HydrationBoundaryPage>
<HydrationBoundaryPage
prefetch={async (queryClient) => {
await queryClient.prefetchQuery(useRequestQueries.list())
}}
>
<RequestPlacesList />
</HydrationBoundaryPage>
</>
)
}

Expand Down
5 changes: 5 additions & 0 deletions apps/web/next.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ const nextConfig: NextConfig = {
hostname: 't1.daumcdn.net',
pathname: '/**',
},
{
protocol: 'https',
hostname: 't1.kakaocdn.net',
pathname: '/**',
},
{
protocol: 'http',
hostname: 't1.kakaocdn.net',
Expand Down