[client-app] convert FocusedContactStore to es6

This commit is contained in:
Evan Morikawa 2017-02-17 14:17:01 -08:00
parent ebb19b4cd8
commit ad65b7d77a
2 changed files with 174 additions and 137 deletions

View file

@ -1,137 +0,0 @@
_ = require 'underscore'
Rx = require 'rx-lite'
Utils = require '../models/utils'
Actions = require('../actions').default
NylasStore = require 'nylas-store'
Thread = require('../models/thread').default
Contact = require('../models/contact').default
MessageStore = require './message-store'
AccountStore = require('./account-store').default
DatabaseStore = require('./database-store').default
FocusedContentStore = require './focused-content-store'
# A store that handles the focuses collections of and individual contacts
class FocusedContactsStore extends NylasStore
constructor: ->
@listenTo MessageStore, @_onMessageStoreChanged
@listenTo Actions.focusContact, @_onFocusContact
@_clearCurrentParticipants()
@_triggerLater = _.debounce(@trigger, 250)
@_loadCurrentParticipantThreads = _.debounce(@_loadCurrentParticipantThreads, 250)
sortedContacts: -> @_currentContacts
focusedContact: -> @_currentFocusedContact
focusedContactThreads: -> @_currentParticipantThreads ? []
# We need to wait now for the MessageStore to grab all of the
# appropriate messages for the given thread.
_onMessageStoreChanged: =>
threadId = if MessageStore.itemsLoading() then null else MessageStore.threadId()
# Always clear data immediately when we're showing the wrong thread
if @_currentThread and @_currentThread.id isnt threadId
@_clearCurrentParticipants()
@trigger()
# Wait to populate until the user has stopped moving through threads. This is
# important because the FocusedContactStore powers tons of third-party extensions,
# which could do /horrible/ things when we trigger.
thread = if MessageStore.itemsLoading() then null else MessageStore.thread()
if thread and thread.id isnt @_currentThread?.id
@_currentThread = thread
@_popuateCurrentParticipants()
# For now we take the last message
_popuateCurrentParticipants: ->
@_scoreAllParticipants()
sorted = _.sortBy(_.values(@_contactScores), "score").reverse()
@_currentContacts = _.map(sorted, (obj) -> obj.contact)
@_onFocusContact(@_currentContacts[0])
_clearCurrentParticipants: ->
@_contactScores = {}
@_currentContacts = []
@_unsubFocusedContact?.dispose()
@_unsubFocusedContact = null
@_currentFocusedContact = null
@_currentThread = null
@_currentParticipantThreads = []
_onFocusContact: (contact) =>
@_unsubFocusedContact?.dispose()
@_unsubFocusedContact = null
@_currentParticipantThreads = []
if contact
query = DatabaseStore.findBy(Contact, {
accountId: @_currentThread.accountId,
email: contact.email,
name: contact.name,
})
@_unsubFocusedContact = Rx.Observable.fromQuery(query).subscribe (match) =>
@_currentFocusedContact = match ? contact
@_triggerLater()
@_loadCurrentParticipantThreads(contact.email)
else
@_currentFocusedContact = null
@_triggerLater()
_loadCurrentParticipantThreads: (email) ->
email = @_currentFocusedContact?.email
return unless email
DatabaseStore.findAll(Thread).where(Thread.attributes.participants.contains(email)).limit(100).background().then (threads = []) =>
return unless @_currentFocusedContact?.email is email
@_currentParticipantThreads = threads
@trigger()
# We score everyone to determine who's the most relevant to display in
# the sidebar.
_scoreAllParticipants: ->
score = (message, msgNum, field, multiplier) =>
for contact, j in (message[field] ? [])
bonus = message[field].length - j
@_assignScore(contact, (msgNum+1) * multiplier + bonus)
for message, msgNum in MessageStore.items() by -1
if message.draft
score(message, msgNum, "to", 10000)
score(message, msgNum, "cc", 1000)
else
score(message, msgNum, "from", 100)
score(message, msgNum, "to", 10)
score(message, msgNum, "cc", 1)
return @_contactScores
# Self always gets a score of 0
_assignScore: (contact, score=0) ->
return unless contact and contact.email
return if contact.email.trim().length is 0
key = Utils.toEquivalentEmailForm(contact.email)
@_contactScores[key] ?=
contact: contact
score: score - @_calculatePenalties(contact, score)
_calculatePenalties: (contact, score) ->
penalties = 0
email = contact.email.toLowerCase().trim()
myEmail = AccountStore.accountForId(@_currentThread?.accountId)?.emailAddress
if email is myEmail
# The whole thing which will penalize to zero
penalties += score
notCommonDomain = not Utils.emailHasCommonDomain(myEmail)
sameDomain = Utils.emailsHaveSameDomain(myEmail, email)
if notCommonDomain and sameDomain
penalties += score * 0.9
return Math.max(penalties, 0)
module.exports = new FocusedContactsStore

View file

@ -0,0 +1,174 @@
import _ from 'underscore';
import Rx from 'rx-lite';
import NylasStore from 'nylas-store';
import Utils from '../models/utils';
import Thread from '../models/thread';
import Actions from '../actions';
import Contact from '../models/contact';
import MessageStore from './message-store';
import AccountStore from './account-store';
import DatabaseStore from './database-store';
// A store that handles the focuses collections of and individual contacts
class FocusedContactsStore extends NylasStore {
constructor() {
super()
this.listenTo(MessageStore, this._onMessageStoreChanged);
this.listenTo(Actions.focusContact, this._onFocusContact);
this._clearCurrentParticipants();
this._triggerLater = _.debounce(this.trigger, 250);
this._loadCurrentParticipantThreads = _.debounce(this._loadCurrentParticipantThreads, 250);
}
sortedContacts() { return this._currentContacts; }
focusedContact() { return this._currentFocusedContact; }
focusedContactThreads() { return this._currentParticipantThreads || []; }
// We need to wait now for the MessageStore to grab all of the
// appropriate messages for the given thread.
_onMessageStoreChanged = () => {
const threadId = MessageStore.itemsLoading() ? null : MessageStore.threadId();
// Always clear data immediately when we're showing the wrong thread
if (this._currentThread && this._currentThread.id !== threadId) {
this._clearCurrentParticipants();
this.trigger();
}
// Wait to populate until the user has stopped moving through threads. This is
// important because the FocusedContactStore powers tons of third-party extensions,
// which could do /horrible/ things when we trigger.
const thread = MessageStore.itemsLoading() ? null : MessageStore.thread();
if (thread && thread.id !== ((this._currentThread || {}).id)) {
this._currentThread = thread;
this._populateCurrentParticipants();
}
}
// For now we take the last message
_populateCurrentParticipants() {
this._scoreAllParticipants();
const sorted = _.sortBy(_.values(this._contactScores), "score").reverse();
this._currentContacts = _.map(sorted, obj => obj.contact);
return this._onFocusContact(this._currentContacts[0]);
}
_clearCurrentParticipants() {
this._contactScores = {};
this._currentContacts = [];
if (this._unsubFocusedContact) this._unsubFocusedContact.dispose();
this._unsubFocusedContact = null;
this._currentFocusedContact = null;
this._currentThread = null;
this._currentParticipantThreads = [];
}
_onFocusContact = (contact) => {
if (this._unsubFocusedContact) this._unsubFocusedContact.dispose();
this._unsubFocusedContact = null;
this._currentParticipantThreads = [];
if (contact) {
const query = DatabaseStore.findBy(Contact, {
accountId: this._currentThread.accountId,
email: contact.email,
name: contact.name,
});
this._unsubFocusedContact = Rx.Observable.fromQuery(query).subscribe(match => {
this._currentFocusedContact = match || contact;
return this._triggerLater();
});
this._loadCurrentParticipantThreads();
} else {
this._currentFocusedContact = null;
this._triggerLater();
}
}
_loadCurrentParticipantThreads() {
const currentContact = this._currentFocusedContact || {}
const email = currentContact.email;
if (!email) {
return
}
DatabaseStore.findAll(Thread)
.where(Thread.attributes.participants.contains(email))
.limit(100).background()
.then((threads = []) => {
if (currentContact.email !== email) {
return
}
this._currentParticipantThreads = threads;
this.trigger();
});
}
// We score everyone to determine who's the most relevant to display in
// the sidebar.
_scoreAllParticipants() {
const score = (message, msgNum, field, multiplier) => {
(message[field] || []).forEach((contact, j) => {
const bonus = message[field].length - j
this._assignScore(contact, (msgNum + 1) * multiplier + bonus)
});
};
const iterable = MessageStore.items();
for (let msgNum = iterable.length - 1; msgNum >= 0; msgNum--) {
const message = iterable[msgNum];
if (message.draft) {
score(message, msgNum, "to", 10000);
score(message, msgNum, "cc", 1000);
} else {
score(message, msgNum, "from", 100);
score(message, msgNum, "to", 10);
score(message, msgNum, "cc", 1);
}
}
return this._contactScores;
}
// Self always gets a score of 0
_assignScore(contact, score = 0) {
if (!contact || !contact.email) { return; }
if (contact.email.trim().length === 0) { return; }
const key = Utils.toEquivalentEmailForm(contact.email);
if (!this._contactScores[key]) {
this._contactScores[key] = {
contact: contact,
score: score - this._calculatePenalties(contact, score),
}
}
}
_calculatePenalties(contact, score) {
let penalties = 0;
const email = contact.email.toLowerCase().trim();
const accountId = (this._currentThread || {}).accountId;
const account = AccountStore.accountForId(accountId) || {}
const myEmail = account.emailAddress
if (email === myEmail) {
// The whole thing which will penalize to zero
penalties += score;
}
const notCommonDomain = !Utils.emailHasCommonDomain(myEmail);
const sameDomain = Utils.emailsHaveSameDomain(myEmail, email);
if (notCommonDomain && sameDomain) {
penalties += score * 0.9;
}
return Math.max(penalties, 0);
}
}
export default new FocusedContactsStore();