Skip to content

Commit

Permalink
refactor(authentication): ent-4899 align hook components (#921)
Browse files Browse the repository at this point in the history
* authContext, bundle api calls, logic into single hook
  • Loading branch information
cdcabrera committed May 25, 2022
1 parent 243a332 commit e5f787a
Show file tree
Hide file tree
Showing 6 changed files with 73 additions and 104 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -49,16 +49,9 @@ exports[`Authentication Component should render a basic component: basic 1`] = `
exports[`Authentication Component should render a component authorized: authorized 1`] = `
<Authentication
appName="subscriptions"
authorizeUser={[Function]}
hideGlobalFilter={[Function]}
initializeChrome={[Function]}
isDisabled={false}
onNavigation={[Function]}
setAppName={[Function]}
t={[Function]}
useAuth={[Function]}
useDispatch={[Function]}
useHistory={[Function]}
useGetAuthorization={[Function]}
>
<span
className="test"
Expand All @@ -71,16 +64,9 @@ exports[`Authentication Component should render a component authorized: authoriz
exports[`Authentication Component should render a component error: error 1`] = `
<Authentication
appName="subscriptions"
authorizeUser={[Function]}
hideGlobalFilter={[Function]}
initializeChrome={[Function]}
isDisabled={false}
onNavigation={[Function]}
setAppName={[Function]}
t={[Function]}
useAuth={[Function]}
useDispatch={[Function]}
useHistory={[Function]}
useGetAuthorization={[Function]}
>
<MessageView
icon={null}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,8 +112,8 @@ Object {
Object {},
[Function],
],
"useAuth": [Function],
"useAuthContext": [Function],
"useGetAuthorization": [Function],
"useSession": [Function],
}
`;
12 changes: 6 additions & 6 deletions src/components/authentication/__tests__/authentication.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ describe('Authentication Component', () => {

it('should render a component error', async () => {
const props = {
useAuth: () => ({
useGetAuthorization: () => ({
error: true,
pending: false,
data: {
Expand Down Expand Up @@ -50,7 +50,7 @@ describe('Authentication Component', () => {

it('should return a redirect on 418 error', async () => {
const props = {
useAuth: () => ({
useGetAuthorization: () => ({
error: true,
pending: false,
data: {
Expand All @@ -71,7 +71,7 @@ describe('Authentication Component', () => {

it('should return a redirect on a specific 403 error and error code', async () => {
const props = {
useAuth: () => ({
useGetAuthorization: () => ({
error: true,
pending: false,
data: {
Expand Down Expand Up @@ -101,7 +101,7 @@ describe('Authentication Component', () => {

it('should return a message on 401 error', async () => {
const props = {
useAuth: () => ({
useGetAuthorization: () => ({
error: true,
pending: false,
data: {
Expand All @@ -122,7 +122,7 @@ describe('Authentication Component', () => {

it('should render a component pending', async () => {
const props = {
useAuth: () => ({
useGetAuthorization: () => ({
error: false,
pending: true,
data: {
Expand All @@ -143,7 +143,7 @@ describe('Authentication Component', () => {

it('should render a component authorized', async () => {
const props = {
useAuth: () => ({
useGetAuthorization: () => ({
error: false,
pending: false,
data: {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { context, useAuth, useSession } from '../authenticationContext';
import { context, useGetAuthorization, useSession } from '../authenticationContext';
import { rhsmConstants } from '../../../services/rhsm/rhsmConstants';

describe('AuthenticationContext', () => {
Expand All @@ -8,7 +8,7 @@ describe('AuthenticationContext', () => {

it('should apply a hook for retrieving auth data from multiple selectors', () => {
const { result: errorResponse } = shallowHook(() =>
useAuth({
useGetAuthorization({
useSelectorsResponse: () => ({
error: true,
data: {
Expand All @@ -30,7 +30,7 @@ describe('AuthenticationContext', () => {
expect(errorResponse).toMatchSnapshot('error response');

const { result: successResponse } = shallowHook(() =>
useAuth({
useGetAuthorization({
useSelectorsResponse: () => ({
fulfilled: true,
data: {
Expand All @@ -49,7 +49,7 @@ describe('AuthenticationContext', () => {

expect(successResponse).toMatchSnapshot('success response');

const { result: mockStoreSuccessResponse } = shallowHook(() => useAuth(), {
const { result: mockStoreSuccessResponse } = shallowHook(() => useGetAuthorization(), {
state: {
user: {
auth: {
Expand Down Expand Up @@ -85,7 +85,7 @@ describe('AuthenticationContext', () => {

expect(mockStoreSuccessResponse).toMatchSnapshot('mock store success response');

const { result: mockStoreErrorResponse } = shallowHook(() => useAuth(), {
const { result: mockStoreErrorResponse } = shallowHook(() => useGetAuthorization(), {
state: {
user: {
auth: {
Expand Down
80 changes: 11 additions & 69 deletions src/components/authentication/authentication.js
Original file line number Diff line number Diff line change
@@ -1,71 +1,31 @@
import React, { useState } from 'react';
import React from 'react';
import PropTypes from 'prop-types';
import { BinocularsIcon } from '@patternfly/react-icons';
import { Maintenance } from '@redhat-cloud-services/frontend-components/Maintenance';
import { NotAuthorized } from '@redhat-cloud-services/frontend-components/NotAuthorized';
import { useMount, useUnmount } from 'react-use';
import { reduxActions, storeHooks } from '../../redux';
import { routerHooks } from '../../hooks/useRouter';
import { routerHelpers, Redirect } from '../router';
import { rhsmConstants } from '../../services/rhsm/rhsmConstants';
import { helpers } from '../../common';
import MessageView from '../messageView/messageView';
import { translate } from '../i18n/i18n';
import { AuthenticationContext, useAuth } from './authenticationContext';
import { AuthenticationContext, useGetAuthorization } from './authenticationContext';

/**
* An authentication pass-through component.
*
* @param {object} props
* @param {string} props.appName
* @param {Function} props.authorizeUser
* @param {React.ReactNode} props.children
* @param {Function} props.hideGlobalFilter
* @param {Function} props.initializeChrome
* @param {boolean} props.isDisabled
* @param {Function} props.onNavigation
* @param {Function} props.setAppName
* @param {Function} props.t
* @param {Function} props.useAuth
* @param {Function} props.useDispatch
* @param {Function} props.useHistory
* @param {Function} props.useGetAuthorization
* @returns {React.ReactNode}
*/
const Authentication = ({
appName,
authorizeUser,
children,
hideGlobalFilter,
initializeChrome,
isDisabled,
onNavigation,
setAppName,
t,
useAuth: useAliasAuth,
useDispatch: useAliasDispatch,
useHistory: useAliasHistory
}) => {
const [unregister, setUnregister] = useState(() => helpers.noop);
const dispatch = useAliasDispatch();
const history = useAliasHistory();

const { pending, data: authData = {} } = useAliasAuth();
const { authorized = {}, errorCodes, errorStatus } = authData;
const Authentication = ({ appName, children, isDisabled, t, useGetAuthorization: useAliasGetAuthorization }) => {
const { pending, data = {} } = useAliasGetAuthorization();
const { authorized = {}, errorCodes, errorStatus } = data;
const { [appName]: isAuthorized } = authorized;

useMount(async () => {
if (!isAuthorized) {
await dispatch(authorizeUser());
}

dispatch([initializeChrome(), setAppName(appName), hideGlobalFilter()]);
setUnregister(() => dispatch(onNavigation(event => history.push(event.navId))));
});

useUnmount(() => {
unregister();
});

const renderContent = () => {
if (isDisabled) {
return (
Expand Down Expand Up @@ -97,50 +57,32 @@ const Authentication = ({
);
};

return <AuthenticationContext.Provider value={authData}>{renderContent()}</AuthenticationContext.Provider>;
return <AuthenticationContext.Provider value={data}>{renderContent()}</AuthenticationContext.Provider>;
};

/**
* Prop types.
*
* @type {{authorizeUser: Function, onNavigation: Function, useHistory: Function, setAppName: Function, t: Function,
* children: React.ReactNode, appName: string, initializeChrome: Function, useDispatch: Function,
* isDisabled: boolean, useAuth: Function,hideGlobalFilter: Function}}
* @type {{useGetAuthorization: Function, children: React.ReactNode, appName: string, isDisabled: boolean}}
*/
Authentication.propTypes = {
appName: PropTypes.string,
authorizeUser: PropTypes.func,
children: PropTypes.node.isRequired,
hideGlobalFilter: PropTypes.func,
initializeChrome: PropTypes.func,
isDisabled: PropTypes.bool,
onNavigation: PropTypes.func,
setAppName: PropTypes.func,
t: PropTypes.func,
useDispatch: PropTypes.func,
useHistory: PropTypes.func,
useAuth: PropTypes.func
useGetAuthorization: PropTypes.func
};

/**
* Default props.
*
* @type {{authorizeUser: Function, onNavigation: Function, useHistory: Function, setAppName: Function, t: Function,
* appName: string, initializeChrome: Function, useDispatch: Function, isDisabled: boolean, useAuth: Function,
* hideGlobalFilter: Function}}
* @type {{useGetAuthorization: Function, t: Function, appName: string, isDisabled: boolean}}
*/
Authentication.defaultProps = {
appName: routerHelpers.appName,
authorizeUser: reduxActions.platform.authorizeUser,
hideGlobalFilter: reduxActions.platform.hideGlobalFilter,
initializeChrome: reduxActions.platform.initializeChrome,
isDisabled: helpers.UI_DISABLED,
onNavigation: reduxActions.platform.onNavigation,
setAppName: reduxActions.platform.setAppName,
t: translate,
useDispatch: storeHooks.reactRedux.useDispatch,
useHistory: routerHooks.useHistory,
useAuth
useGetAuthorization
};

export { Authentication as default, Authentication };
55 changes: 48 additions & 7 deletions src/components/authentication/authenticationContext.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import React, { useContext } from 'react';
import { storeHooks } from '../../redux';
import React, { useContext, useState } from 'react';
import { useMount, useUnmount } from 'react-use';
import { reduxActions, storeHooks } from '../../redux';
import { routerHooks } from '../../hooks/useRouter';
import { helpers } from '../../common';
import { routerHelpers } from '../router';

/**
* Base context.
Expand All @@ -19,14 +22,34 @@ const AuthenticationContext = React.createContext(DEFAULT_CONTEXT);
const useAuthContext = () => useContext(AuthenticationContext);

/**
* Return a combined state store that includes authorization, locale, and API errors
* Initialize an app, and return a combined state store that includes authorization, locale, and API errors
*
* @param {Function} useSelectorsAllSettledResponse
* @param {object} options
* @param {string} options.appName
* @param {Function} options.authorizeUser
* @param {Function} options.hideGlobalFilter
* @param {Function} options.initializeChrome
* @param {Function} options.onNavigation
* @param {Function} options.setAppName
* @param {Function} options.useDispatch
* @param {Function} options.useHistory
* @param {Function} options.useSelectorsResponse
* @returns {{data: {errorCodes, errorStatus: *, locale}, pending: boolean, fulfilled: boolean, error: boolean}}
*/
const useAuth = ({
const useGetAuthorization = ({
appName = routerHelpers.appName,
authorizeUser = reduxActions.platform.authorizeUser,
hideGlobalFilter = reduxActions.platform.hideGlobalFilter,
initializeChrome = reduxActions.platform.initializeChrome,
onNavigation = reduxActions.platform.onNavigation,
setAppName = reduxActions.platform.setAppName,
useDispatch: useAliasDispatch = storeHooks.reactRedux.useDispatch,
useHistory: useAliasHistory = routerHooks.useHistory,
useSelectorsResponse: useAliasSelectorsResponse = storeHooks.reactRedux.useSelectorsResponse
} = {}) => {
const [unregister, setUnregister] = useState(() => helpers.noop);
const history = useAliasHistory();
const dispatch = useAliasDispatch();
const { data, error, fulfilled, pending, responses } = useAliasSelectorsResponse([
{ id: 'auth', selector: ({ user }) => user?.auth },
{ id: 'locale', selector: ({ user }) => user?.locale },
Expand All @@ -36,6 +59,16 @@ const useAuth = ({
}
]);

useMount(async () => {
await dispatch(authorizeUser());
dispatch([initializeChrome(), setAppName(appName), hideGlobalFilter()]);
setUnregister(() => dispatch(onNavigation(event => history.push(event.navId))));
});

useUnmount(() => {
unregister();
});

const [user = {}, app = {}] = (Array.isArray(data.auth) && data.auth) || [];
const errorStatus = (error && responses?.id?.errors?.status) || null;

Expand Down Expand Up @@ -70,8 +103,16 @@ const context = {
AuthenticationContext,
DEFAULT_CONTEXT,
useAuthContext,
useAuth,
useGetAuthorization,
useSession
};

export { context as default, context, AuthenticationContext, DEFAULT_CONTEXT, useAuthContext, useAuth, useSession };
export {
context as default,
context,
AuthenticationContext,
DEFAULT_CONTEXT,
useAuthContext,
useGetAuthorization,
useSession
};

0 comments on commit e5f787a

Please sign in to comment.