Problems setting up custom FB signup with Meteor and React


#1

Hi everyone,

So I have been trying to create a custom FB login with Meteor and React but I am stuck.

I got so far that I am able to signup with FB, create the user in my database but now my current user displays as undefined undefined instead of the first and last name.

I understand that I need to set the values somewhere but I am kinda lost on where or how I should do this.

If anyone has experience setting this up, please give me a push in the right direction.

This is my current code for the signup form:

import React, { Component } from 'react';
import { Link } from 'react-router';
import { Row, Col, FormGroup, ControlLabel, FormControl, Button } from 'react-bootstrap';
import { handleSignup } from '../../modules/signup';

export class Signup extends Component {
  componentDidMount() {
    handleSignup({ component: this });
  }

  handleSubmit(event) {
    event.preventDefault();
  }

    socialLogin(event) {
    event.preventDefault();

    const service = event.target.getAttribute( 'data-social-login' ),
          options = {
            requestPermissions: [ 'email' ]
          };

    if ( service === 'loginWithTwitter' ) {
      delete options.requestPermissions;
    }

    Meteor[ service ]( options, ( error ) => {
      if ( error ) {
        Bert.alert( error.message, 'danger' );
      }
    });
  }



  render() {
    return (
    <div className="login-form">
      <Col xs={12} md={4} sm={4} />
        <Col xs={ 12 } md={ 4 } sm={ 4 } >
          <h4 className="page-header">Sign Up</h4>
          <form ref="signup" className="signup" onSubmit={ this.handleSubmit }>
            <Row>
              <Col xs={ 6 } sm={ 6 }>
                <FormGroup>
                  <ControlLabel>First Name</ControlLabel>
                  <FormControl
                    type="text"
                    ref="firstName"
                    name="firstName"
                    placeholder="First Name"
                  />
                </FormGroup>
              </Col>
              <Col xs={ 6 } sm={ 6 }>
                <FormGroup>
                  <ControlLabel>Last Name</ControlLabel>
                  <FormControl
                    type="text"
                    ref="lastName"
                    name="lastName"
                    placeholder="Last Name"
                  />
                </FormGroup>
              </Col>
            </Row>
            <FormGroup>
              <ControlLabel>Email Address</ControlLabel>
              <FormControl
                type="text"
                ref="emailAddress"
                name="emailAddress"
                placeholder="Email Address"
              />
            </FormGroup>
            <FormGroup>
              <ControlLabel>Password</ControlLabel>
              <FormControl
                type="password"
                ref="password"
                name="password"
                placeholder="Password"
              />
            </FormGroup>
            <Button type="submit" bsStyle="success">Sign Up</Button>
          </form>
          <hr/>
          <Button className= "fb-button" data-social-login="loginWithFacebook" type="button" onClick={ this.socialLogin }>
            <i className="fa fa-facebook"></i> Sign in with Facebook
          </Button>

          <p>Already have an account? <Link to="/login">Log In</Link>.</p>
        </Col>
        <Col xs={12} md={4} sm={4} />
    </div>
    )
  }
}

And this is my handleSignup file:

import $ from 'jquery';
import 'jquery-validation';
import { browserHistory } from 'react-router';
import { Accounts } from 'meteor/accounts-base';
import { Bert } from 'meteor/themeteorchef:bert';
import { getInputValue } from './get-input-value';

let component;

const getUserData = () => ({
  email: getInputValue(component.refs.emailAddress),
  password: getInputValue(component.refs.password),
  profile: {
    name: {
      first: getInputValue(component.refs.firstName),
      last: getInputValue(component.refs.lastName),
    },
  },
});

const signUp = () => {
  const user = getUserData();

  Accounts.createUser(user, (error) => {
    if (error) {
      Bert.alert(error.reason, 'danger');
    } else {
      browserHistory.push('/');
      Bert.alert('Welcome!', 'success');
    }
  });
};

const validate = () => {
  $(component.refs.signup).validate({
    rules: {
      firstName: {
        required: true,
      },
      lastName: {
        required: true,
      },
      emailAddress: {
        required: true,
        email: true,
      },
      password: {
        required: true,
        minlength: 6,
      },
    },
    messages: {
      firstName: {
        required: 'First name?',
      },
      lastName: {
        required: 'Last name?',
      },
      emailAddress: {
        required: 'Need an email address here.',
        email: 'Is this email address legit?',
      },
      password: {
        required: 'Need a password here.',
        minlength: 'Use at least six characters, please.',
      },
    },
    submitHandler() { signUp(); },
  });
};

export const handleSignup = (options) => {
  component = options.component;
  validate();
};


And yes I know my code is a bit messy… I’m still learning :wink:


#2

maybe add a breakpoint after getUserData() and check, if firstname and lastname are already empty there.

I think, Accounts.createUser only accepts username/email and password and every other value needs to be in the profile-param, see http://docs.meteor.com/api/passwords.html#Accounts-createUser

Another feedback: Personally, I never use refs. I would also advice to never use them, unless you have no other choice.

In your case i would change the form to https://github.com/vazco/uniforms/ or similar. Then, you have all the date that you need already in the callback of the form.

Bonus: you don’t need jquery anymore which is usually obsolet with react.

Your login form will look something like this:


const loginSchema = new SimpleSchema({
   firstName: {
       type: String,
   }, 
   lastName: {
      type: String
   },
   email: {
       type: String,
       regEx: SimpleSchema.RegEx.Email,
   },
   password: {
       type: String,
       min: 6
   }
});


const doSocialLogin = ({firstName, lastName, email, password}) => {
   const profile = {firstName, lastName};
   Accounts.createUser({email, password, profile}, (error) => {
       if (error) {
         Bert.alert(error.reason, 'danger');
       } else {
         browserHistory.push('/');
         Bert.alert('Welcome!', 'success');
       }
     });
}

return (
   <AutoForm schema={loginSchema} onSubmit={doSocialLogin} />
);