Skip to content

Commit

Permalink
Merge pull request #390 from adhocteam/main
Browse files Browse the repository at this point in the history
Draft alert and report bug fixes
  • Loading branch information
rahearn authored Mar 16, 2021
2 parents 2aa0a4e + 2e351ea commit 57e3152
Show file tree
Hide file tree
Showing 8 changed files with 114 additions and 64 deletions.
47 changes: 47 additions & 0 deletions frontend/src/components/DismissingComponentWrapper.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import React, { useEffect } from 'react';
import PropTypes from 'prop-types';

function DismissingComponentWrapper({
shown, timeVisibleInSec, hideFromScreenReader, children, updateShown,
}) {
useEffect(() => {
let id;
if (shown) {
id = setTimeout(() => {
updateShown(false);
}, [timeVisibleInSec * 1000]);
} else {
clearTimeout(id);
}

return () => {
clearTimeout(id);
};
}, [shown]);

return (
<>
{shown && (
<div aria-hidden={hideFromScreenReader}>
{children}
</div>
)}
</>
);
}

DismissingComponentWrapper.propTypes = {
shown: PropTypes.bool.isRequired,
timeVisibleInSec: PropTypes.number,
hideFromScreenReader: PropTypes.bool,
updateShown: PropTypes.func.isRequired,
children: PropTypes.node,
};

DismissingComponentWrapper.defaultProps = {
timeVisibleInSec: 30,
hideFromScreenReader: true,
children: null,
};

export default DismissingComponentWrapper;
33 changes: 26 additions & 7 deletions frontend/src/components/Navigator/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,12 @@ import {
} from './constants';
import SideNav from './components/SideNav';
import NavigatorHeader from './components/NavigatorHeader';
import DismissingComponentWrapper from '../DismissingComponentWrapper';

function Navigator({
editable,
formData,
updateFormData,
initialLastUpdated,
pages,
onFormSubmit,
onReview,
Expand All @@ -42,10 +42,13 @@ function Navigator({
reportId,
updatePage,
reportCreator,
lastSaveTime,
updateLastSaveTime,
showValidationErrors,
updateShowValidationErrors,
}) {
const [errorMessage, updateErrorMessage] = useState();
const [lastSaveTime, updateLastSaveTime] = useState(initialLastUpdated);
const [showValidationErrors, updateShowValidationErrors] = useState(false);
const [showSavedDraft, updateShowSavedDraft] = useState(false);
const page = pages.find((p) => p.path === currentPage);

const hookForm = useForm({
Expand All @@ -72,8 +75,8 @@ function Navigator({

const currentPageState = pageState[page.position];
const isComplete = page.isPageComplete ? page.isPageComplete(getValues()) : isValid;

const newPageState = { ...pageState };

if (isComplete) {
newPageState[page.position] = COMPLETE;
} else if (currentPageState === COMPLETE) {
Expand Down Expand Up @@ -107,6 +110,7 @@ function Navigator({
await onSaveForm();
if (index !== page.position) {
updatePage(index);
updateShowSavedDraft(false);
}
};

Expand Down Expand Up @@ -198,10 +202,22 @@ function Navigator({
{page.render(additionalData, formData, reportId)}
<div className="display-flex">
<Button disabled={page.position <= 1} outline type="button" onClick={() => { onUpdatePage(page.position - 1); }}>Back</Button>
<Button type="button" onClick={() => { onSaveForm(); }}>Save draft</Button>
<Button type="button" onClick={async () => { await onSaveForm(); updateShowSavedDraft(true); }}>Save draft</Button>
<Button className="margin-left-auto margin-right-0" type="button" onClick={onContinue}>Save & Continue</Button>
</div>
</Form>
<DismissingComponentWrapper
shown={showSavedDraft}
updateShown={updateShowSavedDraft}
>
{lastSaveTime && (
<Alert className="margin-top-3 maxw-mobile-lg" noIcon slim type="success">
Draft saved on
{' '}
{lastSaveTime.format('MM/DD/YYYY [at] h:mm a z')}
</Alert>
)}
</DismissingComponentWrapper>
</Container>
)}
</div>
Expand All @@ -219,7 +235,10 @@ Navigator.propTypes = {
pageState: PropTypes.shape({}),
}).isRequired,
updateFormData: PropTypes.func.isRequired,
initialLastUpdated: PropTypes.instanceOf(moment),
lastSaveTime: PropTypes.instanceOf(moment),
updateLastSaveTime: PropTypes.func.isRequired,
showValidationErrors: PropTypes.bool.isRequired,
updateShowValidationErrors: PropTypes.func.isRequired,
onFormSubmit: PropTypes.func.isRequired,
onSave: PropTypes.func.isRequired,
onReview: PropTypes.func.isRequired,
Expand Down Expand Up @@ -247,7 +266,7 @@ Navigator.propTypes = {
Navigator.defaultProps = {
additionalData: {},
autoSaveInterval: 1000 * 60 * 2,
initialLastUpdated: null,
lastSaveTime: null,
reportCreator: {
name: null,
role: null,
Expand Down
12 changes: 7 additions & 5 deletions frontend/src/pages/ActivityReport/Pages/activitySummary.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,18 +62,20 @@ const ActivitySummary = ({
const participants = nonGranteeSelected ? nonGranteeParticipants : granteeParticipants;

useEffect(() => {
if (previousActivityRecipientType.current !== activityRecipientType) {
setValue('activityRecipients', []);
setValue('participants', []);
setValue('programTypes', []);
if (previousActivityRecipientType.current !== activityRecipientType
&& previousActivityRecipientType.current !== ''
&& previousActivityRecipientType.current !== null) {
setValue('activityRecipients', [], { shouldValidate: true });
setValue('participants', [], { shouldValidate: true });
setValue('programTypes', [], { shouldValidate: true });
// Goals and objectives (page 3) has required fields when the recipient
// type is grantee, so we need to make sure that page is set as "not started"
// when recipient type is changed and we need to clear out any previously
// selected goals
setValue('goals', []);
setValue('pageState', { ...pageState, 3: NOT_STARTED });
previousActivityRecipientType.current = activityRecipientType;
}
previousActivityRecipientType.current = activityRecipientType;
}, [activityRecipientType, setValue]);

const renderCheckbox = (name, value, label, requiredMessage) => (
Expand Down
11 changes: 8 additions & 3 deletions frontend/src/pages/ActivityReport/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,8 @@ function ActivityReport({
const [initialAdditionalData, updateAdditionalData] = useState({});
const [approvingManager, updateApprovingManager] = useState(false);
const [editable, updateEditable] = useState(false);
const [initialLastUpdated, updateInitialLastUpdated] = useState();
const [lastSaveTime, updateLastSaveTime] = useState();
const [showValidationErrors, updateShowValidationErrors] = useState(false);
const reportId = useRef();

const showLastUpdatedTime = (location.state && location.state.showLastUpdatedTime) || false;
Expand Down Expand Up @@ -141,7 +142,7 @@ function ActivityReport({
updateEditable(canWriteReport);

if (showLastUpdatedTime) {
updateInitialLastUpdated(moment(report.updatedAt));
updateLastSaveTime(moment(report.updatedAt));
}

updateError();
Expand Down Expand Up @@ -256,10 +257,14 @@ function ActivityReport({
</Grid>
</Grid>
<Navigator
key={currentPage}
editable={editable}
updatePage={updatePage}
reportCreator={reportCreator}
initialLastUpdated={initialLastUpdated}
showValidationErrors={showValidationErrors}
updateShowValidationErrors={updateShowValidationErrors}
lastSaveTime={lastSaveTime}
updateLastSaveTime={updateLastSaveTime}
reportId={reportId.current}
currentPage={currentPage}
additionalData={initialAdditionalData}
Expand Down
19 changes: 19 additions & 0 deletions src/migrations/20210315234158-seed-non-grantee-recipients.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
module.exports = {
up: (queryInterface) => queryInterface.bulkInsert('NonGrantees', [
{ name: 'CCDF / Child Care Administrator' },
{ name: 'Head Start Collaboration Office' },
{ name: 'QRIS System' },
{ name: 'Regional Head Start Association' },
{ name: 'Regional TTA/Other Specialists' },
{ name: 'State CCR&R' },
{ name: 'State Early Learning Standards' },
{ name: 'State Education System' },
{ name: 'State Health System' },
{ name: 'State Head Start Association' },
{ name: 'State Professional Development / Continuing Education' },
],
{
ignoreDuplicates: true,
}),
down: (queryInterface) => queryInterface.bulkDelete('Regions', null, {}),
};
45 changes: 0 additions & 45 deletions src/seeders/20210107170250-nonGrantees.js

This file was deleted.

6 changes: 5 additions & 1 deletion src/services/activityReports.js
Original file line number Diff line number Diff line change
Expand Up @@ -560,10 +560,14 @@ export async function setStatus(report, status) {
* @returns {*} Grants and Non grantees
*/
export async function possibleRecipients(regionId) {
const where = regionId ? { regionId } : undefined;
let where = { status: 'Active' };
if (regionId) {
where = { ...where, regionId };
}

const grants = await Grantee.findAll({
attributes: ['id', 'name'],
order: ['name'],
include: [{
where,
model: Grant,
Expand Down
5 changes: 2 additions & 3 deletions src/services/activityReports.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ describe('Activity Reports DB service', () => {
grantee = await Grantee.create({ id: RECIPIENT_ID, name: 'grantee', regionId: 17 });
await Region.create({ name: 'office 17', id: 17 });
await Grant.create({
id: RECIPIENT_ID, number: 1, granteeId: grantee.id, regionId: 17,
id: RECIPIENT_ID, number: 1, granteeId: grantee.id, regionId: 17, status: 'Active',
});
await NonGrantee.create({ id: RECIPIENT_ID, name: 'nonGrantee' });
});
Expand Down Expand Up @@ -454,8 +454,7 @@ describe('Activity Reports DB service', () => {

it('retrieves all recipients when not specifying region', async () => {
const recipients = await possibleRecipients();
const grantees = await Grantee.findAll();
expect(recipients.grants.length).toBe(grantees.length);
expect(recipients.grants.length).toBe(11);
});
});
});

0 comments on commit 57e3152

Please sign in to comment.