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.

actions.js 6.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  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. HIDE_RAISE_HAND_NOTIFICATIONS,
  10. SET_NOTIFICATIONS_ENABLED,
  11. SHOW_NOTIFICATION
  12. } from './actionTypes';
  13. import {
  14. NOTIFICATION_TIMEOUT_TYPE,
  15. NOTIFICATION_TIMEOUT,
  16. NOTIFICATION_TYPE,
  17. SILENT_JOIN_THRESHOLD
  18. } from './constants';
  19. /**
  20. * Function that returns notification timeout value based on notification timeout type.
  21. *
  22. * @param {string} type - Notification type.
  23. * @param {Object} notificationTimeouts - Config notification timeouts.
  24. * @returns {number}
  25. */
  26. function getNotificationTimeout(type: ?string, notificationTimeouts: ?Object) {
  27. if (type === NOTIFICATION_TIMEOUT_TYPE.SHORT) {
  28. return notificationTimeouts?.short ?? NOTIFICATION_TIMEOUT.SHORT;
  29. } else if (type === NOTIFICATION_TIMEOUT_TYPE.MEDIUM) {
  30. return notificationTimeouts?.medium ?? NOTIFICATION_TIMEOUT.MEDIUM;
  31. } else if (type === NOTIFICATION_TIMEOUT_TYPE.LONG) {
  32. return notificationTimeouts?.long ?? NOTIFICATION_TIMEOUT.LONG;
  33. }
  34. return NOTIFICATION_TIMEOUT.STICKY;
  35. }
  36. /**
  37. * Clears (removes) all the notifications.
  38. *
  39. * @returns {{
  40. * type: CLEAR_NOTIFICATIONS
  41. * }}
  42. */
  43. export function clearNotifications() {
  44. return {
  45. type: CLEAR_NOTIFICATIONS
  46. };
  47. }
  48. /**
  49. * Removes the notification with the passed in id.
  50. *
  51. * @param {string} uid - The unique identifier for the notification to be
  52. * removed.
  53. * @returns {{
  54. * type: HIDE_NOTIFICATION,
  55. * uid: string
  56. * }}
  57. */
  58. export function hideNotification(uid: string) {
  59. return {
  60. type: HIDE_NOTIFICATION,
  61. uid
  62. };
  63. }
  64. /**
  65. * Removes the raise hand notifications.
  66. *
  67. * @returns {{
  68. * type: HIDE_RAISE_HAND_NOTIFICATIONS
  69. * }}
  70. */
  71. export function hideRaiseHandNotifications() {
  72. return {
  73. type: HIDE_RAISE_HAND_NOTIFICATIONS
  74. };
  75. }
  76. /**
  77. * Stops notifications from being displayed.
  78. *
  79. * @param {boolean} enabled - Whether or not notifications should display.
  80. * @returns {{
  81. * type: SET_NOTIFICATIONS_ENABLED,
  82. * enabled: boolean
  83. * }}
  84. */
  85. export function setNotificationsEnabled(enabled: boolean) {
  86. return {
  87. type: SET_NOTIFICATIONS_ENABLED,
  88. enabled
  89. };
  90. }
  91. /**
  92. * Queues an error notification for display.
  93. *
  94. * @param {Object} props - The props needed to show the notification component.
  95. * @param {string} type - Notification type.
  96. * @returns {Object}
  97. */
  98. export function showErrorNotification(props: Object, type: ?string) {
  99. return showNotification({
  100. ...props,
  101. appearance: NOTIFICATION_TYPE.ERROR
  102. }, type);
  103. }
  104. /**
  105. * Queues a notification for display.
  106. *
  107. * @param {Object} props - The props needed to show the notification component.
  108. * @param {string} type - Notification type.
  109. * @returns {Function}
  110. */
  111. export function showNotification(props: Object = {}, type: ?string) {
  112. return function(dispatch: Function, getState: Function) {
  113. const { notifications, notificationTimeouts } = getState()['features/base/config'];
  114. const enabledFlag = getFeatureFlag(getState(), NOTIFICATIONS_ENABLED, true);
  115. const shouldDisplay = enabledFlag
  116. && (!notifications
  117. || notifications.includes(props.descriptionKey)
  118. || notifications.includes(props.titleKey));
  119. if (shouldDisplay) {
  120. return dispatch({
  121. type: SHOW_NOTIFICATION,
  122. props,
  123. timeout: getNotificationTimeout(type, notificationTimeouts),
  124. uid: props.uid || window.Date.now().toString()
  125. });
  126. }
  127. };
  128. }
  129. /**
  130. * Queues a warning notification for display.
  131. *
  132. * @param {Object} props - The props needed to show the notification component.
  133. * @param {string} type - Notification type.
  134. * @returns {Object}
  135. */
  136. export function showWarningNotification(props: Object, type: ?string) {
  137. return showNotification({
  138. ...props,
  139. appearance: NOTIFICATION_TYPE.WARNING
  140. }, type);
  141. }
  142. /**
  143. * An array of names of participants that have joined the conference. The array
  144. * is replaced with an empty array as notifications are displayed.
  145. *
  146. * @private
  147. * @type {string[]}
  148. */
  149. let joinedParticipantsNames = [];
  150. /**
  151. * A throttled internal function that takes the internal list of participant
  152. * names, {@code joinedParticipantsNames}, and triggers the display of a
  153. * notification informing of their joining.
  154. *
  155. * @private
  156. * @type {Function}
  157. */
  158. const _throttledNotifyParticipantConnected = throttle((dispatch: Dispatch<any>, getState: Function) => {
  159. const participantCount = getParticipantCount(getState());
  160. // Skip join notifications altogether for large meetings.
  161. if (participantCount > SILENT_JOIN_THRESHOLD) {
  162. joinedParticipantsNames = [];
  163. return;
  164. }
  165. const joinedParticipantsCount = joinedParticipantsNames.length;
  166. let notificationProps;
  167. if (joinedParticipantsCount >= 3) {
  168. notificationProps = {
  169. titleArguments: {
  170. name: joinedParticipantsNames[0]
  171. },
  172. titleKey: 'notify.connectedThreePlusMembers'
  173. };
  174. } else if (joinedParticipantsCount === 2) {
  175. notificationProps = {
  176. titleArguments: {
  177. first: joinedParticipantsNames[0],
  178. second: joinedParticipantsNames[1]
  179. },
  180. titleKey: 'notify.connectedTwoMembers'
  181. };
  182. } else if (joinedParticipantsCount) {
  183. notificationProps = {
  184. titleArguments: {
  185. name: joinedParticipantsNames[0]
  186. },
  187. titleKey: 'notify.connectedOneMember'
  188. };
  189. }
  190. if (notificationProps) {
  191. dispatch(
  192. showNotification(notificationProps, NOTIFICATION_TIMEOUT_TYPE.SHORT));
  193. }
  194. joinedParticipantsNames = [];
  195. }, 2000, { leading: false });
  196. /**
  197. * Queues the display of a notification of a participant having connected to
  198. * the meeting. The notifications are batched so that quick consecutive
  199. * connection events are shown in one notification.
  200. *
  201. * @param {string} displayName - The name of the participant that connected.
  202. * @returns {Function}
  203. */
  204. export function showParticipantJoinedNotification(displayName: string) {
  205. joinedParticipantsNames.push(displayName);
  206. return (dispatch: Dispatch<any>, getState: Function) => _throttledNotifyParticipantConnected(dispatch, getState);
  207. }