|
|
@@ -1,5 +1,6 @@
|
|
1
|
1
|
// @flow
|
|
2
|
2
|
|
|
|
3
|
+import md5 from 'js-md5';
|
|
3
|
4
|
import RNCalendarEvents from 'react-native-calendar-events';
|
|
4
|
5
|
|
|
5
|
6
|
import { APP_WILL_MOUNT } from '../app';
|
|
|
@@ -253,7 +254,10 @@ function _parseCalendarEntry(event, knownDomains) {
|
|
253
|
254
|
}
|
|
254
|
255
|
|
|
255
|
256
|
/**
|
|
256
|
|
- * Updates the calendar entries in redux when new list is received.
|
|
|
257
|
+ * Updates the calendar entries in redux when new list is received. This
|
|
|
258
|
+ * function also dedupes the list of entries based on exact match for title, URL
|
|
|
259
|
+ * and time of the day and then sorts by time and limits the list
|
|
|
260
|
+ * to MAX_LIST_LENGTH.
|
|
257
|
261
|
*
|
|
258
|
262
|
* XXX The function's {@code this} is the redux store.
|
|
259
|
263
|
*
|
|
|
@@ -265,24 +269,39 @@ function _updateCalendarEntries(events) {
|
|
265
|
269
|
if (events && events.length) {
|
|
266
|
270
|
// eslint-disable-next-line no-invalid-this
|
|
267
|
271
|
const { dispatch, getState } = this;
|
|
268
|
|
-
|
|
269
|
272
|
const knownDomains = getState()['features/base/known-domains'];
|
|
270
|
|
- const eventList = [];
|
|
271
|
|
-
|
|
272
|
273
|
const now = Date.now();
|
|
|
274
|
+ const entryMap = new Map();
|
|
273
|
275
|
|
|
274
|
276
|
for (const event of events) {
|
|
275
|
277
|
const calendarEntry = _parseCalendarEntry(event, knownDomains);
|
|
276
|
278
|
|
|
277
|
|
- calendarEntry
|
|
278
|
|
- && calendarEntry.endDate > now
|
|
279
|
|
- && eventList.push(calendarEntry);
|
|
|
279
|
+ if (calendarEntry && calendarEntry.endDate > now) {
|
|
|
280
|
+ // This is the data structure we'll try to match all entries to.
|
|
|
281
|
+ // The smaller the better, hence the single letter field names.
|
|
|
282
|
+ const eventMatchHash = md5.hex(JSON.stringify({
|
|
|
283
|
+ d: new Date(calendarEntry.startDate).toTimeString(),
|
|
|
284
|
+ t: calendarEntry.title,
|
|
|
285
|
+ u: calendarEntry.url
|
|
|
286
|
+ }));
|
|
|
287
|
+ const existingEntry = entryMap.get(eventMatchHash);
|
|
|
288
|
+
|
|
|
289
|
+ // We need to dedupe the list based on title, URL and time of
|
|
|
290
|
+ // the day, and only show the first occurence. So if there was
|
|
|
291
|
+ // no matcing entry or there was, but its a later event, we
|
|
|
292
|
+ // overwrite/save it in the map.
|
|
|
293
|
+ if (!existingEntry
|
|
|
294
|
+ || existingEntry.startDate > event.startDate) {
|
|
|
295
|
+ entryMap.set(eventMatchHash, calendarEntry);
|
|
|
296
|
+ }
|
|
|
297
|
+ }
|
|
280
|
298
|
}
|
|
281
|
299
|
|
|
282
|
300
|
dispatch(
|
|
283
|
301
|
setCalendarEvents(
|
|
284
|
|
- eventList
|
|
|
302
|
+ Array.from(entryMap.values())
|
|
285
|
303
|
.sort((a, b) => a.startDate - b.startDate)
|
|
286
|
|
- .slice(0, MAX_LIST_LENGTH)));
|
|
|
304
|
+ .slice(0, MAX_LIST_LENGTH)
|
|
|
305
|
+ ));
|
|
287
|
306
|
}
|
|
288
|
307
|
}
|