From bef1ed1a871bd6be962f2b06fd97112151705b43 Mon Sep 17 00:00:00 2001 From: Tim Golen Date: Sat, 8 Aug 2020 15:16:55 -0600 Subject: [PATCH 01/44] Remove all async and clean up pages --- package-lock.json | 25 ++++++++++++-- package.json | 2 ++ src/CONFIG.js | 1 + src/Expensify.js | 30 ++++++++-------- src/lib/ActiveClientManager.js | 32 ++++++++++-------- src/lib/PersistentStorage.js | 2 +- src/lib/Str.js | 7 ++-- src/page/HomePage/HomePage.js | 62 +++++++++++++--------------------- src/page/SignInPage.js | 30 ++++++---------- src/store/Store.js | 12 +++++++ webpack.config.js | 11 +++++- 11 files changed, 117 insertions(+), 97 deletions(-) diff --git a/package-lock.json b/package-lock.json index c6cdf54af695..d207e358dc56 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7083,8 +7083,7 @@ "html-entities": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-1.3.1.tgz", - "integrity": "sha512-rhE/4Z3hIhzHAUKbW8jVcCyuT5oJCXXqhN/6mXXVCpzTmvJnoH2HL/bt3EZ6p55jbFJBeAe1ZNpL5BugLujxNA==", - "dev": true + "integrity": "sha512-rhE/4Z3hIhzHAUKbW8jVcCyuT5oJCXXqhN/6mXXVCpzTmvJnoH2HL/bt3EZ6p55jbFJBeAe1ZNpL5BugLujxNA==" }, "html-escaper": { "version": "2.0.2", @@ -11720,6 +11719,15 @@ "prop-types": "^15.6.2" } }, + "react-beforeunload": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/react-beforeunload/-/react-beforeunload-2.2.2.tgz", + "integrity": "sha512-U2ZMbVj58ziIYEwQAKJTsCbe9jXyltnKIrU47OTqk8amXzopL/S4fK7kqg0ph8O4aQoSy5ydvKL+KLg+jIUe0Q==", + "requires": { + "prop-types": "^15.7.2", + "use-latest": "^1.1.0" + } + }, "react-devtools-core": { "version": "4.8.2", "resolved": "https://registry.npmjs.org/react-devtools-core/-/react-devtools-core-4.8.2.tgz", @@ -14101,6 +14109,19 @@ "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==" }, + "use-isomorphic-layout-effect": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.0.0.tgz", + "integrity": "sha512-JMwJ7Vd86NwAt1jH7q+OIozZSIxA4ND0fx6AsOe2q1H8ooBUp5aN6DvVCqZiIaYU6JaMRJGyR0FO7EBCIsb/Rg==" + }, + "use-latest": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/use-latest/-/use-latest-1.1.0.tgz", + "integrity": "sha512-gF04d0ZMV3AMB8Q7HtfkAWe+oq1tFXP6dZKwBHQF5nVXtGsh2oAYeeqma5ZzxtlpOcW8Ro/tLcfmEodjDeqtuw==", + "requires": { + "use-isomorphic-layout-effect": "^1.0.0" + } + }, "use-subscription": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/use-subscription/-/use-subscription-1.4.1.tgz", diff --git a/package.json b/package.json index 4c8aa9e1a702..7736f5996e48 100644 --- a/package.json +++ b/package.json @@ -13,10 +13,12 @@ }, "dependencies": { "@react-native-community/async-storage": "^1.11.0", + "html-entities": "^1.3.1", "jquery": "^3.5.1", "lodash.get": "^4.4.2", "moment": "^2.27.0", "react": "^16.13.1", + "react-beforeunload": "^2.2.2", "react-dom": "^16.13.1", "react-native": "0.63.2", "react-native-web": "^0.13.5", diff --git a/src/CONFIG.js b/src/CONFIG.js index 7dcfe5902d07..f04eb75339f5 100644 --- a/src/CONFIG.js +++ b/src/CONFIG.js @@ -1,5 +1,6 @@ import {Platform} from 'react-native'; +// eslint-disable-next-line no-undef const IS_IN_PRODUCTION = Platform.OS === 'web' ? process.env.NODE_ENV === 'production' : !__DEV__; export default { diff --git a/src/Expensify.js b/src/Expensify.js index 306b7c468529..cb1862799217 100644 --- a/src/Expensify.js +++ b/src/Expensify.js @@ -1,4 +1,5 @@ import React, {Component} from 'react'; +import {Beforeunload} from 'react-beforeunload'; import SignInPage from './page/SignInPage'; import HomePage from './page/HomePage/HomePage'; import * as Store from './store/Store'; @@ -24,7 +25,7 @@ export default class Expensify extends Component { }; } - async componentDidMount() { + componentDidMount() { // Listen for when the app wants to redirect to a specific URL Store.subscribe(STOREKEYS.APP_REDIRECT_TO, (redirectTo) => { this.setState({redirectTo}); @@ -34,25 +35,22 @@ export default class Expensify extends Component { verifyAuthToken(); // Initialize this client as being an active client - await ActiveClientManager.init(); - - // TODO: Refactor window events - // window.addEventListener('beforeunload', () => { - // ActiveClientManager.removeClient(); - // }); + ActiveClientManager.init(); } render() { return ( - - {/* If there is ever a property for redirecting, we do the redirect here */} - {this.state.redirectTo && } - - - - - - + + + {/* If there is ever a property for redirecting, we do the redirect here */} + {this.state.redirectTo && } + + + + + + + ); } } diff --git a/src/lib/ActiveClientManager.js b/src/lib/ActiveClientManager.js index dabd2958f4eb..cfc10f804de5 100644 --- a/src/lib/ActiveClientManager.js +++ b/src/lib/ActiveClientManager.js @@ -1,3 +1,4 @@ +import _ from 'underscore'; import Guid from './Guid'; import * as Store from '../store/Store'; import STOREKEYS from '../store/STOREKEYS'; @@ -6,33 +7,34 @@ const clientID = Guid(); /** * Add our client ID to the list of active IDs + * + * @returns {Promise} */ -const init = async () => { - const activeClientIDs = (await Store.get(STOREKEYS.ACTIVE_CLIENT_IDS)) || []; - activeClientIDs.push(clientID); - Store.set(STOREKEYS.ACTIVE_CLIENT_IDS, activeClientIDs); -}; +const init = () => Store.merge(STOREKEYS.ACTIVE_CLIENT_IDS, clientID); /** * Remove this client ID from the array of active client IDs when this client is exited + * + * @returns {Promise} */ function removeClient() { - const activeClientIDs = Store.get(STOREKEYS.ACTIVE_CLIENT_IDS) || []; - const newActiveClientIDs = activeClientIDs.filter(activeClientID => activeClientID !== clientID); - Store.set(STOREKEYS.ACTIVE_CLIENT_IDS, newActiveClientIDs); + return Store.get(STOREKEYS.ACTIVE_CLIENT_IDS) + .then(activeClientIDs => _.without(activeClientIDs, clientID)) + .then(newActiveClientIDs => Store.set(STOREKEYS.ACTIVE_CLIENT_IDS, newActiveClientIDs)); } /** * Checks if the current client is the leader (the first one in the list of active clients) * - * @returns {boolean} + * @returns {Promise} */ function isClientTheLeader() { - const activeClientIDs = Store.get(STOREKEYS.ACTIVE_CLIENT_IDS) || []; - if (!activeClientIDs.length) { - return false; - } - return activeClientIDs[0] === clientID; + return Store.get(STOREKEYS.ACTIVE_CLIENT_IDS) + .then(activeClientIDs => _.first(activeClientIDs) === clientID); } -export {init, removeClient, isClientTheLeader}; +export { + init, + removeClient, + isClientTheLeader +}; diff --git a/src/lib/PersistentStorage.js b/src/lib/PersistentStorage.js index 0416366dcbf4..a884c23d35e4 100644 --- a/src/lib/PersistentStorage.js +++ b/src/lib/PersistentStorage.js @@ -33,7 +33,7 @@ function multiGet(keys) { ...finalData, [keyValuePair[0]]: JSON.parse(keyValuePair[1]), }), {})) - .catch(err => console.error(`Unable to get item from persistent storage. Keys: ${JSON.stringify(keys)} Error: ${err}`)); + .catch(err => console.error(`Unable to get item from persistent storage. Error: ${err}`, keys)); } /** diff --git a/src/lib/Str.js b/src/lib/Str.js index b768528bc0c5..d8f97dba2df9 100644 --- a/src/lib/Str.js +++ b/src/lib/Str.js @@ -1,7 +1,8 @@ -/* globals $, _ */ - +import _ from 'underscore'; +import {AllHtmlEntities} from 'html-entities'; import Guid from './Guid'; + const Str = { /** * Returns the proper phrase depending on the count that is passed. @@ -39,7 +40,7 @@ const Str = { * @return {String} The decoded string. */ htmlDecode(s) { - return $('