Compare commits
22 Commits
develop
...
new.create
Author | SHA1 | Date |
---|---|---|
Diego Mello | db30859a22 | |
Diego Mello | 0963706266 | |
Diego Mello | b7e075df02 | |
Diego Mello | 943e179e18 | |
Reinaldo Neto | 64f4cc3cf1 | |
Reinaldo Neto | a33eeee317 | |
Reinaldo Neto | f7ef6c61cf | |
Diego Mello | 996b3242ea | |
Diego Mello | e01c31dbf3 | |
Reinaldo Neto | 72b6034d7f | |
Reinaldo Neto | cd583bb503 | |
Diego Mello | 38b8415c73 | |
Reinaldo Neto | d6f9d1d64a | |
Reinaldo Neto | fa87dc6c58 | |
Reinaldo Neto | 9ed35f0f1d | |
Reinaldo Neto | 8d5137ca5b | |
Reinaldo Neto | 9449949ac3 | |
Reinaldo Neto | c57caafaf8 | |
Reinaldo Neto | 06ca560e43 | |
Reinaldo Neto | 5e3eddc66f | |
Reinaldo Neto | 1a63e80861 | |
Reinaldo Neto | 6008b9cacb |
|
@ -5,7 +5,7 @@ import { connect } from 'react-redux';
|
|||
|
||||
import Navigation from './lib/Navigation';
|
||||
import { defaultHeader, getActiveRouteName, navigationTheme } from './utils/navigation';
|
||||
import { ROOT_INSIDE, ROOT_LOADING, ROOT_NEW_SERVER, ROOT_OUTSIDE, ROOT_SET_USERNAME } from './actions/app';
|
||||
import { ROOT_INSIDE, ROOT_LOADING, ROOT_OUTSIDE, ROOT_SET_USERNAME } from './actions/app';
|
||||
// Stacks
|
||||
import AuthLoadingView from './views/AuthLoadingView';
|
||||
// SetUsername Stack
|
||||
|
@ -56,9 +56,7 @@ const App = React.memo(({ root, isMasterDetail }: { root: string; isMasterDetail
|
|||
<Stack.Navigator screenOptions={{ headerShown: false, animationEnabled: false }}>
|
||||
<>
|
||||
{root === ROOT_LOADING ? <Stack.Screen name='AuthLoading' component={AuthLoadingView} /> : null}
|
||||
{root === ROOT_OUTSIDE || root === ROOT_NEW_SERVER ? (
|
||||
<Stack.Screen name='OutsideStack' component={OutsideStack} />
|
||||
) : null}
|
||||
{root === ROOT_OUTSIDE ? <Stack.Screen name='OutsideStack' component={OutsideStack} /> : null}
|
||||
{root === ROOT_INSIDE && isMasterDetail ? (
|
||||
<Stack.Screen name='MasterDetailStack' component={MasterDetailStack} />
|
||||
) : null}
|
||||
|
|
|
@ -3,7 +3,6 @@ import { APP } from './actionsTypes';
|
|||
export const ROOT_OUTSIDE = 'outside';
|
||||
export const ROOT_INSIDE = 'inside';
|
||||
export const ROOT_LOADING = 'loading';
|
||||
export const ROOT_NEW_SERVER = 'newServer';
|
||||
export const ROOT_SET_USERNAME = 'setUsername';
|
||||
|
||||
export function appStart({ root, ...args }) {
|
||||
|
|
|
@ -17,6 +17,7 @@ interface IButtonProps {
|
|||
color: string;
|
||||
fontSize: any;
|
||||
style: any;
|
||||
styleText?: any;
|
||||
testID: string;
|
||||
}
|
||||
|
||||
|
@ -48,7 +49,8 @@ export default class Button extends React.PureComponent<Partial<IButtonProps>, a
|
|||
};
|
||||
|
||||
render() {
|
||||
const { title, type, onPress, disabled, backgroundColor, color, loading, style, theme, fontSize, ...otherProps } = this.props;
|
||||
const { title, type, onPress, disabled, backgroundColor, color, loading, style, theme, fontSize, styleText, ...otherProps } =
|
||||
this.props;
|
||||
const isPrimary = type === 'primary';
|
||||
|
||||
let textColor = isPrimary ? themes[theme!].buttonText : themes[theme!].bodyText;
|
||||
|
@ -72,7 +74,7 @@ export default class Button extends React.PureComponent<Partial<IButtonProps>, a
|
|||
{loading ? (
|
||||
<ActivityIndicator color={textColor} />
|
||||
) : (
|
||||
<Text style={[styles.text, { color: textColor }, fontSize && { fontSize }]} accessibilityLabel={title}>
|
||||
<Text style={[styles.text, { color: textColor }, fontSize && { fontSize }, styleText]} accessibilityLabel={title}>
|
||||
{title}
|
||||
</Text>
|
||||
)}
|
||||
|
|
|
@ -7,7 +7,6 @@ const initialState = {
|
|||
server: '',
|
||||
version: null,
|
||||
loading: true,
|
||||
adding: false,
|
||||
previousServer: null,
|
||||
changingServer: false
|
||||
};
|
||||
|
@ -58,13 +57,11 @@ export default function server(state = initialState, action) {
|
|||
case SERVER.INIT_ADD:
|
||||
return {
|
||||
...state,
|
||||
adding: true,
|
||||
previousServer: action.previousServer
|
||||
};
|
||||
case SERVER.FINISH_ADD:
|
||||
return {
|
||||
...state,
|
||||
adding: false,
|
||||
previousServer: null
|
||||
};
|
||||
default:
|
||||
|
|
|
@ -8,7 +8,7 @@ import { inviteLinksRequest, inviteLinksSetToken } from '../actions/inviteLinks'
|
|||
import database from '../lib/database';
|
||||
import RocketChat from '../lib/rocketchat';
|
||||
import EventEmitter from '../utils/events';
|
||||
import { ROOT_INSIDE, ROOT_NEW_SERVER, appInit, appStart } from '../actions/app';
|
||||
import { ROOT_INSIDE, ROOT_OUTSIDE, appInit, appStart } from '../actions/app';
|
||||
import { localAuthenticate } from '../utils/localAuthentication';
|
||||
import { goRoom } from '../utils/goRoom';
|
||||
import { loginRequest } from '../actions/login';
|
||||
|
@ -180,7 +180,7 @@ const handleOpen = function* handleOpen({ params }) {
|
|||
yield fallbackNavigation();
|
||||
return;
|
||||
}
|
||||
yield put(appStart({ root: ROOT_NEW_SERVER }));
|
||||
yield put(appStart({ root: ROOT_OUTSIDE }));
|
||||
yield put(serverInitAdd(server));
|
||||
yield delay(1000);
|
||||
EventEmitter.emit('NewServer', { server: host });
|
||||
|
|
|
@ -118,8 +118,6 @@ const fetchRooms = function* fetchRooms() {
|
|||
|
||||
const handleLoginSuccess = function* handleLoginSuccess({ user }) {
|
||||
try {
|
||||
const adding = yield select(state => state.server.adding);
|
||||
|
||||
RocketChat.getUserPresence(user.id);
|
||||
|
||||
const server = yield select(getServer);
|
||||
|
@ -170,24 +168,10 @@ const handleLoginSuccess = function* handleLoginSuccess({ user }) {
|
|||
yield put(setUser(user));
|
||||
EventEmitter.emit('connected');
|
||||
|
||||
let currentRoot;
|
||||
if (adding) {
|
||||
yield put(serverFinishAdd());
|
||||
yield put(appStart({ root: ROOT_INSIDE }));
|
||||
} else {
|
||||
currentRoot = yield select(state => state.app.root);
|
||||
if (currentRoot !== ROOT_INSIDE) {
|
||||
yield put(appStart({ root: ROOT_INSIDE }));
|
||||
}
|
||||
}
|
||||
|
||||
// after a successful login, check if it's been invited via invite link
|
||||
currentRoot = yield select(state => state.app.root);
|
||||
if (currentRoot === ROOT_INSIDE) {
|
||||
const inviteLinkToken = yield select(state => state.inviteLinks.token);
|
||||
if (inviteLinkToken) {
|
||||
yield put(inviteLinksRequest(inviteLinkToken));
|
||||
}
|
||||
yield put(appStart({ root: ROOT_INSIDE }));
|
||||
const inviteLinkToken = yield select(state => state.inviteLinks.token);
|
||||
if (inviteLinkToken) {
|
||||
yield put(inviteLinksRequest(inviteLinkToken));
|
||||
}
|
||||
} catch (e) {
|
||||
log(e);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { put, takeLatest } from 'redux-saga/effects';
|
||||
import { put, takeLatest, select } from 'redux-saga/effects';
|
||||
import { Alert } from 'react-native';
|
||||
import { sanitizedRaw } from '@nozbe/watermelondb/RawRecord';
|
||||
import { Q } from '@nozbe/watermelondb';
|
||||
|
@ -7,7 +7,7 @@ import coerce from 'semver/functions/coerce';
|
|||
|
||||
import Navigation from '../lib/Navigation';
|
||||
import { SERVER } from '../actions/actionsTypes';
|
||||
import { selectServerFailure, selectServerRequest, selectServerSuccess, serverFailure } from '../actions/server';
|
||||
import { selectServerFailure, selectServerRequest, selectServerSuccess, serverFailure, serverFinishAdd } from '../actions/server';
|
||||
import { clearSettings } from '../actions/settings';
|
||||
import { setUser } from '../actions/login';
|
||||
import RocketChat from '../lib/rocketchat';
|
||||
|
|
|
@ -1,13 +1,11 @@
|
|||
import React from 'react';
|
||||
import { createStackNavigator } from '@react-navigation/stack';
|
||||
import { connect } from 'react-redux';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import { ThemeContext } from '../theme';
|
||||
import { ModalAnimation, StackAnimation, defaultHeader, themedHeader } from '../utils/navigation';
|
||||
|
||||
// Outside Stack
|
||||
import OnboardingView from '../views/OnboardingView';
|
||||
import NewServerView from '../views/NewServerView';
|
||||
import WorkspaceView from '../views/WorkspaceView';
|
||||
import LoginView from '../views/LoginView';
|
||||
|
@ -15,18 +13,14 @@ import ForgotPasswordView from '../views/ForgotPasswordView';
|
|||
import RegisterView from '../views/RegisterView';
|
||||
import LegalView from '../views/LegalView';
|
||||
import AuthenticationWebView from '../views/AuthenticationWebView';
|
||||
import { ROOT_OUTSIDE } from '../actions/app';
|
||||
|
||||
// Outside
|
||||
const Outside = createStackNavigator();
|
||||
const _OutsideStack = ({ root }) => {
|
||||
const _OutsideStack = () => {
|
||||
const { theme } = React.useContext(ThemeContext);
|
||||
|
||||
return (
|
||||
<Outside.Navigator screenOptions={{ ...defaultHeader, ...themedHeader(theme), ...StackAnimation }}>
|
||||
{root === ROOT_OUTSIDE ? (
|
||||
<Outside.Screen name='OnboardingView' component={OnboardingView} options={OnboardingView.navigationOptions} />
|
||||
) : null}
|
||||
<Outside.Screen name='NewServerView' component={NewServerView} options={NewServerView.navigationOptions} />
|
||||
<Outside.Screen name='WorkspaceView' component={WorkspaceView} options={WorkspaceView.navigationOptions} />
|
||||
<Outside.Screen name='LoginView' component={LoginView} options={LoginView.navigationOptions} />
|
||||
|
@ -41,10 +35,6 @@ const mapStateToProps = state => ({
|
|||
root: state.app.root
|
||||
});
|
||||
|
||||
_OutsideStack.propTypes = {
|
||||
root: PropTypes.string
|
||||
};
|
||||
|
||||
const OutsideStack = connect(mapStateToProps)(_OutsideStack);
|
||||
|
||||
// OutsideStackModal
|
||||
|
|
|
@ -1,9 +1,4 @@
|
|||
export default {
|
||||
// ONBOARDING VIEW
|
||||
ONBOARD_JOIN_A_WORKSPACE: 'onboard_join_a_workspace',
|
||||
ONBOARD_CREATE_NEW_WORKSPACE: 'onboard_create_new_workspace',
|
||||
ONBOARD_CREATE_NEW_WORKSPACE_F: 'onboard_create_new_workspace_f',
|
||||
|
||||
// NEW SERVER VIEW
|
||||
NS_CONNECT_TO_WORKSPACE: 'ns_connect_to_workspace',
|
||||
NS_JOIN_OPEN_WORKSPACE: 'ns_join_open_workspace',
|
||||
|
@ -78,6 +73,8 @@ export default {
|
|||
RL_GROUP_CHANNELS_BY_TYPE: 'rl_group_channels_by_type',
|
||||
RL_GROUP_CHANNELS_BY_FAVORITE: 'rl_group_channels_by_favorite',
|
||||
RL_GROUP_CHANNELS_BY_UNREAD: 'rl_group_channels_by_unread',
|
||||
RL_CREATE_NEW_WORKSPACE: 'rl_create_new_workspace',
|
||||
RL_CREATE_NEW_WORKSPACE_F: 'rl_create_new_workspace_f',
|
||||
|
||||
// QUEUE LIST VIEW
|
||||
QL_GO_ROOM: 'ql_go_room',
|
||||
|
|
|
@ -1,14 +1,11 @@
|
|||
import { Dimensions } from 'react-native';
|
||||
|
||||
import { isTablet } from './deviceInfo';
|
||||
|
||||
const { width, height } = Dimensions.get('window');
|
||||
|
||||
const guidelineBaseWidth = isTablet ? 600 : 375;
|
||||
const guidelineBaseHeight = isTablet ? 800 : 667;
|
||||
|
||||
const scale = size => (width / guidelineBaseWidth) * size;
|
||||
const verticalScale = size => (height / guidelineBaseHeight) * size;
|
||||
const moderateScale = (size, factor = 0.5) => size + (scale(size) - size) * factor;
|
||||
// TODO: we need to refactor this
|
||||
const scale = (size, width) => (width / guidelineBaseWidth) * size;
|
||||
const verticalScale = (size, height) => (height / guidelineBaseHeight) * size;
|
||||
const moderateScale = (size, factor = 0.5, width) => size + (scale(size, width) - size) * factor;
|
||||
|
||||
export { scale, verticalScale, moderateScale };
|
||||
|
|
|
@ -11,7 +11,6 @@ import Item from './Item';
|
|||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
zIndex: 1,
|
||||
marginTop: 24,
|
||||
marginBottom: 32
|
||||
},
|
||||
inputContainer: {
|
||||
|
|
|
@ -1,15 +1,16 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { BackHandler, Keyboard, StyleSheet, Text, View } from 'react-native';
|
||||
import { Text, Keyboard, StyleSheet, View, BackHandler, Image } from 'react-native';
|
||||
import { connect } from 'react-redux';
|
||||
import { Base64 } from 'js-base64';
|
||||
import parse from 'url-parse';
|
||||
import { Q } from '@nozbe/watermelondb';
|
||||
import { TouchableOpacity } from 'react-native-gesture-handler';
|
||||
import Orientation from 'react-native-orientation-locker';
|
||||
|
||||
import UserPreferences from '../../lib/userPreferences';
|
||||
import EventEmitter from '../../utils/events';
|
||||
import { selectServerRequest, serverRequest } from '../../actions/server';
|
||||
import { selectServerRequest, serverRequest, serverFinishAdd as serverFinishAddAction } from '../../actions/server';
|
||||
import { inviteLinksClear as inviteLinksClearAction } from '../../actions/inviteLinks';
|
||||
import sharedStyles from '../Styles';
|
||||
import Button from '../../containers/Button';
|
||||
|
@ -27,31 +28,39 @@ import database from '../../lib/database';
|
|||
import { sanitizeLikeString } from '../../lib/database/utils';
|
||||
import SSLPinning from '../../utils/sslPinning';
|
||||
import RocketChat from '../../lib/rocketchat';
|
||||
import { isTablet } from '../../utils/deviceInfo';
|
||||
import { verticalScale, moderateScale } from '../../utils/scaling';
|
||||
import { withDimensions } from '../../dimensions';
|
||||
import ServerInput from './ServerInput';
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
onboardingImage: {
|
||||
alignSelf: 'center',
|
||||
width: 100,
|
||||
height: 100
|
||||
},
|
||||
title: {
|
||||
...sharedStyles.textBold,
|
||||
fontSize: 22
|
||||
letterSpacing: 0,
|
||||
alignSelf: 'center'
|
||||
},
|
||||
subtitle: {
|
||||
...sharedStyles.textRegular,
|
||||
alignSelf: 'center'
|
||||
},
|
||||
certificatePicker: {
|
||||
marginBottom: 32,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'flex-end'
|
||||
},
|
||||
chooseCertificateTitle: {
|
||||
fontSize: 13,
|
||||
...sharedStyles.textRegular
|
||||
},
|
||||
chooseCertificate: {
|
||||
fontSize: 13,
|
||||
...sharedStyles.textSemibold
|
||||
},
|
||||
description: {
|
||||
...sharedStyles.textRegular,
|
||||
fontSize: 14,
|
||||
textAlign: 'left',
|
||||
marginBottom: 24
|
||||
textAlign: 'center'
|
||||
},
|
||||
connectButton: {
|
||||
marginBottom: 0
|
||||
|
@ -59,23 +68,22 @@ const styles = StyleSheet.create({
|
|||
});
|
||||
|
||||
class NewServerView extends React.Component {
|
||||
static navigationOptions = () => ({
|
||||
title: I18n.t('Workspaces')
|
||||
});
|
||||
|
||||
static propTypes = {
|
||||
navigation: PropTypes.object,
|
||||
theme: PropTypes.string,
|
||||
connecting: PropTypes.bool.isRequired,
|
||||
connectServer: PropTypes.func.isRequired,
|
||||
selectServer: PropTypes.func.isRequired,
|
||||
adding: PropTypes.bool,
|
||||
previousServer: PropTypes.string,
|
||||
inviteLinksClear: PropTypes.func
|
||||
inviteLinksClear: PropTypes.func,
|
||||
serverFinishAdd: PropTypes.func
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
if (!isTablet) {
|
||||
Orientation.lockToPortrait();
|
||||
}
|
||||
this.setHeader();
|
||||
|
||||
this.state = {
|
||||
|
@ -92,25 +100,27 @@ class NewServerView extends React.Component {
|
|||
this.queryServerHistory();
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
const { adding } = this.props;
|
||||
if (prevProps.adding !== adding) {
|
||||
this.setHeader();
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
EventEmitter.removeListener('NewServer', this.handleNewServerEvent);
|
||||
BackHandler.removeEventListener('hardwareBackPress', this.handleBackPress);
|
||||
const { previousServer, serverFinishAdd } = this.props;
|
||||
if (previousServer) {
|
||||
serverFinishAdd();
|
||||
}
|
||||
}
|
||||
|
||||
setHeader = () => {
|
||||
const { adding, navigation } = this.props;
|
||||
if (adding) {
|
||||
navigation.setOptions({
|
||||
const { previousServer, navigation } = this.props;
|
||||
if (previousServer) {
|
||||
return navigation.setOptions({
|
||||
headerTitle: I18n.t('Workspaces'),
|
||||
headerLeft: () => <HeaderButton.CloseModal navigation={navigation} onPress={this.close} testID='new-server-view-close' />
|
||||
});
|
||||
}
|
||||
|
||||
return navigation.setOptions({
|
||||
headerShown: false
|
||||
});
|
||||
};
|
||||
|
||||
handleBackPress = () => {
|
||||
|
@ -273,16 +283,26 @@ class NewServerView extends React.Component {
|
|||
|
||||
renderCertificatePicker = () => {
|
||||
const { certificate } = this.state;
|
||||
const { theme } = this.props;
|
||||
const { theme, width, height } = this.props;
|
||||
return (
|
||||
<View style={styles.certificatePicker}>
|
||||
<Text style={[styles.chooseCertificateTitle, { color: themes[theme].auxiliaryText }]}>
|
||||
<View
|
||||
style={[
|
||||
styles.certificatePicker,
|
||||
{
|
||||
marginBottom: verticalScale(32, height)
|
||||
}
|
||||
]}>
|
||||
<Text
|
||||
style={[
|
||||
styles.chooseCertificateTitle,
|
||||
{ color: themes[theme].auxiliaryText, fontSize: moderateScale(13, null, width) }
|
||||
]}>
|
||||
{certificate ? I18n.t('Your_certificate') : I18n.t('Do_you_have_a_certificate')}
|
||||
</Text>
|
||||
<TouchableOpacity
|
||||
onPress={certificate ? this.handleRemove : this.chooseCertificate}
|
||||
testID='new-server-choose-certificate'>
|
||||
<Text style={[styles.chooseCertificate, { color: themes[theme].tintColor }]}>
|
||||
<Text style={[styles.chooseCertificate, { color: themes[theme].tintColor, fontSize: moderateScale(13, null, width) }]}>
|
||||
{certificate ?? I18n.t('Apply_Your_Certificate')}
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
|
@ -291,12 +311,44 @@ class NewServerView extends React.Component {
|
|||
};
|
||||
|
||||
render() {
|
||||
const { connecting, theme } = this.props;
|
||||
const { connecting, theme, previousServer, width, height } = this.props;
|
||||
const { text, connectingOpen, serversHistory } = this.state;
|
||||
const marginTopHeader = previousServer ? 0 : 70;
|
||||
|
||||
return (
|
||||
<FormContainer theme={theme} testID='new-server-view' keyboardShouldPersistTaps='never'>
|
||||
<FormContainerInner>
|
||||
<Text style={[styles.title, { color: themes[theme].titleText }]}>{I18n.t('Join_your_workspace')}</Text>
|
||||
<Image
|
||||
style={[
|
||||
styles.onboardingImage,
|
||||
{
|
||||
marginTop: isTablet ? 0 : verticalScale(marginTopHeader, height),
|
||||
marginBottom: verticalScale(25, height),
|
||||
maxHeight: verticalScale(150, height)
|
||||
}
|
||||
]}
|
||||
source={require('../../static/images/logo.png')}
|
||||
fadeDuration={0}
|
||||
resizeMode='stretch'
|
||||
/>
|
||||
<Text
|
||||
style={[
|
||||
styles.title,
|
||||
{ color: themes[theme].titleText, fontSize: moderateScale(22, null, width), marginBottom: verticalScale(8, height) }
|
||||
]}>
|
||||
Rocket.Chat
|
||||
</Text>
|
||||
<Text
|
||||
style={[
|
||||
styles.subtitle,
|
||||
{
|
||||
color: themes[theme].controlText,
|
||||
fontSize: moderateScale(16, null, width),
|
||||
marginBottom: verticalScale(41, height)
|
||||
}
|
||||
]}>
|
||||
{I18n.t('Onboarding_subtitle')}
|
||||
</Text>
|
||||
<ServerInput
|
||||
text={text}
|
||||
theme={theme}
|
||||
|
@ -317,7 +369,15 @@ class NewServerView extends React.Component {
|
|||
testID='new-server-view-button'
|
||||
/>
|
||||
<OrSeparator theme={theme} />
|
||||
<Text style={[styles.description, { color: themes[theme].auxiliaryText }]}>
|
||||
<Text
|
||||
style={[
|
||||
styles.description,
|
||||
{
|
||||
color: themes[theme].auxiliaryText,
|
||||
fontSize: moderateScale(14, null, width),
|
||||
marginBottom: verticalScale(24, height)
|
||||
}
|
||||
]}>
|
||||
{I18n.t('Onboarding_join_open_description')}
|
||||
</Text>
|
||||
<Button
|
||||
|
@ -339,14 +399,14 @@ class NewServerView extends React.Component {
|
|||
|
||||
const mapStateToProps = state => ({
|
||||
connecting: state.server.connecting,
|
||||
adding: state.server.adding,
|
||||
previousServer: state.server.previousServer
|
||||
});
|
||||
|
||||
const mapDispatchToProps = dispatch => ({
|
||||
connectServer: (...params) => dispatch(serverRequest(...params)),
|
||||
selectServer: server => dispatch(selectServerRequest(server)),
|
||||
inviteLinksClear: () => dispatch(inviteLinksClearAction())
|
||||
inviteLinksClear: () => dispatch(inviteLinksClearAction()),
|
||||
serverFinishAdd: () => dispatch(serverFinishAddAction())
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(withTheme(NewServerView));
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(withDimensions(withTheme(NewServerView)));
|
||||
|
|
|
@ -1,87 +0,0 @@
|
|||
import React from 'react';
|
||||
import { Image, Linking, Text, View } from 'react-native';
|
||||
import PropTypes from 'prop-types';
|
||||
import Orientation from 'react-native-orientation-locker';
|
||||
|
||||
import I18n from '../../i18n';
|
||||
import Button from '../../containers/Button';
|
||||
import { isTablet } from '../../utils/deviceInfo';
|
||||
import { themes } from '../../constants/colors';
|
||||
import { withTheme } from '../../theme';
|
||||
import FormContainer, { FormContainerInner } from '../../containers/FormContainer';
|
||||
import { events, logEvent } from '../../utils/log';
|
||||
import styles from './styles';
|
||||
|
||||
class OnboardingView extends React.Component {
|
||||
static navigationOptions = {
|
||||
headerShown: false
|
||||
};
|
||||
|
||||
static propTypes = {
|
||||
navigation: PropTypes.object,
|
||||
theme: PropTypes.string
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
if (!isTablet) {
|
||||
Orientation.lockToPortrait();
|
||||
}
|
||||
}
|
||||
|
||||
shouldComponentUpdate(nextProps) {
|
||||
const { theme } = this.props;
|
||||
if (theme !== nextProps.theme) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
connectServer = () => {
|
||||
logEvent(events.ONBOARD_JOIN_A_WORKSPACE);
|
||||
const { navigation } = this.props;
|
||||
navigation.navigate('NewServerView');
|
||||
};
|
||||
|
||||
createWorkspace = async () => {
|
||||
logEvent(events.ONBOARD_CREATE_NEW_WORKSPACE);
|
||||
try {
|
||||
await Linking.openURL('https://cloud.rocket.chat/trial');
|
||||
} catch {
|
||||
logEvent(events.ONBOARD_CREATE_NEW_WORKSPACE_F);
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
const { theme } = this.props;
|
||||
return (
|
||||
<FormContainer theme={theme} testID='onboarding-view'>
|
||||
<FormContainerInner>
|
||||
<Image style={styles.onboarding} source={require('../../static/images/logo.png')} fadeDuration={0} />
|
||||
<Text style={[styles.title, { color: themes[theme].titleText }]}>{I18n.t('Onboarding_title')}</Text>
|
||||
<Text style={[styles.subtitle, { color: themes[theme].controlText }]}>{I18n.t('Onboarding_subtitle')}</Text>
|
||||
<Text style={[styles.description, { color: themes[theme].auxiliaryText }]}>{I18n.t('Onboarding_description')}</Text>
|
||||
<View style={styles.buttonsContainer}>
|
||||
<Button
|
||||
title={I18n.t('Onboarding_join_workspace')}
|
||||
type='primary'
|
||||
onPress={this.connectServer}
|
||||
theme={theme}
|
||||
testID='join-workspace'
|
||||
/>
|
||||
<Button
|
||||
title={I18n.t('Create_a_new_workspace')}
|
||||
type='secondary'
|
||||
backgroundColor={themes[theme].chatComponentBackground}
|
||||
onPress={this.createWorkspace}
|
||||
theme={theme}
|
||||
testID='create-workspace-button'
|
||||
/>
|
||||
</View>
|
||||
</FormContainerInner>
|
||||
</FormContainer>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default withTheme(OnboardingView);
|
|
@ -1,41 +0,0 @@
|
|||
import { StyleSheet } from 'react-native';
|
||||
|
||||
import { moderateScale, verticalScale } from '../../utils/scaling';
|
||||
import { isTablet } from '../../utils/deviceInfo';
|
||||
import sharedStyles from '../Styles';
|
||||
|
||||
export default StyleSheet.create({
|
||||
onboarding: {
|
||||
alignSelf: 'center',
|
||||
marginTop: isTablet ? 0 : verticalScale(116),
|
||||
marginBottom: verticalScale(50),
|
||||
maxHeight: verticalScale(150),
|
||||
resizeMode: 'contain',
|
||||
width: 100,
|
||||
height: 100
|
||||
},
|
||||
title: {
|
||||
...sharedStyles.textBold,
|
||||
letterSpacing: 0,
|
||||
fontSize: moderateScale(24),
|
||||
alignSelf: 'center',
|
||||
marginBottom: verticalScale(8)
|
||||
},
|
||||
subtitle: {
|
||||
...sharedStyles.textRegular,
|
||||
fontSize: moderateScale(16),
|
||||
alignSelf: 'center',
|
||||
marginBottom: verticalScale(24)
|
||||
},
|
||||
description: {
|
||||
...sharedStyles.textRegular,
|
||||
...sharedStyles.textAlignCenter,
|
||||
fontSize: moderateScale(14),
|
||||
alignSelf: 'center',
|
||||
marginHorizontal: 20
|
||||
},
|
||||
buttonsContainer: {
|
||||
marginBottom: verticalScale(10),
|
||||
marginTop: verticalScale(30)
|
||||
}
|
||||
});
|
|
@ -1,13 +1,14 @@
|
|||
import React, { Component } from 'react';
|
||||
import { Animated, Easing, FlatList, Text, TouchableOpacity, TouchableWithoutFeedback, View } from 'react-native';
|
||||
import { View, Text, Animated, Easing, TouchableWithoutFeedback, TouchableOpacity, FlatList, Linking } from 'react-native';
|
||||
import PropTypes from 'prop-types';
|
||||
import { batch, connect } from 'react-redux';
|
||||
import { withSafeAreaInsets } from 'react-native-safe-area-context';
|
||||
|
||||
import * as List from '../../containers/List';
|
||||
import Button from '../../containers/Button';
|
||||
import { toggleServerDropdown as toggleServerDropdownAction } from '../../actions/rooms';
|
||||
import { selectServerRequest as selectServerRequestAction, serverInitAdd as serverInitAddAction } from '../../actions/server';
|
||||
import { ROOT_NEW_SERVER, appStart as appStartAction } from '../../actions/app';
|
||||
import { appStart as appStartAction, ROOT_OUTSIDE } from '../../actions/app';
|
||||
import RocketChat from '../../lib/rocketchat';
|
||||
import I18n from '../../i18n';
|
||||
import EventEmitter from '../../utils/events';
|
||||
|
@ -19,7 +20,7 @@ import { KEY_COMMAND, handleCommandSelectServer } from '../../commands';
|
|||
import { isTablet } from '../../utils/deviceInfo';
|
||||
import { localAuthenticate } from '../../utils/localAuthentication';
|
||||
import { showConfirmationAlert } from '../../utils/info';
|
||||
import { events, logEvent } from '../../utils/log';
|
||||
import log, { events, logEvent } from '../../utils/log';
|
||||
import { headerHeight } from '../../containers/Header';
|
||||
import { goRoom } from '../../utils/goRoom';
|
||||
import UserPreferences from '../../lib/userPreferences';
|
||||
|
@ -97,10 +98,19 @@ class ServerDropdown extends Component {
|
|||
}).start(() => toggleServerDropdown());
|
||||
};
|
||||
|
||||
createWorkspace = async () => {
|
||||
logEvent(events.RL_CREATE_NEW_WORKSPACE);
|
||||
try {
|
||||
await Linking.openURL('https://cloud.rocket.chat/trial');
|
||||
} catch (e) {
|
||||
log(e);
|
||||
}
|
||||
};
|
||||
|
||||
navToNewServer = previousServer => {
|
||||
const { appStart, initAdd } = this.props;
|
||||
batch(() => {
|
||||
appStart({ root: ROOT_NEW_SERVER });
|
||||
appStart({ root: ROOT_OUTSIDE });
|
||||
initAdd(previousServer);
|
||||
});
|
||||
};
|
||||
|
@ -181,7 +191,7 @@ class ServerDropdown extends Component {
|
|||
const { servers } = this.state;
|
||||
const { theme, isMasterDetail, insets } = this.props;
|
||||
const maxRows = 4;
|
||||
const initialTop = 41 + Math.min(servers.length, maxRows) * ROW_HEIGHT;
|
||||
const initialTop = 87 + Math.min(servers.length, maxRows) * ROW_HEIGHT;
|
||||
const statusBarHeight = insets?.top ?? 0;
|
||||
const heightDestination = isMasterDetail ? headerHeight + statusBarHeight : 0;
|
||||
const translateY = this.animatedValue.interpolate({
|
||||
|
@ -230,6 +240,17 @@ class ServerDropdown extends Component {
|
|||
ItemSeparatorComponent={List.Separator}
|
||||
keyboardShouldPersistTaps='always'
|
||||
/>
|
||||
<List.Separator />
|
||||
<Button
|
||||
title={I18n.t('Create_a_new_workspace')}
|
||||
type='secondary'
|
||||
onPress={this.createWorkspace}
|
||||
theme={theme}
|
||||
testID='rooms-list-header-create-workspace-button'
|
||||
style={styles.buttonCreateWorkspace}
|
||||
color={themes[theme].tintColor}
|
||||
styleText={[styles.serverHeaderAdd, { textAlign: 'center' }]}
|
||||
/>
|
||||
</Animated.View>
|
||||
</>
|
||||
);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { BackHandler, FlatList, Keyboard, RefreshControl, Text, View } from 'react-native';
|
||||
import { connect } from 'react-redux';
|
||||
import { batch, connect } from 'react-redux';
|
||||
import { dequal } from 'dequal';
|
||||
import Orientation from 'react-native-orientation-locker';
|
||||
import { Q } from '@nozbe/watermelondb';
|
||||
|
@ -19,12 +19,13 @@ import {
|
|||
roomsRequest as roomsRequestAction,
|
||||
toggleSortDropdown as toggleSortDropdownAction
|
||||
} from '../../actions/rooms';
|
||||
import { appStart as appStartAction, ROOT_OUTSIDE } from '../../actions/app';
|
||||
import debounce from '../../utils/debounce';
|
||||
import { isIOS, isTablet } from '../../utils/deviceInfo';
|
||||
import * as HeaderButton from '../../containers/HeaderButton';
|
||||
import StatusBar from '../../containers/StatusBar';
|
||||
import ActivityIndicator from '../../containers/ActivityIndicator';
|
||||
import { selectServerRequest as selectServerRequestAction } from '../../actions/server';
|
||||
import { selectServerRequest as selectServerRequestAction, serverInitAdd as serverInitAddAction } from '../../actions/server';
|
||||
import { animateNextTransition } from '../../utils/layoutAnimation';
|
||||
import { withTheme } from '../../theme';
|
||||
import { themes } from '../../constants/colors';
|
||||
|
@ -133,7 +134,8 @@ class RoomsListView extends React.Component {
|
|||
insets: PropTypes.object,
|
||||
queueSize: PropTypes.number,
|
||||
inquiryEnabled: PropTypes.bool,
|
||||
encryptionBanner: PropTypes.string
|
||||
encryptionBanner: PropTypes.string,
|
||||
initAdd: PropTypes.func
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
|
@ -763,7 +765,7 @@ class RoomsListView extends React.Component {
|
|||
};
|
||||
|
||||
handleCommands = ({ event }) => {
|
||||
const { navigation, server, isMasterDetail } = this.props;
|
||||
const { navigation, server, isMasterDetail, appStart, initAdd } = this.props;
|
||||
const { input } = event;
|
||||
if (handleCommandShowPreferences(event)) {
|
||||
navigation.navigate('SettingsView');
|
||||
|
@ -782,7 +784,10 @@ class RoomsListView extends React.Component {
|
|||
navigation.navigate('NewMessageStack');
|
||||
}
|
||||
} else if (handleCommandAddNewServer(event)) {
|
||||
navigation.navigate('NewServerView', { previousServer: server });
|
||||
batch(() => {
|
||||
appStart({ root: ROOT_OUTSIDE });
|
||||
initAdd(server);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -967,7 +972,9 @@ const mapDispatchToProps = dispatch => ({
|
|||
closeSearchHeader: () => dispatch(closeSearchHeaderAction()),
|
||||
roomsRequest: params => dispatch(roomsRequestAction(params)),
|
||||
selectServerRequest: server => dispatch(selectServerRequestAction(server)),
|
||||
closeServerDropdown: () => dispatch(closeServerDropdownAction())
|
||||
closeServerDropdown: () => dispatch(closeServerDropdownAction()),
|
||||
appStart: params => dispatch(appStartAction(params)),
|
||||
initAdd: previousServer => dispatch(serverInitAddAction(previousServer))
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(withDimensions(withTheme(withSafeAreaInsets(RoomsListView))));
|
||||
|
|
|
@ -56,5 +56,10 @@ export default StyleSheet.create({
|
|||
marginRight: 12,
|
||||
paddingVertical: 10,
|
||||
...sharedStyles.textRegular
|
||||
},
|
||||
buttonCreateWorkspace: {
|
||||
height: 46,
|
||||
justifyContent: 'center',
|
||||
marginBottom: 0
|
||||
}
|
||||
});
|
||||
|
|
|
@ -96,7 +96,6 @@ class WorkspaceView extends React.Component {
|
|||
|
||||
const mapStateToProps = state => ({
|
||||
server: state.server.server,
|
||||
adding: state.server.adding,
|
||||
Site_Name: state.settings.Site_Name,
|
||||
Site_Url: state.settings.Site_Url,
|
||||
Assets_favicon_512: state.settings.Assets_favicon_512,
|
||||
|
|
|
@ -1,10 +1,6 @@
|
|||
const data = require('../data');
|
||||
|
||||
async function navigateToWorkspace(server = data.server) {
|
||||
await waitFor(element(by.id('onboarding-view')))
|
||||
.toBeVisible()
|
||||
.withTimeout(10000);
|
||||
await element(by.id('join-workspace')).tap();
|
||||
await waitFor(element(by.id('new-server-view')))
|
||||
.toBeVisible()
|
||||
.withTimeout(60000);
|
||||
|
@ -16,9 +12,6 @@ async function navigateToWorkspace(server = data.server) {
|
|||
}
|
||||
|
||||
async function navigateToLogin(server) {
|
||||
await waitFor(element(by.id('onboarding-view')))
|
||||
.toBeVisible()
|
||||
.withTimeout(20000);
|
||||
await navigateToWorkspace(server);
|
||||
await element(by.id('workspace-view-login')).tap();
|
||||
await waitFor(element(by.id('login-view')))
|
||||
|
@ -28,9 +21,6 @@ async function navigateToLogin(server) {
|
|||
}
|
||||
|
||||
async function navigateToRegister(server) {
|
||||
await waitFor(element(by.id('onboarding-view')))
|
||||
.toBeVisible()
|
||||
.withTimeout(20000);
|
||||
await navigateToWorkspace(server);
|
||||
await element(by.id('workspace-view-register')).tap();
|
||||
await waitFor(element(by.id('register-view')))
|
||||
|
@ -70,10 +60,10 @@ async function logout() {
|
|||
.withTimeout(10000);
|
||||
await expect(element(by.text(logoutAlertMessage)).atIndex(0)).toExist();
|
||||
await element(by.text('Logout')).tap();
|
||||
await waitFor(element(by.id('onboarding-view')))
|
||||
await waitFor(element(by.id('new-server-view')))
|
||||
.toBeVisible()
|
||||
.withTimeout(10000);
|
||||
await expect(element(by.id('onboarding-view'))).toBeVisible();
|
||||
await expect(element(by.id('new-server-view'))).toBeVisible();
|
||||
}
|
||||
|
||||
async function mockMessage(message, isThread = false) {
|
||||
|
|
|
@ -5,7 +5,7 @@ const reopenAndCheckServer = async server => {
|
|||
await device.launchApp({ permissions: { notifications: 'YES' } });
|
||||
await waitFor(element(by.id('rooms-list-view')))
|
||||
.toBeVisible()
|
||||
.withTimeout(6000);
|
||||
.withTimeout(10000);
|
||||
await checkServer(server);
|
||||
};
|
||||
|
||||
|
@ -19,13 +19,21 @@ describe('Change server', () => {
|
|||
.withTimeout(10000);
|
||||
});
|
||||
|
||||
it('should login to server, add new server, close the app, open the app and show previous logged server', async () => {
|
||||
it('should open the dropdown button, have the server add button and create workspace button', async () => {
|
||||
await element(by.id('rooms-list-header-server-dropdown-button')).tap();
|
||||
await waitFor(element(by.id('rooms-list-header-server-dropdown')))
|
||||
.toBeVisible()
|
||||
.withTimeout(5000);
|
||||
await element(by.id('rooms-list-header-server-add')).tap();
|
||||
await waitFor(element(by.id('rooms-list-header-server-add')))
|
||||
.toBeVisible()
|
||||
.withTimeout(5000);
|
||||
await waitFor(element(by.id('rooms-list-header-create-workspace-button')))
|
||||
.toBeVisible()
|
||||
.withTimeout(5000);
|
||||
});
|
||||
|
||||
it('should login to server, add new server, close the app, open the app and show previous logged server', async () => {
|
||||
await element(by.id('rooms-list-header-server-add')).tap();
|
||||
await waitFor(element(by.id('new-server-view')))
|
||||
.toBeVisible()
|
||||
.withTimeout(6000);
|
||||
|
|
|
@ -37,11 +37,10 @@ describe('i18n', () => {
|
|||
},
|
||||
delete: true
|
||||
});
|
||||
await waitFor(element(by.id('onboarding-view')))
|
||||
await waitFor(element(by.id('new-server-view')))
|
||||
.toBeVisible()
|
||||
.withTimeout(20000);
|
||||
await expect(element(by.id('join-workspace').and(by.label('Join a workspace')))).toBeVisible();
|
||||
await expect(element(by.id('create-workspace-button').and(by.label('Create a new workspace')))).toBeVisible();
|
||||
await expect(element(by.id('new-server-view-open').and(by.label('Join our open workspace')))).toBeVisible();
|
||||
});
|
||||
|
||||
it("OS set to unavailable language and fallback to 'en'", async () => {
|
||||
|
@ -52,11 +51,10 @@ describe('i18n', () => {
|
|||
locale: 'es-MX'
|
||||
}
|
||||
});
|
||||
await waitFor(element(by.id('onboarding-view')))
|
||||
await waitFor(element(by.id('new-server-view')))
|
||||
.toBeVisible()
|
||||
.withTimeout(20000);
|
||||
await expect(element(by.id('join-workspace').and(by.label('Join a workspace')))).toBeVisible();
|
||||
await expect(element(by.id('create-workspace-button').and(by.label('Create a new workspace')))).toBeVisible();
|
||||
await expect(element(by.id('new-server-view-open').and(by.label('Join our open workspace')))).toBeVisible();
|
||||
});
|
||||
|
||||
/**
|
||||
|
@ -71,9 +69,6 @@ describe('i18n', () => {
|
|||
// locale: "nl"
|
||||
// }
|
||||
// });
|
||||
// await waitFor(element(by.id('onboarding-view'))).toBeVisible().withTimeout(20000);
|
||||
// await expect(element(by.id('join-workspace').and(by.label('Word lid van een werkruimte')))).toBeVisible();
|
||||
// await expect(element(by.id('create-workspace-button').and(by.label('Een nieuwe werkruimte aanmaken')))).toBeVisible();
|
||||
// });
|
||||
});
|
||||
|
||||
|
|
|
@ -3,22 +3,18 @@ const data = require('../../data');
|
|||
describe('Onboarding', () => {
|
||||
before(async () => {
|
||||
await device.launchApp({ permissions: { notifications: 'YES' }, delete: true });
|
||||
await waitFor(element(by.id('onboarding-view')))
|
||||
await waitFor(element(by.id('new-server-view')))
|
||||
.toBeVisible()
|
||||
.withTimeout(20000);
|
||||
});
|
||||
|
||||
describe('Render', () => {
|
||||
it('should have onboarding screen', async () => {
|
||||
await expect(element(by.id('onboarding-view'))).toBeVisible();
|
||||
await expect(element(by.id('new-server-view'))).toBeVisible();
|
||||
});
|
||||
|
||||
it('should have "Join a workspace"', async () => {
|
||||
await expect(element(by.id('join-workspace'))).toBeVisible();
|
||||
});
|
||||
|
||||
it('should have "Create a new workspace"', async () => {
|
||||
await expect(element(by.id('create-workspace-button'))).toBeVisible();
|
||||
it('should have "Join our open workspace"', async () => {
|
||||
await expect(element(by.id('new-server-view-open'))).toBeVisible();
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -27,13 +23,6 @@ describe('Onboarding', () => {
|
|||
// // webviews are not supported by detox: https://github.com/wix/detox/issues/136#issuecomment-306591554
|
||||
// });
|
||||
|
||||
it('should navigate to join a workspace', async () => {
|
||||
await element(by.id('join-workspace')).tap();
|
||||
await waitFor(element(by.id('new-server-view')))
|
||||
.toBeVisible()
|
||||
.withTimeout(60000);
|
||||
});
|
||||
|
||||
it('should enter an invalid server and get error', async () => {
|
||||
await element(by.id('new-server-view-input')).typeText('invalidtest\n');
|
||||
const errorText = 'Oops!';
|
||||
|
@ -52,13 +41,9 @@ describe('Onboarding', () => {
|
|||
|
||||
it('should enter a valid server without login services and navigate to login', async () => {
|
||||
await device.launchApp({ newInstance: true });
|
||||
await waitFor(element(by.id('onboarding-view')))
|
||||
.toBeVisible()
|
||||
.withTimeout(2000);
|
||||
await element(by.id('join-workspace')).tap();
|
||||
await waitFor(element(by.id('new-server-view')))
|
||||
.toBeVisible()
|
||||
.withTimeout(60000);
|
||||
.withTimeout(5000);
|
||||
await element(by.id('new-server-view-input')).typeText(`${data.server}\n`);
|
||||
await waitFor(element(by.id('workspace-view')))
|
||||
.toBeVisible()
|
||||
|
|
Loading…
Reference in New Issue