UNPKG

webcom-reach

Version:
286 lines (269 loc) 7.29 kB
import { ACCEPTED, CANCELED, ONGOING, REJECTED } from './util/constants'; import * as DataSync from './util/DataSync'; import * as Log from './util/Log'; import cache from './util/cache'; import Room from './Room'; import * as Events from '../definitions/Events'; /** * Update * @param {Invite} invite The invite * @param {string} status The new status * @param {string} [reason=null] The reason (a message) * @param {object} [_ended=null] * @access private * @returns {Promise<Invite, Error>} */ const update = (invite, status, reason = null, _ended = null) => { const values = { status, reason, _ended }; if (invite.status !== ONGOING) { return Promise.reject(new Error('This invitation has already been answered')); } return DataSync.update(`_/invites/${invite.to}/${invite.uid}`, values) .then(() => { Object.keys(values).forEach((prop) => { invite[prop] = values[prop]; // eslint-disable-line no-param-reassign }); return Room.get(invite.room); }) .then(() => ({ invite })) .catch(Log.r('Invite_update')); }; /** * Invitation * @public */ export default class Invite { /** * Create an invite * @param {Webcom/api.DataSnapshot|object} snapData The data snapshot * @access protected */ constructor(snapData) { let values = snapData; if (snapData && snapData.val && typeof snapData.val === 'function') { values = Object.assign({}, snapData.val(), { uid: snapData.name(), to: snapData.ref().parent().name() }); } /** * Invite's unique id * @type string */ this.uid = values.uid; /** * Invite's sender uid * @type {string} */ this.from = values.from; /** * Invitee's uid * @type {string} */ this.to = values.to; /** * The id of the room associated to the invite * @type {string} */ this.room = values.room; /** * The invitation status : * - ONGOING - The receiver has not yet responded to the invitation * - ACCEPTED - The receiver has accepted the invitation * - REJECTED - The receiver has rejected the invitation * - CANCELED - The sender canceled the invitation * @type {string} */ this.status = values.status; /** * Invite message. This will be either a custom message, * if the status is ONGOING or a reason when status is CANCELED|REJECTED. * @type {string} */ this.topic = values.topic; /** * Invite creation timestamp * @type {number} */ this._created = values._created; /** * Invite expiration timestamp * @type {number} */ this._ended = values._ended; /** * Invite events callbacks * @type {{}} * @private */ this._callbacks = {}; } /** * Is this invitation waiting for a reply ? * @type {boolean} */ get isOnGoing() { return this.status === ONGOING; } /** * Was this invitation rejected ? * @type {boolean} */ get isRejected() { return this.status === REJECTED; } /** * Was this invitation accepted ? * @type {boolean} */ get isAccepted() { return this.status === ACCEPTED; } /** * Was this invitation canceled ? * @type {boolean} */ get isCanceled() { return this.status === CANCELED; } /** * Cancels the invitation. Only the sender can cancel the invitation. * @param {string} [reason] The reason the sender is canceling the invite * @return {Promise<Invite>} */ cancel(reason) { return update(this, CANCELED, reason, DataSync.ts()); } /** * Rejects the invitation. Only the receiver can reject the invitation. * @param {string} [reason] The reason the receiver is rejecting the invite * @return {Promise<Invite>} */ reject(reason) { return update(this, REJECTED, reason, DataSync.ts()); } /** * Accept the invitation. Only the receiver can accept the invitation. * @return {Promise<Invite>} */ accept() { return update(this, ACCEPTED); } /** * Register a callback for a status update * @param {string} status Can be: * - ACCEPTED * - REJECTED * - CANCELED * @param {function} callback */ on(status, callback) { if (Events.invite.supports(status)) { // Register callback if (!this._callbacks[status]) { this._callbacks[status] = []; } this._callbacks[status].push(callback); // Defined listener & subscribe if needed if (!this._listener) { /** * Invite status update callback * @type {function} * @private */ this._listener = (snapData) => { const updated = snapData.val(); if (updated !== null && updated !== this.status) { this.status = updated; (this._callbacks[updated] || []).forEach((cb) => { cb(this); }); } }; DataSync.on(`_/invites/${this.to}/${this.uid}/status`, 'value', this._listener.bind(this)); } } } /** * Register a callback for all status change events * @param {function} callback */ onStatusChange(callback) { [ACCEPTED, REJECTED, CANCELED].forEach((event) => { this.on(event, callback); }); } /** * Un-register a callback for a status update * @param {string} [status] Can be: * - ACCEPTED * - REJECTED * - CANCELED * - null This will un-register all callbacks * @param {function} [callback] */ off(status, callback) { if (!status) { this._callbacks = {}; } else if (this._callbacks[status]) { if (callback) { const idx = this._callbacks[status].findIndex(cb => cb === callback); if (idx >= 0) { this._callbacks.splice(idx, 1); } } else { this._callbacks[status] = []; } } if (![CANCELED, ACCEPTED, REJECTED] .some(event => this._callbacks[event] && this._callbacks[event].length > 0)) { DataSync.off(`_/invites/${this.to}/${this.uid}/status`, 'value'); } } /** * Un-register a callback for all status change events * @param {function} [callback] */ offStatusChange(callback) { if (!callback) { this.off(); } else { [ACCEPTED, REJECTED, CANCELED].forEach((event) => { this.off(event, callback); }); } } /** * Create the invitation & add the user to the participants list * @access protected * @param {User} invitee The user to invite * @param {Room} room The room to invite the user to * @param {string} [message] A message for the invitee */ static send(invitee, room, message = null) { if (!cache.user) { return Promise.reject(new Error('Only an authenticated user can send an invite.')); } const inviteMetaData = { from: cache.user.uid, room: room.uid, status: ONGOING, _created: DataSync.ts(), topic: message }; return DataSync.push(`_/invites/${invitee.uid}`, inviteMetaData) .then((inviteRef) => { const inviteId = inviteRef.name(); return new Invite(Object.assign({ uid: inviteId, to: invitee.uid }, inviteMetaData)); }) .catch(Log.r('Invite#send')); } }