Skip to content

Commit

Permalink
Siyeon (#44)
Browse files Browse the repository at this point in the history
* fix : 예약 취소 버튼을 눌렀을 때 다른 페이지로 이동, 체크인 날짜부터는 예약 취소 버튼 비활성화

결제 취소를 위해 데이터도 넘겨줘야 할 것 같음 - 다시 확인 필요
예약 취소 완료 페이지로 이동해야 하는데 아직 url을 몰라서 나중에 수정해야 함

* feat : 에약 취소내역 상세페이지 구현

* fix : 예약 취소된 내역을 예약 상세페이지로 접근하면 예약 취소 상세페이지를 렌더링

* refactor : 필요 없어진 중복 코드 제거

* fix : 예약 상세페이지에 호스트 정보 추가

* fix : 예약 상세페이지 url 변경

/reserve/{reserveId} -> /reserve/detail/{reserveId}
/reserve/{hotelId}가 필요해서 변경함

* feat : 예약하기 페이지 화면 기본 구성

* fix : 예약하기 페이지 달력 수정

* fix : 예약하기 페이지에서 인원 선택 시 최대 인원 넘어가지 않도록 설정

* fix : 예약하기 페이지 날짜 선택 화면 수정

체크인 날짜, 체크아웃 날짜 각각 달력 표시
현재 날짜부터 선택 가능, 현재 날짜부터 2년 뒤까지만 선택 가능
react-datepicker, date-fns, dayjs, @mui/icons-material @mui/material @emotion/styled @emotion/react, lodash 설치 필요
아직 예약 불가능한 날짜 비활성화 기능은 없음

* fix : 예약하기 페이지 달력에서 선택 불가능한 날짜 비활성화 설정

아직 DB에서 예약되어있는 날짜를 조회하진 않음
샘플 코드로 선택 불가능한 날짜를 설정했을 때 제대로 동작하는지만 테스트

* fix : 예약하기 페이지 결제 금액 정보 추가

현재는 단순히 1박 가격만 띄워줌. 수정 필요

* fix : 예약하기 페이지 호텔 정보 및 호스트 정보 수정

* fix : HotelReservation에서 isLoading -> isHotelLoading 수정

* feat : 이용 완료된 예약에 한하여 리뷰 작성 버튼 추가

* fix : Calendar에서 사용하던 startDate, endDate와 useState를 HotelReservation으로 이동

HotelReservation에서 그 값을 사용하기 위함
Calendar에는 props로 전달함

* feat : 예약하기 POST

체크인/체크아웃 날짜, 선택한 기간에 대한 결제 요금 전송
isPaid는 false로 전송해서 아직 결제가 되지 않았음을 나타냄(예약 완료되지 않음)

* feat : 멤버 관련해서 접근 권한 설정

* fix : 예약 기간 계산하는 코드 수정, 주석 제거

* feat : 예약하기 버튼 누르면 결제하기 페이지로 라우팅

* feat : 예약할 때 날짜 선택 시 해당 숙소에 예약되어 있는 날짜들 비활성화하기 위한 GET 요청

* fix : 예약하기 페이지 캘린더 수정

* fix : 선택한 체크인/체크아웃 날짜가 디비에는 하루씩 당겨져서 저장되는 문제 해결, 날짜 선택할 때마다 결제 금액 변경

* refactor : 사용하지 않는 달력 코드 삭제

* fix : 이미지 안 뜨는 문제 해결 - Next의 Image 컴포넌트 사용

* refactor : 날짜 관련한 로직 수정

* feat : 예약 취소 버튼 라우팅

* refactor : UI 깔끔하게 수정

* feat : 리뷰 등록 라우팅, 예약 취소 라우팅

* fix : 예약 취소 버튼 라우팅 에러 해결

추가로 reserveId를 전역 상태로 저장하기 위한 Recoil 설정 중

* feat : 예약 상세페이지에서 숙소 이미지와 타이틀 클릭하면 숙소 상세페이지로 이동

* feat : 리뷰가 이미 작성된 예약 내역에서 리뷰 등록 버튼 비활성화

* feat : 예약 데이터 reserveId 전역 상태로 저장

* fix : 결제페이지에서 다른 페이지로 이동한 후 다시 예약 시도하면 새로운 예약 데이터 생성되는 문제 해결
결제가 완료되면 recoil로 관리하던 reserveId를 null로 초기화
결제까지 완료되지 않은 경우에는 다른 숙소 예약해도 기존 예약 임시데이터 사용해서 데이터 변경만 함

* refactor : 디자인 수정

* fix : 달력 날짜 선택 부분 수정...

* fix : 달력 날짜 선택 부분 수정
중간에 하루만 예약되어있지 않은 경우도 선택 못하게 비활성화
체크인/체크아웃 날짜 같은 날짜로 선택되지 않게 변경

* feat : 웹소켓 설정, 채팅방 생성

* feat : 문의하기 버튼 클릭 시 채팅방 생성 후 해당 채팅방 페이지로 이동

* fix : 특정 채팅방만 구독

* feat : 채팅방 UI 변경, 채팅 상대 정보, 송수신자 메세지 분리, 스크롤

* fix : 채팅 메세지 날짜 형식 변경

* refactor : useChatRoomInfo에서 error 부분 이름 변경

* feat : 채팅방 이전 채팅 내역 불러와서 띄우기

* refactor : 사용하지 않는 코드 제거

* feat : 마이페이지 문의내역

* feat : 마이페이지에 문의내역

* feat : 마이페이지 문의내역 채팅방 리스트

* fix : 채팅 입력하는 부분 수정
- 아무것도 입력하지 않았을 때는 전송 못하게 막음
- Enter로 전송, Shift+Enter로 줄바꿈
- 한글 전송 시 마지막 글자가 추가로 전송되는 문제 해결

* feat : 채팅방 퇴장 위한 Dropdown 추가

* feat : 게스트만 퇴장하기 버튼, 퇴장 후에 이전 페이지로 이동

* feat : 게스트는 채팅방 퇴장 가능

* feat : 종료된 채팅방에서 메세지 입력 및 전송 불가, 채팅방에서 이전 페이지로 이동 버튼

* feat : 종료된 채팅방 표시

* feat : 채팅 내역이 없고 생성만 된 채팅방은 마이페이지에서 생성된 시간 표시

* 배포 실패

* feat : 마이페이지 문의내역 호스트와 게스트 분리, 호스트는 진행중/종료 탭으로 분리

* fix : 마이페이지 호스트와 게스트 분리 후 페이징 문제 해결

* fix : 마이페이지 호스트와 게스트 분리 후 페이징 문제 해결

* fix : 마이페이지 문의내역 탭 삭제

* refactor : 웹소켓 설정 파일 분리

* refactor : 웹소켓 설정 파일 분리

* refactor : 웹소켓 설정 파일 분리

* feat : 채팅방에서 나갈 때 읽음 처리 요청

* feat : 채팅방에서 나갈 때 읽음 처리 요청

* feat : 문의내역 안 읽은 메세지 개수 표시

* refactor : 로딩 및 에러 조건 수정
  • Loading branch information
jkeum-dev authored Mar 20, 2024
1 parent bafc430 commit 7c2bd93
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 32 deletions.
53 changes: 31 additions & 22 deletions src/components/chat/Chat.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,13 @@

import { useEffect, useState, useRef } from 'react';
import { useRouter } from 'next/navigation'
import { Stomp } from '@stomp/stompjs';
import SockJS from 'sockjs-client';
import { useUser } from '@/hooks/useUser';
import { useChatRoomInfo, useChatMessageList } from '@/hooks/useChat';
import { format } from 'date-fns';
import { FiMoreVertical, FiChevronLeft } from 'react-icons/fi';
import { Dropdown, DropdownTrigger, DropdownMenu, DropdownItem, Button } from "@nextui-org/react";
import axios from "axios";
import { useUser } from '@/hooks/useUser';
import { useChatRoomInfo, useChatMessageList } from '@/hooks/useChat';
import { connectWebSocket, disconnectWebSocket } from '@/config/websocket-config';

export default function Chat({ id }) {
const [stompClient, setStompClient] = useState(null);
Expand All @@ -28,23 +27,33 @@ export default function Chat({ id }) {
}, [chatMessages]);

useEffect(() => {
const socket = new SockJS(`${process.env.NEXT_PUBLIC_BASE_URL}/chat`);
const client = Stomp.over(socket);
client.connect({}, (frame) => {
console.log('Connected: ' + frame);
client.subscribe(`/topic/messages/${id}`, (message) => {
console.log('Received: ' + message.body);
setMessages((prevMessages) => [...prevMessages, JSON.parse(message.body)]);
});
});
setStompClient(client);
const onMessageReceived = (message) => {
setMessages((prevMessages) => [...prevMessages, message]);
};

return () => {
if (client && client.connected) {
client.disconnect();
const { stompClient } = connectWebSocket(`${process.env.NEXT_PUBLIC_BASE_URL}/chat`, id, onMessageReceived);
setStompClient(stompClient);

const markMessageAsRead = () => {
try {
const response = axios.post(`${process.env.NEXT_PUBLIC_BASE_URL}/api/v1/chat/read/${id}`,
{
nickname: user.objData.nickname
});

if (response.status >= 400) {
throw new Error('Network response was not ok')
}
} catch (error) {
console.error('Error marking message as read:', error);
}
};
}, []);

return () => {
markMessageAsRead();
disconnectWebSocket();
};
}, [user, isLoading, isError]);

useEffect(() => {
// 채팅 메시지 컨테이너의 스크롤 높이를 최신 값으로 설정하여 스크롤을 아래로 이동
Expand All @@ -54,12 +63,12 @@ export default function Chat({ id }) {
}
}, [messages]);

if (isChatLoading || isLoading || isMsgLoading) {
return <div className="h-[60vh] mt-32">loading</div>;
if (isLoading || isChatLoading || isMsgLoading || !chatRoom?.objData || !chatMessages?.objData) {
return <div className="h-[60vh] mt-32 ml-16">loading</div>;
}

if (isChatError || isError || isMsgError || !user?.objData || !chatRoom?.objData || !chatMessages?.objData) {
return <div className="h-[60vh] mt-32">Error</div>;
if (isError || !user?.objData || isChatError || isMsgError) {
return <div className="h-[60vh] mt-32 ml-16">Error</div>;
}

const handleExitChatRoom = async () => {
Expand Down
17 changes: 7 additions & 10 deletions src/components/mypage/MyChatRooms.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { format } from 'date-fns';

export default function MyChatRooms() {
const [page, setPage] = useState(1)
const router = useRouter();

const chatRoomsQuery = useQuery({
queryKey: ["chatRooms", page],
Expand All @@ -29,8 +30,6 @@ export default function MyChatRooms() {
[chatRoomsQuery.data?.objData.totalPages]
)

const router = useRouter();

if (chatRoomsQuery.isLoading) {
return <div>loading</div>
}
Expand Down Expand Up @@ -58,16 +57,14 @@ export default function MyChatRooms() {
<div className={"flex flex-col justify-between w-full"}>
<div className={"flex justiy-between items-center w-full"}>
<div className={"text-2xl"}>{chatRoom.contactNickname}</div>
{chatRoom.latestDate &&
<div className="text-base text-gray-500 ml-auto mr-3">{format(new Date(chatRoom.latestDate), 'MM/dd HH:mm')}</div>
}
{!chatRoom.latestDate &&
<div className="text-base text-gray-500 ml-auto mr-3">{format(new Date(chatRoom.createdAt), 'MM/dd HH:mm')}</div>
}
<div className="text-base text-gray-500 ml-auto mr-3">{format(new Date(chatRoom.latestDate), 'MM/dd HH:mm')}</div>
</div>
<div className={"flex justiy-end items-center w-full"}>
<div className={"flex justiy-between items-center w-full mb-2"}>
{chatRoom.left &&
<Chip className="ml-auto mr-3" size="md" color="danger">채팅 종료</Chip>
<Chip size="md" color="danger" variant="flat">채팅 종료</Chip>
}
{chatRoom.unread > 0 &&
<Chip className="ml-auto mr-3 text-sm" size="md" color="primary">{chatRoom.unread}</Chip>
}
</div>
</div>
Expand Down
36 changes: 36 additions & 0 deletions src/config/websocket-config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { Stomp } from '@stomp/stompjs';
import SockJS from 'sockjs-client';

let stompClient = null;
let subscription = null;

export const connectWebSocket = (url, id, onMessageReceived) => {
if (!stompClient || !stompClient.connected) {
const socket = new SockJS(url);
stompClient = Stomp.over(socket);

stompClient.connect({}, () => {
console.log('Websocket Connected');
subscription = stompClient.subscribe(`/topic/messages/${id}`, (message) => {
console.log('Received: ' + message.body);
onMessageReceived(JSON.parse(message.body));
});
});
}

return { stompClient };
};

export const disconnectWebSocket = () => {
if (stompClient && stompClient.connected) {
stompClient.disconnect(() => {
console.log('Websocket disconnected');
});
stompClient = null;
}

if (subscription) {
subscription.unsubscribe();
subscription = null;
}
};

0 comments on commit 7c2bd93

Please sign in to comment.