feat: help centre

This commit is contained in:
Bettenbuk Zoltan 2020-03-30 17:26:15 +02:00 committed by Zoltan Bettenbuk
parent c5e693f14a
commit 57d14d9517
17 changed files with 338 additions and 9 deletions

View File

@ -757,6 +757,7 @@
"connectCalendarButton": "Connect your calendar",
"connectCalendarText": "Connect your calendar to view all your meetings in {{app}}. Plus, add {{provider}} meetings to your calendar and start them with one click.",
"enterRoomTitle": "Start a new meeting",
"getHelp": "Get help",
"roomNameAllowedChars": "Meeting name should not contain any of these characters: ?, &, :, ', \", %, #.",
"go": "GO",
"goSmall": "GO",
@ -776,5 +777,8 @@
"lonelyMeetingExperience": {
"button": "Invite others",
"youAreAlone": "You are the only one in the meeting"
},
"helpView": {
"header": "Help centre"
}
}

View File

@ -89,10 +89,22 @@ export class AbstractApp extends BaseApp<Props, *> {
return (
<Fragment>
<OverlayContainer />
{ this._createExtraPlatformSpecificElement() }
</Fragment>
);
}
/**
* Renders platform specific extra elements to be added alongside with the main element, if need be.
*
* NOTE: Overridden by child components.
*
* @returns {React$Element}
*/
_createExtraPlatformSpecificElement() {
return null;
}
_createMainElement: (React$Element<*>, Object) => ?React$Element<*>;
/**

View File

@ -12,6 +12,7 @@ import { Platform } from '../../base/react';
import '../../base/responsive-ui';
import { updateSettings } from '../../base/settings';
import '../../google-api';
import { HelpView } from '../../help';
import '../../mobile/audio-mode';
import '../../mobile/back-button';
import '../../mobile/background';
@ -107,6 +108,17 @@ export class App extends AbstractApp {
});
}
/**
* Renders platform specific extra elements to be added alongside with the main element, if need be.
*
* @inheritdoc
*/
_createExtraPlatformSpecificElement() {
return (
<HelpView />
);
}
/**
* Attempts to disable the use of React Native
* {@link ExceptionsManager#handleException} on platforms and in

View File

@ -39,6 +39,7 @@ export default {
statusBarContent: ColorPalette.white,
text: ColorPalette.white
},
'Modal': {},
'LargeVideo': {
background: 'rgb(42, 58, 75)'
},

View File

@ -0,0 +1,6 @@
// @flow
/**
* Action type to set the ID of the active modal (or undefined if needs to be hidden).
*/
export const SET_ACTIVE_MODAL_ID = 'SET_ACTIVE_MODAL_ID';

View File

@ -0,0 +1,19 @@
// @flow
import { SET_ACTIVE_MODAL_ID } from './actionTypes';
/**
* Action to set the ID of the active modal (or undefined if needs to be hidden).
*
* @param {string} activeModalId - The new modal ID or undefined.
* @returns {{
* activeModalId: string,
* type: SET_ACTIVE_MODAL_ID
* }}
*/
export function setActiveModalId(activeModalId: ?string) {
return {
activeModalId,
type: SET_ACTIVE_MODAL_ID
};
}

View File

@ -0,0 +1,151 @@
// @flow
import React, { PureComponent } from 'react';
import { SafeAreaView, View } from 'react-native';
import { ColorSchemeRegistry } from '../../color-scheme';
import { HeaderWithNavigation, SlidingView } from '../../react';
import { connect } from '../../redux';
import { StyleType } from '../../styles';
import { setActiveModalId } from '../actions';
import styles from './styles';
type Props = {
/**
* The color schemed style of the common header component.
*/
_headerStyles: StyleType,
/**
* True if the modal should be shown, false otherwise.
*/
_show: boolean,
/**
* The color schemed style of the modal.
*/
_styles: StyleType,
/**
* The children component(s) of the Modal, to be rendered.
*/
children: React$Node,
/**
* The Redux Dispatch function.
*/
dispatch: Function,
/**
* The i18n label key of the header title.
*/
headerLabelKey: string,
/**
* The ID of the modal that is being rendered. This is used to show/hide the modal.
*/
modalId: string,
/**
* Callback to be invoked when the modal closes.
*/
onClose?: Function,
/**
* The position from where the modal should be opened. This is derived from the
* props of the {@code SlidingView} with the same name.
*/
position?: string
};
/**
* Implements a custom Jitsi Modal that doesn't use the built in native
* Modal component of React Native.
*/
class JitsiModal extends PureComponent<Props> {
static defaultProps = {
position: 'bottom'
};
/**
* Instantiates a new component.
*
* @inheritdoc
*/
constructor(props: Props) {
super(props);
this._onRequestClose = this._onRequestClose.bind(this);
}
/**
* Implements {@code PureComponent#render}.
*
* @inheritdoc
*/
render() {
const { _headerStyles, _show, _styles, children, headerLabelKey, position } = this.props;
return (
<SlidingView
onHide = { this._onRequestClose }
position = { position }
show = { _show }>
<View
style = { [
_headerStyles.page,
_styles.page
] }>
<HeaderWithNavigation
headerLabelKey = { headerLabelKey }
onPressBack = { this._onRequestClose } />
<SafeAreaView style = { styles.safeArea }>
{ children }
</SafeAreaView>
</View>
</SlidingView>
);
}
_onRequestClose: () => boolean;
/**
* Callback to be invoked when the SlidingView requests closing.
*
* @returns {boolean}
*/
_onRequestClose() {
const { _show, dispatch, onClose } = this.props;
if (_show) {
if (typeof onClose === 'function') {
onClose();
}
dispatch(setActiveModalId());
return true;
}
return false;
}
}
/**
* Maps part of the Redix state to the props of this component.
*
* @param {Object} state - The Redux state.
* @param {Props} ownProps - The own props of the component.
* @returns {Props}
*/
function _mapStateToProps(state, ownProps): $Shape<Props> {
return {
_headerStyles: ColorSchemeRegistry.get(state, 'Header'),
_show: state['features/base/modal'].activeModalId === ownProps.modalId,
_styles: ColorSchemeRegistry.get(state, 'Modal')
};
}
export default connect(_mapStateToProps)(JitsiModal);

View File

@ -0,0 +1,3 @@
// @flow
export { default as JitsiModal } from './JitsiModal';

View File

@ -0,0 +1,6 @@
// @flow
import { Component } from 'react';
export const JitsiModal = Component;

View File

@ -0,0 +1,15 @@
// @flow
import { ColorSchemeRegistry, schemeColor } from '../../color-scheme';
export default {
safeArea: {
flex: 1
}
};
ColorSchemeRegistry.register('Modal', {
page: {
backgroundColor: schemeColor('background')
}
});

View File

@ -0,0 +1,7 @@
// @flow
import './reducer';
export * from './actions';
export * from './actionTypes';
export * from './components';

View File

@ -0,0 +1,17 @@
// @flow
import { ReducerRegistry } from '../redux';
import { SET_ACTIVE_MODAL_ID } from './actionTypes';
ReducerRegistry.register('features/base/modal', (state = {}, action) => {
switch (action.type) {
case SET_ACTIVE_MODAL_ID:
return {
...state,
activeModalId: action.activeModalId
};
}
return state;
});

View File

@ -0,0 +1,54 @@
// @flow
import React, { PureComponent } from 'react';
import WebView from 'react-native-webview';
import { JitsiModal } from '../../base/modal';
import { connect } from '../../base/redux';
import { HELP_VIEW_MODAL_ID } from '../constants';
const DEFAULT_HELP_CENTRE_URL = 'https://web-cdn.jitsi.net/faq/meet-faq.html';
type Props = {
/**
* The URL to display in the Help Centre.
*/
_url: string
}
/**
* Implements a page that renders the help content for the app.
*/
class HelpView extends PureComponent<Props> {
/**
* Implements {@code PureComponent#render()}.
*
* @inheritdoc
* @returns {ReactElement}
*/
render() {
return (
<JitsiModal
headerLabelKey = 'helpView.header'
modalId = { HELP_VIEW_MODAL_ID }>
<WebView source = {{ uri: this.props._url }} />
</JitsiModal>
);
}
}
/**
* Maps part of the Redux state to the props of this component.
*
* @param {Object} state - The Redux state.
* @returns {Props}
*/
function _mapStateToProps(state) {
return {
_url: state['features/base/config'].helpCentreURL || DEFAULT_HELP_CENTRE_URL
};
}
export default connect(_mapStateToProps)(HelpView);

View File

@ -0,0 +1,3 @@
// @flow
export { default as HelpView } from './HelpView';

View File

@ -0,0 +1,3 @@
// @flow
export const HELP_VIEW_MODAL_ID = 'helpView';

View File

@ -0,0 +1,4 @@
// @flow
export * from './components';
export * from './constants';

View File

@ -4,7 +4,8 @@ import React, { Component } from 'react';
import { SafeAreaView, ScrollView, Text } from 'react-native';
import { Avatar } from '../../base/avatar';
import { IconInfo, IconSettings } from '../../base/icons';
import { IconInfo, IconSettings, IconHelp } from '../../base/icons';
import { setActiveModalId } from '../../base/modal';
import {
getLocalParticipant,
getParticipantDisplayName
@ -14,6 +15,7 @@ import {
SlidingView
} from '../../base/react';
import { connect } from '../../base/redux';
import { HELP_VIEW_MODAL_ID } from '../../help';
import { setSettingsViewVisible } from '../../settings';
import { setSideBarVisible } from '../actions';
@ -25,11 +27,6 @@ import styles, { SIDEBAR_AVATAR_SIZE } from './styles';
*/
const PRIVACY_URL = 'https://jitsi.org/meet/privacy';
/**
* The URL at which the user may send feedback.
*/
const SEND_FEEDBACK_URL = 'mailto:support@jitsi.org';
/**
* The URL at which the terms (of service/use) are available to the user.
*/
@ -72,6 +69,7 @@ class WelcomePageSideBar extends Component<Props> {
// Bind event handlers so they are only bound once per instance.
this._onHideSideBar = this._onHideSideBar.bind(this);
this._onOpenHelpPage = this._onOpenHelpPage.bind(this);
this._onOpenSettings = this._onOpenSettings.bind(this);
}
@ -112,9 +110,9 @@ class WelcomePageSideBar extends Component<Props> {
label = 'welcomepage.privacy'
url = { PRIVACY_URL } />
<SideBarItem
icon = { IconInfo }
label = 'welcomepage.sendFeedback'
url = { SEND_FEEDBACK_URL } />
icon = { IconHelp }
label = 'welcomepage.getHelp'
onPress = { this._onOpenHelpPage } />
</ScrollView>
</SafeAreaView>
</SlidingView>
@ -133,6 +131,20 @@ class WelcomePageSideBar extends Component<Props> {
this.props.dispatch(setSideBarVisible(false));
}
_onOpenHelpPage: () => void;
/**
* Shows the {@link HelpView}.
*
* @returns {void}
*/
_onOpenHelpPage() {
const { dispatch } = this.props;
dispatch(setSideBarVisible(false));
dispatch(setActiveModalId(HELP_VIEW_MODAL_ID));
}
_onOpenSettings: () => void;
/**