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.

reducer.ts 4.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. import { v4 as uuidv4 } from 'uuid';
  2. import { ILocalParticipant, IParticipant } from '../base/participants/types';
  3. import ReducerRegistry from '../base/redux/ReducerRegistry';
  4. import {
  5. ADD_MESSAGE,
  6. CLEAR_MESSAGES,
  7. CLOSE_CHAT,
  8. EDIT_MESSAGE,
  9. OPEN_CHAT,
  10. REMOVE_LOBBY_CHAT_PARTICIPANT,
  11. SET_IS_POLL_TAB_FOCUSED,
  12. SET_LOBBY_CHAT_ACTIVE_STATE,
  13. SET_LOBBY_CHAT_RECIPIENT,
  14. SET_PRIVATE_MESSAGE_RECIPIENT
  15. } from './actionTypes';
  16. const DEFAULT_STATE = {
  17. isOpen: false,
  18. isPollsTabFocused: false,
  19. lastReadMessage: undefined,
  20. messages: [],
  21. nbUnreadMessages: 0,
  22. privateMessageRecipient: undefined,
  23. lobbyMessageRecipient: undefined,
  24. isLobbyChatActive: false
  25. };
  26. export interface IMessage {
  27. displayName: string;
  28. error?: Object;
  29. id: string;
  30. isReaction: boolean;
  31. lobbyChat: boolean;
  32. message: string;
  33. messageId: string;
  34. messageType: string;
  35. privateMessage: boolean;
  36. recipient: string;
  37. timestamp: number;
  38. }
  39. export interface IChatState {
  40. isLobbyChatActive: boolean;
  41. isOpen: boolean;
  42. isPollsTabFocused: boolean;
  43. lastReadMessage?: IMessage;
  44. lobbyMessageRecipient?: {
  45. id: string;
  46. name: string;
  47. } | ILocalParticipant;
  48. messages: IMessage[];
  49. nbUnreadMessages: number;
  50. privateMessageRecipient?: IParticipant;
  51. }
  52. ReducerRegistry.register<IChatState>('features/chat', (state = DEFAULT_STATE, action): IChatState => {
  53. switch (action.type) {
  54. case ADD_MESSAGE: {
  55. const newMessage: IMessage = {
  56. displayName: action.displayName,
  57. error: action.error,
  58. id: action.id,
  59. isReaction: action.isReaction,
  60. messageId: uuidv4(),
  61. messageType: action.messageType,
  62. message: action.message,
  63. privateMessage: action.privateMessage,
  64. lobbyChat: action.lobbyChat,
  65. recipient: action.recipient,
  66. timestamp: action.timestamp
  67. };
  68. // React native, unlike web, needs a reverse sorted message list.
  69. const messages = navigator.product === 'ReactNative'
  70. ? [
  71. newMessage,
  72. ...state.messages
  73. ]
  74. : [
  75. ...state.messages,
  76. newMessage
  77. ];
  78. return {
  79. ...state,
  80. lastReadMessage:
  81. action.hasRead ? newMessage : state.lastReadMessage,
  82. nbUnreadMessages: state.isPollsTabFocused ? state.nbUnreadMessages + 1 : state.nbUnreadMessages,
  83. messages
  84. };
  85. }
  86. case CLEAR_MESSAGES:
  87. return {
  88. ...state,
  89. lastReadMessage: undefined,
  90. messages: []
  91. };
  92. case EDIT_MESSAGE: {
  93. let found = false;
  94. const newMessage = action.message;
  95. const messages = state.messages.map(m => {
  96. if (m.messageId === newMessage.messageId) {
  97. found = true;
  98. return newMessage;
  99. }
  100. return m;
  101. });
  102. // no change
  103. if (!found) {
  104. return state;
  105. }
  106. return {
  107. ...state,
  108. messages
  109. };
  110. }
  111. case SET_PRIVATE_MESSAGE_RECIPIENT:
  112. return {
  113. ...state,
  114. privateMessageRecipient: action.participant
  115. };
  116. case OPEN_CHAT:
  117. return {
  118. ...state,
  119. isOpen: true,
  120. privateMessageRecipient: action.participant
  121. };
  122. case CLOSE_CHAT:
  123. return {
  124. ...state,
  125. isOpen: false,
  126. lastReadMessage: state.messages[
  127. navigator.product === 'ReactNative' ? 0 : state.messages.length - 1],
  128. privateMessageRecipient: action.participant,
  129. isLobbyChatActive: false
  130. };
  131. case SET_IS_POLL_TAB_FOCUSED: {
  132. return {
  133. ...state,
  134. isPollsTabFocused: action.isPollsTabFocused,
  135. nbUnreadMessages: 0
  136. }; }
  137. case SET_LOBBY_CHAT_RECIPIENT:
  138. return {
  139. ...state,
  140. isLobbyChatActive: true,
  141. lobbyMessageRecipient: action.participant,
  142. privateMessageRecipient: undefined,
  143. isOpen: action.open
  144. };
  145. case SET_LOBBY_CHAT_ACTIVE_STATE:
  146. return {
  147. ...state,
  148. isLobbyChatActive: action.payload,
  149. isOpen: action.payload || state.isOpen,
  150. privateMessageRecipient: undefined
  151. };
  152. case REMOVE_LOBBY_CHAT_PARTICIPANT:
  153. return {
  154. ...state,
  155. messages: state.messages.filter(m => {
  156. if (action.removeLobbyChatMessages) {
  157. return !m.lobbyChat;
  158. }
  159. return true;
  160. }),
  161. isOpen: state.isOpen && state.isLobbyChatActive ? false : state.isOpen,
  162. isLobbyChatActive: false,
  163. lobbyMessageRecipient: undefined
  164. };
  165. }
  166. return state;
  167. });