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

feat: Include Settings page for admin and UI to manually import latest test plan versions #1290

Open
wants to merge 9 commits into
base: development
Choose a base branch
from
4 changes: 2 additions & 2 deletions client/components/App/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ const App = () => {
const [isNavbarExpanded, setIsNavbarExpanded] = useState(false);

const auth = evaluateAuth(data && data.me ? data.me : {});
const { username, isSignedIn, isAdmin, isVendor } = auth;
const { username, isSignedIn, isAdmin, isVendor, isTester } = auth;

const signOut = async () => {
await fetch('/api/auth/signout', { method: 'POST' });
Expand Down Expand Up @@ -104,7 +104,7 @@ const App = () => {
)}
{isSignedIn && (
<>
{!isVendor && (
{(isAdmin || isTester) && (
<li>
<Nav.Link
as={Link}
Expand Down
82 changes: 82 additions & 0 deletions client/components/UserSettings/AdminSettings.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Button } from 'react-bootstrap';
import { LoadingStatus, useTriggerLoad } from '../common/LoadingStatus';
import { useThemedModal, THEMES } from '../../hooks/useThemedModal';
import { dates } from 'shared';

const AdminSettings = ({ latestTestPlanVersion, refetch }) => {
Copy link
Contributor

Choose a reason for hiding this comment

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

Really love this use of the settings page.

const { triggerLoad, loadingMessage, loadingNote } = useTriggerLoad();
const {
themedModal,
showThemedModal,
setShowThemedModal,
setThemedModalTitle,
setThemedModalContent,
setThemedModalType
} = useThemedModal({
type: THEMES.SUCCESS,
title: 'Success'
});

const handleImportTests = async () => {
await triggerLoad(
async () => {
try {
const response = await fetch('/api/test/import', { method: 'POST' });
if (!response.ok) {
throw new Error(
`Failed to import the latest Test Plan Versions: ${response.status}`
);
}

// Success
setThemedModalType(THEMES.SUCCESS);
setThemedModalTitle('Success');
setThemedModalContent(
<>The latest Test Plan Versions have been imported.</>
);
setShowThemedModal(true);
await refetch();
} catch (e) {
// Failed, show themed message
setThemedModalType(THEMES.DANGER);
setThemedModalTitle('Error');
setThemedModalContent(<>{e.message}</>);
setShowThemedModal(true);
}
},
'Importing latest Test Plan Versions',
'This may take a few minutes ...'
);
};

return (
<LoadingStatus message={loadingMessage} note={loadingNote}>
<section>
<h2>Admin Actions</h2>
<Button variant="primary" onClick={handleImportTests}>
Import Latest Test Plan Versions
</Button>
<p>
Date of latest test plan version:{' '}
{dates.convertDateToString(
latestTestPlanVersion?.updatedAt,
'MMMM D, YYYY HH:mm z'
)}
</p>
</section>
{showThemedModal && themedModal}
</LoadingStatus>
);
};

AdminSettings.propTypes = {
latestTestPlanVersion: PropTypes.shape({
id: PropTypes.string.isRequired,
updatedAt: PropTypes.string.isRequired
}),
refetch: PropTypes.func
};

export default AdminSettings;
106 changes: 106 additions & 0 deletions client/components/UserSettings/TesterSettings.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import React, { useCallback, useEffect, useState } from 'react';
import PropTypes from 'prop-types';
import { Button, Form } from 'react-bootstrap';
import { useMutation } from '@apollo/client';
import { TESTER_SETTINGS_QUERY, UPDATE_ME_MUTATION } from './queries';
import { AtPropType } from '../common/proptypes';

const TesterSettings = ({ ats, meAts }) => {
const [updateMe] = useMutation(UPDATE_ME_MUTATION, {
refetchQueries: [{ query: TESTER_SETTINGS_QUERY }]
});

const [checkedAts, setCheckedAts] = useState([]);

if (!ats || !meAts || !checkedAts) return null;

useEffect(() => {
if (!meAts) return;
setCheckedAts(meAts.map(at => at.id));
}, [meAts]);

const handleCheckedAt = useCallback(
event => {
const atId = event.target.id;
const isChecked = checkedAts.includes(atId);
if (isChecked) {
setCheckedAts(checkedAts.filter(item => item !== atId));
} else {
setCheckedAts([...checkedAts, atId]);
}
},
[checkedAts]
);

const handleSave = useCallback(
event => {
event.preventDefault();
updateMe({ variables: { input: { atIds: checkedAts } } });
},
[checkedAts]
);

const savedAts = meAts.map(at => at.id);

return (
<section>
<h2>Assistive Technology Settings</h2>
<div aria-atomic="true" aria-live="polite">
{savedAts.length > 0 ? (
<div>
<p data-testid="testable-ats-status">
You can currently test the following assistive technologies:
</p>
<ul>
{ats
.filter(({ id: atId }) => savedAts.includes(atId))
.map(at => (
<li style={{ listStyle: 'disc' }} key={at.id}>
{at.name}
</li>
))}
</ul>
</div>
) : (
<p data-testid="testable-ats-status">
You have not yet selected any assistive technologies.
</p>
)}
</div>
<p>
Update the assistive technologies you can test by selecting from the
options below:
</p>
<Form>
<h3 id="at-group-label">Assistive Technologies</h3>
<Form.Group
controlId="formBasicCheckbox"
role="group"
aria-labelledby="at-group-label"
>
{ats?.map(at => {
return (
<Form.Check
id={at.id}
key={at.id}
label={at.name}
onChange={handleCheckedAt}
checked={!!checkedAts.find(atId => atId === at.id)}
/>
);
})}
</Form.Group>
<Button variant="primary" type="submit" onClick={handleSave}>
Save
</Button>
</Form>
</section>
);
};

TesterSettings.propTypes = {
ats: PropTypes.arrayOf(AtPropType),
meAts: PropTypes.arrayOf(AtPropType)
};

export default TesterSettings;
143 changes: 0 additions & 143 deletions client/components/UserSettings/UserSettings.jsx

This file was deleted.

Loading
Loading