Chat is working with a local chat-server

This commit is contained in:
2021-03-17 16:52:14 +11:00
parent 8561219542
commit 13e3ce6db8
3 changed files with 96 additions and 37 deletions
+5 -2
View File
@@ -1,6 +1,7 @@
//react //react
import React from 'react'; import React, { useContext } from 'react';
import { BrowserRouter, Switch } from 'react-router-dom'; import { BrowserRouter, Switch } from 'react-router-dom';
import { TokenContext } from './utilities/token-provider';
//library components //library components
import LazyRoute from './lazy-route'; import LazyRoute from './lazy-route';
@@ -15,6 +16,8 @@ import Footer from './panels/footer';
import PopupChat from './panels/popup-chat'; import PopupChat from './panels/popup-chat';
const App = props => { const App = props => {
const authTokens = useContext(TokenContext);
//default render //default render
return ( return (
<BrowserRouter> <BrowserRouter>
@@ -33,7 +36,7 @@ const App = props => {
<LazyRoute path='*' component={() => import('./pages/not-found')} /> <LazyRoute path='*' component={() => import('./pages/not-found')} />
</Switch> </Switch>
<PopupChat /> { authTokens.accessToken ? <PopupChat /> : <></> }
<Footer /> <Footer />
</BrowserRouter> </BrowserRouter>
); );
+57 -32
View File
@@ -1,38 +1,38 @@
import React, { useState, useRef } from 'react'; import React, { useState, useEffect, useRef, useContext } from 'react';
//import { io } from 'socket.io-client'; import { TokenContext } from '../utilities/token-provider';
import { io } from 'socket.io-client';
import '../../styles/popup-chat.css'; import '../../styles/popup-chat.css';
//const socket = io(`${process.env.CHAT_URI}/chat`); const socket = io(`${process.env.CHAT_URI}/chat`);
const PopupChat = props => { const PopupChat = props => {
const [open, setOpen] = useState(false); const [open, setOpen] = useState(false);
const [chatlog, setChatlog] = useState([ const [chatlog, setChatlog] = useState([]);
{ username: 'foo', text: 'bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar '},
{ username: 'foo', text: 'bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar '},
{ username: 'foo', text: 'bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar '},
{ username: 'foo', text: 'bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar '},
{ username: 'foo', text: 'bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar '},
{ username: 'foo', text: 'bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar '},
{ username: 'foo', text: 'bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar '},
{ username: 'foo', text: 'bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar '},
{ username: 'foo', text: 'bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar '},
{ username: 'foo', text: 'bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar '},
{ username: 'foo', text: 'bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar '},
{ username: 'foo', text: 'bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar '},
{ username: 'foo', text: 'bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar '},
{ username: 'foo', text: 'bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar '},
{ username: 'foo', text: 'bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar '},
{ username: 'foo', text: 'bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar '},
{ username: 'foo', text: 'bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar '}
]);
const inputRef = useRef(); const inputRef = useRef();
const sendRef = useRef();
const endRef = useRef();
const authTokens = useContext(TokenContext);
const pushChatlog = line => setChatlog(prevChatlog => [...prevChatlog, line]);
useEffect(() => {
socket.on('message', message => pushChatlog(message));
socket.on('disconnect', reason => pushChatlog({ emphasis: true, text: 'Lost connection' }));
}, []);
useEffect(() => {
if (open) {
endRef.current.scrollIntoView();
}
}, [chatlog, open]);
if (!open) { if (!open) {
return ( return (
<div className='chat'> <div className='chat'>
<button type='button' className='open' onClick={() => handleOpen(setOpen)}>Open Chat</button> <button type='button' className='open' onClick={() => authTokens.tokenCallback(accessToken => handleOpen(setOpen, accessToken))}>Open Chat</button>
</div> </div>
); );
} }
@@ -41,32 +41,57 @@ const PopupChat = props => {
<div className='chat'> <div className='chat'>
<div className='log'> <div className='log'>
<ul className='scrollable'> <ul className='scrollable'>
{chatlog.map((line, index) => <li key={index} className='line'><span className='username'>{line.username}: </span><span className='text'>{line.text}</span></li>)} {chatlog.map(processLine)}
<li ref={endRef} />
</ul> </ul>
</div> </div>
<input type='text' className='input' placeholder='message' ref={inputRef}></input> <input type='text' className='input' placeholder='message' onKeyPress={evt => evt.key == 'Enter' ? sendRef.current.click() : ''} ref={inputRef} />
<button type='button' className='send' onClick={() => handleSend(inputRef)}>Send</button> <button type='button' className='send' onClick={() => authTokens.tokenCallback(accessToken => handleSend(inputRef, pushChatlog, authTokens.getPayload().username, accessToken))} ref={sendRef}>Send</button>
<button type='button' className='close' onClick={() => handleClose(setOpen)}>Close Chat</button> <button type='button' className='close' onClick={() => handleClose(setOpen)}>Close Chat</button>
</div> </div>
); );
}; };
const handleOpen = setOpen => { //handlers
const handleOpen = (setOpen, accessToken) => {
setOpen(true); setOpen(true);
//TODO socket.emit('open chat', {
accessToken
});
}; };
const handleClose = setOpen => { const handleClose = setOpen => {
setOpen(false); setOpen(false);
//TODO
}; };
const handleSend = inputRef => { const handleSend = (inputRef, pushChatlog, username, accessToken) => {
//TODO socket.emit('message', {
accessToken,
text: inputRef.current.value
});
if (!inputRef.current.value.startsWith('/')) {
pushChatlog({ username: username, text: inputRef.current.value });
}
inputRef.current.value = ''; inputRef.current.value = '';
}; };
//render each line
const processLine = (line, index) => {
let content = <span>{line.username ? <span className='username'>{line.username}: </span> : ''}{line.text ? <span className='text'>{line.text}</span> : ''}</span>;
//decorators
if (line.emphasis) {
content = <em>{content}</em>;
}
if (line.strong) {
content = <strong>{content}</strong>;
}
return<li key={index} className='line'>{content}</li>;
};
export default PopupChat; export default PopupChat;
+34 -3
View File
@@ -11,7 +11,7 @@ const TokenProvider = props => {
useEffect(() => { useEffect(() => {
setAccessToken(localStorage.getItem("accessToken") || ''); setAccessToken(localStorage.getItem("accessToken") || '');
setRefreshToken(localStorage.getItem("refreshToken") || ''); setRefreshToken(localStorage.getItem("refreshToken") || '');
}, []) }, []);
useEffect(() => { useEffect(() => {
localStorage.setItem("accessToken", accessToken); localStorage.setItem("accessToken", accessToken);
@@ -79,11 +79,42 @@ const TokenProvider = props => {
//access the refreshed token via callback //access the refreshed token via callback
const tokenCallback = async (cb) => { const tokenCallback = async (cb) => {
//TODO: tokenCallback //if expired (10 minutes, normally)
const expired = new Date(decode(accessToken).exp * 1000) < Date.now();
if (expired) {
//ping the auth server for a new token
const response = await fetch(`${process.env.AUTH_URI}/auth/token`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*'
},
body: JSON.stringify({
token: refreshToken
})
});
//any errors, throw them
if (!response.ok) {
throw `${response.status}: ${await response.text()}`;
}
//save the new auth stuff (setting bearer as well)
const newAuth = await response.json();
setAccessToken(newAuth.accessToken);
setRefreshToken(newAuth.refreshToken);
//finally
return cb(newAuth.accessToken);
} else {
return cb(accessToken);
}
}; };
return ( return (
<TokenContext.Provider value={{ accessToken, refreshToken, setAccessToken, setRefreshToken, tokenFetch, getPayload: () => decode(accessToken) }}> <TokenContext.Provider value={{ accessToken, refreshToken, setAccessToken, setRefreshToken, tokenFetch, tokenCallback, getPayload: () => decode(accessToken) }}>
{props.children} {props.children}
</TokenContext.Provider> </TokenContext.Provider>
) )