diff --git a/src/components/ResearcherReview.js b/src/components/ResearcherReview.js
deleted file mode 100644
index 37d814829..000000000
--- a/src/components/ResearcherReview.js
+++ /dev/null
@@ -1,81 +0,0 @@
-import { Component } from 'react';
-import { div, hh, label, form } from 'react-hyperscript-helpers';
-import {getPropertyValuesFromUser} from '../libs/utils';
-import {isNil} from 'lodash/fp';
-import { isEmpty } from 'lodash';
-
-export const ResearcherReview = hh(class ResearcherReview extends Component {
-
- constructor(props) {
- super(props);
- this.state = {
- value: '',
- user: {},
- institution: {},
- researcherProperties: {
- eraCommonsId: '',
- },
- };
- }
-
- componentDidMount() {
- this.calculateResearcherInfo();
- }
-
- calculateResearcherInfo = () => {
- const user = this.props.user;
- let researcherProps = getPropertyValuesFromUser(user);
- this.setState(prev => {
- prev.user = user;
- prev.institution = !isEmpty(user.institution) ? user.institution : null;
- prev.researcherProperties = researcherProps;
- return prev;
- });
- };
-
- componentDidUpdate(prevProps) {
- if (this.props.user !== prevProps.user) {
- this.setState({
- user: this.props.user
- });
- }
- }
-
- render() {
- const { researcherProperties, user, institution } = this.state;
-
- return (
- div({ className: 'container ' }, [
- div({ className: 'col-lg-10 col-lg-offset-1 col-md-10 col-md-offset-1 col-sm-12 col-xs-12 no-padding' }, [
- form({ name: 'researcherForm', noValidate: true }, [
- div({ className: 'row form-group margin-top-20' }, [
- div({ className: 'col-lg-6 col-md-6 col-sm-6 col-xs-12' }, [
- label({ className: 'control-label' }, ['Full Name']),
- div({ id: 'lbl_profileName', className: 'control-data', name: 'profileName', readOnly: true }, [user.displayName])
- ]),
- ]),
-
- div({ className: 'row margin-top-20' }, [
- div({ className: 'col-lg-12 col-md-12 col-sm-12 col-xs-12' }, [
- label({ className: 'control-label rp-title-question default-color' }, ['Researcher Identification'])
- ])
- ]),
-
- div({ className: 'row no-margin' }, [
- div({ className: 'col-lg-6 col-md-6 col-sm-6 col-xs-12' }, [
- label({ className: 'control-label' }, ['NIH User Name']),
- div({ id: 'lbl_profileeraCommonsId', className: 'control-data', name: 'profileeraCommonsId', readOnly: true}, [researcherProperties.eraCommonsId]),
- ]),
- div({ className: 'col-lg-6 col-md-6 col-sm-6 col-xs-12' }, [
- label({ className: 'control-label' }, ['Institution Name']),
- div({ id: 'lbl_profileInstitution', className: 'control-data', name: 'profileInstitution', readOnly: true}, [isNil(institution) ? '' : institution.name]),
- ])
- ]),
- ])
- ]),
- ])
- );
- }
-});
-
-export default ResearcherReview;
diff --git a/src/components/ResearcherReview.jsx b/src/components/ResearcherReview.jsx
new file mode 100644
index 000000000..e53e8b1c8
--- /dev/null
+++ b/src/components/ResearcherReview.jsx
@@ -0,0 +1,68 @@
+import React, {useState, useEffect} from 'react';
+import {getPropertyValuesFromUser} from '../libs/utils';
+import {isNil} from 'lodash/fp';
+import { isEmpty } from 'lodash';
+
+export const ResearcherReview = (props) => {
+ const [state, setState] = useState({
+ value: '',
+ user: {},
+ institution: {},
+ researcherProperties: {
+ eraCommonsId: ''
+ }
+ });
+
+ useEffect(() => {
+ const user = props.user;
+ let researcherProps = getPropertyValuesFromUser(user);
+ setState((prev) => ({
+ ...prev,
+ user: user,
+ institution: !isEmpty(user.institution) ? user.institution : null,
+ researcherProperties: researcherProps
+ }));
+ }, [props.user]);
+
+ const { researcherProperties, user, institution } = state;
+
+ return (
+
+ );
+};
+
+export default ResearcherReview;
diff --git a/src/pages/AdminEditUser.js b/src/pages/AdminEditUser.js
deleted file mode 100644
index 7d2c9ff46..000000000
--- a/src/pages/AdminEditUser.js
+++ /dev/null
@@ -1,346 +0,0 @@
-import _ from 'lodash';
-import {union, contains, map, isEmpty} from 'lodash/fp';
-import React, {Component} from 'react';
-import {button, div, form, h, hh, input, label} from 'react-hyperscript-helpers';
-import {Institution, User} from '../libs/ajax';
-import {Notifications, USER_ROLES} from '../libs/utils';
-import {ResearcherReview} from '../components/ResearcherReview';
-import editUserIcon from '../images/icon_edit_user.png';
-import {PageHeading} from '../components/PageHeading';
-import {SearchSelect} from '../components/SearchSelect';
-
-const adminRole = {'roleId': 4, 'name': USER_ROLES.admin};
-const researcherRole = {'roleId': 5, 'name': USER_ROLES.researcher};
-const signingOfficialRole = {'roleId': 7, 'name': USER_ROLES.signingOfficial};
-
-export const AdminEditUser = hh(class AdminEditUser extends Component {
-
- constructor(props) {
- super(props);
-
- this.state = {
- user: {},
- displayName: '',
- email: '',
- displayNameValid: false,
- updatedRoles: [researcherRole],
- emailPreference: false
- };
-
- this.nameRef = React.createRef();
- }
-
- async componentDidMount() {
- const user = await User.getById(this.props.match.params.userId);
- const institutionOptions = (await Institution.list()).map((institution) => {
- return {
- key: institution.id,
- displayText: institution.name
- };
- });
- const currentRoles = _.map(user.roles, (ur) => {
- return {'roleId': ur.roleId, 'name': ur.name};
- });
- const updatedRoles = isEmpty(currentRoles) ? [researcherRole] : currentRoles;
- this.setState({
- displayName: user.displayName,
- email: user.email,
- user: user,
- updatedRoles: updatedRoles,
- emailPreference: user.emailPreference,
- institutionOptions: institutionOptions,
- institutionId: user.institutionId
- },
- () => {
- this.setState({
- displayNameValid: this.nameRef.current.validity.valid,
- });
- });
- }
-
- OKHandler = async (event) => {
- event.preventDefault();
-
- if (!this.state.displayNameValid) {
- return;
- }
- const userId = this.state.user.userId;
- let user = {
- userId: userId,
- displayName: this.state.displayName,
- emailPreference: this.state.emailPreference,
- institutionId: this.state.institutionId
- };
-
- try {
- await User.update(user, userId);
- await this.updateRolesIfDifferent(userId, this.state.updatedRoles);
- this.props.history.push('/admin_manage_users');
- } catch (error) {
- Notifications.showError({text: 'Error: Failed to update user'});
- }
- };
-
- updateRolesIfDifferent = async (userId, updatedRoles) => {
- const user = await User.getById(userId);
- const currentRoleIds = map('roleId')(user.roles);
- // Always make sure researcher is a role we already have or need to add.
- const updatedRoleIds = union([researcherRole.roleId])(map('roleId')(updatedRoles));
-
- _.map(updatedRoleIds, roleId => {
- if (!contains(roleId)(currentRoleIds)) {
- User.addRoleToUser(userId, roleId);
- }
- });
-
- _.map(currentRoleIds, roleId => {
- if (!contains(roleId)(updatedRoleIds)) {
- // Safety check ... never delete the researcher role!!!
- if (roleId !== researcherRole.roleId) {
- User.deleteRoleFromUser(userId, roleId);
- }
- }
- });
- };
-
- emailPreferenceChanged = (e) => {
- // disable notifications checkbox is not checked: -> Set email preference TRUE
- // disable notifications checkbox is checked: -> Set email preference FALSE
- const checkState = e.target.checked;
- this.setState({
- emailPreference: !checkState
- });
- };
-
- roleStatusChanged = (e, role) => {
- const checkState = e.target.checked;
- // True? add role to state.updatedRoles
- // False? remove role from state.updatedRoles
- let newRoles = [researcherRole];
- if (checkState) {
- newRoles = _.concat(this.state.updatedRoles, role);
- } else {
- newRoles = _.filter(this.state.updatedRoles, (r) => {
- return r.roleId !== role.roleId;
- });
- }
- this.setState(prev => {
- prev.updatedRoles = newRoles;
- return prev;
- });
- };
-
- userHasRole = (role) => {
- const matches = _.filter(this.state.updatedRoles, _.matches(role));
- return !isEmpty(matches);
- };
-
- handleChange = (e) => {
- const name = e.target.name;
- const validName = name + 'Valid';
- this.setState({
- [name]: e.target.value,
- [validName]: e.currentTarget.validity.valid
- });
- };
-
-
- render() {
- const {displayName, email, displayNameValid, institutionId, institutionOptions} = this.state;
- return (
- div({className: 'container container-wide'}, [
- div({className: 'row no-margin'}, [
- div({className: 'col-lg-7 col-md-7 col-sm-12 col-xs-12 no-padding'}, [
- PageHeading({
- id: 'editUser',
- imgSrc: editUserIcon,
- iconSize: 'medium',
- color: 'common',
- title: 'Edit User',
- description: 'Edit a User in the system'
- }),
- ]),
- div({className: 'col-lg-10 col-lg-offset-1 col-md-10 col-md-offset-1 col-sm-12 col-xs-12 no-padding'}, [
-
- form({
- className: 'form-horizontal css-form ',
- name: 'userForm',
- encType: 'multipart/form-data',
- }, [
- div({className: 'form-group first-form-group'}, [
- label({
- id: 'lbl_name',
- className: 'col-lg-3 col-md-3 col-sm-3 col-xs-4 control-label common-color'
- }, ['Name']),
- div({className: 'col-lg-9 col-md-9 col-sm-9 col-xs-8'}, [
- input({
- type: 'text',
- name: 'displayName',
- id: 'txt_name',
- className: 'form-control col-lg-12 vote-input',
- placeholder: 'User name',
- required: true,
- value: displayName,
- autoFocus: true,
- onChange: this.handleChange,
- ref: this.nameRef
- })
- ])
- ]),
-
- div({className: 'form-group'}, [
- label({
- id: 'lbl_email',
- className: 'col-lg-3 col-md-3 col-sm-3 col-xs-4 control-label common-color'
- }, ['Google account id']),
- div({className: 'col-lg-9 col-md-9 col-sm-9 col-xs-8'}, [
- input({
- type: 'email',
- name: 'email',
- id: 'txt_email',
- className: 'form-control col-lg-12 vote-input',
- placeholder: 'e.g. username@broadinstitute.org',
- required: true,
- value: email,
- disabled: true
- })
- ])
- ]),
-
- div({className: 'form-group'}, [
- label({
- id: 'lbl_institution',
- className: 'col-lg-3 col-md-3 col-sm-3 col-xs-4 control-label common-color'
- }, ['Institution']),
- div({className: 'col-lg-9 col-md-9 col-sm-9 col-xs-8'}, [
- h(SearchSelect, {
- id: 'select_institution',
- label: 'institution',
- onSelection: (selection) => {
- this.setState({ institutionId: selection });
- },
- options: institutionOptions || [],
- placeholder: 'Please Select an Institution',
- searchPlaceholder: 'Search for Institution...',
- value: institutionId,
- className: 'form-control'
- })
- ])
- ]),
-
- div({className: 'form-group'}, [
- label({className: 'col-lg-3 col-md-3 col-sm-3 col-xs-4 control-label common-color'}, ['Roles']),
- div({className: 'col-lg-9 col-md-9 col-sm-9 col-xs-8 bold'}, [
- div({className: 'col-lg-6 col-md-6 col-sm-6 col-xs-6'}, [
- div({className: 'checkbox'}, [
- input({
- type: 'checkbox',
- id: 'chk_researcher',
- checked: true,
- readOnly: true,
- className: 'checkbox-inline user-checkbox',
- }),
- label({
- id: 'lbl_researcher',
- className: 'regular-checkbox rp-choice-questions',
- htmlFor: 'chk_researcher'
- }, ['Researcher'])
- ]),
- ])
- ]),
- ]),
- div({className: 'form-group'}, [
- div({
- className: 'col-lg-9 col-lg-offset-3 col-md-9 col-md-offset-3 col-sm-9 col-sm-offset-3 col-xs-8 col-xs-offset-4',
- style: {'paddingLeft': '30px'}
- }, [
- div({className: 'checkbox'}, [
- input({
- type: 'checkbox',
- id: 'chk_signing_official',
- checked: this.userHasRole(signingOfficialRole),
- className: 'checkbox-inline user-checkbox',
- onChange: e => this.roleStatusChanged(e, signingOfficialRole)
- }),
- label({
- id: 'lbl_signing_official',
- className: 'regular-checkbox rp-choice-questions',
- htmlFor: 'chk_signing_official'
- }, ['Signing Official'])
- ]),
- ])
- ]),
- div({className: 'form-group'}, [
- div({
- className: 'col-lg-9 col-lg-offset-3 col-md-9 col-md-offset-3 col-sm-9 col-sm-offset-3 col-xs-8 col-xs-offset-4',
- style: {'paddingLeft': '30px'}
- }, [
- div({className: 'checkbox'}, [
- input({
- type: 'checkbox',
- id: 'chk_admin',
- checked: this.userHasRole(adminRole),
- className: 'checkbox-inline user-checkbox',
- onChange: e => this.roleStatusChanged(e, adminRole)
- }),
- label({
- id: 'lbl_admin',
- className: 'regular-checkbox rp-choice-questions',
- htmlFor: 'chk_admin'
- }, ['Admin'])
- ])
- ])
- ]),
- div({className: 'form-group'}, [
- div({
- isRendered: this.userHasRole(adminRole),
- className: 'col-lg-9 col-lg-offset-3 col-md-9 col-md-offset-3 col-sm-9 col-sm-offset-3 col-xs-8 col-xs-offset-4',
- style: {'paddingLeft': '30px'}
- }, [
- div({className: 'checkbox'}, [
- input({
- id: 'chk_emailPreference',
- type: 'checkbox',
- className: 'checkbox-inline user-checkbox',
- // If email preference is TRUE -> disable checkbox is not checked
- // If email preference is FALSE -> disable checkbox is checked
- checked: !this.state.emailPreference,
- onChange: this.emailPreferenceChanged
- }),
- label({className: 'regular-checkbox rp-choice-questions bold', htmlFor: 'chk_emailPreference'},
- ['Disable Admin email notifications'])
- ])
- ])
- ]),
- div({className: 'col-lg-12 col-xs-12 inline-block'}, [
- div({
- style: {
- marginLeft: '40px',
- }
- }, [
- button({
- id: 'btn_save',
- onClick: () => {
- this.props.history.push('/admin_manage_users');
- },
- className: 'f-left btn-primary btn-back',
- }, ['Back']),
- ]),
- button({
- id: 'btn_save',
- onClick: this.OKHandler,
- className: 'f-right btn-primary common-background',
- disabled: !displayNameValid
- }, ['Save']),
- ])
- ])
- ]),
- ResearcherReview({
- isRendered: !isEmpty(this.state.user),
- user: this.state.user
- })
- ])
- ])
- );
- }
-});
diff --git a/src/pages/AdminEditUser.jsx b/src/pages/AdminEditUser.jsx
new file mode 100644
index 000000000..10b65b9ba
--- /dev/null
+++ b/src/pages/AdminEditUser.jsx
@@ -0,0 +1,336 @@
+import _ from 'lodash';
+import {union, contains, map, isEmpty} from 'lodash/fp';
+import React, {useState, useEffect, useRef} from 'react';
+import {Institution, User} from '../libs/ajax';
+import {Notifications, USER_ROLES} from '../libs/utils';
+import {ResearcherReview} from '../components/ResearcherReview';
+import editUserIcon from '../images/icon_edit_user.png';
+import {PageHeading} from '../components/PageHeading';
+import {SearchSelect} from '../components/SearchSelect';
+
+const adminRole = {'roleId': 4, 'name': USER_ROLES.admin};
+const researcherRole = {'roleId': 5, 'name': USER_ROLES.researcher};
+const signingOfficialRole = {'roleId': 7, 'name': USER_ROLES.signingOfficial};
+
+
+export const AdminEditUser = (props) => {
+ const [state, setState] = useState({
+ user: {},
+ displayName: '',
+ email: '',
+ displayNameValid: false,
+ updatedRoles: [researcherRole],
+ emailPreference: false,
+ institutionOptions: [],
+ institutionId: null
+ });
+ const [fetchingComplete, setFetchingComplete] = useState(false);
+
+ const nameRef = useRef();
+
+ useEffect(() => {
+ const fetchData = async () => {
+ try {
+ const user = await User.getById(props.match.params.userId);
+ const institutionList = await Institution.list();
+ const institutionOptions = institutionList.map((institution) => {
+ return {
+ key: institution.id,
+ displayText: institution.name
+ };
+ });
+ const currentRoles = _.map(user.roles, (ur) => {
+ return {'roleId': ur.roleId, 'name': ur.name};
+ });
+ const updatedRoles = isEmpty(currentRoles) ? [researcherRole] : currentRoles;
+ setState((prev) => ({
+ ...prev,
+ displayName: user.displayName,
+ email: user.email,
+ user: user,
+ updatedRoles: updatedRoles,
+ emailPreference: user.emailPreference,
+ institutionOptions:institutionOptions,
+ institutionId: user.institutionId,
+ }));
+ setFetchingComplete(true);
+ }
+ catch(e) {
+ Notifications.showError({text: 'Error: Unable to retrieve current user from server'});
+ }
+ };
+ fetchData();
+ }, [props.match.params.userId]);
+
+ useEffect(() => {
+ if (fetchingComplete) {
+ setState((prev) => ({
+ ...prev,
+ displayNameValid: nameRef.current.validity.valid
+ }));
+ }
+ }, [fetchingComplete]);
+
+ const OKHandler = async (event) => {
+ event.preventDefault();
+
+ if (!state.displayNameValid) {
+ return;
+ }
+ const userId = state.user.userId;
+ let user = {
+ userId: userId,
+ displayName: state.displayName,
+ emailPreference: state.emailPreference,
+ institutionId: state.institutionId
+ };
+
+ try {
+ await User.update(user, userId);
+ await updateRolesIfDifferent(userId, state.updatedRoles);
+ props.history.push('/admin_manage_users');
+ } catch (error) {
+ Notifications.showError({ text: 'Error: Failed to update user' });
+ }
+ };
+
+ const updateRolesIfDifferent = async (userId, updatedRoles) => {
+ const user = await User.getById(userId);
+ const currentRoleIds = map('roleId')(user.roles);
+ // Always make sure researcher is a role we already have or need to add.
+ const updatedRoleIds = union([researcherRole.roleId])(map('roleId')(updatedRoles));
+
+ _.map(updatedRoleIds, roleId => {
+ if (!contains(roleId)(currentRoleIds)) {
+ User.addRoleToUser(userId, roleId);
+ }
+ });
+
+ _.map(currentRoleIds, roleId => {
+ if (!contains(roleId)(updatedRoleIds)) {
+ // Safety check ... never delete the researcher role!!!
+ if (roleId !== researcherRole.roleId) {
+ User.deleteRoleFromUser(userId, roleId);
+ }
+ }
+ });
+ };
+
+ const emailPreferenceChanged = (e) => {
+ // disable notifications checkbox is not checked: -> Set email preference TRUE
+ // disable notifications checkbox is checked: -> Set email preference FALSE
+ const checkState = e.target.checked;
+ setState({
+ ...state,
+ emailPreference: !checkState
+ });
+ };
+
+ const roleStatusChanged = (e, role) => {
+ const checkState = e.target.checked;
+ // True? add role to state.updatedRoles
+ // False? remove role from state.updatedRoles
+ let newRoles = [researcherRole];
+ if (checkState) {
+ newRoles = _.concat(state.updatedRoles, role);
+ }
+ else {
+ newRoles = _.filter(state.updatedRoles, (r) => {
+ return r.roleId !== role.roleId;
+ });
+ }
+ setState({
+ ...state,
+ updatedRoles: newRoles
+ });
+ };
+
+ const userHasRole = (role) => {
+ const matches = _.filter(state.updatedRoles, _.matches(role));
+ return !isEmpty(matches);
+ };
+
+ const handleChange = (e) => {
+ const name = e.target.name;
+ const validName = name + 'Valid';
+ setState({
+ ...state,
+ [name]: e.target.value,
+ [validName]: e.currentTarget.validity.valid
+ });
+ };
+
+ const { displayName, email, displayNameValid, institutionId, institutionOptions } = state;
+ return (
+
+
+
+
+ {
+ !isEmpty(state.user) && (
+
+ )
+ }
+
+
+ );
+};