Skip to content

Commit

Permalink
Merge pull request #182 from adhocteam/kw-new-report
Browse files Browse the repository at this point in the history
Add conditional display of the "New Activity Report" button
  • Loading branch information
kryswisnaskas authored Feb 19, 2021
2 parents 8a613cd + 1beabe9 commit 15ee16d
Show file tree
Hide file tree
Showing 8 changed files with 146 additions and 54 deletions.
4 changes: 2 additions & 2 deletions cucumber/features/steps/activityReportSteps.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@ Given('I am on the landing page', async () => {
page.waitForNavigation(),
page.click(selector),
]);

await scope.context.currentPage.waitForSelector('h1');

const selectorNewReport = 'a[href$="activity-reports/new"]';
await Promise.all([
page.waitForNavigation(),
page.click(selectorNewReport),
await page.goto(`${scope.uri}/activity-reports/new`),
]);
await scope.context.currentPage.waitForSelector('h1');
});
Expand Down
28 changes: 27 additions & 1 deletion frontend/src/__tests__/permissions.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import isAdmin from '../permissions';
import isAdmin, { hasReadWrite } from '../permissions';

describe('permissions', () => {
describe('isAdmin', () => {
Expand All @@ -20,4 +20,30 @@ describe('permissions', () => {
expect(isAdmin(user)).toBeFalsy();
});
});

describe('hasReadWrite', () => {
it('returns true if the user has read/write to a region', () => {
const user = {
permissions: [
{
scopeId: 3,
regionId: 1,
},
],
};
expect(hasReadWrite(user)).toBeTruthy();
});

it('returns false if the user does not have read/write to a region', () => {
const user = {
permissions: [
{
scopeId: 2,
regionId: 1,
},
],
};
expect(hasReadWrite(user)).toBeFalsy();
});
});
});
9 changes: 5 additions & 4 deletions frontend/src/pages/Landing/MyAlerts.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ function renderReports(reports) {

const collaboratorsWithTags = collaborators.map((collaborator) => (
<Tag
key={collaborator.id}
key={collaborator.fullName.slice(1, 3) + collaborator.id}
className="smart-hub--table-collection"
>
{collaborator.fullName}
Expand Down Expand Up @@ -89,15 +89,15 @@ function renderReports(reports) {
});
}

function MyAlerts({ reports }) {
function MyAlerts({ reports, newBtn }) {
return (
<>
{ reports && reports.length === 0 && (
<Container className="landing" padding={0}>
<div id="caughtUp">
<div><h2>You&apos;re all caught up!</h2></div>
<p id="beginNew">Would you like to begin a new activity report?</p>
<NewReport />
{ newBtn && <p id="beginNew">Would you like to begin a new activity report?</p> }
{ newBtn && <NewReport /> }
</div>
</Container>
) }
Expand Down Expand Up @@ -141,6 +141,7 @@ function MyAlerts({ reports }) {

MyAlerts.propTypes = {
reports: PropTypes.arrayOf(PropTypes.object),
newBtn: PropTypes.bool.isRequired,
};

MyAlerts.defaultProps = {
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/pages/Landing/NewReport.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import './index.css';
function NewReport() {
return (
<Link
to="/activity-reports/new"
to="/activity-reports/new/activity-summary"
referrerPolicy="same-origin"
className="usa-button smart-hub--new-report-btn"
variant="unstyled"
Expand Down
3 changes: 2 additions & 1 deletion frontend/src/pages/Landing/__tests__/MyAlerts.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,10 @@ import activityReports from '../mocks';

describe('My Alerts', () => {
beforeEach(() => {
const newBtn = true;
render(
<MemoryRouter>
<MyAlerts reports={activityReports} />
<MyAlerts reports={activityReports} newBtn={newBtn} />
</MemoryRouter>,
);
});
Expand Down
62 changes: 53 additions & 9 deletions frontend/src/pages/Landing/__tests__/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,31 @@ import UserContext from '../../../UserContext';
import Landing from '../index';
import activityReports from '../mocks';

const renderLanding = (user) => {
render(
<MemoryRouter>
<UserContext.Provider value={{ user }}>
<Landing authenticated />
</UserContext.Provider>
</MemoryRouter>,
);
};

describe('Landing Page', () => {
beforeEach(() => {
fetchMock.get('/api/activity-reports', activityReports);
fetchMock.get('/api/activity-reports/alerts', []);
const user = {
name: '[email protected]',
permissions: [
{
scopeId: 3,
regionId: 1,
},
],
};

render(
<MemoryRouter>
<UserContext.Provider value={{ user }}>
<Landing authenticated />
</UserContext.Provider>
</MemoryRouter>,
);
renderLanding(user);
});
afterEach(() => fetchMock.restore());

Expand Down Expand Up @@ -156,18 +166,52 @@ describe('Landing Page error', () => {

it('handles errors by displaying an error message', async () => {
fetchMock.get('/api/activity-reports', 500);
render(<MemoryRouter><Landing authenticated /></MemoryRouter>);
const user = {
name: '[email protected]',
permissions: [
{
scopeId: 3,
regionId: 1,
},
],
};
renderLanding(user);
const alert = await screen.findByRole('alert');
expect(alert).toBeVisible();
expect(alert).toHaveTextContent('Unable to fetch reports');
});

it('displays an empty row if there are no reports', async () => {
fetchMock.get('/api/activity-reports', []);
render(<MemoryRouter><Landing authenticated /></MemoryRouter>);
const user = {
name: '[email protected]',
permissions: [
{
scopeId: 3,
regionId: 1,
},
],
};
renderLanding(user);
const rowCells = await screen.findAllByRole('cell');
expect(rowCells.length).toBe(8);
const grantee = rowCells[0];
expect(grantee).toHaveTextContent('');
});

it('does not displays new activity report button without permission', async () => {
fetchMock.get('/api/activity-reports', activityReports);
const user = {
name: '[email protected]',
permissions: [
{
scopeId: 2,
regionId: 1,
},
],
};
renderLanding(user);

await expect(screen.findAllByText(/New Activity Report/)).rejects.toThrow();
});
});
80 changes: 44 additions & 36 deletions frontend/src/pages/Landing/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,15 @@ import { Link } from 'react-router-dom';
import SimpleBar from 'simplebar-react';
import 'simplebar/dist/simplebar.min.css';

import UserContext from '../../UserContext';
import Container from '../../components/Container';
import { getReports, getReportAlerts } from '../../fetchers/activityReports';
import NewReport from './NewReport';
import 'uswds/dist/css/uswds.css';
import '@trussworks/react-uswds/lib/index.css';
import './index.css';
import MyAlerts from './MyAlerts';
import { hasReadWrite } from '../../permissions';

function renderReports(reports) {
const emptyReport = {
Expand Down Expand Up @@ -167,43 +169,49 @@ function Landing() {
<Helmet>
<title>Landing</title>
</Helmet>
<Grid row gap>
<Grid>
<h1 className="landing">Activity Reports</h1>
</Grid>
<Grid className="smart-hub--create-new-report">
{ reportAlerts && reportAlerts.length > 0 && <NewReport /> }
</Grid>
</Grid>
<Grid row>
{error && (
<Alert type="error" role="alert">
{error}
</Alert>
<UserContext.Consumer>
{({ user }) => (
<>
<Grid row gap>
<Grid>
<h1 className="landing">Activity Reports</h1>
</Grid>
<Grid className="smart-hub--create-new-report">
{reportAlerts && reportAlerts.length > 0 && hasReadWrite(user) && <NewReport />}
</Grid>
</Grid>
<Grid row>
{error && (
<Alert type="error" role="alert">
{error}
</Alert>
)}
</Grid>
<MyAlerts reports={reportAlerts} newBtn={hasReadWrite(user)} />
<SimpleBar>
<Container className="landing inline-size" padding={0}>
<Table className="usa-table usa-table--borderless usa-table--striped">
<caption>Activity reports</caption>
<thead>
<tr>
<th scope="col">Report ID</th>
<th scope="col">Grantee</th>
<th scope="col">Start date</th>
<th scope="col">Creator</th>
<th scope="col">Topic(s)</th>
<th scope="col">Collaborator(s)</th>
<th scope="col">Last saved</th>
<th scope="col">Status</th>
<th scope="col" aria-label="..." />
</tr>
</thead>
<tbody>{renderReports(reports)}</tbody>
</Table>
</Container>
</SimpleBar>
</>
)}
</Grid>
<MyAlerts reports={reportAlerts} />
<SimpleBar>
<Container className="landing inline-size" padding={0}>
<Table className="usa-table usa-table--borderless usa-table--striped">
<caption>Activity reports</caption>
<thead>
<tr>
<th scope="col">Report ID</th>
<th scope="col">Grantee</th>
<th scope="col">Start date</th>
<th scope="col">Creator</th>
<th scope="col">Topic(s)</th>
<th scope="col">Collaborator(s)</th>
<th scope="col">Last saved</th>
<th scope="col">Status</th>
<th scope="col" aria-label="..." />
</tr>
</thead>
<tbody>{renderReports(reports)}</tbody>
</Table>
</Container>
</SimpleBar>
</UserContext.Consumer>
</>
);
}
Expand Down
12 changes: 12 additions & 0 deletions frontend/src/permissions.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,16 @@ const isAdmin = (user) => {
) !== undefined;
};

/**
* Search the user's permissions for a read/write permisions for a region
* @param {*} user - user object
* @returns {boolean} - True if the user has re/write access for a region, false otherwise
*/
export const hasReadWrite = (user) => {
const { permissions } = user;
return permissions && permissions.find(
(p) => p.scopeId === SCOPE_IDS.READ_WRITE_ACTIVITY_REPORTS,
) !== undefined;
};

export default isAdmin;

0 comments on commit 15ee16d

Please sign in to comment.