Skip to content

Commit

Permalink
채팅 추가 버전
Browse files Browse the repository at this point in the history
  • Loading branch information
alaneelee committed Jan 3, 2024
2 parents d3b2f1f + 0580bc4 commit 2ec7c3d
Show file tree
Hide file tree
Showing 7 changed files with 349 additions and 107 deletions.
205 changes: 205 additions & 0 deletions src/components/Chat.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
import React, { useEffect, useState, useRef } from "react";
import styled from "styled-components";

const ChatContainer = styled.div`
border: 1px solid #ccc;
width: 99.7%;
height: 100%;
margin: 0 auto;
display: flex;
flex-direction: column;
`;

const MessageContainer = styled.div`
margin-bottom: 10px;
`;

const MessageBox = styled.div`
height: 72vh;
overflow-y: scroll;
`;

const Sender = styled.span`
color: #c0c0c0;
font-size: 1rem;
padding-left: 5px;
font-family: "Gamja Flower", sans-serif;
`;

const SpanText = styled.span`
font-size: 1.1rem;
color: #666;
font-family: "Gamja Flower", sans-serif;
`;

const InputContainer = styled.div`
margin-top: auto;
border-top: 1px solid #333333;
height: 8vh;
display: flex;
align-items: center;
justify-content: center;
`;

const TextInput = styled.input`
border-radius: 10px;
width: 70%;
height: 10%;
padding: 10px;
margin-right: 5px;
`;

const SendButton = styled.button`
font-family: "Gamja Flower", sans-serif;
border-radius: 10px;
width: 20%;
height: 50%;
padding: 5px 10px;
background-color: #f8de7e;
color: #666;
border: none;
cursor: pointer;
`;

const ChatComponent = ({ chattingRoomId }) => {
const [messages, setMessages] = useState([]);
const [inputMessage, setInputMessage] = useState("");
const [socket, setSocket] = useState(null);
const messagesEndRef = useRef(null);

const chattingRoomIdString = chattingRoomId;
const accessToken = localStorage.getItem("accessToken");
const fetchToken = async () => {
try {
console.log(accessToken);
const response = await fetch("https://api.lemonair.me/api/auth/chat", {
method: "POST",
headers: {
Authorization: accessToken,
},
});
if (!response.ok) {
throw new Error("Network response was not ok.");
}
const data = await response.json();
console.log("서버에서 받은 chatTokenResponseDto : ", data);
return data.chatToken;
} catch (error) {
console.error("데이터를 불러오는 중 오류가 발생했습니다:", error);
}
};

useEffect(() => {
// window.addEventListener("beforeunload", () => {
// socket.close();
// });

// chatting 토큰을 먼저 요청하고 나서 webSocket 연결하기 위한 로직
const connectWebSocketAsync = async () => {
let chatToken = "";
console.log("accessToken is null ? :", accessToken === null);
if (accessToken) {
chatToken = await fetchToken();
} else {
chatToken = "notlogin"; // 로그인하지 않은 사용자의 경우 토큰 정보를 notlogin으로 요청한다.
}
const newSocket = new WebSocket(
`ws://chat.lemonair.me:8082/chat/${chattingRoomIdString}/${chatToken}`
);
setSocket(newSocket);
newSocket.onopen = () => {
console.log("웹소켓 연결됨");
};

newSocket.onmessage = (event) => {
console.log(event.data);
const receiveData = event.data.split(":");
const from = receiveData[0];
const message = receiveData.slice(1).join(":").trim();
setMessages((prevMessages) => [...prevMessages, { from, message }]);
};

newSocket.onclose = () => {
console.log("웹소켓 연결 종료");
// 연결 종료 시 재연결 시도
setTimeout(async () => {
console.log("accessToken", accessToken);
const response = await fetch("http://localhost:8081/api/auth/chat", {
method: "POST",
headers: {
Authorization: accessToken,
},
});

// 응답에서 토큰 추출
const tokenString = response.data.chatToken;
const reconnectSocket = new WebSocket(
`ws://localhost:8082/chat/${chattingRoomIdString}/${tokenString}`
);
reconnectSocket.onopen = () => {
console.log("웹소켓 재연결됨");
setSocket(reconnectSocket);
};

reconnectSocket.onmessage = (event) => {
console.log(event.data);
const receiveData = event.data.split(":");
const from = receiveData[0];
const message = receiveData.slice(1).join(":").trim();
setMessages((prevMessages) => [...prevMessages, { from, message }]);
};
}, 3000); // 3초 후 재연결 시도
};
return () => {
newSocket.close();
};
};

connectWebSocketAsync();
}, []);

const scrollToBottom = () => {
messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
};

useEffect(scrollToBottom, [messages]);

const sendMessage = () => {
if (inputMessage.trim() === "") return;

socket.send(inputMessage);
setInputMessage("");
};

const handleKeyDown = (event) => {
if (event.key === "Enter") {
event.preventDefault();
sendMessage();
}
};

return (
<ChatContainer>
<MessageBox>
{messages.map((message, index) => (
<MessageContainer key={index}>
<Sender>{message.from}: </Sender>
<SpanText>{message.message}</SpanText>
</MessageContainer>
))}
<div ref={messagesEndRef} />
</MessageBox>
<InputContainer>
<TextInput
type="text"
value={inputMessage}
onChange={(e) => setInputMessage(e.target.value)}
onKeyDown={handleKeyDown}
/>
<SendButton onClick={sendMessage}>전송</SendButton>
</InputContainer>
</ChatContainer>
);
};

export default ChatComponent;
25 changes: 11 additions & 14 deletions src/components/Slide.js
Original file line number Diff line number Diff line change
@@ -1,36 +1,33 @@
import React from 'react';
import { Link } from 'react-router-dom';
import './Slide.css';
import React from "react";
import { Link } from "react-router-dom";
import "./Slide.css";

export const Slide = React.memo(function (StackedCarouselSlideProps) {
const { data, dataIndex, isCenterSlide, swipeTo, slideIndex } =
StackedCarouselSlideProps;

const coverImage = data[dataIndex].thumbnailUrl;
const text = data[dataIndex].title;
const channelId = data[dataIndex].channelId;

console.log(coverImage);
return (
<div className='card-card' draggable={false}>
<div className="card-card" draggable={false}>
<Link
to={`/channels/${channelId}`}
style={{ textDecoration: 'none', color: 'inherit' }}
style={{ textDecoration: "none", color: "inherit" }}
>
<div className={`cover fill ${isCenterSlide ? 'off' : 'on'}`}>
<div className={`cover fill ${isCenterSlide ? "off" : "on"}`}>
<div
className='card-overlay fill'
className="card-overlay fill"
onClick={() => {
if (!isCenterSlide) swipeTo(slideIndex);
}}
/>
</div>
<div className='detail fill'>
<div className='discription'>
<div className="detail fill">
<div className="discription">
<img
style={{ width: 430 }}
alt='j'
className='cover-image'
alt="j"
className="cover-image"
src={coverImage}
/>
<p>{text}</p>
Expand Down
32 changes: 16 additions & 16 deletions src/components/header.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import React, { useState } from 'react';
import styled from 'styled-components';
import { Link } from 'react-router-dom';
import { ReactComponent as LemonSVG } from '../images/lemon.svg';
import SignupModal from '../modal/SignupModal';
import LoginModal from '../modal/LoginModal';
import React, { useState } from "react";
import styled from "styled-components";
import { Link } from "react-router-dom";
import { ReactComponent as LemonSVG } from "../images/lemon.svg";
import SignupModal from "../modal/SignupModal";
import LoginModal from "../modal/LoginModal";

const HeaderContainer = styled.header`
display: flex;
Expand Down Expand Up @@ -50,7 +50,7 @@ const UserOptions = styled.div`
text-decoration: none;
color: #555;
padding-right: 25px;
font-family: 'Reenie Beanie', cursive;
font-family: "Reenie Beanie", cursive;
}
a:hover {
Expand All @@ -65,13 +65,13 @@ const HeaderText = styled.span`
text-decoration: none;
color: #555;
padding-right: 25px;
font-family: 'Reenie Beanie', cursive;
font-family: "Reenie Beanie", cursive;
`;

const Header = () => {
const [isSignupModalOpen, setIsSignupModalOpen] = useState(false);
const [isLoginModalOpen, setIsLoginModalOpen] = useState(false);
const accessToken = localStorage.getItem('accessToken');
const accessToken = localStorage.getItem("accessToken");

const openSignupModal = () => {
setIsSignupModalOpen(true);
Expand Down Expand Up @@ -99,22 +99,22 @@ const Header = () => {
});

if (response.ok) {
localStorage.removeItem('accessToken');
localStorage.removeItem('refreshToken');
alert('로그아웃 되었습니다.');
localStorage.removeItem("accessToken");
localStorage.removeItem("refreshToken");
alert("로그아웃 되었습니다.");
window.location.reload();
} else {
console.log('로그아웃에 실패하였습니다.');
console.log("로그아웃에 실패하였습니다.");
}
} catch (error) {
console.error('로그아웃 중 오류 발생:', error);
console.error("로그아웃 중 오류 발생:", error);
}
};
return (
<HeaderContainer>
<Logo>
<LogoLink to='/'>
<img src='/logo2.jpg' alt='로고' />
<LogoLink to="/">
<img src="/logo2.jpg" alt="로고" />
</LogoLink>
</Logo>
<SvgDiv>
Expand Down
Loading

0 comments on commit 2ec7c3d

Please sign in to comment.