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

Navigate between judge assign and review views with the queue selector dropdown component #9035

3 changes: 2 additions & 1 deletion client/COPY.json
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,8 @@
"ORGANIZATIONAL_QUEUE_EMPTY_STATE_MESSAGE": "This queue is empty. You can ",

"JUDGE_CASE_REVIEW_TABLE_TITLE": "Review %s Cases",
"SWITCH_TO_ASSIGN_MODE_LINK_LABEL": "Switch to Assign Cases",
"JUDGE_ASSIGN_DROPDOWN_LINK_LABEL": "Assign Cases",
"JUDGE_REVIEW_DROPDOWN_LINK_LABEL": "Review Cases",

"IS_PAPER_CASE": "This is a paper case",

Expand Down
4 changes: 2 additions & 2 deletions client/app/queue/AttorneyTaskListView.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { css } from 'glamor';

import TabWindow from '../components/TabWindow';
import TaskTable from './components/TaskTable';
import QueueSelectorDropdown from './components/QueueSelectorDropdown';
import QueueOrganizationDropdown from './components/QueueOrganizationDropdown';
import AppSegment from '@department-of-veterans-affairs/caseflow-frontend-toolkit/components/AppSegment';
import Link from '@department-of-veterans-affairs/caseflow-frontend-toolkit/components/Link';
import Alert from '../components/Alert';
Expand Down Expand Up @@ -112,7 +112,7 @@ class AttorneyTaskListView extends React.PureComponent<Props> {

return <AppSegment filledBackground styling={containerStyles}>
<h1 {...fullWidth}>{COPY.ATTORNEY_QUEUE_TABLE_TITLE}</h1>
<QueueSelectorDropdown organizations={organizations} />
<QueueOrganizationDropdown organizations={organizations} />
{messages.error && <Alert type="error" title={messages.error.title}>
{messages.error.detail}
</Alert>}
Expand Down
4 changes: 2 additions & 2 deletions client/app/queue/ColocatedTaskListView.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { sprintf } from 'sprintf-js';
import { css } from 'glamor';

import TaskTable from './components/TaskTable';
import QueueSelectorDropdown from './components/QueueSelectorDropdown';
import QueueOrganizationDropdown from './components/QueueOrganizationDropdown';
import AppSegment from '@department-of-veterans-affairs/caseflow-frontend-toolkit/components/AppSegment';

import {
Expand Down Expand Up @@ -85,7 +85,7 @@ class ColocatedTaskListView extends React.PureComponent<Props> {
return <AppSegment filledBackground styling={containerStyles}>
{success && <Alert type="success" title={success.title} message={success.detail} styling={marginBottom(1)} />}
<h1 {...fullWidth}>{COPY.COLOCATED_QUEUE_PAGE_TABLE_TITLE}</h1>
<QueueSelectorDropdown organizations={organizations} />
<QueueOrganizationDropdown organizations={organizations} />
<TabWindow name="tasks-tabwindow" tabs={tabs} />
</AppSegment>;
};
Expand Down
12 changes: 7 additions & 5 deletions client/app/queue/JudgeAssignTaskListView.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { bindActionCreators } from 'redux';
import { css } from 'glamor';
import { NavLink } from 'react-router-dom';

import QueueJudgeAssignOrReviewDropdown from './components/QueueJudgeAssignOrReviewDropdown';
import AppSegment from '@department-of-veterans-affairs/caseflow-frontend-toolkit/components/AppSegment';
import {
resetErrorMessages,
Expand All @@ -13,7 +14,6 @@ import {
} from './uiReducer/uiActions';
import { clearCaseSelectSearch } from '../reader/CaseSelect/CaseSelectActions';
import { fullWidth } from './constants';
import Link from '@department-of-veterans-affairs/caseflow-frontend-toolkit/components/Link';
import LoadingDataDisplay from '../components/LoadingDataDisplay';
import SmallLoader from '../components/SmallLoader';
import { LOGO_COLORS } from '../constants/AppConstants';
Expand All @@ -26,6 +26,10 @@ import PageRoute from '../components/PageRoute';
import AssignedCasesPage from './AssignedCasesPage';
import UnassignedCasesPage from './UnassignedCasesPage';

const containerStyles = css({
position: 'relative'
});

class JudgeAssignTaskListView extends React.PureComponent {
componentWillUnmount = () => {
this.props.resetSaveState();
Expand All @@ -37,8 +41,6 @@ class JudgeAssignTaskListView extends React.PureComponent {
this.props.resetErrorMessages();
};

switchLink = () => <Link to={`/queue/${this.props.userId}/review`}>Switch to Review Cases</Link>

createLoadPromise = () => {
for (const attorney of this.props.attorneysOfJudge) {
this.props.fetchTasksAndAppealsOfAttorney(attorney.id, { role: 'judge' });
Expand All @@ -62,11 +64,11 @@ class JudgeAssignTaskListView extends React.PureComponent {
render = () => {
const { userId, attorneysOfJudge, match } = this.props;

return <AppSegment filledBackground>
return <AppSegment filledBackground styling={containerStyles}>
<div>
<div {...fullWidth} {...css({ marginBottom: '2em' })}>
<h1>Assign {this.props.unassignedTasksCount} Cases</h1>
{this.switchLink()}
<QueueJudgeAssignOrReviewDropdown userId={userId} />
</div>
<div className="usa-width-one-fourth">
<LoadingDataDisplay
Expand Down
9 changes: 7 additions & 2 deletions client/app/queue/JudgeDecisionReviewTaskListView.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { sprintf } from 'sprintf-js';
import { css } from 'glamor';

import TaskTable from './components/TaskTable';
import QueueJudgeAssignOrReviewDropdown from './components/QueueJudgeAssignOrReviewDropdown';
import AppSegment from '@department-of-veterans-affairs/caseflow-frontend-toolkit/components/AppSegment';
import Link from '@department-of-veterans-affairs/caseflow-frontend-toolkit/components/Link';
import Alert from '../components/Alert';
Expand All @@ -21,6 +22,10 @@ import { judgeDecisionReviewTasksSelector } from './selectors';
import { fullWidth } from './constants';
import COPY from '../../COPY.json';

const containerStyles = css({
position: 'relative'
});

class JudgeDecisionReviewTaskListView extends React.PureComponent {
componentWillUnmount = () => {
this.props.resetSaveState();
Expand Down Expand Up @@ -60,9 +65,9 @@ class JudgeDecisionReviewTaskListView extends React.PureComponent {
/>;
}

return <AppSegment filledBackground>
return <AppSegment filledBackground styling={containerStyles}>
<h1 {...fullWidth}>{sprintf(COPY.JUDGE_CASE_REVIEW_TABLE_TITLE, reviewableCount)}</h1>
<Link to={`/queue/${userId}/assign`}>{COPY.SWITCH_TO_ASSIGN_MODE_LINK_LABEL}</Link>
<QueueJudgeAssignOrReviewDropdown userId={userId} />
{messages.error && <Alert type="error" title={messages.error.title}>
{messages.error.detail}
</Alert>}
Expand Down
4 changes: 2 additions & 2 deletions client/app/queue/OrganizationQueue.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { css } from 'glamor';

import TabWindow from '../components/TabWindow';
import TaskTable from './components/TaskTable';
import QueueSelectorDropdown from './components/QueueSelectorDropdown';
import QueueOrganizationDropdown from './components/QueueOrganizationDropdown';
import AppSegment from '@department-of-veterans-affairs/caseflow-frontend-toolkit/components/AppSegment';

import {
Expand Down Expand Up @@ -67,7 +67,7 @@ class OrganizationQueue extends React.PureComponent {
return <AppSegment filledBackground styling={containerStyles}>
<div>
<h1 {...fullWidth}>{sprintf(COPY.ORGANIZATION_QUEUE_TABLE_TITLE, this.props.organizationName)}</h1>
<QueueSelectorDropdown organizations={this.props.organizations} />
<QueueOrganizationDropdown organizations={this.props.organizations} />
<TabWindow
name="tasks-organization-queue"
tabs={tabs}
Expand Down
38 changes: 38 additions & 0 deletions client/app/queue/components/QueueJudgeAssignOrReviewDropdown.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// @flow
import React from 'react';
import PropTypes from 'prop-types';

import QueueSelectorDropdown from './QueueSelectorDropdown';
import COPY from '../../../COPY.json';

type Props = {|
userId: number
|};

export default class QueueJudgeAssignOrReviewDropdown extends React.Component<Props> {
render = () => {
const url = window.location.pathname.split('/');
const location = url[url.length - 1];
const reviewTo = (['review', 'queue'].includes(location)) ? '#' : `/queue/${this.props.userId}/review`;
const assignTo = (location === 'assign') ? '#' : `/queue/${this.props.userId}/assign`;

const items = [
{
key: '0',
to: reviewTo,
label: COPY.JUDGE_REVIEW_DROPDOWN_LINK_LABEL
},
{
key: '1',
to: assignTo,
label: COPY.JUDGE_ASSIGN_DROPDOWN_LINK_LABEL
}
];

return <QueueSelectorDropdown items={items} />;
}
}

QueueJudgeAssignOrReviewDropdown.propTypes = {
userId: PropTypes.number.isRequired
};
49 changes: 49 additions & 0 deletions client/app/queue/components/QueueOrganizationDropdown.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// @flow
import React from 'react';
import PropTypes from 'prop-types';
import { sprintf } from 'sprintf-js';

import QueueSelectorDropdown from './QueueSelectorDropdown';
import COPY from '../../../COPY.json';

type Props = {|
organizations: Array<Object>
|};

export default class QueueOrganizationDropdown extends React.Component<Props> {
render = () => {
const { organizations } = this.props;
const url = window.location.pathname.split('/');
const location = url[url.length - 1];
const queueHref = (location === 'queue') ? '#' : '/queue';

if (organizations.length < 1) {
return null;
}

const queueItem = {
key: '0',
href: queueHref,
label: COPY.CASE_LIST_TABLE_QUEUE_DROPDOWN_OWN_CASES_LABEL
};

const organizationItems = organizations.map((org, index) => {
return {
key: (index + 1).toString(),
href: (location === org.url) ? '#' : `/organizations/${org.url}`,
label: sprintf(COPY.CASE_LIST_TABLE_QUEUE_DROPDOWN_TEAM_CASES_LABEL, org.name)
};
});

const items = [queueItem, ...organizationItems];

return <QueueSelectorDropdown items={items} />;
}
}

QueueOrganizationDropdown.propTypes = {
organizations: PropTypes.arrayOf(PropTypes.shape({
name: PropTypes.string.isRequired,
url: PropTypes.string.isRequired
}))
};
54 changes: 28 additions & 26 deletions client/app/queue/components/QueueSelectorDropdown.jsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
// @flow
import React from 'react';
import PropTypes from 'prop-types';
import { sprintf } from 'sprintf-js';
import { css } from 'glamor';

import Link from '@department-of-veterans-affairs/caseflow-frontend-toolkit/components/Link';
Expand All @@ -25,7 +24,7 @@ const styles = {
};

type Props = {|
organizations: Array<Object>
items: Array<Object>
|};

type ComponentState = {|
Expand All @@ -40,48 +39,41 @@ export default class QueueSelectorDropdown extends React.Component<Props, Compon
};
}

onMenuClick = () => {
toggleMenuVisible = () => {
this.setState((prevState) => ({
menu: !prevState.menu
}));
};

render = () => {
const { organizations } = this.props;
const url = window.location.pathname.split('/');
const location = url[url.length - 1];
const { items } = this.props;
let dropdownButtonList;

if (organizations.length < 1) {
if (items.length < 1) {
return null;
}

if (this.state.menu) {
const queueHref = (location === 'queue') ? '#' : '/queue';

dropdownButtonList = <ul className="cf-dropdown-menu active" {...styles.dropdownList}>
<li key={0}>
<Link className="usa-button-secondary usa-button"
href={queueHref} onClick={this.onMenuClick}>
{COPY.CASE_LIST_TABLE_QUEUE_DROPDOWN_OWN_CASES_LABEL}
</Link>
</li>

{organizations.map((org, index) => {
const orgHref = (location === org.url) ? '#' : `/organizations/${org.url}`;
{items.map((item) => {
const linkProps = {
className: 'usa-button-secondary usa-button',
onClick: this.toggleMenuVisible,
href: item.href,
to: item.to
};

return <li key={index + 1}>
<Link className="usa-button-secondary usa-button"
href={orgHref} onClick={this.onMenuClick}>
{sprintf(COPY.CASE_LIST_TABLE_QUEUE_DROPDOWN_TEAM_CASES_LABEL, org.name)}
return <li key={item.key}>
<Link {...linkProps}>
{item.label}
</Link>
</li>;
})}
</ul>;
}

return <div className="cf-dropdown" {...styles.dropdownButton}>
<a onClick={this.onMenuClick}
<a onClick={this.toggleMenuVisible}
className="cf-dropdown-trigger usa-button usa-button-secondary"
{...styles.dropdownTrigger}>
{COPY.CASE_LIST_TABLE_QUEUE_DROPDOWN_LABEL}
Expand All @@ -91,9 +83,19 @@ export default class QueueSelectorDropdown extends React.Component<Props, Compon
}
}

const hrefOrToRequired = (props, propName, componentName) => {
if (!props.href && !props.to) {
return new Error(`The ${componentName} component requires either an 'href' or a 'to' value.`);
} else if (props.href && props.to) {
return new Error(`The ${componentName} component should not be given both 'href' and 'to' values.`);
}
};

QueueSelectorDropdown.propTypes = {
organizations: PropTypes.arrayOf(PropTypes.shape({
name: PropTypes.string.isRequired,
url: PropTypes.string.isRequired
items: PropTypes.arrayOf(PropTypes.shape({
key: PropTypes.string.isRequired,
href: hrefOrToRequired,
to: hrefOrToRequired,
label: PropTypes.string.isRequired
}))
};
7 changes: 5 additions & 2 deletions spec/feature/queue/ama_queue_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -577,8 +577,11 @@
it "judge can return report to attorney for corrections" do
step "judge reviews case and assigns a task to an attorney" do
visit "/queue"
expect(page).to have_content(format(COPY::JUDGE_CASE_REVIEW_TABLE_TITLE, "0"))

click_on COPY::SWITCH_TO_ASSIGN_MODE_LINK_LABEL
find(".cf-dropdown-trigger", text: COPY::CASE_LIST_TABLE_QUEUE_DROPDOWN_LABEL).click
expect(page).to have_content(COPY::JUDGE_ASSIGN_DROPDOWN_LINK_LABEL)
click_on COPY::JUDGE_ASSIGN_DROPDOWN_LINK_LABEL

click_on veteran_full_name

Expand Down Expand Up @@ -676,7 +679,7 @@
)
end

step "judge sees the case in their queue" do
step "judge sees the case in their review queue" do
User.authenticate!(user: judge_user)
visit "/queue"

Expand Down
Loading