Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. import { generateCollaborationLinkData } from '@jitsi/excalidraw';
  2. import { AnyAction } from 'redux';
  3. import { createOpenWhiteboardEvent } from '../analytics/AnalyticsEvents';
  4. import { sendAnalytics } from '../analytics/functions';
  5. import { IStore } from '../app/types';
  6. import { getCurrentConference } from '../base/conference/functions';
  7. import { hideDialog, openDialog } from '../base/dialog/actions';
  8. import { isDialogOpen } from '../base/dialog/functions';
  9. import { JitsiConferenceEvents } from '../base/lib-jitsi-meet';
  10. import { participantJoined, participantLeft, pinParticipant } from '../base/participants/actions';
  11. import { FakeParticipant } from '../base/participants/types';
  12. import MiddlewareRegistry from '../base/redux/MiddlewareRegistry';
  13. import StateListenerRegistry from '../base/redux/StateListenerRegistry';
  14. import { getCurrentRoomId } from '../breakout-rooms/functions';
  15. import { addStageParticipant } from '../filmstrip/actions.web';
  16. import { isStageFilmstripAvailable } from '../filmstrip/functions.web';
  17. import { RESET_WHITEBOARD, SET_WHITEBOARD_OPEN } from './actionTypes';
  18. import {
  19. notifyWhiteboardLimit,
  20. resetWhiteboard,
  21. restrictWhiteboard,
  22. setWhiteboardOpen,
  23. setupWhiteboard
  24. } from './actions';
  25. import WhiteboardLimitDialog from './components/web/WhiteboardLimitDialog';
  26. import { WHITEBOARD_ID, WHITEBOARD_PARTICIPANT_NAME } from './constants';
  27. import {
  28. getCollabDetails,
  29. getCollabServerUrl,
  30. isWhiteboardOpen,
  31. isWhiteboardPresent,
  32. shouldEnforceUserLimit,
  33. shouldNotifyUserLimit
  34. } from './functions';
  35. import { WhiteboardStatus } from './types';
  36. const focusWhiteboard = (store: IStore) => {
  37. const { dispatch, getState } = store;
  38. const state = getState();
  39. const conference = getCurrentConference(state);
  40. const stageFilmstrip = isStageFilmstripAvailable(state);
  41. const isPresent = isWhiteboardPresent(state);
  42. if (!isPresent) {
  43. dispatch(participantJoined({
  44. conference,
  45. fakeParticipant: FakeParticipant.Whiteboard,
  46. id: WHITEBOARD_ID,
  47. name: WHITEBOARD_PARTICIPANT_NAME
  48. }));
  49. }
  50. if (stageFilmstrip) {
  51. dispatch(addStageParticipant(WHITEBOARD_ID, true));
  52. } else {
  53. dispatch(pinParticipant(WHITEBOARD_ID));
  54. }
  55. };
  56. /**
  57. * Middleware which intercepts whiteboard actions to handle changes to the related state.
  58. *
  59. * @param {Store} store - The redux store.
  60. * @returns {Function}
  61. */
  62. MiddlewareRegistry.register((store: IStore) => (next: Function) => async (action: AnyAction) => {
  63. const { dispatch, getState } = store;
  64. const state = getState();
  65. const conference = getCurrentConference(state);
  66. switch (action.type) {
  67. case SET_WHITEBOARD_OPEN: {
  68. const existingCollabDetails = getCollabDetails(state);
  69. const enforceUserLimit = shouldEnforceUserLimit(state);
  70. const notifyUserLimit = shouldNotifyUserLimit(state);
  71. if (enforceUserLimit) {
  72. dispatch(restrictWhiteboard(false));
  73. dispatch(openDialog(WhiteboardLimitDialog));
  74. return;
  75. }
  76. if (!existingCollabDetails) {
  77. const collabLinkData = await generateCollaborationLinkData();
  78. const collabServerUrl = getCollabServerUrl(state);
  79. const roomId = getCurrentRoomId(state);
  80. const collabDetails = {
  81. roomId,
  82. roomKey: collabLinkData.roomKey
  83. };
  84. focusWhiteboard(store);
  85. dispatch(setupWhiteboard({ collabDetails }));
  86. conference?.getMetadataHandler().setMetadata(WHITEBOARD_ID, {
  87. collabServerUrl,
  88. collabDetails
  89. });
  90. raiseWhiteboardNotification(WhiteboardStatus.INSTANTIATED);
  91. return;
  92. }
  93. if (action.isOpen) {
  94. if (enforceUserLimit) {
  95. dispatch(restrictWhiteboard());
  96. return;
  97. }
  98. if (notifyUserLimit) {
  99. dispatch(notifyWhiteboardLimit());
  100. }
  101. if (isDialogOpen(state, WhiteboardLimitDialog)) {
  102. dispatch(hideDialog(WhiteboardLimitDialog));
  103. }
  104. focusWhiteboard(store);
  105. sendAnalytics(createOpenWhiteboardEvent());
  106. raiseWhiteboardNotification(WhiteboardStatus.SHOWN);
  107. return;
  108. }
  109. dispatch(participantLeft(WHITEBOARD_ID, conference, { fakeParticipant: FakeParticipant.Whiteboard }));
  110. raiseWhiteboardNotification(WhiteboardStatus.HIDDEN);
  111. break;
  112. }
  113. case RESET_WHITEBOARD: {
  114. dispatch(participantLeft(WHITEBOARD_ID, conference, { fakeParticipant: FakeParticipant.Whiteboard }));
  115. raiseWhiteboardNotification(WhiteboardStatus.RESET);
  116. break;
  117. }
  118. }
  119. return next(action);
  120. });
  121. /**
  122. * Raises the whiteboard status notifications changes (if API is enabled).
  123. *
  124. * @param {WhiteboardStatus} status - The whiteboard changed status.
  125. * @returns {Function}
  126. */
  127. function raiseWhiteboardNotification(status: WhiteboardStatus) {
  128. if (typeof APP !== 'undefined') {
  129. APP.API.notifyWhiteboardStatusChanged(status);
  130. }
  131. }
  132. /**
  133. * Set up state change listener to perform maintenance tasks when the conference
  134. * is left or failed, e.g. Disable the whiteboard if it's left open.
  135. */
  136. StateListenerRegistry.register(
  137. state => getCurrentConference(state),
  138. (conference, { dispatch }, previousConference): void => {
  139. if (conference !== previousConference) {
  140. dispatch(resetWhiteboard());
  141. }
  142. if (conference && !previousConference) {
  143. conference.on(JitsiConferenceEvents.METADATA_UPDATED, (metadata: any) => {
  144. if (metadata[WHITEBOARD_ID]) {
  145. dispatch(setupWhiteboard({
  146. collabDetails: metadata[WHITEBOARD_ID].collabDetails
  147. }));
  148. dispatch(setWhiteboardOpen(true));
  149. }
  150. });
  151. }
  152. });
  153. /**
  154. * Set up state change listener to limit whiteboard access.
  155. */
  156. StateListenerRegistry.register(
  157. state => shouldEnforceUserLimit(state),
  158. (enforceUserLimit, { dispatch, getState }): void => {
  159. if (isWhiteboardOpen(getState()) && enforceUserLimit) {
  160. dispatch(restrictWhiteboard());
  161. }
  162. }
  163. );
  164. /**
  165. * Set up state change listener to notify about whiteboard usage.
  166. */
  167. StateListenerRegistry.register(
  168. state => shouldNotifyUserLimit(state),
  169. (notifyUserLimit, { dispatch, getState }, prevNotifyUserLimit): void => {
  170. if (isWhiteboardOpen(getState()) && notifyUserLimit && !prevNotifyUserLimit) {
  171. dispatch(notifyWhiteboardLimit());
  172. }
  173. }
  174. );