From 68a8bf942d0b32aec6140ec0f92c3f2981ddcfb4 Mon Sep 17 00:00:00 2001 From: GleidsonDaniel Date: Mon, 17 Jan 2022 18:27:28 -0300 Subject: [PATCH] chore: migrate redux module inviteUsers to typescript --- app/actions/inviteLinks.js | 54 ---------- app/actions/inviteLinks.ts | 61 +++++++++++ app/actions/server.js | 5 +- app/definitions/index.ts | 1 + app/definitions/redux/index.ts | 8 +- app/reducers/inviteLinks.test.ts | 72 +++++++++++++ .../{inviteLinks.js => inviteLinks.ts} | 20 ++-- app/views/InviteUsersEditView/index.tsx | 48 +++------ app/views/InviteUsersView/index.tsx | 66 ++++-------- app/views/NewServerView/index.tsx | 100 ++++++++---------- 10 files changed, 238 insertions(+), 197 deletions(-) delete mode 100644 app/actions/inviteLinks.js create mode 100644 app/actions/inviteLinks.ts create mode 100644 app/reducers/inviteLinks.test.ts rename app/reducers/{inviteLinks.js => inviteLinks.ts} (53%) diff --git a/app/actions/inviteLinks.js b/app/actions/inviteLinks.js deleted file mode 100644 index cd2fd1639..000000000 --- a/app/actions/inviteLinks.js +++ /dev/null @@ -1,54 +0,0 @@ -import * as types from './actionsTypes'; - -export function inviteLinksSetToken(token) { - return { - type: types.INVITE_LINKS.SET_TOKEN, - token - }; -} - -export function inviteLinksRequest(token) { - return { - type: types.INVITE_LINKS.REQUEST, - token - }; -} - -export function inviteLinksSuccess() { - return { - type: types.INVITE_LINKS.SUCCESS - }; -} - -export function inviteLinksFailure() { - return { - type: types.INVITE_LINKS.FAILURE - }; -} - -export function inviteLinksClear() { - return { - type: types.INVITE_LINKS.CLEAR - }; -} - -export function inviteLinksCreate(rid) { - return { - type: types.INVITE_LINKS.CREATE, - rid - }; -} - -export function inviteLinksSetParams(params) { - return { - type: types.INVITE_LINKS.SET_PARAMS, - params - }; -} - -export function inviteLinksSetInvite(invite) { - return { - type: types.INVITE_LINKS.SET_INVITE, - invite - }; -} diff --git a/app/actions/inviteLinks.ts b/app/actions/inviteLinks.ts new file mode 100644 index 000000000..3f32865d9 --- /dev/null +++ b/app/actions/inviteLinks.ts @@ -0,0 +1,61 @@ +import { Action } from 'redux'; + +import { TInvite } from '../reducers/inviteLinks'; +import { INVITE_LINKS } from './actionsTypes'; + +interface IInviteLinksGeneric extends Action { + token: string; +} + +interface IInviteLinksCreate extends Action { + rid: string; +} + +interface IInviteLinksSetInvite extends Action { + invite: TInvite; +} + +type TParams = Record; + +interface IInviteLinksSetParams extends Action { + params: TParams; +} + +export type TActionInviteLinks = IInviteLinksGeneric & IInviteLinksCreate & IInviteLinksSetInvite & IInviteLinksSetParams; + +export const inviteLinksSetToken = (token: string): IInviteLinksGeneric => ({ + type: INVITE_LINKS.SET_TOKEN, + token +}); + +export const inviteLinksRequest = (token: string): IInviteLinksGeneric => ({ + type: INVITE_LINKS.REQUEST, + token +}); + +export const inviteLinksSuccess = (): Action => ({ + type: INVITE_LINKS.SUCCESS +}); + +export const inviteLinksFailure = (): Action => ({ + type: INVITE_LINKS.FAILURE +}); + +export const inviteLinksClear = (): Action => ({ + type: INVITE_LINKS.CLEAR +}); + +export const inviteLinksCreate = (rid: string): IInviteLinksCreate => ({ + type: INVITE_LINKS.CREATE, + rid +}); + +export const inviteLinksSetParams = (params: TParams): IInviteLinksSetParams => ({ + type: INVITE_LINKS.SET_PARAMS, + params +}); + +export const inviteLinksSetInvite = (invite: TInvite): IInviteLinksSetInvite => ({ + type: INVITE_LINKS.SET_INVITE, + invite +}); diff --git a/app/actions/server.js b/app/actions/server.js index fea239450..acc7c7cb3 100644 --- a/app/actions/server.js +++ b/app/actions/server.js @@ -24,11 +24,12 @@ export function selectServerFailure() { }; } -export function serverRequest(server, username = null, fromServerHistory = false) { +// TODO +export function serverRequest(server, username, fromServerHistory = false) { return { type: SERVER.REQUEST, server, - username, + username: username || null, fromServerHistory }; } diff --git a/app/definitions/index.ts b/app/definitions/index.ts index 80eeb88ca..8db731d92 100644 --- a/app/definitions/index.ts +++ b/app/definitions/index.ts @@ -8,6 +8,7 @@ export * from './INotification'; export * from './IRoom'; export * from './IServer'; export * from './ISubscription'; +export * from './IServerHistory'; export interface IBaseScreen, S extends string> { navigation: StackNavigationProp; diff --git a/app/definitions/redux/index.ts b/app/definitions/redux/index.ts index e95763e29..d873271e3 100644 --- a/app/definitions/redux/index.ts +++ b/app/definitions/redux/index.ts @@ -1,7 +1,9 @@ -import { TActionSelectedUsers } from '../../actions/selectedUsers'; import { TActionActiveUsers } from '../../actions/activeUsers'; +import { TActionInviteLinks } from '../../actions/inviteLinks'; +import { TActionSelectedUsers } from '../../actions/selectedUsers'; // REDUCERS import { IActiveUsers } from '../../reducers/activeUsers'; +import { IInviteLinks } from '../../reducers/inviteLinks'; import { ISelectedUsers } from '../../reducers/selectedUsers'; export interface IApplicationState { @@ -19,7 +21,7 @@ export interface IApplicationState { customEmojis: any; activeUsers: IActiveUsers; usersTyping: any; - inviteLinks: any; + inviteLinks: IInviteLinks; createDiscussion: any; inquiry: any; enterpriseModules: any; @@ -28,4 +30,4 @@ export interface IApplicationState { roles: any; } -export type TApplicationActions = TActionActiveUsers & TActionSelectedUsers; +export type TApplicationActions = TActionActiveUsers & TActionSelectedUsers & TActionInviteLinks; diff --git a/app/reducers/inviteLinks.test.ts b/app/reducers/inviteLinks.test.ts new file mode 100644 index 000000000..ed1a34a46 --- /dev/null +++ b/app/reducers/inviteLinks.test.ts @@ -0,0 +1,72 @@ +import { + inviteLinksClear, + inviteLinksFailure, + inviteLinksRequest, + inviteLinksSetInvite, + inviteLinksSetParams, + inviteLinksSetToken, + inviteLinksSuccess +} from '../actions/inviteLinks'; +import { initialState } from './inviteLinks'; +import { mockedStore } from './mockedStore'; + +describe('test roles reducer', () => { + const invite = { + _id: 'nZestg', + days: 1, + maxUses: 0, + createdAt: '2022-01-17T20:32:44.695Z', + expires: '2022-01-18T20:32:44.695Z', + uses: 0, + _updatedAt: '2022-01-17T20:32:44.695Z', + url: 'https://go.rocket.chat/invite?host=open.rocket.chat&path=invite%2FnZestg', + success: true, + token: '' + }; + it('should return initial state', () => { + const state = mockedStore.getState().inviteLinks; + expect(state).toEqual(initialState); + }); + + it('should return initialState after call inviteLinksFailure', () => { + mockedStore.dispatch(inviteLinksFailure()); + const state = mockedStore.getState().inviteLinks; + expect(state).toEqual(initialState); + }); + + it('should return initialState after call inviteLinksSuccess', () => { + mockedStore.dispatch(inviteLinksSuccess()); + const state = mockedStore.getState().inviteLinks; + expect(state).toEqual(initialState); + }); + + it('should return correctly token after call inviteLinksSetToken', () => { + mockedStore.dispatch(inviteLinksSetToken('xxx')); + const { token } = mockedStore.getState().inviteLinks; + expect(token).toEqual('xxx'); + }); + + it('should return correctly invite value after call inviteLinksSetInvite', () => { + mockedStore.dispatch(inviteLinksSetInvite(invite)); + const state = mockedStore.getState().inviteLinks; + expect(state.invite).toEqual(invite); + }); + + it('should return modified store after call inviteLinksSetParams', () => { + mockedStore.dispatch(inviteLinksSetParams({ token: 'nZestg' })); + const { token } = mockedStore.getState().inviteLinks; + expect(token).toEqual('nZestg'); + }); + + it('should return initialState after call inviteLinksClear', () => { + mockedStore.dispatch(inviteLinksClear()); + const state = mockedStore.getState().inviteLinks; + expect(state).toEqual(initialState); + }); + + it('should return actual state after call inviteLinksRequest', () => { + mockedStore.dispatch(inviteLinksRequest('xxx')); + const state = mockedStore.getState().inviteLinks; + expect(state).toEqual(initialState); + }); +}); diff --git a/app/reducers/inviteLinks.js b/app/reducers/inviteLinks.ts similarity index 53% rename from app/reducers/inviteLinks.js rename to app/reducers/inviteLinks.ts index 2126c4896..9ccd36e76 100644 --- a/app/reducers/inviteLinks.js +++ b/app/reducers/inviteLinks.ts @@ -1,18 +1,26 @@ +import { TActionInviteLinks } from '../actions/inviteLinks'; import { INVITE_LINKS } from '../actions/actionsTypes'; -const initialState = { +export type TInvite = { url: string; expires: string; maxUses: number; uses: number; [x: string]: any }; + +export interface IInviteLinks { + token: string; + days: number; + maxUses: number; + invite: TInvite; +} + +export const initialState: IInviteLinks = { token: '', days: 1, maxUses: 0, - invite: {} + invite: { url: '', expires: '', maxUses: 0, uses: 0 } }; -export default (state = initialState, action) => { +export default (state = initialState, action: TActionInviteLinks): IInviteLinks => { switch (action.type) { case INVITE_LINKS.SET_TOKEN: - return { - token: action.token - }; + return { ...state, token: action.token }; case INVITE_LINKS.SET_PARAMS: return { ...state, diff --git a/app/views/InviteUsersEditView/index.tsx b/app/views/InviteUsersEditView/index.tsx index 4ae1a67df..10f356ae3 100644 --- a/app/views/InviteUsersEditView/index.tsx +++ b/app/views/InviteUsersEditView/index.tsx @@ -1,25 +1,21 @@ +import { StackNavigationOptions } from '@react-navigation/stack'; import React from 'react'; import { TextInputProps, View } from 'react-native'; -import { connect } from 'react-redux'; import RNPickerSelect from 'react-native-picker-select'; -import { StackNavigationOptions, StackNavigationProp } from '@react-navigation/stack'; -import { RouteProp } from '@react-navigation/core'; -import { Dispatch } from 'redux'; +import { connect } from 'react-redux'; -import { - inviteLinksCreate as inviteLinksCreateAction, - inviteLinksSetParams as inviteLinksSetParamsAction -} from '../../actions/inviteLinks'; -import * as List from '../../containers/List'; -import Button from '../../containers/Button'; -import I18n from '../../i18n'; -import StatusBar from '../../containers/StatusBar'; +import { inviteLinksCreate, inviteLinksSetParams } from '../../actions/inviteLinks'; import { themes } from '../../constants/colors'; -import { withTheme } from '../../theme'; +import Button from '../../containers/Button'; +import * as List from '../../containers/List'; import SafeAreaView from '../../containers/SafeAreaView'; +import StatusBar from '../../containers/StatusBar'; +import { IApplicationState, IBaseScreen } from '../../definitions'; +import I18n from '../../i18n'; +import { ChatsStackParamList } from '../../stacks/types'; +import { withTheme } from '../../theme'; import { events, logEvent } from '../../utils/log'; import styles from './styles'; -import { ChatsStackParamList } from '../../stacks/types'; const OPTIONS = { days: [ @@ -68,12 +64,7 @@ const OPTIONS = { ] }; -interface IInviteUsersEditViewProps { - navigation: StackNavigationProp; - route: RouteProp; - theme: string; - createInviteLink(rid: string): void; - inviteLinksSetParams(params: { [key: string]: number }): void; +interface IInviteUsersEditViewProps extends IBaseScreen { days: number; maxUses: number; } @@ -91,18 +82,18 @@ class InviteUsersEditView extends React.Component { + const { dispatch } = this.props; logEvent(events.IU_EDIT_SET_LINK_PARAM); - const { inviteLinksSetParams } = this.props; const params = { [key]: value }; - inviteLinksSetParams(params); + dispatch(inviteLinksSetParams(params)); }; createInviteLink = () => { + const { dispatch, navigation } = this.props; logEvent(events.IU_EDIT_CREATE_LINK); - const { createInviteLink, navigation } = this.props; - createInviteLink(this.rid); + dispatch(inviteLinksCreate(this.rid)); navigation.pop(); }; @@ -151,14 +142,9 @@ class InviteUsersEditView extends React.Component ({ +const mapStateToProps = (state: IApplicationState) => ({ days: state.inviteLinks.days, maxUses: state.inviteLinks.maxUses }); -const mapDispatchToProps = (dispatch: Dispatch) => ({ - inviteLinksSetParams: (params: object) => dispatch(inviteLinksSetParamsAction(params)), - createInviteLink: (rid: string) => dispatch(inviteLinksCreateAction(rid)) -}); - -export default connect(mapStateToProps, mapDispatchToProps)(withTheme(InviteUsersEditView)); +export default connect(mapStateToProps)(withTheme(InviteUsersEditView)); diff --git a/app/views/InviteUsersView/index.tsx b/app/views/InviteUsersView/index.tsx index 60ae339ad..aa2e8ef3d 100644 --- a/app/views/InviteUsersView/index.tsx +++ b/app/views/InviteUsersView/index.tsx @@ -1,62 +1,49 @@ +import { StackNavigationOptions } from '@react-navigation/stack'; +import moment from 'moment'; import React from 'react'; import { ScrollView, Share, View } from 'react-native'; -import moment from 'moment'; import { connect } from 'react-redux'; -import { StackNavigationProp, StackNavigationOptions } from '@react-navigation/stack'; -import { RouteProp } from '@react-navigation/core'; -import { Dispatch } from 'redux'; -import { ChatsStackParamList } from '../../stacks/types'; -import { - inviteLinksClear as inviteLinksClearAction, - inviteLinksCreate as inviteLinksCreateAction -} from '../../actions/inviteLinks'; -import RCTextInput from '../../containers/TextInput'; -import Markdown from '../../containers/markdown'; -import Button from '../../containers/Button'; -import scrollPersistTaps from '../../utils/scrollPersistTaps'; -import I18n from '../../i18n'; -import StatusBar from '../../containers/StatusBar'; +import { inviteLinksClear, inviteLinksCreate } from '../../actions/inviteLinks'; import { themes } from '../../constants/colors'; -import { withTheme } from '../../theme'; +import Button from '../../containers/Button'; +import Markdown from '../../containers/markdown'; import SafeAreaView from '../../containers/SafeAreaView'; +import StatusBar from '../../containers/StatusBar'; +import RCTextInput from '../../containers/TextInput'; +import { IApplicationState, IBaseScreen } from '../../definitions'; +import I18n from '../../i18n'; +import { TInvite } from '../../reducers/inviteLinks'; +import { ChatsStackParamList } from '../../stacks/types'; +import { withTheme } from '../../theme'; import { events, logEvent } from '../../utils/log'; +import scrollPersistTaps from '../../utils/scrollPersistTaps'; import styles from './styles'; -interface IInviteUsersViewProps { - navigation: StackNavigationProp; - route: RouteProp; - theme: string; +interface IInviteUsersViewProps extends IBaseScreen { timeDateFormat: string; - invite: { - url: string; - expires: number; - maxUses: number; - uses: number; - }; - createInviteLink(rid: string): void; - clearInviteLink(): void; + invite: TInvite; } class InviteUsersView extends React.Component { - private rid: string; - static navigationOptions = (): StackNavigationOptions => ({ title: I18n.t('Invite_users') }); + private rid: string; + constructor(props: IInviteUsersViewProps) { super(props); this.rid = props.route.params?.rid; } componentDidMount() { - const { createInviteLink } = this.props; - createInviteLink(this.rid); + const { dispatch } = this.props; + dispatch(inviteLinksCreate(this.rid)); } componentWillUnmount() { - const { clearInviteLink } = this.props; - clearInviteLink(); + const { dispatch } = this.props; + dispatch(inviteLinksClear()); } share = () => { @@ -133,16 +120,9 @@ class InviteUsersView extends React.Component { } } -const mapStateToProps = (state: any) => ({ +const mapStateToProps = (state: IApplicationState) => ({ timeDateFormat: state.settings.Message_TimeAndDateFormat, - days: state.inviteLinks.days, - maxUses: state.inviteLinks.maxUses, invite: state.inviteLinks.invite }); -const mapDispatchToProps = (dispatch: Dispatch) => ({ - createInviteLink: (rid: string) => dispatch(inviteLinksCreateAction(rid)), - clearInviteLink: () => dispatch(inviteLinksClearAction()) -}); - -export default connect(mapStateToProps, mapDispatchToProps)(withTheme(InviteUsersView)); +export default connect(mapStateToProps)(withTheme(InviteUsersView)); diff --git a/app/views/NewServerView/index.tsx b/app/views/NewServerView/index.tsx index 93e493bea..191895ceb 100644 --- a/app/views/NewServerView/index.tsx +++ b/app/views/NewServerView/index.tsx @@ -1,39 +1,37 @@ -import React from 'react'; -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 { Base64 } from 'js-base64'; +import React from 'react'; +import { BackHandler, Image, Keyboard, StyleSheet, Text, View } from 'react-native'; 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 { connect } from 'react-redux'; +import parse from 'url-parse'; -import UserPreferences from '../../lib/userPreferences'; -import EventEmitter from '../../utils/events'; -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'; -import OrSeparator from '../../containers/OrSeparator'; -import FormContainer, { FormContainerInner } from '../../containers/FormContainer'; -import I18n from '../../i18n'; +import { inviteLinksClear } from '../../actions/inviteLinks'; +import { selectServerRequest, serverFinishAdd, serverRequest } from '../../actions/server'; import { themes } from '../../constants/colors'; -import { events, logEvent } from '../../utils/log'; -import { withTheme } from '../../theme'; -import { BASIC_AUTH_KEY, setBasicAuth } from '../../utils/fetch'; +import Button from '../../containers/Button'; +import FormContainer, { FormContainerInner } from '../../containers/FormContainer'; import * as HeaderButton from '../../containers/HeaderButton'; -import { showConfirmationAlert } from '../../utils/info'; +import OrSeparator from '../../containers/OrSeparator'; +import { IBaseScreen, TServerHistory } from '../../definitions'; +import { withDimensions } from '../../dimensions'; +import I18n from '../../i18n'; 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'; +import UserPreferences from '../../lib/userPreferences'; import { OutsideParamList } from '../../stacks/types'; -import { TServerHistory } from '../../definitions/IServerHistory'; +import { withTheme } from '../../theme'; +import { isTablet } from '../../utils/deviceInfo'; +import EventEmitter from '../../utils/events'; +import { BASIC_AUTH_KEY, setBasicAuth } from '../../utils/fetch'; +import { showConfirmationAlert } from '../../utils/info'; +import { events, logEvent } from '../../utils/log'; +import { moderateScale, verticalScale } from '../../utils/scaling'; +import SSLPinning from '../../utils/sslPinning'; +import sharedStyles from '../Styles'; +import ServerInput from './ServerInput'; const styles = StyleSheet.create({ onboardingImage: { @@ -68,20 +66,14 @@ const styles = StyleSheet.create({ } }); -interface INewServerView { - navigation: StackNavigationProp; - theme: string; +interface INewServerViewProps extends IBaseScreen { connecting: boolean; - connectServer(server: string, username?: string, fromServerHistory?: boolean): void; - selectServer(server: string): void; previousServer: string; - inviteLinksClear(): void; - serverFinishAdd(): void; width: number; height: number; } -interface IState { +interface INewServerViewState { text: string; connectingOpen: boolean; certificate: any; @@ -93,8 +85,8 @@ interface ISubmitParams { username?: string; } -class NewServerView extends React.Component { - constructor(props: INewServerView) { +class NewServerView extends React.Component { + constructor(props: INewServerViewProps) { super(props); if (!isTablet) { Orientation.lockToPortrait(); @@ -118,9 +110,9 @@ class NewServerView extends React.Component { componentWillUnmount() { EventEmitter.removeListener('NewServer', this.handleNewServerEvent); BackHandler.removeEventListener('hardwareBackPress', this.handleBackPress); - const { previousServer, serverFinishAdd } = this.props; + const { previousServer, dispatch } = this.props; if (previousServer) { - serverFinishAdd(); + dispatch(serverFinishAdd()); } } @@ -169,9 +161,9 @@ class NewServerView extends React.Component { }; close = () => { - const { selectServer, previousServer, inviteLinksClear } = this.props; - inviteLinksClear(); - selectServer(previousServer); + const { dispatch, previousServer } = this.props; + dispatch(inviteLinksClear()); + dispatch(selectServerRequest(previousServer)); }; handleNewServerEvent = (event: { server: string }) => { @@ -179,10 +171,10 @@ class NewServerView extends React.Component { if (!server) { return; } - const { connectServer } = this.props; + const { dispatch } = this.props; this.setState({ text: server }); server = this.completeUrl(server); - connectServer(server); + dispatch(serverRequest(server)); }; onPressServerHistory = (serverHistory: TServerHistory) => { @@ -192,7 +184,7 @@ class NewServerView extends React.Component { submit = async ({ fromServerHistory = false, username }: ISubmitParams = {}) => { logEvent(events.NS_CONNECT_TO_WORKSPACE); const { text, certificate } = this.state; - const { connectServer } = this.props; + const { dispatch } = this.props; this.setState({ connectingOpen: false }); @@ -207,9 +199,9 @@ class NewServerView extends React.Component { await this.basicAuth(server, text); if (fromServerHistory) { - connectServer(server, username, true); + dispatch(serverRequest(server, username, true)); } else { - connectServer(server); + dispatch(serverRequest(server)); } } }; @@ -217,8 +209,8 @@ class NewServerView extends React.Component { connectOpen = () => { logEvent(events.NS_JOIN_OPEN_WORKSPACE); this.setState({ connectingOpen: true }); - const { connectServer } = this.props; - connectServer('https://open.rocket.chat'); + const { dispatch } = this.props; + dispatch(serverRequest('https://open.rocket.chat')); }; basicAuth = async (server: string, text: string) => { @@ -283,7 +275,7 @@ class NewServerView extends React.Component { await db.write(async () => { await item.destroyPermanently(); }); - this.setState((prevstate: IState) => ({ + this.setState((prevstate: INewServerViewState) => ({ serversHistory: prevstate.serversHistory.filter((server: TServerHistory) => server.id !== item.id) })); } catch { @@ -417,12 +409,4 @@ const mapStateToProps = (state: any) => ({ previousServer: state.server.previousServer }); -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()) -}); - -export default connect(mapStateToProps, mapDispatchToProps)(withDimensions(withTheme(NewServerView))); +export default connect(mapStateToProps)(withDimensions(withTheme(NewServerView)));