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 = () => {
/>
-
+
+
+
+ }
+ >
+
+
);