Skip to content

Commit

Permalink
Merge pull request #208 from adhocteam/dcloud/139-request-permissions…
Browse files Browse the repository at this point in the history
…-page

Request Permissions view & HTTPError handler
  • Loading branch information
dcloud committed Mar 8, 2021
2 parents e7db658 + ff0bc8f commit 5956089
Show file tree
Hide file tree
Showing 6 changed files with 64 additions and 23 deletions.
17 changes: 13 additions & 4 deletions frontend/src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { BrowserRouter, Route, Switch } from 'react-router-dom';
import { Helmet } from 'react-helmet';

import { fetchUser, fetchLogout } from './fetchers/Auth';
import { HTTPError } from './fetchers';

import UserContext from './UserContext';
import SiteNav from './components/SiteNav';
Expand All @@ -22,9 +23,11 @@ import 'react-dates/initialize';
import 'react-dates/lib/css/_datepicker.css';
import './App.css';
import LandingLayout from './components/LandingLayout';
import RequestPermissions from './components/RequestPermissions';

function App() {
const [user, updateUser] = useState();
const [authError, updateAuthError] = useState();
const [loading, updateLoading] = useState(true);
const [loggedOut, updateLoggedOut] = useState(false);
const authenticated = user !== undefined;
Expand All @@ -35,8 +38,12 @@ function App() {
try {
const u = await fetchUser();
updateUser(u);
updateAuthError();
} catch (e) {
updateUser();
if (e instanceof HTTPError && e.status === 403) {
updateAuthError(e.status);
}
} finally {
updateLoading(false);
}
Expand All @@ -47,6 +54,7 @@ function App() {
const logout = async (timeout = false) => {
await fetchLogout();
updateUser();
updateAuthError();
updateLoggedOut(true);
updateTimedOut(timeout);
};
Expand Down Expand Up @@ -124,10 +132,11 @@ function App() {
<div className="grid-row maxw-widescreen flex-align-start smart-hub-offset-nav tablet:smart-hub-offset-nav desktop:smart-hub-offset-nav margin-top-9">
<div className="grid-col-12 margin-top-2 margin-right-2">
<section className="usa-section padding-top-3">
{!authenticated
&& <Unauthenticated loggedOut={loggedOut} timedOut={timedOut} />}
{authenticated
&& renderAuthenticatedRoutes()}
{!authenticated && (authError === 403
? <RequestPermissions />
: <Unauthenticated loggedOut={loggedOut} timedOut={timedOut} />
)}
{authenticated && renderAuthenticatedRoutes()}
</section>
</div>
</div>
Expand Down
5 changes: 3 additions & 2 deletions frontend/src/__tests__/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,9 @@ describe('App', () => {
render(<App />);
});

it('displays the login button for now. in the future this should show the "request permissions" UI', async () => {
expect(await screen.findByText(loginText)).toBeVisible();
it('displays the "request permissions" page', async () => {
expect(await screen.findByText('You need permission to access the TTA Smart Hub.')).toBeVisible();
expect(await screen.findByText('Request Permission')).toBeVisible();
});
});
});
31 changes: 31 additions & 0 deletions frontend/src/components/RequestPermissions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import React from 'react';

function RequestPermissions() {
return (
<>
<div className="smart-hub-dimmer position-fixed top-0 right-0 bottom-0 left-0 z-auto bg-ink opacity-50" />
<div role="dialog" aria-labelledby="permissions-message" aria-describedby="permissions-description" className="position-relative smart-hub-maxw-placard margin-x-auto margin-top-7 z-top bg-white">
<div className="maxw-mobile-lg margin-x-auto padding-y-7">
<h1 id="permissions-message" className="font-serif-xl text-center margin-y-4 margin-x-2">
You need permission to access the TTA Smart Hub.
</h1>
<div className="text-center">
<p className="margin-bottom-4">
<a className="usa-button smart-hub-bg-blue-primary display-inline-block margin-x-1" href="https://app.smartsheetgov.com/b/form/f0b4725683f04f349a939bd2e3f5425a">
Request Permission
</a>
</p>
<p className="text-bold">
First time logging in?
</p>
<p id="permissions-description">
Request permission to use the system.
</p>
</div>
</div>
</div>
</>
);
}

export default RequestPermissions;
11 changes: 10 additions & 1 deletion frontend/src/fetchers/index.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,18 @@
export class HTTPError extends Error {
constructor(statusCode, message, ...params) {
super(message, ...params);
this.name = 'HTTPError';
this.status = statusCode;
this.statusText = message;
}
}

export const get = async (url) => {
const res = await fetch(url, {
credentials: 'same-origin',
});
if (!res.ok) {
throw new Error(res.statusText);
throw new HTTPError(res.status, res.statusText);
}
return res;
};
Expand Down
13 changes: 0 additions & 13 deletions frontend/src/pages/Unauthenticated/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,19 +40,6 @@ function Unauthenticated({ loggedOut, timedOut }) {
<Link referrerPolicy="same-origin" className="usa-button smart-hub-bg-blue-primary display-block margin-x-1 margin-top-4" variant="unstyled" href="/api/login">
Log In with HSES
</Link>
<div className="margin-top-9">
<p className="text-bold">
First time logging in?
</p>
<p>
You must request permission in order to use the TTA Smart Hub.
</p>
<p>
<a href="https://app.smartsheetgov.com/b/form/f0b4725683f04f349a939bd2e3f5425a">
Request Permission
</a>
</p>
</div>
</div>
</div>
</div>
Expand Down
10 changes: 7 additions & 3 deletions frontend/src/permissions.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ export const allRegionsUserHasPermissionTo = (user) => {
* @returns {number} - region id if the user has read/write access for a region, -1 otherwise
*/

export const getRegionWithReadWrite = (user) => {
const getRegionWithReadWrite = (user) => {
const { permissions } = user;
if (!permissions) return -1;

Expand All @@ -64,11 +64,15 @@ export const getRegionWithReadWrite = (user) => {
* @param {*} user - user object
* @returns {boolean} - True if the user has re/write access for a region, false otherwise
*/
export const hasReadWrite = (user) => {
const hasReadWrite = (user) => {
const { permissions } = user;
return permissions && permissions.find(
(p) => p.scopeId === SCOPE_IDS.READ_WRITE_ACTIVITY_REPORTS,
) !== undefined;
};

export default isAdmin;
export {
isAdmin as default,
getRegionWithReadWrite,
hasReadWrite,
};

0 comments on commit 5956089

Please sign in to comment.