How to build a dating app using React Native and Firebase – part 2

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.