해당 페이지는 클라이언트 측 예시 페이지이다.
아직까지 로그인 및 로그아웃만 구현되어있어 상당히 여백의 미? 를 강조하고있다 ㅎ...
우측 하단부에 보면 +
버튼을 볼 수 있는데, 크롬 익스텐션의 display
속성을 바꿔주며 채팅창을 보여주고, 가린다.
물론, 해당 서비스의 회원이 아니어서 엑세스 토큰을 발급받지 않은 상황이거나, 크롬 익스텐션을 사용하지 않는 웹은 버튼 및 채팅창이 보이지 않는다.
해당 서비스(웹)의 크롬 익스텐션 사용 여부 및 엑세스 토큰 발급 여부는 이벤트 리스너를 통해 통신하도록 하였다.
// Client Component
// Let Chrome Extension know you are using app
useEffect(()=>{
document.dispatchEvent(new CustomEvent('chrome_extension_available_app', { detail: { available: true } }));
},[])
// Let Chrome Extension know users Info
useEffect(()=>{
// if Access Token Valid
if(accessToken!==''){
// 1. set Access Token to Redux Store to use for the application
let splitToken = accessToken.split('.');
let id = JSON.parse(atob(splitToken[1])).sub;
getUser(id, accessToken).then((res) => {
setUserInfo(prevState => {return {...prevState, nickname: res.data.nickname, email: res.data.email}})
setIsLoggedIn(true);
// 2. send Access Token to extension with event
let data = {
accessToken: accessToken,
userInfo: res.data,
serverUri: 'http://localhost:8080/stomp/chat',
stomp: {
subscribe: '/channel/chat/room/open',
enter: '/publish/chat/enter',
send: '/publish/chat/message',
roomId: 'open',
},
debugMode: true,
};
// send data through a DOM event
document.dispatchEvent(new CustomEvent('authListener', { detail: data }));
})
}
},[accessToken])
클라이언트는 다음과 같은 두개의 커스텀 이벤트를 발생시켜야한다.
1. chrome_extension_available_app: detail 의 value로는 available이라는 key에 true 값을 넣어줘야한다.
2. authListener: 서버와 통신하기 위한 정보 입력 이벤트로, detail에는 data 객체를 넣어줘야 한다. data 객체는 엑세스토큰, 사용자 정보, 서버 Uri (소켓 서버), stomp direction 주소, debug를 사용할지에 대한 boolean값을 넣어줘야한다.
// Chrome Extension event listener
export function addAppRunEventListener(){
document.addEventListener('chrome_extension_available_app', function (event) {
let data = event.detail;
if(data.available){
chrome.storage.sync.set({CHROME_EXTENSION_AVAILABLE_STATE: true });
}
});
}
// Chrome Extension event listener
export function addAuthEventListener(){
document.addEventListener('authListener', function (event) {
let data = event.detail;
chrome.storage.sync.get(['CHROME_EXTENSION_AVAILABLE_STATE'], function(res){
if(res.CHROME_EXTENSION_AVAILABLE_STATE){
const hostName = window.location.host;
const info = {};
info[hostName] = {SERVER_URI: data.serverUri, STOMP_PROP: data.stomp, ACCESS_TOKEN: data.accessToken, USER_INFO: data.userInfo, DEBUG: data.debugMode};
chrome.storage.sync.set(info, function(){
createChatDiv();
});
}
})
});
}
크롬 익스텐션에서는 두개의 이벤트 리스너가 작동하여 채팅창을 렌더링한다. 우선, chrome_extension_available_app이 사이트 랜더링 시, 해당 사이트가 크롬 익스텐션을 사용하는지 확인한 후, 사용한다면 유저 정보를 받아 올 수 있게 하였다.
authListener가 정보를 받아와 세팅을 한 후, createChatDiv 를 통해 Div 엘리먼트를 생성 및 리엑트 컴포넌트를 렌더링한다.
크롬 익스텐션을 사용하기 위한 정보가 올바르게 입력되었는지, 엑세스 토큰이 유효한지에 대한 코드가 추가되어야 할 것이다.
테스트를 위해 세개의 클라이언트를 각기 다른 포트에서 실행하였다.
메세지의 종류에는 총 3가지가 있다.
1. 서버가 보낸 메세지 (입장 메세지)
2. 상대가 보낸 메세지
3. 내가 보낸 메세지
const renderChat = () => {
return chat.map(({name, id, message}, index) => (
<div key={index} style={{ position: "relative" ,width: "100%" }}>
{id === -1 && <div className="entering_message">{message}</div>}
{id !== -1 && id !== userInfo.current.USER_INFO.id &&
<>
<div className='recieved_chat_name'>{name}</div>
<div className="recieved_chat" ref={messageEndRef}>{message}</div>
</>
}
{id !== -1 && id === userInfo.current.USER_INFO.id && <div className="send_chat" ref={messageEndRef}>{message}</div>}
</div>
));
}
서버가 보낸 채팅은 id값이 -1로 보내진다. 또한 저장된 유저 정보(id)와 메세지가 보낸 유저 정보(id)가 일치하지 않는다면 상대가 보낸 메세지로 인식한다.
CSS에서 조심해야할 부분이 있었다.
바로
인데, width 속성을 fit-content로, 그리고 max-width를 부모 속성의 70%로 제한하여 해당 크기가 넘어가는 메세지가 입력되면 줄바꿈처리가 되었지만, 공백이 적용되지 않은 연속된 숫자의 경우, 하나의 값으로 처리되어 컨텐츠를 overflow 해버리는 효과가 일어났다.
이를 처리하기 위해 찾아본 결과, word-break: break-all을 이용하여, 글자 단위로 크기를 넘어 갈 시 자동 줄바꿈이 되도록 설정하였다.
'개발일지' 카테고리의 다른 글
[이미지 렌더링: 02] 웹 성능과 이미지 최적화 (0) | 2022.07.06 |
---|---|
[이미지 렌더링: 01] 무한스크롤과 이미지 렌더링 (0) | 2022.07.01 |
[크롬 익스텐션: 05] StompJs & SockJs, 디자인 및 구현 - 1 (0) | 2022.06.23 |
[리펙토링: 나들서울] Debounce & Throttling (0) | 2022.06.14 |
[크롬 익스텐션: 04] 클라이언트 - 소셜 로그인 (0) | 2022.06.09 |