You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

124 lines
3.7 KiB

  1. import {
  2. NOTIFICATIONS_UPDATE,
  3. NOTIFICATIONS_EXPAND_SUCCESS,
  4. NOTIFICATIONS_EXPAND_REQUEST,
  5. NOTIFICATIONS_EXPAND_FAIL,
  6. NOTIFICATIONS_FILTER_SET,
  7. NOTIFICATIONS_CLEAR,
  8. NOTIFICATIONS_SCROLL_TOP,
  9. } from '../actions/notifications';
  10. import {
  11. ACCOUNT_BLOCK_SUCCESS,
  12. ACCOUNT_MUTE_SUCCESS,
  13. } from '../actions/accounts';
  14. import { TIMELINE_DELETE, TIMELINE_DISCONNECT } from '../actions/timelines';
  15. import { Map as ImmutableMap, List as ImmutableList } from 'immutable';
  16. import compareId from '../compare_id';
  17. const initialState = ImmutableMap({
  18. items: ImmutableList(),
  19. hasMore: true,
  20. top: true,
  21. unread: 0,
  22. isLoading: false,
  23. });
  24. const notificationToMap = notification => ImmutableMap({
  25. id: notification.id,
  26. type: notification.type,
  27. account: notification.account.id,
  28. created_at: notification.created_at,
  29. status: notification.status ? notification.status.id : null,
  30. });
  31. const normalizeNotification = (state, notification) => {
  32. const top = state.get('top');
  33. if (!top) {
  34. state = state.update('unread', unread => unread + 1);
  35. }
  36. return state.update('items', list => {
  37. if (top && list.size > 40) {
  38. list = list.take(20);
  39. }
  40. return list.unshift(notificationToMap(notification));
  41. });
  42. };
  43. const expandNormalizedNotifications = (state, notifications, next) => {
  44. let items = ImmutableList();
  45. notifications.forEach((n, i) => {
  46. items = items.set(i, notificationToMap(n));
  47. });
  48. return state.withMutations(mutable => {
  49. if (!items.isEmpty()) {
  50. mutable.update('items', list => {
  51. const lastIndex = 1 + list.findLastIndex(
  52. item => item !== null && (compareId(item.get('id'), items.last().get('id')) > 0 || item.get('id') === items.last().get('id'))
  53. );
  54. const firstIndex = 1 + list.take(lastIndex).findLastIndex(
  55. item => item !== null && compareId(item.get('id'), items.first().get('id')) > 0
  56. );
  57. return list.take(firstIndex).concat(items, list.skip(lastIndex));
  58. });
  59. }
  60. if (!next) {
  61. mutable.set('hasMore', false);
  62. }
  63. mutable.set('isLoading', false);
  64. });
  65. };
  66. const filterNotifications = (state, relationship) => {
  67. return state.update('items', list => list.filterNot(item => item !== null && item.get('account') === relationship.id));
  68. };
  69. const updateTop = (state, top) => {
  70. if (top) {
  71. state = state.set('unread', 0);
  72. }
  73. return state.set('top', top);
  74. };
  75. const deleteByStatus = (state, statusId) => {
  76. return state.update('items', list => list.filterNot(item => item !== null && item.get('status') === statusId));
  77. };
  78. export default function notifications(state = initialState, action) {
  79. switch(action.type) {
  80. case NOTIFICATIONS_EXPAND_REQUEST:
  81. return state.set('isLoading', true);
  82. case NOTIFICATIONS_EXPAND_FAIL:
  83. return state.set('isLoading', false);
  84. case NOTIFICATIONS_FILTER_SET:
  85. return state.set('items', ImmutableList()).set('hasMore', true);
  86. case NOTIFICATIONS_SCROLL_TOP:
  87. return updateTop(state, action.top);
  88. case NOTIFICATIONS_UPDATE:
  89. return normalizeNotification(state, action.notification);
  90. case NOTIFICATIONS_EXPAND_SUCCESS:
  91. return expandNormalizedNotifications(state, action.notifications, action.next);
  92. case ACCOUNT_BLOCK_SUCCESS:
  93. case ACCOUNT_MUTE_SUCCESS:
  94. return action.relationship.muting_notifications ? filterNotifications(state, action.relationship) : state;
  95. case NOTIFICATIONS_CLEAR:
  96. return state.set('items', ImmutableList()).set('hasMore', false);
  97. case TIMELINE_DELETE:
  98. return deleteByStatus(state, action.id);
  99. case TIMELINE_DISCONNECT:
  100. return action.timeline === 'home' ?
  101. state.update('items', items => items.first() ? items.unshift(null) : items) :
  102. state;
  103. default:
  104. return state;
  105. }
  106. };