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

actions.js 9.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317
  1. // @flow
  2. import throttle from 'lodash/throttle';
  3. import type { Dispatch } from 'redux';
  4. import { NOTIFICATIONS_ENABLED, getFeatureFlag } from '../base/flags';
  5. import { getParticipantCount } from '../base/participants/functions';
  6. import {
  7. CLEAR_NOTIFICATIONS,
  8. HIDE_NOTIFICATION,
  9. SET_NOTIFICATIONS_ENABLED,
  10. SHOW_NOTIFICATION
  11. } from './actionTypes';
  12. import {
  13. NOTIFICATION_ICON,
  14. NOTIFICATION_TIMEOUT_TYPE,
  15. NOTIFICATION_TIMEOUT,
  16. NOTIFICATION_TYPE,
  17. SILENT_JOIN_THRESHOLD,
  18. SILENT_LEFT_THRESHOLD
  19. } from './constants';
  20. /**
  21. * Function that returns notification timeout value based on notification timeout type.
  22. *
  23. * @param {string} type - Notification type.
  24. * @param {Object} notificationTimeouts - Config notification timeouts.
  25. * @returns {number}
  26. */
  27. function getNotificationTimeout(type: ?string, notificationTimeouts: ?Object) {
  28. if (type === NOTIFICATION_TIMEOUT_TYPE.SHORT) {
  29. return notificationTimeouts?.short ?? NOTIFICATION_TIMEOUT.SHORT;
  30. } else if (type === NOTIFICATION_TIMEOUT_TYPE.MEDIUM) {
  31. return notificationTimeouts?.medium ?? NOTIFICATION_TIMEOUT.MEDIUM;
  32. } else if (type === NOTIFICATION_TIMEOUT_TYPE.LONG) {
  33. return notificationTimeouts?.long ?? NOTIFICATION_TIMEOUT.LONG;
  34. }
  35. return NOTIFICATION_TIMEOUT.STICKY;
  36. }
  37. /**
  38. * Clears (removes) all the notifications.
  39. *
  40. * @returns {{
  41. * type: CLEAR_NOTIFICATIONS
  42. * }}
  43. */
  44. export function clearNotifications() {
  45. return {
  46. type: CLEAR_NOTIFICATIONS
  47. };
  48. }
  49. /**
  50. * Removes the notification with the passed in id.
  51. *
  52. * @param {string} uid - The unique identifier for the notification to be
  53. * removed.
  54. * @returns {{
  55. * type: HIDE_NOTIFICATION,
  56. * uid: string
  57. * }}
  58. */
  59. export function hideNotification(uid: string) {
  60. return {
  61. type: HIDE_NOTIFICATION,
  62. uid
  63. };
  64. }
  65. /**
  66. * Stops notifications from being displayed.
  67. *
  68. * @param {boolean} enabled - Whether or not notifications should display.
  69. * @returns {{
  70. * type: SET_NOTIFICATIONS_ENABLED,
  71. * enabled: boolean
  72. * }}
  73. */
  74. export function setNotificationsEnabled(enabled: boolean) {
  75. return {
  76. type: SET_NOTIFICATIONS_ENABLED,
  77. enabled
  78. };
  79. }
  80. /**
  81. * Queues an error notification for display.
  82. *
  83. * @param {Object} props - The props needed to show the notification component.
  84. * @param {string} type - Notification type.
  85. * @returns {Object}
  86. */
  87. export function showErrorNotification(props: Object, type: ?string) {
  88. return showNotification({
  89. ...props,
  90. appearance: NOTIFICATION_TYPE.ERROR
  91. }, type);
  92. }
  93. /**
  94. * Queues a notification for display.
  95. *
  96. * @param {Object} props - The props needed to show the notification component.
  97. * @param {string} type - Notification type.
  98. * @returns {Function}
  99. */
  100. export function showNotification(props: Object = {}, type: ?string) {
  101. return function(dispatch: Function, getState: Function) {
  102. const { notifications, notificationTimeouts } = getState()['features/base/config'];
  103. const enabledFlag = getFeatureFlag(getState(), NOTIFICATIONS_ENABLED, true);
  104. const shouldDisplay = enabledFlag
  105. && (!notifications
  106. || notifications.includes(props.descriptionKey)
  107. || notifications.includes(props.titleKey));
  108. if (shouldDisplay) {
  109. return dispatch({
  110. type: SHOW_NOTIFICATION,
  111. props,
  112. timeout: getNotificationTimeout(type, notificationTimeouts),
  113. uid: props.uid || window.Date.now().toString()
  114. });
  115. }
  116. };
  117. }
  118. /**
  119. * Queues a warning notification for display.
  120. *
  121. * @param {Object} props - The props needed to show the notification component.
  122. * @param {string} type - Notification type.
  123. * @returns {Object}
  124. */
  125. export function showWarningNotification(props: Object, type: ?string) {
  126. return showNotification({
  127. ...props,
  128. appearance: NOTIFICATION_TYPE.WARNING
  129. }, type);
  130. }
  131. /**
  132. * Queues a message notification for display.
  133. *
  134. * @param {Object} props - The props needed to show the notification component.
  135. * @param {string} type - Notification type.
  136. * @returns {Object}
  137. */
  138. export function showMessageNotification(props: Object, type: ?string) {
  139. return showNotification({
  140. ...props,
  141. concatText: true,
  142. titleKey: 'notify.chatMessages',
  143. appearance: NOTIFICATION_TYPE.NORMAL,
  144. icon: NOTIFICATION_ICON.MESSAGE
  145. }, type);
  146. }
  147. /**
  148. * An array of names of participants that have joined the conference. The array
  149. * is replaced with an empty array as notifications are displayed.
  150. *
  151. * @private
  152. * @type {string[]}
  153. */
  154. let joinedParticipantsNames = [];
  155. /**
  156. * A throttled internal function that takes the internal list of participant
  157. * names, {@code joinedParticipantsNames}, and triggers the display of a
  158. * notification informing of their joining.
  159. *
  160. * @private
  161. * @type {Function}
  162. */
  163. const _throttledNotifyParticipantConnected = throttle((dispatch: Dispatch<any>, getState: Function) => {
  164. const participantCount = getParticipantCount(getState());
  165. // Skip join notifications altogether for large meetings.
  166. if (participantCount > SILENT_JOIN_THRESHOLD) {
  167. joinedParticipantsNames = [];
  168. return;
  169. }
  170. const joinedParticipantsCount = joinedParticipantsNames.length;
  171. let notificationProps;
  172. if (joinedParticipantsCount >= 3) {
  173. notificationProps = {
  174. titleArguments: {
  175. name: joinedParticipantsNames[0]
  176. },
  177. titleKey: 'notify.connectedThreePlusMembers'
  178. };
  179. } else if (joinedParticipantsCount === 2) {
  180. notificationProps = {
  181. titleArguments: {
  182. first: joinedParticipantsNames[0],
  183. second: joinedParticipantsNames[1]
  184. },
  185. titleKey: 'notify.connectedTwoMembers'
  186. };
  187. } else if (joinedParticipantsCount) {
  188. notificationProps = {
  189. titleArguments: {
  190. name: joinedParticipantsNames[0]
  191. },
  192. titleKey: 'notify.connectedOneMember'
  193. };
  194. }
  195. if (notificationProps) {
  196. dispatch(
  197. showNotification(notificationProps, NOTIFICATION_TIMEOUT_TYPE.SHORT));
  198. }
  199. joinedParticipantsNames = [];
  200. }, 2000, { leading: false });
  201. /**
  202. * An array of names of participants that have left the conference. The array
  203. * is replaced with an empty array as notifications are displayed.
  204. *
  205. * @private
  206. * @type {string[]}
  207. */
  208. let leftParticipantsNames = [];
  209. /**
  210. * A throttled internal function that takes the internal list of participant
  211. * names, {@code leftParticipantsNames}, and triggers the display of a
  212. * notification informing of their leaving.
  213. *
  214. * @private
  215. * @type {Function}
  216. */
  217. const _throttledNotifyParticipantLeft = throttle((dispatch: Dispatch<any>, getState: Function) => {
  218. const participantCount = getParticipantCount(getState());
  219. // Skip left notifications altogether for large meetings.
  220. if (participantCount > SILENT_LEFT_THRESHOLD) {
  221. leftParticipantsNames = [];
  222. return;
  223. }
  224. const leftParticipantsCount = leftParticipantsNames.length;
  225. let notificationProps;
  226. if (leftParticipantsCount >= 3) {
  227. notificationProps = {
  228. titleArguments: {
  229. name: leftParticipantsNames[0]
  230. },
  231. titleKey: 'notify.leftThreePlusMembers'
  232. };
  233. } else if (leftParticipantsCount === 2) {
  234. notificationProps = {
  235. titleArguments: {
  236. first: leftParticipantsNames[0],
  237. second: leftParticipantsNames[1]
  238. },
  239. titleKey: 'notify.leftTwoMembers'
  240. };
  241. } else if (leftParticipantsCount) {
  242. notificationProps = {
  243. titleArguments: {
  244. name: leftParticipantsNames[0]
  245. },
  246. titleKey: 'notify.leftOneMember'
  247. };
  248. }
  249. if (notificationProps) {
  250. dispatch(
  251. showNotification(notificationProps, NOTIFICATION_TIMEOUT_TYPE.SHORT));
  252. }
  253. leftParticipantsNames = [];
  254. }, 2000, { leading: false });
  255. /**
  256. * Queues the display of a notification of a participant having connected to
  257. * the meeting. The notifications are batched so that quick consecutive
  258. * connection events are shown in one notification.
  259. *
  260. * @param {string} displayName - The name of the participant that connected.
  261. * @returns {Function}
  262. */
  263. export function showParticipantJoinedNotification(displayName: string) {
  264. joinedParticipantsNames.push(displayName);
  265. return (dispatch: Dispatch<any>, getState: Function) => _throttledNotifyParticipantConnected(dispatch, getState);
  266. }
  267. /**
  268. * Queues the display of a notification of a participant having left to
  269. * the meeting. The notifications are batched so that quick consecutive
  270. * connection events are shown in one notification.
  271. *
  272. * @param {string} displayName - The name of the participant that left.
  273. * @returns {Function}
  274. */
  275. export function showParticipantLeftNotification(displayName: string) {
  276. leftParticipantsNames.push(displayName);
  277. return (dispatch: Dispatch<any>, getState: Function) => _throttledNotifyParticipantLeft(dispatch, getState);
  278. }