diff --git a/src/components/SearchSelectOrText.js b/src/components/SearchSelectOrText.js index 5831658ec..103fdf9cf 100644 --- a/src/components/SearchSelectOrText.js +++ b/src/components/SearchSelectOrText.js @@ -1,5 +1,5 @@ +import React from 'react'; import { useState, useEffect, useRef } from 'react'; -import {div, input, span, a, ul, li } from 'react-hyperscript-helpers'; import {isEqual} from 'lodash'; import {find} from 'lodash/fp'; @@ -68,57 +68,53 @@ export const SearchSelectOrText = (props) => { return ( - div({ className: 'dropdown select-dropdown', id, name: label }, [ - a({ - className: `btn select-btn btn-secondary dropdown-toggle ${errored ? 'errored' : ''}`, - role: 'button', - id: 'dropdownMenuLink', - 'data-toggle': 'dropdown', - 'aria-haspopup': true, - 'aria-expanded': false, - onClick: onOpen, - disabled - }, [ - div({ - style: { width: '100%' } - }, [ - span([currentDisplay]), - span({ className: 'caret select-caret caret-margin', style: { right: '2%' } }) - ]) - ]), - div({ - className: 'dropdown-menu select-dropdown-menu', - onBlur: () => { - selectManual(searchTerms.current.value); - onBlur && onBlur(); - } - }, [ - input({ - type: 'text', - placeholder: searchPlaceholder ? searchPlaceholder : 'Search...', - className: 'search-bar', - onChange:() => handleSearch(searchTerms), - onKeyDown: (e) => { - if (e.key == 'Enter') { +
+ +
{ + selectManual(searchTerms.current.value); + onBlur && onBlur(); + }}> + handleSearch(searchTerms)} + onKeyDown={(e) => { + if (e.key === 'Enter') { selectManual(searchTerms.current.value); } - }, - ref: searchTerms - }), - div({ - className: 'dropdown-divider' - }), - ul({ style: { paddingLeft: 0 } }, filteredList.map(item => { - return li({ - className: item.key === currentSelection - ? 'dropdown-item select-dropdown-item active' - : 'dropdown-item select-dropdown-item', - onMouseUp: () => { - select(item.key); - }, - }, [item.displayText]); - })) - ]) - ]) + }} + ref={searchTerms} + /> +
+
    + {filteredList.map(item => ( +
  • { + select(item.key); + }} + key={item.key} + > + {item.displayText} +
  • + ))} +
+
+
); }; diff --git a/src/components/data_update/DatasetUpdate.js b/src/components/data_update/DatasetUpdate.js index d589e376f..04b028668 100644 --- a/src/components/data_update/DatasetUpdate.js +++ b/src/components/data_update/DatasetUpdate.js @@ -1,7 +1,6 @@ +import React from 'react'; import { useCallback, useState, useEffect } from 'react'; -import { button, h, h2, div } from 'react-hyperscript-helpers'; -import { find, isArray, isNil } from 'lodash/fp'; - +import { find, isNil } from 'lodash/fp'; import { FormFieldTypes, FormField, FormValidators } from '../forms/forms'; import { DAC, DAR, DataSet } from '../../libs/ajax'; import { Notifications } from '../../libs/utils'; @@ -133,261 +132,255 @@ export const DatasetUpdate = (props) => { } }, [prefillFormData, dataset, formData]); - return h(div, { - className: 'data-update-section', - }, [ - h2('1. Dataset Information'), - h(FormField, { - id: 'datasetName', - title: 'Dataset Name', - validators: [FormValidators.REQUIRED], - defaultValue: formData.properties.datasetName, - onChange: ({ value }) => { - formData.properties.datasetName = value; - } - }), - h(FormField, { - id: 'description', - title: 'Dataset Description', - validators: [FormValidators.REQUIRED], - defaultValue: formData.properties.description, - onChange: ({ value }) => { - formData.properties.description = value; - } - }), - h(FormField, { - id: 'dataDepositor', - title: 'Data Custodian', - validators: [FormValidators.REQUIRED], - defaultValue: formData.properties.dataDepositor, - onChange: ({ value }) => { - formData.properties.dataDepositor = value; - } - }), - h(FormField, { - id: 'principalInvestigator', - title: 'Principal Investigator (PI)', - validators: [FormValidators.REQUIRED], - defaultValue: formData.properties.principalInvestigator, - onChange: ({ value }) => { - formData.properties.principalInvestigator = value; - } - }), - h(FormField, { - id: 'dbGap', - title: 'Dataset Repository URL', - validators: [FormValidators.REQUIRED], - defaultValue: formData.properties.dbGap, - onChange: ({ value }) => { - formData.properties.dbGap = value; - } - }), - h(FormField, { - id: 'dataType', - title: 'Data Type', - validators: [FormValidators.REQUIRED], - defaultValue: formData.properties.dataType, - onChange: ({ value }) => { - formData.properties.dataType = value; - } - }), - h(FormField, { - id: 'species', - title: 'Species', - validators: [FormValidators.REQUIRED], - defaultValue: formData.properties.species, - onChange: ({ value }) => { - formData.properties.species = value; - } - }), - h(FormField, { - id: 'phenotype', - title: 'Phenotype/Indication', - validators: [FormValidators.REQUIRED], - defaultValue: formData.properties.phenotype, - onChange: ({ value }) => { - formData.properties.phenotype = value; - } - }), - h(FormField, { - id: 'nrParticipants', - title: '# of Participants', - type: FormFieldTypes.NUMBER, - validators: [FormValidators.REQUIRED], - defaultValue: formData.properties.nrParticipants, - onChange: ({ value }) => { - formData.properties.nrParticipants = value; - } - }), - h(FormField, { - id: 'dac', - title: 'Data Access Committee', - validators: [FormValidators.REQUIRED], - type: FormFieldTypes.SELECT, - selectOptions: dacOptions(formData.dac.dacs), - defaultValue: [ - { displayText: formData.dac.name, dacId: formData.dac.dacId }, - ], - disabled: true, - }), - h2('2. Data Use Terms'), - // readonly primary - div({}, [ - h(FormField, { - title: 'Primary Data Use Terms*', - description: 'Please select one of the following data use permissions for your dataset', - type: FormFieldTypes.RADIOBUTTON, - id: 'generalUse', - toggleText: 'General Research Use', - value: 'generalUse', - defaultValue: formData.dataUse.generalUse === true ? 'generalUse' : undefined, - disabled: true, - }), - h(FormField, { - type: FormFieldTypes.RADIOBUTTON, - id: 'hmbResearch', - toggleText: 'Health/Medical/Biomedical Research Use', - value: 'hmbResearch', - defaultValue: formData.dataUse.hmbResearch === true ? 'hmbResearch' : undefined, - disabled: true, - }), - h(FormField, { - type: FormFieldTypes.RADIOBUTTON, - id: 'diseaseRestrictions', - toggleText: 'Disease-Specific Research Use', - value: 'diseaseRestrictions', - defaultValue: isArray(formData.dataUse.diseaseRestrictions) && formData.dataUse.diseaseRestrictions.length > 0 ? 'diseaseRestrictions' : undefined, - disabled: true, - }), - div({ - style: { - marginBottom: '1.0rem' - } - }, [ - h(FormField, { - type: FormFieldTypes.SELECT, - isMulti: true, - isCreatable: true, - optionsAreString: true, - isAsync: true, - id: 'diseaseRestrictionsText', - validators: [FormValidators.REQUIRED], - placeholder: 'none', - loadOptions: searchOntologies, - defaultValue: formData.dataUse.diseaseLabels, - disabled: true, - }), - ]), - h(FormField, { - type: FormFieldTypes.RADIOBUTTON, - id: 'otherPrimary', - toggleText: 'Other', - value: 'otherPrimary', - defaultValue: formData.dataUse.otherRestrictions ? 'otherPrimary' : undefined, - disabled: true, - }), - h(FormField, { - id: 'otherPrimaryText', - validators: [FormValidators.REQUIRED], - placeholder: 'none', - defaultValue: formData.dataUse.other, - disabled: true, - }), - ]), - // secondary - div({}, [ - h(FormField, { - title: 'Secondary Data Use Terms', - description: 'Please select all applicable data use parameters.', - type: FormFieldTypes.CHECKBOX, - id: 'methodsResearch', - toggleText: 'No methods development or validation studies (NMDS)', - defaultValue: formData.dataUse.methodsResearch === true, - disabled: true, - }), - h(FormField, { - type: FormFieldTypes.CHECKBOX, - id: 'geneticStudiesOnly', - toggleText: 'Genetic studies only (GSO)', - defaultValue: formData.dataUse.geneticStudiesOnly === true, - disabled: true, - }), - h(FormField, { - type: FormFieldTypes.CHECKBOX, - id: 'publicationResults', - toggleText: 'Publication Required (PUB)', - defaultValue: formData.dataUse.publicationResults === true, - disabled: true, - }), - h(FormField, { - type: FormFieldTypes.CHECKBOX, - id: 'collaboratorRequired', - toggleText: 'Collaboration Required (COL)', - defaultValue: formData.dataUse.collaboratorRequired === true, - disabled: true, - }), - h(FormField, { - type: FormFieldTypes.CHECKBOX, - id: 'ethicsApprovalRequired', - name: 'ethicsApprovalRequired', - toggleText: 'Ethics Approval Required (IRB)', - defaultValue: formData.dataUse.ethicsApprovalRequired === true, - disabled: true, - }), - h(FormField, { - type: FormFieldTypes.CHECKBOX, - id: 'geographicalRestrictions', - toggleText: 'Geographic Restriction (GS-)', - defaultValue: formData.dataUse.geographicalRestrictions === 'Yes', - disabled: true, - }), - h(FormField, { - type: FormFieldTypes.CHECKBOX, - id: 'publicationMoratorium', - toggleText: 'Publication Moratorium (MOR)', - defaultValue: formData.dataUse.publicationMoratorium === 'true', - disabled: true, - }), - h(FormField, { - type: FormFieldTypes.CHECKBOX, - id: 'nonCommercialUse', - toggleText: 'Non-profit Use Only (NPU)', - defaultValue: formData.dataUse.commercialUse === false, - disabled: true, - }), - h(FormField, { - type: FormFieldTypes.CHECKBOX, - id: 'otherSecondary', - toggleText: 'Other', - defaultValue: formData.dataUse.hasSecondaryOther, - disabled: true, - }), - h(FormField, { - id: 'otherSecondaryText', - validators: [FormValidators.REQUIRED], - placeholder: 'Please specify', - defaultValue: formData.dataUse.secondaryOther, - disabled: true, - }), - ]), - h2('3. NIH Certification'), - div({ style: { display: 'flex', flexDirection: 'row', justifyContent: 'flex-start', alignItems: 'flex-end', marginRight: '30px' } }, [ - h(FormField, { - type: FormFieldTypes.FILE, - title: 'NIH Institutional Certification', - description: 'If an Institutional Certification for this dataset exists, please upload it here', - id: 'nihInstitutionalCertificationFile', - placeholder: 'default.txt', - }), - ]), - div({ className: 'flex flex-row', style: { justifyContent: 'flex-end', marginTop: '2rem', marginBottom: '2rem' } }, [ - button({ - className: 'button button-white', - type: 'submit', - onClick: submitForm, - }, 'Submit'), - ]), - ]); + return ( +
+

1. Dataset Information

+ { + formData.properties.datasetName = value; + }} + /> + { + formData.properties.description = value; + }} + /> + { + formData.properties.dataDepositor = value; + }} + /> + { + formData.properties.principalInvestigator = value; + }} + /> + { + formData.properties.dbGap = value; + }} + /> + { + formData.properties.dataType = value; + }} + /> + { + formData.properties.species = value; + }} + /> + { + formData.properties.phenotype = value; + }} + /> + { + formData.properties.nrParticipants = value; + }} + /> + +

2. Data Use Terms

+ {/* readonly primary */} +
+ + + 0 ? 'diseaseRestrictions' : undefined} + disabled={true} + /> +
+ +
+ + +
+ {/* secondary */} +
+ + + + + + + + + + +
+

3. NIH Certification

+
+ +
+
+ +
+
+ ); }; export default DatasetUpdate; diff --git a/src/components/modals/TranslatedDulModal.js b/src/components/modals/TranslatedDulModal.js index cdd81d437..dd2990920 100644 --- a/src/components/modals/TranslatedDulModal.js +++ b/src/components/modals/TranslatedDulModal.js @@ -1,10 +1,10 @@ -import {li, ul, span} from 'react-hyperscript-helpers'; +import React from 'react'; import { BaseModal } from '../BaseModal'; import { useState, useEffect } from 'react'; import isEmpty from 'lodash/fp/isEmpty'; import {DataUseTranslation} from '../../libs/dataUseTranslation'; -const MODAL_ID = 'translatedDul'; +const MODAL_ID = 'translatedDulModal'; const listStyle = { listStyle: 'none' @@ -13,53 +13,56 @@ const listStyle = { //NOTE: li partial can be used in components that only need the list async function GenerateUseRestrictionStatements(dataUse) { if (!dataUse || isEmpty(dataUse)) { - return [li({ - className: 'translated restriction', - key: 'restriction-none' - }, ['None'])]; + return ( +
  • + None +
  • + ); } const translations = await DataUseTranslation.translateDataUseRestrictions(dataUse); return translations.map((restriction) => { - return li({ - className: 'translated-restriction', - key: `${restriction.code}-statement`, - }, [span({ style: { fontWeight: 'bold' } }, [restriction.code, ': ']), restriction.description]); + return ( +
  • + {restriction.code}: + {restriction.description} +
  • + ); }); } export default function TranslatedDulModal(props) { - const OKHandler = () => { - props.onOKRequest(MODAL_ID); - }; + const { showModal, onCloseRequest, dataUse } = props; + + const [translatedDulList, setTranslatedDulList] = useState([]); const closeHandler = () => { - props.onCloseRequest(MODAL_ID); + onCloseRequest(MODAL_ID); }; - const [translatedDULList, setTranslatedDULList] = useState(GenerateUseRestrictionStatements(props.dataUse || [])); - useEffect(() => { - const getTranslatedDULList = async() => { - const list = await GenerateUseRestrictionStatements(props.dataUse || []); - setTranslatedDULList(list); + const getTranslatedDulList = async () => { + const dulList = await GenerateUseRestrictionStatements(dataUse || []); + setTranslatedDulList(dulList); }; - getTranslatedDULList(); - }, [props.dataUse]); + getTranslatedDulList(); + }, [dataUse]); return ( BaseModal({ - id: 'translatedDulModal', - showModal: props.showModal, + id: MODAL_ID, + showModal: showModal, onRequestClose: closeHandler, color: 'dataset', type: 'informative', iconSize: 'none', title: 'Data Use Terms', - action: { label: 'Close', handler: OKHandler } + action: { label: 'Close', handler: closeHandler } }, [ - ul({style: listStyle, id: 'txt_translatedRestrictions', className: 'row no-margin translated-restriction'}, translatedDULList), + ]) ); } diff --git a/src/pages/ConsentTextGenerator.js b/src/pages/ConsentTextGenerator.js index 606c912d3..34ff6b01e 100644 --- a/src/pages/ConsentTextGenerator.js +++ b/src/pages/ConsentTextGenerator.js @@ -1,5 +1,5 @@ +import React from 'react'; import {Styles} from '../libs/theme'; -import {a, br, button, div, h, input, label, span, textarea} from 'react-hyperscript-helpers'; import {RadioButton} from '../components/RadioButton'; import AsyncSelect from 'react-select/async'; import {isNil, isEmpty, head} from 'lodash/fp'; @@ -61,227 +61,194 @@ export default function ConsentTextGenerator() { }; return ( - div({style: {...Styles.PAGE, color: '#1f3b50' }}, [ - div({style: {...Styles.TITLE, marginTop: '3.5rem'}}, [ - 'Consent Text Generator' - ]), - div({style: {...Styles.SMALL, marginTop: '1rem'}}, [ - 'This tool is made publicly available by the DUOS team for anyone' + - ' interested in leveraging standardized data sharing language in their' + - ' consent forms. The tool leverages the Global Alliance for Genomics ' + - 'and Health’s (GA4GH) companion standards of the ', - a({href: 'https://github.com/EBISPOT/DUO' , target:'_blank', rel:'noopener noreferrer' - }, ['Data Use Ontology (DUO)']), - ' and ', - a({href: 'https://drive.google.com/file/d/102_I0_phOGs9YSmPx7It9CSt1sHFJ87C/view', target: '_blank', rel: 'noreferrer noopener' - }, ['Machine Readable Consent Guidance (MRCG)']), - '. The DUO is a structured vocabulary describing permitted data uses and ' + - 'the MRCG is a suggested representation of those uses in consent form language. ' + - 'This tool enables users to easily define what types of data use they would ' + - 'like permitted in their consent forms and then suggests corresponding text ' + - 'for the consent form below, based on the MRCG.' - ]), - div({className: 'form-group', style: {marginTop: '1rem'}}, [ - label({style: Styles.MEDIUM}, [ - '1. Permitted data uses', br(), - span({style: Styles.MEDIUM_DESCRIPTION}, ['Determine what type of secondary use is permitted for you study\'s data.']), - ]), - div({}, [ - RadioButton({ - value: 'general', - defaultChecked: general, - onClick: () => { +
    +
    + Consent Text Generator +
    +
    + This tool is made publicly available by the DUOS team for anyone interested in leveraging standardized data sharing language in their consent forms. The tool leverages the Global Alliance for Genomics and Health's (GA4GH) companion standards of the + {' '} + + Data Use Ontology (DUO) + + {' '}and{' '} + + Machine Readable Consent Guidance (MRCG) + + . The DUO is a structured vocabulary describing permitted data uses and the MRCG is a suggested representation of those uses in consent form language. This tool enables users to easily define what types of data use they would like permitted in their consent forms and then suggests corresponding text for the consent form below, based on the MRCG. +
    +
    + +
    + { setGeneral(true), setHmb(false), setDiseases(false), setOther(false), setOntologies([]), clearOtherTextBox(); - }, - label: 'General Research Use (GRU): ', - description: 'use is permitted for any research purpose', - style: { fontFamily: 'Montserrat', color: '#1f3b50'} - }), - - RadioButton({ - value: 'hmb', - defaultChecked: hmb, - onClick: () => { + }} + label="General Research Use (GRU): " + description="use is permitted for any research purpose" + style={{ fontFamily: 'Montserrat', color: '#1f3b50' }} + /> + { setHmb(true), setGeneral(false), setDiseases(false), setOther(false), setOntologies([]), clearOtherTextBox(); - }, - label: 'Health/Medical/Biomedical Use (HMB): ', - description: 'use is permitted for any health, medical, or biomedical purpose', - style: { fontFamily: 'Montserrat', color: '#1f3b50'} - }), - - RadioButton({ - value: 'diseases', - defaultChecked: diseases, - onClick: () => { + }} + label="Health/Medical/Biomedical Use (HMB): " + description="use is permitted for any health, medical, or biomedical purpose" + style={{ fontFamily: 'Montserrat', color: '#1f3b50' }} + /> + { setDiseases(true), setHmb(false), setGeneral(false), setOther(false), clearOtherTextBox(); - }, - label: 'Disease-related studies (DS): ', - description: 'use is permitted for research on the specified disease', - style: { fontFamily: 'Montserrat', color: '#1f3b50'} - }), - - div({ - style: {buttonStyle, marginBottom: '10px', cursor: diseases ? 'pointer' : 'not-allowed'}, - }, [ - h(AsyncSelect, { - isDisabled: !diseases, - isMulti: true, - loadOptions: (query, callback) => searchOntologies(query, callback), - onChange: (option) => option ? setOntologies(option) : setOntologies, - value: ontologies, - placeholder: 'Please enter one or more diseases', - classNamePrefix: 'select', - }), - ]), - - RadioButton({ - value: 'other', - defaultChecked: other, - onClick: () => { - setOther(true), setHmb(false), setDiseases(false), setGeneral(false), setOntologies([]); - }, - label: 'Other Use: ', - description: 'permitted research use is defined as follows: ', - style: { fontFamily: 'Montserrat', color: '#1f3b50'} - }), - - textarea({ - className: 'form-control', - onBlur: (e) => setOtherText(e.target.value), - maxLength: '512', - rows: '2', - required: other, - disabled: !other, - id: 'other_text', - placeholder: 'Please specify if selected (max. 512 characters)', - }), - ]), - ]), - - div({className: 'form-group', style: {marginTop: '2rem'}}, [ - label({style: {...Styles.MEDIUM, marginBottom: '5px'}}, [ - '2. Additional constraints', br(), - span({style: Styles.MEDIUM_DESCRIPTION}, ['If necessary, choose any additional terms on your study\'s data to govern its use.']), - ]), - - div({}, [ - div({className: 'checkbox'}, [ - input({ - checked: nmds, - onChange: (e) => setNmds(e.target.checked), - id: 'checkNMDS', - type: 'checkbox', - }), - label({ - style: labelStyle, - className: 'regular-checkbox', - htmlFor: 'checkNMDS', - }, ['No methods development or validation studies (NMDS)']), - ]), - - div({className: 'checkbox'}, [ - input({ - checked: gso, - onChange: (e) => setGso(e.target.checked), - id: 'checkGSO', - type: 'checkbox', - }), - label({ - style: labelStyle, - className: 'regular-checkbox', - htmlFor: 'checkGSO', - }, ['Genetic Studies Only (GSO)']), - ]), - - div({className: 'checkbox'}, [ - input({ - checked: pub, - onChange: (e) => setPub(e.target.checked), - id: 'checkPUB', - type: 'checkbox', - }), - label({ - style: labelStyle, - className: 'regular-checkbox', - htmlFor: 'checkPUB', - }, ['Publication Required (PUB)']), - ]), - - div({className: 'checkbox'}, [ - input({ - checked: col, - onChange: (e) => setCol(e.target.checked), - id: 'checkCOL', - type: 'checkbox', - }), - label({ - style: labelStyle, - className: 'regular-checkbox', - htmlFor: 'checkCOL', - }, ['Collaboration Required (COL)']), - ]), - - div({className: 'checkbox'}, [ - input({ - checked: irb, - onChange: (e) => setIrb(e.target.checked), - id: 'checkIRB', - type: 'checkbox', - }), - label({ - style: labelStyle, - className: 'regular-checkbox', - htmlFor: 'checkIRB', - }, ['Ethics Approval Required (IRB)']), - ]), - - div({className: 'checkbox'}, [ - input({ - checked: gs, - onChange: (e) => setGs(e.target.checked), - id: 'checkGS', - type: 'checkbox', - }), - label({ - style: labelStyle, - className: 'regular-checkbox', - htmlFor: 'checkGS', - }, ['Geographic Restriction (GS-)']), - ]), - - div({className: 'checkbox'}, [ - input({ - checked: npu, - onChange: (e) => setNpu(e.target.checked), - id: 'checkNPU', - type: 'checkbox', - }), - label({ - style: labelStyle, - className: 'regular-checkbox', - htmlFor: 'checkNPU', - }, ['Non-Profit Use Only (NPU)']), - ]) - ]) - ]), - - button({ - style: {...Styles.TABLE.TABLE_TEXT_BUTTON, marginBottom: '2rem'}, - className: 'button', - onClick: () => generate(), - }, ['Generate']), - - textarea({ - defaultValue: sdsl, - className: 'form-control', - rows: '12', - required: false, - readOnly: true, - style: {backgroundColor: '#fff'} - }), - - div({style: {marginBottom: '2rem'}}) - - ]) + }} + label="Disease-related studies (DS): " + description="use is permitted for research on the specified disease" + style={{ fontFamily: 'Montserrat', color: '#1f3b50' }} + /> +
    +
    + searchOntologies(query, callback)} + onChange={(option) => (option ? setOntologies(option) : setOntologies)} + value={ontologies} + placeholder="Please enter one or more diseases" + classNamePrefix="select" + /> +
    + { + setOther(true), setHmb(false), setDiseases(false), setGeneral(false), setOntologies([]); + }} + label="Other Use: " + description="permitted research use is defined as follows: " + style={{ fontFamily: 'Montserrat', color: '#1f3b50' }} + /> +