-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Wiring the views with the server. r=samgiles
- Loading branch information
Showing
15 changed files
with
888 additions
and
52 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,5 @@ | ||
.microphone { | ||
position: absolute; | ||
position: fixed; | ||
z-index: 1; | ||
top: 8rem; | ||
right: 9rem; | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,159 @@ | ||
'use strict'; | ||
|
||
const p = Object.freeze({ | ||
settings: Symbol('settings'), | ||
net: Symbol('net'), | ||
|
||
// Private methods. | ||
getURL: Symbol('getURL'), | ||
onceOnline: Symbol('onceOnline'), | ||
onceReady: Symbol('onceReady'), | ||
getChannelValues: Symbol('getChannelValues'), | ||
updateChannelValue: Symbol('updateChannelValue'), | ||
}); | ||
|
||
/** | ||
* Instance of the API class is intended to abstract consumer from the API | ||
* specific details (e.g. API base URL and version). It also tracks | ||
* availability of the network, API host and whether correct user session is | ||
* established. If any of this conditions is not met all API requests are | ||
* blocked until it's possible to perform them, so consumer doesn't have to | ||
* care about these additional checks. | ||
*/ | ||
export default class API { | ||
constructor(net, settings) { | ||
this[p.net] = net; | ||
this[p.settings] = settings; | ||
|
||
Object.freeze(this); | ||
} | ||
|
||
/** | ||
* Performs HTTP 'GET' API request and accepts JSON as response. | ||
* | ||
* @param {string} path Specific API resource path to be used in conjunction | ||
* with the base API path. | ||
* @return {Promise} | ||
*/ | ||
get(path) { | ||
return this[p.onceReady]() | ||
.then(() => this[p.net].fetchJSON(this[p.getURL](path))); | ||
} | ||
|
||
/** | ||
* Performs HTTP 'POST' API request and accepts JSON as response. | ||
* | ||
* @param {string} path Specific API resource path to be used in conjunction | ||
* with the base API path. | ||
* @param {Object=} body Optional object that will be serialized to JSON | ||
* string and sent as 'POST' body. | ||
* @return {Promise} | ||
*/ | ||
post(path, body) { | ||
console.log(path, body); | ||
|
||
return this[p.onceReady]() | ||
.then(() => this[p.net].fetchJSON(this[p.getURL](path), 'POST', body)); | ||
} | ||
|
||
/** | ||
* Performs HTTP 'PUT' API request and accepts JSON as response. | ||
* | ||
* @param {string} path Specific API resource path to be used in conjunction | ||
* with the base API path. | ||
* @param {Object=} body Optional object that will be serialized to JSON | ||
* string and sent as 'PUT' body. | ||
* @return {Promise} | ||
*/ | ||
put(path, body) { | ||
return this[p.onceReady]() | ||
.then(() => this[p.net].fetchJSON(this[p.getURL](path), 'PUT', body)); | ||
} | ||
|
||
/** | ||
* Performs HTTP 'DELETE' API request and accepts JSON as response. | ||
* | ||
* @param {string} path Specific API resource path to be used in conjunction | ||
* with the base API path. | ||
* @param {Object=} body Optional object that will be serialized to JSON | ||
* string and sent as 'DELETE' body. | ||
* @return {Promise} | ||
*/ | ||
delete(path, body) { | ||
return this[p.onceReady]() | ||
.then(() => this[p.net].fetchJSON(this[p.getURL](path), 'DELETE', body)); | ||
} | ||
|
||
/** | ||
* Performs either HTTP 'GET' or 'PUT' (if body parameter is specified) API | ||
* request and accepts Blob as response. | ||
* | ||
* @param {string} path Specific API resource path to be used in conjunction | ||
* with the base API path. | ||
* @param {Object=} body Optional object that will be serialized to JSON | ||
* string and sent as 'PUT' body. | ||
* @param {string=} accept Mime type of the Blob we expect as a response | ||
* (default is image/jpeg). | ||
* @return {Promise} | ||
*/ | ||
blob(path, body, accept = 'image/jpeg') { | ||
return this[p.onceReady]() | ||
.then(() => { | ||
if (body) { | ||
return this[p.net].fetchBlob( | ||
this[p.getURL](path), accept, 'PUT', body | ||
); | ||
} | ||
|
||
return this[p.net].fetchBlob(this[p.getURL](path), accept); | ||
}); | ||
} | ||
|
||
/** | ||
* Creates a fully qualified API URL based on predefined base origin, API | ||
* version and specified resource path. | ||
* | ||
* @param {string} path Specific API resource path to be used in conjunction | ||
* with the base API path and version. | ||
* @return {string} | ||
* @private | ||
*/ | ||
[p.getURL](path) { | ||
if (!path || typeof path !== 'string') { | ||
throw new Error('Path should be a valid non-empty string.'); | ||
} | ||
|
||
return `${this[p.net].origin}/api/v${this[p.settings].apiVersion}/${path}`; | ||
} | ||
|
||
/** | ||
* Returns a promise that is resolved once API is ready to use (API host is | ||
* online). | ||
* In the future we can add more checks like: | ||
* * User is authenticated | ||
* * Document is visible | ||
* | ||
* @returns {Promise} | ||
* @private | ||
*/ | ||
[p.onceReady]() { | ||
return Promise.all([ | ||
this[p.onceOnline](), | ||
]); | ||
} | ||
|
||
/** | ||
* Returns a promise that is resolved once API host is discovered and online. | ||
* | ||
* @returns {Promise} | ||
* @private | ||
*/ | ||
[p.onceOnline]() { | ||
const net = this[p.net]; | ||
if (net.online) { | ||
return Promise.resolve(); | ||
} | ||
|
||
return new Promise((resolve) => net.once('online', () => resolve())); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
/* global URLSearchParams */ | ||
|
||
'use strict'; | ||
|
||
import EventDispatcher from '../common/event-dispatcher'; | ||
|
||
import Settings from './settings'; | ||
import Network from './network'; | ||
import WebPush from './webpush'; | ||
import API from './api'; | ||
import Reminders from './reminders'; | ||
|
||
// Private members. | ||
const p = Object.freeze({ | ||
// Private properties. | ||
settings: Symbol('settings'), | ||
net: Symbol('net'), | ||
webPush: Symbol('webPush'), | ||
api: Symbol('api'), | ||
}); | ||
|
||
export default class Server extends EventDispatcher { | ||
constructor({ settings, net } = {}) { | ||
super(['online']); | ||
|
||
// Private properties. | ||
this[p.settings] = settings || new Settings(); | ||
this[p.net] = net || new Network(this[p.settings]); | ||
this[p.api] = new API(this[p.net], this[p.settings]); | ||
this[p.webPush] = new WebPush(this[p.api], this[p.settings]); | ||
|
||
// Init | ||
this.reminders = new Reminders(this[p.api], this[p.settings]); | ||
|
||
this[p.net].on('online', (online) => this.emit('online', online)); | ||
this[p.webPush].on('message', (msg) => this.emit('push-message', msg)); | ||
|
||
window.server = this; | ||
|
||
Object.seal(this); | ||
} | ||
|
||
/** | ||
* Clear all data/settings stored on the browser. Use with caution. | ||
* | ||
* @param {boolean} ignoreServiceWorker | ||
* @return {Promise} | ||
*/ | ||
clear(ignoreServiceWorker = true) { | ||
const promises = [this[p.settings].clear()]; | ||
|
||
if (!navigator.serviceWorker && !ignoreServiceWorker) { | ||
promises.push(navigator.serviceWorker.ready | ||
.then((registration) => registration.unregister())); | ||
} | ||
|
||
return Promise.all(promises); | ||
} | ||
|
||
get online() { | ||
return this[p.net].online; | ||
} | ||
|
||
get isLoggedIn() { | ||
return !!this[p.settings].session; | ||
} | ||
|
||
/** | ||
* Authenticate a user. | ||
* | ||
* @param {string} user | ||
* @param {string} password | ||
* @return {Promise} | ||
*/ | ||
login(user, password) { | ||
return this[p.api].post('login', { user, password }) | ||
.then((res) => { | ||
this[p.settings].session = res.token; | ||
}); | ||
} | ||
|
||
/** | ||
* Log out the user. | ||
* | ||
* @return {Promise} | ||
*/ | ||
logout() { | ||
this[p.settings].session = null; | ||
return Promise.resolve(); | ||
} | ||
|
||
/** | ||
* Ask the user to accept push notifications from the server. | ||
* This method will be called each time that we log in, but will stop the | ||
* execution if we already have the push subscription information. | ||
* | ||
* @param {boolean} resubscribe Parameter used for testing purposes, and | ||
* follow the whole subscription process even if we already have a push | ||
* subscription information. | ||
* @return {Promise} | ||
*/ | ||
subscribeToNotifications(resubscribe = false) { | ||
return this[p.webPush].subscribeToNotifications(resubscribe); | ||
} | ||
} |
Oops, something went wrong.