From a079ac3890b6aaf9efb22f23ca8af4ea1d7bc001 Mon Sep 17 00:00:00 2001 From: Mostafa Rashed <17770919+mrashed-dev@users.noreply.github.com> Date: Thu, 21 Jul 2022 17:55:36 -0400 Subject: [PATCH] Pre release improvements (#2) After playing with this and getting some internal feedback, the following changes will be made to improve this wrapper before release: * Make it more react-y by: * Using the term `Properties` instead of `Options` * Using the term `Provider` in the class and file name of a `React.Provider` type * Set the state in the `useEffect` hook * Eliminate useless `authState` variable * Make `useNylas` act as a wrapper of the `nylas-js` package instead of re-defining the functions in the provider * Safeguard the setting of the client in the provider * Readme improvements * Update package.json for publishing the package on npm --- README.md | 83 +++++++++++++++++++++++++++++++++++++---- package.json | 10 ++++- src/index.ts | 12 ++---- src/nylas-container.tsx | 44 ---------------------- src/nylas-context.ts | 16 ++------ src/nylas-provider.tsx | 38 +++++++++++++++++++ 6 files changed, 129 insertions(+), 74 deletions(-) delete mode 100644 src/nylas-container.tsx create mode 100644 src/nylas-provider.tsx diff --git a/README.md b/README.md index eefc2b2..1ce801c 100644 --- a/README.md +++ b/README.md @@ -37,18 +37,87 @@ The Nylas React SDK provides an easy way to implement authentication in your rea ### Components -The Nylas React SDK provides the following component: +The Nylas React SDK currently provides the following component: -* [NylasContainer](src/nylas-container.tsx) - This is a component that utilizes React Context API to maintain a state for authentication and the [Nylas JS](https://github.com/nylas/nylas-js) client. This context can be accessed via the [useNylas](https://github.com/nylas/nylas-react#useNylas) hook. +* [NylasProvider](src/nylas-provider.tsx) - This is a component that utilizes React Context API to maintain a state for authentication and the [Nylas JS](https://github.com/nylas/nylas-js) client. This context can be accessed via the [useNylas](https://github.com/nylas/nylas-react#useNylas) hook. ### Hooks These are the following options that can be passed in to configure an instance of the Nylas JS SDK -* useNylas - returns an object with the following: - * client - The Nylas JS client instance - * authState - The current authentication state - * authWithRedirect - The function for building, and redirecting to, the authentication URL - * exchangeCodeFromUrlForToken - The function for parsing the code from the authentication URL and exchanging it for an access token +* useNylas - returns `Nylas`; an instance of the [Nylas JavaScript SDK](https://github.com/nylas/nylas-js) + +### Example +Here's how you can get started with integrating the React SDK into your application for the purpose of authenticating. For this example we're going to wrap it around the entire app, but feel free to wrap the component where you see fit. + +#### index.tsx +```typescript jsx +import React from 'react'; +import ReactDOM from 'react-dom/client'; +import App from './App'; + +import {NylasProvider} from "@nylas/nylas-react"; + +const root = ReactDOM.createRoot( + document.getElementById('root') as HTMLElement +); +root.render( + + + + + +); +``` + +#### App.tsx +```typescript jsx +import React, { useEffect } from 'react'; + +import {useNylas} from "@nylas/nylas-react"; + +function App() { + const { authWithRedirect, exchangeCodeFromUrlForToken } = useNylas(); + const [email, setEmail] = React.useState(''); + + useEffect(() => { + const params = new URLSearchParams(window.location.search); + if (params.has("code")) { + exchangeCodeFromUrlForToken().then((token: string) => { + // do something with the response + }); + } + }, [exchangeCodeFromUrlForToken]); + + return ( +
+
+

Read emails sample app

+

Authenticate your email to read

+
+
{ + e.preventDefault() + authWithRedirect({emailAddress: email, successRedirectUrl: "/success"}) + }} + > + setEmail(e.target.value)} + /> + +
+
+
+
+ ); +} + +export default App; + +``` ## 💙 Contributing diff --git a/package.json b/package.json index 0a3604d..798c59a 100644 --- a/package.json +++ b/package.json @@ -4,8 +4,12 @@ "description": "React SDK for the Nylas Platform API", "main": "lib/index.js", "types": "lib/index.d.ts", + "files": [ + "lib" + ], "scripts": { "build": "tsc", + "prepare": "npm run build", "lint": "eslint --ext .js,.ts -f visualstudio .", "lint:fix": "npm run lint -- --fix", "lint:ci": "npm run lint:fix -- --quiet", @@ -13,11 +17,10 @@ "lint:prettier:check": "prettier --check '**/*.{ts,js}'" }, "dependencies": { - "@nylas/nylas-js": "^0.1.0" + "@nylas/nylas-js": "^0.2.0" }, "devDependencies": { "typescript": "^4.7.4", - "react": "^18.2.0", "@types/react": "^18.0.12", "@typescript-eslint/eslint-plugin": "^5.30.7", "eslint": "^8.20.0", @@ -26,6 +29,9 @@ "eslint-plugin-react": "^7.30.1", "prettier": "^2.7.1" }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, "repository": { "type": "git", "url": "git+https://github.com/nylas/nylas-react.git" diff --git a/src/index.ts b/src/index.ts index 53d61f8..35d04ed 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,12 +1,8 @@ export { - default as NylasContainer, - NylasContainerOptions, -} from './nylas-container'; -export { - default as NylasContext, - NylasContextInterface, - useNylas, -} from './nylas-context'; + default as NylasProvider, + NylasProviderProperties, +} from './nylas-provider'; +export { default as NylasContext, useNylas } from './nylas-context'; export { NylasProps, AuthUrlOptions, diff --git a/src/nylas-container.tsx b/src/nylas-container.tsx deleted file mode 100644 index 2c94461..0000000 --- a/src/nylas-container.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import React, { useCallback, useState } from "react"; -import NylasContext from "./nylas-context"; -import Nylas, { AuthUrlOptions, ExchangeCodeOptions } from "@nylas/nylas-js"; - -export interface NylasContainerOptions { - serverBaseUrl: string; - children?: React.ReactNode; -} - -const NylasContainer = (opts: NylasContainerOptions): JSX.Element => { - const {children, ...nylasProps} = opts; - const [client] = useState(() => new Nylas(nylasProps)); - const [authState, setAuthState] = useState(false); - - const authWithRedirect = useCallback( - async (opts: AuthUrlOptions): Promise => client.authWithRedirect(opts), - [client] - ); - - const exchangeCodeFromUrlForToken = useCallback( - async (opts?: ExchangeCodeOptions): Promise => { - const accessToken = await client.exchangeCodeFromUrlForToken(opts); - if(accessToken !== false) { - setAuthState(true); - } - - return accessToken; - }, - [client, authState] - ) - - return ( - - {children} - - ) -} - -export default NylasContainer; \ No newline at end of file diff --git a/src/nylas-context.ts b/src/nylas-context.ts index acf7f78..e77e5cb 100644 --- a/src/nylas-context.ts +++ b/src/nylas-context.ts @@ -1,18 +1,8 @@ import * as React from 'react'; -import Nylas, { AuthUrlOptions, ExchangeCodeOptions } from '@nylas/nylas-js'; +import Nylas from '@nylas/nylas-js'; -export interface NylasContextInterface { - client: Nylas; - authState: boolean; - authWithRedirect(opts: AuthUrlOptions): Promise; - exchangeCodeFromUrlForToken( - opts?: ExchangeCodeOptions - ): Promise; -} +const NylasContext = React.createContext(null); -const NylasContext = React.createContext(null); - -export const useNylas = (): NylasContextInterface => - React.useContext(NylasContext) as NylasContextInterface; +export const useNylas = (): Nylas => React.useContext(NylasContext) as Nylas; export default NylasContext; diff --git a/src/nylas-provider.tsx b/src/nylas-provider.tsx new file mode 100644 index 0000000..398fd35 --- /dev/null +++ b/src/nylas-provider.tsx @@ -0,0 +1,38 @@ +import React, {useEffect, useState} from "react"; +import NylasContext from "./nylas-context"; +import Nylas from "@nylas/nylas-js"; + +export interface NylasProviderProperties { + serverBaseUrl: string; + children?: React.ReactNode; +} + +const NylasProvider = (props: NylasProviderProperties): JSX.Element => { + const {children, ...nylasProps} = props; + const [client, setClient] = useState(new Nylas(nylasProps)); + + const safeSetState = (state: Nylas) => { + if(client) { + console.warn("Client already exists."); + return; + } + + setClient(state); + }; + + useEffect(() => { + if(!nylasProps || !nylasProps.serverBaseUrl) { + return; + } + + safeSetState(new Nylas(nylasProps)); + }, [nylasProps]) + + return ( + + {children} + + ) +} + +export default NylasProvider; \ No newline at end of file