From a6d49f2ab074dc242db7fa6fcd37bee48a83c144 Mon Sep 17 00:00:00 2001 From: Connor Barker Date: Tue, 11 Oct 2022 10:13:44 -0400 Subject: [PATCH] [DUOS-2033][risk=no] Update ResearcherProfile to use FormField components (#1814) * researcher profile use formfield * undo * feedback * feedbac * maybe fix? --- src/components/forms/formUtils.js | 9 +- src/components/forms/forms.js | 4 +- src/pages/ResearcherProfile.js | 253 ++++++++++++++++-------------- 3 files changed, 140 insertions(+), 126 deletions(-) diff --git a/src/components/forms/formUtils.js b/src/components/forms/formUtils.js index 203f42c13..f99a01f16 100644 --- a/src/components/forms/formUtils.js +++ b/src/components/forms/formUtils.js @@ -1,5 +1,5 @@ import { FormFieldTypes, commonRequiredProps, commonOptionalProps } from './forms'; -import { isNil, isFunction, isArray, isEmpty, isString } from 'lodash/fp'; +import { isNil, isFunction, isArray, isString } from 'lodash/fp'; import { isEmailAddress } from '../../libs/utils'; export const validateFormProps = (props) => { @@ -43,18 +43,13 @@ export const customSelectPropValidation = (props) => { throw 'prop \'selectOptions\' must be an array'; } - if (isEmpty(props.selectOptions)) { - throw '\'selectOptions\' cannot be empty'; - } - - const isStringArr = isString(props.selectOptions[0]); + const isStringArr = props.selectOptions.length > 0 && isString(props.selectOptions[0]); props.selectOptions.forEach((opt) => { if (isStringArr) { if (!isString(opt)) { throw 'all values in \'selectOptions\' must be string typed'; } - return; } diff --git a/src/components/forms/forms.js b/src/components/forms/forms.js index 0fbfd21d7..dab3b75b8 100644 --- a/src/components/forms/forms.js +++ b/src/components/forms/forms.js @@ -40,7 +40,9 @@ export const commonOptionalProps = [ 'hideTitle', 'style', 'validators', - 'type' + 'onChange', + 'type', + 'key', ]; // ----------------------------------------------------------------------------------------------------- // diff --git a/src/pages/ResearcherProfile.js b/src/pages/ResearcherProfile.js index 1aef3a1a3..1808b5726 100644 --- a/src/pages/ResearcherProfile.js +++ b/src/pages/ResearcherProfile.js @@ -1,10 +1,10 @@ -import {useState, useEffect} from 'react'; +import {useState, useEffect, useCallback} from 'react'; import {find, isNil, isNumber} from 'lodash'; -import {button, div, form, h, h2, hr, input, label, p, a, textarea} from 'react-hyperscript-helpers'; +import {button, div, form, h, h2, hr, input, label, p, a} from 'react-hyperscript-helpers'; import {eRACommons} from '../components/eRACommons'; import {PageHeading} from '../components/PageHeading'; import {Notification} from '../components/Notification'; -import {SearchSelectOrText} from '../components/SearchSelectOrText'; +import {FormField, FormFieldTypes, FormValidators} from '../components/forms/forms'; import {Institution, Support, User} from '../libs/ajax'; import {NotificationService} from '../libs/notificationService'; import {Storage} from '../libs/storage'; @@ -51,7 +51,10 @@ export default function ResearcherProfile(props) { }); const [institutionList, setInstitutionList] = useState([]); + + const [selectedInstitution, setSelectedInstitution] = useState(); const [signingOfficialList, setSigningOfficialList] = useState([]); + const [currentSigningOfficial, setCurrentSigningOfficial] = useState(null); const [notificationData, setNotificationData] = useState(); @@ -82,11 +85,19 @@ export default function ResearcherProfile(props) { return; } + setSelectedInstitution(institution); + setSigningOfficialList((institution.signingOfficials ? institution.signingOfficials : [])); }); + } else { + setSelectedInstitution(null); } }, [profile.institutionId]); + useEffect(() => { + setCurrentSigningOfficial(findSigningOfficial(profile.selectedSigningOfficialId)); + }, [profile.selectedSigningOfficialId, signingOfficialList, findSigningOfficial]); + const hasInstitution = () => { return (isNumber(profile.institutionId) && profile.institutionId !== 0) || (profile.suggestedInstitution !== undefined && profile.suggestedInstitution !== ''); }; @@ -109,11 +120,10 @@ export default function ResearcherProfile(props) { const getResearcherProfile = async () => { const user = await User.getMe(); - const userProps = getPropertyValuesFromUser(user); setProfile({ - institutionId: userProps.institutionId, + institutionId: user.institutionId || userProps.institutionId, suggestedInstitution: userProps.suggestedInstitution, selectedSigningOfficialId: parseInt(userProps.selectedSigningOfficialId), suggestedSigningOfficial: userProps.suggestedSigningOfficial, @@ -124,20 +134,8 @@ export default function ResearcherProfile(props) { }); }; - const handleChange = (event) => { - let field = event.target.name; - let value = event.target.value; - - let newProfile = Object.assign({}, profile, {[field]: value}); - setProfile(newProfile); - }; - - const handleSupportRequestsChange = (event) => { - let field = event.target.name; - let value = event.target.type === 'checkbox' - ? event.target.checked - : event.target.value; - let newSupportRequests = Object.assign({}, supportRequests, {[field]: value}); + const handleSupportRequestsChange = ({key, value}) => { + let newSupportRequests = Object.assign({}, supportRequests, {[key]: value}); setSupportRequests(newSupportRequests); }; @@ -216,37 +214,56 @@ export default function ResearcherProfile(props) { if (!isSigningOfficial() || (isNil(profile.institutionId) && isNil(profile.suggestedInstitution))) { return div({}, [ - h(SearchSelectOrText, { - id: 'Institution', - label: 'institution', - onPresetSelection: async (selection) => { - setSigningOfficialList([]); // reset - - setProfile(Object.assign({}, profile, {institutionId: selection, suggestedInstitution: undefined})); - }, - onManualSelection: (selection) => { - if (selection == '') { - setProfile(Object.assign({}, profile, {institutionId: undefined, suggestedInstitution: undefined})); - } else { - setProfile(Object.assign({}, profile, {institutionId: null, suggestedInstitution: selection})); - } - }, - options: institutionList.map(institution => { + h(FormField, { + id: 'institutionId', + type: FormFieldTypes.SELECT, + selectOptions: (institutionList).map((i) => { return { - key: institution.id, - displayText: institution.name, + institutionId: i.id, + displayText: i.name, }; }), - value: profile.institutionId, - freetextValue: profile.suggestedInstitution, placeholder: 'Search for Institution...', - className: 'form-control' - }) + 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(institutionList, {id: profile.institutionId}) : null); - const institutionName = (institution ? institution.name : profile.suggestedInstitution); @@ -274,12 +291,20 @@ export default function ResearcherProfile(props) { marginBottom: '1rem' }; + const onChange = ({key, value}) => { + setProfile(Object.assign({}, profile, {[key]: value})); + }; + + const findSigningOfficial = useCallback((id) => { + return signingOfficialList.find((so) => so.userId === id); + }, [signingOfficialList]); + return ( div({ - className: 'container' , + className: 'container', style: { color: '#333F52', - } + }, }, [ div({ className: 'row no-margin' }, [ div({ className: 'col-md-10 col-md-offset-1 col-sm-12 col-xs-12' }, [ @@ -306,18 +331,13 @@ export default function ResearcherProfile(props) { }, [ div({ className: 'form-group' }, [ div({ className: 'col-xs-12' }, [ - label({ - id: 'lbl_profileName', - className: 'control-label', - style: headerStyle, - }, ['Full Name*']), - input({ + h(FormField, { + type: FormFieldTypes.TEXT, + title: 'Full Name', + validators: [FormValidators.REQUIRED], id: 'profileName', - name: 'profileName', - type: 'text', - className: 'form-control', defaultValue: profile.profileName, - onBlur: handleChange, + onChange, }), p( @@ -369,8 +389,6 @@ export default function ResearcherProfile(props) { ]), p({}, ['Please select an institution or enter your institution name if not available from the dropdown.']), generateInstitutionSelectionDisplay(), - - ]), @@ -379,45 +397,55 @@ export default function ResearcherProfile(props) { style: { 'marginTop': '20px' }, isRendered: hasInstitution() && !isSigningOfficial(), }, [ - label({ - id: 'lbl_profileInstitution', - className: 'control-label', - style: headerStyle, - }, [ - 'Signing Official* ', - ]), - p({}, ['Please select your Signing Official or enter your signing official’s email address. This is an individual who has the authority to engage your institution in legal contracts, likely someone in your grants department or office of sponsored research.']), - div({}, - [ - h(SearchSelectOrText, { - id: 'SigningOfficial', - label: 'SigningOfficial', - onPresetSelection: (selection) => { - setProfile(Object.assign({}, profile, {selectedSigningOfficialId: selection, suggestedSigningOfficial: undefined})); - }, - onManualSelection: (selection) => { - if (selection == '') { - setProfile(Object.assign({}, profile, {selectedSigningOfficialId: undefined, suggestedSigningOfficial: undefined})); - } else { - setProfile(Object.assign({}, profile, {selectedSigningOfficialId: null, suggestedSigningOfficial: selection})); - } - }, - options: signingOfficialList.map(signingOfficial => { - return { - key: signingOfficial.userId, - displayText: signingOfficial.displayName, - }; - }), - placeholder: 'Please Select a Signing Official', - searchPlaceholder: 'Search for a Signing Official...', - value: profile.selectedSigningOfficialId, - freetextValue: profile.suggestedSigningOfficial, - className: 'form-control' - }) - ]), + h(FormField, { + title: 'Signing Official', + description: 'Please select your Signing Official or enter your signing official’s email address. This is an individual who has the authority to engage your institution in legal contracts, likely someone in your grants department or office of sponsored research.', + validators: [FormValidators.REQUIRED], + id: 'signingOfficial', + type: FormFieldTypes.SELECT, + defaultValue: { + displayText: ( + (!isNil(currentSigningOfficial) + ? `${currentSigningOfficial.displayName}` + : `Suggested: ${profile.suggestedSigningOfficial}` + )), + }, + selectOptions: (signingOfficialList).map((so) => { + return { + signingOfficialId: so.userId, + displayText: so.displayName, + }; + }), + placeholder: 'Please Select a Signing Official', + isCreatable: true, + selectConfig: { + getNewOptionData: (val) => { + return { + suggestedSigningOfficial: val, + displayText: val, + }; + }, + clearValue: () => { + setProfile(Object.assign({}, + profile, + { + selectedSigningOfficialId: undefined, + suggestedSigningOfficial: undefined + })); + } + }, + onChange: ({value}) => { + setProfile(Object.assign({}, + profile, + { + selectedSigningOfficialId: value?.signingOfficialId, + suggestedSigningOfficial: value?.suggestedSigningOfficial + })); + }, + }), p( { - isRendered: !suggestSigningOfficialValid(), + isRendered: isNil(currentSigningOfficial) && isNil(profile.signingOfficialId) && !suggestSigningOfficialValid(), style: { fontStyle: 'italic', color: '#D13B07', @@ -457,42 +485,31 @@ export default function ResearcherProfile(props) { }, ['Which of the following are you looking to do?*']), possibleSupportRequests.map(supportRequest => { - return div({ className: 'col-xs-12 checkbox', key: supportRequest.key }, [ - input({ - type: 'checkbox', - id: `chk_${supportRequest.key}`, - name: supportRequest.key, - className: 'checkbox-inline checkbox', - checked: supportRequests[supportRequest.id], - onChange: handleSupportRequestsChange - }), - label({ className: 'regular-checkbox', htmlFor: `chk_${supportRequest.key}` }, - [supportRequest.label]) - ]); + return h(FormField, { + toggleText: supportRequest.label, + type: FormFieldTypes.CHECKBOX, + + key: supportRequest.key, + id: supportRequest.key, + onChange: handleSupportRequestsChange, + }); }), div({ className: 'col-xs-12' }, [ div({ style: { margin: '15px 0 10px' }}, [ `Is there anything else you'd like to request?` ]), - - textarea({ - value: supportRequests.extraRequest, - onChange: handleSupportRequestsChange, - className: 'form-control col-xs-12', - name: 'extraRequest', - id: 'supportRequests_extraRequest', + h(FormField, { + type: FormFieldTypes.TEXTAREA, + id: 'extraRequest', + placeholder: 'Enter your request', maxLength: '512', rows: '3', - placeholder: 'Enter your request' - }) + onChange: handleSupportRequestsChange, + }), ]) ]) ]), - - - - div({ className: 'row', style: { margin: '20px 0' }