-
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
880 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,157 @@ | ||
'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 | ||
* discovered and online, authenticated user session is established and | ||
* document is visible). | ||
* | ||
* @returns {Promise} | ||
* @private | ||
*/ | ||
[p.onceReady]() { | ||
return Promise.all([ | ||
this[p.onceOnline](), | ||
]); | ||
} | ||
|
||
/** | ||
* Returns 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,106 @@ | ||
/* 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; | ||
} | ||
|
||
/** | ||
* Redirect the user to the box to get authenticated if she isn't already. | ||
* | ||
* @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 for accepting push notifications from the box. | ||
* This method will be call 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 have push subscription information. | ||
* @return {Promise} | ||
*/ | ||
subscribeToNotifications(resubscribe = false) { | ||
return this[p.webPush].subscribeToNotifications(resubscribe); | ||
} | ||
} |
Oops, something went wrong.