diff --git a/internal_packages/thread-list/lib/thread-list-participants.cjsx b/internal_packages/thread-list/lib/thread-list-participants.cjsx index e93aef1bf..148d86044 100644 --- a/internal_packages/thread-list/lib/thread-list-participants.cjsx +++ b/internal_packages/thread-list/lib/thread-list-participants.cjsx @@ -59,49 +59,62 @@ class ThreadListParticipants extends React.Component getParticipants: => + makeMetadataFilterer = (toOrFrom) -> + (msg, i, msgs) -> + isFirstMsg = i is 0 + if msg.draft + false + else if isFirstMsg + true + else # check adjacent email uniqueness + last = msgs[i - 1][toOrFrom][0] + curr = msgs[i][toOrFrom][0] + isUniqueEmail = last.email isnt curr.email + isUniqueName = last.name isnt curr.name + isUniqueEmail or isUniqueName + + makeMetadataMapper = (toOrFrom) -> + (msg) -> + msg[toOrFrom].map (contact) -> + { contact: contact, unread: msg.unread } + if @props.thread.metadata - list = [] - last = {} - for msg in @props.thread.metadata - continue if msg.draft - from = msg.from[0] - continue unless from - if from.email isnt last.email or from.name isnt last.name - list.push({ - contact: msg.from[0] - unread: msg.unread - }) - last = from - + shouldOnlyShowRecipients = @props.thread.metadata.every (msg) -> + sender = msg.from[0] + sender.email is NamespaceStore.current().emailAddress + input = @props.thread.metadata + toOrFrom = if shouldOnlyShowRecipients then "to" else "from" + filterer = makeMetadataFilterer toOrFrom + mapper = makeMetadataMapper toOrFrom else - list = @props.thread.participants - return [] unless list and list instanceof Array - me = NamespaceStore.current().emailAddress - list = _.reject list, (p) -> p.email is me + input = @props.thread.participants + return [] unless input and input instanceof Array + currentUserEmail = NamespaceStore.current().emailAddress + filterer = (msg) -> msg.email isnt currentUserEmail + mapper = (contact) -> { contact: contact, unread: false } - # Removing "Me" may remove "Me" several times due to the way - # participants is created. If we're left with an empty array, - # put one a "Me" back in. - if list.length is 0 and @props.thread.participants.length > 0 - list.push(@props.thread.participants[0]) + list = _.chain(input) + .filter(filterer) + .map(mapper) + .reduce(((prevContacts, next) -> prevContacts.concat(next)), []) + .value() - # Change the list to have the appropriate output format - list = list.map (contact) -> - contact: contact - unread: false # We don't have the data. + # If no participants, we should at least add current user as sole participant + if list.length is 0 and @props.thread.participants.length > 0 + list.push({ contact: @props.thread.participants[0], unread: false }) # We only ever want to show three. Ben...Kevin... Marty # But we want the *right* three. if list.length > 3 - listTrimmed = [] + listTrimmed = [ + # Always include the first item + list[0], + { spacer: true }, - # Always include the first item - listTrimmed.push(list[0]) - listTrimmed.push({spacer: true}) - - # Always include the last two item - listTrimmed.push(list[list.length - 2]) - listTrimmed.push(list[list.length - 1]) + # Always include last two items + list[list.length - 2], + list[list.length - 1] + ] list = listTrimmed list diff --git a/internal_packages/thread-list/spec/thread-list-participants-spec.cjsx b/internal_packages/thread-list/spec/thread-list-participants-spec.cjsx index 1a5f20ade..44923196f 100644 --- a/internal_packages/thread-list/spec/thread-list-participants-spec.cjsx +++ b/internal_packages/thread-list/spec/thread-list-participants-spec.cjsx @@ -168,6 +168,52 @@ describe "ThreadListParticipants", -> if (!_.isEqual(participants.getParticipants(), scenario.out)) expect(scenario.name).toBe('correct') + describe "when getParticipants() called and current user is only sender", -> + beforeEach -> + @me = NamespaceStore.current().me() + @ben = new Contact(email: 'ben@nylas.com', name: 'ben') + @evan = new Contact(email: 'evan@nylas.com', name: 'evan') + @michael = new Contact(email: 'michael@nylas.com', name: 'michael') + @kavya = new Contact(email: 'kavya@nylas.com', name: 'kavya') + + getParticipants = (threadMetadata) -> + thread = new Thread() + thread.metadata = threadMetadata + participants = ReactTestUtils.renderIntoDocument( + + ) + participants.getParticipants() + + it "shows only recipients for emails sent from me to different recipients", -> + input = [new Message(unread: false, from: [@me], to: [@ben]) + new Message(unread: false, from: [@me], to: [@evan]) + new Message(unread: false, from: [@me], to: [@ben])] + actualOut = getParticipants input + expectedOut = [{contact: @ben, unread: false} + {contact: @evan, unread: false} + {contact: @ben, unread: false}] + expect(actualOut).toEqual expectedOut + + it "shows only first, spacer, second to last, and last recipients if recipients count > 3", -> + input = [new Message(unread: false, from: [@me], to: [@ben]) + new Message(unread: false, from: [@me], to: [@evan]) + new Message(unread: false, from: [@me], to: [@michael]) + new Message(unread: false, from: [@me], to: [@kavya])] + actualOut = getParticipants input + expectedOut = [{contact: @ben, unread: false} + {spacer: true} + {contact: @michael, unread: false} + {contact: @kavya, unread: false}] + expect(actualOut).toEqual expectedOut + + it "shows correct recipients even if only one email", -> + input = [new Message(unread: false, from: [@me], to: [@ben, @evan, @michael, @kavya])] + actualOut = getParticipants input + expectedOut = [{contact: @ben, unread: false} + {spacer: true} + {contact: @michael, unread: false} + {contact: @kavya, unread: false}] + expect(actualOut).toEqual expectedOut describe "when thread.messages is not available", -> it "correctly produces items for display in a wide range of scenarios", ->