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.

191 lines
5.5 KiB

  1. import {
  2. NOTIFICATIONS_UPDATE,
  3. NOTIFICATIONS_REFRESH_SUCCESS,
  4. NOTIFICATIONS_EXPAND_SUCCESS,
  5. NOTIFICATIONS_REFRESH_REQUEST,
  6. NOTIFICATIONS_EXPAND_REQUEST,
  7. NOTIFICATIONS_REFRESH_FAIL,
  8. NOTIFICATIONS_EXPAND_FAIL,
  9. NOTIFICATIONS_CLEAR,
  10. NOTIFICATIONS_SCROLL_TOP,
  11. NOTIFICATIONS_DELETE_MARKED_REQUEST,
  12. NOTIFICATIONS_DELETE_MARKED_SUCCESS,
  13. NOTIFICATION_MARK_FOR_DELETE,
  14. NOTIFICATIONS_DELETE_MARKED_FAIL,
  15. NOTIFICATIONS_ENTER_CLEARING_MODE,
  16. NOTIFICATIONS_MARK_ALL_FOR_DELETE,
  17. } from 'flavours/glitch/actions/notifications';
  18. import {
  19. ACCOUNT_BLOCK_SUCCESS,
  20. ACCOUNT_MUTE_SUCCESS,
  21. } from 'flavours/glitch/actions/accounts';
  22. import { TIMELINE_DELETE } from 'flavours/glitch/actions/timelines';
  23. import { Map as ImmutableMap, List as ImmutableList } from 'immutable';
  24. const initialState = ImmutableMap({
  25. items: ImmutableList(),
  26. next: null,
  27. top: true,
  28. unread: 0,
  29. loaded: false,
  30. isLoading: true,
  31. cleaningMode: false,
  32. // notification removal mark of new notifs loaded whilst cleaningMode is true.
  33. markNewForDelete: false,
  34. });
  35. const notificationToMap = (state, notification) => ImmutableMap({
  36. id: notification.id,
  37. type: notification.type,
  38. account: notification.account.id,
  39. markedForDelete: state.get('markNewForDelete'),
  40. status: notification.status ? notification.status.id : null,
  41. });
  42. const normalizeNotification = (state, notification) => {
  43. const top = state.get('top');
  44. if (!top) {
  45. state = state.update('unread', unread => unread + 1);
  46. }
  47. return state.update('items', list => {
  48. if (top && list.size > 40) {
  49. list = list.take(20);
  50. }
  51. return list.unshift(notificationToMap(state, notification));
  52. });
  53. };
  54. const normalizeNotifications = (state, notifications, next) => {
  55. let items = ImmutableList();
  56. const loaded = state.get('loaded');
  57. notifications.forEach((n, i) => {
  58. items = items.set(i, notificationToMap(state, n));
  59. });
  60. if (state.get('next') === null) {
  61. state = state.set('next', next);
  62. }
  63. return state
  64. .update('items', list => loaded ? items.concat(list) : list.concat(items))
  65. .set('loaded', true)
  66. .set('isLoading', false);
  67. };
  68. const appendNormalizedNotifications = (state, notifications, next) => {
  69. let items = ImmutableList();
  70. notifications.forEach((n, i) => {
  71. items = items.set(i, notificationToMap(state, n));
  72. });
  73. return state
  74. .update('items', list => list.concat(items))
  75. .set('next', next)
  76. .set('isLoading', false);
  77. };
  78. const filterNotifications = (state, relationship) => {
  79. return state.update('items', list => list.filterNot(item => item.get('account') === relationship.id));
  80. };
  81. const updateTop = (state, top) => {
  82. if (top) {
  83. state = state.set('unread', 0);
  84. }
  85. return state.set('top', top);
  86. };
  87. const deleteByStatus = (state, statusId) => {
  88. return state.update('items', list => list.filterNot(item => item.get('status') === statusId));
  89. };
  90. const markForDelete = (state, notificationId, yes) => {
  91. return state.update('items', list => list.map(item => {
  92. if(item.get('id') === notificationId) {
  93. return item.set('markedForDelete', yes);
  94. } else {
  95. return item;
  96. }
  97. }));
  98. };
  99. const markAllForDelete = (state, yes) => {
  100. return state.update('items', list => list.map(item => {
  101. if(yes !== null) {
  102. return item.set('markedForDelete', yes);
  103. } else {
  104. return item.set('markedForDelete', !item.get('markedForDelete'));
  105. }
  106. }));
  107. };
  108. const unmarkAllForDelete = (state) => {
  109. return state.update('items', list => list.map(item => item.set('markedForDelete', false)));
  110. };
  111. const deleteMarkedNotifs = (state) => {
  112. return state.update('items', list => list.filterNot(item => item.get('markedForDelete')));
  113. };
  114. export default function notifications(state = initialState, action) {
  115. let st;
  116. switch(action.type) {
  117. case NOTIFICATIONS_REFRESH_REQUEST:
  118. case NOTIFICATIONS_EXPAND_REQUEST:
  119. case NOTIFICATIONS_DELETE_MARKED_REQUEST:
  120. return state.set('isLoading', true);
  121. case NOTIFICATIONS_DELETE_MARKED_FAIL:
  122. case NOTIFICATIONS_REFRESH_FAIL:
  123. case NOTIFICATIONS_EXPAND_FAIL:
  124. return state.set('isLoading', false);
  125. case NOTIFICATIONS_SCROLL_TOP:
  126. return updateTop(state, action.top);
  127. case NOTIFICATIONS_UPDATE:
  128. return normalizeNotification(state, action.notification);
  129. case NOTIFICATIONS_REFRESH_SUCCESS:
  130. return normalizeNotifications(state, action.notifications, action.next);
  131. case NOTIFICATIONS_EXPAND_SUCCESS:
  132. return appendNormalizedNotifications(state, action.notifications, action.next);
  133. case ACCOUNT_BLOCK_SUCCESS:
  134. case ACCOUNT_MUTE_SUCCESS:
  135. return filterNotifications(state, action.relationship);
  136. case NOTIFICATIONS_CLEAR:
  137. return state.set('items', ImmutableList()).set('next', null);
  138. case TIMELINE_DELETE:
  139. return deleteByStatus(state, action.id);
  140. case NOTIFICATION_MARK_FOR_DELETE:
  141. return markForDelete(state, action.id, action.yes);
  142. case NOTIFICATIONS_DELETE_MARKED_SUCCESS:
  143. return deleteMarkedNotifs(state).set('isLoading', false);
  144. case NOTIFICATIONS_ENTER_CLEARING_MODE:
  145. st = state.set('cleaningMode', action.yes);
  146. if (!action.yes) {
  147. return unmarkAllForDelete(st).set('markNewForDelete', false);
  148. } else {
  149. return st;
  150. }
  151. case NOTIFICATIONS_MARK_ALL_FOR_DELETE:
  152. st = state;
  153. if (action.yes === null) {
  154. // Toggle - this is a bit confusing, as it toggles the all-none mode
  155. //st = st.set('markNewForDelete', !st.get('markNewForDelete'));
  156. } else {
  157. st = st.set('markNewForDelete', action.yes);
  158. }
  159. return markAllForDelete(st, action.yes);
  160. default:
  161. return state;
  162. }
  163. };