Validating URL whena adding new server. Closes #17

This commit is contained in:
Rodrigo Nascimento 2017-08-11 12:47:18 -03:00
parent 328b7be226
commit 0b702dc4ca
2 changed files with 160 additions and 14 deletions

View File

@ -1,6 +1,7 @@
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { TextInput, StyleSheet } from 'react-native'; import { Text, TextInput, View, StyleSheet } from 'react-native';
import _ from 'underscore';
import RocketChat from '../lib/rocketchat'; import RocketChat from '../lib/rocketchat';
@ -10,7 +11,6 @@ const styles = StyleSheet.create({
view: { view: {
flex: 1, flex: 1,
flexDirection: 'column', flexDirection: 'column',
justifyContent: 'center',
alignItems: 'stretch' alignItems: 'stretch'
}, },
input: { input: {
@ -24,6 +24,26 @@ const styles = StyleSheet.create({
text: { text: {
textAlign: 'center', textAlign: 'center',
color: '#888' color: '#888'
},
validateText: {
position: 'absolute',
color: 'green',
textAlign: 'center',
paddingLeft: 50,
paddingRight: 50,
width: '100%'
},
validText: {
color: 'green'
},
invalidText: {
color: 'red'
},
validatingText: {
color: '#aaa'
},
spaceView: {
flexGrow: 1
} }
}); });
@ -40,6 +60,7 @@ export default class NewServerView extends React.Component {
super(props); super(props);
this.state = { this.state = {
defaultServer: 'https://demo.rocket.chat', defaultServer: 'https://demo.rocket.chat',
editable: true,
text: '' text: ''
}; };
@ -47,36 +68,160 @@ export default class NewServerView extends React.Component {
let url = this.state.text.trim(); let url = this.state.text.trim();
if (!url) { if (!url) {
url = this.state.defaultServer; url = this.state.defaultServer;
} else {
url = this.completeUrl(this.state.text);
} }
// TODO: validate URL this.setState({
if (url.indexOf('.') === -1) { editable: false
url = `https://${ url }.rocket.chat`; });
}
if (/^https?:\/\//.test(url) === false) { this.inputElement.blur();
this.validateServer(url).then(() => {
RocketChat.currentServer = url;
this.props.navigation.dispatch({ type: 'Navigation/BACK' });
}).catch(() => {
this.setState({
editable: true
});
this.inputElement.focus();
});
};
}
componentDidMount() {
this._mounted = true;
}
componentWillUnmount() {
this._mounted = false;
}
onChangeText = (text) => {
this.setState({ text });
this.validateServerDebounced(text);
}
validateServer = url => new Promise((resolve, reject) => {
url = this.completeUrl(url);
this.setState({
validating: false,
url
});
if (/^(https?:\/\/)?(((\w|[0-9])+(\.(\w|[0-9-_])+)+)|localhost)(:\d+)?$/.test(url)) {
this.setState({
validating: true
});
const a = fetch(url, { method: 'HEAD' })
.then((response) => {
if (!this._mounted) {
return;
}
if (response.status === 200 && response.headers.get('x-instance-id') != null && response.headers.get('x-instance-id').length) {
this.setState({
validInstance: true,
validating: false
});
resolve(url);
} else {
this.setState({
validInstance: false,
validating: false
});
reject(url);
}
})
.catch(() => {
if (!this._mounted) {
return;
}
this.setState({
validInstance: false,
validating: false
});
reject(url);
});
console.log(a.stop);
} else {
this.setState({
validInstance: undefined
});
reject(url);
}
})
validateServerDebounced = _.debounce(this.validateServer, 1000)
completeUrl = (url) => {
url = url.trim();
if (/^(\w|[0-9-_]){3,}$/.test(url) && /^(htt(ps?)?)|(loca((l)?|(lh)?|(lho)?|(lhos)?|(lhost:?\d*)?)$)/.test(url) === false) {
url = `${ url }.rocket.chat`;
}
if (/^(https?:\/\/)?(((\w|[0-9])+(\.(\w|[0-9-_])+)+)|localhost)(:\d+)?$/.test(url)) {
if (/^localhost(:\d+)?/.test(url)) {
url = `http://${ url }`;
} else if (/^https?:\/\//.test(url) === false) {
url = `https://${ url }`; url = `https://${ url }`;
} }
}
RocketChat.currentServer = url; url = url.replace(/\/+$/, '');
this.props.navigation.dispatch({ type: 'Navigation/BACK' });
}; return url;
}
renderValidation = () => {
if (this.state.validating) {
return (
<Text style={[styles.validateText, styles.validatingText]}>
Validating {this.state.url} ...
</Text>
);
}
if (this.state.validInstance) {
return (
<Text style={[styles.validateText, styles.validText]}>
{this.state.url} is a valid Rocket.Chat instance
</Text>
);
}
if (this.state.validInstance === false) {
return (
<Text style={[styles.validateText, styles.invalidText]}>
{this.state.url} is not a valid Rocket.Chat instance
</Text>
);
}
} }
render() { render() {
return ( return (
<KeyboardView style={styles.view}> <KeyboardView style={styles.view} keyboardVerticalOffset={64}>
<View style={styles.spaceView} />
<TextInput <TextInput
ref={ref => this.inputElement = ref}
style={styles.input} style={styles.input}
onChangeText={text => this.setState({ text })} onChangeText={this.onChangeText}
keyboardType='url' keyboardType='url'
autoCorrect={false} autoCorrect={false}
returnKeyType='done' returnKeyType='done'
autoCapitalize='none' autoCapitalize='none'
autoFocus autoFocus
editable={this.state.editable}
onSubmitEditing={this.submit} onSubmitEditing={this.submit}
placeholder={this.state.defaultServer} placeholder={this.state.defaultServer}
/> />
<View style={styles.spaceView}>
{this.renderValidation()}
</View>
</KeyboardView> </KeyboardView>
); );
} }

View File

@ -18,8 +18,8 @@
"react-native-action-button": "^2.7.2", "react-native-action-button": "^2.7.2",
"react-native-easy-markdown": "git+https://github.com/lappalj4/react-native-easy-markdown.git", "react-native-easy-markdown": "git+https://github.com/lappalj4/react-native-easy-markdown.git",
"react-native-fetch-blob": "^0.10.8", "react-native-fetch-blob": "^0.10.8",
"react-native-image-picker": "^0.26.3",
"react-native-form-generator": "^0.9.9", "react-native-form-generator": "^0.9.9",
"react-native-image-picker": "^0.26.3",
"react-native-img-cache": "^1.4.0", "react-native-img-cache": "^1.4.0",
"react-native-meteor": "^1.1.0", "react-native-meteor": "^1.1.0",
"react-native-svg": "^5.4.1", "react-native-svg": "^5.4.1",
@ -28,7 +28,8 @@
"react-native-zeroconf": "^0.8.1", "react-native-zeroconf": "^0.8.1",
"react-navigation": "^1.0.0-beta.11", "react-navigation": "^1.0.0-beta.11",
"realm": "^1.10.1", "realm": "^1.10.1",
"strip-ansi": "^4.0.0" "strip-ansi": "^4.0.0",
"underscore": "^1.8.3"
}, },
"devDependencies": { "devDependencies": {
"babel-eslint": "^7.2.3", "babel-eslint": "^7.2.3",