// simple version, only toggle watch / unwatch const simpleWatchable = collection => { collection.attachSchema({ watchers: { type: [String], optional: true, }, }); collection.helpers({ getWatchLevels() { return [true, false]; }, watcherIndex(userId) { return this.watchers.indexOf(userId); }, findWatcher(userId) { return _.contains(this.watchers, userId); }, }); collection.mutations({ setWatcher(userId, level) { // if level undefined or null or false, then remove if (!level) return { $pull: { watchers: userId } }; return { $addToSet: { watchers: userId } }; }, }); }; // more complex version of same interface, with 3 watching levels const complexWatchOptions = ['watching', 'tracking', 'muted']; const complexWatchDefault = 'muted'; const complexWatchable = collection => { collection.attachSchema({ 'watchers.$.userId': { type: String, }, 'watchers.$.level': { type: String, allowedValues: complexWatchOptions, }, }); collection.helpers({ getWatchOptions() { return complexWatchOptions; }, getWatchDefault() { return complexWatchDefault; }, watcherIndex(userId) { return _.pluck(this.watchers, 'userId').indexOf(userId); }, findWatcher(userId) { return _.findWhere(this.watchers, { userId }); }, getWatchLevel(userId) { const watcher = this.findWatcher(userId); return watcher ? watcher.level : complexWatchDefault; }, }); collection.mutations({ setWatcher(userId, level) { // if level undefined or null or false, then remove if (level === complexWatchDefault) level = null; if (!level) return { $pull: { watchers: { userId } } }; const index = this.watcherIndex(userId); if (index < 0) return { $push: { watchers: { userId, level } } }; return { $set: { [`watchers.${index}.level`]: level, }, }; }, }); }; complexWatchable(Boards); simpleWatchable(Lists); simpleWatchable(Cards);