diff --git a/apps/web/app/_apis/schemas/request.ts b/apps/web/app/_apis/schemas/request.ts index c96c340..f7dcec8 100644 --- a/apps/web/app/_apis/schemas/request.ts +++ b/apps/web/app/_apis/schemas/request.ts @@ -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 diff --git a/apps/web/app/_components/EmptyFallback/EmptyFallback.tsx b/apps/web/app/_components/EmptyFallback/EmptyFallback.tsx new file mode 100644 index 0000000..35ab7f6 --- /dev/null +++ b/apps/web/app/_components/EmptyFallback/EmptyFallback.tsx @@ -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 + * + * + * + * ``` + */ +export const EmptyFallback = ({ + isEmpty, + fallbackTitle, + fallbackDescription, + children, +}: Props) => { + if (!isEmpty) return <>{children} + + return ( + + {fallbackTitle && ( + + {fallbackTitle} + + )} + {fallbackDescription && ( + + {fallbackDescription} + + )} + + ) +} diff --git a/apps/web/app/_components/EmptyFallback/index.tsx b/apps/web/app/_components/EmptyFallback/index.tsx new file mode 100644 index 0000000..69243a5 --- /dev/null +++ b/apps/web/app/_components/EmptyFallback/index.tsx @@ -0,0 +1 @@ +export { EmptyFallback } from './EmptyFallback' diff --git a/apps/web/app/likes/_components/LikePlacesList/LikePlacesList.tsx b/apps/web/app/likes/_components/LikePlacesList/LikePlacesList.tsx index 1f1b644..1b0baaf 100644 --- a/apps/web/app/likes/_components/LikePlacesList/LikePlacesList.tsx +++ b/apps/web/app/likes/_components/LikePlacesList/LikePlacesList.tsx @@ -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 ( - - - {/*아직 찜한 맛집이 없어요*/} - 나만의 맛집 리스트를 만들어보세요! - - - {/*하트를 눌러 나만의 맛집을 저장해보세요!*/} - 자주 가는 식당을 찜해두면 편하게 볼 수 있어요. - - - ) - } - return ( - + + + ) } diff --git a/apps/web/app/map/_components/PlaceList/PlaceList.tsx b/apps/web/app/map/_components/PlaceList/PlaceList.tsx index e53b7d9..b619c4b 100644 --- a/apps/web/app/map/_components/PlaceList/PlaceList.tsx +++ b/apps/web/app/map/_components/PlaceList/PlaceList.tsx @@ -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(null) @@ -23,21 +23,16 @@ export const PlaceList = ({ places }: { places: PlaceByMap[] }) => { ]} expandOnContentDrag > - {places.length > 0 ? ( +
    {places.map((place) => ( ))}
- ) : ( - - 주위 검색된 맛집이 없습니다 - - )} +
) } diff --git a/apps/web/app/requests/_components/PlaceListItem/PlaceListItem.tsx b/apps/web/app/requests/_components/PlaceListItem/PlaceListItem.tsx index 8714d15..19da9de 100644 --- a/apps/web/app/requests/_components/PlaceListItem/PlaceListItem.tsx +++ b/apps/web/app/requests/_components/PlaceListItem/PlaceListItem.tsx @@ -8,7 +8,7 @@ import { StatusChip } from '../StatusChip' import type { Request } from '@/_apis/schemas/request' export const PlaceListItem = ({ - // placeId, + placeId, placeName, categories, requestDate, @@ -21,7 +21,7 @@ export const PlaceListItem = ({ diff --git a/apps/web/app/requests/_components/RequestPlacesList/RequestPlacesList.tsx b/apps/web/app/requests/_components/RequestPlacesList/RequestPlacesList.tsx index 1b8d82d..0b44cfd 100644 --- a/apps/web/app/requests/_components/RequestPlacesList/RequestPlacesList.tsx +++ b/apps/web/app/requests/_components/RequestPlacesList/RequestPlacesList.tsx @@ -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 ( -
    - {data.map((place) => ( - - ))} -
+ +
    + {data.map((place) => ( + + ))} +
+
) } diff --git a/apps/web/app/requests/page.tsx b/apps/web/app/requests/page.tsx index 7c7a67a..2a3a3ac 100644 --- a/apps/web/app/requests/page.tsx +++ b/apps/web/app/requests/page.tsx @@ -12,11 +12,7 @@ export const dynamic = 'force-dynamic' const Page = async () => { return ( - { - await queryClient.prefetchQuery(useRequestQueries.list()) - }} - > + <>
} center={ @@ -26,8 +22,14 @@ const Page = async () => { } /> - - + { + await queryClient.prefetchQuery(useRequestQueries.list()) + }} + > + + + ) } diff --git a/apps/web/next.config.ts b/apps/web/next.config.ts index e27f557..dcc071a 100644 --- a/apps/web/next.config.ts +++ b/apps/web/next.config.ts @@ -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',