threads.js 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. import moment from 'moment';
  2. import concatUnique from 'misago/utils/concat-unique';
  3. export const APPEND_THREADS = 'APPEND_THREADS';
  4. export const DELETE_THREAD = 'DELETE_THREAD';
  5. export const FILTER_THREADS = 'FILTER_THREADS';
  6. export const HYDRATE_THREADS = 'HYDRATE_THREADS';
  7. export const PATCH_THREAD = 'PATCH_THREAD';
  8. export const SORT_THREADS = 'SORT_THREADS';
  9. export const MODERATION_PERMISSIONS = [
  10. 'can_announce',
  11. 'can_approve',
  12. 'can_close',
  13. 'can_hide',
  14. 'can_move',
  15. 'can_merge',
  16. 'can_pin',
  17. 'can_review'
  18. ];
  19. export function append(items, sorting) {
  20. return {
  21. type: APPEND_THREADS,
  22. items,
  23. sorting
  24. };
  25. }
  26. export function deleteThread(thread) {
  27. return {
  28. type: DELETE_THREAD,
  29. thread
  30. };
  31. }
  32. export function filterThreads(category, categoriesMap) {
  33. return {
  34. type: FILTER_THREADS,
  35. category,
  36. categoriesMap
  37. };
  38. }
  39. export function hydrate(items) {
  40. return {
  41. type: HYDRATE_THREADS,
  42. items
  43. };
  44. }
  45. export function patch(thread, patch, sorting=null) {
  46. return {
  47. type: PATCH_THREAD,
  48. thread,
  49. patch,
  50. sorting
  51. };
  52. }
  53. export function sort(sorting) {
  54. return {
  55. type: SORT_THREADS,
  56. sorting
  57. };
  58. }
  59. export function getThreadModerationOptions(thread_acl) {
  60. let options = [];
  61. MODERATION_PERMISSIONS.forEach(function(perm) {
  62. if (thread_acl[perm]) {
  63. options.push(perm);
  64. }
  65. });
  66. return options;
  67. }
  68. export function hydrateThread(thread) {
  69. return Object.assign({}, thread, {
  70. started_on: moment(thread.started_on),
  71. last_post_on: moment(thread.last_post_on),
  72. moderation: getThreadModerationOptions(thread.acl)
  73. });
  74. }
  75. export default function thread(state=[], action=null) {
  76. switch (action.type) {
  77. case APPEND_THREADS:
  78. const mergedState = concatUnique(action.items.map(hydrateThread), state);
  79. return mergedState.sort(action.sorting);
  80. case DELETE_THREAD:
  81. return state.filter(function(item) {
  82. return item.id !== action.thread.id;
  83. });
  84. case FILTER_THREADS:
  85. return state.filter(function(item) {
  86. const itemCategory = action.categoriesMap[item.category];
  87. if (itemCategory.lft >= action.category.lft && itemCategory.rght <= action.category.rght) {
  88. // same or sub category
  89. return true;
  90. } else if (item.weight == 2) {
  91. // globally pinned
  92. return true;
  93. } else {
  94. // thread moved outside displayed scope, hide it
  95. return false;
  96. }
  97. });
  98. case HYDRATE_THREADS:
  99. return action.items.map(hydrateThread);
  100. case PATCH_THREAD:
  101. const patchedState = state.map(function(item) {
  102. if (item.id === action.thread.id) {
  103. return Object.assign({}, item, action.patch);
  104. } else {
  105. return item;
  106. }
  107. });
  108. if (action.sorting) {
  109. return patchedState.sort(action.sorting);
  110. }
  111. return patchedState;
  112. case SORT_THREADS:
  113. return state.sort(action.sorting);
  114. default:
  115. return state;
  116. }
  117. }