diff --git a/apps/web/app/_components/PlaceListItem/PlaceListItem.tsx b/apps/web/app/_components/PlaceListItem/PlaceListItem.tsx
index e034b0a..2e49f6c 100644
--- a/apps/web/app/_components/PlaceListItem/PlaceListItem.tsx
+++ b/apps/web/app/_components/PlaceListItem/PlaceListItem.tsx
@@ -6,6 +6,7 @@ import { Text } from '@repo/ui/components/Text'
import { Icon } from '@repo/ui/components/Icon'
import { Chip } from '@repo/ui/components/Chip'
import { Column, Flex } from '@repo/ui/components/Layout'
+import { PlaceListItemSkeleton } from './PlaceListItemSkeleton'
type Props = {
showCategory?: boolean
@@ -53,3 +54,5 @@ export const PlaceListItem = ({
)
}
+
+PlaceListItem.Skeleton = PlaceListItemSkeleton
diff --git a/apps/web/app/_components/PlaceListItem/PlaceListItemSkeleton.tsx b/apps/web/app/_components/PlaceListItem/PlaceListItemSkeleton.tsx
new file mode 100644
index 0000000..3eec057
--- /dev/null
+++ b/apps/web/app/_components/PlaceListItem/PlaceListItemSkeleton.tsx
@@ -0,0 +1,29 @@
+'use client'
+
+import { Skeleton } from '@heroui/react'
+import { Column, Flex } from '@repo/ui/components/Layout'
+import { cn } from '@repo/ui/utils/cn'
+
+type Props = {
+ count?: number
+}
+
+export const PlaceListItemSkeleton = ({ count = 3 }: Props) => {
+ return (
+
+ {Array.from({ length: count }).map((_, index) => (
+
+
+
+
+
+
+
+
+ ))}
+
+ )
+}
diff --git a/apps/web/app/_components/RankingPlaceList/MostLikesPlaces/MostLikesPlaces.tsx b/apps/web/app/_components/RankingPlaceList/MostLikesPlaces/MostLikesPlaces.tsx
deleted file mode 100644
index 8df4501..0000000
--- a/apps/web/app/_components/RankingPlaceList/MostLikesPlaces/MostLikesPlaces.tsx
+++ /dev/null
@@ -1,15 +0,0 @@
-'use client'
-
-import { useSuspenseQuery } from '@tanstack/react-query'
-import { usePlaceQueries } from '@/_apis/queries/place'
-import { RankingPlaceList } from '@/_components/RankingPlaceList'
-import { useCampusStore } from '@/_store/campus'
-
-export const MostLikesPlaces = () => {
- const { campus } = useCampusStore()
- const { data } = useSuspenseQuery(usePlaceQueries.byRanking('likes', campus))
-
- return (
-
- )
-}
diff --git a/apps/web/app/_components/RankingPlaceList/MostLikesPlaces/index.tsx b/apps/web/app/_components/RankingPlaceList/MostLikesPlaces/index.tsx
deleted file mode 100644
index e57fea4..0000000
--- a/apps/web/app/_components/RankingPlaceList/MostLikesPlaces/index.tsx
+++ /dev/null
@@ -1 +0,0 @@
-export { MostLikesPlaces } from './MostLikesPlaces'
diff --git a/apps/web/app/_components/RankingPlaceList/MostViewsPlaces/MostViewsPlaces.tsx b/apps/web/app/_components/RankingPlaceList/MostViewsPlaces/MostViewsPlaces.tsx
deleted file mode 100644
index 999d8ba..0000000
--- a/apps/web/app/_components/RankingPlaceList/MostViewsPlaces/MostViewsPlaces.tsx
+++ /dev/null
@@ -1,13 +0,0 @@
-'use client'
-
-import { useSuspenseQuery } from '@tanstack/react-query'
-import { usePlaceQueries } from '@/_apis/queries/place'
-import { RankingPlaceList } from '@/_components/RankingPlaceList'
-import { useCampusStore } from '@/_store/campus'
-
-export const MostViewsPlaces = () => {
- const { campus } = useCampusStore()
- const { data } = useSuspenseQuery(usePlaceQueries.byRanking('views', campus))
-
- return
-}
diff --git a/apps/web/app/_components/RankingPlaceList/MostViewsPlaces/index.tsx b/apps/web/app/_components/RankingPlaceList/MostViewsPlaces/index.tsx
deleted file mode 100644
index 4bb7554..0000000
--- a/apps/web/app/_components/RankingPlaceList/MostViewsPlaces/index.tsx
+++ /dev/null
@@ -1 +0,0 @@
-export { MostViewsPlaces } from './MostViewsPlaces'
diff --git a/apps/web/app/_components/RankingPlaceList/RankingPlaceList.tsx b/apps/web/app/_components/RankingPlaceList/RankingPlaceList.tsx
index 83b1ee6..6367fe3 100644
--- a/apps/web/app/_components/RankingPlaceList/RankingPlaceList.tsx
+++ b/apps/web/app/_components/RankingPlaceList/RankingPlaceList.tsx
@@ -1,5 +1,11 @@
+'use client'
+
+import { Suspense } from 'react'
+import { useSuspenseQuery } from '@tanstack/react-query'
+import { useCampusStore } from '@/_store/campus'
+import { usePlaceQueries } from '@/_apis/queries/place'
import type { IconType } from '@repo/ui/components/Icon'
-import type { BasePlace } from '@/_apis/schemas/place'
+import type { RankingPlaceSort } from '@/_apis/schemas/place'
import { Column } from '@repo/ui/components/Layout'
import { SubTitle } from '@/_components/SubTitle'
import { PlaceListItem } from '@/_components/PlaceListItem'
@@ -7,22 +13,39 @@ import { PlaceListItem } from '@/_components/PlaceListItem'
type Props = {
title: string
icon: IconType
- places: BasePlace[]
+ rankingPlaceSort: RankingPlaceSort
}
-export const RankingPlaceList = ({ title, icon, places }: Props) => {
+export const RankingPlaceList = ({ title, icon, rankingPlaceSort }: Props) => {
return (
-
- {places.map((place, index) => (
-
- ))}
-
+ }>
+
+
)
}
+
+const PlaceList = ({
+ rankingPlaceSort,
+}: {
+ rankingPlaceSort: RankingPlaceSort
+}) => {
+ const { campus } = useCampusStore()
+ const { data: places } = useSuspenseQuery(
+ usePlaceQueries.byRanking(rankingPlaceSort, campus),
+ )
+
+ return (
+
+ {places.map((place, index) => (
+
+ ))}
+
+ )
+}
diff --git a/apps/web/app/_components/RankingPlaceList/index.tsx b/apps/web/app/_components/RankingPlaceList/index.tsx
index fa5f639..065d851 100644
--- a/apps/web/app/_components/RankingPlaceList/index.tsx
+++ b/apps/web/app/_components/RankingPlaceList/index.tsx
@@ -1,3 +1 @@
export { RankingPlaceList } from './RankingPlaceList'
-export { MostViewsPlaces } from './MostViewsPlaces'
-export { MostLikesPlaces } from './MostLikesPlaces'
diff --git a/apps/web/app/categories/[id]/CategoryDetailPage.tsx b/apps/web/app/categories/[id]/CategoryDetailPage.tsx
index 39015f3..38bd4a9 100644
--- a/apps/web/app/categories/[id]/CategoryDetailPage.tsx
+++ b/apps/web/app/categories/[id]/CategoryDetailPage.tsx
@@ -1,28 +1,25 @@
'use client'
-
-import { usePathname } from 'next/navigation'
+import { Suspense, useEffect } from 'react'
import { useSuspenseQuery } from '@tanstack/react-query'
import { useCategoryQueries } from '@/_apis/queries/category'
+import { useCategoryIdFromUrl } from './_hooks/useCategoryIdFromUrl'
+
import { Icon } from '@repo/ui/components/Icon'
import { Text } from '@repo/ui/components/Text'
import { Header } from '@repo/ui/components/Header'
import { Flex } from '@repo/ui/components/Layout'
import { HeaderBackButton } from '@/_components/HeaderBackButton'
+import { PlaceListItem } from '@/_components/PlaceListItem'
import { RowCategories, Places } from './_components'
-import { Suspense, useEffect } from 'react'
-import { Spinner } from '@heroui/react'
+import { SwipeableArea } from './_components/SwipeableArea'
export const CategoryDetailPage = () => {
const { data: categories } = useSuspenseQuery(useCategoryQueries.list())
- const activeCategoryId = usePathname().split('/')[2] || '0'
+ const [categoryId, setCategoryId] = useCategoryIdFromUrl()
const activeCategory = categories.find(
- (category) => category.id === activeCategoryId,
+ (category) => category.id === categoryId,
)
- const setIdFunc = (id: string) => {
- window.history.replaceState(null, '', `/categories/${id}`)
- }
-
useEffect(() => {
document.title = `공주대 맛집 | ${activeCategory?.name}`
}, [activeCategory])
@@ -42,14 +39,15 @@ export const CategoryDetailPage = () => {
className={'border-b-1 border-gray-50'}
/>
- {/*Todo: 맛집 리스트 스켈레톤으로 변경하기*/}
- }>
-
-
+
+ }>
+
+
+
>
)
}
diff --git a/apps/web/app/categories/[id]/_components/Places/Places.tsx b/apps/web/app/categories/[id]/_components/Places/Places.tsx
index 3932cca..12fac79 100644
--- a/apps/web/app/categories/[id]/_components/Places/Places.tsx
+++ b/apps/web/app/categories/[id]/_components/Places/Places.tsx
@@ -1,5 +1,4 @@
import { useSuspenseQuery } from '@tanstack/react-query'
-import { motion, PanInfo } from 'motion/react'
import { useCampusStore } from '@/_store/campus'
import { usePlaceQueries } from '@/_apis/queries/place'
import { PlaceListItem } from '@/_components/PlaceListItem'
@@ -7,68 +6,31 @@ import { VerticalScrollArea } from '@repo/ui/components/Layout'
import { EmptyPlaces } from './EmptyPlaces'
type Props = {
- id: string
- setIdFunc: (id: string) => void
+ categoryId: string
}
-// 스와이프 감도
-const SWIPE_CONFIDENCE_THRESHOLD = 20
-
-export const Places = ({ id, setIdFunc }: Props) => {
+export const Places = ({ categoryId }: Props) => {
const { campus } = useCampusStore()
const { data: places } = useSuspenseQuery(
- usePlaceQueries.byCategory(id, campus),
+ usePlaceQueries.byCategory(categoryId, campus),
)
- const currentCategoryId = Number(id)
- const onDragEnd = (
- _e: MouseEvent | TouchEvent | PointerEvent,
- { offset, velocity }: PanInfo,
- ) => {
- const swipePower = Math.abs(offset.x) * velocity.x
-
- if (swipePower < -SWIPE_CONFIDENCE_THRESHOLD) {
- if (currentCategoryId < 15) {
- setIdFunc(String(currentCategoryId + 1))
- }
- } else if (swipePower > SWIPE_CONFIDENCE_THRESHOLD) {
- if (currentCategoryId > 1) {
- setIdFunc(String(currentCategoryId - 1))
- }
- }
- }
-
- const content =
- places.length === 0 ? (
-
- ) : (
-
- {places.map((place, index) => (
-
- ))}
-
- )
-
return (
-
- = 15 ? 0 : undefined,
- }}
- dragElastic={0.2}
- onDragEnd={onDragEnd}
- className='relative h-full w-full bg-white'
- >
- {content}
-
-
+ <>
+ {places.length === 0 ? (
+
+ ) : (
+
+ {places.map((place, index) => (
+
+ ))}
+
+ )}
+ >
)
}
diff --git a/apps/web/app/categories/[id]/_components/RowCategories/RowCategories.tsx b/apps/web/app/categories/[id]/_components/RowCategories/RowCategories.tsx
index b189b50..a0b320b 100644
--- a/apps/web/app/categories/[id]/_components/RowCategories/RowCategories.tsx
+++ b/apps/web/app/categories/[id]/_components/RowCategories/RowCategories.tsx
@@ -5,11 +5,15 @@ import { cn } from '@repo/ui/utils/cn'
type Props = {
categories: Category[]
- id: string
- setIdFunc: (id: string) => void
+ categoryId: string
+ setCategoryId: (id: string) => void
}
-export const RowCategories = ({ id, categories, setIdFunc }: Props) => {
+export const RowCategories = ({
+ categoryId,
+ categories,
+ setCategoryId,
+}: Props) => {
return (
@@ -17,9 +21,9 @@ export const RowCategories = ({ id, categories, setIdFunc }: Props) => {
{
- setIdFunc(category.id)
+ setCategoryId(category.id)
}}
/>
))}
diff --git a/apps/web/app/categories/[id]/_components/SwipeableArea/SwipeableArea.tsx b/apps/web/app/categories/[id]/_components/SwipeableArea/SwipeableArea.tsx
new file mode 100644
index 0000000..72432b5
--- /dev/null
+++ b/apps/web/app/categories/[id]/_components/SwipeableArea/SwipeableArea.tsx
@@ -0,0 +1,52 @@
+import { motion, PanInfo } from 'motion/react'
+
+type Props = {
+ categoryId: string
+ setCategoryId: (id: string) => void
+ children: React.ReactNode
+}
+
+const SWIPE_CONFIDENCE_THRESHOLD = 20
+
+export const SwipeableArea = ({
+ categoryId,
+ setCategoryId,
+ children,
+}: Props) => {
+ const NumberToCategoryId = Number(categoryId)
+
+ const onDragEnd = (
+ _e: MouseEvent | TouchEvent | PointerEvent,
+ { offset, velocity }: PanInfo,
+ ) => {
+ const swipePower = Math.abs(offset.x) * velocity.x
+
+ if (swipePower < -SWIPE_CONFIDENCE_THRESHOLD) {
+ if (NumberToCategoryId < 15) {
+ setCategoryId(String(NumberToCategoryId + 1))
+ }
+ } else if (swipePower > SWIPE_CONFIDENCE_THRESHOLD) {
+ if (NumberToCategoryId > 1) {
+ setCategoryId(String(NumberToCategoryId - 1))
+ }
+ }
+ }
+
+ return (
+
+ = 15 ? 0 : undefined,
+ }}
+ dragElastic={0.2}
+ onDragEnd={onDragEnd}
+ className='relative h-full w-full bg-white'
+ >
+ {children}
+
+
+ )
+}
diff --git a/apps/web/app/categories/[id]/_components/SwipeableArea/index.ts b/apps/web/app/categories/[id]/_components/SwipeableArea/index.ts
new file mode 100644
index 0000000..9e9a49d
--- /dev/null
+++ b/apps/web/app/categories/[id]/_components/SwipeableArea/index.ts
@@ -0,0 +1 @@
+export { SwipeableArea } from './SwipeableArea'
diff --git a/apps/web/app/categories/[id]/_hooks/useCategoryIdFromUrl.ts b/apps/web/app/categories/[id]/_hooks/useCategoryIdFromUrl.ts
new file mode 100644
index 0000000..2efec16
--- /dev/null
+++ b/apps/web/app/categories/[id]/_hooks/useCategoryIdFromUrl.ts
@@ -0,0 +1,11 @@
+import { usePathname } from 'next/navigation'
+import { CLIENT_PATH } from '@/_constants/path'
+
+export const useCategoryIdFromUrl = () => {
+ const categoryId = usePathname().split('/')[2] || '0'
+ const setCategoryId = (id: string) => {
+ window.history.replaceState(null, '', CLIENT_PATH.CATEGORY_DETAIL(id))
+ }
+
+ return [categoryId, setCategoryId] as const
+}
diff --git a/apps/web/app/page.tsx b/apps/web/app/page.tsx
index 61aeadf..3ba3273 100644
--- a/apps/web/app/page.tsx
+++ b/apps/web/app/page.tsx
@@ -6,10 +6,7 @@ import { Flex, VerticalScrollArea } from '@repo/ui/components/Layout'
import { Icon } from '@repo/ui/components/Icon'
import { Text } from '@repo/ui/components/Text'
import { Divider } from '@repo/ui/components/Divider'
-import {
- MostLikesPlaces,
- MostViewsPlaces,
-} from '@/_components/RankingPlaceList'
+import { RankingPlaceList } from '@/_components/RankingPlaceList'
import { HydrationBoundaryPage } from '@/HydrationBoundaryPage'
import { Banner } from '@repo/ui/components/Banner'
import { Categories } from '@/_components/Categories'
@@ -24,11 +21,7 @@ export const dynamic = 'force-dynamic'
export default function Page() {
return (
- {
- await queryClient.prefetchQuery(useCategoryQueries.list())
- }}
- >
+ <>
@@ -42,18 +35,32 @@ export default function Page() {
/>
-
+ {
+ await queryClient.prefetchQuery(useCategoryQueries.list())
+ }}
+ >
+
+
,
,
]}
/>
-
+
-
+
-
+ >
)
}