ref(TS) Convert some components to TS (#13142)

pull/13162/head jitsi-meet_8505
Robert Pintilii 2 years ago committed by GitHub
parent aa3a8f24b8
commit 0bea2926d2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      react/features/analytics/AnalyticsEvents.ts
  2. 10
      react/features/audio-level-indicator/components/AudioLevelIndicator.tsx
  3. 2
      react/features/base/conference/functions.ts
  4. 3
      react/features/base/react/components/web/BaseIndicator.tsx
  5. 3
      react/features/base/toolbox/components/AbstractToolboxItem.tsx
  6. 3
      react/features/base/tooltip/components/Tooltip.tsx
  7. 5
      react/features/base/tracks/functions.any.ts
  8. 2
      react/features/base/ui/components/web/Checkbox.tsx
  9. 3
      react/features/base/ui/constants.any.ts
  10. 2
      react/features/connection-indicator/components/web/ConnectionIndicator.tsx
  11. 1
      react/features/desktop-picker/actions.ts
  12. 3
      react/features/desktop-picker/components/DesktopPicker.tsx
  13. 32
      react/features/desktop-picker/components/DesktopPickerPane.tsx
  14. 30
      react/features/desktop-picker/components/DesktopSourcePreview.tsx
  15. 2
      react/features/display-name/components/web/DisplayName.tsx
  16. 2
      react/features/feedback/actions.ts
  17. 11
      react/features/filmstrip/components/web/AudioMutedIndicator.tsx
  18. 21
      react/features/filmstrip/components/web/AudioTracksContainer.tsx
  19. 1
      react/features/filmstrip/components/web/Filmstrip.tsx
  20. 3
      react/features/filmstrip/components/web/ModeratorIndicator.tsx
  21. 3
      react/features/filmstrip/components/web/PinnedIndicator.tsx
  22. 3
      react/features/filmstrip/components/web/RaisedHandIndicator.tsx
  23. 14
      react/features/filmstrip/components/web/ScreenShareIndicator.tsx
  24. 28
      react/features/filmstrip/components/web/StatusIndicators.tsx
  25. 9
      react/features/filmstrip/components/web/Thumbnail.tsx
  26. 15
      react/features/filmstrip/components/web/ThumbnailAudioIndicator.tsx
  27. 3
      react/features/filmstrip/components/web/ThumbnailBottomIndicators.tsx
  28. 16
      react/features/filmstrip/components/web/ThumbnailTopIndicators.tsx
  29. 8
      react/features/filmstrip/components/web/VideoMenuTriggerButton.tsx
  30. 48
      react/features/filmstrip/components/web/VirtualScreenshareParticipant.tsx
  31. 4
      react/features/filmstrip/functions.web.ts
  32. 1
      react/features/invite/components/add-people-dialog/web/AddPeopleDialog.tsx
  33. 14
      react/features/invite/components/add-people-dialog/web/LiveStreamSection.tsx
  34. 2
      react/features/lobby/actions.any.ts
  35. 23
      react/features/no-audio-signal/components/DialInLink.tsx
  36. 2
      react/features/no-audio-signal/middleware.tsx
  37. 2
      react/features/overlay/actions.web.ts
  38. 9
      react/features/overlay/components/web/AbstractPageReloadOverlay.tsx
  39. 4
      react/features/overlay/components/web/AbstractUserMediaPermissionsOverlay.ts
  40. 6
      react/features/overlay/components/web/OverlayFrame.tsx
  41. 10
      react/features/overlay/components/web/PageReloadOverlay.tsx
  42. 23
      react/features/overlay/components/web/ReloadButton.tsx
  43. 2
      react/features/overlay/components/web/SuspendedOverlay.tsx
  44. 10
      react/features/overlay/components/web/UserMediaPermissionsOverlay.tsx
  45. 6
      react/features/overlay/functions.web.ts
  46. 1
      react/features/overlay/middleware.ts
  47. 2
      react/features/participants-pane/components/native/MeetingParticipantItem.js
  48. 16
      react/features/participants-pane/components/web/LobbyParticipantItems.tsx
  49. 1
      react/features/participants-pane/components/web/LobbyParticipants.tsx
  50. 38
      react/features/participants-pane/components/web/MeetingParticipantContextMenu.tsx
  51. 85
      react/features/participants-pane/components/web/MeetingParticipantItem.tsx
  52. 62
      react/features/participants-pane/components/web/MeetingParticipantItems.tsx
  53. 5
      react/features/participants-pane/components/web/MeetingParticipants.tsx
  54. 4
      react/features/participants-pane/components/web/ParticipantItem.tsx
  55. 4
      react/features/participants-pane/components/web/ParticipantQuickAction.tsx
  56. 13
      react/features/participants-pane/functions.ts
  57. 29
      react/features/presence-status/components/PresenceLabel.tsx
  58. 3
      react/features/reactions/components/web/ReactionButton.tsx
  59. 12
      react/features/video-menu/components/web/LocalVideoMenuTriggerButton.tsx
  60. 12
      react/features/video-menu/components/web/RemoteVideoMenuTriggerButton.tsx

@ -350,7 +350,7 @@ export function createOfferAnswerFailedEvent() {
* @returns {Object} The event in a format suitable for sending via
* sendAnalytics.
*/
export function createPageReloadScheduledEvent(reason: string, timeout: number, details: Object) {
export function createPageReloadScheduledEvent(reason: string, timeout: number, details: Object = {}) {
return {
action: 'page.reload.scheduled',
attributes: {

@ -1,5 +1,3 @@
/* @flow */
import React, { Component } from 'react';
/**
@ -17,21 +15,21 @@ const CENTER_DOT_INDEX = Math.floor(AUDIO_LEVEL_DOTS / 2);
/**
* The type of the React {@code Component} props of {@link AudioLevelIndicator}.
*/
type Props = {
interface IProps {
/**
* The current audio level to display. The value should be a number between
* 0 and 1.
*/
audioLevel: number
};
audioLevel: number;
}
/**
* Creates a ReactElement responsible for drawing audio levels.
*
* @augments {Component}
*/
class AudioLevelIndicator extends Component<Props> {
class AudioLevelIndicator extends Component<IProps> {
/**
* Implements React's {@link Component#render()}.
*

@ -494,7 +494,7 @@ function _reportError(msg: string, err: Error) {
*/
export function sendLocalParticipant(
stateful: IStateful,
conference: IJitsiConference) {
conference?: IJitsiConference) {
const {
avatarURL,
email,

@ -5,6 +5,7 @@ import { makeStyles } from 'tss-react/mui';
import { translate } from '../../../i18n/functions';
import Icon from '../../../icons/components/Icon';
import Tooltip from '../../../tooltip/components/Tooltip';
import { TOOLTIP_POSITION } from '../../../ui/constants.any';
/**
* The type of the React {@code Component} props of {@link BaseIndicator}.
@ -56,7 +57,7 @@ interface IProps extends WithTranslation {
* From which side of the indicator the tooltip should appear from,
* defaulting to "top".
*/
tooltipPosition: 'top' | 'bottom' | 'left' | 'right';
tooltipPosition: TOOLTIP_POSITION;
}
const useStyles = makeStyles()(() => {

@ -3,6 +3,7 @@ import { WithTranslation } from 'react-i18next';
import { GestureResponderEvent } from 'react-native';
import type { StyleType } from '../../styles/functions.any';
import { TOOLTIP_POSITION } from '../../ui/constants.any';
export type Styles = {
@ -94,7 +95,7 @@ export interface IProps extends WithTranslation {
* From which direction the tooltip should appear, relative to the
* item. Used only on web.
*/
tooltipPosition: 'top' | 'bottom' | 'left' | 'right';
tooltipPosition: TOOLTIP_POSITION;
/**
* Whether this item is visible or not.

@ -7,6 +7,7 @@ import { IReduxState } from '../../../app/types';
import { isMobileBrowser } from '../../environment/utils';
import Popover from '../../popover/components/Popover.web';
import { withPixelLineHeight } from '../../styles/functions.web';
import { TOOLTIP_POSITION } from '../../ui/constants.any';
import { hideTooltip, showTooltip } from '../actions';
const TOOLTIP_DELAY = 300;
@ -16,7 +17,7 @@ interface IProps {
children: ReactElement;
containerClassName?: string;
content: string;
position?: 'top' | 'bottom' | 'left' | 'right';
position?: TOOLTIP_POSITION;
}
const useStyles = makeStyles()(theme => {

@ -29,7 +29,8 @@ export const getTrackState = (state: IReduxState) => state['features/base/tracks
* @param {IReduxState} state - Global state.
* @returns {boolean} - Is the media type muted for the participant.
*/
export function isParticipantMediaMuted(participant: IParticipant, mediaType: MediaType, state: IReduxState) {
export function isParticipantMediaMuted(participant: IParticipant | undefined,
mediaType: MediaType, state: IReduxState) {
if (!participant) {
return false;
}
@ -63,7 +64,7 @@ export function isParticipantAudioMuted(participant: IParticipant, state: IRedux
* @param {IReduxState} state - Global state.
* @returns {boolean} - Is video muted for the participant.
*/
export function isParticipantVideoMuted(participant: IParticipant, state: IReduxState) {
export function isParticipantVideoMuted(participant: IParticipant | undefined, state: IReduxState) {
return isParticipantMediaMuted(participant, MEDIA_TYPE.VIDEO, state);
}

@ -11,7 +11,7 @@ interface ICheckboxProps {
/**
* Whether the input is checked or not.
*/
checked: boolean;
checked?: boolean;
/**
* Class name for additional styles.

@ -26,3 +26,6 @@ export const BUTTON_MODES: {
CONTAINED: 'contained',
TEXT: 'text'
};
export type TOOLTIP_POSITION = 'top' | 'bottom' | 'left' | 'right';

@ -377,7 +377,7 @@ class ConnectionIndicator extends AbstractConnectionIndicator<IProps, IState> {
* @param {IProps} ownProps - The own props of the component.
* @returns {IProps}
*/
export function _mapStateToProps(state: IReduxState, ownProps: IProps) {
export function _mapStateToProps(state: IReduxState, ownProps: any) {
const { participantId } = ownProps;
const tracks = state['features/base/tracks'];
const participant = participantId ? getParticipantById(state, participantId) : getLocalParticipant(state);

@ -1,6 +1,5 @@
import { openDialog } from '../base/dialog/actions';
// @ts-ignore
import DesktopPicker from './components/DesktopPicker';
/**

@ -9,7 +9,6 @@ import Dialog from '../../base/ui/components/web/Dialog';
import Tabs from '../../base/ui/components/web/Tabs';
import { obtainDesktopSources } from '../functions';
// @ts-ignore
import DesktopPickerPane from './DesktopPickerPane';
/**
@ -88,7 +87,7 @@ interface IState {
/**
* An object containing all the DesktopCapturerSources.
*/
sources: Object;
sources: any;
/**
* The desktop source types to fetch previews for.

@ -1,6 +1,5 @@
/* @flow */
import React, { Component } from 'react';
import { WithTranslation } from 'react-i18next';
import { translate } from '../../base/i18n/functions';
import Platform from '../../base/react/Platform.web';
@ -12,50 +11,45 @@ import DesktopSourcePreview from './DesktopSourcePreview';
/**
* The type of the React {@code Component} props of {@link DesktopPickerPane}.
*/
type Props = {
interface IProps extends WithTranslation {
/**
* The handler to be invoked when a DesktopSourcePreview is clicked.
*/
onClick: Function,
onClick: Function;
/**
* The handler to be invoked when a DesktopSourcePreview is double clicked.
*/
onDoubleClick: Function,
onDoubleClick: Function;
/**
* The handler to be invoked if the users checks the audio screen sharing checkbox.
*/
onShareAudioChecked: Function,
onShareAudioChecked: Function;
/**
* The id of the DesktopCapturerSource that is currently selected.
*/
selectedSourceId: string,
selectedSourceId: string;
/**
* An array of DesktopCapturerSources.
*/
sources: Array<Object>,
sources: Array<any>;
/**
* The source type of the DesktopCapturerSources to display.
*/
type: string,
/**
* Used to obtain translations.
*/
t: Function
};
type: string;
}
/**
* React component for showing a grid of DesktopSourcePreviews.
*
* @augments Component
*/
class DesktopPickerPane extends Component<Props> {
class DesktopPickerPane extends Component<IProps> {
/**
* Initializes a new DesktopPickerPane instance.
@ -63,21 +57,19 @@ class DesktopPickerPane extends Component<Props> {
* @param {Object} props - The read-only properties with which the new
* instance is to be initialized.
*/
constructor(props: Props) {
constructor(props: IProps) {
super(props);
this._onShareAudioCheck = this._onShareAudioCheck.bind(this);
}
_onShareAudioCheck: (Object) => void;
/**
* Function to be called when the Checkbox is used.
*
* @param {boolean} checked - Checkbox status (checked or not).
* @returns {void}
*/
_onShareAudioCheck({ target: { checked } }) {
_onShareAudioCheck({ target: { checked } }: { target: { checked: boolean; }; }) {
this.props.onShareAudioChecked(checked);
}

@ -1,6 +1,5 @@
/* @flow */
import React, { Component } from 'react';
import { WithTranslation } from 'react-i18next';
import { translate } from '../../base/i18n/functions';
@ -9,56 +8,51 @@ import { translate } from '../../base/i18n/functions';
* The type of the React {@code Component} props of
* {@link DesktopSourcePreview}.
*/
type Props = {
interface IProps extends WithTranslation {
/**
* The callback to invoke when the component is clicked. The id of the
* clicked on DesktopCapturerSource will be passed in.
*/
onClick: Function,
onClick: Function;
/**
* The callback to invoke when the component is double clicked. The id of
* the DesktopCapturerSource will be passed in.
*/
onDoubleClick: Function,
onDoubleClick: Function;
/**
* The indicator which determines whether this DesktopSourcePreview is
* selected. If true, the 'is-selected' CSS class will be added to the root
* of Component.
*/
selected: boolean,
selected: boolean;
/**
* The DesktopCapturerSource to display.
*/
source: Object,
source: any;
/**
* The source type of the DesktopCapturerSources to display.
*/
type: string,
/**
* Invoked to obtain translated strings.
*/
t: Function
};
type: string;
}
/**
* React component for displaying a preview of a DesktopCapturerSource.
*
* @augments Component
*/
class DesktopSourcePreview extends Component<Props> {
class DesktopSourcePreview extends Component<IProps> {
/**
* Initializes a new DesktopSourcePreview instance.
*
* @param {Object} props - The read-only properties with which the new
* instance is to be initialized.
*/
constructor(props: Props) {
constructor(props: IProps) {
super(props);
this._onClick = this._onClick.bind(this);
@ -93,8 +87,6 @@ class DesktopSourcePreview extends Component<Props> {
);
}
_onClick: () => void;
/**
* Invokes the passed in onClick callback.
*
@ -106,8 +98,6 @@ class DesktopSourcePreview extends Component<Props> {
this.props.onClick(source.id, type);
}
_onDoubleClick: () => void;
/**
* Invokes the passed in onDoubleClick callback.
*

@ -43,7 +43,7 @@ interface IProps {
/**
* The type of thumbnail.
*/
thumbnailType: string;
thumbnailType?: string;
}
const useStyles = makeStyles()(theme => {

@ -11,8 +11,6 @@ import {
SUBMIT_FEEDBACK_ERROR,
SUBMIT_FEEDBACK_SUCCESS
} from './actionTypes';
// eslint-disable-next-line lines-around-comment
// @ts-ignore
import FeedbackDialog from './components/FeedbackDialog';
import { sendFeedbackToJaaSRequest } from './functions';

@ -1,27 +1,26 @@
/* @flow */
import React from 'react';
import { IconMicSlash } from '../../../base/icons/svg';
import BaseIndicator from '../../../base/react/components/web/BaseIndicator';
import { TOOLTIP_POSITION } from '../../../base/ui/constants.any';
/**
* The type of the React {@code Component} props of {@link AudioMutedIndicator}.
*/
type Props = {
interface IProps {
/**
* From which side of the indicator the tooltip should appear from.
*/
tooltipPosition: string
};
tooltipPosition: TOOLTIP_POSITION;
}
/**
* React {@code Component} for showing an audio muted icon with a tooltip.
*
* @returns {Component}
*/
const AudioMutedIndicator = ({ tooltipPosition }: Props) => (
const AudioMutedIndicator = ({ tooltipPosition }: IProps) => (
<BaseIndicator
icon = { IconMicSlash }
iconId = 'mic-disabled'

@ -1,28 +1,31 @@
/* @flow */
import React from 'react';
import { connect } from 'react-redux';
import { IReduxState } from '../../../app/types';
// eslint-disable-next-line lines-around-comment
// @ts-ignore
import AudioTrack from '../../../base/media/components/web/AudioTrack';
import { MEDIA_TYPE } from '../../../base/media/constants';
import { ITrack } from '../../../base/tracks/types';
/**
* The type of the React {@code Component} props of {@link AudioTracksContainer}.
*/
type Props = {
interface IProps {
/**
* All media tracks stored in redux.
*/
_tracks: Array<Object>
};
_tracks: ITrack[];
}
/**
* A container for the remote tracks audio elements.
*
* @param {Props} props - The props of the component.
* @param {IProps} props - The props of the component.
* @returns {Array<ReactElement>}
*/
function AudioTracksContainer(props: Props) {
function AudioTracksContainer(props: IProps) {
const { _tracks } = props;
const remoteAudioTracks = _tracks.filter(t => !t.local && t.mediaType === MEDIA_TYPE.AUDIO);
@ -31,7 +34,7 @@ function AudioTracksContainer(props: Props) {
{
remoteAudioTracks.map(t => {
const { jitsiTrack, participantId } = t;
const audioTrackId = jitsiTrack && jitsiTrack.getId();
const audioTrackId = jitsiTrack?.getId();
const id = `remoteAudio_${audioTrackId || ''}`;
return (
@ -50,9 +53,9 @@ function AudioTracksContainer(props: Props) {
*
* @param {Object} state - The Redux state.
* @private
* @returns {Props}
* @returns {IProps}
*/
function _mapStateToProps(state) {
function _mapStateToProps(state: IReduxState) {
// NOTE: The disadvantage of this approach is that the component will re-render on any track change.
// One way to solve the problem would be to pass only the participant ID to the AudioTrack component and
// find the corresponding track inside the AudioTrack's mapStateToProps. But currently this will be very

@ -43,7 +43,6 @@ import {
shouldRemoteVideosBeVisible
} from '../../functions';
// @ts-ignore
import AudioTracksContainer from './AudioTracksContainer';
import Thumbnail from './Thumbnail';
import ThumbnailWrapper from './ThumbnailWrapper';

@ -2,6 +2,7 @@ import React from 'react';
import { IconModerator } from '../../../base/icons/svg';
import BaseIndicator from '../../../base/react/components/web/BaseIndicator';
import { TOOLTIP_POSITION } from '../../../base/ui/constants.any';
/**
* The type of the React {@code Component} props of {@link ModeratorIndicator}.
@ -11,7 +12,7 @@ interface IProps {
/**
* From which side of the indicator the tooltip should appear from.
*/
tooltipPosition: 'top' | 'bottom' | 'left' | 'right';
tooltipPosition: TOOLTIP_POSITION;
}
/**

@ -6,6 +6,7 @@ import { IReduxState } from '../../../app/types';
import { IconPin } from '../../../base/icons/svg';
import { getParticipantById } from '../../../base/participants/functions';
import BaseIndicator from '../../../base/react/components/web/BaseIndicator';
import { TOOLTIP_POSITION } from '../../../base/ui/constants.any';
import { getPinnedActiveParticipants, isStageFilmstripAvailable } from '../../functions.web';
/**
@ -27,7 +28,7 @@ interface IProps {
/**
* From which side of the indicator the tooltip should appear from.
*/
tooltipPosition: 'top' | 'bottom' | 'left' | 'right';
tooltipPosition: TOOLTIP_POSITION;
}
const useStyles = makeStyles()(() => {

@ -7,6 +7,7 @@ import { IconRaiseHand } from '../../../base/icons/svg';
import { getParticipantById, hasRaisedHand } from '../../../base/participants/functions';
import { IParticipant } from '../../../base/participants/types';
import BaseIndicator from '../../../base/react/components/web/BaseIndicator';
import { TOOLTIP_POSITION } from '../../../base/ui/constants.any';
/**
* The type of the React {@code Component} props of {@link RaisedHandIndicator}.
@ -27,7 +28,7 @@ interface IProps {
/**
* From which side of the indicator the tooltip should appear from.
*/
tooltipPosition: 'top' | 'bottom' | 'left' | 'right';
tooltipPosition: TOOLTIP_POSITION;
}
const useStyles = makeStyles()(theme => {

@ -1,26 +1,24 @@
// @flow
import React from 'react';
import { IconScreenshare } from '../../../base/icons/svg';
import BaseIndicator from '../../../base/react/components/web/BaseIndicator';
import { TOOLTIP_POSITION } from '../../../base/ui/constants.any';
type Props = {
interface IProps {
/**
* From which side of the indicator the tooltip should appear from.
*/
tooltipPosition: string
};
tooltipPosition: TOOLTIP_POSITION;
}
/**
* React {@code Component} for showing a screen-sharing icon with a tooltip.
*
* @param {Props} props - React props passed to this component.
* @param {IProps} props - React props passed to this component.
* @returns {React$Element<any>}
*/
export default function ScreenShareIndicator(props: Props) {
export default function ScreenShareIndicator(props: IProps) {
return (
<BaseIndicator
icon = { IconScreenshare }

@ -1,14 +1,10 @@
/* @flow */
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { IReduxState } from '../../../app/types';
import { MEDIA_TYPE } from '../../../base/media/constants';
import { PARTICIPANT_ROLE } from '../../../base/participants/constants';
import {
getParticipantByIdOrUndefined,
isScreenShareParticipantById
} from '../../../base/participants/functions';
import { getParticipantByIdOrUndefined, isScreenShareParticipantById } from '../../../base/participants/functions';
import {
getVideoTrackByParticipant,
isLocalTrackMuted,
@ -20,45 +16,43 @@ import AudioMutedIndicator from './AudioMutedIndicator';
import ModeratorIndicator from './ModeratorIndicator';
import ScreenShareIndicator from './ScreenShareIndicator';
declare var interfaceConfig: Object;
/**
* The type of the React {@code Component} props of {@link StatusIndicators}.
*/
type Props = {
interface IProps {
/**
* Indicates if the audio muted indicator should be visible or not.
*/
_showAudioMutedIndicator: Boolean,
_showAudioMutedIndicator: Boolean;
/**
* Indicates if the moderator indicator should be visible or not.
*/
_showModeratorIndicator: Boolean,
_showModeratorIndicator: Boolean;
/**
* Indicates if the screen share indicator should be visible or not.
*/
_showScreenShareIndicator: Boolean,
_showScreenShareIndicator: Boolean;
/**
* The ID of the participant for which the status bar is rendered.
*/
participantID: String,
participantID: String;
/**
* The type of thumbnail.
*/
thumbnailType: string
};
thumbnailType: string;
}
/**
* React {@code Component} for showing the status bar in a thumbnail.
*
* @augments Component
*/
class StatusIndicators extends Component<Props> {
class StatusIndicators extends Component<IProps> {
/**
* Implements React's {@link Component#render()}.
*
@ -96,7 +90,7 @@ class StatusIndicators extends Component<Props> {
* _showScreenShareIndicator: boolean
* }}
*/
function _mapStateToProps(state, ownProps) {
function _mapStateToProps(state: IReduxState, ownProps: any) {
const { participantID, audio, moderator, screenshare } = ownProps;
// Only the local participant won't have id for the time when the conference is not yet joined.

@ -1,4 +1,3 @@
/* eslint-disable lines-around-comment */
import { Theme } from '@mui/material';
import { withStyles } from '@mui/styles';
import clsx from 'clsx';
@ -14,6 +13,7 @@ import Avatar from '../../../base/avatar/components/Avatar';
import { isMobileBrowser } from '../../../base/environment/utils';
import { translate } from '../../../base/i18n/functions';
import { JitsiTrackEvents } from '../../../base/lib-jitsi-meet';
// eslint-disable-next-line lines-around-comment
// @ts-ignore
import VideoTrack from '../../../base/media/components/web/VideoTrack';
import { MEDIA_TYPE } from '../../../base/media/constants';
@ -36,10 +36,10 @@ import {
getTrackByMediaTypeAndParticipant,
getVideoTrackByParticipant
} from '../../../base/tracks/functions';
import { ITrack } from '../../../base/tracks/types';
import { getVideoObjectPosition } from '../../../face-landmarks/functions';
import { hideGif, showGif } from '../../../gifs/actions';
import { getGifDisplayMode, getGifForParticipant } from '../../../gifs/functions';
// @ts-ignore
import PresenceLabel from '../../../presence-status/components/PresenceLabel';
import { LAYOUTS } from '../../../video-layout/constants';
import { getCurrentLayout } from '../../../video-layout/functions.web';
@ -61,13 +61,10 @@ import {
showGridInVerticalView
} from '../../functions';
// @ts-ignore
import ThumbnailAudioIndicator from './ThumbnailAudioIndicator';
import ThumbnailBottomIndicators from './ThumbnailBottomIndicators';
import ThumbnailTopIndicators from './ThumbnailTopIndicators';
// @ts-ignore
import VirtualScreenshareParticipant from './VirtualScreenshareParticipant';
/* eslint-enable lines-around-comment */
/**
* The type of the React {@code Component} state of {@link Thumbnail}.
@ -103,7 +100,7 @@ export interface IProps extends WithTranslation {
/**
* The audio track related to the participant.
*/
_audioTrack?: Object;
_audioTrack?: ITrack;
/**
* Indicates whether the local video flip feature is disabled or not.

@ -1,23 +1,24 @@
// @flow
import React, { useEffect, useState } from 'react';
import AudioLevelIndicator from '../../../audio-level-indicator/components/AudioLevelIndicator';
// eslint-disable-next-line lines-around-comment
// @ts-ignore
import JitsiMeetJS from '../../../base/lib-jitsi-meet/_';
import { ITrack } from '../../../base/tracks/types';
const JitsiTrackEvents = JitsiMeetJS.events.track;
type Props = {
interface IProps {
/**
* The audio track related to the participant.
*/
_audioTrack: ?Object
_audioTrack?: ITrack;
}
const ThumbnailAudioIndicator = ({
_audioTrack
}: Props) => {
}: IProps) => {
const [ audioLevel, setAudioLevel ] = useState(0);
useEffect(() => {
@ -25,14 +26,14 @@ const ThumbnailAudioIndicator = ({
if (_audioTrack) {
const { jitsiTrack } = _audioTrack;
jitsiTrack && jitsiTrack.on(JitsiTrackEvents.TRACK_AUDIO_LEVEL_CHANGED, setAudioLevel);
jitsiTrack?.on(JitsiTrackEvents.TRACK_AUDIO_LEVEL_CHANGED, setAudioLevel);
}
return () => {
if (_audioTrack) {
const { jitsiTrack } = _audioTrack;
jitsiTrack && jitsiTrack.off(JitsiTrackEvents.TRACK_AUDIO_LEVEL_CHANGED, setAudioLevel);
jitsiTrack?.off(JitsiTrackEvents.TRACK_AUDIO_LEVEL_CHANGED, setAudioLevel);
}
};
}, [ _audioTrack ]);

@ -10,7 +10,6 @@ import {
import { isScreenShareParticipantById } from '../../../base/participants/functions';
import DisplayName from '../../../display-name/components/web/DisplayName';
// @ts-ignore
import StatusIndicators from './StatusIndicators';
interface IProps {
@ -38,7 +37,7 @@ interface IProps {
/**
* The type of thumbnail.
*/
thumbnailType: string;
thumbnailType?: string;
}
const useStyles = makeStyles()(() => {

@ -11,8 +11,6 @@ import { getIndicatorsTooltipPosition } from '../../functions.web';
import PinnedIndicator from './PinnedIndicator';
import RaisedHandIndicator from './RaisedHandIndicator';
// eslint-disable-next-line lines-around-comment
// @ts-ignore
import StatusIndicators from './StatusIndicators';
import VideoMenuTriggerButton from './VideoMenuTriggerButton';
@ -26,12 +24,12 @@ interface IProps {
/**
* Hide popover callback.
*/
hidePopover: Function;
hidePopover?: Function;
/**
* Class name for the status indicators container.
*/
indicatorsClassName: string;
indicatorsClassName?: string;
/**
* Whether or not the thumbnail is hovered.
@ -41,7 +39,7 @@ interface IProps {
/**
* Whether or not the indicators are for the local participant.
*/
local: boolean;
local?: boolean;
/**
* Id of the participant for which the component is displayed.
@ -51,12 +49,12 @@ interface IProps {
/**
* Whether popover is visible or not.
*/
popoverVisible: boolean;
popoverVisible?: boolean;
/**
* Show popover callback.
*/
showPopover: Function;
showPopover?: Function;
/**
* The type of thumbnail.
@ -104,7 +102,7 @@ const ThumbnailTopIndicators = ({
if (isVirtualScreenshareParticipant) {
return (
<div className = { styles.container }>
{!_connectionIndicatorDisabled // @ts-ignore
{!_connectionIndicatorDisabled
&& <ConnectionIndicator
alwaysVisible = { showConnectionIndicator }
enableStatsDisplay = { true }
@ -124,7 +122,7 @@ const ThumbnailTopIndicators = ({
iconSize = { _indicatorIconSize }
participantId = { participantId }
tooltipPosition = { tooltipPosition } />
{!_connectionIndicatorDisabled // @ts-ignore
{!_connectionIndicatorDisabled
&& <ConnectionIndicator
alwaysVisible = { showConnectionIndicator }
enableStatsDisplay = { true }

@ -8,12 +8,12 @@ interface IProps {
/**
* Hide popover callback.
*/
hidePopover: Function;
hidePopover?: Function;
/**
* Whether or not the button is for the local participant.
*/
local: boolean;
local?: boolean;
/**
* The id of the participant for which the button is.
@ -23,12 +23,12 @@ interface IProps {
/**
* Whether popover is visible or not.
*/
popoverVisible: boolean;
popoverVisible?: boolean;
/**
* Show popover callback.
*/
showPopover: Function;
showPopover?: Function;
/**
* The type of thumbnail.

@ -1,102 +1,102 @@
// @flow
import clsx from 'clsx';
import React from 'react';
import React, { TouchEventHandler } from 'react';
import { useSelector } from 'react-redux';
// @ts-ignore
import VideoTrack from '../../../base/media/components/web/VideoTrack';
import { ITrack } from '../../../base/tracks/types';
import { LAYOUTS } from '../../../video-layout/constants';
import { getCurrentLayout } from '../../../video-layout/functions.web';
import ThumbnailBottomIndicators from './ThumbnailBottomIndicators';
import ThumbnailTopIndicators from './ThumbnailTopIndicators';
type Props = {
interface IProps {
/**
* An object containing the CSS classes.
*/
classes: Object,
classes: any;
/**
* The class name that will be used for the container.
*/
containerClassName: string,
containerClassName: string;
/**
* Indicates whether the thumbnail is hovered or not.
*/
isHovered: boolean,
isHovered: boolean;
/**
* Indicates whether the thumbnail is for local screenshare or not.
*/
isLocal: boolean,
isLocal: boolean;
/**
* Indicates whether we are currently running in a mobile browser.
*/
isMobile: boolean,
isMobile: boolean;
/**
* Click handler.
*/
onClick: Function,
onClick: (e?: React.MouseEvent) => void;
/**
* Mouse enter handler.
*/
onMouseEnter: Function,
onMouseEnter: (e?: React.MouseEvent) => void;
/**
* Mouse leave handler.
*/
onMouseLeave: Function,
onMouseLeave: (e?: React.MouseEvent) => void;
/**
/**
* Mouse move handler.
*/
onMouseMove: Function,
onMouseMove: (e?: React.MouseEvent) => void;
/**
* Touch end handler.
*/
onTouchEnd: Function,
onTouchEnd: TouchEventHandler;
/**
* Touch move handler.
*/
onTouchMove: Function,
onTouchMove: TouchEventHandler;
/**
* Touch start handler.
*/
onTouchStart: Function,
onTouchStart: TouchEventHandler;
/**
* The ID of the virtual screen share participant.
*/
participantId: string,
participantId: string;
/**
* Whether or not to display a tint background over tile.
*/
shouldDisplayTintBackground: boolean,
shouldDisplayTintBackground: boolean;
/**
* An object with the styles for thumbnail.
*/
styles: Object,
styles: any;
/**
* The type of thumbnail.
*/
thumbnailType: string,
thumbnailType: string;
/**
* JitsiTrack instance.
*/
videoTrack: Object
videoTrack: ITrack;
}
const VirtualScreenshareParticipant = ({
@ -117,7 +117,7 @@ const VirtualScreenshareParticipant = ({
styles,
videoTrack,
thumbnailType
}: Props) => {
}: IProps) => {
const currentLayout = useSelector(getCurrentLayout);
const videoTrackId = videoTrack?.jitsiTrack?.getId();
const video = videoTrack && <VideoTrack
@ -152,7 +152,6 @@ const VirtualScreenshareParticipant = ({
currentLayout === LAYOUTS.TILE_VIEW && 'tile-view-mode'
) }>
<ThumbnailTopIndicators
currentLayout = { currentLayout }
isHovered = { isHovered }
participantId = { participantId }
thumbnailType = { thumbnailType } />
@ -165,7 +164,6 @@ const VirtualScreenshareParticipant = ({
) }>
<ThumbnailBottomIndicators
className = { classes.indicatorsBackground }
currentLayout = { currentLayout }
local = { false }
participantId = { participantId }
showStatusIndicators = { true } />

@ -613,8 +613,8 @@ export function getDisplayModeInput(props: any, state: { canPlayEventReceived: b
* @param {string} thumbnailType - The current thumbnail type.
* @returns {string}
*/
export function getIndicatorsTooltipPosition(thumbnailType: string) {
return INDICATORS_TOOLTIP_POSITION[thumbnailType] || 'top';
export function getIndicatorsTooltipPosition(thumbnailType?: string) {
return INDICATORS_TOOLTIP_POSITION[thumbnailType ?? ''] || 'top';
}
/**

@ -30,7 +30,6 @@ import DialInSection from './DialInSection';
import InviteByEmailSection from './InviteByEmailSection';
// @ts-ignore
import InviteContactsSection from './InviteContactsSection';
// @ts-ignore
import LiveStreamSection from './LiveStreamSection';
/* eslint-enable lines-around-comment */

@ -1,25 +1,19 @@
// @flow
/* eslint-disable react/jsx-no-bind */
import React, { useState } from 'react';
import { WithTranslation } from 'react-i18next';
import { translate } from '../../../../base/i18n/functions';
import Icon from '../../../../base/icons/components/Icon';
import { IconCheck, IconCopy } from '../../../../base/icons/svg';
import { copyText } from '../../../../base/util/copyText.web';
type Props = {
interface IProps extends WithTranslation {
/**
* The current known URL for a live stream in progress.
*/
liveStreamViewURL: string,
/**
* Invoked to obtain translated strings.
*/
t: Function
liveStreamViewURL: string;
}
/**
@ -28,7 +22,7 @@ type Props = {
*
* @returns {React$Element<any>}
*/
function LiveStreamSection({ liveStreamViewURL, t }: Props) {
function LiveStreamSection({ liveStreamViewURL, t }: IProps) {
const [ isClicked, setIsClicked ] = useState(false);
const [ isHovered, setIsHovered ] = useState(false);

@ -207,12 +207,10 @@ export function startKnocking() {
const { membersOnly } = state['features/base/conference'];
const localParticipant = getLocalParticipant(state);
// @ts-ignore
dispatch(conferenceWillJoin(membersOnly));
// We need to update the conference object with the current display name, if approved
// we want to send that display name, it was not updated in case when pre-join is disabled
// @ts-ignore
sendLocalParticipant(state, membersOnly);
membersOnly?.joinLobby(localParticipant?.name, localParticipant?.email);

@ -1,31 +1,26 @@
// @flow
import React, { Component } from 'react';
import { WithTranslation } from 'react-i18next';
import { connect } from 'react-redux';
import { IReduxState } from '../../app/types';
import { translate } from '../../base/i18n/functions';
import { getDialInfoPageURL, shouldDisplayDialIn } from '../../invite/functions';
/**
* The type of the React {@code Component} props of {@link DialInLink}.
*/
type Props = {
interface IProps extends WithTranslation {
/**
* The redux state representing the dial-in numbers feature.
*/
_dialIn: Object,
_dialIn: Object;
/**
* The url of the page containing the dial-in numbers list.
*/
_dialInfoPageUrl: string,
/**
* Invoked to obtain translated strings.
*/
t: Function
};
_dialInfoPageUrl: string;
}
/**
* React {@code Component} responsible for displaying a telephone number and
@ -33,7 +28,7 @@ type Props = {
*
* @augments Component
*/
class DialInLink extends Component<Props> {
class DialInLink extends Component<IProps> {
/**
* Implements React's {@link Component#render()}.
*
@ -66,9 +61,9 @@ class DialInLink extends Component<Props> {
*
* @param {Object} state - The Redux state.
* @private
* @returns {Props}
* @returns {IProps}
*/
function _mapStateToProps(state) {
function _mapStateToProps(state: IReduxState) {
return {
_dialIn: state['features/invite'],
_dialInfoPageUrl: getDialInfoPageURL(state)

@ -14,8 +14,6 @@ import { hideNotification, showNotification } from '../notifications/actions';
import { NOTIFICATION_TIMEOUT_TYPE } from '../notifications/constants';
import { setNoAudioSignalNotificationUid } from './actions';
// eslint-disable-next-line lines-around-comment
// @ts-ignore
import DialInLink from './components/DialInLink';
import { NO_AUDIO_SIGNAL_SOUND_ID } from './constants';
import { NO_AUDIO_SIGNAL_SOUND_FILE } from './sounds';

@ -27,6 +27,6 @@ export function mediaPermissionPromptVisibilityChanged(isVisible: boolean, brows
*
* @returns {Function}
*/
export function openPageReloadDialog() {
export function openPageReloadDialog(): any {
// Dummy
}

@ -13,7 +13,6 @@ import {
} from '../../../base/lib-jitsi-meet/functions.web';
import logger from '../../logger';
// @ts-ignore
import ReloadButton from './ReloadButton';
/**
@ -26,7 +25,7 @@ export interface IProps extends WithTranslation {
* The details is an object containing more information about the connection
* failed (shard changes, was the computer suspended, etc.).
*/
details: Object;
details?: Object;
/**
* Redux dispatch function.
@ -36,7 +35,7 @@ export interface IProps extends WithTranslation {
/**
* The error that caused the display of the overlay.
*/
error: Error;
error?: any;
/**
* The indicator which determines whether the reload was caused by network
@ -48,7 +47,7 @@ export interface IProps extends WithTranslation {
* The reason for the error that will cause the reload.
* NOTE: Used by PageReloadOverlay only.
*/
reason: string;
reason?: string;
}
/**
@ -167,7 +166,7 @@ export default class AbstractPageReloadOverlay<P extends IProps>
}
sendAnalytics(createPageReloadScheduledEvent(
this.props.reason,
this.props.reason ?? '',
this.state.timeoutSeconds,
this.props.details));

@ -9,11 +9,13 @@ import { IReduxState } from '../../../app/types';
*/
interface IProps extends WithTranslation {
_premeetingBackground?: any;
/**
* The browser which is used currently. The text is different for every
* browser.
*/
browser: string;
browser?: string;
}
/**

@ -1,4 +1,4 @@
import React, { Component, ReactChildren } from 'react';
import React, { Component, ReactNode } from 'react';
/**
* The type of the React {@code Component} props of {@link OverlayFrame}.
@ -8,7 +8,7 @@ interface IProps {
/**
* The children components to be displayed into the overlay frame.
*/
children: ReactChildren;
children: ReactNode;
/**
* Indicates the css style of the overlay. If true, then lighter; darker,
@ -19,7 +19,7 @@ interface IProps {
/**
* The style property.
*/
style: Object;
style?: Object;
}
/**

@ -1,12 +1,10 @@
// @flow
import React from 'react';
import { connect } from 'react-redux';
import { translate } from '../../../base/i18n/functions';
import AbstractPageReloadOverlay, {
type Props,
IProps,
abstractMapStateToProps
} from './AbstractPageReloadOverlay';
import OverlayFrame from './OverlayFrame';
@ -16,7 +14,7 @@ import OverlayFrame from './OverlayFrame';
* conference is reloaded. Shows a warning message and counts down towards the
* reload.
*/
class PageReloadOverlay extends AbstractPageReloadOverlay<Props> {
class PageReloadOverlay extends AbstractPageReloadOverlay<IProps> {
/**
* Implements React's {@link Component#render()}.
*
@ -51,10 +49,6 @@ class PageReloadOverlay extends AbstractPageReloadOverlay<Props> {
</OverlayFrame>
);
}
_renderButton: () => React$Element<*>;
_renderProgressBar: () => React$Element<*>;
}
export default translate(connect(abstractMapStateToProps)(PageReloadOverlay));

@ -1,37 +1,32 @@
// @flow
import React, { Component } from 'react';
import { WithTranslation } from 'react-i18next';
import { connect } from 'react-redux';
import { reloadNow } from '../../../app/actions';
import { reloadNow } from '../../../app/actions.web';
import { IStore } from '../../../app/types';
import { translate } from '../../../base/i18n/functions';
/**
* The type of the React {@code Component} props of {@link ReloadButton}.
*/
type Props = {
interface IProps extends WithTranslation {
/**
* Reloads the page.
*/
_reloadNow: Function,
/**
* The function to translate human-readable text.
*/
t: Function,
_reloadNow: () => void;
/**
* The translation key for the text in the button.
*/
textKey: string
};
textKey: string;
}
/**
* Implements a React Component for button for the overlays that will reload
* the page.
*/
class ReloadButton extends Component<Props> {
class ReloadButton extends Component<IProps> {
/**
* Renders the button for relaod the page if necessary.
*
@ -63,7 +58,7 @@ class ReloadButton extends Component<Props> {
* @private
* @returns {Object}
*/
function _mapDispatchToProps(dispatch: Function) {
function _mapDispatchToProps(dispatch: IStore['dispatch']) {
return {
/**
* Dispatches the redux action to reload the page.

@ -1,5 +1,3 @@
// @flow
import React from 'react';
import { translate } from '../../../base/i18n/functions';

@ -1,16 +1,13 @@
// @flow
import React from 'react';
import { connect } from 'react-redux';
import { IReduxState } from '../../../app/types';
import { translate, translateToHTML } from '../../../base/i18n/functions';
import AbstractUserMediaPermissionsOverlay, { abstractMapStateToProps }
from './AbstractUserMediaPermissionsOverlay';
import OverlayFrame from './OverlayFrame';
declare var interfaceConfig: Object;
/**
* Implements a React Component for overlay with guidance how to proceed with
* gUM prompt.
@ -96,7 +93,7 @@ class UserMediaPermissionsOverlay extends AbstractUserMediaPermissionsOverlay {
* @param {Object} ownProps - The props passed to the component.
* @returns {Object}
*/
function mapStateToProps(state) {
function mapStateToProps(state: IReduxState) {
const { premeetingBackground } = state['features/dynamic-branding'];
return {
@ -105,5 +102,4 @@ function mapStateToProps(state) {
};
}
export default translate(
connect(mapStateToProps)(UserMediaPermissionsOverlay));
export default translate(connect(mapStateToProps)(UserMediaPermissionsOverlay));

@ -1,13 +1,9 @@
/* eslint-disable lines-around-comment */
import { IReduxState } from '../app/types';
// @ts-ignore
import PageReloadOverlay from './components/web/PageReloadOverlay';
// @ts-ignore
import SuspendedOverlay from './components/web/SuspendedOverlay';
// @ts-ignore
import UserMediaPermissionsOverlay from './components/web/UserMediaPermissionsOverlay';
/**
* Returns the overlay to be currently rendered.
*

@ -108,7 +108,6 @@ StateListenerRegistry.register(
});
} else if (RN_NO_RELOAD_DIALOG_ERRORS.indexOf(error.name) === -1 && typeof error.recoverable === 'undefined') {
setTimeout(() => {
// @ts-ignore
store.dispatch(openPageReloadDialog());
}, 500);
}

@ -172,7 +172,7 @@ function mapStateToProps(state, ownProps): Object {
const { participant } = ownProps;
const { ownerId } = state['features/shared-video'];
const localParticipantId = getLocalParticipant(state).id;
const _isAudioMuted = isParticipantAudioMuted(participant, state);
const _isAudioMuted = Boolean(participant && isParticipantAudioMuted(participant, state));
const _isVideoMuted = isParticipantVideoMuted(participant, state);
const audioMediaState = getParticipantAudioMediaState(participant, _isAudioMuted, state);
const videoMediaState = getParticipantVideoMediaState(participant, _isVideoMuted, state);

@ -1,25 +1,25 @@
// @flow
import React from 'react';
import { IParticipant } from '../../../base/participants/types';
import { LobbyParticipantItem } from './LobbyParticipantItem';
type Props = {
interface IProps {
/**
* Opens a drawer with actions for a knocking participant.
*/
openDrawerForParticipant: Function,
openDrawerForParticipant: Function;
/**
* If a drawer with actions should be displayed.
*/
overflowDrawer: boolean,
overflowDrawer: boolean;
/**
* List with the knocking participants.
*/
participants: Array<Object>
participants: IParticipant[];
}
/**
@ -28,7 +28,7 @@ type Props = {
* @param {Object} props - The props of the component.
* @returns {ReactNode}
*/
function LobbyParticipantItems({ openDrawerForParticipant, overflowDrawer, participants }: Props) {
function LobbyParticipantItems({ openDrawerForParticipant, overflowDrawer, participants }: IProps) {
return (
<div id = 'lobby-list'>
@ -44,4 +44,4 @@ function LobbyParticipantItems({ openDrawerForParticipant, overflowDrawer, parti
}
// Memoize the component in order to avoid rerender on drawer open/close.
export default React.memo<Props>(LobbyParticipantItems);
export default React.memo<IProps>(LobbyParticipantItems);

@ -14,7 +14,6 @@ import JitsiPortal from '../../../toolbox/components/web/JitsiPortal';
import { showOverflowDrawer } from '../../../toolbox/functions.web';
import { useLobbyActions, useParticipantDrawer } from '../../hooks';
// @ts-ignore
import LobbyParticipantItems from './LobbyParticipantItems';
const useStyles = makeStyles()(theme => {

@ -1,73 +1,77 @@
// @flow
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { IReduxState, IStore } from '../../../app/types';
import { translate } from '../../../base/i18n/functions';
import {
getLocalParticipant,
getParticipantByIdOrUndefined
} from '../../../base/participants/functions';
import { IParticipant } from '../../../base/participants/types';
import FakeParticipantContextMenu from '../../../video-menu/components/web/FakeParticipantContextMenu';
import ParticipantContextMenu from '../../../video-menu/components/web/ParticipantContextMenu';
type Props = {
interface IProps {
/**
* Shared video local participant owner.
*/
_localVideoOwner: boolean,
_localVideoOwner: boolean;
/**
* Participant reference.
*/
_participant: Object,
_participant?: IParticipant;
/**
* Closes a drawer if open.
*/
closeDrawer: Function,
closeDrawer: () => void;
/**
* The dispatch function from redux.
*/
dispatch: Function,
dispatch: IStore['dispatch'];
/**
* The participant for which the drawer is open.
* It contains the displayName & participantID.
*/
drawerParticipant: Object,
drawerParticipant: {
displayName: string;
participantID: string;
};
/**
* Target elements against which positioning calculations are made.
*/
offsetTarget?: HTMLElement,
offsetTarget?: HTMLElement;
/**
* Callback for the mouse entering the component.
*/
onEnter: Function,
onEnter: (e?: React.MouseEvent) => void;
/**
* Callback for the mouse leaving the component.
*/
onLeave: Function,
onLeave: (e?: React.MouseEvent) => void;
/**
* Callback for making a selection in the menu.
*/
onSelect: Function,
onSelect: (e?: React.MouseEvent | boolean) => void;
/**
* The ID of the participant.
*/
participantID: string
};
participantID: string;
}
/**
* Implements the MeetingParticipantContextMenu component.
*/
class MeetingParticipantContextMenu extends Component<Props> {
class MeetingParticipantContextMenu extends Component<IProps> {
/**
* Implements React's {@link Component#render()}.
@ -120,12 +124,12 @@ class MeetingParticipantContextMenu extends Component<Props> {
* @param {Object} state - The Redux state.
* @param {Object} ownProps - The own props of the component.
* @private
* @returns {Props}
* @returns {IProps}
*/
function _mapStateToProps(state, ownProps) {
function _mapStateToProps(state: IReduxState, ownProps: any) {
const { participantID, overflowDrawer, drawerParticipant } = ownProps;
const { ownerId } = state['features/shared-video'];
const localParticipantId = getLocalParticipant(state).id;
const localParticipantId = getLocalParticipant(state)?.id;
const participant = getParticipantByIdOrUndefined(state,
overflowDrawer ? drawerParticipant?.participantID : participantID);

@ -1,8 +1,7 @@
// @flow
import React, { useCallback, useEffect, useState } from 'react';
import { connect } from 'react-redux';
import { IReduxState } from '../../../app/types';
import { JitsiTrackEvents } from '../../../base/lib-jitsi-meet';
import { MEDIA_TYPE } from '../../../base/media/constants';
import {
@ -12,12 +11,14 @@ import {
hasRaisedHand,
isParticipantModerator
} from '../../../base/participants/functions';
import { IParticipant } from '../../../base/participants/types';
import {
getLocalAudioTrack,
getTrackByMediaTypeAndParticipant,
isParticipantAudioMuted,
isParticipantVideoMuted
} from '../../../base/tracks/functions.web';
import { ITrack } from '../../../base/tracks/types';
import { ACTION_TRIGGER, MEDIA_STATE, type MediaState } from '../../constants';
import {
getParticipantAudioMediaState,
@ -30,57 +31,57 @@ import ParticipantActionEllipsis from './ParticipantActionEllipsis';
import ParticipantItem from './ParticipantItem';
import ParticipantQuickAction from './ParticipantQuickAction';
type Props = {
interface IProps {
/**
* Media state for audio.
*/
_audioMediaState: MediaState,
_audioMediaState: MediaState;
/**
* The audio track related to the participant.
*/
_audioTrack: ?Object,
_audioTrack?: ITrack;
/**
* Whether or not to disable the moderator indicator.
*/
_disableModeratorIndicator: boolean,
_disableModeratorIndicator: boolean;
/**
* The display name of the participant.
*/
_displayName: string,
_displayName: string;
/**
* Whether or not moderation is supported.
*/
_isModerationSupported: boolean,
_isModerationSupported: boolean;
/**
* True if the participant is the local participant.
*/
_local: boolean,
_local: boolean;
/**
* Whether or not the local participant is moderator.
*/
_localModerator: boolean,
_localModerator: boolean;
/**
* Shared video local participant owner.
*/
_localVideoOwner: boolean,
_localVideoOwner: boolean;
/**
* Whether or not the participant name matches the search string.
*/
_matchesSearch: boolean,
_matchesSearch: boolean;
/**
* The participant.
*/
_participant: Object,
_participant?: IParticipant;
/**
* The participant ID.
@ -88,94 +89,94 @@ type Props = {
* NOTE: This ID may be different from participantID prop in the case when we pass undefined for the local
* participant. In this case the local participant ID will be filled through _participantID prop.
*/
_participantID: string,
_participantID: string;
/**
* The type of button to be rendered for the quick action.
*/
_quickActionButtonType: string,
_quickActionButtonType: string;
/**
* True if the participant have raised hand.
*/
_raisedHand: boolean,
_raisedHand: boolean;
/**
* Media state for video.
*/
_videoMediaState: MediaState,
_videoMediaState: MediaState;
/**
* The translated ask unmute text for the qiuck action buttons.
* The translated ask unmute text for the quick action buttons.
*/
askUnmuteText: string,
askUnmuteText: string;
/**
* Is this item highlighted.
*/
isHighlighted: boolean,
isHighlighted: boolean;
/**
* Whether or not the local participant is in a breakout room.
*/
isInBreakoutRoom: boolean,
isInBreakoutRoom: boolean;
/**
* Callback used to open a confirmation dialog for audio muting.
*/
muteAudio: Function,
muteAudio: Function;
/**
* The translated text for the mute participant button.
*/
muteParticipantButtonText: string,
muteParticipantButtonText: string;
/**
* Callback for the activation of this item's context menu.
*/
onContextMenu: Function,
onContextMenu: () => void;
/**
* Callback for the mouse leaving this item.
*/
onLeave: Function,
onLeave: (e?: React.MouseEvent) => void;
/**
* Callback used to open an actions drawer for a participant.
*/
openDrawerForParticipant: Function,
openDrawerForParticipant: Function;
/**
* True if an overflow drawer should be displayed.
*/
overflowDrawer: boolean,
overflowDrawer: boolean;
/**
* The aria-label for the ellipsis action.
*/
participantActionEllipsisLabel: string,
participantActionEllipsisLabel: string;
/**
* The ID of the participant.
*/
participantID: ?string,
participantID?: string;
/**
* Callback used to stop a participant's video.
*/
stopVideo: Function,
stopVideo: Function;
/**
* The translated "you" text.
*/
youText: string
};
youText: string;
}
/**
* Implements the MeetingParticipantItem component.
*
* @param {Props} props - The props of the component.
* @param {IProps} props - The props of the component.
* @returns {ReactElement}
*/
function MeetingParticipantItem({
@ -201,7 +202,7 @@ function MeetingParticipantItem({
participantActionEllipsisLabel,
stopVideo,
youText
}: Props) {
}: IProps) {
const [ hasAudioLevels, setHasAudioLevel ] = useState(false);
const [ registeredEvent, setRegisteredEvent ] = useState(false);
@ -227,7 +228,7 @@ function MeetingParticipantItem({
if (_audioTrack && registeredEvent) {
const { jitsiTrack } = _audioTrack;
jitsiTrack && jitsiTrack.off(JitsiTrackEvents.TRACK_AUDIO_LEVEL_CHANGED, _updateAudioLevel);
jitsiTrack?.off(JitsiTrackEvents.TRACK_AUDIO_LEVEL_CHANGED, _updateAudioLevel);
}
};
}, [ _audioTrack ]);
@ -292,20 +293,20 @@ function MeetingParticipantItem({
* @param {Object} state - The Redux state.
* @param {Object} ownProps - The own props of the component.
* @private
* @returns {Props}
* @returns {IProps}
*/
function _mapStateToProps(state, ownProps) {
function _mapStateToProps(state: IReduxState, ownProps: any) {
const { participantID, searchString } = ownProps;
const { ownerId } = state['features/shared-video'];
const localParticipantId = getLocalParticipant(state).id;
const localParticipantId = getLocalParticipant(state)?.id;
const participant = getParticipantByIdOrUndefined(state, participantID);
const _displayName = getParticipantDisplayName(state, participant?.id);
const _displayName = getParticipantDisplayName(state, participant?.id ?? '');
const _matchesSearch = participantMatchesSearch(participant, searchString);
const _isAudioMuted = isParticipantAudioMuted(participant, state);
const _isAudioMuted = Boolean(participant && isParticipantAudioMuted(participant, state));
const _isVideoMuted = isParticipantVideoMuted(participant, state);
const _audioMediaState = getParticipantAudioMediaState(participant, _isAudioMuted, state);
const _videoMediaState = getParticipantVideoMediaState(participant, _isVideoMuted, state);
@ -320,13 +321,13 @@ function _mapStateToProps(state, ownProps) {
return {
_audioMediaState,
_audioTrack,
_disableModeratorIndicator: disableModeratorIndicator,
_disableModeratorIndicator: Boolean(disableModeratorIndicator),
_displayName,
_local: Boolean(participant?.local),
_localVideoOwner: Boolean(ownerId === localParticipantId),
_matchesSearch,
_participant: participant,
_participantID: participant?.id,
_participantID: participant?.id ?? '',
_quickActionButtonType,
_raisedHand: hasRaisedHand(participant),
_videoMediaState

@ -1,80 +1,78 @@
// @flow
import React from 'react';
import MeetingParticipantItem from './MeetingParticipantItem';
type Props = {
interface IProps {
/**
* The translated ask unmute text for the qiuck action buttons.
* The translated ask unmute text for the quick action buttons.
*/
askUnmuteText: string,
askUnmuteText?: string;
/**
* Whether or not the local participant is in a breakout room.
*/
isInBreakoutRoom: boolean,
isInBreakoutRoom: boolean;
/**
* Callback for the mouse leaving this item.
*/
lowerMenu: Function,
/**
* Callback for the activation of this item's context menu.
*/
toggleMenu: Function,
lowerMenu: Function;
/**
* Callback used to open a confirmation dialog for audio muting.
*/
muteAudio: Function,
muteAudio: Function;
/**
* The translated text for the mute participant button.
*/
muteParticipantButtonText: string,
muteParticipantButtonText?: string;
/**
* The meeting participants.
* Callback used to open an actions drawer for a participant.
*/
participantIds: Array<string>,
openDrawerForParticipant: Function;
/**
* Callback used to open an actions drawer for a participant.
* True if an overflow drawer should be displayed.
*/
openDrawerForParticipant: Function,
overflowDrawer?: boolean;
/**
* True if an overflow drawer should be displayed.
* The aria-label for the ellipsis action.
*/
overflowDrawer: boolean,
participantActionEllipsisLabel: string;
/**
* The if of the participant for which the context menu should be open.
* The meeting participants.
*/
raiseContextId?: string,
participantIds: Array<string>;
/**
* The aria-label for the ellipsis action.
* The if of the participant for which the context menu should be open.
*/
participantActionEllipsisLabel: string,
raiseContextId?: string;
/**
* Current search string.
*/
searchString?: string,
searchString?: string;
/**
* Callback used to stop a participant's video.
*/
stopVideo: Function,
stopVideo: Function;
/**
* Callback for the activation of this item's context menu.
*/
toggleMenu: Function;
/**
* The translated "you" text.
*/
youText: string
youText: string;
}
/**
@ -95,8 +93,8 @@ function MeetingParticipantItems({
searchString,
stopVideo,
youText
}: Props) {
const renderParticipant = id => (
}: IProps) {
const renderParticipant = (id: string) => (
<MeetingParticipantItem
isHighlighted = { raiseContextId === id }
isInBreakoutRoom = { isInBreakoutRoom }
@ -113,8 +111,10 @@ function MeetingParticipantItems({
youText = { youText } />
);
return participantIds.map(renderParticipant);
return (<>
{participantIds.map(renderParticipant)}
</>);
}
// Memoize the component in order to avoid rerender on drawer open/close.
export default React.memo<Props>(MeetingParticipantItems);
export default React.memo<IProps>(MeetingParticipantItems);

@ -1,4 +1,3 @@
/* eslint-disable lines-around-comment */
import React, { useCallback } from 'react';
import { useTranslation } from 'react-i18next';
import { connect, useDispatch, useSelector } from 'react-redux';
@ -21,11 +20,8 @@ import { getSortedParticipantIds, shouldRenderInviteButton } from '../../functio
import { useParticipantDrawer } from '../../hooks';
import { InviteButton } from './InviteButton';
// @ts-ignore
import MeetingParticipantContextMenu from './MeetingParticipantContextMenu';
// @ts-ignore
import MeetingParticipantItems from './MeetingParticipantItems';
/* eslint-enable lines-around-comment */
const useStyles = makeStyles()(theme => {
return {
@ -140,7 +136,6 @@ function MeetingParticipants({
overflowDrawer = { overflowDrawer }
participantActionEllipsisLabel = { participantActionEllipsisLabel }
participantIds = { sortedParticipantIds }
participantsCount = { participantsCount }
raiseContextId = { raiseContext.entity }
searchString = { normalizeAccents(searchString) }
stopVideo = { stopVideo }

@ -1,4 +1,4 @@
import React, { ReactElement, useCallback } from 'react';
import React, { ReactNode, useCallback } from 'react';
import { WithTranslation } from 'react-i18next';
import { makeStyles } from 'tss-react/mui';
@ -32,7 +32,7 @@ interface IProps extends WithTranslation {
/**
* React children.
*/
children?: ReactElement | boolean;
children?: ReactNode;
/**
* Whether or not to disable the moderator indicator.

@ -17,7 +17,7 @@ interface IProps {
/**
* The translated "ask unmute" text.
*/
askUnmuteText: string;
askUnmuteText?: string;
/**
* The type of button to be displayed.
@ -32,7 +32,7 @@ interface IProps {
/**
* Label for mute participant button.
*/
muteParticipantButtonText: string;
muteParticipantButtonText?: string;
/**
* The ID of the participant.

@ -57,7 +57,8 @@ export function isForceMuted(participant: IParticipant | undefined, mediaType: M
* @param {IReduxState} state - The redux state.
* @returns {MediaState}
*/
export function getParticipantAudioMediaState(participant: IParticipant, muted: Boolean, state: IReduxState) {
export function getParticipantAudioMediaState(participant: IParticipant | undefined,
muted: Boolean, state: IReduxState) {
const dominantSpeaker = getDominantSpeakerParticipant(state);
if (muted) {
@ -83,7 +84,8 @@ export function getParticipantAudioMediaState(participant: IParticipant, muted:
* @param {IReduxState} state - The redux state.
* @returns {MediaState}
*/
export function getParticipantVideoMediaState(participant: IParticipant, muted: Boolean, state: IReduxState) {
export function getParticipantVideoMediaState(participant: IParticipant | undefined,
muted: Boolean, state: IReduxState) {
if (muted) {
if (isForceMuted(participant, MEDIA_TYPE.VIDEO, state)) {
return MEDIA_STATE.FORCE_MUTED;
@ -136,7 +138,7 @@ export const getParticipantsPaneOpen = (state: IReduxState) => Boolean(getState(
* @returns {string} - The type of the quick action button.
*/
export function getQuickActionButtonType(
participant: IParticipant,
participant: IParticipant | undefined,
isAudioMuted: Boolean,
isVideoMuted: Boolean,
state: IReduxState) {
@ -232,8 +234,9 @@ export function getSortedParticipantIds(stateful: IStateful) {
* @param {string} searchString - The participants search string.
* @returns {boolean}
*/
export function participantMatchesSearch(participant: { displayName: string; jid: string; name?: string; },
searchString: string) {
export function participantMatchesSearch(participant: IParticipant | undefined
| { displayName?: string; name?: string; },
searchString: string) {
if (searchString === '') {
return true;
}

@ -1,8 +1,8 @@
/* @flow */
import React, { Component } from 'react';
import { WithTranslation } from 'react-i18next';
import { connect } from 'react-redux';
import { IReduxState } from '../../app/types';
import { translate } from '../../base/i18n/functions';
import { getParticipantById } from '../../base/participants/functions';
import { Text } from '../../base/react/components/index';
@ -12,40 +12,35 @@ import { presenceStatusDisabled } from '../functions';
/**
* The type of the React {@code Component} props of {@link PresenceLabel}.
*/
type Props = {
interface IProps extends WithTranslation {
/**
* The current present status associated with the passed in participantID
* prop.
*/
_presence: string,
_presence: string;
/**
* Class name for the presence label.
*/
className: string,
className: string;
/**
* Default presence status that will be displayed if user's presence status
* is not available.
*/
defaultPresence: string,
defaultPresence: string;
/**
* The ID of the participant whose presence status should display.
*/
participantID: string,
participantID: string;
/**
* Styles for the presence label.
*/
style: Object,
/**
* Invoked to obtain translated strings.
*/
t: Function
};
style: Object;
}
/**
* React {@code Component} for displaying the current presence status of a
@ -53,7 +48,7 @@ type Props = {
*
* @augments Component
*/
class PresenceLabel extends Component<Props> {
class PresenceLabel extends Component<IProps> {
/**
* The default values for {@code PresenceLabel} component's property types.
*
@ -98,7 +93,7 @@ class PresenceLabel extends Component<Props> {
return null;
}
const i18nKey = STATUS_TO_I18N_KEY[_presence];
const i18nKey = STATUS_TO_I18N_KEY[_presence as keyof typeof STATUS_TO_I18N_KEY];
if (!i18nKey) { // fallback to status value
return _presence;
@ -120,7 +115,7 @@ class PresenceLabel extends Component<Props> {
* _presence: (string|undefined)
* }}
*/
function _mapStateToProps(state, ownProps) {
function _mapStateToProps(state: IReduxState, ownProps: any) {
const participant = getParticipantById(state, ownProps.participantID);
return {

@ -1,6 +1,7 @@
import React from 'react';
import Tooltip from '../../../base/tooltip/components/Tooltip';
import { TOOLTIP_POSITION } from '../../../base/ui/constants.any';
import AbstractToolbarButton, {
IProps as AbstractToolbarButtonProps
} from '../../../toolbox/components/AbstractToolbarButton';
@ -24,7 +25,7 @@ interface IProps extends AbstractToolbarButtonProps {
* From which direction the tooltip should appear, relative to the
* button.
*/
tooltipPosition: 'top' | 'bottom' | 'left' | 'right';
tooltipPosition: TOOLTIP_POSITION;
}
/**

@ -79,17 +79,17 @@ interface IProps {
/**
* Hides popover.
*/
hidePopover: Function;
hidePopover?: Function;
/**
* Whether the popover is visible or not.
*/
popoverVisible: boolean;
popoverVisible?: boolean;
/**
* Shows popover.
*/
showPopover: Function;
showPopover?: Function;
/**
* The type of the thumbnail.
@ -141,12 +141,12 @@ const LocalVideoMenuTriggerButton = ({
const { t } = useTranslation();
const _onPopoverOpen = useCallback(() => {
showPopover();
showPopover?.();
dispatch(setParticipantContextMenuOpen(true));
}, []);
const _onPopoverClose = useCallback(() => {
hidePopover();
hidePopover?.();
batch(() => {
dispatch(setParticipantContextMenuOpen(false));
dispatch(renderConnectionStatus(false));
@ -194,7 +194,7 @@ const LocalVideoMenuTriggerButton = ({
onPopoverClose = { _onPopoverClose }
onPopoverOpen = { _onPopoverOpen }
position = { _menuPosition }
visible = { popoverVisible }>
visible = { Boolean(popoverVisible) }>
{buttonVisible && !isMobileBrowser() && (
<Button
accessibilityLabel = { t('dialog.localUserControls') }

@ -75,7 +75,7 @@ interface IProps {
/**
* Hides popover.
*/
hidePopover: Function;
hidePopover?: Function;
/**
* The ID for the participant on which the remote video menu will act.
@ -85,12 +85,12 @@ interface IProps {
/**
* Whether the popover is visible or not.
*/
popoverVisible: boolean;
popoverVisible?: boolean;
/**
* Shows popover.
*/
showPopover: Function;
showPopover?: Function;
/**
* The type of the thumbnail.
@ -139,12 +139,12 @@ const RemoteVideoMenuTriggerButton = ({
const { t } = useTranslation();
const _onPopoverOpen = useCallback(() => {
showPopover();
showPopover?.();
dispatch(setParticipantContextMenuOpen(true));
}, []);
const _onPopoverClose = useCallback(() => {
hidePopover();
hidePopover?.();
batch(() => {
dispatch(setParticipantContextMenuOpen(false));
dispatch(renderConnectionStatus(false));
@ -197,7 +197,7 @@ const RemoteVideoMenuTriggerButton = ({
onPopoverClose = { _onPopoverClose }
onPopoverOpen = { _onPopoverOpen }
position = { _menuPosition }
visible = { popoverVisible }>
visible = { Boolean(popoverVisible) }>
{buttonVisible && !_disabled && (
!isMobileBrowser() && <Button
accessibilityLabel = { t('dialog.remoteUserControls', { username }) }

Loading…
Cancel
Save