1.0.3 • Published 3 years ago

accounts-react v1.0.3

Weekly downloads
6
License
MIT
Repository
github
Last release
3 years ago

This package is not maintained anymore

Meteor Accounts UI for React

meteor add meteoreact:accounts

Forked from royGil/accounts-react. Updated react-meteor-data to current. A huge credit goes to the useraccounts package and the people behind it.

This package has been created to be used in one of my projects which was purely React. Although the original useraccounts package can be used in react, it depends on blaze and jquery which are both useless when developing with react.

Right now, you might find that there are several features which hasn't been included in this package. Please open an issue if you need a feature and think it will benefit the community.

Goals

This package has multiple goals:

  1. Be an almost identical fork of the great useraccounts package with the difference of being dependent only on react (no blaze/jquery/templating).

  2. Allow an easy migration path for applications which already use the useraccounts package.

  3. Make sense. The codebase should be understandable and easy to modify.

  4. Stay actively maintained.

Setup

Important - Please note that you must provide a set of components either by using one of the versions below or by adding your own

Also note that it's mandatory to call AccountsReact.configure on both client/server even with an empty object!

Styled versions

Pick the package that suit your app. (Create it if it doesn't exist!)

If you've created a package and want to include it here, please open a pull request with a link to the package on atmoshperejs

Routing

This package currently supports react-router.

React Router

If you want to use different paths for your routes see custom routes

import React, { Component } from 'react'
import { Redirect } from 'react-router'
import { Route, Switch } from 'react-router-dom'
import { AccountsReactComponent } from 'meteor/meteoreact:accounts'

class Authentication extends Component {

  render () {
    const arState = this.arState

    return (
      <Switch>
        <Route exact path='/sign-in'          component={arState} />
        <Route exact path='/sign-up'          component={arState} />
        <Route exact path='/forgot-password'  component={arState} />
        <Route exact path='/change-password'  component={arState} />
        <Route exact path='/reset-password/:token' component={arState} />
        <Route exact path='/resend-verification'   component={arState} />
      </Switch>
    )
  }

  arState = ({ match, history }) => {
    const { path, params } = match

    // Cant change password if not logged in.
    if (Meteor.userId() && path !== '/change-password') {
      return (<Redirect to='/' />)
    }

    return (
      <AccountsReactComponent
        history={history}
        route={path}
        token={params.token} // for the reset-password route
      />
    )
  }
}

export default Authentication

States

When you render AccountsReactComponent there are 3 ways to make it render the form you want

  • Pass a "state" prop
  <AccountsReactComponent
    state='signUp'
  />
  • Pass a "route" prop
  <AccountsReactComponent
    route='/sign-up'
  />

You must pass a route that resolves to one of the possible states (example)

  • Configure the "defaultState" key
  AccountsReact.configure({
    defaultState: 'signUp'
  })

Currently available states are:

StateDetails
changePwdSet a new password (Must be logged in)
forgotPwdSend a password reset email to an address
resetPwdSet a new password (After reset, a "token" prop must be passed to AccountsReactComponent)
signInLogin form
signUpRegistration form
resendVerificationResend email with verification link

Configuration

  • Configuration should be the same on both ends. A good place to put the configuration file is imports/both/startup (and import it on both ends)

  • Although it is valid to use different configurations for the client and the server you'd better avoid it in order to prevent possible unknown side-effects. However, it's perfectly fine to set client configurations (like texts) only on the client and vice versa.

  • Configuration must also run before Meteor's startup.

The following is a list with details about each configurable option.

OptionTypeDefaultDescription
Behaviour
confirmPasswordBooleantrueAsk the password twice for confirmation (only on sign up)
defaultStateString'signIn'The state to use if no route has been declared (via route or prop)
disableForgotPasswordBooleanfalseDisable the option the call Accounts.forgotPassword
enablePasswordChangeBooleantrueMake the changePwd state available, you can either set it to false or just don't set a route for it.
focusFirstInputBoolean!Meteor.isCordovaWhether to focus the first input when a form is rendered.
forbidClientAccountCreationBooleanfalseDont allow user creation on the client. If set to true - no sign up link/form will be available.
lowercaseUsernameBooleanfalseTransform username field to lowercase upon registration
loginAfterSignupBooleantrueLogin automatically after sign up
overrideLoginErrorsBooleantrueShow general error on failed login (without specifying which field was wrong)
sendVerificationEmailBooleantrueSend email verification after successful registration
setDenyRulesBooleantrueApply default deny rules on Meteor.users collection
disableConfigureLoginServiceBooleantrueDisable configureLoginService() insecure method
Appearance
hideSignInLinkBooleanfalseWhen set to true, asks to never show the link to the sign in page
hideSignUpLinkBooleanfalseWhen set to true, asks to never show the link to the sign up page
showForgotPasswordLinkBooleanfalseSpecifies whether to display a link to the forgot password page/form
showResendVerificationLinkBooleanfalseSpecifies whether to display a link to the resend verification page/form
showLabelsBooleantrueSpecifies whether to display text labels above input elements
showPlaceholdersBooleantrueSpecifies whether to display place-holder text inside input elements
Client side validation
continuousValidationBooleanfalseValidate input as the user type (on every "onChange" event)
negativeValidationBooleantrueValidate input on every "onBlur" event (only after first data insertion)
Hooks
onLoginHookFunctionA function to be called after a successful login
onLogoutHookFunctionTriggered by calling AccountsReact.logout()
onSubmitHookFunctionA function to be called after a form submission. It takes 2 arguments (error, state).
preSignupHookFunctionA function to be called before calling the "createUser" method. It takes 2 arguments (password, info). Password is the raw password (before hashing), info is the object with all the data about the new user (you can modify it directly)
showReCaptchaBooleanfalseAdd reCaptcha mechanism to the sign up form (details)
OAuth
Redirects
mapStateToRoute

Hooks

const onLogoutHook = () => {
  // A good use case will be to redirect the user somewhere
}

const onSubmitHook = (err, state) => {
  if (!err) {
    if (state === 'signIn') {
      //
    }
    if (state === 'signUp') {
      //
    }  
  }
}

const preSignupHook = (password, info) => {
  /*
    info structure might look like this
    {
      username,
      email,
      password (hashed),
      profile
    }
  */
}

AccountsReact.configure({
  onLogoutHook,
  onSubmitHook,
  preSignupHook
})

ReCaptcha

First, obtain the necessary API keys from here

Choose one of the following ways to configure reCaptcha settings (Make sure your secretKey never reach the client!)

  "public": {
    "reCaptcha": {
      "siteKey": SITE KEY,
      // params
    }
  }
  "reCaptcha": {
    "secretKey": SECRET KEY
  }
  AccountsReact.configure({
    showReCaptcha: true
  })
  • Configuration Object
  AccountsReact.configure({
    reCaptcha: {
      // params (except secretKey!)
    },
    showReCaptcha: true
  })

And on a server only file

  AccountsReact.configure({
    reCaptcha: {
      secretKey: SECRET KEY
    }
  })

List of available params (except callback)

OAuth

You can specify whether to allow users to login with 3rd party service. The only requirements are that you add the service-configuration package (meteor add service-configuration) and the relevant packages for the services you want (e.g accounts-google. accounts-facebook, etc...)

And configure the services you want to support (server side)

  // google example
  ServiceConfiguration.configurations.update(
    { service: "google" },
    {
      $set: {
        "loginStyle": "popup",
        "clientId": "-",
        "secret": "-"
      }
    }
  )

You can also specify additional options for each service like so

  AccountsReact.configure({
    oauth: {
      'google': {
        // options
      },
      'facebook': {
        // ...
      }
    }
  })

You can find the available options here

Redirects

You can specify directly what happens when a user clicks on a link that normally will redirect him to a different form (e.g "Forgot your password?" link).

  AccountsReact.configure({
    redirects: {
      toSignUp: () => {},
      toSignIn: () => {},
      toForgotPwd: () => {}
    }
  })

Note that if you set any of the above, its your responsibility to take the user to a different route. If routing support (no internal state) is what you seek, you should probably just pass a "history" prop (see example above) to AccountsReactComponent

Custom Routes

Behind the scenes, AccountsReactComponent will use an object called mapStateToRoute to map different routes to the desired states.

The default object used is the following

  mapStateToRoute: {
   signIn: '/sign-in',
   signUp: '/sign-up',
   forgotPwd: '/forgot-password',
   changePwd: '/change-password',
   resetPwd: '/reset-password',
   resendVerification: '/resend-verification'
  }

You can easily override it with

  AccountsReact.configure({
    mapStateToRoute: {
      signIn: '/login',
      signUp: '/register'
      // ...
    }
  })

Fields

Form fields are defined as objects in an array and can be easily customized to your needs. You can edit, add or remove fields directly or via one of the built in functions (addField, removeField ...)

The supported properties are listed in the following table. Note that you can also specify your own properties

PropertyTypeRequiredDescription
_idStringXA unique field's id/name (internal use only) to be also used as attribute name into Meteor.user().profile in case it identifies an additional sign up field. Usually all lowercase letters
typeStringXSpecifies the input element type. At the moment supported inputs are: password, email, text, select, radio
displayNameStringThe field's label text. The text label is shown only if showLabels options is set to true
errStrStringError message to display in case of a false validation.
excludeBoolean(On sign up only) If set to true the field will be excluded from the new user object
funcFunctionSpecify a custom function for validation. (example below)
minLengthIntegerIf specified, requires the content of the field to be at least minLength characters
maxLengthIntegerIf specified, require the content of the field to be at most maxLength characters.
optionsObjectIn case type property is set to "select" or "radio", this field must be set to an array of options to be used
placeholderStringThe field's (input) placeholder text. The place-holder is shown only if showPlaceholders option is set to true
reRegExpSpecify a regular expression to validate against. (example below)
requiredBooleanIf set to true the corresponding field cannot be left blank
autocompleteString<input> autocomplete tag value

The original user accounts package supports several more properties. Pull requests are more then welcome!

You can see each state default fields here

Examples of func and re properties.

func

{
  _id: 'confirmPassword',
  displayName: 'Confirm password',
  type: 'password',
  placeholder: 'Re-enter your password',
  errStr: 'Password doesn\'t match',
  exclude: true,
  func: (fields, fieldObj, value, model, errorsArray) => {
    /*
      fields:      Current form fields array
      fieldObj:    This object
      value:       This field's value
      model:       Current form values object
      errorsArray: Current form errors array
    */

    if (!this.config.confirmPassword) {
      return true
    }

    // check that passwords match
    const { password } = model
    const { _id, errStr } = fieldObj

    if (typeof password === 'string') {
      if (!value || (value !== password)) {
        errorsArray.push({ _id, errStr })
        return
      }
    }

    return true
  }
}

re

{
  _id: 'email',
  displayName: 'Email',
  placeholder: 'Enter your email',
  re: regExp.Email,
  errStr: 'Please enter a valid email'
}

Add Fields

To add additional fields, you must specify the state you want to mutate, and an array of object(s) containing your field's data.

import { AccountsReact } from 'meteor/meteoreact:accounts'

AccountsReact.addFields('signUp', [
  {
    _id: 'fullName',
    displayName: 'Full Name',
    placeholder: 'Enter your full name',
    minLength: 4,
    maxLength: 70,
    required: true,
    errStr: 'This field must contain at least 4 characters and no more than 70',
    autocomplete: 'name'
  }
])

Remove Fields

This functionality is not implemented yet, You can help

Edit Fields

This functionality is not implemented yet, You can help

Texts

Configuring the text to be used by the forms is done via the AccountsReact.configure function.

The default configuration object contains a texts property which you can view here

Here is an example of how to override those

import { AccountsReact } from 'meteor/meteoreact:accounts'
AccountsReact.configure({
  texts: {
    button: {
      changedPwd: 'Change your password!'
    },
    info: {
      emailSent: 'Check your inbox!'
    },
    loginForbiddenMessage: 'The username or password is incorrect'
  }
})

Override Styling

Lets say that you are using semantic-ui-react and meteoreact:accounts-semantic and want to add a simple description below each input field.

Instead of copying the full package into your local packages folder and directly change the code (which is totally legitimate and will work just fine!) you can look at the source code of that package and copy only the implementation of the input field into your project.

From there you can edit (almost*) anything you'd like. Save the file when you are done and then add it like so:

import { AccountsReact } from 'meteor/meteoreact:accounts'
import YourInputField from '...'

AccountsReact.style({
    InputField: YourInputField
})

You can override any of the following fields

InputField, SelectField, RadioField, SubmitField, TitleField, ErrorsField

*Dont edit or remove anything that might break the core functionality (like the onChange handlers for example)

Contributing

  1. Fork this repo

  2. git clone https://github.com/royGil/accounts-react-demo && cd accounts-react-demo

  3. git clone https://github.com/{your_account}/accounts-react packages/meteoreact:accounts

  4. meteor npm install

From this point you can make changes to the package folder and run the demo app to see them.

Note that if you want to test anything related to the social buttons you'll have to include a proper settings.json file (see example below)

To commit your changes

  1. cd packages/meteoreact:accounts

  2. npm install (so you can run tests)

  3. npm test and make sure there are no errors

  4. Push your changes (from within the "meteoreact:accounts" folder!) and create a PR from your fork on github.

I'll appreciate if you write tests for your new commit but its not a requirement.


{
  "services": {
    "google": {
      "loginStyle": "popup",
      "clientId": "XXX",
      "secret": "XXX"
    },
    "facebook": {
      "loginStyle": "popup",
      "appId": "XXX",
      "secret": "XXX"
    },
    "github": {
      "loginStyle": "popup",
      "clientId": "XXX",
      "secret": "XXX"
    },
    "twitter": {
      "loginStyle": "popup",
      "consumerKey": "XXX",
      "secret": "XXX"
    }
  }
}