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

lthompson/APPEALS-26633 #19112

Merged
merged 51 commits into from
Aug 23, 2023
Merged
Show file tree
Hide file tree
Changes from 49 commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
c468255
Added feature toggles to index.html.rb
breedbah Jul 20, 2023
7f0bae2
Added toggle to index.html.erb
breedbah Jul 21, 2023
5fe4690
Progress on conference types radio field
lauren-e-thompson Jul 21, 2023
6780e00
adding conference type selection logic
lauren-e-thompson Jul 24, 2023
72cc092
APPEALS-25141: created migrations to add pexip bool column to users v…
konhilas-ariana Jul 24, 2023
e18314c
APPEALS-25141: set default value to true on users
konhilas-ariana Jul 24, 2023
07be387
Work on radio field selection
lauren-e-thompson Jul 24, 2023
4d9694c
Fixed errors with conference selection radio field
lauren-e-thompson Jul 24, 2023
3264c4b
Clean up code after new import file
lauren-e-thompson Jul 25, 2023
fc72e95
Update copy file and state
lauren-e-thompson Jul 25, 2023
6fc2c0f
APPEALS-25112 Added styling for radio field component
lauren-e-thompson Jul 26, 2023
8db7067
Merge branch 'lthompson/APPEALS-25112' into b_reed/APPEALS-25130-v3
breedbah Jul 26, 2023
6957d77
APPEALS-25130 updated user.rb
breedbah Jul 26, 2023
ba63cf8
APPEALS-25141: rolling back changes, creating new migrations, deletin…
konhilas-ariana Jul 26, 2023
0e48803
APPEALS-25141: removed version 5.2 from migrations
konhilas-ariana Jul 26, 2023
e22ddda
Merge branch 'b_reed/APPEALS-25130-v3' of https://github.com/departme…
breedbah Jul 27, 2023
ab8ce3c
Merge pull request #19038 from department-of-veterans-affairs/b_reed/…
mchbidwell Jul 27, 2023
bdc3a52
Create jest test
lauren-e-thompson Jul 28, 2023
3dae8f5
Test passing
lauren-e-thompson Jul 28, 2023
5bfdc9b
Fixed syntax errors from merged code
lauren-e-thompson Jul 28, 2023
c023af4
Radio buttons fixed to only display on Hearings Admin page
lauren-e-thompson Jul 28, 2023
08c7910
Wrap li elements in ul elements
lauren-e-thompson Jul 28, 2023
7421103
Test that radio button values change when selected
lauren-e-thompson Jul 28, 2023
daae3bf
Update to testing logic with radio buttons
lauren-e-thompson Jul 28, 2023
5115f7c
APPEALS-25141: refactoring migrations to include up/down methods, add…
konhilas-ariana Jul 31, 2023
78af497
Styling comments updated after review
lauren-e-thompson Aug 1, 2023
ba97e73
Merge branch 'master' into akonhilas/APPEALS-25141
mchbidwell Aug 1, 2023
0ab42a3
Revert 'Merge pull request #19038 from department-of-veterans-affairs…
ThorntonMatthew Aug 1, 2023
97bba81
Fixed linting issues and updated jest snapshot
lauren-e-thompson Aug 1, 2023
6e9c1e8
Merge branch 'feature/APPEALS-25109' into lthompson/APPEALS-25112
ThorntonMatthew Aug 1, 2023
a6c4afa
Merge pull request #19057 from department-of-veterans-affairs/lthomps…
ThorntonMatthew Aug 1, 2023
bf5b312
Merge branch 'master' into feature/APPEALS-25109
ThorntonMatthew Aug 2, 2023
88d9317
Merge branch 'master' into feature/APPEALS-25109
ThorntonMatthew Aug 2, 2023
b78168a
APPEALS-25141: updated user_spec.rb
konhilas-ariana Aug 3, 2023
f048b80
Merge branch 'akonhilas/APPEALS-25141' of https://github.com/departme…
konhilas-ariana Aug 3, 2023
2fc1c02
Merge branch 'master' into feature/APPEALS-25109
ThorntonMatthew Aug 3, 2023
df20d92
APPEALS-26633 Added method to update meeting_type in Users Controller…
lauren-e-thompson Aug 3, 2023
fbdffcf
Merge branch 'feature/APPEALS-25109' into akonhilas/APPEALS-25141
ThorntonMatthew Aug 4, 2023
4987df1
Merge pull request #19055 from department-of-veterans-affairs/akonhil…
mchbidwell Aug 7, 2023
6a8edf6
APPEALS-26633 Progress on linking backend and frontend radio option c…
lauren-e-thompson Aug 7, 2023
1b1353e
Merge branch 'feature/APPEALS-25109' into lthompson/APPEALS-26633
lauren-e-thompson Aug 7, 2023
55ac16f
APPEALS-26633 Framing for logic to link onChange function
lauren-e-thompson Aug 7, 2023
e670373
Adding modifyConferenceType to patch to backend
lauren-e-thompson Aug 9, 2023
c376385
Add meeting_type to user to capture new meeting type from frontend, d…
lauren-e-thompson Aug 15, 2023
d5df546
Fixed bug so frontend hearings change is persisted to backend and upd…
lauren-e-thompson Aug 15, 2023
6b2dad9
Fixed linting issues and added rspec test to check the new meeting type
lauren-e-thompson Aug 17, 2023
14d7675
Add information about patch response test
lauren-e-thompson Aug 17, 2023
7c0f3c6
Fix code climates issues
lauren-e-thompson Aug 17, 2023
73aa405
Jest testing fixed to check for changing values by radio button selec…
lauren-e-thompson Aug 18, 2023
0ae9576
Hearing Admin selection changed to Hearings Management
lauren-e-thompson Aug 22, 2023
923fb83
Merge branch 'master' into lthompson/APPEALS-26633
mchbidwell Aug 23, 2023
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
9 changes: 9 additions & 0 deletions app/controllers/organizations/users_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ def update
adjust_admin_rights
end

update_user_meeting_type
render json: { users: json_administered_users([user_to_modify]) }, status: :ok
end

Expand Down Expand Up @@ -67,6 +68,14 @@ def adjust_admin_rights
end
end

def update_user_meeting_type
new_meeting_type = params.dig(:attributes, :meeting_type)

if organization["url"] == HearingAdmin.singleton.url && new_meeting_type
OrganizationsUser.update_user_conference_type(user_to_modify, new_meeting_type)
end
end

def organization_url
params[:organization_url]
end
Expand Down
6 changes: 6 additions & 0 deletions app/models/organizations_user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@ def remove_admin_rights_from_user(user, organization)
existing_record(user, organization)&.update!(admin: false)
end

def update_user_conference_type(user, new_meeting_type)
if user.meeting_type
user.update!(meeting_type: new_meeting_type)
end
end

def remove_user_from_organization(user, organization)
if user_is_judge_of_team?(user, organization)
fail Caseflow::Error::ActionForbiddenError, message: COPY::JUDGE_TEAM_REMOVE_JUDGE_ERROR
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,5 @@ class WorkQueue::AdministeredUserSerializer < WorkQueue::UserSerializer
params[:organization].dvc&.eql?(object)
end
end
attribute :meeting_type
end
1 change: 1 addition & 0 deletions client/COPY.json
Original file line number Diff line number Diff line change
Expand Up @@ -772,6 +772,7 @@
"USER_MANAGEMENT_GIVE_USER_ADMIN_RIGHTS_BUTTON_TEXT": "Add admin rights",
"USER_MANAGEMENT_REMOVE_USER_ADMIN_RIGHTS_BUTTON_TEXT": "Remove admin rights",
"USER_MANAGEMENT_REMOVE_USER_FROM_ORG_BUTTON_TEXT": "Remove from team",
"USER_MANAGEMENT_SELECT_HEARINGS_CONFERENCE_TYPE": "Schedule hearings using:",
"MEMBERSHIP_REQUEST_ACTION_SUCCESS_TITLE": "You successfully %s %s's request",
"MEMBERSHIP_REQUEST_ACTION_SUCCESS_MESSAGE": "The user was %s regular member access to %s.",
"VHA_MEMBERSHIP_REQUEST_AUTOMATIC_VHA_ACCESS_NOTE": "Note: If you are requesting specialized access and are not a member of the general VHA group, you will automatically be given access to the general VHA group if your request is approved.",
Expand Down
55 changes: 39 additions & 16 deletions client/app/queue/OrganizationUsers.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { LOGO_COLORS } from '../constants/AppConstants';
import COPY from '../../COPY';
import LoadingDataDisplay from '../components/LoadingDataDisplay';
import MembershipRequestTable from './MembershipRequestTable';
import SelectConferenceTypeRadioField from './SelectConferenceTypeRadioField';

const userStyle = css({
margin: '.5rem 0 .5rem',
Expand All @@ -38,11 +39,17 @@ const buttonStyle = css({
const buttonContainerStyle = css({
borderBottom: '1rem solid gray',
borderWidth: '1px',
padding: '.5rem 0 2rem',
padding: '.5rem 7rem 2rem 0',
display: 'flex',
justifyContent: 'space-between',
flexWrap: 'wrap'
});
const listStyle = css({
listStyle: 'none'
});
const radioContainerStyle = css({
padding: '-5rem 5rem 2rem 2rem',
});

export default class OrganizationUsers extends React.PureComponent {
constructor(props) {
Expand Down Expand Up @@ -248,18 +255,34 @@ export default class OrganizationUsers extends React.PureComponent {
const style = i === 0 ? topUserStyle : userStyle;

return <React.Fragment key={user.id}>
<li key={user.id} {...style}>{this.formatName(user)}
{ judgeTeam && admin && <strong> ( {COPY.USER_MANAGEMENT_JUDGE_LABEL} )</strong> }
{ dvcTeam && dvc && <strong> ( {COPY.USER_MANAGEMENT_DVC_LABEL} )</strong> }
{ judgeTeam && !admin && <strong> ( {COPY.USER_MANAGEMENT_ATTORNEY_LABEL} )</strong> }
{ (judgeTeam || dvcTeam) && admin && <strong> ( {COPY.USER_MANAGEMENT_ADMIN_LABEL} )</strong> }
</li>
{ (judgeTeam || dvcTeam) && admin ?
<div {...topUserBorder}></div> :
<div {...buttonContainerStyle}>
{ (judgeTeam || dvcTeam) ? '' : this.adminButton(user, admin) }
{ this.removeUserButton(user) }
</div> }
<div>
<ul>
<li key={user.id} {...style}>{this.formatName(user)}
{ judgeTeam && admin && <strong> ( {COPY.USER_MANAGEMENT_JUDGE_LABEL} )</strong> }
{ dvcTeam && dvc && <strong> ( {COPY.USER_MANAGEMENT_DVC_LABEL} )</strong> }
{ judgeTeam && !admin && <strong> ( {COPY.USER_MANAGEMENT_ATTORNEY_LABEL} )</strong> }
{ (judgeTeam || dvcTeam) && admin && <strong> ( {COPY.USER_MANAGEMENT_ADMIN_LABEL} )</strong> }
</li>
{ (judgeTeam || dvcTeam) && admin ?
<div {...topUserBorder}></div > :
<div {...buttonContainerStyle}>
<div>
{ (judgeTeam || dvcTeam) ? '' : this.adminButton(user, admin) }
{ this.removeUserButton(user) }
</div>
{ this.state.organizationName === 'Hearing Admin' &&
<div {...radioContainerStyle}>
<SelectConferenceTypeRadioField
key={`${user.id}-conference-selection`}
name={user.id}
meetingType={user.attributes.meeting_type}
organization={this.props.organization}
user={user} />
</div>
}
</div> }
</ul>
</div>
</React.Fragment>;
});

Expand All @@ -285,10 +308,10 @@ export default class OrganizationUsers extends React.PureComponent {
<div>
<h2>{COPY.USER_MANAGEMENT_EDIT_USER_IN_ORG_LABEL}</h2>
<ul {...listStyle}>
{ (judgeTeam || dvcTeam) ? '' : <li><strong>{COPY.USER_MANAGEMENT_ADMIN_RIGHTS_HEADING}</strong>{COPY.USER_MANAGEMENT_ADMIN_RIGHTS_DESCRIPTION}</li> }
<li><strong>{COPY.USER_MANAGEMENT_REMOVE_USER_HEADING}</strong>{ judgeTeam ?
{ (judgeTeam || dvcTeam) ? '' : <ul><li><strong>{COPY.USER_MANAGEMENT_ADMIN_RIGHTS_HEADING}</strong>{COPY.USER_MANAGEMENT_ADMIN_RIGHTS_DESCRIPTION}</li></ul> }
<ul><li><strong>{COPY.USER_MANAGEMENT_REMOVE_USER_HEADING}</strong>{ judgeTeam ?
COPY.USER_MANAGEMENT_JUDGE_TEAM_REMOVE_USER_DESCRIPTION :
COPY.USER_MANAGEMENT_REMOVE_USER_DESCRIPTION }</li>
COPY.USER_MANAGEMENT_REMOVE_USER_DESCRIPTION }</li></ul>
</ul>
</div>
<ul>{listOfUsers}</ul>
Expand Down
48 changes: 48 additions & 0 deletions client/app/queue/SelectConferenceTypeRadioField.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import React, { useState } from 'react';
import PropTypes from 'prop-types';
import ApiUtil from '../util/ApiUtil';

import RadioField from '../components/RadioField';
import COPY from '../../COPY';

const radioOptions = [
{ displayText: 'Pexip',
value: 'pexip' },
{ displayText: 'Webex',
value: 'webex' }
];

const SelectConferenceTypeRadioField = ({ name, meetingType, organization, user }) => {
const [value, setValue] = useState(meetingType);

const modifyConferenceType = (newMeetingType) => {
const payload = { data: { ...user, attributes: { ...user.attributes, meeting_type: newMeetingType } } };

ApiUtil.patch(`/organizations/${organization}/users/${user.id}`, payload);
};

return (
<>
<RadioField
label={COPY.USER_MANAGEMENT_SELECT_HEARINGS_CONFERENCE_TYPE}
name={name}
options={radioOptions}
value={value}
onChange={((newValue) => setValue(newValue) || modifyConferenceType(newValue))}
vertical
/></>
);
};

SelectConferenceTypeRadioField.propTypes = {
name: PropTypes.string,
onClick: PropTypes.func,
meetingType: PropTypes.string,
organization: PropTypes.string,
user: PropTypes.shape({
id: PropTypes.string,
attributes: PropTypes.object
})
};

export default SelectConferenceTypeRadioField;
80 changes: 80 additions & 0 deletions client/test/app/queue/SelectConferenceTypeRadioField.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import React from 'react';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import ApiUtil from 'app/util/ApiUtil';

import SelectConferenceTypeRadioField from 'app/queue/SelectConferenceTypeRadioField';

const createSpy = () => jest.spyOn(ApiUtil, 'patch').
mockImplementation(() => jest.fn(() => Promise.resolve(
{
body: { }
}
)));

const defaults = {
name: 'field1',
value: '1',
options: [
{ displayText: 'Pexip',
value: 'pexip' },
{ displayText: 'Webex',
value: 'webex' },
],
};

describe('SelectConferenceTypeRadioField', () => {
beforeEach(() => {
jest.clearAllMocks();
});

const setupComponent = (props = {
user: {
attributes: {
id: 1
}
},
meetingType: 'pexip',
organization: 'my org'
}) => {
const utils = render(
<SelectConferenceTypeRadioField
name={defaults.name}
options={defaults.options}
{...props}
/>
);
const inputs = utils.getAllByRole('radio');

return {
inputs,
...utils,
};
};

it('renders correctly', async () => {
const { container } = setupComponent();

expect(container).toMatchSnapshot();
});

it('changes values by radio button selected', () => {
let requestPatchSpy = createSpy();

setupComponent();

const webexRadioButton = screen.getByRole('radio', { name: 'Webex' });
const pexipRadioButton = screen.getByRole('radio', { name: 'Pexip' });

expect(webexRadioButton).not.toHaveAttribute('checked', '');
expect(pexipRadioButton).toHaveAttribute('checked', '');

userEvent.click(webexRadioButton);

expect(requestPatchSpy.mock.calls[0][1].data.attributes.meeting_type).toBe('webex');

userEvent.click(pexipRadioButton);

expect(requestPatchSpy.mock.calls[1][1].data.attributes.meeting_type).toBe('pexip');
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`SelectConferenceTypeRadioField renders correctly 1`] = `
<div>
<fieldset
class="usa-fieldset-inputs cf-form-radio "
>
<legend
class=""
>
<span>
Schedule hearings using:

</span>
</legend>
<div
class="cf-form-radio-options"
>
<div
class="cf-form-radio-option"
>
<input
checked=""
id="field1_pexip"
name="field1"
type="radio"
value="pexip"
/>
<label
class=""
for="field1_pexip"
>
Pexip
</label>
</div>
<div
class="cf-form-radio-option"
>
<input
id="field1_webex"
name="field1"
type="radio"
value="webex"
/>
<label
class=""
for="field1_webex"
>
Webex
</label>
</div>
</div>
</fieldset>
</div>
`;
9 changes: 9 additions & 0 deletions db/migrate/20230726201514_add_meeting_type_to_users.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
class AddMeetingTypeToUsers < Caseflow::Migration
def up
add_column :users, :meeting_type, :varChar, default: "pexip", comment: "Video Conferencing Application Type"
end

def down
remove_column :users, :meeting_type
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
class AddMeetingTypeToVirtualHearings < Caseflow::Migration
def up
add_column :virtual_hearings, :meeting_type, :varChar, default: "pexip", comment: "Video Conferencing Application Type"
end

def down
remove_column :virtual_hearings, :meeting_type
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
class AddMeetingTypeToConferenceLinks < Caseflow::Migration
def up
add_column :conference_links, :meeting_type, :varChar, default: "pexip", comment: "Video Conferencing Application Type"
end

def down
remove_column :conference_links, :meeting_type
end
end
Loading