您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

reducer.ts 4.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. import { getURLWithoutParamsNormalized } from '../base/connection/utils';
  2. import PersistenceRegistry from '../base/redux/PersistenceRegistry';
  3. import ReducerRegistry from '../base/redux/ReducerRegistry';
  4. import {
  5. DELETE_RECENT_LIST_ENTRY,
  6. _STORE_CURRENT_CONFERENCE,
  7. _UPDATE_CONFERENCE_DURATION
  8. } from './actionTypes';
  9. // eslint-disable-next-line lines-around-comment
  10. // @ts-ignore
  11. import { isRecentListEnabled } from './functions';
  12. interface IRecent {
  13. conference: string;
  14. date: number;
  15. duration: number;
  16. }
  17. export type IRecentListState = IRecent[];
  18. /**
  19. * The default/initial redux state of the feature {@code recent-list}.
  20. *
  21. * @type {IRecentListState}
  22. */
  23. const DEFAULT_STATE: IRecentListState = [];
  24. /**
  25. * The max size of the list.
  26. *
  27. * @type {number}
  28. */
  29. export const MAX_LIST_SIZE = 30;
  30. /**
  31. * The redux subtree of this feature.
  32. */
  33. const STORE_NAME = 'features/recent-list';
  34. /**
  35. * Sets up the persistence of the feature {@code recent-list}.
  36. */
  37. PersistenceRegistry.register(STORE_NAME);
  38. /**
  39. * Reduces redux actions for the purposes of the feature {@code recent-list}.
  40. */
  41. ReducerRegistry.register<IRecentListState>(STORE_NAME, (state = DEFAULT_STATE, action): IRecentListState => {
  42. if (isRecentListEnabled()) {
  43. switch (action.type) {
  44. case DELETE_RECENT_LIST_ENTRY:
  45. return _deleteRecentListEntry(state, action.entryId);
  46. case _STORE_CURRENT_CONFERENCE:
  47. return _storeCurrentConference(state, action);
  48. case _UPDATE_CONFERENCE_DURATION:
  49. return _updateConferenceDuration(state, action);
  50. default:
  51. return state;
  52. }
  53. }
  54. return state;
  55. });
  56. /**
  57. * Deletes a recent list entry based on the url and date of the item.
  58. *
  59. * @param {IRecentListState} state - The Redux state.
  60. * @param {Object} entryId - The ID object of the entry.
  61. * @returns {IRecentListState}
  62. */
  63. function _deleteRecentListEntry(
  64. state: Array<IRecent>, entryId: { date: number; url: string; }): Array<IRecent> {
  65. return state.filter(entry =>
  66. entry.conference !== entryId.url || entry.date !== entryId.date);
  67. }
  68. /**
  69. * Adds a new list entry to the redux store.
  70. *
  71. * @param {IRecentListState} state - The redux state of the feature {@code recent-list}.
  72. * @param {Object} action - The redux action.
  73. * @returns {Object}
  74. */
  75. function _storeCurrentConference(state: IRecentListState, { locationURL }: { locationURL: { href: string; }; }) {
  76. const conference = locationURL.href;
  77. // If the current conference is already in the list, we remove it to re-add
  78. // it to the top.
  79. const nextState
  80. = state.filter(e => !_urlStringEquals(e.conference, conference));
  81. // The list is a reverse-sorted (i.e. the newer elements are at the end).
  82. nextState.push({
  83. conference,
  84. date: Date.now(),
  85. duration: 0 // We don't have the duration yet!
  86. });
  87. // Ensure the list doesn't exceed a/the maximum size.
  88. nextState.splice(0, nextState.length - MAX_LIST_SIZE);
  89. return nextState;
  90. }
  91. /**
  92. * Updates the conference length when left.
  93. *
  94. * @param {IRecentListState} state - The redux state of the feature {@code recent-list}.
  95. * @param {Object} action - The redux action.
  96. * @returns {Object} The next redux state of the feature {@code recent-list}.
  97. */
  98. function _updateConferenceDuration(state: IRecentListState, { locationURL }: { locationURL: { href: string; }; }) {
  99. if (locationURL?.href && state.length) {
  100. const mostRecentIndex = state.length - 1;
  101. const mostRecent = state[mostRecentIndex];
  102. if (_urlStringEquals(mostRecent.conference, locationURL.href)) {
  103. // The last conference start was stored so we need to update the
  104. // length.
  105. const nextMostRecent = {
  106. ...mostRecent,
  107. duration: Date.now() - mostRecent.date
  108. };
  109. // Shallow copy to avoid in-place modification.
  110. const nextState = state.slice();
  111. nextState[mostRecentIndex] = nextMostRecent;
  112. return nextState;
  113. }
  114. }
  115. return state;
  116. }
  117. /**
  118. * Determines whether two specific URL {@code strings} are equal in the sense
  119. * that they identify one and the same conference resource (irrespective of
  120. * time) for the purposes of the feature {@code recent-list}.
  121. *
  122. * @param {string} a - The URL {@code string} to test for equality to {@code b}.
  123. * @param {string} b - The URL {@code string} to test for equality to {@code a}.
  124. * @returns {boolean}
  125. */
  126. function _urlStringEquals(a: string, b: string) {
  127. const aHref = getURLWithoutParamsNormalized(new URL(a));
  128. const bHref = getURLWithoutParamsNormalized(new URL(b));
  129. return aHref === bHref;
  130. }