Skip to content

Commit

Permalink
feat: add a useIsSignedIn custom hook for react (#3093)
Browse files Browse the repository at this point in the history
Add signed in state core functionality
Add a hook to check the signed in state
Add documentation of custom hooks on read me
Add tests for isSignedIn
Update the react-contoso sample to use the mgt-react hook
Add sample stories for HTML and React usages
  • Loading branch information
musale authored Mar 21, 2024
1 parent 056b15e commit 1e695aa
Show file tree
Hide file tree
Showing 12 changed files with 149 additions and 36 deletions.
1 change: 1 addition & 0 deletions packages/mgt-element/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ export * from './utils/LocalizationHelper';
export * from './utils/mgtHtml';
export * from './utils/CustomElement';
export * from './utils/registerComponent';
export * from './utils/isSignedIn';

export { PACKAGE_VERSION } from './utils/version';

Expand Down
22 changes: 22 additions & 0 deletions packages/mgt-element/src/utils/isSignedIn.tests.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/**
* -------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License.
* See License in the project root for license information.
* -------------------------------------------------------------------------------------------
*/

import { expect } from '@open-wc/testing';
import { MockProvider } from '../mock/MockProvider';
import { ProviderState } from '../providers/IProvider';
import { Providers } from '../providers/Providers';
import { isSignedIn } from './isSignedIn';

describe('signedInState', () => {
it('should change', () => {
/* eslint-disable @typescript-eslint/no-unused-expressions */
Providers.globalProvider = new MockProvider(false);
expect(isSignedIn()).to.be.false;
Providers.globalProvider.setState(ProviderState.SignedIn);
expect(isSignedIn()).to.be.true;
});
});
19 changes: 19 additions & 0 deletions packages/mgt-element/src/utils/isSignedIn.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/**
* -------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License.
* See License in the project root for license information.
* -------------------------------------------------------------------------------------------
*/

import { ProviderState } from '../providers/IProvider';
import { Providers } from '../providers/Providers';

/**
* Checks the provider state if it's in signed in.
*
* @returns true if signed in, otherwise false.
*/
export const isSignedIn = (): boolean => {
const provider = Providers.globalProvider;
return provider && provider.state === ProviderState.SignedIn;
};
18 changes: 18 additions & 0 deletions packages/mgt-react/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,24 @@ const App = (props) => {

The `template` prop allows you to specify which template to overwrite. In this case, the `MyEvent` component will be repeated for every event, and the `event` object will be passed as part of the `dataContext` prop.

## Custom hooks

`mgt-react` exposes some custom hooks that you can use in your app:

### `useIsSignedIn`

You can use this hook to check the signed in state:

```tsx
import { Agenda, useIsSignedIn } from '@microsoft/mgt-react';

const App = (props) => {
const [isSignedIn] = useIsSignedIn();

return {isSignedIn && <Agenda></Agenda>}
}
```

## Why

If you've used web components in React, you know that proper interop between web components and React components requires a bit of extra work.
Expand Down
8 changes: 8 additions & 0 deletions packages/mgt-react/src/hooks/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/**
* -------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License.
* See License in the project root for license information.
* -------------------------------------------------------------------------------------------
*/

export * from './useIsSignedIn';
31 changes: 31 additions & 0 deletions packages/mgt-react/src/hooks/useIsSignedIn.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/**
* -------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License.
* See License in the project root for license information.
* -------------------------------------------------------------------------------------------
*/

import { isSignedIn, Providers } from '@microsoft/mgt-element';
import { useState, useEffect } from 'react';

/**
* Hook to check if a user is signed in.
*
* @returns true if a user is signed on, otherwise false.
*/
export const useIsSignedIn = (): [boolean] => {
const [signedIn, setIsSignedIn] = useState(false);
useEffect(() => {
const updateState = () => {
setIsSignedIn(isSignedIn());
};

Providers.onProviderUpdated(updateState);
updateState();

return () => {
Providers.removeProviderUpdatedListener(updateState);
};
}, [setIsSignedIn]);
return [signedIn];
};
1 change: 1 addition & 0 deletions packages/mgt-react/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,6 @@
export * from './Mgt';
export * from './MgtTemplateProps';
export * from './generated/react';
export * from './hooks';
export * from '@microsoft/mgt-components/dist/es6/exports';
export * from '@microsoft/mgt-element';
2 changes: 1 addition & 1 deletion samples/react-contoso/src/Layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React, { Suspense, lazy } from 'react';
import { BrowserRouter, Route, Routes } from 'react-router-dom';
import { Header } from './components/Header';
import { SideNavigation } from './components/SideNavigation';
import { useIsSignedIn } from './hooks/useIsSignedIn';
import { useIsSignedIn } from '@microsoft/mgt-react';
import { NavigationItem } from './models/NavigationItem';
import { getNavigation } from './services/Navigation';
import { FluentProvider, makeStyles, mergeClasses, shorthands } from '@fluentui/react-components';
Expand Down
12 changes: 3 additions & 9 deletions samples/react-contoso/src/components/Header.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
import * as React from 'react';
import { Login, SearchBox } from '@microsoft/mgt-react';
import { Login, SearchBox, useIsSignedIn } from '@microsoft/mgt-react';
import { PACKAGE_VERSION } from '@microsoft/mgt-element';
import { InfoButton } from '@fluentui/react-components/unstable';
import { SimpleLogin } from './SimpleLogin';
import { useIsSignedIn } from '../hooks/useIsSignedIn';
import { useNavigate } from 'react-router-dom';
import { ThemeSwitcher } from './ThemeSwitcher';
import { useAppContext } from '../AppContext';
import { Label, makeStyles, mergeClasses, shorthands, tokens } from '@fluentui/react-components';
import { Label, makeStyles, mergeClasses, shorthands, tokens, InfoLabel } from '@fluentui/react-components';
import { GridDotsRegular } from '@fluentui/react-icons';
import { useLocation } from 'react-router-dom';

Expand Down Expand Up @@ -149,11 +147,7 @@ const HeaderComponent: React.FunctionComponent = () => {

<div className={styles.waffleTitle}>
<Label className={styles.name}>{import.meta.env.VITE_SITE_NAME} </Label>
<InfoButton
className={styles.infoIcon}
size="medium"
info={<>Using the Graph Toolkit v{PACKAGE_VERSION}</>}
/>
<InfoLabel className={styles.infoIcon} size="medium" info={<>Using the Graph Toolkit v{PACKAGE_VERSION}</>} />
</div>
</div>
<div className={styles.search}>
Expand Down
23 changes: 0 additions & 23 deletions samples/react-contoso/src/hooks/useIsSignedIn.ts

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { html } from 'lit';
import { withCodeEditor } from '../../.storybook/addons/codeEditorAddon/codeAddon';

export default {
title: 'Samples / General',
title: 'Samples / General / HTML',
decorators: [withCodeEditor],
parameters: {
viewMode: 'story'
Expand Down Expand Up @@ -89,7 +89,7 @@ export const Localization = () => html`
</script>
`;

export const cache = () => html`
export const Cache = () => html`
<fluent-button id="ClearCacheButton" appearance="accent">Clear Cache</fluent-button>
<div id="status" class="notes"></div>
<span class="notes"
Expand Down Expand Up @@ -169,7 +169,7 @@ clearCacheButton.addEventListener('click', onClearCacheButtonClick);
</script>
`;

export const theme = () => html`
export const Theme = () => html`
<div>
<p>This demonstrates how to set the theme globally without using a theme toggle and customize styling within specific scopes</p>
<p>Please refer to the JS and CSS tabs in the editor for implentation details</p>
Expand Down Expand Up @@ -223,3 +223,17 @@ body {
}
</style>
`;

export const IsSignedIn = () => html`
<p>This demonstrates how to use the <code>isSignedIn</code> utility function in JavaScript. If you're signed in, <code>mgt-person</code> is rendered below.</p>
<div id="person"></div>
<script>
import { isSignedIn } from '@microsoft/mgt-element';
const person = document.getElementById("person");
if(isSignedIn() && person){
const mgtPerson = document.createElement("mgt-person");
mgtPerson.setAttribute("person-query", "me");
person.appendChild(mgtPerson);
}
</script>
`;
28 changes: 28 additions & 0 deletions stories/samples/general.react.stories.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/**
* -------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License.
* See License in the project root for license information.
* -------------------------------------------------------------------------------------------
*/

import { html } from 'lit';
import { withCodeEditor } from '../../.storybook/addons/codeEditorAddon/codeAddon';

export default {
title: 'Samples / General / React',
component: 'person-card',
decorators: [withCodeEditor]
};

export const Hooks = () => html`
<p>This demonstrates how to use the <code>useIsSignedIn</code> hook in React.</p>
<mgt-person-card person-query="me"></mgt-person-card>
<react>
import { PersonCard, useIsSignedIn } from '@microsoft/mgt-react';
const [isSignedIn] = useIsSignedIn();
export default () => (
isSignedIn ? <PersonCard personQuery="me"></PersonCard> : null
);
</react>
`;

0 comments on commit 1e695aa

Please sign in to comment.