Skip to content

Instantly share code, notes, and snippets.

@darotar
Created June 21, 2018 06:29
Show Gist options
  • Save darotar/d8b448497dafe897287a25916a19b551 to your computer and use it in GitHub Desktop.
Save darotar/d8b448497dafe897287a25916a19b551 to your computer and use it in GitHub Desktop.
Examle of React Native multi-part registration form
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);
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);
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;
});
});
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));
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