Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

actions.js 7.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. // @flow
  2. import i18next from 'i18next';
  3. import _ from 'lodash';
  4. import type { Dispatch } from 'redux';
  5. import { createBreakoutRoomsEvent, sendAnalytics } from '../analytics';
  6. import {
  7. conferenceLeft,
  8. conferenceWillLeave,
  9. createConference,
  10. getCurrentConference
  11. } from '../base/conference';
  12. import { setAudioMuted, setVideoMuted } from '../base/media';
  13. import { getRemoteParticipants } from '../base/participants';
  14. import { clearNotifications } from '../notifications';
  15. import {
  16. getBreakoutRooms,
  17. getMainRoom
  18. } from './functions';
  19. import logger from './logger';
  20. declare var APP: Object;
  21. /**
  22. * Action to create a breakout room.
  23. *
  24. * @param {string} name - Name / subject for the breakout room.
  25. * @returns {Function}
  26. */
  27. export function createBreakoutRoom(name?: string) {
  28. return (dispatch: Dispatch<any>, getState: Function) => {
  29. const rooms = getBreakoutRooms(getState);
  30. // TODO: remove this once we add UI to customize the name.
  31. const index = Object.keys(rooms).length;
  32. const subject = name || i18next.t('breakoutRooms.defaultName', { index });
  33. sendAnalytics(createBreakoutRoomsEvent('create'));
  34. // $FlowExpectedError
  35. getCurrentConference(getState)?.getBreakoutRooms()
  36. ?.createBreakoutRoom(subject);
  37. };
  38. }
  39. /**
  40. * Action to close a room and send participants to the main room.
  41. *
  42. * @param {string} roomId - The id of the room to close.
  43. * @returns {Function}
  44. */
  45. export function closeBreakoutRoom(roomId: string) {
  46. return (dispatch: Dispatch<any>, getState: Function) => {
  47. const rooms = getBreakoutRooms(getState);
  48. const room = rooms[roomId];
  49. const mainRoom = getMainRoom(getState);
  50. sendAnalytics(createBreakoutRoomsEvent('close'));
  51. if (room && mainRoom) {
  52. Object.values(room.participants).forEach(p => {
  53. // $FlowExpectedError
  54. dispatch(sendParticipantToRoom(p.jid, mainRoom.id));
  55. });
  56. }
  57. };
  58. }
  59. /**
  60. * Action to remove a breakout room.
  61. *
  62. * @param {string} breakoutRoomJid - The jid of the breakout room to remove.
  63. * @returns {Function}
  64. */
  65. export function removeBreakoutRoom(breakoutRoomJid: string) {
  66. return (dispatch: Dispatch<any>, getState: Function) => {
  67. sendAnalytics(createBreakoutRoomsEvent('remove'));
  68. // $FlowExpectedError
  69. getCurrentConference(getState)?.getBreakoutRooms()
  70. ?.removeBreakoutRoom(breakoutRoomJid);
  71. };
  72. }
  73. /**
  74. * Action to auto-assign the participants to breakout rooms.
  75. *
  76. * @returns {Function}
  77. */
  78. export function autoAssignToBreakoutRooms() {
  79. return (dispatch: Dispatch<any>, getState: Function) => {
  80. const rooms = getBreakoutRooms(getState);
  81. const breakoutRooms = _.filter(rooms, (room: Object) => !room.isMainRoom);
  82. if (breakoutRooms) {
  83. sendAnalytics(createBreakoutRoomsEvent('auto.assign'));
  84. const participantIds = Array.from(getRemoteParticipants(getState).keys());
  85. const length = Math.ceil(participantIds.length / breakoutRooms.length);
  86. _.chunk(_.shuffle(participantIds), length).forEach((group, index) =>
  87. group.forEach(participantId => {
  88. dispatch(sendParticipantToRoom(participantId, breakoutRooms[index].id));
  89. })
  90. );
  91. }
  92. };
  93. }
  94. /**
  95. * Action to send a participant to a room.
  96. *
  97. * @param {string} participantId - The participant id.
  98. * @param {string} roomId - The room id.
  99. * @returns {Function}
  100. */
  101. export function sendParticipantToRoom(participantId: string, roomId: string) {
  102. return (dispatch: Dispatch<any>, getState: Function) => {
  103. const rooms = getBreakoutRooms(getState);
  104. const room = rooms[roomId];
  105. if (!room) {
  106. logger.warn(`Invalid room: ${roomId}`);
  107. return;
  108. }
  109. // Get the full JID of the participant. We could be getting the endpoint ID or
  110. // a participant JID. We want to find the connection JID.
  111. const participantJid = _findParticipantJid(getState, participantId);
  112. if (!participantJid) {
  113. logger.warn(`Could not find participant ${participantId}`);
  114. return;
  115. }
  116. // $FlowExpectedError
  117. getCurrentConference(getState)?.getBreakoutRooms()
  118. ?.sendParticipantToRoom(participantJid, room.jid);
  119. };
  120. }
  121. /**
  122. * Action to move to a room.
  123. *
  124. * @param {string} roomId - The room id to move to. If omitted move to the main room.
  125. * @returns {Function}
  126. */
  127. export function moveToRoom(roomId?: string) {
  128. return (dispatch: Dispatch<any>, getState: Function) => {
  129. let _roomId = roomId || getMainRoom(getState)?.id;
  130. // Check if we got a full JID.
  131. // $FlowExpectedError
  132. if (_roomId?.indexOf('@') !== -1) {
  133. // $FlowExpectedError
  134. const [ id, ...domainParts ] = _roomId.split('@');
  135. // On mobile we first store the room and the connection is created
  136. // later, so let's attach the domain to the room String object as
  137. // a little hack.
  138. // eslint-disable-next-line no-new-wrappers
  139. _roomId = new String(id);
  140. // $FlowExpectedError
  141. _roomId.domain = domainParts.join('@');
  142. }
  143. if (navigator.product === 'ReactNative') {
  144. const conference = getCurrentConference(getState);
  145. const { audio, video } = getState()['features/base/media'];
  146. dispatch(conferenceWillLeave(conference));
  147. conference.leave()
  148. .catch(error => {
  149. logger.warn(
  150. 'JitsiConference.leave() rejected with:',
  151. error);
  152. dispatch(conferenceLeft(conference));
  153. });
  154. dispatch(clearNotifications());
  155. // dispatch(setRoom(_roomId));
  156. dispatch(createConference(_roomId));
  157. dispatch(setAudioMuted(audio.muted));
  158. dispatch(setVideoMuted(video.muted));
  159. } else {
  160. APP.conference.leaveRoom()
  161. .finally(() => APP.conference.joinRoom(_roomId));
  162. }
  163. };
  164. }
  165. /**
  166. * Finds a participant's connection JID given its ID.
  167. *
  168. * @param {Function} getState - The redux store state getter.
  169. * @param {string} participantId - ID of the given participant.
  170. * @returns {string|undefined} - The participant connection JID if found.
  171. */
  172. function _findParticipantJid(getState: Function, participantId: string) {
  173. const conference = getCurrentConference(getState);
  174. if (!conference) {
  175. return;
  176. }
  177. // Get the full JID of the participant. We could be getting the endpoint ID or
  178. // a participant JID. We want to find the connection JID.
  179. let _participantId = participantId;
  180. let participantJid;
  181. if (!participantId.includes('@')) {
  182. const p = conference.getParticipantById(participantId);
  183. // $FlowExpectedError
  184. _participantId = p?.getJid(); // This will be the room JID.
  185. }
  186. if (_participantId) {
  187. const rooms = getBreakoutRooms(getState);
  188. for (const room of Object.values(rooms)) {
  189. // $FlowExpectedError
  190. const participants = room.participants || {};
  191. const p = participants[_participantId]
  192. // $FlowExpectedError
  193. || Object.values(participants).find(item => item.jid === _participantId);
  194. if (p) {
  195. participantJid = p.jid;
  196. break;
  197. }
  198. }
  199. }
  200. return participantJid;
  201. }