feat(invite/native): add people functionality fixes (#13240)

feat(invite/native): add people functionality fixes
This commit is contained in:
Calinteodor
2023-04-21 14:13:25 +03:00
committed by GitHub
parent 007283aab3
commit a5663872d9
13 changed files with 235 additions and 130 deletions

View File

@@ -13,7 +13,7 @@ type Props = {
/**
* Adds bottom padding.
*/
addBottomPadding: boolean,
addBottomPadding?: boolean,
/**
* Additional style to be appended to the KeyboardAvoidingView content container.

View File

@@ -3,14 +3,18 @@ import { getGravatarURL } from '@jitsi/js-utils/avatar';
import { IReduxState, IStore } from '../../app/types';
import { isStageFilmstripAvailable } from '../../filmstrip/functions';
import { isAddPeopleEnabled, isDialOutEnabled } from '../../invite/functions';
import { toggleShareDialog } from '../../share-room/actions';
import { IStateful } from '../app/types';
import { GRAVATAR_BASE_URL } from '../avatar/constants';
import { isCORSAvatarURL } from '../avatar/functions';
import { getCurrentConference } from '../conference/functions';
import { ADD_PEOPLE_ENABLED } from '../flags/constants';
import { getFeatureFlag } from '../flags/functions';
import i18next from '../i18n/i18next';
import { MEDIA_TYPE, VIDEO_TYPE } from '../media/constants';
import { toState } from '../redux/functions';
import { getScreenShareTrack } from '../tracks/functions';
import { getScreenShareTrack } from '../tracks/functions.any';
import { createDeferred } from '../util/helpers';
import {
@@ -22,6 +26,7 @@ import {
import { preloadImage } from './preloadImage';
import { FakeParticipant, IJitsiParticipant, IParticipant, ISourceInfo } from './types';
/**
* Temp structures for avatar urls to be checked/preloaded.
*/
@@ -706,3 +711,32 @@ export function getRaiseHandsQueue(stateful: IStateful): Array<{ id: string; rai
export function hasRaisedHand(participant?: IParticipant): boolean {
return Boolean(participant?.raisedHandTimestamp);
}
/**
* Add people feature enabling/disabling.
*
* @param {Object|Function} stateful - Object or function that can be resolved
* to the Redux state.
* @returns {boolean}
*/
export const addPeopleFeatureControl = (stateful: IStateful) => {
const state = toState(stateful);
return getFeatureFlag(state, ADD_PEOPLE_ENABLED, true)
&& (isAddPeopleEnabled(state) || isDialOutEnabled(state));
};
/**
* Controls share dialog visibility.
*
* @param {boolean} addPeopleFeatureEnabled - Checks if add people functionality is enabled.
* @param {Function} dispatch - The Redux dispatch function.
* @returns {Function}
*/
export const setShareDialogVisiblity = (addPeopleFeatureEnabled: boolean, dispatch: Function) => {
if (addPeopleFeatureEnabled) {
dispatch(toggleShareDialog(false));
} else {
dispatch(toggleShareDialog(true));
}
};

View File

@@ -52,6 +52,8 @@ export type Item = {
*/
title: string;
type: string;
/**
* Item url.
*/

View File

@@ -1,6 +1,6 @@
import React, { PureComponent } from 'react';
import { WithTranslation } from 'react-i18next';
import { Text, View } from 'react-native';
import { Text, View, ViewStyle } from 'react-native';
import { connect } from 'react-redux';
import { IReduxState } from '../../../app/types';
@@ -9,12 +9,15 @@ import { getFeatureFlag } from '../../../base/flags/functions';
import { translate } from '../../../base/i18n/functions';
import Icon from '../../../base/icons/components/Icon';
import { IconAddUser } from '../../../base/icons/svg';
import { getParticipantCountWithFake } from '../../../base/participants/functions';
import {
addPeopleFeatureControl,
getParticipantCountWithFake,
setShareDialogVisiblity
} from '../../../base/participants/functions';
import Button from '../../../base/ui/components/native/Button';
import { BUTTON_TYPES } from '../../../base/ui/constants.native';
import { isInBreakoutRoom } from '../../../breakout-rooms/functions';
import { doInvitePeople } from '../../../invite/actions.native';
import { toggleShareDialog } from '../../../share-room/actions';
import { getInviteOthersControl } from '../../../share-room/functions';
// @ts-ignore
@@ -31,6 +34,11 @@ interface IProps extends WithTranslation {
*/
_inviteOthersControl: any;
/**
* Checks if add-people feature is enabled.
*/
_isAddPeopleFeatureEnabled: boolean;
/**
* True if currently in a breakout room.
*/
@@ -87,7 +95,7 @@ class LonelyMeetingExperience extends PureComponent<IProps> {
}
return (
<View style = { styles.lonelyMeetingContainer }>
<View style = { styles.lonelyMeetingContainer as ViewStyle }>
<Text style = { styles.lonelyMessage }>
{ t('lonelyMeetingExperience.youAreAlone') }
</Text>
@@ -116,8 +124,11 @@ class LonelyMeetingExperience extends PureComponent<IProps> {
* @returns {void}
*/
_onPress() {
this.props.dispatch(toggleShareDialog(true));
this.props.dispatch(doInvitePeople());
const { _isAddPeopleFeatureEnabled, dispatch } = this.props;
setShareDialogVisiblity(_isAddPeopleFeatureEnabled, dispatch);
dispatch(doInvitePeople());
}
}
@@ -133,9 +144,11 @@ function _mapStateToProps(state: IReduxState) {
const { conference } = state['features/base/conference'];
const _inviteOthersControl = getInviteOthersControl(state);
const flag = getFeatureFlag(state, INVITE_ENABLED, true);
const _isAddPeopleFeatureEnabled = addPeopleFeatureControl(state);
const _isInBreakoutRoom = isInBreakoutRoom(state);
return {
_isAddPeopleFeatureEnabled,
_inviteOthersControl,
_isInBreakoutRoom,
_isInviteFunctionsDisabled: Boolean(!flag || disableInviteFunctions),

View File

@@ -1,7 +1,6 @@
/* eslint-disable lines-around-comment */
import { IStore } from '../app/types';
import { ADD_PEOPLE_ENABLED } from '../base/flags/constants';
import { getFeatureFlag } from '../base/flags/functions';
import { addPeopleFeatureControl } from '../base/participants/functions';
// @ts-ignore
import { navigate } from '../mobile/navigation/components/conference/ConferenceNavigationContainerRef';
// @ts-ignore
@@ -9,7 +8,6 @@ import { screen } from '../mobile/navigation/routes';
import { beginShareRoom } from '../share-room/actions';
/* eslint-enable lines-around-comment */
import { isAddPeopleEnabled, isDialOutEnabled } from './functions';
export * from './actions.any';
@@ -22,10 +20,8 @@ export * from './actions.any';
export function doInvitePeople() {
return (dispatch: IStore['dispatch'], getState: IStore['getState']) => {
const state = getState();
const addPeopleEnabled = getFeatureFlag(state, ADD_PEOPLE_ENABLED, true)
&& (isAddPeopleEnabled(state) || isDialOutEnabled(state));
if (addPeopleEnabled) {
if (addPeopleFeatureControl(state)) {
return navigate(screen.conference.invite);
}

View File

@@ -6,7 +6,7 @@ import { IReduxState } from '../../../app/types';
import { showErrorNotification, showNotification } from '../../../notifications/actions';
import { NOTIFICATION_TIMEOUT_TYPE } from '../../../notifications/constants';
import { INotificationProps } from '../../../notifications/types';
import { invite } from '../../actions';
import { invite } from '../../actions.any';
import { INVITE_TYPES } from '../../constants';
import {
getInviteResultsForQuery,

View File

@@ -1,13 +1,17 @@
/* eslint-disable lines-around-comment */
import _ from 'lodash';
import React, { ReactElement } from 'react';
import {
ActivityIndicator,
FlatList,
TouchableOpacity,
View
View,
ViewStyle
} from 'react-native';
import { connect } from 'react-redux';
import { IReduxState } from '../../../../app/types';
import { openDialog } from '../../../../base/dialog/actions';
import AlertDialog from '../../../../base/dialog/components/native/AlertDialog';
import { translate } from '../../../../base/i18n/functions';
@@ -19,6 +23,7 @@ import {
IconSearch,
IconShare
} from '../../../../base/icons/svg';
// @ts-ignore
import JitsiScreen from '../../../../base/modal/components/JitsiScreen';
import AvatarListItem from '../../../../base/react/components/native/AvatarListItem';
import { Item } from '../../../../base/react/types';
@@ -29,64 +34,70 @@ import HeaderNavigationButton
import { beginShareRoom } from '../../../../share-room/actions';
import { INVITE_TYPES } from '../../../constants';
import AbstractAddPeopleDialog, {
// @ts-ignore
type Props as AbstractProps,
// @ts-ignore
type State as AbstractState,
_mapStateToProps as _abstractMapStateToProps
} from '../AbstractAddPeopleDialog';
// @ts-ignore
import styles, { AVATAR_SIZE } from './styles';
type Props = AbstractProps & {
interface IProps extends AbstractProps {
/**
* True if the invite dialog should be open, false otherwise.
*/
_isVisible: boolean,
_isVisible: boolean;
/**
* Default prop for navigation between screen components(React Navigation).
*/
navigation: Object,
navigation: Object;
/**
* Function used to translate i18n labels.
*/
t: Function,
t: Function;
/**
* Theme used for styles.
*/
theme: Object
};
theme: Object;
}
type State = AbstractState & {
interface IState extends AbstractState {
/**
* Boolean to show if an extra padding needs to be added to the bottom bar.
*/
bottomPadding: boolean,
bottomPadding: boolean;
/**
* State variable to keep track of the search field value.
*/
fieldValue: string,
fieldValue: string;
/**
* True if a search is in progress, false otherwise.
*/
searchInprogress: boolean,
searchInprogress: boolean;
/**
* An array of items that are selectable on this dialog. This is usually
* populated by an async search.
*/
selectableItems: Array<Object>
};
selectableItems: Array<Object>;
}
/**
* Implements a special dialog to invite people from a directory service.
*/
class AddPeopleDialog extends AbstractAddPeopleDialog<Props, State> {
class AddPeopleDialog
// @ts-ignore
extends AbstractAddPeopleDialog<IProps, IState> {
/**
* Default state object to reset the state to when needed.
*/
@@ -105,14 +116,14 @@ class AddPeopleDialog extends AbstractAddPeopleDialog<Props, State> {
*/
/* eslint-disable-next-line no-undef */
searchTimeout: TimeoutID;
searchTimeout: number;
/**
* Contrustor of the component.
*
* @inheritdoc
*/
constructor(props: Props) {
constructor(props: IProps) {
super(props);
this.state = this.defaultState;
@@ -140,11 +151,13 @@ class AddPeopleDialog extends AbstractAddPeopleDialog<Props, State> {
componentDidMount() {
const { navigation, t } = this.props;
// @ts-ignore
navigation.setOptions({
headerRight: () => (
<HeaderNavigationButton
disabled = { this._isAddDisabled() }
label = { t('inviteDialog.send') }
style = { styles.sendBtn }
twoActions = { true } />
)
});
@@ -155,9 +168,10 @@ class AddPeopleDialog extends AbstractAddPeopleDialog<Props, State> {
*
* @inheritdoc
*/
componentDidUpdate(prevProps) {
componentDidUpdate(prevProps: IProps) {
const { navigation, t } = this.props;
// @ts-ignore
navigation.setOptions({
// eslint-disable-next-line react/no-multi-comp
headerRight: () => (
@@ -165,6 +179,7 @@ class AddPeopleDialog extends AbstractAddPeopleDialog<Props, State> {
disabled = { this._isAddDisabled() }
label = { t('inviteDialog.send') }
onPress = { this._onInvite }
style = { styles.sendBtn }
twoActions = { true } />
)
});
@@ -182,9 +197,12 @@ class AddPeopleDialog extends AbstractAddPeopleDialog<Props, State> {
*/
render() {
const {
// @ts-ignore
_addPeopleEnabled,
// @ts-ignore
_dialOutEnabled
} = this.props;
// @ts-ignore
const { inviteItems, selectableItems } = this.state;
let placeholderKey = 'searchPlaceholder';
@@ -212,7 +230,7 @@ class AddPeopleDialog extends AbstractAddPeopleDialog<Props, State> {
data = { inviteItems }
horizontal = { true }
keyExtractor = { this._keyExtractor }
renderItem = { this._renderInvitedItem } />
renderItem = { this._renderInvitedItem as any } />
</View> }
<View style = { styles.resultList }>
<FlatList
@@ -220,7 +238,7 @@ class AddPeopleDialog extends AbstractAddPeopleDialog<Props, State> {
data = { selectableItems }
extraData = { inviteItems }
keyExtractor = { this._keyExtractor }
renderItem = { this._renderItem } />
renderItem = { this._renderItem as any } />
</View>
</JitsiScreen>
);
@@ -241,7 +259,7 @@ class AddPeopleDialog extends AbstractAddPeopleDialog<Props, State> {
* @param {Object} flatListItem - An item of the data array of the {@code FlatList}.
* @returns {?Object}
*/
_getRenderableItem(flatListItem) {
_getRenderableItem(flatListItem: any) {
const { item } = flatListItem;
switch (item.type) {
@@ -262,12 +280,6 @@ class AddPeopleDialog extends AbstractAddPeopleDialog<Props, State> {
}
}
_invite: Array<Object> => Promise<Array<Object>>;
_isAddDisabled: () => boolean;
_keyExtractor: Object => string;
/**
* Key extractor for the flatlist.
*
@@ -275,12 +287,10 @@ class AddPeopleDialog extends AbstractAddPeopleDialog<Props, State> {
* generated for.
* @returns {string}
*/
_keyExtractor(item) {
_keyExtractor(item: any) {
return item.type === INVITE_TYPES.USER ? item.id || item.user_id : item.number;
}
_onClearField: () => void;
/**
* Callback to clear the text field.
*
@@ -292,21 +302,22 @@ class AddPeopleDialog extends AbstractAddPeopleDialog<Props, State> {
});
// Clear search results
// @ts-ignore
this._onTypeQuery('');
}
_onInvite: () => void;
/**
* Invites the selected entries.
*
* @returns {void}
*/
_onInvite() {
// @ts-ignore
this._invite(this.state.inviteItems)
.then(invitesLeftToSend => {
.then((invitesLeftToSend: ArrayLike<any>) => {
if (invitesLeftToSend.length) {
this.setState({
// @ts-ignore
inviteItems: invitesLeftToSend
});
this._showFailedInviteAlert();
@@ -314,55 +325,56 @@ class AddPeopleDialog extends AbstractAddPeopleDialog<Props, State> {
});
}
_onPressItem: Item => Function;
/**
* Function to prepare a callback for the onPress event of the touchable.
*
* @param {Item} item - The item on which onPress was invoked.
* @returns {Function}
*/
_onPressItem(item) {
_onPressItem(item: Item) {
return () => {
// @ts-ignore
const { inviteItems } = this.state;
const finderKey = item.type === INVITE_TYPES.PHONE ? 'number' : 'user_id';
if (inviteItems.find(
_.matchesProperty(finderKey, item[finderKey]))) {
// @ts-ignore
_.matchesProperty(finderKey, item[finderKey]))) {
// Item is already selected, need to unselect it.
this.setState({
// @ts-ignore
inviteItems: inviteItems.filter(
element => item[finderKey] !== element[finderKey])
// @ts-ignore
(element: any) => item[finderKey] !== element[finderKey])
});
} else {
// Item is not selected yet, need to add to the list.
const items: Array<Object> = inviteItems.concat(item);
this.setState({
// @ts-ignore
inviteItems: _.sortBy(items, [ 'name', 'number' ])
});
}
};
}
_onShareMeeting: () => void;
/**
* Shows the system share sheet to share the meeting information.
*
* @returns {void}
*/
_onShareMeeting() {
// @ts-ignore
if (this.state.inviteItems.length > 0) {
// The use probably intended to invite people.
this._onInvite();
} else {
// @ts-ignore
this.props.dispatch(beginShareRoom());
}
}
_onTypeQuery: string => void;
/**
* Handles the typing event of the text field on the dialog and performs the
* search.
@@ -370,12 +382,13 @@ class AddPeopleDialog extends AbstractAddPeopleDialog<Props, State> {
* @param {string} query - The query that is typed in the field.
* @returns {void}
*/
_onTypeQuery(query) {
_onTypeQuery(query: string) {
this.setState({
fieldValue: query
});
clearTimeout(this.searchTimeout);
// @ts-ignore
this.searchTimeout = setTimeout(() => {
this.setState({
searchInprogress: true
@@ -391,7 +404,7 @@ class AddPeopleDialog extends AbstractAddPeopleDialog<Props, State> {
* @param {string} query - The query to search for.
* @returns {void}
*/
_performSearch(query) {
_performSearch(query: string) {
this._query(query).then(results => {
this.setState({
selectableItems: _.sortBy(results, [ 'name', 'number' ])
@@ -404,19 +417,15 @@ class AddPeopleDialog extends AbstractAddPeopleDialog<Props, State> {
});
}
_query: (string) => Promise<Array<Object>>;
_renderInvitedItem: Object => ReactElement | null;
/**
* Renders a single item in the invited {@code FlatList}.
*
* @param {Object} flatListItem - An item of the data array of the
* {@code FlatList}.
* @param {number} index - The index of the currently rendered item.
* @returns {?React$Element<any>}
* @returns {ReactElement<any>}
*/
_renderInvitedItem(flatListItem, index): ReactElement | null {
_renderInvitedItem(flatListItem: any, index: number): ReactElement | null {
const { item } = flatListItem;
const renderableItem = this._getRenderableItem(flatListItem);
@@ -424,14 +433,14 @@ class AddPeopleDialog extends AbstractAddPeopleDialog<Props, State> {
<TouchableOpacity onPress = { this._onPressItem(item) } >
<View
pointerEvents = 'box-only'
style = { styles.itemWrapper }>
style = { styles.itemWrapper as ViewStyle }>
<AvatarListItem
avatarOnly = { true }
avatarSize = { AVATAR_SIZE }
avatarStatus = { item.status }
avatarStyle = { styles.avatar }
avatarTextStyle = { styles.avatarText }
item = { renderableItem }
item = { renderableItem as any }
key = { index }
linesStyle = { styles.itemLinesStyle }
titleStyle = { styles.itemText } />
@@ -443,18 +452,17 @@ class AddPeopleDialog extends AbstractAddPeopleDialog<Props, State> {
);
}
_renderItem: Object => ReactElement | null;
/**
* Renders a single item in the search result {@code FlatList}.
*
* @param {Object} flatListItem - An item of the data array of the
* {@code FlatList}.
* @param {number} index - The index of the currently rendered item.
* @returns {?React$Element<*>}
* @returns {?ReactElement<*>}
*/
_renderItem(flatListItem, index): ReactElement | null {
_renderItem(flatListItem: any, index: number): ReactElement | null {
const { item } = flatListItem;
// @ts-ignore
const { inviteItems } = this.state;
let selected = false;
const renderableItem = this._getRenderableItem(flatListItem);
@@ -480,13 +488,13 @@ class AddPeopleDialog extends AbstractAddPeopleDialog<Props, State> {
<TouchableOpacity onPress = { this._onPressItem(item) } >
<View
pointerEvents = 'box-only'
style = { styles.itemWrapper }>
style = { styles.itemWrapper as ViewStyle }>
<AvatarListItem
avatarSize = { AVATAR_SIZE }
avatarStatus = { item.status }
avatarStyle = { styles.avatar }
avatarTextStyle = { styles.avatarText }
item = { renderableItem }
item = { renderableItem as any }
key = { index }
linesStyle = { styles.itemLinesStyle }
titleStyle = { styles.itemText } />
@@ -498,12 +506,10 @@ class AddPeopleDialog extends AbstractAddPeopleDialog<Props, State> {
);
}
_renderSeparator: () => ReactElement | null;
/**
* Renders the item separator.
*
* @returns {?React$Element<*>}
* @returns {?ReactElement<*>}
*/
_renderSeparator() {
return (
@@ -511,19 +517,16 @@ class AddPeopleDialog extends AbstractAddPeopleDialog<Props, State> {
);
}
_renderShareMeetingButton: () => ReactElement;
/**
* Renders a button to share the meeting info.
*
* @returns {React#Element<*>}
*/
_renderShareMeetingButton() {
return (
<View
style = { [
styles.bottomBar,
styles.bottomBar as ViewStyle,
this.state.bottomPadding ? styles.extraBarPadding : null
] }>
<TouchableOpacity
@@ -536,15 +539,12 @@ class AddPeopleDialog extends AbstractAddPeopleDialog<Props, State> {
);
}
_renderIcon: () => ReactElement;
/**
* Renders an icon.
*
* @returns {React#Element<*>}
*/
_renderIcon() {
if (this.state.searchInprogress) {
return (
<ActivityIndicator
@@ -570,6 +570,7 @@ class AddPeopleDialog extends AbstractAddPeopleDialog<Props, State> {
* @returns {void}
*/
_showFailedInviteAlert() {
// @ts-ignore
this.props.dispatch(openDialog(AlertDialog, {
contentKey: {
key: 'inviteDialog.alertText'
@@ -586,10 +587,10 @@ class AddPeopleDialog extends AbstractAddPeopleDialog<Props, State> {
* _isVisible: boolean
* }}
*/
function _mapStateToProps(state: Object) {
function _mapStateToProps(state: IReduxState) {
return {
..._abstractMapStateToProps(state)
};
}
// @ts-ignore
export default translate(connect(_mapStateToProps)(AddPeopleDialog));

View File

@@ -113,5 +113,9 @@ export default {
left: AVATAR_SIZE / -3,
position: 'relative',
top: AVATAR_SIZE / -3
},
sendBtn: {
marginRight: BaseTheme.spacing[2]
}
};

View File

@@ -12,7 +12,7 @@ import Dialog from '../../../../base/ui/components/web/Dialog';
import { StatusCode } from '../../../../base/util/uri';
import { isDynamicBrandingDataLoaded } from '../../../../dynamic-branding/functions.any';
import { getActiveSession } from '../../../../recording/functions';
import { updateDialInNumbers } from '../../../actions';
import { updateDialInNumbers } from '../../../actions.web';
import {
_getDefaultPhoneNumber,
getInviteText,

View File

@@ -28,7 +28,6 @@ import {
import logger from './logger';
import { IInvitee } from './types';
declare let $: any;
export const sharingFeatures = {
email: 'email',
@@ -50,11 +49,16 @@ export function checkDialNumber(
): Promise<{ allow?: boolean; country?: string; phone?: string; }> {
const fullUrl = `${dialOutAuthUrl}?phone=${dialNumber}`;
return new Promise((resolve, reject) => {
$.getJSON(fullUrl)
.then(resolve)
.catch(reject);
});
return new Promise((resolve, reject) =>
fetch(fullUrl)
.then(res => {
if (res.ok) {
resolve(res.json());
} else {
reject(new Error('Request not successful!'));
}
})
.catch(reject));
}
/**

View File

@@ -1,12 +1,14 @@
import React from 'react';
import { GestureResponderEvent } from 'react-native';
import { StyleType } from '../../../base/styles/functions.native';
import Button from '../../../base/ui/components/native/Button';
import IconButton from '../../../base/ui/components/native/IconButton';
import { BUTTON_TYPES } from '../../../base/ui/constants.native';
import { navigationStyles } from './styles';
interface IProps {
/**
@@ -29,45 +31,61 @@ interface IProps {
*/
src?: any;
/**
* Style of the button.
*/
style?: StyleType;
/**
* Header has two actions.
*/
twoActions?: boolean;
}
const HeaderNavigationButton
= ({
disabled,
label,
onPress,
src,
twoActions
}: IProps) =>
(
<>
{
src ? (
<IconButton
onPress = { onPress }
size = { 24 }
src = { src }
style = { navigationStyles.headerNavigationButton } />
) : (
<Button
disabled = { disabled }
labelKey = { label }
labelStyle = {
twoActions
? navigationStyles.headerNavigationButtonLabelBold
: navigationStyles.headerNavigationButtonLabel
}
onClick = { onPress }
style = { navigationStyles.headerNavigationButton }
type = { BUTTON_TYPES.TERTIARY }
useRippleColor = { false } />
)}
</>
);
const HeaderNavigationButton = ({ disabled, label, onPress, src, style, twoActions }: IProps) => {
let btnStyle;
let labelStyle;
if (disabled) {
btnStyle = navigationStyles.headerNavigationButtonDisabled;
labelStyle = twoActions
? navigationStyles.headerNavigationButtonLabelBoldDisabled
: navigationStyles.headerNavigationButtonLabelDisabled;
} else {
btnStyle = navigationStyles.headerNavigationButton;
labelStyle = twoActions
? navigationStyles.headerNavigationButtonLabelBold
: navigationStyles.headerNavigationButtonLabel;
}
return (
<>
{
src ? (
<IconButton
onPress = { onPress }
size = { 24 }
src = { src }
style = { [
navigationStyles.headerNavigationButton,
style
] } />
) : (
<Button
disabled = { disabled }
labelKey = { label }
labelStyle = { labelStyle }
onClick = { onPress }
style = { [
btnStyle,
style
] }
type = { BUTTON_TYPES.TERTIARY }
useRippleColor = { false } />
)}
</>
);
};
export default HeaderNavigationButton;

View File

@@ -46,15 +46,31 @@ export const navigationStyles = {
marginLeft: BaseTheme.spacing[2]
},
headerNavigationButtonDisabled: {
backgroundColor: 'transparent',
marginLeft: BaseTheme.spacing[2]
},
headerNavigationButtonLabel: {
...headerNavigationButtonLabel
},
headerNavigationButtonLabelDisabled: {
...headerNavigationButtonLabel,
color: BaseTheme.palette.text03
},
headerNavigationButtonLabelBold: {
...headerNavigationButtonLabel,
...BaseTheme.typography.bodyShortRegularLarge
},
headerNavigationButtonLabelBoldDisabled: {
...headerNavigationButtonLabel,
...BaseTheme.typography.bodyShortRegularLarge,
color: BaseTheme.palette.text03
},
unreadCounterContainer: {
alignItems: 'center',
display: 'flex',

View File

@@ -10,18 +10,25 @@ import { translate } from '../../../base/i18n/functions';
import Icon from '../../../base/icons/components/Icon';
import { IconAddUser } from '../../../base/icons/svg';
import {
addPeopleFeatureControl,
getLocalParticipant,
getParticipantCountWithFake,
getRemoteParticipants
getRemoteParticipants,
setShareDialogVisiblity
} from '../../../base/participants/functions';
import Button from '../../../base/ui/components/native/Button';
import Input from '../../../base/ui/components/native/Input';
import { BUTTON_TYPES } from '../../../base/ui/constants.native';
import { getBreakoutRooms, getCurrentRoomId } from '../../../breakout-rooms/functions';
import {
getBreakoutRooms,
getCurrentRoomId
} from '../../../breakout-rooms/functions';
import { doInvitePeople } from '../../../invite/actions.native';
import { toggleShareDialog } from '../../../share-room/actions';
import { getInviteOthersControl } from '../../../share-room/functions';
import { participantMatchesSearch, shouldRenderInviteButton } from '../../functions';
import {
participantMatchesSearch,
shouldRenderInviteButton
} from '../../functions';
// @ts-ignore
import CollapsibleList from './CollapsibleList';
@@ -43,6 +50,11 @@ interface IProps extends WithTranslation {
*/
_inviteOthersControl: any;
/**
* Checks if add-people feature is enabled.
*/
_isAddPeopleFeatureEnabled: boolean;
/**
* The local participant.
*/
@@ -139,8 +151,11 @@ class MeetingParticipantList extends PureComponent<IProps> {
* @returns {void}
*/
_onInvite() {
this.props.dispatch(toggleShareDialog(true));
this.props.dispatch(doInvitePeople());
const { _isAddPeopleFeatureEnabled, dispatch } = this.props;
setShareDialogVisiblity(_isAddPeopleFeatureEnabled, dispatch);
dispatch(doInvitePeople());
}
/**
@@ -279,6 +294,7 @@ function _mapStateToProps(state: IReduxState): Object {
const { remoteParticipants } = state['features/filmstrip'];
const { shareDialogVisible } = state['features/share-room'];
const _inviteOthersControl = getInviteOthersControl(state);
const _isAddPeopleFeatureEnabled = addPeopleFeatureControl(state);
const _showInviteButton = shouldRenderInviteButton(state);
const _remoteParticipants = getRemoteParticipants(state);
const currentRoomId = getCurrentRoomId(state);
@@ -286,6 +302,7 @@ function _mapStateToProps(state: IReduxState): Object {
return {
_currentRoom,
_isAddPeopleFeatureEnabled,
_inviteOthersControl,
_participantsCount,
_remoteParticipants,