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.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. import { IStore } from '../app/types';
  2. import { getCurrentConference } from '../base/conference/functions';
  3. import { getLocalParticipant } from '../base/participants/functions';
  4. import { IParticipant } from '../base/participants/types';
  5. import { LOBBY_CHAT_INITIALIZED } from '../lobby/constants';
  6. import {
  7. ADD_MESSAGE,
  8. ADD_MESSAGE_REACTION,
  9. CLEAR_MESSAGES,
  10. CLOSE_CHAT,
  11. EDIT_MESSAGE,
  12. REMOVE_LOBBY_CHAT_PARTICIPANT,
  13. SEND_MESSAGE,
  14. SEND_REACTION,
  15. SET_IS_POLL_TAB_FOCUSED,
  16. SET_LOBBY_CHAT_ACTIVE_STATE,
  17. SET_LOBBY_CHAT_RECIPIENT,
  18. SET_PRIVATE_MESSAGE_RECIPIENT
  19. } from './actionTypes';
  20. /**
  21. * Adds a chat message to the collection of messages.
  22. *
  23. * @param {Object} messageDetails - The chat message to save.
  24. * @param {string} messageDetails.displayName - The displayName of the
  25. * participant that authored the message.
  26. * @param {boolean} messageDetails.hasRead - Whether or not to immediately mark
  27. * the message as read.
  28. * @param {string} messageDetails.message - The received message to display.
  29. * @param {string} messageDetails.messageType - The kind of message, such as
  30. * "error" or "local" or "remote".
  31. * @param {string} messageDetails.timestamp - A timestamp to display for when
  32. * the message was received.
  33. * @param {string} messageDetails.isReaction - Whether or not the
  34. * message is a reaction message.
  35. * @returns {{
  36. * type: ADD_MESSAGE,
  37. * displayName: string,
  38. * hasRead: boolean,
  39. * message: string,
  40. * messageType: string,
  41. * timestamp: string,
  42. * isReaction: boolean
  43. * }}
  44. */
  45. export function addMessage(messageDetails: Object) {
  46. return {
  47. type: ADD_MESSAGE,
  48. ...messageDetails
  49. };
  50. }
  51. /**
  52. * Adds a reaction to a chat message.
  53. *
  54. * @param {Object} reactionDetails - The reaction to add.
  55. * @param {string} reactionDetails.participantId - The ID of the message to react to.
  56. * @param {string} reactionDetails.reactionList - The reaction to add.
  57. * @param {string} reactionDetails.messageId - The receiver ID of the reaction.
  58. * @returns {{
  59. * type: ADD_MESSAGE_REACTION,
  60. * participantId: string,
  61. * reactionList: string[],
  62. * messageId: string
  63. * }}
  64. */
  65. export function addMessageReaction(reactionDetails: Object) {
  66. return {
  67. type: ADD_MESSAGE_REACTION,
  68. ...reactionDetails
  69. };
  70. }
  71. /**
  72. * Edits an existing chat message.
  73. *
  74. * @param {Object} message - The chat message to edit/override. The messages will be matched from the state
  75. * comparing the messageId.
  76. * @returns {{
  77. * type: EDIT_MESSAGE,
  78. * message: Object
  79. * }}
  80. */
  81. export function editMessage(message: Object) {
  82. return {
  83. type: EDIT_MESSAGE,
  84. message
  85. };
  86. }
  87. /**
  88. * Clears the chat messages in Redux.
  89. *
  90. * @returns {{
  91. * type: CLEAR_MESSAGES
  92. * }}
  93. */
  94. export function clearMessages() {
  95. return {
  96. type: CLEAR_MESSAGES
  97. };
  98. }
  99. /**
  100. * Action to signal the closing of the chat dialog.
  101. *
  102. * @returns {{
  103. * type: CLOSE_CHAT
  104. * }}
  105. */
  106. export function closeChat() {
  107. return {
  108. type: CLOSE_CHAT
  109. };
  110. }
  111. /**
  112. * Sends a chat message to everyone in the conference.
  113. *
  114. * @param {string} message - The chat message to send out.
  115. * @param {boolean} ignorePrivacy - True if the privacy notification should be ignored.
  116. * @returns {{
  117. * type: SEND_MESSAGE,
  118. * ignorePrivacy: boolean,
  119. * message: string
  120. * }}
  121. */
  122. export function sendMessage(message: string, ignorePrivacy = false) {
  123. return {
  124. type: SEND_MESSAGE,
  125. ignorePrivacy,
  126. message
  127. };
  128. }
  129. /**
  130. * Sends a reaction to a message.
  131. *
  132. * @param {string} reaction - The reaction to send.
  133. * @param {string} messageId - The message ID to react to.
  134. * @param {string} receiverId - The receiver ID of the reaction.
  135. * @returns {Function}
  136. */
  137. export function sendReaction(reaction: string, messageId: string, receiverId?: string) {
  138. return {
  139. type: SEND_REACTION,
  140. reaction,
  141. messageId,
  142. receiverId
  143. };
  144. }
  145. /**
  146. * Initiates the sending of a private message to the supplied participant.
  147. *
  148. * @param {IParticipant} participant - The participant to set the recipient to.
  149. * @returns {{
  150. * participant: IParticipant,
  151. * type: SET_PRIVATE_MESSAGE_RECIPIENT
  152. * }}
  153. */
  154. export function setPrivateMessageRecipient(participant?: Object) {
  155. return {
  156. participant,
  157. type: SET_PRIVATE_MESSAGE_RECIPIENT
  158. };
  159. }
  160. /**
  161. * Set the value of _isPollsTabFocused.
  162. *
  163. * @param {boolean} isPollsTabFocused - The new value for _isPollsTabFocused.
  164. * @returns {Function}
  165. */
  166. export function setIsPollsTabFocused(isPollsTabFocused: boolean) {
  167. return {
  168. isPollsTabFocused,
  169. type: SET_IS_POLL_TAB_FOCUSED
  170. };
  171. }
  172. /**
  173. * Initiates the sending of messages between a moderator and a lobby attendee.
  174. *
  175. * @param {Object} lobbyChatInitializedInfo - The information about the attendee and the moderator
  176. * that is going to chat.
  177. *
  178. * @returns {Function}
  179. */
  180. export function onLobbyChatInitialized(lobbyChatInitializedInfo: { attendee: IParticipant; moderator: IParticipant; }) {
  181. return async (dispatch: IStore['dispatch'], getState: IStore['getState']) => {
  182. const state = getState();
  183. const conference = getCurrentConference(state);
  184. const lobbyLocalId = conference?.myLobbyUserId();
  185. if (!lobbyLocalId) {
  186. return;
  187. }
  188. if (lobbyChatInitializedInfo.moderator.id === lobbyLocalId) {
  189. dispatch({
  190. type: SET_LOBBY_CHAT_RECIPIENT,
  191. participant: lobbyChatInitializedInfo.attendee,
  192. open: true
  193. });
  194. }
  195. if (lobbyChatInitializedInfo.attendee.id === lobbyLocalId) {
  196. return dispatch({
  197. type: SET_LOBBY_CHAT_RECIPIENT,
  198. participant: lobbyChatInitializedInfo.moderator,
  199. open: false
  200. });
  201. }
  202. };
  203. }
  204. /**
  205. * Sets the lobby room's chat active state.
  206. *
  207. * @param {boolean} value - The active state.
  208. *
  209. * @returns {Object}
  210. */
  211. export function setLobbyChatActiveState(value: boolean) {
  212. return {
  213. type: SET_LOBBY_CHAT_ACTIVE_STATE,
  214. payload: value
  215. };
  216. }
  217. /**
  218. * Removes lobby type messages.
  219. *
  220. * @param {boolean} removeLobbyChatMessages - Should remove messages from chat (works only for accepted users).
  221. * If not specified, it will delete all lobby messages.
  222. *
  223. * @returns {Object}
  224. */
  225. export function removeLobbyChatParticipant(removeLobbyChatMessages?: boolean) {
  226. return {
  227. type: REMOVE_LOBBY_CHAT_PARTICIPANT,
  228. removeLobbyChatMessages
  229. };
  230. }
  231. /**
  232. * Handles initial setup of lobby message between
  233. * Moderator and participant.
  234. *
  235. * @param {string} participantId - The participant id.
  236. *
  237. * @returns {Object}
  238. */
  239. export function handleLobbyChatInitialized(participantId: string) {
  240. return async (dispatch: IStore['dispatch'], getState: IStore['getState']) => {
  241. if (!participantId) {
  242. return;
  243. }
  244. const state = getState();
  245. const conference = state['features/base/conference'].conference;
  246. const { knockingParticipants } = state['features/lobby'];
  247. const { lobbyMessageRecipient } = state['features/chat'];
  248. const me = getLocalParticipant(state);
  249. const lobbyLocalId = conference?.myLobbyUserId();
  250. if (lobbyMessageRecipient && lobbyMessageRecipient.id === participantId) {
  251. return dispatch(setLobbyChatActiveState(true));
  252. }
  253. const attendee = knockingParticipants.find(p => p.id === participantId);
  254. if (attendee && attendee.chattingWithModerator === lobbyLocalId) {
  255. return dispatch({
  256. type: SET_LOBBY_CHAT_RECIPIENT,
  257. participant: attendee,
  258. open: true
  259. });
  260. }
  261. if (!attendee) {
  262. return;
  263. }
  264. const payload = { type: LOBBY_CHAT_INITIALIZED,
  265. moderator: {
  266. ...me,
  267. name: 'Moderator',
  268. id: lobbyLocalId
  269. },
  270. attendee };
  271. // notify attendee privately.
  272. conference?.sendLobbyMessage(payload, attendee.id);
  273. // notify other moderators.
  274. return conference?.sendLobbyMessage(payload);
  275. };
  276. }