diff --git a/src/api/chatApi.ts b/src/api/chatApi.ts deleted file mode 100644 index eb26cdc..0000000 --- a/src/api/chatApi.ts +++ /dev/null @@ -1,182 +0,0 @@ -import axios from "axios"; -import { API_ENDPOINTS } from "./endpoints"; - -// 채팅 요청 인터페이스 -export interface ChatRequest { - id: number; - senderId: number; - receiverId: number; - message: string; - status: "PENDING" | "APPROVED" | "REJECTED"; - createdAt: string; -} - -// 채팅방 인터페이스 -export interface ChatRoom { - id: number; - name: string; - type: "DIRECT" | "GROUP"; - lastMessage?: string; - lastMessageTime?: string; - unreadCount: number; - participants: ChatParticipant[]; -} - -// 채팅 참여자 인터페이스 -export interface ChatParticipant { - id: number; - nickname: string; - profileImage?: string; -} - -// 메시지 인터페이스 -export interface ChatMessage { - id: number; - roomId: number; - senderId: number; - senderName: string; - message: string; - timestamp: string; - isOwn: boolean; -} - -// 사용자 검색 결과 인터페이스 -export interface UserSearchResult { - id: number; - nickname: string; - name: string; - profileImage?: string; - apartmentName?: string; -} - -// 1대1 채팅 요청 -export const sendChatRequest = async (receiverId: number, message: string) => { - const response = await axios.post( - `${API_ENDPOINTS.CHAT.REQUEST}`, - { - receiverId, - message, - }, - { withCredentials: true } - ); - return response.data; -}; - -// 채팅 요청 승인 -export const approveChatRequest = async (requestId: number) => { - const response = await axios.post( - `${API_ENDPOINTS.CHAT.APPROVE_REQUEST}/${requestId}/approve`, - {}, - { withCredentials: true } - ); - return response.data; -}; - -// 채팅 요청 거절 -export const rejectChatRequest = async (requestId: number) => { - const response = await axios.delete( - `${API_ENDPOINTS.CHAT.REJECT_REQUEST}/${requestId}/reject`, - { withCredentials: true } - ); - return response.data; -}; - -// 보낸 채팅 취소 -export const cancelChatRequest = async (requestId: number) => { - const response = await axios.delete( - `${API_ENDPOINTS.CHAT.CANCEL_REQUEST}/${requestId}`, - { withCredentials: true } - ); - return response.data; -}; - -// 받은 채팅 요청 목록 조회 -export const getReceivedChatRequests = async (): Promise => { - const response = await axios.get(`${API_ENDPOINTS.CHAT.RECEIVED_REQUESTS}`, { - withCredentials: true, - }); - // API 응답 구조에 따라 data 필드에서 배열을 추출 - return response.data?.data || response.data || []; -}; - -// 보낸 채팅 요청 목록 조회 -export const getSentChatRequests = async (): Promise => { - const response = await axios.get(`${API_ENDPOINTS.CHAT.SENT_REQUESTS}`, { - withCredentials: true, - }); - // API 응답 구조에 따라 data 필드에서 배열을 추출 - return response.data?.data || response.data || []; -}; - -// 1대1 채팅 목록 조회 -export const getDirectChatRooms = async (): Promise => { - const response = await axios.get(`${API_ENDPOINTS.CHAT.DIRECT_ROOMS}`, { - withCredentials: true, - }); - // API 응답 구조에 따라 data 필드에서 배열을 추출 - return response.data?.data || response.data || []; -}; - -// 단체 채팅 목록 조회 -export const getGroupChatRooms = async (): Promise => { - const response = await axios.get(`${API_ENDPOINTS.CHAT.GROUP_ROOMS}`, { - withCredentials: true, - }); - // API 응답 구조에 따라 data 필드에서 배열을 추출 - return response.data?.data || response.data || []; -}; - -// 채팅방 상세 조회 -export const getChatRoomDetail = async (roomId: number): Promise => { - const response = await axios.get( - `${API_ENDPOINTS.CHAT.ROOM_DETAIL}/${roomId}`, - { withCredentials: true } - ); - return response.data; -}; - -// 임시 토큰 발급 -export const getWebSocketToken = async (): Promise<{ token: string }> => { - console.log("WebSocket 토큰 발급 시작..."); - - try { - // /api/ws/token 엔드포인트 시도 (프록시를 통해 https://danjitalk.duckdns.org/api/ws/token로 전달) - console.log("토큰 발급 엔드포인트 시도: /api/ws/token"); - const response = await axios.post( - "/api/ws/token", - {}, - { withCredentials: true } - ); - console.log("토큰 발급 응답:", response.data); - - // API 응답 구조에 따라 토큰 추출 - let token: string; - if (typeof response.data === "string") { - // 응답이 문자열인 경우 - token = response.data; - } else if (response.data?.token) { - // 응답이 { token: "..." } 형태인 경우 - token = response.data.token; - } else if (response.data?.data?.token) { - // 응답이 { data: { token: "..." } } 형태인 경우 - token = response.data.data.token; - } else if (response.data?.data) { - // 응답이 { data: "..." } 형태인 경우 - token = response.data.data; - } else { - console.error("토큰을 찾을 수 없습니다. 응답 구조:", response.data); - throw new Error("토큰을 찾을 수 없습니다."); - } - - console.log("추출된 토큰:", token ? "토큰 있음" : "토큰 없음"); - return { token }; - } catch (error: any) { - console.error("WebSocket 토큰 발급 실패:", { - status: error.response?.status, - statusText: error.response?.statusText, - data: error.response?.data, - message: error.message, - }); - throw new Error("WebSocket 토큰을 발급받을 수 없습니다."); - } -}; diff --git a/src/api/endpoints.ts b/src/api/endpoints.ts index 4a1fb89..e733afe 100644 --- a/src/api/endpoints.ts +++ b/src/api/endpoints.ts @@ -10,11 +10,11 @@ export const API_ENDPOINTS = { CERTIFICATION: "/mail/certification-code/send", }, - FIND:{ - EMAIL: '/member/find-id', - RESET_PW: '/member/reset-password', + FIND: { + EMAIL: "/member/find-id", + RESET_PW: "/member/reset-password", }, - + // 사용자 관련 엔드포인트 USER: { PROFILE: "/users/profile", @@ -67,19 +67,4 @@ export const API_ENDPOINTS = { ADD_RECENT_KEYWORD: "/search/recent-keywords", RECENT_APARTMENT: "/search/recent-apartment", }, - - // 채팅 관련 엔드포인트 - CHAT: { - REQUEST: "/chat/request", - APPROVE_REQUEST: "/chat/request", - REJECT_REQUEST: "/chat/request", - CANCEL_REQUEST: "/chat/request", - RECEIVED_REQUESTS: "/chat/request/received", - SENT_REQUESTS: "/chat/request/sent", - DIRECT_ROOMS: "/chat/direct", - GROUP_ROOMS: "/chat/group", - ROOM_DETAIL: "/chat/room", - SEARCH_USERS: "/users/search", - WS_TOKEN: "/ws/token", - }, }; diff --git a/src/components/chat/ChatRequestModal.module.scss b/src/components/chat/ChatRequestModal.module.scss deleted file mode 100644 index 975517e..0000000 --- a/src/components/chat/ChatRequestModal.module.scss +++ /dev/null @@ -1,197 +0,0 @@ -.overlay { - position: fixed; - top: 0; - left: 0; - right: 0; - bottom: 0; - background-color: rgba(0, 0, 0, 0.5); - display: flex; - align-items: center; - justify-content: center; - z-index: 1000; -} - -.modal { - background: white; - border-radius: 12px; - width: 90%; - max-width: 400px; - max-height: 80vh; - overflow: hidden; - box-shadow: 0 10px 25px rgba(0, 0, 0, 0.2); -} - -.header { - display: flex; - justify-content: space-between; - align-items: center; - padding: 20px 20px 0 20px; - border-bottom: 1px solid #e9ecef; - - h3 { - margin: 0; - font-size: 18px; - font-weight: 600; - color: #333; - } - - .closeButton { - background: none; - border: none; - font-size: 24px; - color: #999; - cursor: pointer; - padding: 0; - width: 30px; - height: 30px; - display: flex; - align-items: center; - justify-content: center; - border-radius: 50%; - - &:hover { - background-color: #f8f9fa; - color: #666; - } - } -} - -.content { - padding: 20px; - - .receiverInfo { - margin-bottom: 16px; - padding: 12px; - background-color: #f8f9fa; - border-radius: 8px; - border-left: 4px solid #2773e6; - - span { - font-size: 14px; - color: #666; - font-weight: 500; - } - } - - .receiverInput { - margin-bottom: 16px; - - label { - display: block; - font-size: 14px; - font-weight: 600; - color: #333; - margin-bottom: 8px; - } - - input { - width: 100%; - padding: 12px; - border: 1px solid #e9ecef; - border-radius: 8px; - font-size: 14px; - margin-bottom: 12px; - outline: none; - transition: border-color 0.2s ease; - - &::placeholder { - color: #999; - } - - &:focus { - border-color: #2773e6; - } - } - } - - .messageInput { - label { - display: block; - font-size: 14px; - font-weight: 600; - color: #333; - margin-bottom: 8px; - } - - textarea { - width: 100%; - padding: 12px; - border: 1px solid #e9ecef; - border-radius: 8px; - font-size: 14px; - font-family: inherit; - resize: vertical; - min-height: 100px; - outline: none; - transition: border-color 0.2s ease; - - &::placeholder { - color: #999; - } - - &:focus { - border-color: #2773e6; - } - } - } -} - -.footer { - display: flex; - gap: 12px; - padding: 0 20px 20px 20px; - - button { - flex: 1; - padding: 12px; - border: none; - border-radius: 8px; - font-size: 14px; - font-weight: 600; - cursor: pointer; - transition: all 0.2s ease; - - &:disabled { - opacity: 0.6; - cursor: not-allowed; - } - } - - .cancelButton { - background-color: #f8f9fa; - color: #666; - - &:hover:not(:disabled) { - background-color: #e9ecef; - } - } - - .sendButton { - background-color: #2773e6; - color: white; - - &:hover:not(:disabled) { - background-color: #1e5bb8; - } - } -} - -// 반응형 디자인 -@media (max-width: 768px) { - .modal { - width: 95%; - margin: 20px; - } - - .header { - padding: 16px 16px 0 16px; - } - - .content { - padding: 16px; - } - - .footer { - padding: 0 16px 16px 16px; - } -} diff --git a/src/components/chat/ChatRequestModal.tsx b/src/components/chat/ChatRequestModal.tsx deleted file mode 100644 index 5ea7360..0000000 --- a/src/components/chat/ChatRequestModal.tsx +++ /dev/null @@ -1,120 +0,0 @@ -import { useState } from "react"; -import styles from "./ChatRequestModal.module.scss"; - -interface ChatRequestModalProps { - isOpen: boolean; - onClose: () => void; - onSendRequest: (receiverId: number, message: string) => Promise; - receiverId?: number; - receiverName?: string; -} - -const ChatRequestModal = ({ - isOpen, - onClose, - onSendRequest, - receiverId, - receiverName, -}: ChatRequestModalProps) => { - const [message, setMessage] = useState(""); - const [isLoading, setIsLoading] = useState(false); - const [inputReceiverId, setInputReceiverId] = useState(""); - const [inputReceiverName, setInputReceiverName] = useState(""); - - const handleSendRequest = async () => { - const targetReceiverId = receiverId || parseInt(inputReceiverId); - if (!message.trim() || !targetReceiverId) return; - - try { - setIsLoading(true); - await onSendRequest(targetReceiverId, message); - setMessage(""); - setInputReceiverId(""); - setInputReceiverName(""); - onClose(); - } catch (error) { - console.error("채팅 요청 전송 실패:", error); - } finally { - setIsLoading(false); - } - }; - - const handleKeyPress = (e: React.KeyboardEvent) => { - if (e.key === "Enter" && !e.shiftKey) { - e.preventDefault(); - handleSendRequest(); - } - }; - - if (!isOpen) return null; - - return ( -
-
e.stopPropagation()}> -
-

채팅 요청

- -
- -
- {receiverName ? ( -
- 받는 사람: {receiverName} -
- ) : ( -
- - setInputReceiverId(e.target.value)} - /> - - setInputReceiverName(e.target.value)} - /> -
- )} - -
- -