class App { constructor() { this.data = { promises: {getUser: {}, subscribeUser: {}}, users: {}, }; this.socket = io({transports: ['websocket'], upgrade: false}); this.socket.on('PATCH', (patch) => { const re = new RegExp(`^/users/(${Object.keys(this.data.users).join('|')})`); const filteredPatch = patch.filter(operation => re.test(operation.path)); jsonpatch.applyPatch(this.data, filteredPatch); }); } getUser(userId) { if (userId in this.data.promises.getUser) { return this.data.promises.getUser[userId]; } this.data.promises.getUser[userId] = new Promise((resolve, reject) => { this.socket.emit('GET /users/', userId, (response) => { if (response.code === 200) { this.data.users[userId] = response.payload; resolve(this.data.users[userId]); } else { reject(response); } }); }); return this.data.promises.getUser[userId]; } subscribeUser(userId) { if (userId in this.data.promises.subscribeUser) { return this.data.promises.subscribeUser[userId]; } this.data.promises.subscribeUser[userId] = new Promise((resolve, reject) => { this.socket.emit('SUBSCRIBE /users/', userId, (response) => { if (response.code === 200) { resolve(response); } else { reject(response); } }); }); return this.data.promises.subscribeUser[userId]; } flash(message, category) { let iconPrefix; let toast; let toastCloseActionElement; switch (category) { case 'corpus': iconPrefix = 'book'; break; case 'error': iconPrefix = 'error'; break; case 'job': iconPrefix = 'J'; break; default: iconPrefix = 'notifications'; break; } toast = M.toast( { html: ` ${iconPrefix}${message} `.trim() } ); toastCloseActionElement = toast.el.querySelector('.toast-action[data-action="close"]'); toastCloseActionElement.addEventListener('click', () => {toast.dismiss();}); } }