From e4224aa116b1f26365cf83f3f31107cff9f8fc13 Mon Sep 17 00:00:00 2001 From: Sejin Cha <62418379+chasj0326@users.noreply.github.com> Date: Sun, 19 Nov 2023 01:49:01 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20=EC=A0=84=EC=B2=B4=20=EB=B0=A9=20?= =?UTF-8?q?=EC=A1=B0=ED=9A=8C=20API=20=EC=97=B0=EA=B2=B0=20=EB=B0=8F=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84=20(#164)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: 전체 방 조회 msw API 및 쿼리 작성 * feat: 방 전체 조회 API 연결 * feat: 옵저버 제외한 무한 fetching 기능 추가 * feat: 로딩 fallback 추가 * feat: 무한스크롤 쿼리 로직 분리 * feat: 무한스크롤 커스텀 훅 구현 및 기능 연결 * feat: 옵저버 훅 및 UI 수정 * feat: 코드 리뷰 반영 --- src/RoomSearch/components/ResultList.tsx | 50 +- .../components/ResultListFallback.tsx | 20 + .../hooks/useIntersectionObserver.ts | 41 + src/core/api/functions/couponAPI.ts | 2 +- src/core/api/functions/roomAPI.ts | 6 + src/core/api/options/coupon.ts | 2 +- src/core/api/options/room.ts | 7 + src/core/api/queries/index.ts | 1 + src/core/api/queries/useInfiniteSearch.ts | 27 + src/core/mocks/datas/totalRooms.ts | 766 ++++++++++++++++++ src/core/mocks/handlers/rooms.ts | 31 + src/core/types/TotalRooms.ts | 28 + src/core/types/index.ts | 6 + src/pages/SearchPage.tsx | 24 +- 14 files changed, 993 insertions(+), 18 deletions(-) create mode 100644 src/RoomSearch/components/ResultListFallback.tsx create mode 100644 src/RoomSearch/hooks/useIntersectionObserver.ts create mode 100644 src/core/api/queries/index.ts create mode 100644 src/core/api/queries/useInfiniteSearch.ts create mode 100644 src/core/mocks/datas/totalRooms.ts create mode 100644 src/core/types/TotalRooms.ts diff --git a/src/RoomSearch/components/ResultList.tsx b/src/RoomSearch/components/ResultList.tsx index 523f4b0a..2c84af10 100644 --- a/src/RoomSearch/components/ResultList.tsx +++ b/src/RoomSearch/components/ResultList.tsx @@ -1,19 +1,51 @@ -import { Room } from '@/RoomList/mocks/types/rooms'; +import { RoomSelectType } from '@/core/types'; +import { useInfiniteSearch } from '@/core/api/queries'; +import useIntersectionObserver from '../hooks/useIntersectionObserver'; +import ResultListFallback from './ResultListFallback'; import { RoomAccordion } from '@/RoomList'; +import { Deffered } from '@/shared/Deffered'; interface ResultListProps { - rooms: Room[]; + type: RoomSelectType; + size: number; } -const ResultList = ({ rooms }: ResultListProps) => { +const ResultList = ({ type, size }: ResultListProps) => { + const { fetchNextPage, data, isFetchingNextPage, hasNextPage } = + useInfiniteSearch({ + type, + size + }); + const intersectionRef = useIntersectionObserver({ + threshold: 0.5, + onObserve: fetchNextPage + }); + return (
- {rooms.map((room) => ( - - ))} + {data.map((rooms) => + rooms.map((room) => ( + + )) + )} + {isFetchingNextPage && ( + + + + )} + {hasNextPage ? ( +
+ ) : ( +
+ 모든 방을 다 불러왔어요. +
+ )}
); }; diff --git a/src/RoomSearch/components/ResultListFallback.tsx b/src/RoomSearch/components/ResultListFallback.tsx new file mode 100644 index 00000000..154c1c29 --- /dev/null +++ b/src/RoomSearch/components/ResultListFallback.tsx @@ -0,0 +1,20 @@ +import React from 'react'; + +interface ResultListFallbackProps { + size?: number; +} + +const ResultListFallback = ({ size = 10 }: ResultListFallbackProps) => { + return ( +
+ {Array.from({ length: size }, (_, index) => ( +
+ ))} +
+ ); +}; + +export default ResultListFallback; diff --git a/src/RoomSearch/hooks/useIntersectionObserver.ts b/src/RoomSearch/hooks/useIntersectionObserver.ts new file mode 100644 index 00000000..eab79d71 --- /dev/null +++ b/src/RoomSearch/hooks/useIntersectionObserver.ts @@ -0,0 +1,41 @@ +import { useCallback, useEffect, useRef } from 'react'; + +interface ObserverOptions { + root?: Element | null; + rootMargin?: string; + threshold?: number; + onObserve: VoidFunction; +} + +const useIntersectionObserver = ({ + onObserve, + ...options +}: ObserverOptions) => { + const intersectionRef = useRef(null); + + const handleIntersect: IntersectionObserverCallback = useCallback( + (entries) => { + entries.forEach((entry) => { + if (entry.isIntersecting) { + onObserve(); + } + }); + }, + [onObserve] + ); + + useEffect(() => { + const observer = new IntersectionObserver(handleIntersect, options); + const intersectionElement = intersectionRef.current; + + intersectionElement && observer.observe(intersectionElement); + + return () => { + intersectionElement && observer.unobserve(intersectionElement); + }; + }, [handleIntersect, options]); + + return intersectionRef; +}; + +export default useIntersectionObserver; diff --git a/src/core/api/functions/couponAPI.ts b/src/core/api/functions/couponAPI.ts index 63d72401..07f6fc1a 100644 --- a/src/core/api/functions/couponAPI.ts +++ b/src/core/api/functions/couponAPI.ts @@ -3,7 +3,7 @@ import { CouponStatus } from '@/core/types'; import { baseInstance } from '../instance'; const couponAPI = { - postAllCoupons: async (body: CouponStatus) => { + postCouponsByStatus: async (body: CouponStatus) => { return await baseInstance.post('/coupons/search', body); } }; diff --git a/src/core/api/functions/roomAPI.ts b/src/core/api/functions/roomAPI.ts index c2fe0eaf..f2f01025 100644 --- a/src/core/api/functions/roomAPI.ts +++ b/src/core/api/functions/roomAPI.ts @@ -1,3 +1,4 @@ +import { RoomsRequestParams, TotalRooms } from '@/core/types'; import { baseInstance } from '../instance'; import { MyJoinRoom } from '@/core/types/MyJoinRoom'; import { RoomInfo } from '@/core/types/Room'; @@ -49,6 +50,11 @@ const roomAPI = { return await baseInstance.put( `/rooms/${roomId}/members/${memberId}/delegation` ); + }, + + getRoomsAll: async (params?: RoomsRequestParams) => { + const response: TotalRooms = await baseInstance.get('/rooms', { params }); + return response.rooms; } }; diff --git a/src/core/api/options/coupon.ts b/src/core/api/options/coupon.ts index 09d2a63f..cbbc8262 100644 --- a/src/core/api/options/coupon.ts +++ b/src/core/api/options/coupon.ts @@ -6,7 +6,7 @@ const couponOptions = { all: (body: CouponStatus) => queryOptions({ queryKey: ['coupons', body] as const, - queryFn: () => couponAPI.postAllCoupons(body) + queryFn: () => couponAPI.postCouponsByStatus(body) }) }; diff --git a/src/core/api/options/room.ts b/src/core/api/options/room.ts index aad2445a..bb5cb74d 100644 --- a/src/core/api/options/room.ts +++ b/src/core/api/options/room.ts @@ -1,4 +1,5 @@ import { queryOptions } from '@tanstack/react-query'; +import { RoomsRequestParams } from '@/core/types'; import roomAPI from '../functions/roomAPI'; const roomOptions = { @@ -12,6 +13,12 @@ const roomOptions = { queryOptions({ queryKey: ['rooms', 'myJoin'] as const, queryFn: () => roomAPI.getMyJoinRoom() + }), + + all: (params?: RoomsRequestParams) => + queryOptions({ + queryKey: ['rooms', params?.type || 'all'] as const, + queryFn: () => roomAPI.getRoomsAll(params) }) }; diff --git a/src/core/api/queries/index.ts b/src/core/api/queries/index.ts new file mode 100644 index 00000000..f22f6544 --- /dev/null +++ b/src/core/api/queries/index.ts @@ -0,0 +1 @@ +export { default as useInfiniteSearch } from './useInfiniteSearch'; diff --git a/src/core/api/queries/useInfiniteSearch.ts b/src/core/api/queries/useInfiniteSearch.ts new file mode 100644 index 00000000..840e9a5e --- /dev/null +++ b/src/core/api/queries/useInfiniteSearch.ts @@ -0,0 +1,27 @@ +import { useSuspenseInfiniteQuery } from '@tanstack/react-query'; +import { RoomSelectType } from '@/core/types'; +import roomAPI from '../functions/roomAPI'; + +const useInfiniteSearch = ({ + type, + size +}: { + type: RoomSelectType; + size: number; +}) => { + return useSuspenseInfiniteQuery({ + queryKey: ['rooms', type], + + queryFn: ({ pageParam }) => + roomAPI.getRoomsAll({ page: pageParam, type, size }), + + initialPageParam: 1, + + getNextPageParam: (lastPage, allPages, lastPageParam) => + lastPage.length < size ? null : lastPageParam + 1, + + select: ({ pages }) => pages + }); +}; + +export default useInfiniteSearch; diff --git a/src/core/mocks/datas/totalRooms.ts b/src/core/mocks/datas/totalRooms.ts new file mode 100644 index 00000000..ded9f50f --- /dev/null +++ b/src/core/mocks/datas/totalRooms.ts @@ -0,0 +1,766 @@ +import { TotalRooms } from '@/core/types'; + +export const TOTAL_ROOMS: TotalRooms = { + rooms: [ + { + id: 1, + title: '재윤이의 루틴방', + managerNickname: 'DevUNI', + level: 5, + roomType: 'MORNING', + certifyTime: 8, + currentUserCount: 5, + maxUserCount: 9, + routine: [ + { + routineId: 5, + content: '물 마시기' + }, + { + routineId: 9, + content: '아침 먹기' + } + ] + }, + { + id: 2, + title: '영명이의 루틴방', + managerNickname: 'ymkim', + level: 7, + roomType: 'NIGHT', + certifyTime: 21, + currentUserCount: 4, + maxUserCount: 10, + routine: [ + { + routineId: 5, + content: '물 마시기' + }, + { + routineId: 9, + content: '아침 먹기' + } + ] + }, + { + id: 3, + title: '홍박사의 루틴방', + managerNickname: 'HongJJANG', + level: 4, + roomType: 'NIGHT', + certifyTime: 1, + currentUserCount: 4, + maxUserCount: 7, + routine: [ + { + routineId: 5, + content: '물 마시기' + }, + { + routineId: 9, + content: '아침 먹기' + } + ] + }, + { + id: 4, + title: '재윤이의 루틴방', + managerNickname: 'DevUNI', + level: 5, + roomType: 'MORNING', + certifyTime: 8, + currentUserCount: 5, + maxUserCount: 9, + routine: [ + { + routineId: 5, + content: '물 마시기' + }, + { + routineId: 9, + content: '아침 먹기' + } + ] + }, + { + id: 5, + title: '프롱루틴방', + managerNickname: 'Frong', + level: 4, + roomType: 'MORNING', + certifyTime: 9, + currentUserCount: 4, + maxUserCount: 10, + routine: [ + { + routineId: 5, + content: 'PR 올리기' + }, + { + routineId: 9, + content: '코드 리뷰하기' + } + ] + }, + { + id: 6, + title: '방이름이엄청나게긴루틴방이랍니다하하하하', + managerNickname: 'long_Frong', + level: 5, + roomType: 'MORNING', + certifyTime: 9, + currentUserCount: 4, + maxUserCount: 10, + routine: [ + { + routineId: 5, + content: 'PR 올리기' + }, + { + routineId: 9, + content: '코드 리뷰하기' + } + ] + }, + { + id: 7, + title: '영명이의 루틴방', + managerNickname: 'ymkim', + level: 7, + roomType: 'NIGHT', + certifyTime: 21, + currentUserCount: 4, + maxUserCount: 10, + routine: [ + { + routineId: 5, + content: '물 마시기' + }, + { + routineId: 9, + content: '아침 먹기' + } + ] + }, + { + id: 8, + title: '홍박사의 루틴방', + managerNickname: 'HongJJANG', + level: 4, + roomType: 'NIGHT', + certifyTime: 1, + currentUserCount: 4, + maxUserCount: 7, + routine: [ + { + routineId: 5, + content: '물 마시기' + }, + { + routineId: 9, + content: '아침 먹기' + } + ] + }, + { + id: 9, + title: '프롱루틴방', + managerNickname: 'Frong', + level: 4, + roomType: 'MORNING', + certifyTime: 9, + currentUserCount: 4, + maxUserCount: 10, + routine: [ + { + routineId: 5, + content: 'PR 올리기' + }, + { + routineId: 9, + content: '코드 리뷰하기' + } + ] + }, + { + id: 10, + title: '재윤이의 루틴방', + managerNickname: 'DevUNI', + level: 5, + roomType: 'MORNING', + certifyTime: 8, + currentUserCount: 5, + maxUserCount: 9, + routine: [ + { + routineId: 5, + content: '물 마시기' + }, + { + routineId: 9, + content: '아침 먹기' + } + ] + }, + { + id: 11, + title: '영명이의 루틴방', + managerNickname: 'ymkim', + level: 7, + roomType: 'NIGHT', + certifyTime: 21, + currentUserCount: 4, + maxUserCount: 10, + routine: [ + { + routineId: 5, + content: '물 마시기' + }, + { + routineId: 9, + content: '아침 먹기' + } + ] + }, + { + id: 12, + title: '홍박사의 루틴방', + managerNickname: 'HongJJANG', + level: 4, + roomType: 'NIGHT', + certifyTime: 1, + currentUserCount: 4, + maxUserCount: 7, + routine: [ + { + routineId: 5, + content: '물 마시기' + }, + { + routineId: 9, + content: '아침 먹기' + } + ] + }, + { + id: 13, + title: '재윤이의 루틴방', + managerNickname: 'DevUNI', + level: 5, + roomType: 'MORNING', + certifyTime: 8, + currentUserCount: 5, + maxUserCount: 9, + routine: [ + { + routineId: 5, + content: '물 마시기' + }, + { + routineId: 9, + content: '아침 먹기' + } + ] + }, + { + id: 14, + title: '프롱루틴방', + managerNickname: 'Frong', + level: 4, + roomType: 'MORNING', + certifyTime: 9, + currentUserCount: 4, + maxUserCount: 10, + routine: [ + { + routineId: 5, + content: 'PR 올리기' + }, + { + routineId: 9, + content: '코드 리뷰하기' + } + ] + }, + { + id: 15, + title: '방이름이엄청나게긴루틴방이랍니다하하하하', + managerNickname: 'long_Frong', + level: 5, + roomType: 'MORNING', + certifyTime: 9, + currentUserCount: 4, + maxUserCount: 10, + routine: [ + { + routineId: 5, + content: 'PR 올리기' + }, + { + routineId: 9, + content: '코드 리뷰하기' + } + ] + }, + { + id: 16, + title: '영명이의 루틴방', + managerNickname: 'ymkim', + level: 7, + roomType: 'NIGHT', + certifyTime: 21, + currentUserCount: 4, + maxUserCount: 10, + routine: [ + { + routineId: 5, + content: '물 마시기' + }, + { + routineId: 9, + content: '아침 먹기' + } + ] + }, + { + id: 17, + title: '홍박사의 루틴방', + managerNickname: 'HongJJANG', + level: 4, + roomType: 'NIGHT', + certifyTime: 1, + currentUserCount: 4, + maxUserCount: 7, + routine: [ + { + routineId: 5, + content: '물 마시기' + }, + { + routineId: 9, + content: '아침 먹기' + } + ] + }, + { + id: 18, + title: '프롱루틴방', + managerNickname: 'Frong', + level: 4, + roomType: 'MORNING', + certifyTime: 9, + currentUserCount: 4, + maxUserCount: 10, + routine: [ + { + routineId: 5, + content: 'PR 올리기' + }, + { + routineId: 9, + content: '코드 리뷰하기' + } + ] + }, + { + id: 19, + title: '방이름이엄청나게긴루틴방이랍니다하하하하', + managerNickname: 'long_Frong', + level: 5, + roomType: 'NIGHT', + certifyTime: 9, + currentUserCount: 4, + maxUserCount: 10, + routine: [ + { + routineId: 5, + content: 'PR 올리기' + }, + { + routineId: 9, + content: '코드 리뷰하기' + } + ] + }, + { + id: 21, + title: '재윤이의 루틴방', + managerNickname: 'DevUNI', + level: 5, + roomType: 'MORNING', + certifyTime: 8, + currentUserCount: 5, + maxUserCount: 9, + routine: [ + { + routineId: 5, + content: '물 마시기' + }, + { + routineId: 9, + content: '아침 먹기' + } + ] + }, + { + id: 20, + title: '영명이의 루틴방', + managerNickname: 'ymkim', + level: 7, + roomType: 'NIGHT', + certifyTime: 21, + currentUserCount: 4, + maxUserCount: 10, + routine: [ + { + routineId: 5, + content: '물 마시기' + }, + { + routineId: 9, + content: '아침 먹기' + } + ] + }, + { + id: 21, + title: '홍박사의 루틴방', + managerNickname: 'HongJJANG', + level: 4, + roomType: 'NIGHT', + certifyTime: 1, + currentUserCount: 4, + maxUserCount: 7, + routine: [ + { + routineId: 5, + content: '물 마시기' + }, + { + routineId: 9, + content: '아침 먹기' + } + ] + }, + { + id: 22, + title: '재윤이의 루틴방', + managerNickname: 'DevUNI', + level: 5, + roomType: 'MORNING', + certifyTime: 8, + currentUserCount: 5, + maxUserCount: 9, + routine: [ + { + routineId: 5, + content: '물 마시기' + }, + { + routineId: 9, + content: '아침 먹기' + } + ] + }, + { + id: 23, + title: '프롱루틴방', + managerNickname: 'Frong', + level: 4, + roomType: 'MORNING', + certifyTime: 9, + currentUserCount: 4, + maxUserCount: 10, + routine: [ + { + routineId: 5, + content: 'PR 올리기' + }, + { + routineId: 9, + content: '코드 리뷰하기' + } + ] + }, + { + id: 24, + title: '방이름이엄청나게긴루틴방이랍니다하하하하', + managerNickname: 'long_Frong', + level: 5, + roomType: 'MORNING', + certifyTime: 9, + currentUserCount: 4, + maxUserCount: 10, + routine: [ + { + routineId: 5, + content: 'PR 올리기' + }, + { + routineId: 9, + content: '코드 리뷰하기' + } + ] + }, + { + id: 25, + title: '영명이의 루틴방', + managerNickname: 'ymkim', + level: 7, + roomType: 'NIGHT', + certifyTime: 21, + currentUserCount: 4, + maxUserCount: 10, + routine: [ + { + routineId: 5, + content: '물 마시기' + }, + { + routineId: 9, + content: '아침 먹기' + } + ] + }, + { + id: 26, + title: '홍박사의 루틴방', + managerNickname: 'HongJJANG', + level: 4, + roomType: 'NIGHT', + certifyTime: 1, + currentUserCount: 4, + maxUserCount: 7, + routine: [ + { + routineId: 5, + content: '물 마시기' + }, + { + routineId: 9, + content: '아침 먹기' + } + ] + }, + { + id: 27, + title: '프롱루틴방', + managerNickname: 'Frong', + level: 4, + roomType: 'MORNING', + certifyTime: 9, + currentUserCount: 4, + maxUserCount: 10, + routine: [ + { + routineId: 5, + content: 'PR 올리기' + }, + { + routineId: 9, + content: '코드 리뷰하기' + } + ] + }, + { + id: 28, + title: '재윤이의 루틴방', + managerNickname: 'DevUNI', + level: 5, + roomType: 'MORNING', + certifyTime: 8, + currentUserCount: 5, + maxUserCount: 9, + routine: [ + { + routineId: 5, + content: '물 마시기' + }, + { + routineId: 9, + content: '아침 먹기' + } + ] + }, + { + id: 29, + title: '영명이의 루틴방', + managerNickname: 'ymkim', + level: 7, + roomType: 'NIGHT', + certifyTime: 21, + currentUserCount: 4, + maxUserCount: 10, + routine: [ + { + routineId: 5, + content: '물 마시기' + }, + { + routineId: 9, + content: '아침 먹기' + } + ] + }, + { + id: 30, + title: '홍박사의 루틴방', + managerNickname: 'HongJJANG', + level: 4, + roomType: 'NIGHT', + certifyTime: 1, + currentUserCount: 4, + maxUserCount: 7, + routine: [ + { + routineId: 5, + content: '물 마시기' + }, + { + routineId: 9, + content: '아침 먹기' + } + ] + }, + { + id: 31, + title: '재윤이의 루틴방', + managerNickname: 'DevUNI', + level: 5, + roomType: 'MORNING', + certifyTime: 8, + currentUserCount: 5, + maxUserCount: 9, + routine: [ + { + routineId: 5, + content: '물 마시기' + }, + { + routineId: 9, + content: '아침 먹기' + } + ] + }, + { + id: 32, + title: '프롱루틴방', + managerNickname: 'Frong', + level: 4, + roomType: 'MORNING', + certifyTime: 9, + currentUserCount: 4, + maxUserCount: 10, + routine: [ + { + routineId: 5, + content: 'PR 올리기' + }, + { + routineId: 9, + content: '코드 리뷰하기' + } + ] + }, + { + id: 33, + title: '방이름이엄청나게긴루틴방이랍니다하하하하', + managerNickname: 'long_Frong', + level: 5, + roomType: 'MORNING', + certifyTime: 9, + currentUserCount: 4, + maxUserCount: 10, + routine: [ + { + routineId: 5, + content: 'PR 올리기' + }, + { + routineId: 9, + content: '코드 리뷰하기' + } + ] + }, + { + id: 34, + title: '영명이의 루틴방', + managerNickname: 'ymkim', + level: 7, + roomType: 'NIGHT', + certifyTime: 21, + currentUserCount: 4, + maxUserCount: 10, + routine: [ + { + routineId: 5, + content: '물 마시기' + }, + { + routineId: 9, + content: '아침 먹기' + } + ] + }, + { + id: 35, + title: '홍박사의 루틴방', + managerNickname: 'HongJJANG', + level: 4, + roomType: 'NIGHT', + certifyTime: 1, + currentUserCount: 4, + maxUserCount: 7, + routine: [ + { + routineId: 5, + content: '물 마시기' + }, + { + routineId: 9, + content: '아침 먹기' + } + ] + }, + { + id: 36, + title: '프롱루틴방', + managerNickname: 'Frong', + level: 4, + roomType: 'MORNING', + certifyTime: 9, + currentUserCount: 4, + maxUserCount: 10, + routine: [ + { + routineId: 5, + content: 'PR 올리기' + }, + { + routineId: 9, + content: '코드 리뷰하기' + } + ] + }, + { + id: 37, + title: '방이름이엄청나게긴루틴방이랍니다하하하하', + managerNickname: 'long_Frong', + level: 5, + roomType: 'NIGHT', + certifyTime: 9, + currentUserCount: 4, + maxUserCount: 10, + routine: [ + { + routineId: 5, + content: 'PR 올리기' + }, + { + routineId: 9, + content: '코드 리뷰하기' + } + ] + } + ] +}; diff --git a/src/core/mocks/handlers/rooms.ts b/src/core/mocks/handlers/rooms.ts index 4e4a7803..d3382403 100644 --- a/src/core/mocks/handlers/rooms.ts +++ b/src/core/mocks/handlers/rooms.ts @@ -2,6 +2,7 @@ import { http, HttpResponse, delay } from 'msw'; import { baseURL } from '../baseURL'; import { RoomInfo } from '../datas/room'; import { MY_JOIN_ROOMS } from '../datas/myJoinRoom'; +import { TOTAL_ROOMS } from '../datas/totalRooms'; const roomsHandlers = [ http.post(baseURL('/rooms'), async () => { @@ -158,6 +159,36 @@ const roomsHandlers = [ } return HttpResponse.json(response, { status }); + }), + + http.get(baseURL('/rooms'), async ({ request }) => { + await delay(2000); + const url = new URL(request.url); + const type = url.searchParams.get('type'); + const page = Number(url.searchParams.get('page')) || 1; + const size = Number(url.searchParams.get('size')) || 10; + + const totalRooms = TOTAL_ROOMS.rooms; + const morningRooms = totalRooms.filter( + ({ roomType }) => roomType === 'MORNING' + ); + const nightRooms = totalRooms.filter( + ({ roomType }) => roomType === 'NIGHT' + ); + + let rooms = []; + switch (type) { + case 'morning': + rooms = morningRooms.slice(size * (page - 1), size * page); + break; + case 'night': + rooms = nightRooms.slice(size * (page - 1), size * page); + break; + default: + rooms = totalRooms.slice(size * (page - 1), size * page); + } + + return HttpResponse.json({ rooms }, { status: 200 }); }) ]; diff --git a/src/core/types/TotalRooms.ts b/src/core/types/TotalRooms.ts new file mode 100644 index 00000000..6bb94415 --- /dev/null +++ b/src/core/types/TotalRooms.ts @@ -0,0 +1,28 @@ +import { DayType } from '.'; + +export type RoomSelectType = 'morning' | 'night' | 'all'; + +export interface Room { + id: number; + title: string; + managerNickname: string; + level: number; + roomType: DayType; + certifyTime: number; + currentUserCount: number; + maxUserCount: number; + routine: { + routineId: number; + content: string; + }[]; +} + +export interface TotalRooms { + rooms: Room[]; +} + +export interface RoomsRequestParams { + type?: RoomSelectType; + page?: number; + size?: number; +} diff --git a/src/core/types/index.ts b/src/core/types/index.ts index 049754b6..6c2a3ae8 100644 --- a/src/core/types/index.ts +++ b/src/core/types/index.ts @@ -3,3 +3,9 @@ export type { MyJoinRoom } from './MyJoinRoom'; export type { DayType } from './Room'; export type { ParticipatingRoom } from './MyJoinRoom'; export type { Coupons, Coupon, CouponStatus } from './Coupons'; +export type { + TotalRooms, + Room, + RoomSelectType, + RoomsRequestParams +} from './TotalRooms'; diff --git a/src/pages/SearchPage.tsx b/src/pages/SearchPage.tsx index aa4cfe17..33f23ad3 100644 --- a/src/pages/SearchPage.tsx +++ b/src/pages/SearchPage.tsx @@ -1,12 +1,11 @@ -import { useState } from 'react'; -import { totalRooms } from '@/RoomList/mocks/totalRooms'; +import { Suspense, useState } from 'react'; +import { RoomSelectType } from '@/core/types'; import { SearchBar, Selection, ResultList } from '@/RoomSearch'; -import { SelectType } from '@/RoomSearch/types/search'; +import { Deffered } from '@/shared/Deffered'; +import ResultListFallback from '@/RoomSearch/components/ResultListFallback'; const SearchPage = () => { - // TODO : mock api 연결하기 - const { rooms } = totalRooms; - const [type, setType] = useState('all'); + const [type, setType] = useState('all'); const [keyword, setKeyword] = useState(''); return ( @@ -24,7 +23,18 @@ const SearchPage = () => { />
- + + + + } + > + +
);