Compare commits
2 commits
2b929bfd15
...
5eb1c2d0ae
Author | SHA1 | Date | |
---|---|---|---|
|
5eb1c2d0ae | ||
|
8f4e3980c7 |
19 changed files with 104 additions and 60 deletions
|
@ -1,14 +1,10 @@
|
||||||
import Logger from '../common/util/Logger';
|
import Logger from '../common/util/logger';
|
||||||
import gateway from "./gateway/globalGatewayConnection";
|
import gateway from "./gateway/globalGatewayConnection";
|
||||||
import token from "./tokenManager";
|
import { getToken } from "./tokenManager";
|
||||||
|
|
||||||
const { log: authLog } = Logger([ 'Authenticator' ]);
|
const { log: authLog } = Logger([ 'Authenticator' ]);
|
||||||
|
|
||||||
const Authenticator = {
|
export function login() {
|
||||||
login: async function() {
|
|
||||||
authLog('Logging in through gateway...');
|
authLog('Logging in through gateway...');
|
||||||
return gateway.connect(token.getToken());
|
return gateway.connect(getToken());
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Authenticator;
|
|
|
@ -1,4 +1,4 @@
|
||||||
import logger from "../../common/util/Logger";
|
import logger from "../../common/util/logger";
|
||||||
|
|
||||||
const { log: logGateway } = logger([ "Gateway" ]);
|
const { log: logGateway } = logger([ "Gateway" ]);
|
||||||
const { log: logRtc } = logger([ "Gateway", "RTC" ]);
|
const { log: logRtc } = logger([ "Gateway", "RTC" ]);
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import GatewayConnection from './GatewayConnection';
|
import GatewayConnection from './GatewayConnection';
|
||||||
import config from '../../config';
|
import config from '../../config';
|
||||||
import store from '../../common/store';
|
import store from '../../common/store';
|
||||||
import logger from '../../common/util/Logger';
|
import logger from '../../common/util/logger';
|
||||||
|
|
||||||
const { log } = logger(["globalGatewayConnection"]);
|
const { log } = logger(["globalGatewayConnection"]);
|
||||||
const { warn: experimentsWarn } = logger(["globalGatewayConnection", "Experiments"]);
|
const { warn: experimentsWarn } = logger(["globalGatewayConnection", "Experiments"]);
|
||||||
|
@ -18,6 +18,7 @@ const wsCloseCodes = {
|
||||||
NOT_AUTHORIZED: [4006, "Not authorized"],
|
NOT_AUTHORIZED: [4006, "Not authorized"],
|
||||||
FLOODING: [4007, "Flooding"],
|
FLOODING: [4007, "Flooding"],
|
||||||
NO_PING: [4008, "No ping"],
|
NO_PING: [4008, "No ping"],
|
||||||
|
UNSUPPORTED_ATTRIBUTE: [4009, "Unsupported attribute."],
|
||||||
};
|
};
|
||||||
const cancelReconnectionForCodes = [
|
const cancelReconnectionForCodes = [
|
||||||
wsCloseCodes.NOT_AUTHENTICATED[0],
|
wsCloseCodes.NOT_AUTHENTICATED[0],
|
||||||
|
@ -25,6 +26,7 @@ const cancelReconnectionForCodes = [
|
||||||
wsCloseCodes.SERVER_DENIED_CONNECTION[0],
|
wsCloseCodes.SERVER_DENIED_CONNECTION[0],
|
||||||
wsCloseCodes.TOO_MANY_SESSIONS[0],
|
wsCloseCodes.TOO_MANY_SESSIONS[0],
|
||||||
wsCloseCodes.FLOODING[0],
|
wsCloseCodes.FLOODING[0],
|
||||||
|
wsCloseCodes.UNSUPPORTED_ATTRIBUTE[0],
|
||||||
];
|
];
|
||||||
|
|
||||||
globalGatewayConnection.onopen = (sessionData) => {
|
globalGatewayConnection.onopen = (sessionData) => {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import config from '../config';
|
import config from '../config';
|
||||||
import token from "./tokenManager";
|
import { getToken } from "./tokenManager";
|
||||||
|
|
||||||
async function APIRequest(endpoint, options) {
|
export async function APIRequest(endpoint, options) {
|
||||||
let res;
|
let res;
|
||||||
let json;
|
let json;
|
||||||
let isOK = false;
|
let isOK = false;
|
||||||
|
@ -28,7 +28,7 @@ async function APIRequest(endpoint, options) {
|
||||||
return { res, json, isOK, err };
|
return { res, json, isOK, err };
|
||||||
}
|
}
|
||||||
|
|
||||||
APIRequest.authenticated = async function(endpoint, options) {
|
export async function authenticated(endpoint, options) {
|
||||||
let res;
|
let res;
|
||||||
let json;
|
let json;
|
||||||
let isOK = false;
|
let isOK = false;
|
||||||
|
@ -38,7 +38,7 @@ APIRequest.authenticated = async function(endpoint, options) {
|
||||||
if (!options.headers) options.headers = {};
|
if (!options.headers) options.headers = {};
|
||||||
|
|
||||||
options.headers = {
|
options.headers = {
|
||||||
"Authorization": token.getToken(),
|
"Authorization": getToken(),
|
||||||
...options.headers
|
...options.headers
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
const tokenManager = {
|
export function getToken() {
|
||||||
getToken: () => localStorage.getItem("token"),
|
return localStorage.getItem("token");
|
||||||
setToken: (token) => localStorage.setItem("token", token)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default tokenManager;
|
export function setToken(token) {
|
||||||
|
localStorage.setItem("token", token);
|
||||||
|
};
|
||||||
|
|
|
@ -54,6 +54,19 @@ const reducer = (state = intitialState, payload) => {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case 'messagestore/addmessagesback': {
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
messages: {
|
||||||
|
...state.messages,
|
||||||
|
[payload.channelId]: [
|
||||||
|
...payload.messages,
|
||||||
|
...state.messages[payload.channelId] || []
|
||||||
|
]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
case 'channels/selectchannel': {
|
case 'channels/selectchannel': {
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
export default function FullMessage({ glyph, title, content }) {
|
export default function FullMessage({ glyph, title, content }) {
|
||||||
return (<div className="center grow col-flex">
|
return (
|
||||||
|
<div className="center grow col-flex">
|
||||||
<div className="greeter-logo">
|
<div className="greeter-logo">
|
||||||
<span className="greeter-logo-text">{glyph}</span>
|
<span className="greeter-logo-text">{glyph}</span>
|
||||||
</div>
|
</div>
|
||||||
|
@ -7,5 +8,6 @@ export default function FullMessage({ glyph, title, content }) {
|
||||||
<div className="center">
|
<div className="center">
|
||||||
{content}
|
{content}
|
||||||
</div>
|
</div>
|
||||||
</div>)
|
</div>
|
||||||
|
);
|
||||||
}
|
}
|
|
@ -3,7 +3,7 @@ import { useHistory } from 'react-router-dom';
|
||||||
|
|
||||||
import Notification from '../Notification';
|
import Notification from '../Notification';
|
||||||
import APIRequest from '../../api/request';
|
import APIRequest from '../../api/request';
|
||||||
import { getSignupMessageFromError } from '../../common/util/Errors'
|
import { getSignupMessageFromError } from '../../common/util/errors'
|
||||||
|
|
||||||
export default function Create() {
|
export default function Create() {
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
|
@ -11,7 +11,6 @@ export default function Create() {
|
||||||
const [ usernameInput, setUsernameInput ] = useState();
|
const [ usernameInput, setUsernameInput ] = useState();
|
||||||
const [ passwordInput, setPasswordInput ] = useState();
|
const [ passwordInput, setPasswordInput ] = useState();
|
||||||
const [ specialCodeInput, setSpecialCodeInput ] = useState();
|
const [ specialCodeInput, setSpecialCodeInput ] = useState();
|
||||||
|
|
||||||
const [ specialCodePrompt, setSpecialCodePrompt ] = useState();
|
const [ specialCodePrompt, setSpecialCodePrompt ] = useState();
|
||||||
|
|
||||||
const [ info, setInfo ] = useState();
|
const [ info, setInfo ] = useState();
|
||||||
|
|
|
@ -3,9 +3,9 @@ import { useHistory } from 'react-router-dom';
|
||||||
|
|
||||||
import Notification from '../Notification';
|
import Notification from '../Notification';
|
||||||
import APIRequest from '../../api/request';
|
import APIRequest from '../../api/request';
|
||||||
import Authenticator from '../../api/authenticator';
|
import { login } from '../../api/authenticator';
|
||||||
import token from "../../api/tokenManager";
|
import { setToken } from "../../api/tokenManager";
|
||||||
import { getLoginMessageFromError } from '../../common/util/Errors'
|
import { getLoginMessageFromError } from '../../common/util/errors'
|
||||||
|
|
||||||
export default function Login() {
|
export default function Login() {
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
|
@ -42,8 +42,8 @@ export default function Login() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
token.setToken(json.token);
|
setToken(json.token);
|
||||||
await Authenticator.login();
|
await login();
|
||||||
|
|
||||||
history.push('/');
|
history.push('/');
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
|
import { useHistory } from 'react-router-dom';
|
||||||
|
|
||||||
import ChannelProfile from './ChannelProfileLink';
|
import ChannelProfile from './ChannelProfileLink';
|
||||||
import gatewayConnection from '../../api/gateway/globalGatewayConnection';
|
import gatewayConnection from '../../api/gateway/globalGatewayConnection';
|
||||||
|
|
||||||
import { useHistory } from 'react-router-dom';
|
|
||||||
|
|
||||||
export default function ChannelButton({ channel, selected }) {
|
export default function ChannelButton({ channel, selected }) {
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
|
import { connect } from 'react-redux'
|
||||||
|
|
||||||
import ChannelListLoader from './ChannelListLoader';
|
import ChannelListLoader from './ChannelListLoader';
|
||||||
import ChannelButton from './ChannelButton';
|
import ChannelButton from './ChannelButton';
|
||||||
|
|
||||||
import { connect } from 'react-redux'
|
|
||||||
|
|
||||||
function ChannelList({ selectedChannelId, channels }) {
|
function ChannelList({ selectedChannelId, channels }) {
|
||||||
if (!channels) {
|
if (!channels) {
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -1,21 +1,51 @@
|
||||||
import Message from "../Message";
|
import { useRef, useEffect, useState } from 'react';
|
||||||
import { useRef, useEffect } from 'react';
|
import { useDispatch } from "react-redux";
|
||||||
|
|
||||||
export default function ChannelMessageView({messages}) {
|
import { authenticated } from "../../api/request";
|
||||||
|
import Message from "../Message";
|
||||||
|
|
||||||
|
export default function ChannelMessageView({ messages, channelId }) {
|
||||||
const invisibleBottomMessageRef = useRef();
|
const invisibleBottomMessageRef = useRef();
|
||||||
|
|
||||||
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
const scroller = useRef();
|
||||||
|
|
||||||
|
const loadOlderMessages = () => {
|
||||||
|
if (isLoading) return;
|
||||||
|
if (!channelId) return;
|
||||||
|
setIsLoading(true);
|
||||||
|
|
||||||
|
const request = messages[0] ? `/api/v1/content/channel/${channelId}/messages?before=${messages[0]._id}` : `/api/v1/content/channel/${channelId}/messages`;
|
||||||
|
|
||||||
|
authenticated(request)
|
||||||
|
.then((res) => {
|
||||||
|
if (res.json.channelMessages)
|
||||||
|
dispatch({
|
||||||
|
type: "messagestore/addmessagesback",
|
||||||
|
messages: res.json.channelMessages.reverse(),
|
||||||
|
channelId
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
setIsLoading(false);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const onScroll = () => {
|
||||||
|
if (scroller.current.scrollTop === 0) {
|
||||||
|
loadOlderMessages();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(loadOlderMessages, [channelId, dispatch]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
invisibleBottomMessageRef.current.scrollIntoView(true);
|
invisibleBottomMessageRef.current.scrollIntoView(true);
|
||||||
}, [messages]);
|
}, [messages]);
|
||||||
|
|
||||||
let messagesView = messages.map((message) => (<Message key={message._id} message={message} />));
|
return <div className="message-list" id="message-list" ref={ scroller } onScroll={ onScroll }>
|
||||||
if (messagesView === undefined || messagesView.length <= 0)
|
{messages.map(message => <Message message={message} key={message._id} />)}
|
||||||
messagesView = (<div className='no-messages-warning'>
|
|
||||||
<span style={{ margin: "12px" }}>No messages yet...</span>
|
|
||||||
</div>);
|
|
||||||
|
|
||||||
return <div className="message-list">
|
|
||||||
{ messagesView }
|
|
||||||
<div className="messages-scroll-div" ref={ invisibleBottomMessageRef }></div>
|
<div className="messages-scroll-div" ref={ invisibleBottomMessageRef }></div>
|
||||||
</div>;
|
</div>;
|
||||||
}
|
}
|
|
@ -1,10 +1,10 @@
|
||||||
|
import { connect, useDispatch } from 'react-redux';
|
||||||
|
import { useState, useRef, useEffect } from 'react';
|
||||||
|
|
||||||
import ChannelProfile from './ChannelProfileLink';
|
import ChannelProfile from './ChannelProfileLink';
|
||||||
import gatewayConnection from '../../api/gateway/globalGatewayConnection';
|
import gatewayConnection from '../../api/gateway/globalGatewayConnection';
|
||||||
import ChannelUserList from "./ChannelUserList";
|
import ChannelUserList from "./ChannelUserList";
|
||||||
import ProfileLinkLoader from "../ProfileLinkLoader";
|
import ProfileLinkLoader from "../ProfileLinkLoader";
|
||||||
|
|
||||||
import { connect, useDispatch } from 'react-redux';
|
|
||||||
import { useState, useRef, useEffect } from 'react';
|
|
||||||
import ChannelMessageView from './ChannelMessageView';
|
import ChannelMessageView from './ChannelMessageView';
|
||||||
|
|
||||||
const ChannelView = ({ messages, channel, channelPresenceClientList }) => {
|
const ChannelView = ({ messages, channel, channelPresenceClientList }) => {
|
||||||
|
@ -41,7 +41,7 @@ const ChannelView = ({ messages, channel, channelPresenceClientList }) => {
|
||||||
|
|
||||||
<div className="row-flex hidden-overflow">
|
<div className="row-flex hidden-overflow">
|
||||||
<div className="channel-message-panel">
|
<div className="channel-message-panel">
|
||||||
<ChannelMessageView messages={messages}></ChannelMessageView>
|
<ChannelMessageView messages={messages} channelId={channel._id}></ChannelMessageView>
|
||||||
<div className="col-flex">
|
<div className="col-flex">
|
||||||
<input className="text-input message-input" type="text" placeholder="Go on, type something interesting!" ref={ textInputRef } onKeyDown={ handleTextboxKeydown } onChange={ ({ target }) => setTextInput(target.value) }></input>
|
<input className="text-input message-input" type="text" placeholder="Go on, type something interesting!" ref={ textInputRef } onKeyDown={ handleTextboxKeydown } onChange={ ({ target }) => setTextInput(target.value) }></input>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -2,12 +2,12 @@ import { useEffect, useState } from 'react';
|
||||||
import { connect } from 'react-redux'
|
import { connect } from 'react-redux'
|
||||||
import { BrowserRouter, Switch, Route } from 'react-router-dom';
|
import { BrowserRouter, Switch, Route } from 'react-router-dom';
|
||||||
|
|
||||||
|
import './../../styles/App.scss';
|
||||||
import Login from '../auth/Login';
|
import Login from '../auth/Login';
|
||||||
import Create from '../auth/Create';
|
import Create from '../auth/Create';
|
||||||
import Root from '../main/Root';
|
import Root from '../main/Root';
|
||||||
import Authenticator from '../../api/authenticator';
|
import { login } from '../../api/authenticator';
|
||||||
import Notification from '../Notification';
|
import Notification from '../Notification';
|
||||||
import './../../styles/App.scss';
|
|
||||||
import LoggedInMount from './LoggedInMount';
|
import LoggedInMount from './LoggedInMount';
|
||||||
import FullMessage from '../FullMessage';
|
import FullMessage from '../FullMessage';
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@ function App({ user, fullscreenMessage }) {
|
||||||
const [ hasError ] = useState(false);
|
const [ hasError ] = useState(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
Authenticator.login();
|
login();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
if (user === null && !hasError) {
|
if (user === null && !hasError) {
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
|
import { connect } from "react-redux";
|
||||||
import { useParams } from "react-router-dom";
|
import { useParams } from "react-router-dom";
|
||||||
|
|
||||||
import Sidebar from "../Sidebar";
|
import Sidebar from "../Sidebar";
|
||||||
import ChannelView from "../channel/ChannelView";
|
import ChannelView from "../channel/ChannelView";
|
||||||
import GradientBanner from "../GradientBanner";
|
import GradientBanner from "../GradientBanner";
|
||||||
import UserView from "../user/UserView";
|
import UserView from "../user/UserView";
|
||||||
import { connect } from "react-redux";
|
|
||||||
|
|
||||||
function LoggedInMount({ gradientBannerNotificationText }) {
|
function LoggedInMount({ gradientBannerNotificationText }) {
|
||||||
const { channelId, userId } = useParams();
|
const { channelId, userId } = useParams();
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import APIRequest from "../../api/request";
|
import { authenticated } from "../../api/request";
|
||||||
import UserProfile from "./UserProfileLink";
|
import UserProfile from "./UserProfileLink";
|
||||||
import ProfileLinkLoader from "../ProfileLinkLoader";
|
import ProfileLinkLoader from "../ProfileLinkLoader";
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ export default function UserView({ userId }) {
|
||||||
const [userObject, setUserObject] = useState(null);
|
const [userObject, setUserObject] = useState(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
APIRequest.authenticated(`/api/v1/users/user/${userId}/info`, {
|
authenticated(`/api/v1/users/user/${userId}/info`, {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
headers: {
|
headers: {
|
||||||
"Accept": "application/json"
|
"Accept": "application/json"
|
||||||
|
@ -23,8 +23,8 @@ export default function UserView({ userId }) {
|
||||||
if (userObject) {
|
if (userObject) {
|
||||||
view = <>
|
view = <>
|
||||||
<UserProfile user={ userObject } size="32" />
|
<UserProfile user={ userObject } size="32" />
|
||||||
{(userObject.role === "ADMIN") && <span>Admin</span>}
|
{(userObject.role === "ADMIN") && <span style={{ padding: "12px" }}>Admin</span>}
|
||||||
{(userObject.role === "USER") && <span>User</span>}
|
{(userObject.role === "USER") && <span style={{ padding: "12px" }}>User</span>}
|
||||||
</>
|
</>
|
||||||
} else {
|
} else {
|
||||||
view = <>
|
view = <>
|
||||||
|
|
|
@ -69,7 +69,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.profile-username {
|
.profile-username {
|
||||||
font-weight: 500;
|
font-weight: 600;
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
line-height: 1.256rem;
|
line-height: 1.256rem;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue