Created
June 21, 2018 06:29
-
-
Save darotar/d8b448497dafe897287a25916a19b551 to your computer and use it in GitHub Desktop.
Examle of React Native multi-part registration form
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { Component } from 'react'; | |
import { reduxForm, Field } from 'redux-form'; | |
import PropTypes from 'prop-types'; | |
import {Title, Input, Button} from '../../../elements'; | |
import { | |
Description, | |
StyledTitle, | |
DescriptionWrapper, | |
Container | |
} from './styles'; | |
class EmailPhoneForm extends Component { | |
static propTypes = { | |
previousPage: PropTypes.func.isRequired, | |
onSubmit: PropTypes.func.isRequired, | |
handleSubmit: PropTypes.func.isRequired, | |
}; | |
render() { | |
const {handleSubmit} = this.props; | |
return ( | |
<Container> | |
<Title style={StyledTitle}>Registration</Title> | |
<DescriptionWrapper> | |
<Description> | |
Phone or mail is required to restore access to your account | |
</Description> | |
</DescriptionWrapper> | |
<Field | |
focusedColor="#7bb2ff" | |
component={Input} | |
name="email" | |
placeholder="Email" | |
/> | |
<Field | |
focusedColor="#7bb2ff" | |
name="firstName" | |
component={Input} | |
placeholder="Name" | |
/> | |
<Field | |
focusedColor="#7bb2ff" | |
name="secondName" | |
component={Input} | |
placeholder="Second Name" | |
/> | |
<Button style={{marginTop: 10}} color="black" onPress={handleSubmit}>Done</Button> | |
</Container> | |
); | |
} | |
} | |
export default reduxForm({ | |
form: 'registration', | |
destroyOnUnmount: false, | |
forceUnregisterOnUnmount: true | |
})(EmailPhoneForm); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, {Component} from 'react'; | |
import {View} from 'react-native'; | |
import {Field, reduxForm} from 'redux-form'; | |
import PropTypes from 'prop-types'; | |
import Button from '../../../elements/button'; | |
import Input from '../../../elements/input'; | |
import { | |
Description, | |
StyledTitle, | |
DescriptionWrapper, | |
NicknameView | |
} from './styles'; | |
import Title from '../../../elements/title'; | |
// import validate from '../validate'; | |
class MainForm extends Component { | |
static propTypes = { | |
defaultServer: PropTypes.string, | |
onSubmit: PropTypes.func, | |
handleSubmit: PropTypes.func.isRequired, | |
}; | |
constructor(props) { | |
super(props); | |
} | |
toggleServerInput = () => { | |
this.setState({isChecked: !this.state.isChecked}); | |
}; | |
render() { | |
return ( | |
<View> | |
<Title style={StyledTitle}>Registration</Title> | |
<DescriptionWrapper> | |
<Description> | |
During registration, the application will create security key for recovery | |
</Description> | |
</DescriptionWrapper> | |
<NicknameView> | |
<Field | |
name="nickname" | |
focusedColor="#7bb2ff" | |
component={Input} | |
placeholder="Create login" | |
/> | |
</NicknameView> | |
<Button color="black" onPress={this.props.handleSubmit}>Continue</Button> | |
</View> | |
); | |
} | |
} | |
export default reduxForm({ | |
form: 'registration', | |
destroyOnUnmount: false, | |
forceUnregisterOnUnmount: true | |
})(MainForm); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React from 'react'; | |
import renderer from 'react-test-renderer'; | |
import { Provider } from 'react-redux'; | |
import { createStore, combineReducers } from 'redux'; | |
import { reducer as formReducer, Field } from 'redux-form'; | |
import MainForm from './'; | |
import Button from '../../../elements/button'; | |
import Checkbox from '../../../elements/checkbox'; | |
const store = createStore(combineReducers({ form: formReducer })); | |
const mainForm = renderer.create( | |
<Provider store={store}> | |
<MainForm /> | |
</Provider> | |
); | |
describe('<MainForm />', () => { | |
it('renders without crashing', () => { | |
expect(mainForm.toJSON()).toBeTruthy(); | |
}); | |
it('contains 3 required <Field /> components', () => { | |
expect(mainForm.root.findAllByType(Field).length).toEqual(3); | |
}); | |
it('contains one <Checkbox /> component', () => { | |
expect(mainForm.root.findAllByType(Checkbox).length).toEqual(1); | |
}); | |
it('contains one <Button /> component', () => { | |
expect(mainForm.root.findAllByType(Button).length).toEqual(1); | |
}); | |
it('show server input when press checkbox', () => { | |
const checkbox = mainForm.root.findByType(Checkbox); | |
const pageComponent = mainForm.root.findByType(MainForm); | |
checkbox.props.onCheck(); | |
// expect(registrationInstance; | |
}); | |
}); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, {Component} from 'react'; | |
import {connect} from 'react-redux'; | |
import {withNavigation} from 'react-navigation'; | |
import PropTypes from 'prop-types'; | |
import {Alert} from 'react-native'; | |
import MainForm from '../../components/forms/registration/main-form'; | |
import EmailPhoneForm from '../../components/forms/registration/email-phone-form'; | |
import BackgroundContainer from '../background-container'; | |
import {accountActions} from '../../store/actions'; | |
import {services} from '../../utils'; | |
import routeEnum from '../../enums/route-enum'; | |
import {dbEnum} from '../../enums'; | |
import backgroundImage from './img/bg.png'; | |
class Registration extends Component { | |
static propTypes = { | |
account: PropTypes.object, | |
dispatch: PropTypes.func.isRequired, | |
navigation: PropTypes.shape({navigate: PropTypes.func}) | |
}; | |
static contextTypes = { | |
t: PropTypes.func.isRequired, | |
}; | |
state = { | |
page: 1, | |
}; | |
constructor(props) { | |
super(props); | |
this.realm = services.getRealm(); | |
} | |
nextPage = (data) => { | |
return data.nickname | |
? this.setState({page: this.state.page + 1}) | |
: Alert.alert('Fill nickname field'); | |
}; | |
previousPage = () => { | |
return this.setState({page: this.state.page - 1}); | |
}; | |
saveToDatabase = () => { | |
const {account} = this.props; | |
const {username} = account.user; | |
const {deviceId, hostname} = account; | |
const dateCreate = new Date(); | |
const dateUpdate = new Date(); | |
const user = { | |
...account.user, | |
username, | |
}; | |
const keys = { | |
...account.keys, | |
username, | |
}; | |
const resultAccount = { | |
username, | |
user, | |
keys, | |
deviceId, | |
hostname, | |
dateCreate, | |
dateUpdate, | |
}; | |
this.realm.write(() => { | |
this.realm.create(dbEnum.Account, resultAccount, true); | |
}); | |
}; | |
registration = async (data) => { | |
const {account, dispatch} = this.props; | |
if (data.email && this.checkEmail(data.email)) { | |
Alert.alert('Invalid email address'); | |
return null; | |
} | |
if (account.loading) { | |
Alert.alert('Account is loading'); | |
return null; | |
} | |
const sendData = { | |
name: (data.nickname || '').toLowerCase(), | |
email: (data.email || '').toLowerCase(), | |
device_id: account.deviceId, | |
device_name: account.deviceName, | |
platform: account.platform, | |
settings: null, | |
firstName: data.firstName, | |
secondName: data.secondName, | |
}; | |
dispatch(accountActions.register(sendData)) | |
.then(() => { | |
Alert.alert('Registration success'); | |
console.error('registration success', this.props.account); | |
this.saveToDatabase(); | |
this.props.navigation.navigate(routeEnum.Login); | |
}) | |
.catch((error) => { | |
Alert.alert('Registration error'); | |
console.error('registration error', error.response.data); | |
if (error.response.status === 400) { | |
this.props.navigation.navigate(routeEnum.Login); | |
} | |
}); | |
}; | |
checkEmail = (value) => { | |
return !/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i.test(value); | |
} | |
render() { | |
const {page} = this.state; | |
const {hostname, isSecure} = this.props.account; | |
const server = `http${isSecure ? 's' : ''}://${hostname}`; | |
return ( | |
<BackgroundContainer image={backgroundImage}> | |
{page === 1 && <MainForm defaultServer={server} onSubmit={this.nextPage}/>} | |
{page === 2 && <EmailPhoneForm previousPage={this.previousPage} onSubmit={this.registration}/>} | |
</BackgroundContainer> | |
); | |
} | |
} | |
export default connect(state => ({ | |
account: state.account, | |
}))(withNavigation(Registration)); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React from 'react'; | |
import renderer from 'react-test-renderer'; | |
import { Provider } from 'react-redux'; | |
import { createStore, combineReducers } from 'redux'; | |
import { reducer as formReducer } from 'redux-form'; | |
import Registration from './'; | |
const store = createStore(combineReducers({ form: formReducer })); | |
const registration = renderer.create( | |
<Provider store={store}> | |
<Registration /> | |
</Provider> | |
); | |
describe('<Registration />', () => { | |
it('renders without crashing', () => { | |
expect(registration.toJSON()).toBeTruthy(); | |
}); | |
it('show one of forms when rendered', () => { | |
expect(registration.toJSON().children.length).toEqual(1); | |
}); | |
it('change state.page when click on Button component', () => { | |
const registrationInnerComponent = registration.root.findByType(Registration)._fiber.stateNode; | |
registrationInnerComponent.nextPage(); | |
expect(registrationInnerComponent.state.page).toBeGreaterThan(1); | |
registrationInnerComponent.previousPage(); | |
expect(registrationInnerComponent.state.page).toEqual(1); | |
}); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment