diff --git a/react/features/device-selection/actions.js b/react/features/device-selection/actions.ts similarity index 81% rename from react/features/device-selection/actions.js rename to react/features/device-selection/actions.ts index 66be918a1..e0658da67 100644 --- a/react/features/device-selection/actions.js +++ b/react/features/device-selection/actions.ts @@ -1,11 +1,12 @@ -import { createDeviceChangedEvent, sendAnalytics } from '../analytics'; +import { createDeviceChangedEvent } from '../analytics/AnalyticsEvents'; +import { sendAnalytics } from '../analytics/functions'; +import { IStore } from '../app/types'; import { - getDeviceLabelById, setAudioInputDevice, - setAudioOutputDeviceId, setVideoInputDevice -} from '../base/devices'; -import { updateSettings } from '../base/settings'; +} from '../base/devices/actions'; +import { getDeviceLabelById, setAudioOutputDeviceId } from '../base/devices/functions'; +import { updateSettings } from '../base/settings/actions'; import { getDeviceSelectionDialogProps } from './functions'; import logger from './logger'; @@ -18,8 +19,8 @@ import logger from './logger'; * welcome page or not. * @returns {Function} */ -export function submitDeviceSelectionTab(newState, isDisplayedOnWelcomePage) { - return (dispatch, getState) => { +export function submitDeviceSelectionTab(newState: any, isDisplayedOnWelcomePage: boolean) { + return (dispatch: IStore['dispatch'], getState: IStore['getState']) => { const currentState = getDeviceSelectionDialogProps(getState(), isDisplayedOnWelcomePage); if (newState.selectedVideoInputId && (newState.selectedVideoInputId !== currentState.selectedVideoInputId)) { diff --git a/react/features/device-selection/logger.js b/react/features/device-selection/logger.ts similarity index 91% rename from react/features/device-selection/logger.js rename to react/features/device-selection/logger.ts index b18cf68da..e1bee04f9 100644 --- a/react/features/device-selection/logger.js +++ b/react/features/device-selection/logger.ts @@ -1,5 +1,3 @@ -// @flow - import { getLogger } from '../base/logging/functions'; export default getLogger('features/device-selection'); diff --git a/react/features/device-selection/middleware.js b/react/features/device-selection/middleware.ts similarity index 80% rename from react/features/device-selection/middleware.js rename to react/features/device-selection/middleware.ts index 925cc4172..d984685fe 100644 --- a/react/features/device-selection/middleware.js +++ b/react/features/device-selection/middleware.ts @@ -1,9 +1,5 @@ -// @flow - -import { UPDATE_DEVICE_LIST } from '../base/devices'; -import { MiddlewareRegistry } from '../base/redux'; - -declare var APP: Object; +import { UPDATE_DEVICE_LIST } from '../base/devices/actionTypes'; +import MiddlewareRegistry from '../base/redux/MiddlewareRegistry'; /** * Implements the middleware of the feature device-selection. diff --git a/react/features/dynamic-branding/actions.any.js b/react/features/dynamic-branding/actions.any.ts similarity index 94% rename from react/features/dynamic-branding/actions.any.js rename to react/features/dynamic-branding/actions.any.ts index e750c2147..6aa66ed85 100644 --- a/react/features/dynamic-branding/actions.any.js +++ b/react/features/dynamic-branding/actions.any.ts @@ -1,4 +1,4 @@ -import { doGetJSON } from '../base/util'; +import { doGetJSON } from '../base/util/httpUtils'; import { SET_DYNAMIC_BRANDING_DATA, @@ -47,7 +47,7 @@ export function fetchCustomBrandingData() { * @param {Object} value - The custom data to be set. * @returns {Object} */ -export function setDynamicBrandingData(value) { +export function setDynamicBrandingData(value: Object) { return { type: SET_DYNAMIC_BRANDING_DATA, value diff --git a/react/features/dynamic-branding/actions.native.js b/react/features/dynamic-branding/actions.native.ts similarity index 88% rename from react/features/dynamic-branding/actions.native.js rename to react/features/dynamic-branding/actions.native.ts index 9ae8a5744..6d7cfa775 100644 --- a/react/features/dynamic-branding/actions.native.js +++ b/react/features/dynamic-branding/actions.native.ts @@ -1,4 +1,5 @@ -import { doGetJSON } from '../base/util'; +import { IStore } from '../app/types'; +import { doGetJSON } from '../base/util/httpUtils'; import { UNSET_DYNAMIC_BRANDING } from './actionTypes'; import { @@ -18,7 +19,7 @@ import logger from './logger'; * @returns {Function} */ export function fetchCustomBrandingData() { - return async function(dispatch: Function, getState: Function) { + return async function(dispatch: IStore['dispatch'], getState: IStore['getState']) { const state = getState(); const dynamicBrandingUrl = await getDynamicBrandingUrl(state); diff --git a/react/features/dynamic-branding/logger.js b/react/features/dynamic-branding/logger.ts similarity index 91% rename from react/features/dynamic-branding/logger.js rename to react/features/dynamic-branding/logger.ts index b35cc2fd8..839fe4305 100644 --- a/react/features/dynamic-branding/logger.js +++ b/react/features/dynamic-branding/logger.ts @@ -1,5 +1,3 @@ -// @flow - import { getLogger } from '../base/logging/functions'; export default getLogger('features/dynamic-branding'); diff --git a/react/features/dynamic-branding/middleware.native.js b/react/features/dynamic-branding/middleware.native.ts similarity index 83% rename from react/features/dynamic-branding/middleware.native.js rename to react/features/dynamic-branding/middleware.native.ts index 629f1fb3b..fd79a696c 100644 --- a/react/features/dynamic-branding/middleware.native.js +++ b/react/features/dynamic-branding/middleware.native.ts @@ -1,5 +1,5 @@ -import { SET_CONFIG } from '../base/config'; -import { MiddlewareRegistry } from '../base/redux'; +import { SET_CONFIG } from '../base/config/actionTypes'; +import MiddlewareRegistry from '../base/redux/MiddlewareRegistry'; import { SET_DYNAMIC_BRANDING_DATA } from './actionTypes'; import { fetchCustomBrandingData } from './actions.native'; @@ -34,7 +34,7 @@ MiddlewareRegistry.register(store => next => action => { // TODO: implement support for gradients. action.value.avatarBackgrounds = avatarBackgrounds.filter( - color => !color.includes('linear-gradient') + (color: string) => !color.includes('linear-gradient') ); break; diff --git a/react/features/dynamic-branding/middleware.web.js b/react/features/dynamic-branding/middleware.web.ts similarity index 82% rename from react/features/dynamic-branding/middleware.web.js rename to react/features/dynamic-branding/middleware.web.ts index 7ac6c3eb8..9b6d2d7fd 100644 --- a/react/features/dynamic-branding/middleware.web.js +++ b/react/features/dynamic-branding/middleware.web.ts @@ -1,5 +1,5 @@ -import { APP_WILL_MOUNT } from '../base/app'; -import { MiddlewareRegistry } from '../base/redux'; +import { APP_WILL_MOUNT } from '../base/app/actionTypes'; +import MiddlewareRegistry from '../base/redux/MiddlewareRegistry'; import { SET_DYNAMIC_BRANDING_DATA } from './actionTypes'; import { fetchCustomBrandingData } from './actions.any'; diff --git a/react/features/etherpad/actions.js b/react/features/etherpad/actions.ts similarity index 93% rename from react/features/etherpad/actions.js rename to react/features/etherpad/actions.ts index b5a737039..d93cbed20 100644 --- a/react/features/etherpad/actions.js +++ b/react/features/etherpad/actions.ts @@ -1,5 +1,3 @@ -// @flow - import { SET_DOCUMENT_EDITING_STATUS, SET_DOCUMENT_URL, @@ -32,7 +30,7 @@ export function setDocumentEditingState(editing: boolean) { * documentUrl: string * }} */ -export function setDocumentUrl(documentUrl: ?string) { +export function setDocumentUrl(documentUrl?: string) { return { type: SET_DOCUMENT_URL, documentUrl diff --git a/react/features/etherpad/functions.js b/react/features/etherpad/functions.ts similarity index 82% rename from react/features/etherpad/functions.js rename to react/features/etherpad/functions.ts index a9112db71..75a749e16 100644 --- a/react/features/etherpad/functions.js +++ b/react/features/etherpad/functions.ts @@ -1,6 +1,5 @@ -// @flow - -import { toState } from '../base/redux'; +import { IStateful } from '../base/app/types'; +import { toState } from '../base/redux/functions'; const ETHERPAD_OPTIONS = { showControls: 'true', @@ -15,7 +14,7 @@ const ETHERPAD_OPTIONS = { * @param {Function|Object} stateful - The redux store or {@code getState} function. * @returns {?string} - Current shared document URL or undefined. */ -export function getSharedDocumentUrl(stateful: Function | Object) { +export function getSharedDocumentUrl(stateful: IStateful) { const state = toState(stateful); const { documentUrl } = state['features/etherpad']; const { displayName } = state['features/base/settings']; diff --git a/react/features/etherpad/middleware.js b/react/features/etherpad/middleware.ts similarity index 85% rename from react/features/etherpad/middleware.js rename to react/features/etherpad/middleware.ts index 58f0adb65..b4d61721c 100644 --- a/react/features/etherpad/middleware.js +++ b/react/features/etherpad/middleware.ts @@ -1,15 +1,13 @@ -// @flow - +// @ts-expect-error import UIEvents from '../../../service/UI/UIEvents'; -import { getCurrentConference } from '../base/conference'; import { CONFERENCE_JOIN_IN_PROGRESS } from '../base/conference/actionTypes'; -import { MiddlewareRegistry, StateListenerRegistry } from '../base/redux'; +import { getCurrentConference } from '../base/conference/functions'; +import MiddlewareRegistry from '../base/redux/MiddlewareRegistry'; +import StateListenerRegistry from '../base/redux/StateListenerRegistry'; import { TOGGLE_DOCUMENT_EDITING } from './actionTypes'; import { setDocumentUrl } from './actions'; -declare var APP: Object; - const ETHERPAD_COMMAND = 'etherpad'; /** @@ -26,7 +24,7 @@ MiddlewareRegistry.register(({ dispatch, getState }) => next => action => { const { conference } = action; conference.addCommandListener(ETHERPAD_COMMAND, - ({ value }) => { + ({ value }: { value: string; }) => { let url; const { etherpad_base: etherpadBase } = getState()['features/base/config']; diff --git a/react/features/no-audio-signal/actions.js b/react/features/no-audio-signal/actions.ts similarity index 86% rename from react/features/no-audio-signal/actions.js rename to react/features/no-audio-signal/actions.ts index 1d9d9c49f..4080b0e35 100644 --- a/react/features/no-audio-signal/actions.js +++ b/react/features/no-audio-signal/actions.ts @@ -1,5 +1,3 @@ -// @flow - import { SET_NO_AUDIO_SIGNAL_NOTIFICATION_UID } from './actionTypes'; /** @@ -13,7 +11,7 @@ import { SET_NO_AUDIO_SIGNAL_NOTIFICATION_UID } from './actionTypes'; * uid: number * }} */ -export function setNoAudioSignalNotificationUid(uid: ?number) { +export function setNoAudioSignalNotificationUid(uid?: string) { return { type: SET_NO_AUDIO_SIGNAL_NOTIFICATION_UID, uid diff --git a/react/features/no-audio-signal/middleware.js b/react/features/no-audio-signal/middleware.tsx similarity index 85% rename from react/features/no-audio-signal/middleware.js rename to react/features/no-audio-signal/middleware.tsx index f83333671..555071249 100644 --- a/react/features/no-audio-signal/middleware.js +++ b/react/features/no-audio-signal/middleware.tsx @@ -1,20 +1,21 @@ -// @flow - import React from 'react'; +import { AnyAction } from 'redux'; -import { APP_WILL_MOUNT, APP_WILL_UNMOUNT } from '../base/app'; -import { CONFERENCE_JOINED } from '../base/conference'; -import { - formatDeviceLabel, - setAudioInputDevice -} from '../base/devices'; +import { IStore } from '../app/types'; +import { APP_WILL_MOUNT, APP_WILL_UNMOUNT } from '../base/app/actionTypes'; +import { CONFERENCE_JOINED } from '../base/conference/actionTypes'; +import { setAudioInputDevice } from '../base/devices/actions'; +import { formatDeviceLabel } from '../base/devices/functions'; import JitsiMeetJS, { JitsiConferenceEvents } from '../base/lib-jitsi-meet'; -import { MiddlewareRegistry } from '../base/redux'; -import { updateSettings } from '../base/settings'; -import { playSound, registerSound, unregisterSound } from '../base/sounds'; -import { NOTIFICATION_TIMEOUT_TYPE, hideNotification, showNotification } from '../notifications'; +import MiddlewareRegistry from '../base/redux/MiddlewareRegistry'; +import { updateSettings } from '../base/settings/actions'; +import { playSound, registerSound, unregisterSound } from '../base/sounds/actions'; +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'; @@ -48,11 +49,11 @@ MiddlewareRegistry.register(store => next => async action => { * @private * @returns {void} */ -async function _handleNoAudioSignalNotification({ dispatch, getState }, action) { +async function _handleNoAudioSignalNotification({ dispatch, getState }: IStore, action: AnyAction) { const { conference } = action; - conference.on(JitsiConferenceEvents.AUDIO_INPUT_STATE_CHANGE, hasAudioInput => { + conference.on(JitsiConferenceEvents.AUDIO_INPUT_STATE_CHANGE, (hasAudioInput: boolean) => { const { noAudioSignalNotificationUid } = getState()['features/no-audio-signal']; // In case the notification is displayed but the conference detected audio input signal we hide it. diff --git a/react/features/no-audio-signal/reducer.ts b/react/features/no-audio-signal/reducer.ts index f6bab4996..d7122af2a 100644 --- a/react/features/no-audio-signal/reducer.ts +++ b/react/features/no-audio-signal/reducer.ts @@ -4,7 +4,7 @@ import { set } from '../base/redux/functions'; import { SET_NO_AUDIO_SIGNAL_NOTIFICATION_UID } from './actionTypes'; export interface INoAudioSignalState { - noAudioSignalNotificationUid?: number; + noAudioSignalNotificationUid?: string; } /** diff --git a/react/features/no-audio-signal/sounds.js b/react/features/no-audio-signal/sounds.ts similarity index 100% rename from react/features/no-audio-signal/sounds.js rename to react/features/no-audio-signal/sounds.ts diff --git a/react/features/noise-detection/actions.js b/react/features/noise-detection/actions.ts similarity index 86% rename from react/features/noise-detection/actions.js rename to react/features/noise-detection/actions.ts index a4bdb2266..fba5befad 100644 --- a/react/features/noise-detection/actions.js +++ b/react/features/noise-detection/actions.ts @@ -1,5 +1,3 @@ -// @flow - import { SET_NOISY_AUDIO_INPUT_NOTIFICATION_UID } from './actionTypes'; /** @@ -13,7 +11,7 @@ import { SET_NOISY_AUDIO_INPUT_NOTIFICATION_UID } from './actionTypes'; * uid: number * }} */ -export function setNoisyAudioInputNotificationUid(uid: ?number) { +export function setNoisyAudioInputNotificationUid(uid?: string) { return { type: SET_NOISY_AUDIO_INPUT_NOTIFICATION_UID, uid diff --git a/react/features/noise-detection/middleware.js b/react/features/noise-detection/middleware.ts similarity index 83% rename from react/features/noise-detection/middleware.js rename to react/features/noise-detection/middleware.ts index a25650a56..d41f87ad2 100644 --- a/react/features/noise-detection/middleware.js +++ b/react/features/noise-detection/middleware.ts @@ -1,11 +1,10 @@ -// @flow - -import { APP_WILL_MOUNT, APP_WILL_UNMOUNT } from '../base/app'; -import { CONFERENCE_JOINED } from '../base/conference'; +import { APP_WILL_MOUNT, APP_WILL_UNMOUNT } from '../base/app/actionTypes'; +import { CONFERENCE_JOINED } from '../base/conference/actionTypes'; import { JitsiConferenceEvents } from '../base/lib-jitsi-meet'; -import { MiddlewareRegistry } from '../base/redux'; -import { playSound, registerSound, unregisterSound } from '../base/sounds'; -import { NOTIFICATION_TIMEOUT_TYPE, hideNotification, showNotification } from '../notifications'; +import MiddlewareRegistry from '../base/redux/MiddlewareRegistry'; +import { playSound, registerSound, unregisterSound } from '../base/sounds/actions'; +import { hideNotification, showNotification } from '../notifications/actions'; +import { NOTIFICATION_TIMEOUT_TYPE } from '../notifications/constants'; import { setNoisyAudioInputNotificationUid } from './actions'; import { NOISY_AUDIO_INPUT_SOUND_ID } from './constants'; @@ -27,7 +26,7 @@ MiddlewareRegistry.register(store => next => action => { conference.on( JitsiConferenceEvents.TRACK_MUTE_CHANGED, - track => { + (track: any) => { const { noisyAudioInputNotificationUid } = getState()['features/noise-detection']; // Hide the notification in case the user mutes the microphone diff --git a/react/features/noise-detection/reducer.ts b/react/features/noise-detection/reducer.ts index e8c29a207..04c38bc45 100644 --- a/react/features/noise-detection/reducer.ts +++ b/react/features/noise-detection/reducer.ts @@ -4,7 +4,7 @@ import { set } from '../base/redux/functions'; import { SET_NOISY_AUDIO_INPUT_NOTIFICATION_UID } from './actionTypes'; export interface INoiseDetectionState { - noisyAudioInputNotificationUid?: number; + noisyAudioInputNotificationUid?: string; } /** diff --git a/react/features/noise-detection/sounds.js b/react/features/noise-detection/sounds.ts similarity index 100% rename from react/features/noise-detection/sounds.js rename to react/features/noise-detection/sounds.ts diff --git a/react/features/notifications/actions.ts b/react/features/notifications/actions.ts index afeba9fe7..ea293fe0d 100644 --- a/react/features/notifications/actions.ts +++ b/react/features/notifications/actions.ts @@ -19,6 +19,7 @@ import { SILENT_JOIN_THRESHOLD, SILENT_LEFT_THRESHOLD } from './constants'; +import { INotificationProps } from './types'; /** * Function that returns notification timeout value based on notification timeout type. @@ -89,23 +90,6 @@ export function setNotificationsEnabled(enabled: boolean) { }; } -interface INotificationProps { - appearance?: string; - concatText?: boolean; - customActionHandler?: Function[]; - customActionNameKey?: string[]; - description?: string; - descriptionKey?: string; - icon?: string; - sticky?: boolean; - title?: string; - titleArguments?: { - [key: string]: string; - }; - titleKey?: string; - uid?: string; -} - /** * Queues an error notification for display. * diff --git a/react/features/notifications/types.ts b/react/features/notifications/types.ts new file mode 100644 index 000000000..1a583ee0c --- /dev/null +++ b/react/features/notifications/types.ts @@ -0,0 +1,20 @@ +import React from 'react'; + +export interface INotificationProps { + appearance?: string; + concatText?: boolean; + customActionHandler?: Function[]; + customActionNameKey?: string[]; + description?: string | React.ReactNode; + descriptionArguments?: Object; + descriptionKey?: string; + icon?: string; + maxLines?: number; + sticky?: boolean; + title?: string; + titleArguments?: { + [key: string]: string; + }; + titleKey?: string; + uid?: string; +} diff --git a/react/features/participants-pane/actions.any.js b/react/features/participants-pane/actions.any.ts similarity index 97% rename from react/features/participants-pane/actions.any.js rename to react/features/participants-pane/actions.any.ts index 4ce63e75f..e2896f0f9 100644 --- a/react/features/participants-pane/actions.any.js +++ b/react/features/participants-pane/actions.any.ts @@ -1,5 +1,3 @@ -// @flow - import { PARTICIPANTS_PANE_CLOSE, PARTICIPANTS_PANE_OPEN diff --git a/react/features/participants-pane/actions.native.js b/react/features/participants-pane/actions.native.ts similarity index 89% rename from react/features/participants-pane/actions.native.js rename to react/features/participants-pane/actions.native.ts index ad8c18ea0..1cf4679fe 100644 --- a/react/features/participants-pane/actions.native.js +++ b/react/features/participants-pane/actions.native.ts @@ -1,18 +1,24 @@ -import type { Dispatch } from 'redux'; - -import { openSheet } from '../base/dialog'; +/* eslint-disable lines-around-comment */ +import { IStore } from '../app/types'; +import { openSheet } from '../base/dialog/actions'; +// @ts-ignore import { SharedVideoMenu } from '../video-menu'; +// @ts-ignore import { LocalVideoMenu } from '../video-menu/components/native'; import ConnectionStatusComponent +// @ts-ignore from '../video-menu/components/native/ConnectionStatusComponent'; +// @ts-ignore import RemoteVideoMenu from '../video-menu/components/native/RemoteVideoMenu'; import { SET_VOLUME } from './actionTypes'; import { ContextMenuLobbyParticipantReject + // @ts-ignore } from './components/native'; import RoomParticipantMenu from './components/native/RoomParticipantMenu'; export * from './actions.any'; +/* eslint-enable lines-around-comment */ /** * Displays the context menu for the selected lobby participant. @@ -42,8 +48,8 @@ export function showConnectionStatus(participantID: string) { * @param {boolean} local - Whether the participant is local or not. * @returns {Function} */ -export function showContextMenuDetails(participantId: string, local: boolean = false) { - return (dispatch: Dispatch, getState: Function) => { +export function showContextMenuDetails(participantId: string, local = false) { + return (dispatch: IStore['dispatch'], getState: IStore['getState']) => { const { remoteVideoMenu } = getState()['features/base/config']; if (local) { @@ -92,6 +98,7 @@ export function setVolume(participantId: string, volume: number) { * @returns {Function} */ export function showRoomParticipantMenu(room: Object, participantJid: string, participantName: string) { + // @ts-ignore return openSheet(RoomParticipantMenu, { room, participantJid, participantName }); diff --git a/react/features/participants-pane/actions.web.js b/react/features/participants-pane/actions.web.ts similarity index 75% rename from react/features/participants-pane/actions.web.js rename to react/features/participants-pane/actions.web.ts index 7e5279fe7..02b37d475 100644 --- a/react/features/participants-pane/actions.web.js +++ b/react/features/participants-pane/actions.web.ts @@ -1,3 +1 @@ -// @flow - export * from './actions.any'; diff --git a/react/features/participants-pane/hooks.js b/react/features/participants-pane/hooks.ts similarity index 60% rename from react/features/participants-pane/hooks.js rename to react/features/participants-pane/hooks.ts index a8d6042bc..6a58c055d 100644 --- a/react/features/participants-pane/hooks.js +++ b/react/features/participants-pane/hooks.ts @@ -2,8 +2,15 @@ import { useCallback, useState } from 'react'; import { useDispatch } from 'react-redux'; import { handleLobbyChatInitialized } from '../chat/actions.any'; +// eslint-disable-next-line lines-around-comment +// @ts-ignore import { approveKnockingParticipant, rejectKnockingParticipant } from '../lobby/actions'; +interface DrawerParticipant { + displayName?: string; + participantID: string; +} + /** * Hook used to create admit/reject lobby actions. * @@ -11,23 +18,23 @@ import { approveKnockingParticipant, rejectKnockingParticipant } from '../lobby/ * @param {Function} closeDrawer - Callback for closing the drawer. * @returns {Array} */ -export function useLobbyActions(participant, closeDrawer) { +export function useLobbyActions(participant?: DrawerParticipant | null, closeDrawer?: Function) { const dispatch = useDispatch(); return [ useCallback(e => { e.stopPropagation(); - dispatch(approveKnockingParticipant(participant && participant.participantID)); - closeDrawer && closeDrawer(); + dispatch(approveKnockingParticipant(participant?.participantID)); + closeDrawer?.(); }, [ dispatch, closeDrawer ]), useCallback(() => { - dispatch(rejectKnockingParticipant(participant && participant.participantID)); - closeDrawer && closeDrawer(); + dispatch(rejectKnockingParticipant(participant?.participantID)); + closeDrawer?.(); }, [ dispatch, closeDrawer ]), useCallback(() => { - dispatch(handleLobbyChatInitialized(participant && participant.participantID)); + dispatch(handleLobbyChatInitialized(participant?.participantID ?? '')); }, [ dispatch ]) ]; } @@ -37,11 +44,14 @@ export function useLobbyActions(participant, closeDrawer) { * * @returns {Array} */ -export function useParticipantDrawer() { - const [ drawerParticipant, openDrawerForParticipant ] = useState(null); +export function useParticipantDrawer(): [ + DrawerParticipant | null, + () => void, + (p: DrawerParticipant | null) => void ] { + const [ drawerParticipant, openDrawerForParticipant ] = useState(null); const closeDrawer = useCallback(() => { openDrawerForParticipant(null); - }); + }, []); return [ drawerParticipant,