From 50cec3149ff26cfe5a96f52fa202943be860de94 Mon Sep 17 00:00:00 2001 From: Hamsini Malli Date: Fri, 21 Jul 2023 17:15:14 -0400 Subject: [PATCH] Duos UI 2602 affiliation and roles (#2290) * added email text field * added new user page * stopped page from reloading * removed sections that are not needed * removed all sections except name/email * removed props * removed functions that were not needed * created user profile directory * changed fields to read-only * used read-only form fields * initialized controlled access grants page * affiliation and roles * completed affiliation and roles component * removed unnecessary files * deleted ControlledAccessGrants * Update ChairConsole.js * Update ajax.js * Update src/Routes.js Co-authored-by: codacy-production[bot] <61871480+codacy-production[bot]@users.noreply.github.com> * Update Routes.js * Update Routes.js * Update src/Routes.js Co-authored-by: codacy-production[bot] <61871480+codacy-production[bot]@users.noreply.github.com> * Update src/Routes.js Co-authored-by: codacy-production[bot] <61871480+codacy-production[bot]@users.noreply.github.com> * added new role component * Revert "Update src/Routes.js" This reverts commit 86b251193281d26881a8d1abf265fa5ca613622b. * Update src/Routes.js Co-authored-by: codacy-production[bot] <61871480+codacy-production[bot]@users.noreply.github.com> * Update src/pages/user_profile/NewRole.js Co-authored-by: codacy-production[bot] <61871480+codacy-production[bot]@users.noreply.github.com> * Update Routes.js * Delete NewRole.js * Update UserProfile.js * Update UserProfile.js * Update UserProfile.js * Update package.json * Update package-lock.json * fix: ensure lockfile uses lf instead of crlf --------- Co-authored-by: codacy-production[bot] <61871480+codacy-production[bot]@users.noreply.github.com> Co-authored-by: Florian Boulnois --- src/Routes.js | 2 + src/pages/ChairConsole.js | 2 +- src/pages/user_profile/AffiliationAndRoles.js | 208 ++++++++++++++++++ src/pages/user_profile/UserProfile.js | 143 ++++++------ 4 files changed, 286 insertions(+), 69 deletions(-) create mode 100644 src/pages/user_profile/AffiliationAndRoles.js diff --git a/src/Routes.js b/src/Routes.js index 68c00281f..3aa2a63e4 100644 --- a/src/Routes.js +++ b/src/Routes.js @@ -16,6 +16,7 @@ import PrivacyPolicy from './pages/PrivacyPolicy'; import ResearcherConsole from './pages/ResearcherConsole'; import ResearcherProfile from './pages/ResearcherProfile'; import UserProfile from './pages/user_profile/UserProfile'; +import AffiliationsAndRoles from './pages/user_profile/AffiliationAndRoles'; import SigningOfficialResearchers from './pages/signing_official_console/SigningOfficialResearchers'; import SigningOfficialDarRequests from './pages/signing_official_console/SigningOfficialDarRequests'; import SigningOfficialDataSubmitters from './pages/signing_official_console/SigningOfficialDataSubmitters'; @@ -64,6 +65,7 @@ const Routes = (props) => ( + diff --git a/src/pages/ChairConsole.js b/src/pages/ChairConsole.js index 7ada2265e..bf61622c5 100644 --- a/src/pages/ChairConsole.js +++ b/src/pages/ChairConsole.js @@ -103,4 +103,4 @@ export default function ChairConsole(props) { consoleType: consoleTypes.CHAIR }), ]); -} \ No newline at end of file +} diff --git a/src/pages/user_profile/AffiliationAndRoles.js b/src/pages/user_profile/AffiliationAndRoles.js new file mode 100644 index 000000000..28c115a07 --- /dev/null +++ b/src/pages/user_profile/AffiliationAndRoles.js @@ -0,0 +1,208 @@ +import { useEffect, useState } from 'react'; +import { Institution, User } from '../../libs/ajax'; +import { find, isNil, isNumber } from 'lodash'; +import { div, p, h1, h, input, button } from 'react-hyperscript-helpers'; +import { Notifications } from '../../libs/utils'; +import { FormField, FormFieldTypes } from '../../components/forms/forms'; + + +export default function AffiliationAndRole(props) { + + const { + user, + userProps, + institutions + } = props; + + const [profile, setProfile] = useState({ + roles: '', + institutionId: undefined, + suggestedInstitution: undefined, + selectedSigningOfficialId: undefined, + suggestedSigningOfficial: undefined, + id: undefined + }); + + const [selectedInstitution, setSelectedInstitution] = useState(); + + useEffect(() => { + const init = async () => { + try { + const rolesList = []; + if (!isNil(user) && !isNil(user.roles)) { + for (let i = 0; i < user.roles.length; i++) { + const newRole = user.roles[i].name; + rolesList.push(newRole); + } + const allRoles = rolesList.join(', '); + setProfile({ + roles: allRoles, + institutionId: user.institutionId || userProps.institutionId, + suggestedInstitution: userProps.suggestedInstitution, + selectedSigningOfficialId: parseInt(userProps.selectedSigningOfficialId), + suggestedSigningOfficial: userProps.suggestedSigningOfficial, + id: user.userId + }); + } + } catch (error) { + Notifications.showError({ text: 'Error: Unable to retrieve user data from server' }); + } + }; + + init(); + + }, [user, userProps]); + + useEffect(() => { + if (profile.institutionId) { + Institution.getById(profile.institutionId).then((institution) => { + if (!institution) { + return; + } + setSelectedInstitution(institution); + }); + } else { + setSelectedInstitution(null); + } + }, [profile.institutionId]); + + + const hasInstitution = () => { + return (isNumber(profile.institutionId) && profile.institutionId !== 0) || (profile.suggestedInstitution !== undefined && profile.suggestedInstitution !== ''); + }; + + const isSigningOfficial = () => { + return user.isSigningOfficial; + }; + + const submitForm = async (event) => { + event.preventDefault(); + await updateInstitution(); + }; + + const formIsValid = () => { + return !hasInstitution() || !isSigningOfficial(); + }; + + const updateInstitution = async () => { + const payload = { + institutionId: profile.institutionId, + suggestedInstitution: profile.suggestedInstitution + }; + + let updatedUser = await User.updateSelf(payload); + return updatedUser; + }; + + const generateInstitutionSelectionDisplay = () => { + if (!isSigningOfficial() || (isNil(profile.institutionId) && isNil(profile.suggestedInstitution))) { + return div({}, + [ + h(FormField, { + id: 'institutionId', + type: FormFieldTypes.SELECT, + selectOptions: (institutions).map((i) => { + return { + institutionId: i.id, + displayText: i.name, + }; + }), + placeholder: 'Search for Institution...', + isCreatable: true, + defaultValue: { + institutionId: selectedInstitution?.institutionId, + suggestedInstitution: profile.suggestedInstitution, + displayText: ( + (!isNil(selectedInstitution) + ? `${selectedInstitution.name}` + : (!isNil(profile.suggestedInstitution) + ? `${profile.suggestedInstitution}` + : '')) + ), + }, + selectConfig: { + clearValue: () => { + setProfile(Object.assign({}, + profile, + { + institutionId: undefined, + suggestedInstitution: undefined + })); + }, + }, + onChange: ({ value }) => { + if (!isNil(value?.institutionId)) { + setProfile(Object.assign({}, profile, { + institutionId: value?.institutionId, + suggestedInstitution: undefined + })); + } else { + setProfile(Object.assign({}, profile, { + institutionId: undefined, + suggestedInstitution: value?.displayText + })); + } + } + }), + ] + ); + } else { + let institution = (profile.institutionId ? find(institutions, { id: profile.institutionId }) : null); + const institutionName = (institution ? institution.name : profile.suggestedInstitution); + + + return div({ + className: '', + style: { padding: 0 }, + }, [ + input({ + id: 'profileInstitution', + name: 'institution', + type: 'text', + disabled: true, + className: 'form-control', + value: institutionName, + }), + ]); + } + }; + + return div({}, [ + h1({ + style: { + color: '#01549F', + fontSize: '20px', + fontWeight: '600', + } + }, ['Affiliation & Role']), + div({ className: '', style: { 'marginTop': '20px' } }, []), + div({ + style: + { + color: '#000', + fontFamily: 'Montserrat', + fontSize: '16px', + fontStyle: 'normal', + fontWeight: '600', + lineHeight: 'normal' + } + }, + [ + p({}, ['Institution']), + div({ style: { marginBottom: '15px' } }, []), + generateInstitutionSelectionDisplay(), + button({ + id: 'btn_submit', + onClick: submitForm, + className: 'f-right btn-primary common-background', + style: { + marginTop: '2rem', + }, + disabled: !formIsValid(), + }, ['Save']), + div({ className: '', style: { 'marginTop': '83px' } }, []), + p({}, ['Role']), + ]), + p({}, [profile.roles]), + ]); +} \ No newline at end of file diff --git a/src/pages/user_profile/UserProfile.js b/src/pages/user_profile/UserProfile.js index 603c755a7..0e4947310 100644 --- a/src/pages/user_profile/UserProfile.js +++ b/src/pages/user_profile/UserProfile.js @@ -1,89 +1,96 @@ -import {useState, useEffect} from 'react'; -import {div, h, h1, hr} from 'react-hyperscript-helpers'; -import {FormField, FormFieldTypes} from '../../components/forms/forms'; -import {PageHeading} from '../../components/PageHeading'; -import {Notification} from '../../components/Notification'; -import {User} from '../../libs/ajax'; -import {NotificationService} from '../../libs/notificationService'; -import { Notifications} from '../../libs/utils'; + +import { useState, useEffect } from 'react'; +import { div, h, h1, hr } from 'react-hyperscript-helpers'; +import { FormField, FormFieldTypes } from '../../components/forms/forms'; +import { PageHeading } from '../../components/PageHeading'; +import { Notification } from '../../components/Notification'; +import AffiliationAndRoles from './AffiliationAndRoles'; +import { Institution } from '../../libs/ajax'; +import { Storage } from '../../libs/storage'; +import { NotificationService } from '../../libs/notificationService'; +import { Notifications, getPropertyValuesFromUser } from '../../libs/utils'; export default function UserProfile() { + + const [user, setUser] = useState({}); + const [userProps, setUserProps] = useState({}); + const [institutions, setInstitutions] = useState([]); + const [profile, setProfile] = useState({ profileName: '', email: undefined, id: undefined }); - const [notificationData, setNotificationData] = useState(); + const [notificationData, setNotificationData] = useState({}); useEffect(() => { const init = async () => { try { - await getUserProfile(); - + const user = Storage.getCurrentUser(); + setUser(user); + setUserProps(getPropertyValuesFromUser(user)); + setProfile({ + profileName: user.displayName, + email: user.email, + id: user.userId + }); + const institutions = await Institution.list(); + setInstitutions(institutions); setNotificationData(await NotificationService.getBannerObjectById('eRACommonsOutage')); } catch (error) { - Notifications.showError({text: 'Error: Unable to retrieve user data from server'}); + Notifications.showError({ text: 'Error: Unable to retrieve user data from server' }); } }; init(); }, []); - const getUserProfile = async () => { - const user = await User.getMe(); - - setProfile({ - profileName: user.displayName, - email: user.email, - id: user.userId - }); - }; - - return ( - div({ - className: 'container', + return div({ + className: '', + style: { + flexDirection: 'column', + padding: '20px 240px 20px' + } + }, [ + div({ className: '' }, [ + Notification({notificationData}), + PageHeading({ + id: 'researcherProfile', + color: 'common', + title: 'Your Profile', + description: 'Please complete the form below to start using DUOS.' + }), + hr({ className: 'section-separator' }) + ]), + h1({ style: { - color: '#333F52', - }, - }, [ - div({ className: 'row no-margin'}, [ - div({ className: 'col-md-10 col-md-offset-1 col-sm-12 col-xs-12' }, [ - Notification({notificationData}), - PageHeading({ - id: 'researcherProfile', - color: 'common', - title: 'Your Profile', - description: 'Please complete the form below to start using DUOS.' - }), - hr({ className: 'section-separator' }) - ]), - div({ - className: 'col-md-10 col-md-offset-1 col-xs-12 no-padding', - style: { - fontFamily: 'Montserrat', - } }, [ - h1({style: { - color: '#01549F', - fontSize: '20px', - fontWeight: '600', - } }, ['Full Name:']), - div({ className: '', style: { 'marginTop': '10px' } }, []), - h(FormField, { - id: 'profileName', - type: FormFieldTypes.TEXT, - defaultValue: profile.profileName, - readOnly: true, - }), - div({ className: '', style: { 'marginTop': '10px' } }, []), - h(FormField, { - id: 'profileEmail', - type: FormFieldTypes.TEXT, - defaultValue: profile.email, - readOnly: true, - }), - ]) - ]) - ]) - ); -} \ No newline at end of file + color: '#01549F', + fontSize: '20px', + fontWeight: '600', + marginBottom: '15px', + marginTop: '40px' + } + }, ['Full Name']), + h(FormField, { + type: FormFieldTypes.TEXT, + id: 'profileName', + defaultValue: profile.profileName, + readOnly: true, + }), + div({ className: '', style: { 'marginTop': '10px' } }, []), + h(FormField, { + type: FormFieldTypes.TEXT, + id: 'profileEmail', + defaultValue: profile.email, + readOnly: true, + }), + div({ className: '', style: { 'marginTop': '60px' } }, []), + AffiliationAndRoles({ + user: user, + userProps: userProps, + institutions: institutions + }), + ]); + +}