Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add sorting to my alerts #212

Merged
merged 16 commits into from
Mar 12, 2021
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions frontend/src/Constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,3 +78,6 @@ export const REPORT_STATUSES = {
NEEDS_ACTION: 'needs_action',
APPROVED: 'approved',
};

export const REPORTS_PER_PAGE = 10;
export const ALERTS_PER_PAGE = 7;
8 changes: 4 additions & 4 deletions frontend/src/fetchers/activityReports.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import join from 'url-join';
import { get, put, post } from './index';
import { DECIMAL_BASE } from '../Constants';
import { DECIMAL_BASE, REPORTS_PER_PAGE, ALERTS_PER_PAGE } from '../Constants';

const activityReportUrl = join('/', 'api', 'activity-reports');
const activityReportAlertUrl = join('/', 'api', 'activity-reports', 'alerts');
Expand Down Expand Up @@ -31,13 +31,13 @@ export const getReport = async (reportId) => {
return report.json();
};

export const getReports = async (sortBy = 'updatedAt', sortDir = 'desc', offset = 0, limit = 10) => {
export const getReports = async (sortBy = 'updatedAt', sortDir = 'desc', offset = 0, limit = REPORTS_PER_PAGE) => {
const reports = await get(`${activityReportUrl}?sortBy=${sortBy}&sortDir=${sortDir}&offset=${offset}&limit=${limit}`);
return reports.json();
};

export const getReportAlerts = async () => {
const reports = await get(activityReportAlertUrl);
export const getReportAlerts = async (sortBy = 'startDate', sortDir = 'asc', offset = 0, limit = ALERTS_PER_PAGE) => {
const reports = await get(`${activityReportAlertUrl}?sortBy=${sortBy}&sortDir=${sortDir}&offset=${offset}&limit=${limit}`);
return reports.json();
};

Expand Down
177 changes: 131 additions & 46 deletions frontend/src/pages/Landing/MyAlerts.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* eslint-disable jsx-a11y/anchor-is-valid */
import React from 'react';
import PropTypes from 'prop-types';
import { Tag, Table } from '@trussworks/react-uswds';
Expand Down Expand Up @@ -51,12 +52,16 @@ function renderReports(reports) {
</Tag>
));

const idKey = `my_alerts_${id}`;
const idLink = `/activity-reports/${id}`;
const statusClassName = `smart-hub--table-tag-status smart-hub--status-${status}`;

return (
<tr key={`my_alerts_${id}`}>
<tr key={idKey}>
<td>
<Link
to={`/activity-reports/${id}`}
href={`/activity-reports/${id}`}
to={idLink}
href={idLink}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are both to and href required?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed href.

>
{displayId}
</Link>
Expand All @@ -79,7 +84,7 @@ function renderReports(reports) {
</td>
<td>
<Tag
className={`smart-hub--table-tag-status smart-hub--status-${status}`}
className={statusClassName}
>
{status === 'needs_action' ? 'Needs action' : status}
</Tag>
Expand All @@ -89,51 +94,121 @@ function renderReports(reports) {
});
}

function MyAlerts({ reports, newBtn }) {
export function renderTotal(offset, perPage, activePage, reportsCount) {
const from = offset >= reportsCount ? 0 : offset + 1;
const offsetTo = perPage * activePage;
let to;
if (offsetTo > reportsCount) {
to = reportsCount;
} else {
to = offsetTo;
}
return `${from}-${to} of ${reportsCount}`;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's hide this until pagination is active. With 11 reports the table is displaying all 11 (good, since otherwise one would be inaccessible) but this says 1-10 of 11 which is confusing

}

function MyAlerts(props) {
const {
reports,
newBtn,
alertsSortConfig,
alertsOffset,
alertsPerPage,
alertsActivePage,
alertReportsCount,
sortHandler,
} = props;
const getClassNamesFor = (name) => (alertsSortConfig.sortBy === name ? alertsSortConfig.direction : '');

const renderColumnHeader = (displayName, name) => {
const sortClassName = getClassNamesFor(name);
let fullAriaSort;
switch (sortClassName) {
case 'asc':
fullAriaSort = 'ascending';
break;
case 'desc':
fullAriaSort = 'descending';
break;
default:
fullAriaSort = 'none';
break;
}
return (
<th scope="col" aria-sort={fullAriaSort}>
<a
role="button"
tabIndex={0}
onClick={() => {
sortHandler(name);
}}
onKeyPress={() => sortHandler(name)}
className={sortClassName}
aria-label={`${displayName}. Activate to sort ${
sortClassName === 'asc' ? 'descending' : 'ascending'
}`}
>
{displayName}
</a>
</th>
);
};

return (
<>
{ reports && reports.length === 0 && (
<Container className="landing" padding={0}>
<div id="caughtUp">
<div><h2>You&apos;re all caught up!</h2></div>
{ newBtn && <p id="beginNew">Would you like to begin a new activity report?</p> }
{ newBtn && <NewReport /> }
</div>
</Container>
) }
{ reports && reports.length > 0 && (
<SimpleBar>
<Container className="landing inline-size" padding={0}>
<Table bordered={false}>
<caption className="smart-hub--table-caption">
My activity report alerts
</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">Collaborator(s)</th>
<th
scope="col"
>
Status
</th>
</tr>
</thead>
<tbody>{renderReports(reports)}</tbody>
</Table>
{reports && reports.length === 0 && (
<Container className="landing" padding={0}>
<div id="caughtUp">
<div>
<h2>You&apos;re all caught up!</h2>
</div>
{newBtn && (
<p id="beginNew">
Would you like to begin a new activity report?
</p>
)}
{newBtn && <NewReport />}
</div>
</Container>
</SimpleBar>
)}
{reports && reports.length > 0 && (
<SimpleBar>
<Container className="landing inline-size" padding={0}>
<span
id="alertsTotalCount"
aria-label={`Displaying rows ${renderTotal(
alertsOffset,
alertsPerPage,
alertsActivePage,
alertReportsCount,
)}`}
>
{renderTotal(
alertsOffset,
alertsPerPage,
alertsActivePage,
alertReportsCount,
)}
</span>

<Table bordered={false}>
<caption className="smart-hub--table-caption">
My activity report alerts
<p id="arTblDesc">with sorting</p>
</caption>
<thead>
<tr>
{renderColumnHeader('Report ID', 'regionId')}
{renderColumnHeader('Grantee', 'activityRecipients')}
{renderColumnHeader('Start date', 'startDate')}
{renderColumnHeader('Creator', 'author')}
{renderColumnHeader('Collaborator(s)', 'collaborators')}
{renderColumnHeader('Status', 'status')}
</tr>
</thead>
<tbody>{renderReports(reports)}</tbody>
</Table>
</Container>
</SimpleBar>
)}
</>
);
Expand All @@ -142,10 +217,20 @@ function MyAlerts({ reports, newBtn }) {
MyAlerts.propTypes = {
reports: PropTypes.arrayOf(PropTypes.object),
newBtn: PropTypes.bool.isRequired,
alertsSortConfig: PropTypes.shape({ sortBy: PropTypes.string, direction: PropTypes.string }),
alertsOffset: PropTypes.number,
alertsPerPage: PropTypes.number,
alertsActivePage: PropTypes.number,
alertReportsCount: PropTypes.number.isRequired,
sortHandler: PropTypes.func.isRequired,
};

MyAlerts.defaultProps = {
reports: [],
alertsSortConfig: { sortBy: 'startDate', direction: 'asc' },
alertsOffset: 0,
alertsPerPage: 7,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this default to 10?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed it to 10, but right now since the pagination is not working it will be a placeholder only until we find a way to integrate the pagination with sorting (HHS#369)

alertsActivePage: 1,
};

export default MyAlerts;
18 changes: 17 additions & 1 deletion frontend/src/pages/Landing/__tests__/MyAlerts.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,29 @@ import { MemoryRouter } from 'react-router';

import MyAlerts from '../MyAlerts';
import activityReports from '../mocks';
import { ALERTS_PER_PAGE } from '../../../Constants';

describe('My Alerts', () => {
beforeEach(() => {
const newBtn = true;
const alertsSortConfig = { sortBy: 'startDate', direction: 'desc' };
const alertsOffset = 0;
const alertsPerPage = ALERTS_PER_PAGE;
const alertsActivePage = 1;
const alertReportsCount = 10;
const requestAlertsSort = jest.fn();
render(
<MemoryRouter>
<MyAlerts reports={activityReports} newBtn={newBtn} />
<MyAlerts
reports={activityReports}
newBtn={newBtn}
alertsSortConfig={alertsSortConfig}
alertsOffset={alertsOffset}
alertsPerPage={alertsPerPage}
alertsActivePage={alertsActivePage}
alertReportsCount={alertReportsCount}
sortHandler={requestAlertsSort}
/>
</MemoryRouter>,
);
});
Expand Down
Loading