Tutorials
Add User Invites

Add user invites

Invitation process overview

The invitation process flow is outlined as a series of steps below:

User Initiates Invite

The process starts with a user's decision to send an invitation. To send any invitation later, we should know which user is sending the invitation and the tenant.

In Next.js, we can get the user data from the session:

import { useSession } from "@/lib/roq"
 
const { session } = useSession()
 
const roq_user_id = session.roqUserId
const tenant_id = session.user.tenantId

Another way we can query these data is using the findMany() on the user entity. For example, we can find a user based on the email:

const getUserData = async () => {
  const userData = await roqBrowserClient.user.findMany({
    where: {
      email: {
        equals: "t.justin@roq.tech"
      }
    }
  })
}

From the code, we can get the response as an object:

[
    {
        "id": "2aef5b13-b647-4ff4-b76f-a58d62cdb0ef",
        "email": "Francis43@roq.tech",
        "firstName": null,
        "lastName": null,
        "roq_user_id": "06077069-4193-4f2d-98e1-2c1354df9ba6",
        "tenant_id": "dc92f95d-42bd-45af-84a7-da227d694cbb",
        "created_at": "2023-10-19T09:46:27.664Z",
        "updated_at": "2023-10-19T09:46:27.664Z"
    }
]

We will use the roq_user_id and tenant_id data for the next step, which is sent invitation. By default, the role of the invitee is the same as the user who's sent the invitation.

Invite Sent

The sendUserInvites() API invites users and automatically creates a user invite.

const status = async() => {
  await roqBrowserClient.roqPlatform.sendUserInvites({
    userInvites: {
      tenantId: 'dc92f95d-42bd-45af-84a7-da227d694cbb',
      userInvites: [{
        createdByUserId: '8b249b07-bdd9-43f7-a10e-ace10f27ff66',
        email: "wick.john@roq.tech",
        locale: "en-US"
      }]
    }
  })
} 

If the user invitation is a success, we will get the response data:

{
    "sendUserInvites": {
        "success": [
            {
                "acceptedByUserId": null,
                "createdAt": "2023-10-27T00:14:36.900Z",
                "createdByUserId": "8b249b07-bdd9-43f7-a10e-ace10f27ff66",
                "data": null,
                "email": "wick.john@roq.tech",
                "firstName": "",
                "id": "db7a682d-6dca-4259-b15b-83aef12d1f5c",
                "locale": "en-US",
                "lastName": "",
                "roleKeys": null,
                "status": "pending",
                "statusUpdatedAt": "2022-08-10T09:02:18.579Z",
                "tenantId": "dc92f95d-42bd-45af-84a7-da227d694cbb",
                "updatedAt": "2023-10-27T00:14:36.900Z",
                "userTokenId": "e9ff1946-6060-4917-911b-c571cd98466a"
            }
        ],
        "errors": []
    }
}

In case we want to resend the invitation, we can use the ID from the sendUserInvites() response and then resend the user invitation using the resendUserInvite() API.

const resendUserInvitationStatus = async() => {
    const userInviteModel = await roqBrowserClient.roqPlatform.resendUserInvite({
        userInviteId: "db7a682d-6dca-4259-b15b-83aef12d1f5c"
    })
}

In Next.js, it is easy to implement a form that allows users to invite others via email:

invite.tsx
"use client"
 
import { useState } from 'react'
import { roqBrowserClient } from "@/lib/roq/roq-client";
import { useSession } from '@/lib/roq'
 
export default function InvitePage() {
  const { session } = useSession();
  const [email, setEmail] = useState('')
  const [statusMessage, setStatusMessage] = useState('')
 
  const handleInvite = async () => {
    if (session?.roqUserId && session?.user?.tenantId) {
      await roqBrowserClient.roqPlatform.sendUserInvites({
        userInvites: {
          tenantId: session.user.tenantId,
          userInvites: [{
            createdByUserId: session.roqUserId,
            email: email,
            locale: "en-US"
          }]
        }
      });
      setStatusMessage(`Invite sent to ${email}`)
    } else {
      setStatusMessage(`Unable to fetch session details.`)
    }
  };
 
  return (
    <div>
      <h1>Send an Invitation</h1>
      <input 
        type="email" 
        placeholder="Enter email to invite" 
        value={email}
        onChange={(e) => setEmail(e.target.value)}
      />
      <button onClick={handleInvite}>Send Invite</button>
      {statusMessage && <p>{statusMessage}</p>}
    </div>
  );
}

Recipient Receives Invite

The invitee gets a notification by email.

user invitation email

Invite Accepted or Rejected

The recipient can choose to either accept or decline the invitation and then we can check the invitation status using the userInvites() API.

import { roqBrowserClient } from "@/lib/roq/roq-client";
 
const findUserInvitebyEmail = async() => {
    const inviteeData = await roqBrowserClient.roqPlatform.userInvites({
        filter: {
            email: {
                equalTo: "wick.john@roq.tech"
            }
        }
    })
    return inviteeData
}

If the invitee accepts the invitation, the response status will have an accepted value:

{
    "userInvites": {
        "data": [
            {
                "acceptedByUserId": "9a2f96fa-6313-4b97-9de8-d735a0365d2e",
                "createdAt": "2023-10-27T00:14:36.900Z",
                "createdByUserId": "8b249b07-bdd9-43f7-a10e-ace10f27ff66",
                "data": null,
                "email": "wick.john@roq.tech",
                "firstName": "",
                "id": "db7a682d-6dca-4259-b15b-83aef12d1f5c",
                "locale": "en-US",
                "lastName": "",
                "roleKeys": [],
                "status": "accepted",
                "statusUpdatedAt": "2023-10-27T03:27:02.343Z",
                "tenantId": "dc92f95d-42bd-45af-84a7-da227d694cbb",
                "updatedAt": "2023-10-27T03:27:03.202Z",
                "userTokenId": "e9ff1946-6060-4917-911b-c571cd98466a"
            }
        ],
        "totalCount": 1
    }
}

In this Next.js page, we will use it for a single email use case. To support more emails, we need a better solution for auto status checking rather than polling.

invite.tsx
"use client"
 
import { useState, useEffect } from 'react'
import { roqBrowserClient } from "@/lib/roq/roq-client";
import { useSession } from '@/lib/roq'
 
export default function InvitePage() {
  const { session } = useSession()
  const [email, setEmail] = useState('')
  const [statusMessage, setStatusMessage] = useState('')
  const [inviteStatus, setInviteStatus] = useState('pending')
  const POLL_INTERVAL = 5000 // Polling every 5 seconds
 
  useEffect(() => {
    const pollInviteStatus = setInterval(async () => {
      if (email) {
        const inviteeData = await roqBrowserClient.roqPlatform.userInvites({
          filter: {
            email: {
              equalTo: email
            }
          }
        });
  
        if (inviteeData && inviteeData.data && inviteeData.data.length) {
          setInviteStatus(inviteeData.data[0].status);
        }
      }
    }, POLL_INTERVAL);
 
    return () => clearInterval(pollInviteStatus);
  }, [email]);
 
  const handleInvite = async () => {
    if (session?.roqUserId && session?.user?.tenantId) {
      await roqBrowserClient.roqPlatform.sendUserInvites({
        userInvites: {
          tenantId: session.user.tenantId,
          userInvites: [{
            createdByUserId: session.roqUserId,
            email: email,
            locale: "en-US"
          }]
        }
      });
      setStatusMessage(`Invite sent to ${email}`);
    } else {
      setStatusMessage(`Unable to fetch session details.`);
    }
  };
 
  return (
    <div>
      <h1>Send an Invitation</h1>
      <input 
        type="email" 
        placeholder="Enter email to invite" 
        value={email}
        onChange={(e) => setEmail(e.target.value)}
      />
      <button onClick={handleInvite}>Send Invite</button>
      {statusMessage && <p>{statusMessage}</p>}
      <p>Invitation Status: {inviteStatus}</p>
    </div>
  )
}

Invite Confirmed

If accepted, the system verifies the invitation, potentially involving further setup for the invitee.

Cancel Invitation

At any point after sending the invite and before its acceptance, the inviter can opt to cancel the invitation. We can use cancelUserInvite() to cancel a user invitation.

const cancleInvitation = async() => {
    const cancelStatus = await roqBrowserClient.roqPlatform.cancelUserInvite({
        userInviteId: "db7a682d-6dca-4259-b15b-83aef12d1f5c"
    })
    return cancelStatus
}

End of Flow

The process wraps up either with the invitee successfully onboarded, the invitation declined, or the invitation canceled.

Please note that the user invites API is part of the ROQ platform API and cannot be generated. You can read the documentation about the API here.