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