From 6226276ba6f715e6dac864cb46b233273b50a302 Mon Sep 17 00:00:00 2001 From: leeleeleeleejun Date: Mon, 1 Dec 2025 16:16:37 +0900 Subject: [PATCH 1/6] =?UTF-8?q?refactor:=20setIdFunc=20=EC=97=90=EC=84=9C?= =?UTF-8?q?=20setId=20=EC=9C=BC=EB=A1=9C=20=EC=9D=B4=EB=A6=84=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD=20-=20=EC=A1=B0=EA=B8=88=20=EB=8D=94=20=EC=9D=BC?= =?UTF-8?q?=EB=B0=98=EC=A0=81=EC=9D=B8=20=EC=9D=B4=EB=A6=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/web/app/categories/[id]/CategoryDetailPage.tsx | 6 +++--- .../web/app/categories/[id]/_components/Places/Places.tsx | 8 ++++---- .../[id]/_components/RowCategories/RowCategories.tsx | 6 +++--- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/apps/web/app/categories/[id]/CategoryDetailPage.tsx b/apps/web/app/categories/[id]/CategoryDetailPage.tsx index 39015f3..be062a7 100644 --- a/apps/web/app/categories/[id]/CategoryDetailPage.tsx +++ b/apps/web/app/categories/[id]/CategoryDetailPage.tsx @@ -19,7 +19,7 @@ export const CategoryDetailPage = () => { (category) => category.id === activeCategoryId, ) - const setIdFunc = (id: string) => { + const setId = (id: string) => { window.history.replaceState(null, '', `/categories/${id}`) } @@ -44,11 +44,11 @@ export const CategoryDetailPage = () => { {/*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..849c1bc 100644 --- a/apps/web/app/categories/[id]/_components/Places/Places.tsx +++ b/apps/web/app/categories/[id]/_components/Places/Places.tsx @@ -8,13 +8,13 @@ import { EmptyPlaces } from './EmptyPlaces' type Props = { id: string - setIdFunc: (id: string) => void + setId: (id: string) => void } // 스와이프 감도 const SWIPE_CONFIDENCE_THRESHOLD = 20 -export const Places = ({ id, setIdFunc }: Props) => { +export const Places = ({ id, setId }: Props) => { const { campus } = useCampusStore() const { data: places } = useSuspenseQuery( usePlaceQueries.byCategory(id, campus), @@ -29,11 +29,11 @@ export const Places = ({ id, setIdFunc }: Props) => { if (swipePower < -SWIPE_CONFIDENCE_THRESHOLD) { if (currentCategoryId < 15) { - setIdFunc(String(currentCategoryId + 1)) + setId(String(currentCategoryId + 1)) } } else if (swipePower > SWIPE_CONFIDENCE_THRESHOLD) { if (currentCategoryId > 1) { - setIdFunc(String(currentCategoryId - 1)) + setId(String(currentCategoryId - 1)) } } } diff --git a/apps/web/app/categories/[id]/_components/RowCategories/RowCategories.tsx b/apps/web/app/categories/[id]/_components/RowCategories/RowCategories.tsx index b189b50..8c8e654 100644 --- a/apps/web/app/categories/[id]/_components/RowCategories/RowCategories.tsx +++ b/apps/web/app/categories/[id]/_components/RowCategories/RowCategories.tsx @@ -6,10 +6,10 @@ import { cn } from '@repo/ui/utils/cn' type Props = { categories: Category[] id: string - setIdFunc: (id: string) => void + setId: (id: string) => void } -export const RowCategories = ({ id, categories, setIdFunc }: Props) => { +export const RowCategories = ({ id, categories, setId }: Props) => { return (
@@ -19,7 +19,7 @@ export const RowCategories = ({ id, categories, setIdFunc }: Props) => { category={category} isActive={id === category.id} onClick={() => { - setIdFunc(category.id) + setId(category.id) }} /> ))} From bf13677e40080bbe4bdb828fb88edb5993f7b54a Mon Sep 17 00:00:00 2001 From: leeleeleeleejun Date: Mon, 1 Dec 2025 16:16:49 +0900 Subject: [PATCH 2/6] =?UTF-8?q?feat:=20PlaceListItem=EC=97=90=20=EC=8A=A4?= =?UTF-8?q?=EC=BC=88=EB=A0=88=ED=86=A4=20=EB=A0=8C=EB=8D=94=EB=A7=81=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80=20-=20=EC=8A=A4?= =?UTF-8?q?=EC=BC=88=EB=A0=88=ED=86=A4=20UI=20=EC=BB=B4=ED=8F=AC=EB=84=8C?= =?UTF-8?q?=ED=8A=B8=20=EA=B5=AC=ED=98=84=20-=20PlaceListItem.Skeleton=20?= =?UTF-8?q?=ED=98=95=ED=83=9C=EB=A1=9C=20=EC=84=9C=EB=B8=8C=20=EC=BB=B4?= =?UTF-8?q?=ED=8F=AC=EB=84=8C=ED=8A=B8=20=ED=8C=A8=ED=84=B4=20=EC=A0=81?= =?UTF-8?q?=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../PlaceListItem/PlaceListItem.tsx | 3 ++ .../PlaceListItem/PlaceListItemSkeleton.tsx | 29 +++++++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 apps/web/app/_components/PlaceListItem/PlaceListItemSkeleton.tsx 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..00bd77a --- /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) => ( + + + + + + + + + ))} +
+ ) +} From d5908da9d50a81547cf6e1268bf823ffc01d1786 Mon Sep 17 00:00:00 2001 From: leeleeleeleejun Date: Mon, 1 Dec 2025 16:22:08 +0900 Subject: [PATCH 3/6] =?UTF-8?q?refactor:=20=EB=9E=AD=ED=82=B9=20=EB=A6=AC?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8=20?= =?UTF-8?q?=ED=86=B5=ED=95=A9=20=EB=B0=8F=20=EC=B6=94=EC=83=81=ED=99=94=20?= =?UTF-8?q?(RankingPlaceList)=20-=20=EA=B0=9C=EB=B3=84=20=EC=BB=B4?= =?UTF-8?q?=ED=8F=AC=EB=84=8C=ED=8A=B8(MostLikes,=20MostViews)=EB=A5=BC=20?= =?UTF-8?q?=EC=A0=9C=EA=B1=B0=ED=95=98=EA=B3=A0=20RankingPlaceList?= =?UTF-8?q?=EB=A1=9C=20=ED=86=B5=ED=95=A9=20-=20=EC=A0=95=EB=A0=AC=20?= =?UTF-8?q?=EA=B8=B0=EC=A4=80(SortType)=EC=9D=84=20Prop=EC=9C=BC=EB=A1=9C?= =?UTF-8?q?=20=EC=A3=BC=EC=9E=85=EB=B0=9B=EB=8F=84=EB=A1=9D=20=EA=B5=AC?= =?UTF-8?q?=EC=A1=B0=20=EA=B0=9C=EC=84=A0=ED=95=98=EC=97=AC=20=EC=9E=AC?= =?UTF-8?q?=EC=82=AC=EC=9A=A9=EC=84=B1=20=EC=A6=9D=EB=8C=80=20-=20UI=20?= =?UTF-8?q?=EB=A0=88=EC=9D=B4=EC=95=84=EC=9B=83=EA=B3=BC=20=EB=8D=B0?= =?UTF-8?q?=EC=9D=B4=ED=84=B0=20=ED=8E=98=EC=B9=AD=20=EB=A1=9C=EC=A7=81?= =?UTF-8?q?=EC=9D=98=20=EA=B4=80=EC=8B=AC=EC=82=AC=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../MostLikesPlaces/MostLikesPlaces.tsx | 15 ------ .../MostLikesPlaces/index.tsx | 1 - .../MostViewsPlaces/MostViewsPlaces.tsx | 13 ----- .../MostViewsPlaces/index.tsx | 1 - .../RankingPlaceList/RankingPlaceList.tsx | 47 ++++++++++++++----- .../_components/RankingPlaceList/index.tsx | 2 - apps/web/app/page.tsx | 33 ++++++++----- 7 files changed, 55 insertions(+), 57 deletions(-) delete mode 100644 apps/web/app/_components/RankingPlaceList/MostLikesPlaces/MostLikesPlaces.tsx delete mode 100644 apps/web/app/_components/RankingPlaceList/MostLikesPlaces/index.tsx delete mode 100644 apps/web/app/_components/RankingPlaceList/MostViewsPlaces/MostViewsPlaces.tsx delete mode 100644 apps/web/app/_components/RankingPlaceList/MostViewsPlaces/index.tsx 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/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()) + }} + > + + , , ]} /> - + - + - + ) } From 70e4b5fbd4ed65a32021042a57cfbcf0b542ae22 Mon Sep 17 00:00:00 2001 From: leeleeleeleejun Date: Mon, 1 Dec 2025 17:50:27 +0900 Subject: [PATCH 4/6] =?UTF-8?q?feat:=20=EC=B9=B4=ED=85=8C=EA=B3=A0?= =?UTF-8?q?=EB=A6=AC=20URL=20=EC=83=81=ED=83=9C=EB=A5=BC=20useCategoryIdFr?= =?UTF-8?q?omUrl=20=ED=9B=85=EC=9C=BC=EB=A1=9C=20=EC=B6=94=EC=83=81?= =?UTF-8?q?=ED=99=94=20-=20URL=EC=97=90=EC=84=9C=20=EC=B9=B4=ED=85=8C?= =?UTF-8?q?=EA=B3=A0=EB=A6=AC=20ID=EB=A5=BC=20=EC=9D=BD=EA=B3=A0=20?= =?UTF-8?q?=EC=97=85=EB=8D=B0=EC=9D=B4=ED=8A=B8=ED=95=98=EB=8A=94=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=EC=9D=84=20useCategoryIdFromUrl=20=ED=9B=85?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20=EB=B6=84=EB=A6=AC=20-=20CategoryDetailPag?= =?UTF-8?q?e=EC=9D=98=20=EB=9D=BC=EC=9A=B0=ED=8A=B8=20=EC=97=85=EB=8D=B0?= =?UTF-8?q?=EC=9D=B4=ED=8A=B8=20=EB=B0=8F=20=EC=83=81=ED=83=9C=20=EA=B4=80?= =?UTF-8?q?=EB=A6=AC=20=EB=A1=9C=EC=A7=81=20=EA=B0=84=EC=86=8C=ED=99=94=20?= =?UTF-8?q?-=20=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8=20=EC=B1=85=EC=9E=84?= =?UTF-8?q?=20=EB=B6=84=EB=A6=AC=20=EB=B0=8F=20=EC=9E=AC=EC=82=AC=EC=9A=A9?= =?UTF-8?q?=EC=84=B1=20=ED=96=A5=EC=83=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../categories/[id]/_hooks/useCategoryIdFromUrl.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 apps/web/app/categories/[id]/_hooks/useCategoryIdFromUrl.ts 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 +} From 924b77f0a2e0d921a97691cbbc959307cf520422 Mon Sep 17 00:00:00 2001 From: leeleeleeleejun Date: Mon, 1 Dec 2025 17:52:37 +0900 Subject: [PATCH 5/6] =?UTF-8?q?feat:=20=EC=B9=B4=ED=85=8C=EA=B3=A0?= =?UTF-8?q?=EB=A6=AC=20=EA=B0=84=20=EC=A2=8C=EC=9A=B0=20=EC=8A=A4=EC=99=80?= =?UTF-8?q?=EC=9D=B4=ED=94=84=20=EC=9D=B4=EB=8F=99=EC=9D=84=20=EC=9C=84?= =?UTF-8?q?=ED=95=9C=20SwipeableArea=20=EC=BB=B4=ED=8F=AC=EB=84=8C?= =?UTF-8?q?=ED=8A=B8=20=EC=B6=94=EA=B0=80=20-=20=EC=B9=B4=ED=85=8C?= =?UTF-8?q?=EA=B3=A0=EB=A6=AC=20=EC=83=81=EC=84=B8=20=ED=8E=98=EC=9D=B4?= =?UTF-8?q?=EC=A7=80=EC=97=90=EC=84=9C=20=EC=A2=8C=EC=9A=B0=20=EB=93=9C?= =?UTF-8?q?=EB=9E=98=EA=B7=B8=20=EC=A0=9C=EC=8A=A4=EC=B2=98=EB=A1=9C=20?= =?UTF-8?q?=EC=9D=B4=EC=A0=84/=EB=8B=A4=EC=9D=8C=20=EC=B9=B4=ED=85=8C?= =?UTF-8?q?=EA=B3=A0=EB=A6=AC=20=EC=9D=B4=EB=8F=99=20=EA=B0=80=EB=8A=A5?= =?UTF-8?q?=ED=95=98=EB=8F=84=EB=A1=9D=20=EA=B5=AC=ED=98=84=20-=20swipe=20?= =?UTF-8?q?=EB=B0=A9=ED=96=A5=20=EB=B0=8F=20=EA=B0=95=EB=8F=84=20=EA=B3=84?= =?UTF-8?q?=EC=82=B0=20=EB=A1=9C=EC=A7=81=EC=9D=84=20=EB=B3=84=EB=8F=84=20?= =?UTF-8?q?=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8(SwipeableArea)=EB=A1=9C=20?= =?UTF-8?q?=EC=B6=94=EC=83=81=ED=99=94=20-=20=EC=83=81=ED=83=9C=20?= =?UTF-8?q?=EA=B4=80=EB=A6=AC(setActiveCategoryId)=EC=99=80=20UI=20?= =?UTF-8?q?=EC=98=81=EC=97=AD(children)=20=EB=B6=84=EB=A6=AC=EB=A1=9C=20?= =?UTF-8?q?=EA=B5=AC=EC=A1=B0=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../categories/[id]/CategoryDetailPage.tsx | 30 ++++---- .../[id]/_components/Places/Places.tsx | 76 +++++-------------- .../RowCategories/RowCategories.tsx | 14 ++-- .../SwipeableArea/SwipeableArea.tsx | 52 +++++++++++++ .../[id]/_components/SwipeableArea/index.ts | 1 + 5 files changed, 95 insertions(+), 78 deletions(-) create mode 100644 apps/web/app/categories/[id]/_components/SwipeableArea/SwipeableArea.tsx create mode 100644 apps/web/app/categories/[id]/_components/SwipeableArea/index.ts diff --git a/apps/web/app/categories/[id]/CategoryDetailPage.tsx b/apps/web/app/categories/[id]/CategoryDetailPage.tsx index be062a7..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 setId = (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 849c1bc..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 - setId: (id: string) => void + categoryId: string } -// 스와이프 감도 -const SWIPE_CONFIDENCE_THRESHOLD = 20 - -export const Places = ({ id, setId }: 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) { - setId(String(currentCategoryId + 1)) - } - } else if (swipePower > SWIPE_CONFIDENCE_THRESHOLD) { - if (currentCategoryId > 1) { - setId(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 8c8e654..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 - setId: (id: string) => void + categoryId: string + setCategoryId: (id: string) => void } -export const RowCategories = ({ id, categories, setId }: Props) => { +export const RowCategories = ({ + categoryId, + categories, + setCategoryId, +}: Props) => { return (
@@ -17,9 +21,9 @@ export const RowCategories = ({ id, categories, setId }: Props) => { { - setId(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' From f28aa78ea793e9449661346e9d7289263bebb89a Mon Sep 17 00:00:00 2001 From: leeleeleeleejun Date: Tue, 2 Dec 2025 02:06:34 +0900 Subject: [PATCH 6/6] =?UTF-8?q?refactor:=20PlaceListItemSkeleton=20?= =?UTF-8?q?=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8=EC=9D=98=20=EC=8A=A4?= =?UTF-8?q?=EC=BC=88=EB=A0=88=ED=86=A4=20=EC=8A=A4=ED=83=80=EC=9D=BC=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../_components/PlaceListItem/PlaceListItemSkeleton.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/web/app/_components/PlaceListItem/PlaceListItemSkeleton.tsx b/apps/web/app/_components/PlaceListItem/PlaceListItemSkeleton.tsx index 00bd77a..3eec057 100644 --- a/apps/web/app/_components/PlaceListItem/PlaceListItemSkeleton.tsx +++ b/apps/web/app/_components/PlaceListItem/PlaceListItemSkeleton.tsx @@ -16,11 +16,11 @@ export const PlaceListItemSkeleton = ({ count = 3 }: Props) => { key={index} className='border-b-1 w-full gap-3 border-gray-50 pb-4 pt-2.5' > - - + + - - + + ))}