diff --git a/src/apis/getBookmarkData.ts b/src/apis/getBookmarkData.ts index 1d49609d..bfd4b699 100644 --- a/src/apis/getBookmarkData.ts +++ b/src/apis/getBookmarkData.ts @@ -1,5 +1,3 @@ -/* eslint-disable @typescript-eslint/no-unsafe-call */ -/* eslint-disable @typescript-eslint/no-unsafe-member-access */ import { instance } from '@/apis/api'; import type { GetBookmarkRequest, GetBookmarkResponse } from '@manchui-api'; @@ -27,4 +25,4 @@ export async function getBookmarkData(request: GetBookmarkRequest): Promise(`/api/chat/list/${roomId}${queryParams}`); + + return res.data; + } catch (e) { + console.error('getChatMessageData 함수에서 오류 발생:', e); + throw new Error('채팅 데이터를 불러오는데 실패했습니다.'); + } +} diff --git a/src/apis/getGatheringData.ts b/src/apis/getGatheringData.ts index 6c4cae63..85f93642 100644 --- a/src/apis/getGatheringData.ts +++ b/src/apis/getGatheringData.ts @@ -5,7 +5,7 @@ export async function getGatheringData(request: GetGatheringRequest): Promise(`/api/chat/user/list/${roomId}`); + + return res.data; + } catch (e) { + console.error('getRoomUserData 함수에서 오류 발생:', e); + throw new Error('채팅방 유저 데이터를 불러오는데 실패했습니다.'); + } +} diff --git a/src/components/bookmark/BookmarkBanner/index.tsx b/src/components/bookmark/BookmarkBanner/index.tsx index ec5dd735..c5bdb3ea 100644 --- a/src/components/bookmark/BookmarkBanner/index.tsx +++ b/src/components/bookmark/BookmarkBanner/index.tsx @@ -1,7 +1,7 @@ import * as m from 'framer-motion/m'; /* eslint-disable tailwindcss/no-custom-classname */ -export default function BookmarkBanner({ isError }: { isError: boolean }) { +export default function BookmarkBanner() { return ( - {isError ? '잠시 후 다시 시도해주세요.' : '마감되기 전에 지금 바로 참여해보세요'} + 마감되기 전에 지금 바로 참여해보세요 ); } diff --git a/src/components/bookmark/BookmarkCardList/index.tsx b/src/components/bookmark/BookmarkCardList/index.tsx deleted file mode 100644 index 461455a4..00000000 --- a/src/components/bookmark/BookmarkCardList/index.tsx +++ /dev/null @@ -1,31 +0,0 @@ -/* eslint-disable tailwindcss/no-custom-classname */ -import CardSection, { CardSkeleton, MessageWithLink } from '@/components/main/MainCardSection/CardSection'; -import NoData from '@/components/shared/NoData'; -import type { GetBookmarkResponse } from '@manchui-api'; - -interface BookmarkCardListProps { - data?: GetBookmarkResponse['data']; - isError: boolean; - isLoading: boolean; - skeletonCount: number; -} - -export default function BookmarkCardList({ data, isLoading, isError, skeletonCount }: BookmarkCardListProps) { - return ( -
-
- {isLoading && !isError - ? Array.from({ length: skeletonCount }).map((_, idx) => ) - : data?.gatheringList.map((gathering) => )} - - {data?.gatheringCount === 0 && !isError && !isLoading && } - - {isError && ( -
- window.location.reload()} /> -
- )} -
-
- ); -} diff --git a/src/components/bookmark/BookmarkContainer/index.tsx b/src/components/bookmark/BookmarkContainer/index.tsx index 0ae352f2..3e6ef801 100644 --- a/src/components/bookmark/BookmarkContainer/index.tsx +++ b/src/components/bookmark/BookmarkContainer/index.tsx @@ -1,3 +1,3 @@ export default function BookmarkContainer({ children }: { children: React.ReactNode }) { - return
{children}
; + return
{children}
; } diff --git a/src/components/bookmark/BookmarkFilter/index.tsx b/src/components/bookmark/BookmarkFilter/index.tsx deleted file mode 100644 index b62b671f..00000000 --- a/src/components/bookmark/BookmarkFilter/index.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import CategoryList from '@/components/main/HeaderSection/FilterList/CategoryList'; -import CloseDateToggle from '@/components/main/HeaderSection/FilterList/CloseDateToggle'; -import DateDropdown from '@/components/main/HeaderSection/FilterList/DateDropdown'; -import RegionDropdown from '@/components/main/HeaderSection/FilterList/RegionDropdown'; - -export default function BookmarkFilter() { - return ( - <> -
-
- -
-
- - -
- -
-
- - ); -} diff --git a/src/components/bookmark/BookmarkHeader/index.tsx b/src/components/bookmark/BookmarkHeader/index.tsx index 3ef51bf2..4583c7e2 100644 --- a/src/components/bookmark/BookmarkHeader/index.tsx +++ b/src/components/bookmark/BookmarkHeader/index.tsx @@ -3,12 +3,24 @@ import type { GetBookmarkResponse } from '@manchui-api'; export default function BookmarkHeader({ data }: { data?: GetBookmarkResponse['data'] }) { return ( -
+
-

찜한 모임

+

찜한 모임

{data?.gatheringCount}
); } + +export function BookmarkHeaderSkeleton() { + return ( +
+
+

찜한 모임

+ 0 +
+ +
+ ); +} diff --git a/src/components/bookmark/BookmarkSection/index.tsx b/src/components/bookmark/BookmarkSection/index.tsx new file mode 100644 index 00000000..2f364925 --- /dev/null +++ b/src/components/bookmark/BookmarkSection/index.tsx @@ -0,0 +1,38 @@ +import CardItem from '@/components/main/CardSection/CardItem'; +import { MessageWithLink } from '@/components/main/MainCardSection/CardSection'; +import ErrorBoundary from '@/components/shared/ErrorBoundary'; +import NoData from '@/components/shared/NoData'; +import PaginationBtn from '@/components/shared/PaginationBtn'; +import type { GetBookmarkResponse } from '@manchui-api'; + +interface BookmarkSectionProps { + bookmark?: GetBookmarkResponse['data']; + isError: boolean; + isLoading: boolean; +} + +function BookmarkSectionContent({ bookmark, isLoading, isError }: BookmarkSectionProps) { + return ( + <> +
    + {bookmark?.gatheringList.map((data) => )} +
+ {bookmark?.gatheringCount === 0 && } + {!isLoading && !isError && bookmark?.gatheringCount !== 0 && } + + ); +} + +export default function BookmarkSection({ bookmark, isLoading, isError }: BookmarkSectionProps) { + return ( + + window.location.reload()} /> +
+ } + > + + + ); +} diff --git a/src/components/detail/FloatingBar.tsx b/src/components/detail/FloatingBar.tsx index 6fad57f9..19263bca 100644 --- a/src/components/detail/FloatingBar.tsx +++ b/src/components/detail/FloatingBar.tsx @@ -26,24 +26,33 @@ export function FloatingBar({ gatherings, id }: DetailPageBaseType) { 당신의 취미가 특별해지는 시간 🎮 모임 참여로 새로운 즐거움을 발견하세요.
- {isClosed ? ( ) : isDisabled ? ( + )} ); diff --git a/src/components/main/CardSection/CardItem/index.tsx b/src/components/main/CardSection/CardItem/index.tsx index 585a123c..0d6dbe37 100644 --- a/src/components/main/CardSection/CardItem/index.tsx +++ b/src/components/main/CardSection/CardItem/index.tsx @@ -43,7 +43,7 @@ export default function CardItem({ data }: { data: GetGatheringResponse['data'][ await queryClient.invalidateQueries({ queryKey: ['main'] }); await queryClient.invalidateQueries({ queryKey: ['bookmark'] }); } catch (error) { - console.error('API 요청에 실패했습니다:', error); + console.error('찜하기 실패:', error); setIsHearted((prevHearted) => !prevHearted); } }; diff --git a/src/components/main/CardSection/index.tsx b/src/components/main/CardSection/index.tsx index c63316e2..bfe71451 100644 --- a/src/components/main/CardSection/index.tsx +++ b/src/components/main/CardSection/index.tsx @@ -16,13 +16,14 @@ function CardSectionContent() { const sentinelRef = useRef(null); const isIntersecting = useIntersectionObserver(sentinelRef); - const { mainData, isError, hasNextPage, fetchNextPage } = useGetGatheringData({ + const { mainData, hasNextPage, fetchNextPage } = useGetGatheringData({ query: keyword, location, category, sort: closeDate, startDate: dateStart, endDate: dateEnd, + cursor: undefined, }); useEffect(() => { @@ -30,11 +31,13 @@ function CardSectionContent() { }, [isIntersecting, hasNextPage, fetchNextPage]); return ( -
-
    {mainData?.map((data) => )}
- {mainData?.length === 0 && } - {!isError &&
} -
+ <> +
+
    {mainData?.map((data) => )}
+ {mainData?.length === 0 && } +
+ {hasNextPage &&
} + ); } diff --git a/src/components/main/HeaderSection/FilterList/index.tsx b/src/components/main/HeaderSection/FilterList/index.tsx index 52e90ebe..9b0f03e4 100644 --- a/src/components/main/HeaderSection/FilterList/index.tsx +++ b/src/components/main/HeaderSection/FilterList/index.tsx @@ -20,7 +20,7 @@ export default function FilterList() { }, [isLoggedIn, router]); return ( -
+
{/* 필터 버튼들 */} diff --git a/src/hooks/useGetBookmarkData.ts b/src/hooks/useGetBookmarkData.ts index 83503600..08fd28ac 100644 --- a/src/hooks/useGetBookmarkData.ts +++ b/src/hooks/useGetBookmarkData.ts @@ -2,11 +2,14 @@ import { getBookmarkData } from '@/apis/getBookmarkData'; import type { GetBookmarkRequest, GetBookmarkResponse } from '@manchui-api'; import { keepPreviousData, useQuery } from '@tanstack/react-query'; -const useGetBookmarkData = (request: GetBookmarkRequest) => - useQuery({ +const useGetBookmarkData = (request: GetBookmarkRequest) => { + const { data, isLoading, isError } = useQuery({ queryKey: ['bookmark', request], queryFn: () => getBookmarkData(request), placeholderData: keepPreviousData, }); + return { bookmark: data?.data, isLoading, isError }; +}; + export default useGetBookmarkData; diff --git a/src/hooks/useGetChattingData.ts b/src/hooks/useGetChattingData.ts new file mode 100644 index 00000000..26adccbf --- /dev/null +++ b/src/hooks/useGetChattingData.ts @@ -0,0 +1,25 @@ +import { getChatMessageData } from '@/apis/getChatMessageData'; +import { getRoomUserData } from '@/apis/getRoomUsersData'; +import type { GetChatListResponse, RoomUserResponse } from '@manchui-api'; +import { keepPreviousData, useInfiniteQuery, useQuery } from '@tanstack/react-query'; + +export default function useGetChattingData(roomId: string) { + const { data: roomData } = useQuery({ + queryKey: ['roomUsers', roomId], + queryFn: () => getRoomUserData(roomId), + }); + + const { + data: chatData, + hasNextPage, + fetchNextPage, + } = useInfiniteQuery({ + queryKey: ['chatMessages', roomId], + queryFn: ({ pageParam }) => getChatMessageData(roomId, pageParam as number | undefined), + getNextPageParam: (lastPage) => (lastPage.data.hasNext ? lastPage.data.nextCursor : undefined), + initialPageParam: undefined, + placeholderData: keepPreviousData, + }); + + return { chatData, roomUser: roomData?.data.userInfoList, hasNextPage, fetchNextPage }; +} diff --git a/src/hooks/useGetGatheringData.ts b/src/hooks/useGetGatheringData.ts index ce0dbb11..d6f4e6bc 100644 --- a/src/hooks/useGetGatheringData.ts +++ b/src/hooks/useGetGatheringData.ts @@ -3,9 +3,9 @@ import type { GetGatheringRequest, GetGatheringResponse } from '@manchui-api'; import { keepPreviousData, useInfiniteQuery } from '@tanstack/react-query'; const useGetGatheringData = (request: GetGatheringRequest) => { - const { data, isLoading, isError, hasNextPage, fetchNextPage } = useInfiniteQuery({ + const { data, hasNextPage, fetchNextPage } = useInfiniteQuery({ queryKey: ['main', request], - queryFn: ({ pageParam = request.cursor }) => getGatheringData({ ...request, size: 8, cursor: pageParam as number | undefined }), + queryFn: ({ pageParam }) => getGatheringData({ ...request, size: 8, cursor: pageParam as number | undefined }), getNextPageParam: (lastPage) => lastPage.data.nextCursor || undefined, initialPageParam: undefined, placeholderData: keepPreviousData, @@ -13,7 +13,7 @@ const useGetGatheringData = (request: GetGatheringRequest) => { const mainDataFlat = data?.pages.map((page) => page.data.gatheringList).flat(); - return { mainData: mainDataFlat, isLoading, isError, hasNextPage, fetchNextPage }; + return { mainData: mainDataFlat, hasNextPage, fetchNextPage }; }; export default useGetGatheringData; diff --git a/src/hooks/useIntersectionObserver.ts b/src/hooks/useIntersectionObserver.ts index b892e2ee..5b5357c7 100644 --- a/src/hooks/useIntersectionObserver.ts +++ b/src/hooks/useIntersectionObserver.ts @@ -5,7 +5,7 @@ import { useEffect, useState } from 'react'; export default function useIntersectionObserver( elementRef: RefObject, options: IntersectionObserverInit = { - threshold: 0, + threshold: 0.1, root: null, rootMargin: '0px', }, diff --git a/src/pages/bookmark/index.tsx b/src/pages/bookmark/index.tsx index 010d26f5..ef74995a 100644 --- a/src/pages/bookmark/index.tsx +++ b/src/pages/bookmark/index.tsx @@ -3,11 +3,10 @@ import { useEffect, useState } from 'react'; import dynamic from 'next/dynamic'; import { getBookmarkData } from '@/apis/getBookmarkData'; import BookmarkBanner from '@/components/bookmark/BookmarkBanner'; -import BookmarkCardList from '@/components/bookmark/BookmarkCardList'; import BookmarkContainer from '@/components/bookmark/BookmarkContainer'; -import BookmarkFilter from '@/components/bookmark/BookmarkFilter'; -import BookmarkHeader from '@/components/bookmark/BookmarkHeader'; -import PaginationBtn from '@/components/shared/PaginationBtn'; +import { BookmarkHeaderSkeleton } from '@/components/bookmark/BookmarkHeader'; +import { CardSkeleton } from '@/components/main/CardSection'; +import FilterList from '@/components/main/HeaderSection/FilterList'; import RootLayout from '@/components/shared/RootLayout'; import { SEO } from '@/components/shared/SEO'; import PAGE_SIZE_BY_DEVICE from '@/constants/pageSize'; @@ -15,21 +14,18 @@ import useDeviceState from '@/hooks/useDeviceState'; import useGetBookmarkData from '@/hooks/useGetBookmarkData'; import useInternalRouter from '@/hooks/useInternalRouter'; import useFilterStore, { useResetFilters } from '@/store/useFilterStore'; -import type { DehydratedState } from '@tanstack/react-query'; -import { dehydrate, HydrationBoundary, QueryClient } from '@tanstack/react-query'; +import { dehydrate, QueryClient } from '@tanstack/react-query'; -import Error from 'public/lottie/error.json'; - -const Lottie = dynamic(() => import('lottie-light-react'), { ssr: false }); +const BookmarkHeader = dynamic(() => import('@/components/bookmark/BookmarkHeader'), { loading: () => , ssr: false }); +const BookmarkSection = dynamic(() => import('@/components/bookmark/BookmarkSection'), { loading: () => , ssr: false }); interface BookmarkProps { - dehydratedState: DehydratedState; seo: { title: string; }; } -export default function BookmarkPage({ seo, dehydratedState }: BookmarkProps) { +export default function BookmarkPage({ seo }: BookmarkProps) { const deviceState = useDeviceState(); const [pageSize, setPageSize] = useState(PAGE_SIZE_BY_DEVICE.MAIN[deviceState]); @@ -39,11 +35,7 @@ export default function BookmarkPage({ seo, dehydratedState }: BookmarkProps) { const router = useInternalRouter(); const resetFilters = useResetFilters(); - const { - data: bookmark, - isLoading, - isError, - } = useGetBookmarkData({ + const { bookmark, isLoading, isError } = useGetBookmarkData({ page, size: pageSize, query: keyword, @@ -54,8 +46,6 @@ export default function BookmarkPage({ seo, dehydratedState }: BookmarkProps) { endDate: dateEnd, }); - const data = bookmark?.data; - useEffect(() => { if (pageSize !== PAGE_SIZE_BY_DEVICE.BOOKMARK[deviceState]) { setPageSize(PAGE_SIZE_BY_DEVICE.BOOKMARK[deviceState]); @@ -77,25 +67,14 @@ export default function BookmarkPage({ seo, dehydratedState }: BookmarkProps) { return ( <> - - {isError ? ( -
- -
- ) : ( - - )} - - - -
- - - {!isLoading && !isError && bookmark?.data.gatheringCount !== 0 && } -
-
-
-
+ + + + + + + + ); } @@ -110,7 +89,7 @@ export const getServerSideProps = async () => { return { props: { - dehydratedState: dehydrate(queryClient), + dehydratedState: JSON.parse(JSON.stringify(dehydrate(queryClient))), seo: { title: '만취 - 찜한 모임 페이지', }, diff --git a/src/pages/detail/[id]/chat/index.tsx b/src/pages/detail/[id]/chat/index.tsx index 06b31066..08c4f2e1 100644 --- a/src/pages/detail/[id]/chat/index.tsx +++ b/src/pages/detail/[id]/chat/index.tsx @@ -1,76 +1,93 @@ -import { useEffect, useState } from 'react'; +import { useEffect, useRef, useState } from 'react'; +import Image from 'next/image'; import { useRouter } from 'next/router'; import { IS_SERVER } from '@/constants/server'; +import useGetChattingData from '@/hooks/useGetChattingData'; +import useIntersectionObserver from '@/hooks/useIntersectionObserver'; import { userStore } from '@/store/userStore'; -import type Stomp from '@stomp/stompjs'; import { Client } from '@stomp/stompjs'; interface Message { - createdAt: string; + createdAt: number[]; message: string; - sender?: string; + sender: string; } -// 채팅방 회원 목록 조회 - /api/chat/user/list/{roomId} -// 채팅방 채팅 내역 조회 - /api/chat/list/{roomId}?lastMessageId={lastMessageId}&limit={limit} - export default function ChatPage() { const router = useRouter(); const { roomId } = router.query; - const [messages, setMessages] = useState([]); - const [stompClient, setStompClient] = useState(null); + const [stompClient, setStompClient] = useState(null); + const [messages, setMessages] = useState([]); const [inputMessage, setInputMessage] = useState(''); - const user = userStore((state) => state.user.name); + const [isUserListOpen, setIsUserListOpen] = useState(false); + const toggleUserList = () => setIsUserListOpen(!isUserListOpen); + const user = userStore((state) => state.user.name); const accessToken = !IS_SERVER && localStorage.getItem('accessToken'); + const sentinelRef = useRef(null); + const isIntersecting = useIntersectionObserver(sentinelRef); + + const messageContainerRef = useRef(null); + + const { chatData, roomUser, hasNextPage, fetchNextPage } = useGetChattingData(roomId as string); + + useEffect(() => { + if (messageContainerRef.current) { + messageContainerRef.current.scrollTop = messageContainerRef.current.scrollHeight; + } + }, [messages]); + + useEffect(() => { + if (messageContainerRef.current && chatData?.pages[0]) { + messageContainerRef.current.scrollTop = messageContainerRef.current.scrollHeight; + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [chatData?.pages[0]]); + + useEffect(() => { + if (isIntersecting && hasNextPage) void fetchNextPage(); + }, [isIntersecting, hasNextPage, fetchNextPage]); + useEffect(() => { const stomp = new Client({ brokerURL: 'wss://manchui.shop/ws', connectHeaders: { Authorization: `${accessToken}`, }, - debug: (str: string) => { - console.log(str); - }, + // debug: (str: string) => { + // console.log('WebSocket Debug:', str); + // }, reconnectDelay: 5000, - heartbeatIncoming: 4000, // 서버로부터 4초마다 하트비트 체크 - heartbeatOutgoing: 4000, // 클라이언트에서 4초마다 하트비트 신호 전송 + heartbeatIncoming: 4000, + heartbeatOutgoing: 4000, }); setStompClient(stomp); - stomp.activate(); - console.log('stomp', stomp); - stomp.onConnect = () => { console.log('WebSocket 연결에 성공했습니다.'); stomp.subscribe(`/exchange/chat.exchange/room.${roomId as string}`, (frame) => { try { const parsedMessage = JSON.parse(frame.body); - - console.log('parsedMessage', parsedMessage); - setMessages((prevMessages) => [...prevMessages, parsedMessage as Message]); + setMessages((prevMessages) => [parsedMessage as Message, ...prevMessages]); } catch (error) { - console.error('오류가 발생했습니다:', error); + console.error('구독오류가 발생했습니다:', error); } }); }; return () => { - if (stompClient && stompClient.connected) void stompClient.deactivate(); // STOMP 클라이언트 비활성화 - 소켓 연결 해제 - setStompClient(null); + if (stompClient && stompClient.connected) void stompClient.deactivate(); }; // eslint-disable-next-line react-hooks/exhaustive-deps - }, [accessToken, roomId]); + }, [roomId]); const sendMessage = () => { - if (!inputMessage.trim() || !roomId) return; - if (stompClient && stompClient.connected) { stompClient.publish({ destination: `/pub/chat.room.${roomId as string}`, @@ -84,58 +101,149 @@ export default function ChatPage() { setInputMessage(''); }; + const formatTime = (dateString: string) => { + const date = new Date(dateString); + let hours = date.getHours(); + const minutes = String(date.getMinutes()).padStart(2, '0'); + const ampm = hours >= 12 ? '오후' : '오전'; + + hours %= 12; + hours = hours === 0 ? 12 : hours; + + return `${ampm} ${hours}:${minutes}`; + }; + + const formatArrayTime = (timeArray: number[]) => { + const [hour, minute] = timeArray; + let hours = hour; + const minutes = String(minute).padStart(2, '0'); + const ampm = hours >= 12 ? '오후' : '오전'; + + hours %= 12; + hours = hours === 0 ? 12 : hours; + + return `${ampm} ${hours}:${minutes}`; + }; + return ( -
+
{/* 채팅방 헤더 */} - {/*
-

{data?.groupName}

-
*/} +
+
+
모임 문의하기
+ +
+
+ + {/* 채팅방 안내 메시지 */} +
+

+ 이 채팅방은 모임장과의 실시간 소통 공간입니다. 모임에 대해 궁금한 점이나 문의사항이 있으시다면 자유롭게 대화를 나누실 수 있습니다. +

+
+ + {/* 참여자 목록 슬라이드 */} +
+
+
+

참여자 목록

+ +
+ +
+ {roomUser?.map((room, index) => ( +
+
+ {`${room.name}의 +
+ {room.name} +
+ ))} +
+
+
{/* 메시지 목록 */} -
- {messages.map((msg, index) => ( -
-
-
{msg.sender}
-
{msg.message}
+
+
+ {messages.map((msg, index) => ( +
+ {msg.sender !== user && ( +
+ u.name === msg.sender)?.profileImagePath || '/images/profile.svg'} + alt="프로필" + fill + className="object-cover" + sizes="40px" + /> +
+ )} +
+ {msg.sender !== user && {msg.sender}} +
+
+
{msg.message}
+
+ {formatArrayTime(msg.createdAt)} +
+
-
- ))} + ))} + {chatData?.pages.map((page, i) => ( +
+ {page.data.chatMessageResponseList.map((msg, index) => ( +
+ {msg.sender !== user && ( +
+ u.name === msg.sender)?.profileImagePath || '/images/profile.svg'} + alt="프로필" + fill + className="object-cover" + sizes="40px" + /> +
+ )} +
+ {msg.sender !== user && {msg.sender}} +
+
+
{msg.message}
+
+ {formatTime(msg.createdAt)} +
+
+
+ ))} +
+ ))} +
+
{/* 메시지 입력 */} -
-
- setInputMessage(e.target.value)} - onKeyPress={(e) => e.key === 'Enter' && sendMessage()} - className="flex-1 rounded-lg border p-2 focus:border-blue-800 focus:outline-none" - placeholder="메시지를 입력하세요" - /> - -
+
+ setInputMessage(e.target.value)} + onKeyPress={(e) => e.key === 'Enter' && sendMessage()} + className="flex-1 rounded-2xl border bg-gray-600 p-2 pl-5 placeholder:text-gray-400 focus:border-background focus:outline-none" + placeholder="채팅을 입력하세요..." + /> +
); } - -// /** -// * 소켓 연결 주소는 ws://localhost:8080/ws -// ws://localhost:8080/ws -// ws://manchui.shop/ws -// 메시지 보내는 주소 = /pub/chat/room/{roomId} -// 구독 주소 = /sub/chat/room/{roomId} -// */ - -// 구독: /exchange/chat.exchange/room.394d93d1-e4d7-45cc-abb5-e42e73d7a04c -// 보내기: /pub/chat.room.394d93d1-e4d7-45cc-abb5-e42e73d7a04c - -// 구독 - /exchange/chat.exchange/room.{roomId} -// 보내기 - /pub/chat.room.{roomId} - -// 채팅방 회원 목록 조회 - /api/chat/user/list/{roomId} -// 채팅방 채팅 내역 조회 - /api/chat/list/{roomId}?lastMessageId={lastMessageId}&limit={limit} diff --git a/src/pages/review/index.tsx b/src/pages/review/index.tsx index 8ffc57ef..8fec0956 100644 --- a/src/pages/review/index.tsx +++ b/src/pages/review/index.tsx @@ -2,7 +2,6 @@ /* eslint-disable @typescript-eslint/no-unused-vars */ import { useState } from 'react'; import { getReviewData } from '@/apis/getReviewData'; -import HeaderSection from '@/components/main/HeaderSection'; import FilterSection from '@/components/review/FilterSection'; import MainHeader from '@/components/review/MainHeader'; import ReviewCardList from '@/components/review/ReviewCardList'; @@ -40,8 +39,6 @@ export default function ReviewPage() { - {/* Header (타이틀, 검색창) */} - {/* 카테고리 */} {/* 카드 */} diff --git a/src/types/gathering.d.ts b/src/types/gathering.d.ts index 353e06b7..5c0524c9 100644 --- a/src/types/gathering.d.ts +++ b/src/types/gathering.d.ts @@ -81,4 +81,35 @@ declare module '@manchui-api' { notificationId: number; notificationType: 'GATHERING_LIKE' | 'GATHERING_JOIN'; }; + + export type RoomUserInfo = { + name: string; + profileImagePath: string; + }; + + export type RoomUserResponse = { + data: { + userInfoList: RoomUserInfo[]; + }; + message: string; + success: boolean; + }; + + export type ChatMessage = { + _id: string; + chatMessageType: 'MESSAGE' | 'ENTER'; + createdAt: string; + message: string; + sender: string; + }; + + export type GetChatListResponse = { + data: { + chatMessageResponseList: ChatMessage[]; + hasNext: boolean; + nextCursor: string | undefined; + }; + message: string; + success: boolean; + }; }