diff --git a/react/features/calendar-sync/middleware.js b/react/features/calendar-sync/middleware.js index e8816b5c6..2b1937d88 100644 --- a/react/features/calendar-sync/middleware.js +++ b/react/features/calendar-sync/middleware.js @@ -1,5 +1,6 @@ // @flow +import md5 from 'js-md5'; import RNCalendarEvents from 'react-native-calendar-events'; import { APP_WILL_MOUNT } from '../app'; @@ -253,7 +254,10 @@ function _parseCalendarEntry(event, knownDomains) { } /** - * Updates the calendar entries in redux when new list is received. + * Updates the calendar entries in redux when new list is received. This + * function also dedupes the list of entries based on exact match for title, URL + * and time of the day and then sorts by time and limits the list + * to MAX_LIST_LENGTH. * * XXX The function's {@code this} is the redux store. * @@ -265,24 +269,39 @@ function _updateCalendarEntries(events) { if (events && events.length) { // eslint-disable-next-line no-invalid-this const { dispatch, getState } = this; - const knownDomains = getState()['features/base/known-domains']; - const eventList = []; - const now = Date.now(); + const entryMap = new Map(); for (const event of events) { const calendarEntry = _parseCalendarEntry(event, knownDomains); - calendarEntry - && calendarEntry.endDate > now - && eventList.push(calendarEntry); + if (calendarEntry && calendarEntry.endDate > now) { + // This is the data structure we'll try to match all entries to. + // The smaller the better, hence the single letter field names. + const eventMatchHash = md5.hex(JSON.stringify({ + d: new Date(calendarEntry.startDate).toTimeString(), + t: calendarEntry.title, + u: calendarEntry.url + })); + const existingEntry = entryMap.get(eventMatchHash); + + // We need to dedupe the list based on title, URL and time of + // the day, and only show the first occurence. So if there was + // no matcing entry or there was, but its a later event, we + // overwrite/save it in the map. + if (!existingEntry + || existingEntry.startDate > event.startDate) { + entryMap.set(eventMatchHash, calendarEntry); + } + } } dispatch( setCalendarEvents( - eventList + Array.from(entryMap.values()) .sort((a, b) => a.startDate - b.startDate) - .slice(0, MAX_LIST_LENGTH))); + .slice(0, MAX_LIST_LENGTH) + )); } }