In last article we implemented age filter( http://calsob.in/how-to-build-a-dating-app-using-react-native-and-firebase-part-1/ ). So, we were able to filter user by there age. In this article we will add height filter and then we will be able to filter users by there age and height, both.
For age filter we user two sliders to input of users age range. For height filter we will do something similar, but, its a bit more complicated, because we will have to use four slider components. Age range will be in feet and inches and thats why we will need four sliders for height range. Now enough talk, lets start coding.
First we will add some code to our Profile component. Here is the new code of Profile component :
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View,
Button
} from 'react-native';
import firebase from 'firebase'
export default class Profile extends Component {
constructor(props) {
super(props)
this.state = {
user: this.props.screenProps
}
}
componentWillUnmount() {
const { uid } = this.state.user
this.firebaseRef.child(uid).child('dp').off('value')
}
componentDidMount(){
//console.warn("Profile");
const { uid } = this.state.user
this.firebaseRef = firebase.database().ref('users')
this.firebaseRef.child(uid).on('value', snap => {
const user = snap.val()
this.setState({ user: user, SwitchGender: user.filterGender })
})
}
toggleGender(value){
let user = this.state.user
const userData = {
filterGender: value
}
firebase.database().ref('users').child(user.uid).update({ ...userData})
this.setState({SwitchGender: value})
}
render() {
return (
<View style={styles.container}>
<Button
onPress={() => this.props.navigation.navigate('Age', { user: this.state.user })}
title={ "Age("+this.state.user.ageRange[0]+"yrs "+"to"+this.state.user.ageRange[1]+"yrs)" }
/>
<Button
onPress={() => this.props.navigation.navigate('Height', { user: this.state.user })}
title={"Height("+this.state.user.heightRange[0]+"'"+this.state.user.heightRange[1]+'"'+"to"+this.state.user.heightRange[2]+"'"+this.state.user.heightRange[3]+'"'+")"}
/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
welcome: {
fontSize: 20,
textAlign: 'center',
margin: 10,
},
instructions: {
textAlign: 'center',
color: '#333333',
marginBottom: 5,
},
});
We have added one more button, Height button, below the Age button. On pressing the height button the user will be navigated to Height component, with his login info as parameter.
Now, lets add code for Height component :
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View,
Slider
} from 'react-native';
import firebase from 'firebase'
export default class Height extends Component {
constructor(props) {
super(props)
this.state = {
user: this.props.navigation.state.params.user,
heightfromft: 4,
heightfromin: 5,
heighttoft:7,
heighttoin: 0
}
}
componentDidMount(){
const { heightRange } = this.state.user
this.setState({ heightfromft: heightRange[0],heightfromin: heightRange[1],heighttoft: heightRange[2],heighttoin: heightRange[3] })
this.heightfromft = heightRange[0]
this.heightfromin = heightRange[1]
this.heighttoft = heightRange[2]
this.heighttoin = heightRange[3]
}
toinches(ft,inch){
totalInch = ft*12+inch
return totalInch
}
setheightftfrom(val){
const valtoin = this.toinches(val,this.heightfromin)
const totalheightto = this.toinches(this.heighttoft,this.heighttoin)
if(valtoin<totalheightto)
this.setState({ heightfromft: val })
}
getheightftfrom(val){
const valtoin = this.toinches(val,this.heightfromin)
const totalheightto = this.toinches(this.heighttoft,this.heighttoin)
if(valtoin<totalheightto){
const { uid } = this.state.user
const userData = {
heightRange: [val, this.heightfromin, this.heighttoft, this.heighttoin ]
}
this.heightfromft = val
firebase.database().ref('users').child(uid).update({ ...userData})
}else{
this.setState({ heightfromft: this.heightfromft })
}
}
setheightftto(val){
const valtoin = this.toinches(val,this.heighttoin)
const totalheightfrom = this.toinches(this.heightfromft,this.heightfromin)
if(valtoin>totalheightfrom)
this.setState({ heighttoft: val })
}
getheightftto(val){
const valtoin = this.toinches(val,this.heighttoin)
const totalheightfrom = this.toinches(this.heightfromft,this.heightfromin)
if(valtoin>totalheightfrom){
const { uid } = this.state.user
const userData = {
heightRange: [this.heightfromft, this.heightfromin, val, this.heighttoin ]
}
this.heighttoft = val
firebase.database().ref('users').child(uid).update({ ...userData})
}else{
this.setState({ heighttoft: this.heighttoft })
}
}
setheightinfrom(val){
const valtoin = this.toinches(this.heightfromft,val)
const totalheightto = this.toinches(this.heighttoft,this.heighttoin)
if(valtoin<totalheightto)
this.setState({ heightfromin: val })
}
getheightinfrom(val){
const valtoin = this.toinches(this.heightfromft,val)
const totalheightto = this.toinches(this.heighttoft,this.heighttoin)
if(valtoin<totalheightto){
const { uid } = this.state.user
const userData = {
heightRange: [this.heightfromft, val, this.heighttoft, this.heighttoin ]
}
this.heightfromin = val
firebase.database().ref('users').child(uid).update({ ...userData})
}else{
this.setState({ heightfromin: this.heightfromin })
}
}
setheightinto(val){
const valtoin = this.toinches(this.heighttoft,val)
const totalheightto = this.toinches(this.heightfromft,this.heightfromin)
if(valtoin>totalheightto)
this.setState({ heighttoin: val })
}
getheightinto(val){
const valtoin = this.toinches(this.heighttoft,val)
const totalheightto = this.toinches(this.heightfromft,this.heightfromin)
if(valtoin>totalheightto){
const { uid } = this.state.user
const userData = {
heightRange: [this.heightfromft, this.heightfromin, this.heighttoft, val ]
}
this.heighttoin = val
firebase.database().ref('users').child(uid).update({ ...userData})
}else{
this.setState({ heighttoin: this.heighttoin })
}
}
render() {
return (
<View style={styles.container}>
<Text style={styles.instructions}>
height from :
</Text>
<Slider
style={{ width: 150 }}
step={1}
minimumValue={4}
maximumValue={7}
value={this.state.heightfromft}
onValueChange={ val => this.setheightftfrom(val) }
onSlidingComplete={ val => this.getheightftfrom(val) }
/>
<Slider
style={{ width: 300 }}
step={1}
minimumValue={0}
maximumValue={11}
value={this.state.heightfromin}
onValueChange={ val => this.setheightinfrom(val) }
onSlidingComplete={ val => this.getheightinfrom(val) }
/>
<Text style={styles.welcome}>
{this.state.heightfromft+' ft '+this.state.heightfromin+' in'}
</Text>
<Text style={styles.instructions}>
height to :
</Text>
<Slider
style={{ width: 150 }}
step={1}
minimumValue={4}
maximumValue={7}
value={this.state.heighttoft}
onValueChange={ val => this.setheightftto(val) }
onSlidingComplete={ val => this.getheightftto(val) }
/>
<Slider
style={{ width: 300 }}
step={1}
minimumValue={0}
maximumValue={11}
value={this.state.heighttoin}
onValueChange={ val => this.setheightinto(val) }
onSlidingComplete={ val => this.getheightinto(val) }
/>
<Text style={styles.welcome}>
{this.state.heighttoft+' ft '+this.state.heighttoin+' in'}
</Text>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
welcome: {
fontSize: 20,
textAlign: 'center',
margin: 10,
},
instructions: {
textAlign: 'center',
color: '#333333',
marginBottom: 5,
},
});
In the above code we have used four slider component. The first slider take input of height in feet and the second slider takes input of height in inches. The first two slider takes input of lower part of the height range. Similarly, the the third and fourth slider takers input of higher part of height range. In the above code, we are also validating that the lower part never exceeds the higher part. In ‘onSlidingComplete’ event of slider we are updating the height range in the database.
Now, Lets update code in Match Component so that the members list updates when user changes height range. Here is the code for Match component :
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View,
ListView,
Image
} from 'react-native';
import _ from 'lodash'
import moment from 'moment'
import firebase from 'firebase'
export default class Match extends Component {
constructor(props) {
super(props)
const ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
this.state = {
user: this.props.screenProps,
dataSource: ds.cloneWithRows([]),
}
}
componentDidMount(){
const { uid } = this.state.user
this.firebaseRef = firebase.database().ref('users')
this.firebaseRef.on('value', snap => {
let users = snap.val();
const rejectMe = _.reject(users, user => user.uid === uid)
const filterMe = _.filter(users, user => user.uid === uid)
const user = filterMe[0];
/* Age filter start */
const userBday = moment(user.birthday, 'MM/DD/YYYY')
const userAge = moment().diff(userBday, 'years')
const filterByAge = _.filter(rejectMe, profile => {
const profileBday = moment(profile.birthday, 'MM/DD/YYYY')
const profileAge = moment().diff(profileBday, 'years')
const inRangeUser = _.inRange(profileAge, user.ageRange[0], user.ageRange[1] + 1)
const inRangeProfile = _.inRange(userAge, profile.ageRange[0], profile.ageRange[1] + 1)
return inRangeUser && inRangeProfile
})
/* Age filter end */
/* Height filter start */
const userheightin = user.height[0]*12+user.height[1]
const userheightrangefrom = user.heightRange[0]*12+user.heightRange[1]
const userheightrangeto = user.heightRange[2]*12+user.heightRange[3]
const filterByHeight = _.filter(filterByAge, profile => {
const profileheightin = profile.height[0]*12+profile.height[1]
const profileheightrangefrom = profile.heightRange[0]*12+profile.heightRange[1]
const profileheightrangeto = profile.heightRange[2]*12+profile.heightRange[3]
const inRangeUserHeight = _.inRange(profileheightin, userheightrangefrom, userheightrangeto + 1)
const inRangeProfileHeight = _.inRange(userheightin, profileheightrangefrom, profileheightrangeto + 1)
return inRangeUserHeight && inRangeProfileHeight
})
/* Height filter end */
const ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
this.setState({ dataSource: ds.cloneWithRows(filterByHeight) })
})
}
renderRow(rowData, sectionID, rowID) {
return (
<View style={styles.rowContainer}>
<Image source={{ uri: rowData.dp }} style={styles.photo} />
<Text style={styles.text}>
{`${rowData.first_name} ${rowData.last_name}`}
</Text>
</View>
)
}
render() {
return (
<ListView
enableEmptySections={true}
removeClippedSubviews={false}
style={styles.container}
dataSource={this.state.dataSource}
renderRow={this.renderRow.bind(this)}
/>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
marginTop: 20,
},
rowContainer: {
flex: 1,
padding: 12,
flexDirection: 'row',
alignItems: 'center',
},
text: {
marginLeft: 12,
fontSize: 16,
},
photo: {
height: 40,
width: 40,
borderRadius: 20,
},
});
In the above code, we are taking the result of age filter i.e. ‘filterByAge’ and passing it through the height filter. Next, we are taking the result of height filter i.e. ‘filterByHeight’ and passing it as data source to ListView component.