Chore: Migrate NewServerView to Typescript (#3431)
* Chore: Migrate NewServerView to Typescript * fix one alert lgtm * Item.tsx * export interface and try to rewrite write instead action * minor tweak * minor tweak * refactor: change the type of username to connectServer * refactor scaling * minor tweak Co-authored-by: AlexAlexandre <alexalexandrejr@gmail.com>
This commit is contained in:
parent
744893fa31
commit
27db881962
|
@ -1,5 +1,5 @@
|
|||
import React from 'react';
|
||||
import { ScrollView, StyleSheet, View } from 'react-native';
|
||||
import { ScrollView, ScrollViewProps, StyleSheet, View } from 'react-native';
|
||||
|
||||
import { themes } from '../constants/colors';
|
||||
import sharedStyles from '../views/Styles';
|
||||
|
@ -10,10 +10,10 @@ import AppVersion from './AppVersion';
|
|||
import { isTablet } from '../utils/deviceInfo';
|
||||
import SafeAreaView from './SafeAreaView';
|
||||
|
||||
interface IFormContainer {
|
||||
interface IFormContainer extends ScrollViewProps {
|
||||
theme: string;
|
||||
testID: string;
|
||||
children: JSX.Element;
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
import { isTablet } from './deviceInfo';
|
||||
|
||||
const guidelineBaseWidth = isTablet ? 600 : 375;
|
||||
const guidelineBaseHeight = isTablet ? 800 : 667;
|
||||
|
||||
// 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 };
|
|
@ -0,0 +1,16 @@
|
|||
import { isTablet } from './deviceInfo';
|
||||
|
||||
const guidelineBaseWidth = isTablet ? 600 : 375;
|
||||
const guidelineBaseHeight = isTablet ? 800 : 667;
|
||||
|
||||
function scale({ size, width }: { size: number; width: number }): number {
|
||||
return (width / guidelineBaseWidth) * size;
|
||||
}
|
||||
function verticalScale({ size, height }: { size: number; height: number }): number {
|
||||
return (height / guidelineBaseHeight) * size;
|
||||
}
|
||||
function moderateScale({ size, factor = 0.5, width }: { size: number; factor?: number; width: number }): number {
|
||||
return size + (scale({ size, width }) - size) * factor;
|
||||
}
|
||||
|
||||
export { scale, verticalScale, moderateScale };
|
|
@ -1,12 +1,12 @@
|
|||
import React from 'react';
|
||||
import { StyleSheet, Text, View } from 'react-native';
|
||||
import PropTypes from 'prop-types';
|
||||
import { BorderlessButton } from 'react-native-gesture-handler';
|
||||
|
||||
import { themes } from '../../../constants/colors';
|
||||
import { CustomIcon } from '../../../lib/Icons';
|
||||
import sharedStyles from '../../Styles';
|
||||
import Touch from '../../../utils/touch';
|
||||
import { IServer } from '../index';
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
|
@ -27,13 +27,20 @@ const styles = StyleSheet.create({
|
|||
}
|
||||
});
|
||||
|
||||
const Item = ({ item, theme, onPress, onDelete }) => (
|
||||
interface IItem {
|
||||
item: IServer;
|
||||
theme: string;
|
||||
onPress(url: string): void;
|
||||
onDelete(item: IServer): void;
|
||||
}
|
||||
|
||||
const Item = ({ item, theme, onPress, onDelete }: IItem): JSX.Element => (
|
||||
<Touch style={styles.container} onPress={() => onPress(item.url)} theme={theme} testID={`server-history-${item.url}`}>
|
||||
<View style={styles.content}>
|
||||
<Text numberOfLines={1} style={[styles.server, { color: themes[theme].bodyText }]}>
|
||||
{item.url}
|
||||
</Text>
|
||||
<Text numberOfLines={1} style={[styles.username, { color: themes[theme].auxiliaryText }]}>
|
||||
<Text numberOfLines={1} style={{ color: themes[theme].auxiliaryText }}>
|
||||
{item.username}
|
||||
</Text>
|
||||
</View>
|
||||
|
@ -43,11 +50,4 @@ const Item = ({ item, theme, onPress, onDelete }) => (
|
|||
</Touch>
|
||||
);
|
||||
|
||||
Item.propTypes = {
|
||||
item: PropTypes.object,
|
||||
theme: PropTypes.string,
|
||||
onPress: PropTypes.func,
|
||||
onDelete: PropTypes.func
|
||||
};
|
||||
|
||||
export default Item;
|
|
@ -1,12 +1,12 @@
|
|||
import React, { useState } from 'react';
|
||||
import { FlatList, StyleSheet, View } from 'react-native';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import TextInput from '../../../containers/TextInput';
|
||||
import * as List from '../../../containers/List';
|
||||
import { themes } from '../../../constants/colors';
|
||||
import I18n from '../../../i18n';
|
||||
import Item from './Item';
|
||||
import { IServer } from '../index';
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
|
@ -28,7 +28,25 @@ const styles = StyleSheet.create({
|
|||
}
|
||||
});
|
||||
|
||||
const ServerInput = ({ text, theme, serversHistory, onChangeText, onSubmit, onDelete, onPressServerHistory }) => {
|
||||
interface IServerInput {
|
||||
text: string;
|
||||
theme: string;
|
||||
serversHistory: any[];
|
||||
onChangeText(text: string): void;
|
||||
onSubmit(): void;
|
||||
onDelete(item: IServer): void;
|
||||
onPressServerHistory(serverHistory: IServer): void;
|
||||
}
|
||||
|
||||
const ServerInput = ({
|
||||
text,
|
||||
theme,
|
||||
serversHistory,
|
||||
onChangeText,
|
||||
onSubmit,
|
||||
onDelete,
|
||||
onPressServerHistory
|
||||
}: IServerInput): JSX.Element => {
|
||||
const [focused, setFocused] = useState(false);
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
|
@ -68,14 +86,4 @@ const ServerInput = ({ text, theme, serversHistory, onChangeText, onSubmit, onDe
|
|||
);
|
||||
};
|
||||
|
||||
ServerInput.propTypes = {
|
||||
text: PropTypes.string,
|
||||
theme: PropTypes.string,
|
||||
serversHistory: PropTypes.array,
|
||||
onChangeText: PropTypes.func,
|
||||
onSubmit: PropTypes.func,
|
||||
onDelete: PropTypes.func,
|
||||
onPressServerHistory: PropTypes.func
|
||||
};
|
||||
|
||||
export default ServerInput;
|
|
@ -1,5 +1,4 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Text, Keyboard, StyleSheet, View, BackHandler, Image } from 'react-native';
|
||||
import { connect } from 'react-redux';
|
||||
import { Base64 } from 'js-base64';
|
||||
|
@ -7,6 +6,9 @@ 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 { StackNavigationProp } from '@react-navigation/stack';
|
||||
import { Dispatch } from 'redux';
|
||||
import Model from '@nozbe/watermelondb/Model';
|
||||
|
||||
import UserPreferences from '../../lib/userPreferences';
|
||||
import EventEmitter from '../../utils/events';
|
||||
|
@ -19,7 +21,6 @@ import FormContainer, { FormContainerInner } from '../../containers/FormContaine
|
|||
import I18n from '../../i18n';
|
||||
import { themes } from '../../constants/colors';
|
||||
import { events, logEvent } from '../../utils/log';
|
||||
import { animateNextTransition } from '../../utils/layoutAnimation';
|
||||
import { withTheme } from '../../theme';
|
||||
import { BASIC_AUTH_KEY, setBasicAuth } from '../../utils/fetch';
|
||||
import * as HeaderButton from '../../containers/HeaderButton';
|
||||
|
@ -66,19 +67,32 @@ const styles = StyleSheet.create({
|
|||
}
|
||||
});
|
||||
|
||||
class NewServerView extends React.Component {
|
||||
static propTypes = {
|
||||
navigation: PropTypes.object,
|
||||
theme: PropTypes.string,
|
||||
connecting: PropTypes.bool.isRequired,
|
||||
connectServer: PropTypes.func.isRequired,
|
||||
selectServer: PropTypes.func.isRequired,
|
||||
previousServer: PropTypes.string,
|
||||
inviteLinksClear: PropTypes.func,
|
||||
serverFinishAdd: PropTypes.func
|
||||
};
|
||||
export interface IServer extends Model {
|
||||
url: string;
|
||||
username: string;
|
||||
}
|
||||
interface INewServerView {
|
||||
navigation: StackNavigationProp<any, 'NewServerView'>;
|
||||
theme: string;
|
||||
connecting: boolean;
|
||||
connectServer(server: string, username?: string, fromServerHistory?: boolean): void;
|
||||
selectServer(server: string): void;
|
||||
previousServer: string;
|
||||
inviteLinksClear(): void;
|
||||
serverFinishAdd(): void;
|
||||
width: number;
|
||||
height: number;
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
interface IState {
|
||||
text: string;
|
||||
connectingOpen: boolean;
|
||||
certificate: any;
|
||||
serversHistory: IServer[];
|
||||
}
|
||||
|
||||
class NewServerView extends React.Component<INewServerView, IState> {
|
||||
constructor(props: INewServerView) {
|
||||
super(props);
|
||||
if (!isTablet) {
|
||||
Orientation.lockToPortrait();
|
||||
|
@ -131,21 +145,21 @@ class NewServerView extends React.Component {
|
|||
return false;
|
||||
};
|
||||
|
||||
onChangeText = text => {
|
||||
onChangeText = (text: string) => {
|
||||
this.setState({ text });
|
||||
this.queryServerHistory(text);
|
||||
};
|
||||
|
||||
queryServerHistory = async text => {
|
||||
queryServerHistory = async (text?: string) => {
|
||||
const db = database.servers;
|
||||
try {
|
||||
const serversHistoryCollection = db.get('servers_history');
|
||||
let whereClause = [Q.where('username', Q.notEq(null)), Q.experimentalSortBy('updated_at', Q.desc), Q.experimentalTake(3)];
|
||||
const likeString = sanitizeLikeString(text);
|
||||
if (text) {
|
||||
const likeString = sanitizeLikeString(text);
|
||||
whereClause = [...whereClause, Q.where('url', Q.like(`%${likeString}%`))];
|
||||
}
|
||||
const serversHistory = await serversHistoryCollection.query(...whereClause).fetch();
|
||||
const serversHistory = (await serversHistoryCollection.query(...whereClause).fetch()) as IServer[];
|
||||
this.setState({ serversHistory });
|
||||
} catch {
|
||||
// Do nothing
|
||||
|
@ -158,7 +172,7 @@ class NewServerView extends React.Component {
|
|||
selectServer(previousServer);
|
||||
};
|
||||
|
||||
handleNewServerEvent = event => {
|
||||
handleNewServerEvent = (event: { server: string }) => {
|
||||
let { server } = event;
|
||||
if (!server) {
|
||||
return;
|
||||
|
@ -169,13 +183,11 @@ class NewServerView extends React.Component {
|
|||
connectServer(server);
|
||||
};
|
||||
|
||||
onPressServerHistory = serverHistory => {
|
||||
this.setState({ text: serverHistory?.url }, () =>
|
||||
this.submit({ fromServerHistory: true, username: serverHistory?.username })
|
||||
);
|
||||
onPressServerHistory = (serverHistory: IServer) => {
|
||||
this.setState({ text: serverHistory.url }, () => this.submit(true, serverHistory?.username));
|
||||
};
|
||||
|
||||
submit = async ({ fromServerHistory = false, username }) => {
|
||||
submit = async (fromServerHistory?: boolean, username?: string) => {
|
||||
logEvent(events.NS_CONNECT_TO_WORKSPACE);
|
||||
const { text, certificate } = this.state;
|
||||
const { connectServer } = this.props;
|
||||
|
@ -207,7 +219,7 @@ class NewServerView extends React.Component {
|
|||
connectServer('https://open.rocket.chat');
|
||||
};
|
||||
|
||||
basicAuth = async (server, text) => {
|
||||
basicAuth = async (server: string, text: string) => {
|
||||
try {
|
||||
const parsedUrl = parse(text, true);
|
||||
if (parsedUrl.auth.length) {
|
||||
|
@ -222,14 +234,14 @@ class NewServerView extends React.Component {
|
|||
|
||||
chooseCertificate = async () => {
|
||||
try {
|
||||
const certificate = await SSLPinning.pickCertificate();
|
||||
const certificate = await SSLPinning?.pickCertificate();
|
||||
this.setState({ certificate });
|
||||
} catch {
|
||||
// Do nothing
|
||||
}
|
||||
};
|
||||
|
||||
completeUrl = url => {
|
||||
completeUrl = (url: string) => {
|
||||
const parsedUrl = parse(url, true);
|
||||
if (parsedUrl.auth.length) {
|
||||
url = parsedUrl.origin;
|
||||
|
@ -252,14 +264,11 @@ class NewServerView extends React.Component {
|
|||
return url.replace(/\/+$/, '').replace(/\\/g, '/');
|
||||
};
|
||||
|
||||
uriToPath = uri => uri.replace('file://', '');
|
||||
|
||||
saveCertificate = certificate => {
|
||||
animateNextTransition();
|
||||
this.setState({ certificate });
|
||||
};
|
||||
uriToPath = (uri: string) => uri.replace('file://', '');
|
||||
|
||||
handleRemove = () => {
|
||||
// TODO: Remove ts-ignore when migrate the showConfirmationAlert
|
||||
// @ts-ignore
|
||||
showConfirmationAlert({
|
||||
message: I18n.t('You_will_unset_a_certificate_for_this_server'),
|
||||
confirmationText: I18n.t('Remove'),
|
||||
|
@ -267,14 +276,15 @@ class NewServerView extends React.Component {
|
|||
});
|
||||
};
|
||||
|
||||
deleteServerHistory = async item => {
|
||||
const { serversHistory } = this.state;
|
||||
deleteServerHistory = async (item: IServer) => {
|
||||
const db = database.servers;
|
||||
try {
|
||||
await db.action(async () => {
|
||||
await db.write(async () => {
|
||||
await item.destroyPermanently();
|
||||
});
|
||||
this.setState({ serversHistory: serversHistory.filter(server => server.id !== item.id) });
|
||||
this.setState((prevstate: IState) => ({
|
||||
serversHistory: prevstate.serversHistory.filter((server: IServer) => server.id !== item.id)
|
||||
}));
|
||||
} catch {
|
||||
// Nothing
|
||||
}
|
||||
|
@ -288,20 +298,21 @@ class NewServerView extends React.Component {
|
|||
style={[
|
||||
styles.certificatePicker,
|
||||
{
|
||||
marginBottom: verticalScale(previousServer && !isTablet ? 10 : 30, height)
|
||||
marginBottom: verticalScale({ size: previousServer && !isTablet ? 10 : 30, height })
|
||||
}
|
||||
]}>
|
||||
<Text
|
||||
style={[
|
||||
styles.chooseCertificateTitle,
|
||||
{ color: themes[theme].auxiliaryText, fontSize: moderateScale(13, null, width) }
|
||||
{ color: themes[theme].auxiliaryText, fontSize: moderateScale({ size: 13, 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, fontSize: moderateScale(13, null, width) }]}>
|
||||
<Text
|
||||
style={[styles.chooseCertificate, { color: themes[theme].tintColor, fontSize: moderateScale({ size: 13, width }) }]}>
|
||||
{certificate ?? I18n.t('Apply_Your_Certificate')}
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
|
@ -321,10 +332,10 @@ class NewServerView extends React.Component {
|
|||
style={[
|
||||
styles.onboardingImage,
|
||||
{
|
||||
marginBottom: verticalScale(10, height),
|
||||
marginTop: isTablet ? 0 : verticalScale(marginTop, height),
|
||||
width: verticalScale(100, height),
|
||||
height: verticalScale(100, height)
|
||||
marginBottom: verticalScale({ size: 10, height }),
|
||||
marginTop: isTablet ? 0 : verticalScale({ size: marginTop, height }),
|
||||
width: verticalScale({ size: 100, height }),
|
||||
height: verticalScale({ size: 100, height })
|
||||
}
|
||||
]}
|
||||
source={require('../../static/images/logo.png')}
|
||||
|
@ -335,8 +346,8 @@ class NewServerView extends React.Component {
|
|||
styles.title,
|
||||
{
|
||||
color: themes[theme].titleText,
|
||||
fontSize: moderateScale(22, null, width),
|
||||
marginBottom: verticalScale(8, height)
|
||||
fontSize: moderateScale({ size: 22, width }),
|
||||
marginBottom: verticalScale({ size: 8, height })
|
||||
}
|
||||
]}>
|
||||
Rocket.Chat
|
||||
|
@ -346,8 +357,8 @@ class NewServerView extends React.Component {
|
|||
styles.subtitle,
|
||||
{
|
||||
color: themes[theme].controlText,
|
||||
fontSize: moderateScale(16, null, width),
|
||||
marginBottom: verticalScale(30, height)
|
||||
fontSize: moderateScale({ size: 16, width }),
|
||||
marginBottom: verticalScale({ size: 30, height })
|
||||
}
|
||||
]}>
|
||||
{I18n.t('Onboarding_subtitle')}
|
||||
|
@ -367,7 +378,7 @@ class NewServerView extends React.Component {
|
|||
onPress={this.submit}
|
||||
disabled={!text || connecting}
|
||||
loading={!connectingOpen && connecting}
|
||||
style={[styles.connectButton, { marginTop: verticalScale(16, height) }]}
|
||||
style={[styles.connectButton, { marginTop: verticalScale({ size: 16, height }) }]}
|
||||
theme={theme}
|
||||
testID='new-server-view-button'
|
||||
/>
|
||||
|
@ -377,8 +388,8 @@ class NewServerView extends React.Component {
|
|||
styles.description,
|
||||
{
|
||||
color: themes[theme].auxiliaryText,
|
||||
fontSize: moderateScale(14, null, width),
|
||||
marginBottom: verticalScale(16, height)
|
||||
fontSize: moderateScale({ size: 14, width }),
|
||||
marginBottom: verticalScale({ size: 16, height })
|
||||
}
|
||||
]}>
|
||||
{I18n.t('Onboarding_join_open_description')}
|
||||
|
@ -400,14 +411,15 @@ class NewServerView extends React.Component {
|
|||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
const mapStateToProps = (state: any) => ({
|
||||
connecting: state.server.connecting,
|
||||
previousServer: state.server.previousServer
|
||||
});
|
||||
|
||||
const mapDispatchToProps = dispatch => ({
|
||||
connectServer: (...params) => dispatch(serverRequest(...params)),
|
||||
selectServer: server => dispatch(selectServerRequest(server)),
|
||||
const mapDispatchToProps = (dispatch: Dispatch) => ({
|
||||
connectServer: (server: string, username: string & null, fromServerHistory?: boolean) =>
|
||||
dispatch(serverRequest(server, username, fromServerHistory)),
|
||||
selectServer: (server: string) => dispatch(selectServerRequest(server)),
|
||||
inviteLinksClear: () => dispatch(inviteLinksClearAction()),
|
||||
serverFinishAdd: () => dispatch(serverFinishAddAction())
|
||||
});
|
Loading…
Reference in New Issue