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.

MeetingParticipantList.js 3.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. // @flow
  2. import _ from 'lodash';
  3. import React, { useCallback, useRef, useState } from 'react';
  4. import { useTranslation } from 'react-i18next';
  5. import { useSelector } from 'react-redux';
  6. import { getParticipants } from '../../base/participants';
  7. import { findStyledAncestor } from '../functions';
  8. import { InviteButton } from './InviteButton';
  9. import { MeetingParticipantContextMenu } from './MeetingParticipantContextMenu';
  10. import { MeetingParticipantItem } from './MeetingParticipantItem';
  11. import { Heading, ParticipantContainer } from './styled';
  12. type NullProto = {
  13. [key: string]: any,
  14. __proto__: null
  15. };
  16. type RaiseContext = NullProto | {
  17. /**
  18. * Target elements against which positioning calculations are made
  19. */
  20. offsetTarget?: HTMLElement,
  21. /**
  22. * Participant reference
  23. */
  24. participant?: Object,
  25. };
  26. const initialState = Object.freeze(Object.create(null));
  27. export const MeetingParticipantList = () => {
  28. const isMouseOverMenu = useRef(false);
  29. const participants = useSelector(getParticipants, _.isEqual);
  30. const [ raiseContext, setRaiseContext ] = useState<RaiseContext>(initialState);
  31. const { t } = useTranslation();
  32. const lowerMenu = useCallback(() => {
  33. /**
  34. * We are tracking mouse movement over the active participant item and
  35. * the context menu. Due to the order of enter/leave events, we need to
  36. * defer checking if the mouse is over the context menu with
  37. * queueMicrotask
  38. */
  39. window.queueMicrotask(() => {
  40. if (isMouseOverMenu.current) {
  41. return;
  42. }
  43. if (raiseContext !== initialState) {
  44. setRaiseContext(initialState);
  45. }
  46. });
  47. }, [ raiseContext ]);
  48. const raiseMenu = useCallback((participant, target) => {
  49. setRaiseContext({
  50. participant,
  51. offsetTarget: findStyledAncestor(target, ParticipantContainer)
  52. });
  53. }, [ raiseContext ]);
  54. const toggleMenu = useCallback(participant => e => {
  55. const { participant: raisedParticipant } = raiseContext;
  56. if (raisedParticipant && raisedParticipant === participant) {
  57. lowerMenu();
  58. } else {
  59. raiseMenu(participant, e.target);
  60. }
  61. }, [ raiseContext ]);
  62. const menuEnter = useCallback(() => {
  63. isMouseOverMenu.current = true;
  64. }, []);
  65. const menuLeave = useCallback(() => {
  66. isMouseOverMenu.current = false;
  67. lowerMenu();
  68. }, [ lowerMenu ]);
  69. return (
  70. <>
  71. <Heading>{t('participantsPane.headings.participantsList', { count: participants.length })}</Heading>
  72. <InviteButton />
  73. <div>
  74. {participants.map(p => (
  75. <MeetingParticipantItem
  76. isHighlighted = { raiseContext.participant === p }
  77. key = { p.id }
  78. onContextMenu = { toggleMenu(p) }
  79. onLeave = { lowerMenu }
  80. participant = { p } />
  81. ))}
  82. </div>
  83. <MeetingParticipantContextMenu
  84. onEnter = { menuEnter }
  85. onLeave = { menuLeave }
  86. onSelect = { lowerMenu }
  87. { ...raiseContext } />
  88. </>
  89. );
  90. };