npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

bs-react-netlify-identity

v2.0.3

Published

Reason bindings for react-netlify-identity

Downloads

20

Readme

bs-react-netlify-identity

Reason bindings for react-netlify-identity with react context and hooks.

NPM

Includes example of a fully implemented authentication solution using netlify identity (login, signup, forgot password, account recovery and login using external providers) wrapped in material-ui with hooks creating a beautiful design out of the box 😍

Check out demo at https://bs-react-netlify-identity.netlify.com/.


Installation

npm i --save bs-react-netlify-identity
// or
yarn add bs-react-netlify-identity

Then update your bsconfig.json:

"bs-dependencies": [
  ...
+ "bs-react-netlify-identity",
]

Setting up

You need to have an active Netlify site with Netlify identity turned on, instructions are in this section readme of react-netlify-identity.

Add the netlify identity provider to the top of the tree:

// url of the netlify site, should already be public, so no point in using .env
let url = "https://your-identity-instance.netlify.com/";

ReactDOMRe.renderToElementWithId(
  <ReactNetlifyIdentity.IdentityContextProvider url>
   ...
  </ReactNetlifyIdentity.IdentityContextProvider>,
  "root",
);

Usage

There are two different hooks that can be used, depending on whether you need to save extra meta data about the user (besides email and password), like username, date of birth etc. and be able to access the data as a strongly typed reason record (as opposed to Js.t({..})).

The extra data about the user is saved in user metadata field by go-true (used in react-netlify-identity) when calling signupUser. The simpler version of the hook will have this field typed to a js object Js.t({..}) and is not intended to be used if you need to manipulate that metadata (compiler won't know anything about the type so it would be extremely unsafe).

If you want to manipulate the meta data object, you will want to define your own type for user's metadata, conversion functions (to and from JS) and configure the hook with those in order to get compiler help when accessing the metadata field.

Simple case: signup, login, logout

Let's start with the simple version of the hook where you don't need to take account of the user metadata - useIdentityContextSimple. Here are some basic operations on the netlify identity object we can perform:

// somewhere in your component
let identity = ReactNetlifyIdentity.useIdentityContextSimple();

// check if user is logged in
let isLoggedIn = identity.isLoggedIn;

// login user
identity.loginUser(~email, ~password, ~remember, ())
    |> Js.Promise.then_(_ => ...);

// signup user with data as empty js object since there is no need for extra data
identity.signupUser(~email, ~password, ~data=Js.Obj.empty())
    |> Js.Promise.then_(_ => ...);

// logout
identity.logoutUser()
    |> Js.Promise.then_(_ => ...);

These operations will look exactly the same for the other version of the hook, where we need to have the metadata typed.

Account recovery

To recover an account we first call requestPasswordRecovery with the user's email:

// somewhere in your component
let identity = ReactNetlifyIdentity.useIdentityContextSimple();

identityContext.requestPasswordRecovery(~email)
    |> Js.Promise.then_(_ => ...);

This will send an email with a link containing a recovery token to the email address, for more information and testing tips check gotrue-js docs on account recovery.

The recovery token is appended as a parameter to the link and will be parsed into identity.param, that we can access in a root component when the application loads:

let identity = ReactNetlifyIdentity.useIdentityContextSimple();

// Handle recovery token.
switch (identity.param.token, identity.param.type_) {
  | (Some(_), NetlifyToken.Recovery) =>
    identity.recoverAccount(~remember=false, ())
    |> Js.Promise.(then_(/* show a dialog to reset password */))
    |> ignore
  | _ => ignore()
  };

If the token is not empty and is of type Recovery, we can call identity.recoverAccount, which will log in the user, for more see gotrue-js recovery.

Check the full example at Root.re and RecoveryDialog.re

Other token types

Token, that comes as a url parameter, can serve different purposes:

  • account recovery,
  • invitation to create an account,
  • email change, etc.

To model these types, there is a module NetlifyToken that exposes the following variant:

type tokenType =
  | Invite
  | Recovery
  | EmailChange
  | Unknown;

Expanding on the previous step for account recovery, we can handle other token types in the root component:

let identity = ReactNetlifyIdentity.useIdentityContextSimple();

switch (identity.param.token, identity.param.type_) {
  | (Some(_), NetlifyToken.Recovery) => // recover
  | (Some(_), NetlifyToken.Invite) => // register user
  | (Some(_), NetlifyToken.EmailChange) // change email
  | _ => ignore()
  };

Work with user metadata

There is a functor ReactNetlifyIdentity.Make, that needs to know the type of the metadata on the reason side (record), the type of the metadata on the JS side (a js object) and functions to convert between the two.

If you don't need to have different metadata representations (e.g. field "full_name" in the netlify identity db and field "fullName" in reason), you can use [@bs.deriving {jsConverter: newType}] that will generate a type for JS (abs_myMetadata) and conversion functions (myMetadataFromJs and myMetadataToJs), more on this in the docs on converters.

Let's say we want to save user name as metadata. We need to define a file where we will create a hooks based on the custom metadata type, e.g. UserIdentity.re:

[@bs.deriving {jsConverter: newType}]
type userMetaData = {userName: string};

module Context =
  ReactNetlifyIdentity.Make({
    type userData = userMetaData;
    type userDataJs = abs_userMetaData;
    let convertFromJs = userMetaDataFromJs;
    let convertToJs = userMetaDataToJs;
  });

Now we will use

UserIdentity.Context.useIdentityContext()

instead of ReactNetlifyIdentity.useIdentityContextSimple() and we have access to all the same functionality, the only difference being signupUser, that accepts third argument of type userMetaData, and how we access the metadata object:

let identity = UserIdentity.Context.useIdentityContext();

// won't compile if passed wrong type in data
identity.signupUser(~email, ~password, ~data={userName: userName})
    |> Js.Promise.then_(_ => ...);

// access username
let userName =
  identity.user
  ->Belt.Option.flatMap(u => u.metaData)
  // won't compile if the property doesn't exist on the metadata type
  ->Belt.Option.map(m => m.userName);

Work with roles

Netlify allows you to configure roles and assign them to your users either manually via the interface, or using a lambda function (see how to set roles in Netlify Identity).

Roles are then stored in app metadata on the user object. Here is an example of how to access roles from a reason component:

let identity = UserIdentity.Context.useIdentityContext();

let roles =
  identity.user
  ->Belt.Option.flatMap(u => u.appMetaData)
  ->Belt.Option.flatMap(m => m.roles);

let isAdmin =
  switch (roles) {
  | Some(roles) =>
    roles->Belt.Array.keep(r => r == "admin")->Belt.Array.length > 0
  | _ => false
  };

Work with external providers

An external provider is exposed as variant:

type provider =
  | Bitbucket
  | GitHub
  | GitLab
  | Google;

and can be used to implement login with a specific provider, e.g.:

let identity = ReactNetlifyIdentity.useIdentityContextSimple();
let handleClick = _ => identity.loginProvider(GitHub);

It is however more practical to get the enabled providers via the identity hook and iterate over them:

let identity = ReactNetlifyIdentity.useIdentityContextSimple();

identity.settings.providers
->Belt.Array.map(provider =>
    <MyProviderButton
      provider
      key={ReactNetlifyIdentity.providerToString(provider)}
    />
  )
|> React.array;

Running locally

yarn
npm start

License

MIT © Margaret