From f8cd3bf8c4f11388e5ccf908b76549431b323105 Mon Sep 17 00:00:00 2001 From: Tom Moor Date: Thu, 7 Jun 2018 21:35:40 -0700 Subject: [PATCH] Improved offline handling --- app/models/Document.js | 6 +--- app/scenes/Document/Document.js | 11 +++++- app/scenes/{Error404 => }/Error404.js | 3 +- app/scenes/Error404/index.js | 3 -- app/scenes/ErrorOffline.js | 17 +++++++++ app/scenes/Search/Search.js | 2 +- app/stores/DocumentsStore.js | 6 ++-- app/utils/ApiClient.js | 50 ++++++++------------------- 8 files changed, 50 insertions(+), 48 deletions(-) rename app/scenes/{Error404 => }/Error404.js (77%) delete mode 100644 app/scenes/Error404/index.js create mode 100644 app/scenes/ErrorOffline.js diff --git a/app/models/Document.js b/app/models/Document.js index 43369297d..2b895017f 100644 --- a/app/models/Document.js +++ b/app/models/Document.js @@ -158,11 +158,7 @@ class Document extends BaseModel { @action view = async () => { this.views++; - try { - await client.post('/views.create', { id: this.id }); - } catch (e) { - this.ui.showToast('Document failed to record view'); - } + await client.post('/views.create', { id: this.id }); }; @action diff --git a/app/scenes/Document/Document.js b/app/scenes/Document/Document.js index efa69b2a5..1d5120f20 100644 --- a/app/scenes/Document/Document.js +++ b/app/scenes/Document/Document.js @@ -32,6 +32,7 @@ import CenteredContent from 'components/CenteredContent'; import PageTitle from 'components/PageTitle'; import Search from 'scenes/Search'; import Error404 from 'scenes/Error404'; +import ErrorOffline from 'scenes/ErrorOffline'; const AUTOSAVE_INTERVAL = 3000; const MARK_AS_VIEWED_AFTER = 3000; @@ -245,7 +246,15 @@ class DocumentScene extends React.Component { const isShare = match.params.shareId; if (this.notFound) { - return isShare ? : ; + return navigator.onLine ? ( + isShare ? ( + + ) : ( + + ) + ) : ( + + ); } return ( diff --git a/app/scenes/Error404/Error404.js b/app/scenes/Error404.js similarity index 77% rename from app/scenes/Error404/Error404.js rename to app/scenes/Error404.js index dfab52b8c..ebb858ca0 100644 --- a/app/scenes/Error404/Error404.js +++ b/app/scenes/Error404.js @@ -2,13 +2,14 @@ import * as React from 'react'; import CenteredContent from 'components/CenteredContent'; import PageTitle from 'components/PageTitle'; +import Empty from 'components/Empty'; const Error404 = () => { return (

Not Found

-

We were unable to find the page you’re looking for.

+ We were unable to find the page you’re looking for.

Go to homepage.

diff --git a/app/scenes/Error404/index.js b/app/scenes/Error404/index.js deleted file mode 100644 index 36dea2bd7..000000000 --- a/app/scenes/Error404/index.js +++ /dev/null @@ -1,3 +0,0 @@ -// @flow -import Error404 from './Error404'; -export default Error404; diff --git a/app/scenes/ErrorOffline.js b/app/scenes/ErrorOffline.js new file mode 100644 index 000000000..57d4c827b --- /dev/null +++ b/app/scenes/ErrorOffline.js @@ -0,0 +1,17 @@ +// @flow +import * as React from 'react'; +import CenteredContent from 'components/CenteredContent'; +import PageTitle from 'components/PageTitle'; +import Empty from 'components/Empty'; + +const ErrorOffline = () => { + return ( + + +

Offline

+ We were unable to load the document while offline. +
+ ); +}; + +export default ErrorOffline; diff --git a/app/scenes/Search/Search.js b/app/scenes/Search/Search.js index e4a031ba4..de5cd0839 100644 --- a/app/scenes/Search/Search.js +++ b/app/scenes/Search/Search.js @@ -186,7 +186,7 @@ class Search extends React.Component { {notFound && (

Not Found

-

We’re unable to find the page you’re accessing.

+ We were unable to find the page you’re looking for.
)} diff --git a/app/stores/DocumentsStore.js b/app/stores/DocumentsStore.js index 488cc2ff8..ca91c62c5 100644 --- a/app/stores/DocumentsStore.js +++ b/app/stores/DocumentsStore.js @@ -196,8 +196,10 @@ class DocumentsStore extends BaseStore { }); return document; - } catch (e) { - this.ui.showToast('Failed to load document'); + } catch (_err) { + if (!options.prefetch && navigator.onLine) { + this.ui.showToast('Failed to load document'); + } } finally { this.isFetching = false; } diff --git a/app/utils/ApiClient.js b/app/utils/ApiClient.js index be832bfb7..56353b4aa 100644 --- a/app/utils/ApiClient.js +++ b/app/utils/ApiClient.js @@ -16,7 +16,7 @@ class ApiClient { this.userAgent = 'OutlineFrontend'; } - fetch = ( + fetch = async ( path: string, method: string, data: ?Object, @@ -45,9 +45,8 @@ class ApiClient { headers.set('Authorization', `Bearer ${stores.auth.token}`); } - // Construct request // $FlowFixMe don't care much about this right now - const request = fetch(this.baseUrl + (modifiedPath || path), { + const response = await fetch(this.baseUrl + (modifiedPath || path), { method, body, headers, @@ -55,40 +54,21 @@ class ApiClient { credentials: 'include', }); - // Handle request promises and return a new promise - return new Promise((resolve, reject) => { - request - .then(response => { - // Handle successful responses - if (response.status >= 200 && response.status < 300) { - return response; - } + if (response.status >= 200 && response.status < 300) { + return response.json(); + } - // Handle 401, log out user - if (response.status === 401) { - stores.auth.logout(); - return; - } + // Handle 401, log out user + if (response.status === 401) { + stores.auth.logout(); + return; + } - // Handle failed responses - const error = {}; - error.statusCode = response.status; - error.response = response; - throw error; - }) - .then(response => { - return response && response.json(); - }) - .then(json => { - resolve(json); - }) - .catch(error => { - error.response.json().then(json => { - error.error = json; - reject(error); - }); - }); - }); + // Handle failed responses + const error = {}; + error.statusCode = response.status; + error.response = response; + throw error; }; get = (path: string, data: ?Object, options?: Object) => {