diff --git a/globals.d.ts b/globals.d.ts index 89b20d8482..3de71264aa 100644 --- a/globals.d.ts +++ b/globals.d.ts @@ -13,8 +13,10 @@ declare global { const interfaceConfig: any; interface Window { - config?: IConfig; + config: IConfig; JITSI_MEET_LITE_SDK?: boolean; interfaceConfig?: any; } + + const config: IConfig; } diff --git a/react/features/base/conference/reducer.ts b/react/features/base/conference/reducer.ts index 7443628cfc..81d1788416 100644 --- a/react/features/base/conference/reducer.ts +++ b/react/features/base/conference/reducer.ts @@ -49,6 +49,7 @@ export interface IJitsiConference { getLocalTracks: Function; grantOwner: Function; isAVModerationSupported: Function; + isCallstatsEnabled: Function; isEndConferenceSupported: Function; isLobbySupported: Function; kickParticipant: Function; @@ -60,6 +61,7 @@ export interface IJitsiConference { replaceTrack: Function; sendCommand: Function; sendEndpointMessage: Function; + sendFeedback: Function; sendLobbyMessage: Function; sessionId: string; setDisplayName: Function; diff --git a/react/features/base/config/configType.ts b/react/features/base/config/configType.ts index cc1dc4a284..92e993e5a0 100644 --- a/react/features/base/config/configType.ts +++ b/react/features/base/config/configType.ts @@ -115,6 +115,7 @@ export interface IConfig { autoKnockLobby?: boolean; backgroundAlpha?: number; bosh?: string; + brandingDataUrl?: string; brandingRoomAlias?: string; breakoutRooms?: { hideAddRoomButton?: boolean; @@ -342,6 +343,8 @@ export interface IConfig { iAmRecorder?: boolean; iAmSipGateway?: boolean; inviteAppName?: string | null; + jaasFeedbackMetadataURL?: string; + jaasTokenUrl?: string; lastNLimits?: { [key: number]: number; }; diff --git a/react/features/base/jwt/reducer.ts b/react/features/base/jwt/reducer.ts index 69cad1e922..d01fca6c4c 100644 --- a/react/features/base/jwt/reducer.ts +++ b/react/features/base/jwt/reducer.ts @@ -12,6 +12,7 @@ export interface IJwtState { server?: string; tenant?: string; user?: { + id: string; name: string; }; } diff --git a/react/features/base/settings/reducer.ts b/react/features/base/settings/reducer.ts index c76dc373d9..86d689244c 100644 --- a/react/features/base/settings/reducer.ts +++ b/react/features/base/settings/reducer.ts @@ -86,7 +86,7 @@ export interface ISettingsState { userSelectedMicDeviceLabel?: string; userSelectedNotifications?: { [key: string]: boolean; - } | boolean; + }; userSelectedSkipPrejoin?: boolean; videoSettingsVisible?: boolean; visible?: boolean; diff --git a/react/features/chat/middleware.js b/react/features/chat/middleware.ts similarity index 84% rename from react/features/chat/middleware.js rename to react/features/chat/middleware.ts index c4df0d58e9..6952d18e88 100644 --- a/react/features/chat/middleware.js +++ b/react/features/chat/middleware.ts @@ -1,12 +1,12 @@ -// @flow -import { type Dispatch } from 'redux'; - -import { APP_WILL_MOUNT, APP_WILL_UNMOUNT } from '../base/app'; -import { - CONFERENCE_JOINED, - getCurrentConference -} from '../base/conference'; -import { openDialog } from '../base/dialog'; +/* eslint-disable lines-around-comment */ +import { AnyAction } from 'redux'; + +import { IState, IStore } from '../app/types'; +import { APP_WILL_MOUNT, APP_WILL_UNMOUNT } from '../base/app/actionTypes'; +import { CONFERENCE_JOINED } from '../base/conference/actionTypes'; +import { getCurrentConference } from '../base/conference/functions'; +import { IJitsiConference } from '../base/conference/reducer'; +import { openDialog } from '../base/dialog/actions'; import { JitsiConferenceErrors, JitsiConferenceEvents @@ -15,27 +15,28 @@ import { getLocalParticipant, getParticipantById, getParticipantDisplayName -} from '../base/participants'; -import { MiddlewareRegistry, StateListenerRegistry } from '../base/redux'; -import { playSound, registerSound, unregisterSound } from '../base/sounds'; +} from '../base/participants/functions'; +import MiddlewareRegistry from '../base/redux/MiddlewareRegistry'; +import StateListenerRegistry from '../base/redux/StateListenerRegistry'; +import { playSound, registerSound, unregisterSound } from '../base/sounds/actions'; import { addGif } from '../gifs/actions'; import { GIF_PREFIX } from '../gifs/constants'; import { getGifDisplayMode, isGifMessage } from '../gifs/functions'; -import { NOTIFICATION_TIMEOUT_TYPE, showMessageNotification } from '../notifications'; +import { showMessageNotification } from '../notifications/actions'; +import { NOTIFICATION_TIMEOUT_TYPE } from '../notifications/constants'; import { resetNbUnreadPollsMessages } from '../polls/actions'; import { ADD_REACTION_MESSAGE } from '../reactions/actionTypes'; import { pushReactions } from '../reactions/actions.any'; import { ENDPOINT_REACTION_NAME } from '../reactions/constants'; import { getReactionMessageFromBuffer, isReactionsEnabled } from '../reactions/functions.any'; -import { endpointMessageReceived } from '../subtitles'; -import { - showToolbox -} from '../toolbox/actions'; +import { endpointMessageReceived } from '../subtitles/actions.any'; +// @ts-ignore +import { showToolbox } from '../toolbox/actions'; import { ADD_MESSAGE, CLOSE_CHAT, OPEN_CHAT, SEND_MESSAGE, SET_IS_POLL_TAB_FOCUSED } from './actionTypes'; -import { addMessage, clearMessages } from './actions'; -import { closeChat } from './actions.any'; +import { addMessage, clearMessages, closeChat } from './actions.any'; +// @ts-ignore import { ChatPrivacyDialog } from './components'; import { INCOMING_MSG_SOUND_ID, @@ -47,9 +48,6 @@ import { import { getUnreadCount } from './functions'; import { INCOMING_MSG_SOUND_FILE } from './sounds'; -declare var APP: Object; -declare var interfaceConfig : Object; - /** * Timeout for when to show the privacy notice after a private message was received. * @@ -167,13 +165,15 @@ MiddlewareRegistry.register(store => next => action => { } case ADD_REACTION_MESSAGE: { - _handleReceivedMessage(store, { - id: localParticipant.id, - message: action.message, - privateMessage: false, - timestamp: Date.now(), - lobbyChat: false - }, false, true); + if (localParticipant?.id) { + _handleReceivedMessage(store, { + id: localParticipant.id, + message: action.message, + privateMessage: false, + timestamp: Date.now(), + lobbyChat: false + }, false, true); + } } } @@ -220,7 +220,7 @@ StateListenerRegistry.register( * @private * @returns {void} */ -function _addChatMsgListener(conference, store) { +function _addChatMsgListener(conference: IJitsiConference, store: IStore) { if (store.getState()['features/base/config'].iAmRecorder) { // We don't register anything on web if we are in iAmRecorder mode return; @@ -228,7 +228,7 @@ function _addChatMsgListener(conference, store) { conference.on( JitsiConferenceEvents.MESSAGE_RECEIVED, - (id, message, timestamp) => { + (id: string, message: string, timestamp: number) => { _onConferenceMessageReceived(store, { id, message, timestamp, @@ -238,7 +238,7 @@ function _addChatMsgListener(conference, store) { conference.on( JitsiConferenceEvents.PRIVATE_MESSAGE_RECEIVED, - (id, message, timestamp) => { + (id: string, message: string, timestamp: number) => { _onConferenceMessageReceived(store, { id, message, @@ -250,13 +250,14 @@ function _addChatMsgListener(conference, store) { conference.on( JitsiConferenceEvents.ENDPOINT_MESSAGE_RECEIVED, - (...args) => { + (...args: any) => { const state = store.getState(); if (!isReactionsEnabled(state)) { return; } + // @ts-ignore store.dispatch(endpointMessageReceived(...args)); if (args && args.length >= 2) { @@ -277,7 +278,7 @@ function _addChatMsgListener(conference, store) { }); conference.on( - JitsiConferenceEvents.CONFERENCE_ERROR, (errorType, error) => { + JitsiConferenceEvents.CONFERENCE_ERROR, (errorType: string, error: Error) => { errorType === JitsiConferenceErrors.CHAT_ERROR && _handleChatError(store, error); }); } @@ -289,7 +290,8 @@ function _addChatMsgListener(conference, store) { * @param {Object} message - The message object. * @returns {void} */ -function _onConferenceMessageReceived(store, { id, message, timestamp, privateMessage }) { +function _onConferenceMessageReceived(store: IStore, { id, message, timestamp, privateMessage }: { + id: string; message: string; privateMessage: boolean; timestamp: number; }) { const isGif = isGifMessage(message); if (isGif) { @@ -315,7 +317,7 @@ function _onConferenceMessageReceived(store, { id, message, timestamp, privateMe * @param {string} message - The message sent. * @returns {void} */ -function _handleGifMessageReceived(store, id, message) { +function _handleGifMessageReceived(store: IStore, id: string, message: string) { const url = message.substring(GIF_PREFIX.length, message.length - 1); store.dispatch(addGif(id, url)); @@ -328,7 +330,7 @@ function _handleGifMessageReceived(store, id, message) { * @param {string} error - The error message. * @returns {void} */ -function _handleChatError({ dispatch }, error) { +function _handleChatError({ dispatch }: IStore, error: Error) { dispatch(addMessage({ hasRead: true, messageType: MESSAGE_TYPE_ERROR, @@ -346,7 +348,7 @@ function _handleChatError({ dispatch }, error) { * @returns {Function} */ export function handleLobbyMessageReceived(message: string, participantId: string) { - return async (dispatch: Dispatch, getState: Function) => { + return async (dispatch: IStore['dispatch'], getState: IStore['getState']) => { _handleReceivedMessage({ dispatch, getState }, { id: participantId, message, @@ -364,11 +366,11 @@ export function handleLobbyMessageReceived(message: string, participantId: strin * @param {string} id - The knocking participant id. * @returns {string} */ -function getLobbyChatDisplayName(state, id) { +function getLobbyChatDisplayName(state: IState, id: string) { const { knockingParticipants } = state['features/lobby']; const { lobbyMessageRecipient } = state['features/chat']; - if (id === lobbyMessageRecipient.id) { + if (id === lobbyMessageRecipient?.id) { return lobbyMessageRecipient.name; } @@ -390,8 +392,9 @@ function getLobbyChatDisplayName(state, id) { * @param {boolean} isReaction - Whether or not the message is a reaction message. * @returns {void} */ -function _handleReceivedMessage({ dispatch, getState }, - { id, message, privateMessage, timestamp, lobbyChat }, +function _handleReceivedMessage({ dispatch, getState }: IStore, + { id, message, privateMessage, timestamp, lobbyChat }: { + id: string; lobbyChat: boolean; message: string; privateMessage: boolean; timestamp: number; }, shouldPlaySound = true, isReaction = false ) { @@ -407,7 +410,7 @@ function _handleReceivedMessage({ dispatch, getState }, // Provide a default for for the case when a message is being // backfilled for a participant that has left the conference. - const participant = getParticipantById(state, id) || {}; + const participant = getParticipantById(state, id) || { local: undefined }; const localParticipant = getLocalParticipant(getState); const displayName = lobbyChat @@ -418,7 +421,7 @@ function _handleReceivedMessage({ dispatch, getState }, const millisecondsTimestamp = timestampToDate.getTime(); // skip message notifications on join (the messages having timestamp - coming from the history) - const shouldShowNotification = userSelectedNotifications['notify.chatMessages'] + const shouldShowNotification = userSelectedNotifications?.['notify.chatMessages'] && !hasRead && !isReaction && !timestamp; dispatch(addMessage({ @@ -429,7 +432,7 @@ function _handleReceivedMessage({ dispatch, getState }, message, privateMessage, lobbyChat, - recipient: getParticipantDisplayName(state, localParticipant.id), + recipient: getParticipantDisplayName(state, localParticipant?.id ?? ''), timestamp: millisecondsTimestamp, isReaction })); @@ -471,9 +474,14 @@ function _handleReceivedMessage({ dispatch, getState }, * @param {boolean} isLobbyPrivateMessage - Is a lobby message. * @returns {void} */ -function _persistSentPrivateMessage({ dispatch, getState }, recipientID, message, isLobbyPrivateMessage = false) { +function _persistSentPrivateMessage({ dispatch, getState }: IStore, recipientID: string, + message: string, isLobbyPrivateMessage = false) { const state = getState(); const localParticipant = getLocalParticipant(state); + + if (!localParticipant?.id) { + return; + } const displayName = getParticipantDisplayName(state, localParticipant.id); const { lobbyMessageRecipient } = state['features/chat']; @@ -486,7 +494,7 @@ function _persistSentPrivateMessage({ dispatch, getState }, recipientID, message privateMessage: !isLobbyPrivateMessage, lobbyChat: isLobbyPrivateMessage, recipient: isLobbyPrivateMessage - ? lobbyMessageRecipient && lobbyMessageRecipient.name + ? lobbyMessageRecipient?.name : getParticipantDisplayName(getState, recipientID), timestamp: Date.now() })); @@ -500,7 +508,7 @@ function _persistSentPrivateMessage({ dispatch, getState }, recipientID, message * @param {Object} action - The action being dispatched now. * @returns {string?} */ -function _shouldSendPrivateMessageTo(state, action): ?string { +function _shouldSendPrivateMessageTo(state: IState, action: AnyAction) { if (action.ignorePrivacy) { // Shortcut: this is only true, if we already displayed the notice, so no need to show it again. return undefined; diff --git a/react/features/chat/reducer.ts b/react/features/chat/reducer.ts index 9c5bc5bac4..f0fc47e188 100644 --- a/react/features/chat/reducer.ts +++ b/react/features/chat/reducer.ts @@ -38,7 +38,7 @@ export interface IMessage { messageType: string; privateMessage: boolean; recipient: string; - timestamp: string; + timestamp: number; } export interface IChatState { diff --git a/react/features/display-name/actions.js b/react/features/display-name/actions.ts similarity index 72% rename from react/features/display-name/actions.js rename to react/features/display-name/actions.ts index 771a2be6ac..ff4ce2b1cd 100644 --- a/react/features/display-name/actions.js +++ b/react/features/display-name/actions.ts @@ -1,7 +1,6 @@ -// @flow - -import { openDialog } from '../../features/base/dialog'; +import { openDialog } from '../base/dialog/actions'; +// @ts-ignore import { DisplayNamePrompt } from './components'; /** @@ -11,7 +10,7 @@ import { DisplayNamePrompt } from './components'; * submit of the dialog. * @returns {Object} */ -export function openDisplayNamePrompt(onPostSubmit: ?Function) { +export function openDisplayNamePrompt(onPostSubmit?: Function) { return openDialog(DisplayNamePrompt, { onPostSubmit }); diff --git a/react/features/display-name/middleware.js b/react/features/display-name/middleware.ts similarity index 67% rename from react/features/display-name/middleware.js rename to react/features/display-name/middleware.ts index 163cc1f335..8a5455d1bb 100644 --- a/react/features/display-name/middleware.js +++ b/react/features/display-name/middleware.ts @@ -1,9 +1,9 @@ -// @flow - -import { hideDialog, isDialogOpen } from '../base/dialog'; -import { MiddlewareRegistry } from '../base/redux'; -import { SETTINGS_UPDATED } from '../base/settings'; +import { hideDialog } from '../base/dialog/actions'; +import { isDialogOpen } from '../base/dialog/functions'; +import MiddlewareRegistry from '../base/redux/MiddlewareRegistry'; +import { SETTINGS_UPDATED } from '../base/settings/actionTypes'; +// @ts-ignore import { DisplayNamePrompt } from './components'; /** diff --git a/react/features/dynamic-branding/functions.any.js b/react/features/dynamic-branding/functions.any.ts similarity index 79% rename from react/features/dynamic-branding/functions.any.js rename to react/features/dynamic-branding/functions.any.ts index 26cc80b537..73bf3b8bca 100644 --- a/react/features/dynamic-branding/functions.any.js +++ b/react/features/dynamic-branding/functions.any.ts @@ -1,6 +1,6 @@ -// @flow - -import { toState } from '../base/redux'; +import { IState } from '../app/types'; +import { IStateful } from '../base/app/types'; +import { toState } from '../base/redux/functions'; /** @@ -10,13 +10,13 @@ import { toState } from '../base/redux'; * @param {Object} state - A redux state. * @returns {string} */ -export function extractFqnFromPath(state?: Object) { +export function extractFqnFromPath(state?: IState) { let pathname; if (window.location.pathname) { pathname = window.location.pathname; - } else if (state && state['features/base/connection']) { - pathname = state['features/base/connection'].locationURL.pathname; + } else if (state?.['features/base/connection']) { + pathname = state['features/base/connection'].locationURL?.pathname ?? ''; } else { return ''; } @@ -34,7 +34,7 @@ export function extractFqnFromPath(state?: Object) { * {@code getState} function. * @returns {string} */ -export async function getDynamicBrandingUrl(stateful: Object | Function) { +export async function getDynamicBrandingUrl(stateful: IStateful) { const state = toState(stateful); // NB: On web this is dispatched really early, before the config has been stored in the @@ -61,6 +61,6 @@ export async function getDynamicBrandingUrl(stateful: Object | Function) { * @param {Object} state - Global state of the app. * @returns {boolean} */ -export function isDynamicBrandingDataLoaded(state: Object) { +export function isDynamicBrandingDataLoaded(state: IState) { return state['features/dynamic-branding'].customizationReady; } diff --git a/react/features/e2ee/functions.js b/react/features/e2ee/functions.ts similarity index 82% rename from react/features/e2ee/functions.js rename to react/features/e2ee/functions.ts index 1257733fc6..495171a319 100644 --- a/react/features/e2ee/functions.js +++ b/react/features/e2ee/functions.ts @@ -1,6 +1,6 @@ - +import { IStateful } from '../base/app/types'; import { getParticipantCount } from '../base/participants/functions'; -import { toState } from '../base/redux'; +import { toState } from '../base/redux/functions'; import { MAX_MODE_LIMIT, MAX_MODE_THRESHOLD } from './constants'; @@ -8,14 +8,14 @@ import { MAX_MODE_LIMIT, MAX_MODE_THRESHOLD } from './constants'; * Gets the value of a specific React {@code Component} prop of the currently * mounted {@link App}. * - * @param {Function|Object} stateful - The redux store or {@code getState} + * @param {IStateful} stateful - The redux store or {@code getState} * function. * @param {string} propName - The name of the React {@code Component} prop of * the currently mounted {@code App} to get. * @returns {*} The value of the specified React {@code Component} prop of the * currently mounted {@code App}. */ -export function doesEveryoneSupportE2EE(stateful) { +export function doesEveryoneSupportE2EE(stateful: IStateful) { const state = toState(stateful); const { everyoneSupportE2EE } = state['features/e2ee']; const { e2eeSupported } = state['features/base/conference']; @@ -37,7 +37,7 @@ export function doesEveryoneSupportE2EE(stateful) { * function. * @returns {boolean}. */ -export function isMaxModeReached(stateful) { +export function isMaxModeReached(stateful: IStateful) { const participantCount = getParticipantCount(toState(stateful)); return participantCount >= MAX_MODE_LIMIT; @@ -50,7 +50,7 @@ export function isMaxModeReached(stateful) { * function. * @returns {boolean}. */ -export function isMaxModeThresholdReached(stateful) { +export function isMaxModeThresholdReached(stateful: IStateful) { const participantCount = getParticipantCount(toState(stateful)); return participantCount >= MAX_MODE_LIMIT + MAX_MODE_THRESHOLD; diff --git a/react/features/e2ee/logger.js b/react/features/e2ee/logger.ts similarity index 90% rename from react/features/e2ee/logger.js rename to react/features/e2ee/logger.ts index ef2342ebd4..cdad6b5194 100644 --- a/react/features/e2ee/logger.js +++ b/react/features/e2ee/logger.ts @@ -1,5 +1,3 @@ -// @flow - import { getLogger } from '../base/logging/functions'; export default getLogger('features/e2ee'); diff --git a/react/features/e2ee/middleware.js b/react/features/e2ee/middleware.ts similarity index 88% rename from react/features/e2ee/middleware.js rename to react/features/e2ee/middleware.ts index bd029c8020..383a513545 100644 --- a/react/features/e2ee/middleware.js +++ b/react/features/e2ee/middleware.ts @@ -1,22 +1,21 @@ -// @flow - import { batch } from 'react-redux'; -import { APP_WILL_MOUNT, APP_WILL_UNMOUNT } from '../base/app'; -import { CONFERENCE_JOINED, getCurrentConference } from '../base/conference'; +import { IStore } from '../app/types'; +import { APP_WILL_MOUNT, APP_WILL_UNMOUNT } from '../base/app/actionTypes'; +import { CONFERENCE_JOINED } from '../base/conference/actionTypes'; +import { getCurrentConference } from '../base/conference/functions'; +import { PARTICIPANT_JOINED, PARTICIPANT_LEFT, PARTICIPANT_UPDATED } from '../base/participants/actionTypes'; +import { participantUpdated } from '../base/participants/actions'; import { - PARTICIPANT_JOINED, - PARTICIPANT_LEFT, - PARTICIPANT_UPDATED, getLocalParticipant, getParticipantById, getParticipantCount, getRemoteParticipants, - isScreenShareParticipant, - participantUpdated -} from '../base/participants'; -import { MiddlewareRegistry, StateListenerRegistry } from '../base/redux'; -import { playSound, registerSound, unregisterSound } from '../base/sounds'; + isScreenShareParticipant +} from '../base/participants/functions'; +import MiddlewareRegistry from '../base/redux/MiddlewareRegistry'; +import StateListenerRegistry from '../base/redux/StateListenerRegistry'; +import { playSound, registerSound, unregisterSound } from '../base/sounds/actions'; import { SET_MEDIA_ENCRYPTION_KEY, TOGGLE_E2EE } from './actionTypes'; import { setE2EEMaxMode, setEveryoneEnabledE2EE, setEveryoneSupportE2EE, toggleE2EE } from './actions'; @@ -66,7 +65,7 @@ MiddlewareRegistry.register(({ dispatch, getState }) => next => action => { let newEveryoneSupportE2EE = true; let newEveryoneEnabledE2EE = true; - // eslint-disable-next-line no-unused-vars + // eslint-disable-next-line @typescript-eslint/no-unused-vars for (const [ key, p ] of getRemoteParticipants(state)) { if (!p.e2eeEnabled) { newEveryoneEnabledE2EE = false; @@ -136,10 +135,10 @@ MiddlewareRegistry.register(({ dispatch, getState }) => next => action => { case PARTICIPANT_LEFT: { const previosState = getState(); - const participant = getParticipantById(previosState, action.participant?.id) || {}; + const participant = getParticipantById(previosState, action.participant?.id); const result = next(action); const newState = getState(); - const { e2eeEnabled = false, e2eeSupported = false } = participant; + const { e2eeEnabled = false, e2eeSupported = false } = participant ?? {}; if (isScreenShareParticipant(participant)) { return result; @@ -154,7 +153,7 @@ MiddlewareRegistry.register(({ dispatch, getState }) => next => action => { let latestEveryoneEnabledE2EE = true; let latestEveryoneSupportE2EE = true; - // eslint-disable-next-line no-unused-vars + // eslint-disable-next-line @typescript-eslint/no-unused-vars for (const [ key, p ] of getRemoteParticipants(newState)) { if (!p.e2eeEnabled) { latestEveryoneEnabledE2EE = false; @@ -190,7 +189,7 @@ MiddlewareRegistry.register(({ dispatch, getState }) => next => action => { } case TOGGLE_E2EE: { - if (conference && conference.isE2EESupported() && conference.isE2EEEnabled() !== action.enabled) { + if (conference?.isE2EESupported() && conference.isE2EEEnabled() !== action.enabled) { logger.debug(`E2EE will be ${action.enabled ? 'enabled' : 'disabled'}`); conference.toggleE2EE(action.enabled); @@ -199,7 +198,7 @@ MiddlewareRegistry.register(({ dispatch, getState }) => next => action => { dispatch(participantUpdated({ e2eeEnabled: action.enabled, - id: participant.id, + id: participant?.id ?? '', local: true })); @@ -212,7 +211,7 @@ MiddlewareRegistry.register(({ dispatch, getState }) => next => action => { } case SET_MEDIA_ENCRYPTION_KEY: { - if (conference && conference.isE2EESupported()) { + if (conference?.isE2EESupported()) { const { exportedKey, index } = action.keyInfo; if (exportedKey) { @@ -265,7 +264,7 @@ StateListenerRegistry.register( * @private * @returns {void} */ -function _updateMaxMode(dispatch, getState) { +function _updateMaxMode(dispatch: IStore['dispatch'], getState: IStore['getState']) { const state = getState(); const { e2ee = {} } = state['features/base/config']; diff --git a/react/features/e2ee/sounds.js b/react/features/e2ee/sounds.ts similarity index 96% rename from react/features/e2ee/sounds.js rename to react/features/e2ee/sounds.ts index e349d62d46..1519b4db95 100644 --- a/react/features/e2ee/sounds.js +++ b/react/features/e2ee/sounds.ts @@ -1,5 +1,3 @@ -// @flow - /** * The name of the bundled audio file which will be played when e2ee is disabled. * diff --git a/react/features/feedback/actions.js b/react/features/feedback/actions.ts similarity index 86% rename from react/features/feedback/actions.js rename to react/features/feedback/actions.ts index 688a6d4e97..ad5606b9b2 100644 --- a/react/features/feedback/actions.js +++ b/react/features/feedback/actions.ts @@ -1,9 +1,8 @@ -// @flow - -import type { Dispatch } from 'redux'; - +// @ts-ignore import { FEEDBACK_REQUEST_IN_PROGRESS } from '../../../modules/UI/UIErrors'; -import { openDialog } from '../base/dialog'; +import { IStore } from '../app/types'; +import { IJitsiConference } from '../base/conference/reducer'; +import { openDialog } from '../base/dialog/actions'; import { extractFqnFromPath } from '../dynamic-branding/functions.any'; import { isVpaasMeeting } from '../jaas/functions'; @@ -12,11 +11,11 @@ import { SUBMIT_FEEDBACK_ERROR, SUBMIT_FEEDBACK_SUCCESS } from './actionTypes'; +// eslint-disable-next-line lines-around-comment +// @ts-ignore import { FeedbackDialog } from './components'; import { sendFeedbackToJaaSRequest } from './functions'; -declare var config: Object; - /** * Caches the passed in feedback in the redux store. * @@ -48,13 +47,13 @@ export function cancelFeedback(score: number, message: string) { * resolved with true if the dialog is disabled or the feedback was already * submitted. Rejected if another dialog is already displayed. */ -export function maybeOpenFeedbackDialog(conference: Object) { +export function maybeOpenFeedbackDialog(conference: IJitsiConference) { type R = { - feedbackSubmitted: boolean, - showThankYou: boolean + feedbackSubmitted: boolean; + showThankYou: boolean; }; - return (dispatch: Dispatch, getState: Function): Promise => { + return (dispatch: IStore['dispatch'], getState: IStore['getState']): Promise => { const state = getState(); const { feedbackPercentage = 100 } = state['features/base/config']; @@ -105,7 +104,7 @@ export function maybeOpenFeedbackDialog(conference: Object) { * is closed. * @returns {Object} */ -export function openFeedbackDialog(conference: Object, onClose: ?Function) { +export function openFeedbackDialog(conference: Object, onClose?: Function) { return openDialog(FeedbackDialog, { conference, onClose @@ -120,8 +119,8 @@ export function openFeedbackDialog(conference: Object, onClose: ?Function) { * * @returns {Promise} */ -export function sendJaasFeedbackMetadata(conference: Object, feedback: Object) { - return (dispatch: Dispatch, getState: Function): Promise => { +export function sendJaasFeedbackMetadata(conference: IJitsiConference, feedback: Object) { + return (dispatch: IStore['dispatch'], getState: IStore['getState']): Promise => { const state = getState(); const { jaasFeedbackMetadataURL } = state['features/base/config']; @@ -135,7 +134,7 @@ export function sendJaasFeedbackMetadata(conference: Object, feedback: Object) { const feedbackData = { ...feedback, sessionId: conference.sessionId, - userId: user.id, + userId: user?.id, meetingFqn, jwt, tenant @@ -159,8 +158,8 @@ export function sendJaasFeedbackMetadata(conference: Object, feedback: Object) { export function submitFeedback( score: number, message: string, - conference: Object) { - return (dispatch: Dispatch) => + conference: IJitsiConference) { + return (dispatch: IStore['dispatch']) => conference.sendFeedback(score, message) .then(() => dispatch({ type: SUBMIT_FEEDBACK_SUCCESS })) .then(() => dispatch(sendJaasFeedbackMetadata(conference, { score, diff --git a/react/features/feedback/functions.js b/react/features/feedback/functions.ts similarity index 87% rename from react/features/feedback/functions.js rename to react/features/feedback/functions.ts index bdc14ae50e..47963c71b4 100644 --- a/react/features/feedback/functions.js +++ b/react/features/feedback/functions.ts @@ -1,5 +1,3 @@ -// @flow - import logger from './logger'; /** @@ -9,7 +7,10 @@ import logger from './logger'; * @param {Object} feedbackData - The feedback data object. * @returns {Promise} */ -export async function sendFeedbackToJaaSRequest(url: string, feedbackData: Object) { +export async function sendFeedbackToJaaSRequest(url: string, feedbackData: { + jwt?: string; meetingFqn: string; message?: string; score?: number; + sessionId: string; tenant?: string; userId?: string; +}) { const { jwt, sessionId, diff --git a/react/features/feedback/logger.js b/react/features/feedback/logger.ts similarity index 91% rename from react/features/feedback/logger.js rename to react/features/feedback/logger.ts index 9ab94be315..7ba2e68455 100644 --- a/react/features/feedback/logger.js +++ b/react/features/feedback/logger.ts @@ -1,5 +1,3 @@ -// @flow - import { getLogger } from '../base/logging/functions'; export default getLogger('features/feedback'); diff --git a/react/features/jaas/functions.js b/react/features/jaas/functions.ts similarity index 81% rename from react/features/jaas/functions.js rename to react/features/jaas/functions.ts index ba7cc79aab..447366cdf9 100644 --- a/react/features/jaas/functions.js +++ b/react/features/jaas/functions.ts @@ -1,5 +1,4 @@ -// @flow - +import { IState } from '../app/types'; import { VPAAS_TENANT_PREFIX } from './constants'; import logger from './logger'; @@ -23,20 +22,20 @@ function extractVpaasTenantFromPath(path: string) { /** * Returns the vpaas tenant. * - * @param {Object} state - The global state. + * @param {IState} state - The global state. * @returns {string} */ -export function getVpaasTenant(state: Object) { - return extractVpaasTenantFromPath(state['features/base/connection'].locationURL.pathname); +export function getVpaasTenant(state: IState) { + return extractVpaasTenantFromPath(state['features/base/connection'].locationURL?.pathname ?? ''); } /** * Returns true if the current meeting is a vpaas one. * - * @param {Object} state - The state of the app. + * @param {IState} state - The state of the app. * @returns {boolean} */ -export function isVpaasMeeting(state: Object) { +export function isVpaasMeeting(state: IState) { const connection = state['features/base/connection']; if (connection?.locationURL?.pathname) { @@ -57,8 +56,8 @@ export function isVpaasMeeting(state: Object) { * @returns {void} */ export async function sendGetDetailsRequest({ appId, baseUrl }: { - appId: string, - baseUrl: string, + appId: string; + baseUrl: string; }) { const fullUrl = `${baseUrl}/v1/public/tenants/${encodeURIComponent(appId)}`; @@ -70,7 +69,7 @@ export async function sendGetDetailsRequest({ appId, baseUrl }: { } throw new Error('Request not successful'); - } catch (err) { + } catch (err: any) { throw new Error(err); } @@ -79,11 +78,11 @@ export async function sendGetDetailsRequest({ appId, baseUrl }: { /** * Returns the billing id for vpaas meetings. * - * @param {Object} state - The state of the app. + * @param {IState} state - The state of the app. * @param {string} feature - Feature to be looked up for disable state. * @returns {boolean} */ -export function isFeatureDisabled(state: Object, feature: string) { +export function isFeatureDisabled(state: IState, feature: string) { return state['features/jaas'].disabledFeatures.includes(feature); } @@ -96,8 +95,8 @@ export function isFeatureDisabled(state: Object, feature: string) { * @returns {void} */ export async function sendGetJWTRequest({ appId, baseUrl }: { - appId: string, - baseUrl: string + appId: string; + baseUrl: string; }) { const fullUrl = `${baseUrl}/v1/public/token/${encodeURIComponent(appId)}`; @@ -111,7 +110,7 @@ export async function sendGetJWTRequest({ appId, baseUrl }: { } throw new Error('Request not successful'); - } catch (err) { + } catch (err: any) { throw new Error(err); } @@ -120,10 +119,10 @@ export async function sendGetJWTRequest({ appId, baseUrl }: { /** * Gets a jaas JWT. * - * @param {Object} state - Redux state. + * @param {IState} state - Redux state. * @returns {string} The JWT. */ -export async function getJaasJWT(state: Object) { +export async function getJaasJWT(state: IState) { const baseUrl = state['features/base/config'].jaasTokenUrl; const appId = getVpaasTenant(state); @@ -133,7 +132,7 @@ export async function getJaasJWT(state: Object) { try { const jwt = await sendGetJWTRequest({ appId, - baseUrl + baseUrl: baseUrl ?? '' }); return jwt.token; diff --git a/react/features/jaas/logger.js b/react/features/jaas/logger.ts similarity index 90% rename from react/features/jaas/logger.js rename to react/features/jaas/logger.ts index 725fa328d0..c8f5fb0700 100644 --- a/react/features/jaas/logger.js +++ b/react/features/jaas/logger.ts @@ -1,5 +1,3 @@ -// @flow - import { getLogger } from '../base/logging/functions'; export default getLogger('features/jaas'); diff --git a/react/features/subtitles/actions.any.js b/react/features/subtitles/actions.any.ts similarity index 97% rename from react/features/subtitles/actions.any.js rename to react/features/subtitles/actions.any.ts index 221de7ac4d..9f20e417be 100644 --- a/react/features/subtitles/actions.any.js +++ b/react/features/subtitles/actions.any.ts @@ -1,5 +1,3 @@ -// @flow - import { ENDPOINT_MESSAGE_RECEIVED, REMOVE_TRANSCRIPT_MESSAGE, @@ -102,7 +100,7 @@ export function setRequestingSubtitles(enabled: boolean) { * type: UPDATE_TRANSLATION_LANGUAGE * }} */ -export function updateTranslationLanguage(value) { +export function updateTranslationLanguage(value: boolean) { return { type: UPDATE_TRANSLATION_LANGUAGE, value