Skip to content

Commit

Permalink
Merge branch 'master' into STCOR-905
Browse files Browse the repository at this point in the history
  • Loading branch information
ryandberger authored Nov 6, 2024
2 parents 5222342 + 8524811 commit 59936bf
Show file tree
Hide file tree
Showing 13 changed files with 183 additions and 250 deletions.
12 changes: 8 additions & 4 deletions src/RootWithIntl.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ import {
HandlerManager,
TitleManager,
Logout,
LogoutTimeout,
OverlayContainer,
CreateResetPassword,
CheckEmailStatusPage,
Expand Down Expand Up @@ -99,7 +98,7 @@ const RootWithIntl = ({ stripes, token = '', isAuthenticated = false, disableAut
<TitledRoute
name="logoutTimeout"
path="/logout-timeout"
component={<LogoutTimeout />}
component={<Logout />}
/>
<TitledRoute
name="settings"
Expand All @@ -109,7 +108,7 @@ const RootWithIntl = ({ stripes, token = '', isAuthenticated = false, disableAut
<TitledRoute
name="logout"
path="/logout"
component={<Logout history={history} />}
component={<Logout />}
/>
<ModuleRoutes stripes={connectedStripes} />
</Switch>
Expand Down Expand Up @@ -156,10 +155,15 @@ const RootWithIntl = ({ stripes, token = '', isAuthenticated = false, disableAut
path="/check-email"
component={<CheckEmailStatusPage />}
/>
<TitledRoute
name="logout"
path="/logout"
component={<Logout />}
/>
<TitledRoute
name="logoutTimeout"
path="/logout-timeout"
component={<LogoutTimeout />}
component={<Logout />}
/>
<TitledRoute
name="login"
Expand Down
File renamed without changes.
69 changes: 58 additions & 11 deletions src/components/Logout/Logout.js
Original file line number Diff line number Diff line change
@@ -1,36 +1,83 @@
import { useEffect, useState } from 'react';
import { Redirect } from 'react-router';
import { useLocation } from 'react-router';
import { FormattedMessage } from 'react-intl';
import { branding } from 'stripes-config';

import {
Button,
Col,
Headline,
LoadingView,
Row,
} from '@folio/stripes-components';

import OrganizationLogo from '../OrganizationLogo';
import { useStripes } from '../../StripesContext';
import { getLocale, logout } from '../../loginServices';
import { logout } from '../../loginServices';

import styles from './Logout.css';

/**
* Logout
* Call logout, then redirect to root.
* Make an API call to /logout to terminate the session server-side and render
* a "you've logged out" message. This component can be invoked from different
* UI routes and will display a different message depending on that route:
*
* This corresponds to the '/logout' route, allowing that route to be directly
* accessible rather than only accessible through the menu action.
* /logout: a user chose to end the session
* /logout-timeout: stripes redirects to this location due to idle-session timeout
*
*/
const Logout = () => {
const stripes = useStripes();
const [didLogout, setDidLogout] = useState(false);
const location = useLocation();

const messageId = location.pathName === '/logout-timeout' ? 'stripes-core.rtr.idleSession.sessionExpiredSoSad' : 'stripes-core.logoutComplete';

useEffect(
() => {
getLocale(stripes.okapi.url, stripes.store, stripes.okapi.tenant)
.then(logout(stripes.okapi.url, stripes.store))
.then(setDidLogout(true));
if (stripes.okapi.isAuthenticated) {
// returns a promise, which we ignore
logout(stripes.okapi.url, stripes.store)
.then(setDidLogout(true));
} else {
setDidLogout(true);
}
},
// no dependencies because we only want to start the logout process once.
// we don't care about changes to history or stripes; certainly those
// could be updated as part of the logout process
// we don't care about changes to stripes; certainly it'll be updated as
// part of the logout process
// eslint-disable-next-line react-hooks/exhaustive-deps
[]
);

return didLogout ? <Redirect to="/" /> : <FormattedMessage id="stripes-core.logoutPending" />;
if (!didLogout) {
return <LoadingView />;
}

return (
<main>
<div className={styles.wrapper} style={branding.style?.login ?? {}}>
<div className={styles.container}>
<Row center="xs">
<Col xs={12}>
<OrganizationLogo />
</Col>
</Row>
<Row center="xs">
<Col xs={12}>
<Headline size="large"><FormattedMessage id={messageId} /></Headline>
</Col>
</Row>
<Row center="xs">
<Col xs={12}>
<Button to="/"><FormattedMessage id="stripes-core.rtr.idleSession.logInAgain" /></Button>
</Col>
</Row>
</div>
</div>
</main>
);
};

export default Logout;
80 changes: 49 additions & 31 deletions src/components/Logout/Logout.test.js
Original file line number Diff line number Diff line change
@@ -1,46 +1,64 @@
import { render, screen, waitFor } from '@folio/jest-config-stripes/testing-library/react';
import { render, screen } from '@folio/jest-config-stripes/testing-library/react';
import { useLocation } from 'react-router';

import Harness from '../../../test/jest/helpers/harness';
import Logout from './Logout';
import { useStripes } from '../../StripesContext';
import { logout } from '../../loginServices';

jest.mock('../OrganizationLogo');
jest.mock('../../StripesContext');
jest.mock('react-router');

jest.mock('../../loginServices', () => ({
...(jest.requireActual('../../loginServices')),
getLocale: () => Promise.resolve(),
logout: jest.fn()
logout: jest.fn(() => Promise.resolve()),
}));

jest.mock('react-router', () => ({
...(jest.requireActual('react-router')),
Redirect: () => <div>Redirect</div>
}));
describe('Logout', () => {
describe('Direct logout', () => {
beforeEach(() => {
const mockUseLocation = useLocation;
mockUseLocation.mockReturnValue({ pathName: '/logout' });
});

const stripes = {
config: {
rtr: {
idleModalTTL: '3s',
idleSessionTTL: '3s',
}
},
okapi: {
url: 'https://blah',
},
logger: { log: jest.fn() },
store: {
getState: jest.fn(),
},
};
it('if not authenticated, renders a logout message', async () => {
const mockUseStripes = useStripes;
mockUseStripes.mockReturnValue({ okapi: { isAuthenticated: false } });

describe('Logout', () => {
it('calls logout and redirects', async () => {
logout.mockReturnValue(Promise.resolve());
render(<Logout />);
screen.getByText('stripes-core.logoutComplete');
});

it('if authenticated, calls logout then renders a logout message', async () => {
const mockUseStripes = useStripes;
mockUseStripes.mockReturnValue({ okapi: { isAuthenticated: true } });

render(<Harness stripes={stripes}><Logout /></Harness>);
render(<Logout />);
expect(logout).toHaveBeenCalled();
screen.getByText('stripes-core.logoutComplete');
});
});

await waitFor(() => {
screen.getByText('Redirect');
describe('Timeout logout', () => {
beforeEach(() => {
const mockUseLocation = useLocation;
mockUseLocation.mockReturnValue({ pathName: '/logout-timeout' });
});

expect(logout).toHaveBeenCalledTimes(1);
it('if not authenticated, renders a timeout message', async () => {
const mockUseStripes = useStripes;
mockUseStripes.mockReturnValue({ okapi: { isAuthenticated: false } });

render(<Logout />);
screen.getByText('stripes-core.rtr.idleSession.sessionExpiredSoSad');
});

it('if authenticated, calls logout then renders a timeout message', async () => {
const mockUseStripes = useStripes;
mockUseStripes.mockReturnValue({ okapi: { isAuthenticated: true } });

render(<Logout />);
expect(logout).toHaveBeenCalled();
screen.getByText('stripes-core.rtr.idleSession.sessionExpiredSoSad');
});
});
});
90 changes: 0 additions & 90 deletions src/components/LogoutTimeout/LogoutTimeout.js

This file was deleted.

71 changes: 0 additions & 71 deletions src/components/LogoutTimeout/LogoutTimeout.test.js

This file was deleted.

1 change: 0 additions & 1 deletion src/components/LogoutTimeout/index.js

This file was deleted.

Loading

0 comments on commit 59936bf

Please sign in to comment.