login page is displayed now

This commit is contained in:
or-else
2018-10-25 14:02:53 +03:00
parent 358f9eb970
commit e139c1371e
15 changed files with 251 additions and 164 deletions
+1 -28
View File
@@ -28,38 +28,11 @@
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet" /> <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet" />
<!-- Styles for local elements --> <!-- Styles for local elements -->
<link rel="stylesheet" href="css/base.css" /> <link rel="stylesheet" href="css/base.css" />
<!-- ReactJs scripts -->
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<script crossorigin src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<!-- Localization support -->
<script crossorigin src="https://unpkg.com/prop-types@15/prop-types.js"></script>
<script crossorigin src="https://unpkg.com/react-intl@2/dist/react-intl.js"></script>
<script>
// Extract react-intl objects
var {IntlProvider, FormattedMessage} = ReactIntl;
</script>
<!-- Firebase push notifications. -->
<script crossorigin src="https://unpkg.com/firebase@5.5.5/firebase-app.js"></script>
<script crossorigin src="https://unpkg.com/firebase@5.5.5/firebase-messaging.js"></script>
</head> </head>
<body> <body>
<div id="mountPoint"></div> <div id="mountPoint"></div>
<!-- core tinode libraries -->
<script src="src/drafty.js"></script>
<script src="src/tinode.js"></script>
<!-- the application --> <!-- the application -->
<script src="/firebase-init.js"></script> <script src="umd/index.dev.js"></script>
<script type="text/babel" src="src/index.js"></script>
<!--script type="text/babel">
ReactDOM.render(
<IntlProvider
locale={navigator.language}>
<TinodeWeb />
</IntlProvider>,
document.getElementById('mountPoint')
);
</script-->
</body> </body>
</html> </html>
+3 -3
View File
@@ -22,9 +22,9 @@
"build:prod": "browserify ./src/index.js --standalone Webapp | uglifyjs --compress --mangle > ./umd/index.prod.js", "build:prod": "browserify ./src/index.js --standalone Webapp | uglifyjs --compress --mangle > ./umd/index.prod.js",
"build:dev": "browserify ./src/index.js --standalone Webapp > ./umd/index.dev.js", "build:dev": "browserify ./src/index.js --standalone Webapp > ./umd/index.dev.js",
"build:css": "postcss css/base.css > css/base.min.css", "build:css": "postcss css/base.css > css/base.min.css",
"wp-build:dev": "webpack --mode development --output ./umd/index.dev.js", "wp-build:dev": "webpack --mode development --output-library-target umd --output ./umd/index.dev.js",
"wp-build:prod": "webpack --mode production --output ./umd/index.prod.js", "wp-build:prod": "webpack --mode production --output-library-target umd --output ./umd/index.prod.js",
"vers": "echo \"{\\\"version\\\": \\\"`node -p -e \"require('./package.json').version\"`\\\"}\" > version.json" "vers": "echo \"export const PACKAGE_VERSION = \\\"`node -p -e \"require('./package.json').version\"`\\\";\" > src/version.js"
}, },
"files": [ "files": [
"src/index.js", "src/index.js",
+1 -1
View File
@@ -1,7 +1,7 @@
// Must be located at the root. // Must be located at the root.
importScripts("https://unpkg.com/firebase@5.5.5/firebase-app.js"); importScripts("https://unpkg.com/firebase@5.5.5/firebase-app.js");
importScripts("https://unpkg.com/firebase@5.5.5/firebase-messaging.js"); importScripts("https://unpkg.com/firebase@5.5.5/firebase-messaging.js");
importScripts("/firebase-init.js") importScripts("/src/firebase-init.js")
firebase.initializeApp(FIREBASE_INIT); firebase.initializeApp(FIREBASE_INIT);
+3 -1
View File
@@ -1,5 +1,7 @@
import { PACKAGE_VERSION } from './version.js';
// Name of this application, used in the User-Agent. // Name of this application, used in the User-Agent.
export const APP_NAME = 'TinodeWeb/' + (package_version || '0.15'); export const APP_NAME = 'TinodeWeb/' + (PACKAGE_VERSION || '0.15');
// API key. Use https://github.com/tinode/chat/tree/master/keygen to generate your own // API key. Use https://github.com/tinode/chat/tree/master/keygen to generate your own
export const API_KEY = 'AQEAAAABAAD_rAp4DJh05a1HAwFT3A6K'; export const API_KEY = 'AQEAAAABAAD_rAp4DJh05a1HAwFT3A6K';
+6 -1
View File
@@ -3,9 +3,14 @@
import React from 'react'; import React from 'react';
import ReactDOM from 'react-dom'; import ReactDOM from 'react-dom';
import { IntlProvider } from 'react-intl';
import TinodeWeb from './views/tinode-web.jsx'; import TinodeWeb from './views/tinode-web.jsx';
ReactDOM.render( ReactDOM.render(
React.createElement(TinodeWeb, null), <IntlProvider
locale={navigator.language}>
<TinodeWeb />
</IntlProvider>,
document.getElementById('mountPoint') document.getElementById('mountPoint')
); );
+4 -4
View File
@@ -1,7 +1,7 @@
import {KNOWN_HOSTS, DEFAULT_HOST} from '../config.js'; import { KNOWN_HOSTS, DEFAULT_HOST } from '../config.js';
// Detect server address from the URL // Detect server address from the URL
function detectServerAddress() { export function detectServerAddress() {
let host = DEFAULT_HOST; let host = DEFAULT_HOST;
if (typeof window.location == 'object') { if (typeof window.location == 'object') {
if (window.location.protocol == 'file:' || window.location.hostname == 'localhost') { if (window.location.protocol == 'file:' || window.location.hostname == 'localhost') {
@@ -14,14 +14,14 @@ function detectServerAddress() {
} }
// Detect if the page is served over HTTPS. // Detect if the page is served over HTTPS.
function isSecureConnection() { export function isSecureConnection() {
if (typeof window.location == 'object') { if (typeof window.location == 'object') {
return window.location.protocol == 'https:'; return window.location.protocol == 'https:';
} }
return false; return false;
} }
function isLocalHost() { export function isLocalHost() {
if (typeof window.location == 'object') { if (typeof window.location == 'object') {
return window.location.hostname == 'localhost'; return window.location.hostname == 'localhost';
} }
+21
View File
@@ -0,0 +1,21 @@
// Helper functions for storing values in localStorage.
// By default localStorage can store only strings, not objects or other types.
export default class LocalStorageUtil {
// Replace old object with the new one.
static setObject(key, value) {
localStorage.setItem(key, JSON.stringify(value));
}
// Get stored object.
static getObject(key) {
let value = localStorage.getItem(key);
return value && JSON.parse(value);
}
// Partially or wholly update stored object.
static updateObject(key, value) {
let oldVal = localStorage.getObject(key);
localStorage.setObject(key, Object.assign(oldVal || {}, value));
}
}
+57 -56
View File
@@ -1,67 +1,68 @@
// Helper functions for hash navigation. // Utility class for hash navigation.
// Parse hash as in http://www.example.com/path#hash as if it were // Parse hash as in http://www.example.com/path#hash as if it were
// path and arguments. // path and arguments.
export function parseUrlHash(hash) { export default class HashNavigation {
// Split path from args, path -> parts[0], args->path[1] static parseUrlHash(hash) {
let parts = hash.split('?', 2); // Split path from args, path -> parts[0], args->path[1]
let params = {}; let parts = hash.split('?', 2);
let path = []; let params = {};
if (parts[0]) { let path = [];
path = parts[0].substr(1).split('/'); if (parts[0]) {
} path = parts[0].substr(1).split('/');
if (parts[1]) {
parts[1].split('&').forEach(function(part) {
let item = part.split('=');
if (item[0]) {
params[decodeURIComponent(item[0])] = decodeURIComponent(item[1]);
}
});
}
return {path: path, params: params};
}
export function navigateTo(url) {
window.location.hash = url;
}
export function composeUrlHash(path, params) {
var url = path.join('/');
var args = [];
for (var key in params) {
if (params.hasOwnProperty(key)) {
args.push(key + '=' + params[key]);
} }
if (parts[1]) {
parts[1].split('&').forEach(function(part) {
let item = part.split('=');
if (item[0]) {
params[decodeURIComponent(item[0])] = decodeURIComponent(item[1]);
}
});
}
return {path: path, params: params};
} }
if (args.length > 0) {
url += '?' + args.join('&'); static navigateTo(url) {
window.location.hash = url;
} }
return url;
}
export function addUrlParam(hash, key, value) { static composeUrlHash(path, params) {
var parsed = parseUrlHash(hash); var url = path.join('/');
parsed.params[key] = value; var args = [];
return composeUrlHash(parsed.path, parsed.params); for (var key in params) {
} if (params.hasOwnProperty(key)) {
args.push(key + '=' + params[key]);
}
}
if (args.length > 0) {
url += '?' + args.join('&');
}
return url;
}
export function removeUrlParam(hash, key) { static addUrlParam(hash, key, value) {
var parsed = parseUrlHash(hash); var parsed = parseUrlHash(hash);
delete parsed.params[key]; parsed.params[key] = value;
return composeUrlHash(parsed.path, parsed.params); return composeUrlHash(parsed.path, parsed.params);
} }
export function setUrlSidePanel(hash, sidepanel) { static removeUrlParam(hash, key) {
var parsed = parseUrlHash(hash); var parsed = parseUrlHash(hash);
parsed.path[0] = sidepanel; delete parsed.params[key];
return composeUrlHash(parsed.path, parsed.params); return composeUrlHash(parsed.path, parsed.params);
} }
export function setUrlTopic(hash, topic) { static setUrlSidePanel(hash, sidepanel) {
var parsed = parseUrlHash(hash); var parsed = parseUrlHash(hash);
parsed.path[1] = topic; parsed.path[0] = sidepanel;
// Close InfoView on topic change. return composeUrlHash(parsed.path, parsed.params);
delete parsed.params.info; }
return composeUrlHash(parsed.path, parsed.params);
static setUrlTopic(hash, topic) {
var parsed = parseUrlHash(hash);
parsed.path[1] = topic;
// Close InfoView on topic change.
delete parsed.params.info;
return composeUrlHash(parsed.path, parsed.params);
}
} }
// END of hash navigation helper functions
+3 -3
View File
@@ -1,5 +1,5 @@
// Short representation of time in the past. // Short representation of time in the past.
function shortDateFormat(then) { export function shortDateFormat(then) {
var locale = window.navigator.userLanguage || window.navigator.language; var locale = window.navigator.userLanguage || window.navigator.language;
var now = new Date(); var now = new Date();
if (then.getFullYear() == now.getFullYear()) { if (then.getFullYear() == now.getFullYear()) {
@@ -15,7 +15,7 @@ function shortDateFormat(then) {
} }
// Convert a number of bytes to human-readable format. // Convert a number of bytes to human-readable format.
function bytesToHumanSize(bytes) { export function bytesToHumanSize(bytes) {
if (!bytes || bytes == 0) { if (!bytes || bytes == 0) {
return '0 Bytes'; return '0 Bytes';
} }
@@ -29,7 +29,7 @@ function bytesToHumanSize(bytes) {
// Get 32 bit integer hash value for a string. Ideally it should produce the same value // Get 32 bit integer hash value for a string. Ideally it should produce the same value
// as Java's String#hash(). // as Java's String#hash().
function stringHash(value) { export function stringHash(value) {
var hash = 0; var hash = 0;
value = '' + value; value = '' + value;
for (var i = 0; i < value.length; i++) { for (var i = 0; i < value.length; i++) {
+5 -3
View File
@@ -1,11 +1,13 @@
// Login form // Login form
import React from 'react'; import React from 'react';
import {FormattedMessage} from 'react-intl'; import { FormattedMessage } from 'react-intl';
import CheckBox from '../widgets/checkbox.jsx'; import CheckBox from '../widgets/checkbox.jsx';
import VisiblePassword from '../widgets/visible-password.jsx'; import VisiblePassword from '../widgets/visible-password.jsx';
import LocalStorageUtil from '../lib/local-storage.js';
export default class LoginView extends React.Component { export default class LoginView extends React.Component {
constructor(props) { constructor(props) {
super(props); super(props);
@@ -14,7 +16,7 @@ export default class LoginView extends React.Component {
login: props.login, login: props.login,
password: '', password: '',
hostName: props.serverAddress, hostName: props.serverAddress,
saveToken: localStorage.getObject('keep-logged-in') saveToken: LocalStorageUtil.getObject('keep-logged-in')
}; };
this.handleLoginChange = this.handleLoginChange.bind(this); this.handleLoginChange = this.handleLoginChange.bind(this);
this.handlePasswordChange = this.handlePasswordChange.bind(this); this.handlePasswordChange = this.handlePasswordChange.bind(this);
@@ -31,7 +33,7 @@ export default class LoginView extends React.Component {
} }
handleToggleSaveToken() { handleToggleSaveToken() {
localStorage.setObject('keep-logged-in', !this.state.saveToken); LocalStorageUtil.setObject('keep-logged-in', !this.state.saveToken);
this.setState({saveToken: !this.state.saveToken}); this.setState({saveToken: !this.state.saveToken});
} }
+4 -1
View File
@@ -1,7 +1,10 @@
/* This is just a static page to display when no conversation is selected. */ /* This is just a static page to display when no conversation is selected. */
import React from 'react'; import React from 'react';
import Tinode from 'tinode-sdk';
import { APP_NAME } from '../config.js';
export default class LogoView extends React.PureComponent { export default class LogoView extends React.PureComponent {
render() { render() {
var version = APP_NAME + ' (' + Tinode.getLibrary() + ')'; var version = APP_NAME + ' (' + Tinode.getLibrary() + ')';
-1
View File
@@ -1,5 +1,4 @@
/* A password reset form */ /* A password reset form */
import React from 'react'; import React from 'react';
import VisiblePassword from '../widgets/visible-password.jsx'; import VisiblePassword from '../widgets/visible-password.jsx';
+54 -44
View File
@@ -3,7 +3,9 @@ import React from 'react';
import 'firebase/app'; import 'firebase/app';
import 'firebase/messaging'; import 'firebase/messaging';
import { FIREBASE_INIT } from '../../firebase-init.js' import { FIREBASE_INIT } from '../firebase-init.js'
import Tinode from 'tinode-sdk';
import ContextMenu from '../widgets/context-menu.jsx'; import ContextMenu from '../widgets/context-menu.jsx';
@@ -11,6 +13,11 @@ import InfoView from './info-view.jsx';
import MessagesView from './messages-view.jsx'; import MessagesView from './messages-view.jsx';
import SidepanelView from './sidepanel-view.jsx'; import SidepanelView from './sidepanel-view.jsx';
import { API_KEY, APP_NAME, MEDIA_BREAKPOINT, RECEIVED_DELAY } from '../config.js';
import { isLocalHost, isSecureConnection } from '../lib/host-name.js';
import LocalStorageUtil from '../lib/local-storage.js';
import HashNavigation from '../lib/navigation.js';
// Sound to play on message received. // Sound to play on message received.
export const POP_SOUND = new Audio('audio/msg.mp3'); export const POP_SOUND = new Audio('audio/msg.mp3');
@@ -76,7 +83,7 @@ export default class TinodeWeb extends React.Component {
} }
getBlankState() { getBlankState() {
let settings = localStorage.getObject("settings") || {}; let settings = LocalStorageUtil.getObject("settings") || {};
return { return {
connected: false, connected: false,
@@ -89,7 +96,7 @@ export default class TinodeWeb extends React.Component {
desktopAlertsEnabled: (isSecureConnection() || isLocalHost()) && desktopAlertsEnabled: (isSecureConnection() || isLocalHost()) &&
(typeof firebase != 'undefined') && (typeof navigator != 'undefined') && (typeof firebase != 'undefined') && (typeof navigator != 'undefined') &&
(typeof FIREBASE_INIT != 'undefined'), (typeof FIREBASE_INIT != 'undefined'),
firebaseToken: localStorage.getObject("firebase-token"), firebaseToken: LocalStorageUtil.getObject("firebase-token"),
errorText: '', errorText: '',
errorLevel: null, errorLevel: null,
@@ -169,10 +176,10 @@ export default class TinodeWeb extends React.Component {
} }
} }
let token = localStorage.getObject('keep-logged-in') ? let token = LocalStorageUtil.getObject('keep-logged-in') ?
localStorage.getObject('auth-token') : undefined; LocalStorageUtil.getObject('auth-token') : undefined;
let parsedNav = parseUrlHash(window.location.hash); let parsedNav = HashNavigation.parseUrlHash(window.location.hash);
if (token) { if (token) {
// When reading from storage, date is returned as string. // When reading from storage, date is returned as string.
token.expires = new Date(token.expires); token.expires = new Date(token.expires);
@@ -184,9 +191,9 @@ export default class TinodeWeb extends React.Component {
delete parsedNav.params.info; delete parsedNav.params.info;
delete parsedNav.params.tab; delete parsedNav.params.tab;
parsedNav.path[0] = ''; parsedNav.path[0] = '';
navigateTo(composeUrlHash(parsedNav.path, parsedNav.params)); HashNavigation.navigateTo(HashNavigation.composeUrlHash(parsedNav.path, parsedNav.params));
} else if (!parsedNav.params.token) { } else if (!parsedNav.params.token) {
navigateTo(''); HashNavigation.navigateTo('');
} }
this.readTimer = null; this.readTimer = null;
@@ -218,7 +225,7 @@ export default class TinodeWeb extends React.Component {
// Handle for hashchange event: display appropriate panels. // Handle for hashchange event: display appropriate panels.
handleHashRoute() { handleHashRoute() {
var hash = parseUrlHash(window.location.hash); var hash = HashNavigation.parseUrlHash(window.location.hash);
if (hash.path && hash.path.length > 0) { if (hash.path && hash.path.length > 0) {
// Left-side panel selector. // Left-side panel selector.
if (['register','settings','edit','cred','reset','newtpk','contacts',''].includes(hash.path[0])) { if (['register','settings','edit','cred','reset','newtpk','contacts',''].includes(hash.path[0])) {
@@ -315,7 +322,7 @@ export default class TinodeWeb extends React.Component {
doLogin(login, password, cred) { doLogin(login, password, cred) {
if (this.tinode.isAuthenticated()) { if (this.tinode.isAuthenticated()) {
// Already logged in. Go to default screen. // Already logged in. Go to default screen.
navigateTo(""); HashNavigation.navigateTo('');
return; return;
} }
// Sanitize and package credentail. // Sanitize and package credentail.
@@ -344,30 +351,30 @@ export default class TinodeWeb extends React.Component {
// Login failed, report error. // Login failed, report error.
this.setState({loginDisabled: false, credMethod: undefined, credCode: undefined}); this.setState({loginDisabled: false, credMethod: undefined, credCode: undefined});
this.handleError(err.message, 'err'); this.handleError(err.message, 'err');
localStorage.removeItem('auth-token'); LocalStorageUtil.removeItem('auth-token');
navigateTo(''); HashNavigation.navigateTo('');
}); });
} else { } else {
// No login credentials provided. // No login credentials provided.
// Make sure we are on the login page. // Make sure we are on the login page.
navigateTo(''); HashNavigation.navigateTo('');
this.setState({loginDisabled: false}); this.setState({loginDisabled: false});
} }
} }
handleCredentialsRequest(params) { handleCredentialsRequest(params) {
var parsed = parseUrlHash(window.location.hash); var parsed = HashNavigation.parseUrlHash(window.location.hash);
parsed.path[0] = 'cred'; parsed.path[0] = 'cred';
parsed.params['method'] = params.cred[0]; parsed.params['method'] = params.cred[0];
navigateTo(composeUrlHash(parsed.path, parsed.params)); HashNavigation.navigateTo(HashNavigation.composeUrlHash(parsed.path, parsed.params));
} }
handleLoginSuccessful() { handleLoginSuccessful() {
this.handleError('', null); this.handleError('', null);
// Refresh authentication token. // Refresh authentication token.
if (localStorage.getObject('keep-logged-in')) { if (LocalStorageUtil.getObject('keep-logged-in')) {
localStorage.setObject('auth-token', this.tinode.getAuthToken()); LocalStorageUtil.setObject('auth-token', this.tinode.getAuthToken());
} }
// Logged in fine, subscribe to 'me' attaching callbacks from the contacts view. // Logged in fine, subscribe to 'me' attaching callbacks from the contacts view.
var me = this.tinode.getMeTopic(); var me = this.tinode.getMeTopic();
@@ -387,11 +394,11 @@ export default class TinodeWeb extends React.Component {
withDesc(). withDesc().
build() build()
).catch((err) => { ).catch((err) => {
localStorage.removeItem('auth-token'); LocalStorageUtil.removeItem('auth-token');
this.handleError(err.message, 'err'); this.handleError(err.message, 'err');
navigateTo(''); HashNavigation.navigateTo('');
}); });
navigateTo(setUrlSidePanel(window.location.hash, 'contacts')); HashNavigation.navigateTo(HashNavigation.setUrlSidePanel(window.location.hash, 'contacts'));
} }
handleDisconnect(err) { handleDisconnect(err) {
@@ -575,7 +582,7 @@ export default class TinodeWeb extends React.Component {
topicSelectedOnline: online, topicSelectedOnline: online,
topicSelectedAcs: acs topicSelectedAcs: acs
}); });
navigateTo(setUrlTopic('', topicName)); HashNavigation.navigateTo(HashNavigation.setUrlTopic('', topicName));
} }
} else { } else {
// Currently selected contact deleted // Currently selected contact deleted
@@ -588,7 +595,7 @@ export default class TinodeWeb extends React.Component {
showInfoPanel: false showInfoPanel: false
}); });
if (this.state.topicSelected) { if (this.state.topicSelected) {
navigateTo(setUrlTopic('', null)); HashNavigation.navigateTo(HashNavigation.setUrlTopic('', null));
} }
} }
} }
@@ -598,7 +605,7 @@ export default class TinodeWeb extends React.Component {
this.setState({ this.setState({
mobilePanel: 'sidepanel' mobilePanel: 'sidepanel'
}); });
navigateTo(setUrlTopic(window.location.hash, null)); HashNavigation.navigateTo(HashNavigation.setUrlTopic(window.location.hash, null));
} }
// User is sending a message, either plain text or a drafty object, possibly // User is sending a message, either plain text or a drafty object, possibly
@@ -631,7 +638,7 @@ export default class TinodeWeb extends React.Component {
// User chose a Sign Up menu item. // User chose a Sign Up menu item.
handleNewAccount() { handleNewAccount() {
navigateTo(setUrlSidePanel(window.location.hash, 'register')); HashNavigation.navigateTo(HashNavigation.setUrlSidePanel(window.location.hash, 'register'));
} }
// Actual registration of a new account. // Actual registration of a new account.
@@ -673,7 +680,8 @@ export default class TinodeWeb extends React.Component {
// User chose Settings menu item. // User chose Settings menu item.
handleSettings() { handleSettings() {
navigateTo(setUrlSidePanel(window.location.hash, this.state.myUserId ? 'edit' : 'settings')); HashNavigation.navigateTo(HashNavigation.setUrlSidePanel(window.location.hash,
this.state.myUserId ? 'edit' : 'settings'));
} }
// User updated global parameters. // User updated global parameters.
@@ -692,12 +700,12 @@ export default class TinodeWeb extends React.Component {
serverAddress: serverAddress, serverAddress: serverAddress,
transport: transport transport: transport
}); });
localStorage.setObject('settings', { LocalStorageUtil.setObject('settings', {
serverAddress: serverAddress, serverAddress: serverAddress,
transport: transport transport: transport
}); });
navigateTo(setUrlSidePanel(window.location.hash, '')); HashNavigation.navigateTo(HashNavigation.setUrlSidePanel(window.location.hash, ''));
} }
// Initialize desktop alerts = push notifications. // Initialize desktop alerts = push notifications.
@@ -722,24 +730,24 @@ export default class TinodeWeb extends React.Component {
}).catch((err) => { }).catch((err) => {
this.handleError(err.message, 'err'); this.handleError(err.message, 'err');
this.setState({desktopAlerts: false, firebaseToken: null}); this.setState({desktopAlerts: false, firebaseToken: null});
localStorage.updateObject('settings', {desktopAlerts: false}); LocalStorageUtil.updateObject('settings', {desktopAlerts: false});
console.log("Failed to get permission to notify.", err); console.log("Failed to get permission to notify.", err);
}); });
} else { } else {
this.setState({desktopAlerts: true}); this.setState({desktopAlerts: true});
localStorage.updateObject('settings', {desktopAlerts: true}); LocalStorageUtil.updateObject('settings', {desktopAlerts: true});
} }
} else if (this.state.firebaseToken) { } else if (this.state.firebaseToken) {
this.fbPush.deleteToken(this.state.firebaseToken).catch((err) => { this.fbPush.deleteToken(this.state.firebaseToken).catch((err) => {
console.log("Unable to delete token.", err); console.log("Unable to delete token.", err);
}).finally(() => { }).finally(() => {
localStorage.updateObject('settings', {desktopAlerts: false}); LocalStorageUtil.updateObject('settings', {desktopAlerts: false});
localStorage.removeItem('firebase-token'); LocalStorageUtil.removeItem('firebase-token');
this.setState({desktopAlerts: false, firebaseToken: null}); this.setState({desktopAlerts: false, firebaseToken: null});
}); });
} else { } else {
this.setState({desktopAlerts: false, firebaseToken: null}); this.setState({desktopAlerts: false, firebaseToken: null});
localStorage.updateObject('settings', {desktopAlerts: false}); LocalStorageUtil.updateObject('settings', {desktopAlerts: false});
} }
} }
@@ -747,10 +755,10 @@ export default class TinodeWeb extends React.Component {
this.fbPush.getToken().then((refreshedToken) => { this.fbPush.getToken().then((refreshedToken) => {
if (refreshedToken != this.state.firebaseToken) { if (refreshedToken != this.state.firebaseToken) {
this.tinode.setDeviceToken(refreshedToken, sendToServer); this.tinode.setDeviceToken(refreshedToken, sendToServer);
localStorage.setObject('firebase-token', refreshedToken); LocalStorageUtil.setObject('firebase-token', refreshedToken);
} }
this.setState({firebaseToken: refreshedToken, desktopAlerts: true}); this.setState({firebaseToken: refreshedToken, desktopAlerts: true});
localStorage.updateObject('settings', {desktopAlerts: true}); LocalStorageUtil.updateObject('settings', {desktopAlerts: true});
}).catch((err) => { }).catch((err) => {
this.handleError(err.message, 'err'); this.handleError(err.message, 'err');
console.log("Failed to retrieve firebase token", err); console.log("Failed to retrieve firebase token", err);
@@ -759,27 +767,27 @@ export default class TinodeWeb extends React.Component {
handleToggleMessageSounds(enabled) { handleToggleMessageSounds(enabled) {
this.setState({messageSounds: enabled}); this.setState({messageSounds: enabled});
localStorage.updateObject('settings', { LocalStorageUtil.updateObject('settings', {
messageSoundsOff: !enabled messageSoundsOff: !enabled
}); });
} }
// User clicked Cancel button in Setting or Sign Up panel. // User clicked Cancel button in Setting or Sign Up panel.
handleSidepanelCancel() { handleSidepanelCancel() {
var parsed = parseUrlHash(window.location.hash); var parsed = HashNavigation.parseUrlHash(window.location.hash);
parsed.path[0] = this.state.myUserId ? 'contacts' : ''; parsed.path[0] = this.state.myUserId ? 'contacts' : '';
if (parsed.params) { if (parsed.params) {
delete parsed.params.code; delete parsed.params.code;
delete parsed.params.method; delete parsed.params.method;
delete parsed.params.tab; delete parsed.params.tab;
} }
navigateTo(composeUrlHash(parsed.path, parsed.params)); HashNavigation.navigateTo(HashNavigation.composeUrlHash(parsed.path, parsed.params));
this.setState({errorText: '', errorLevel: null}); this.setState({errorText: '', errorLevel: null});
} }
// User clicked a (+) menu item. // User clicked a (+) menu item.
handleNewTopic() { handleNewTopic() {
navigateTo(setUrlSidePanel(window.location.hash, 'newtpk')); HashNavigation.navigateTo(HashNavigation.setUrlSidePanel(window.location.hash, 'newtpk'));
} }
// Request to start a new topic. New P2P topic requires peer's name. // Request to start a new topic. New P2P topic requires peer's name.
@@ -801,7 +809,9 @@ export default class TinodeWeb extends React.Component {
// If the current URl contains the old topic name, replace it with new. // If the current URl contains the old topic name, replace it with new.
// Update the name of the selected topic first so the navigator doen't clear // Update the name of the selected topic first so the navigator doen't clear
// the state. // the state.
this.setState({topicSelected: newName}, () => { navigateTo(setUrlTopic('', newName)); }); this.setState({topicSelected: newName}, () => {
HashNavigation.navigateTo(HashNavigation.setUrlTopic('', newName));
});
} }
} }
@@ -853,7 +863,7 @@ export default class TinodeWeb extends React.Component {
handleLogout() { handleLogout() {
updateFavicon(0); updateFavicon(0);
localStorage.removeItem('auth-token'); LocalStorageUtil.removeItem('auth-token');
if (this.tinode) { if (this.tinode) {
this.tinode.onDisconnect = undefined; this.tinode.onDisconnect = undefined;
this.tinode.disconnect(); this.tinode.disconnect();
@@ -862,7 +872,7 @@ export default class TinodeWeb extends React.Component {
this.tinode = TinodeWeb.tnSetup(this.state.serverAddress, this.state.transport); this.tinode = TinodeWeb.tnSetup(this.state.serverAddress, this.state.transport);
this.tinode.onConnect = this.handleConnected; this.tinode.onConnect = this.handleConnected;
this.tinode.onDisconnect = this.handleDisconnect; this.tinode.onDisconnect = this.handleDisconnect;
navigateTo(''); HashNavigation.navigateTo('');
} }
handleLeaveUnsubRequest(topicName) { handleLeaveUnsubRequest(topicName) {
@@ -873,7 +883,7 @@ export default class TinodeWeb extends React.Component {
topic.leave(true).then((ctrl) => { topic.leave(true).then((ctrl) => {
// Hide MessagesView and InfoView panels. // Hide MessagesView and InfoView panels.
navigateTo(setUrlTopic(window.location.hash, '')); HashNavigation.navigateTo(HashNavigation.setUrlTopic(window.location.hash, ''));
}).catch((err) => { }).catch((err) => {
this.handleError(err.message, 'err'); this.handleError(err.message, 'err');
}); });
@@ -926,12 +936,12 @@ export default class TinodeWeb extends React.Component {
} }
handleShowInfoView() { handleShowInfoView() {
navigateTo(addUrlParam(window.location.hash, 'info', true)); HashNavigation.navigateTo(HashNavigation.addUrlParam(window.location.hash, 'info', true));
this.setState({showInfoPanel: true}); this.setState({showInfoPanel: true});
} }
handleHideInfoView() { handleHideInfoView() {
navigateTo(removeUrlParam(window.location.hash, 'info')); HashNavigation.navigateTo(HashNavigation.removeUrlParam(window.location.hash, 'info'));
this.setState({showInfoPanel: false}); this.setState({showInfoPanel: false});
} }
+88 -17
View File
File diff suppressed because one or more lines are too long