diff --git a/package.json b/package.json
index 3ea1e41e8..806ff7189 100644
--- a/package.json
+++ b/package.json
@@ -82,7 +82,6 @@
"prop-types": "15.7.2",
"raf": "3.4.1",
"react": "16.13.0",
- "react-children-utilities": "2.0.12",
"react-dates": "21.8.0",
"react-dom": "16.13.0",
"react-error-boundary": "1.2.5",
diff --git a/src/components/Form/FormDatePicker.tsx b/src/components/Form/FormDatePicker.tsx
index 012c94098..9257431ba 100644
--- a/src/components/Form/FormDatePicker.tsx
+++ b/src/components/Form/FormDatePicker.tsx
@@ -7,6 +7,7 @@ import Media from 'react-media'
import { Col, FormGroup, Row } from 'reactstrap'
import FormLabel from './FormLabel'
+import { HelpProps } from './FormHelpButton'
import { DateRange } from '../../algorithms/types/Param.types'
@@ -21,7 +22,7 @@ function getNumberOfMonthsCount(media: { tiny: boolean; small: boolean; medium:
export interface FormDatePickerProps {
identifier: string
label: string
- help?: string | React.ReactNode
+ help?: HelpProps
allowPast?: boolean
}
diff --git a/src/components/Form/FormDropdown.tsx b/src/components/Form/FormDropdown.tsx
index a6fdf5f54..78a6e383c 100644
--- a/src/components/Form/FormDropdown.tsx
+++ b/src/components/Form/FormDropdown.tsx
@@ -3,6 +3,8 @@ import React from 'react'
import { Field, FieldProps, FormikErrors, FormikTouched, FormikValues } from 'formik'
import FormDropdownStateless from './FormDropdownStateless'
+import { HelpProps } from './FormHelpButton'
+
export interface FormDropdownOption {
value: ValueType
label: string
@@ -11,7 +13,7 @@ export interface FormDropdownOption {
export interface FormDropdownProps {
identifier: string
label: string
- help?: string | React.ReactNode
+ help?: HelpProps
options: FormDropdownOption[]
errors?: FormikErrors
touched?: FormikTouched
diff --git a/src/components/Form/FormDropdownStateless.tsx b/src/components/Form/FormDropdownStateless.tsx
index 93f5ff60e..630f2a75f 100644
--- a/src/components/Form/FormDropdownStateless.tsx
+++ b/src/components/Form/FormDropdownStateless.tsx
@@ -5,11 +5,12 @@ import { Col, FormGroup, Row } from 'reactstrap'
import { FormDropdownOption } from './FormDropdownOption'
import FormLabel from './FormLabel'
+import { HelpProps } from './FormHelpButton'
export interface FormDropdownProps {
identifier: string
label: string | React.ReactNode
- help?: string | React.ReactNode
+ help?: HelpProps
options: FormDropdownOption[]
defaultOption?: FormDropdownOption
value?: FormDropdownOption
diff --git a/src/components/Form/FormHelpButton.test.tsx b/src/components/Form/FormHelpButton.test.tsx
index be79d4714..c1fba65e2 100644
--- a/src/components/Form/FormHelpButton.test.tsx
+++ b/src/components/Form/FormHelpButton.test.tsx
@@ -1,22 +1,24 @@
import React from 'react'
import { render, fireEvent, waitForElementToBeRemoved } from '@testing-library/react'
-import FormHelpButton from './FormHelpButton'
+import FormHelpButton, { help } from './FormHelpButton'
describe('FormHelpButton', () => {
it('renders', () => {
- const { getByLabelText } = render( )
+ const { getByLabelText } = render( )
expect(getByLabelText('help')).not.toBeNull()
})
it('initially hides help', () => {
- const { queryByText } = render( )
+ const { queryByText } = render( )
expect(queryByText('def')).toBeNull()
})
it('opens', async () => {
- const { getByLabelText, findByText, queryByText } = render( )
+ const { getByLabelText, findByText, queryByText } = render(
+ ,
+ )
fireEvent.click(getByLabelText('help'))
@@ -26,7 +28,7 @@ describe('FormHelpButton', () => {
it('displays help', async () => {
const { getByLabelText, findByText, queryByText } = render(
- ,
+ ,
)
fireEvent.click(getByLabelText('help'))
@@ -35,8 +37,21 @@ describe('FormHelpButton', () => {
expect(queryByText('some help')).toBeTruthy()
})
+ it('it displays a ReactNode', async () => {
+ const { getByLabelText, findByText, queryByText } = render(
+ Hello, ReactNode)} />,
+ )
+
+ fireEvent.click(getByLabelText('help'))
+
+ await findByText('Hello, ReactNode')
+ expect(queryByText('Hello, ReactNode')).toBeTruthy()
+ })
+
it('closes inside', async () => {
- const { getByLabelText, findByText, queryByText } = render( )
+ const { getByLabelText, findByText, queryByText } = render(
+ ,
+ )
fireEvent.click(getByLabelText('help'))
await findByText('def')
expect(queryByText('def')).not.toBeNull()
@@ -50,7 +65,7 @@ describe('FormHelpButton', () => {
it('closes outside', async () => {
const { getByLabelText, findByText, getByText, queryByText } = render(
-
+
click outside
,
)
diff --git a/src/components/Form/FormHelpButton.tsx b/src/components/Form/FormHelpButton.tsx
index 9edacb4a7..e80c6aa06 100644
--- a/src/components/Form/FormHelpButton.tsx
+++ b/src/components/Form/FormHelpButton.tsx
@@ -2,8 +2,6 @@ import React from 'react'
import { Button, Card, CardBody, UncontrolledPopover } from 'reactstrap'
-import { onlyText } from 'react-children-utilities'
-
import { FaQuestion } from 'react-icons/fa'
import './FormHelpButton.scss'
@@ -12,13 +10,21 @@ function safeId(id: string) {
return id.replace('.', '-')
}
+export interface HelpProps {
+ label: string
+ content: string | React.ReactNode
+}
+
+export function help(label: string, content: string | React.ReactNode): HelpProps {
+ return { label, content }
+}
+
export interface FormHelpButtonProps {
identifier: string
- label: string | React.ReactNode
- help?: string | React.ReactNode
+ help?: HelpProps
}
-export default function FormHelpButton({ identifier, label, help }: FormHelpButtonProps) {
+export default function FormHelpButton({ identifier, help }: FormHelpButtonProps) {
return (
<>
- {label && {onlyText(label)} }
- {help}
+ {help && {help.label} }
+ {help && {help.content}
}
+ {!help && No help attribute assigned.
}
diff --git a/src/components/Form/FormLabel.test.tsx b/src/components/Form/FormLabel.test.tsx
index 1c4e63c82..1ec18b1da 100644
--- a/src/components/Form/FormLabel.test.tsx
+++ b/src/components/Form/FormLabel.test.tsx
@@ -1,6 +1,7 @@
import React from 'react'
import { render } from '@testing-library/react'
import FormLabel from './FormLabel'
+import { help } from './FormHelpButton'
const findLabelInTree = (el: HTMLElement | null): HTMLElement | null => {
if (!el) {
@@ -18,7 +19,7 @@ describe('FormLabel', () => {
// element tree that shows the label text. And that should be for
// the identifier.
- const { getByText } = render( )
+ const { getByText } = render( )
const labelElement = findLabelInTree(getByText('def')) as HTMLLabelElement
diff --git a/src/components/Form/FormLabel.tsx b/src/components/Form/FormLabel.tsx
index 0ebdc2c56..5e0646dec 100644
--- a/src/components/Form/FormLabel.tsx
+++ b/src/components/Form/FormLabel.tsx
@@ -1,11 +1,12 @@
import React from 'react'
import HelpLabel from './HelpLabel'
+import { HelpProps } from './FormHelpButton'
export interface LabelWithHelpButtonProps {
identifier: string
label: string | React.ReactNode
- help?: string | React.ReactNode
+ help?: HelpProps
}
export default function FormLabel({ identifier, label, help }: LabelWithHelpButtonProps) {
diff --git a/src/components/Form/FormSpinBox.tsx b/src/components/Form/FormSpinBox.tsx
index ec6ced5e9..093686b70 100644
--- a/src/components/Form/FormSpinBox.tsx
+++ b/src/components/Form/FormSpinBox.tsx
@@ -6,11 +6,12 @@ import { Field, FormikErrors, FormikTouched } from 'formik'
import { Col, FormGroup, Row } from 'reactstrap'
import FormLabel from './FormLabel'
+import { HelpProps } from './FormHelpButton'
export interface FormSpinBoxProps {
identifier: string
label: string
- help?: string | React.ReactNode
+ help?: HelpProps
step?: number | string
min?: number
max?: number
diff --git a/src/components/Form/FormSwitch.tsx b/src/components/Form/FormSwitch.tsx
index 8f48d674a..79028f0f0 100644
--- a/src/components/Form/FormSwitch.tsx
+++ b/src/components/Form/FormSwitch.tsx
@@ -3,11 +3,12 @@ import React from 'react'
import { CustomInput } from 'reactstrap'
import FormLabel from './FormLabel'
+import { HelpProps } from './FormHelpButton'
export interface FormSwitchProps {
identifier: string
label: string
- help?: string
+ help?: HelpProps
checked: boolean
hidden?: boolean
onValueChanged(checked: boolean): void
diff --git a/src/components/Form/HelpLabel.test.tsx b/src/components/Form/HelpLabel.test.tsx
index a567e2727..5752f3c5a 100644
--- a/src/components/Form/HelpLabel.test.tsx
+++ b/src/components/Form/HelpLabel.test.tsx
@@ -1,16 +1,17 @@
import React from 'react'
import { render } from '@testing-library/react'
import HelpLabel from './HelpLabel'
+import { help } from './FormHelpButton'
describe('HelpLabel', () => {
it('displays the label', () => {
- const { getByText } = render( )
+ const { getByText } = render( )
expect(getByText('def')).not.toBeNull()
})
it('displays a help button', () => {
- const { getByLabelText } = render( )
+ const { getByLabelText } = render( )
expect(getByLabelText('help')).not.toBeNull()
})
diff --git a/src/components/Form/HelpLabel.tsx b/src/components/Form/HelpLabel.tsx
index a5dea2c9e..ae197f06e 100644
--- a/src/components/Form/HelpLabel.tsx
+++ b/src/components/Form/HelpLabel.tsx
@@ -1,18 +1,18 @@
import React from 'react'
-import FormHelpButton from './FormHelpButton'
+import FormHelpButton, { HelpProps } from './FormHelpButton'
export interface HelpLabelProps {
identifier: string
label: string | React.ReactNode
- help?: string | React.ReactNode
+ help?: HelpProps
}
export default function HelpLabel({ identifier, label, help }: HelpLabelProps) {
return (
{label}
-
+
)
}
diff --git a/src/components/Main/Main.tsx b/src/components/Main/Main.tsx
index 15ab45811..a608f4d05 100644
--- a/src/components/Main/Main.tsx
+++ b/src/components/Main/Main.tsx
@@ -60,7 +60,7 @@ async function runSimulation(
return
}
- if (params.population.cases !== "none" && !isRegion(params.population.cases)) {
+ if (params.population.cases !== 'none' && !isRegion(params.population.cases)) {
console.error(`The given confirmed cases region is invalid: ${params.population.cases}`)
return
}
diff --git a/src/components/Main/Results/ResultsCard.tsx b/src/components/Main/Results/ResultsCard.tsx
index c8ff670ba..8eb29adea 100644
--- a/src/components/Main/Results/ResultsCard.tsx
+++ b/src/components/Main/Results/ResultsCard.tsx
@@ -4,6 +4,7 @@ import { Button, Col, Row } from 'reactstrap'
import { useTranslation } from 'react-i18next'
import ExportSimulationDialog from './ExportSimulationDialog'
import FormSwitch from '../../Form/FormSwitch'
+import { help } from '../../Form/FormHelpButton'
import LocalStorage, { LOCAL_STORAGE_KEYS } from '../../../helpers/localStorage'
import processUserResult from '../../../algorithms/utils/userResult'
import { AgeBarChart } from './AgeBarChart'
@@ -106,7 +107,7 @@ function ResultsCardFunction({
{t('Results')}
}
- help={t('This section contains simulation results')}
+ help={help(t('Results'), t('This section contains simulation results'))}
defaultCollapsed={false}
>
@@ -159,7 +160,7 @@ function ResultsCardFunction({
@@ -168,7 +169,7 @@ function ResultsCardFunction({
diff --git a/src/components/Main/Scenario/ScenarioCard.tsx b/src/components/Main/Scenario/ScenarioCard.tsx
index f0a779870..f7df3b2e3 100644
--- a/src/components/Main/Scenario/ScenarioCard.tsx
+++ b/src/components/Main/Scenario/ScenarioCard.tsx
@@ -9,6 +9,7 @@ import { useTranslation } from 'react-i18next'
import { CardWithDropdown } from '../../Form/CardWithDropdown'
import { stringsToOptions } from '../../Form/FormDropdownOption'
+import { help } from '../../Form/FormHelpButton'
import { setScenario } from '../state/actions'
import { State } from '../state/state'
@@ -40,7 +41,7 @@ function ScenarioCard({ severity, scenarioState, errors, touched, setSeverity, s
{t('Scenario')}}
- help={t('Combination of population, epidemiology, and mitigation scenarios')}
+ help={help(t('Scenario'), t('Combination of population, epidemiology, and mitigation scenarios'))}
options={scenarioOptions}
value={scenarioOptions.find((s) => s.label === scenarioState.current)}
onValueChange={handleChangeScenario}
diff --git a/src/components/Main/Scenario/ScenarioCardContainment.tsx b/src/components/Main/Scenario/ScenarioCardContainment.tsx
index a8a24bd23..04e047053 100644
--- a/src/components/Main/Scenario/ScenarioCardContainment.tsx
+++ b/src/components/Main/Scenario/ScenarioCardContainment.tsx
@@ -7,6 +7,8 @@ import { useTranslation } from 'react-i18next'
import { CardWithoutDropdown } from '../../Form/CardWithoutDropdown'
import { FormSpinBox } from '../../Form/FormSpinBox'
+import { help } from '../../Form/FormHelpButton'
+
import { ContainmentGraph } from '../Containment/ContainmentGraph'
import { setContainmentData } from '../state/actions'
@@ -33,14 +35,17 @@ function ScenarioCardContainment({ scenarioState, errors, touched, scenarioDispa
{t('Mitigation')}}
- help={t(
- 'Reduction of transmission through mitigation measures over time. Different presets with variable degree of reduction can be selected from the dropdown.',
+ help={help(
+ t('Mitigation'),
+ t(
+ 'Reduction of transmission through mitigation measures over time. Different presets with variable degree of reduction can be selected from the dropdown.',
+ ),
)}
>
{t('Epidemiology')}}
- help={t(
- 'Epidemiological parameters specifing growth rate, seasonal variation, and duration of hospital stay. The presets are combinations of speed and geography (speed/region).',
+ help={help(
+ t('Epidemiology'),
+ t(
+ 'Epidemiological parameters specifing growth rate, seasonal variation, and duration of hospital stay. The presets are combinations of speed and geography (speed/region).',
+ ),
)}
>
identifier="epidemiological.peakMonth"
label={t('Seasonal peak')}
- help={t('Time of the year with peak transmission')}
+ help={help(t('Seasonal peak'), t('Time of the year with peak transmission'))}
options={monthOptions}
errors={errors}
touched={touched}
@@ -91,7 +104,10 @@ function ScenarioCardEpidemiological({
{t('Population')}}
- help={t('Parameters of the population in the health care system.')}
+ help={help(t('Population'), 'Parameters of the population in the health care system.')}
>
identifier="population.country"
label={t('Age distribution')}
- help={t('Country to determine the age distribution in the population')}
+ help={help(t('Age distribution'), t('Country to determine the age distribution in the population'))}
options={countryOptions}
errors={errors}
touched={touched}
@@ -62,7 +63,7 @@ function ScenarioCardPopulation({ scenarioState, errors, touched, scenarioDispat
identifier="population.cases"
label={t('Confirmed cases')}
- help={t('Select region for which to plot confirmed case and death counts.')}
+ help={help(t('Confirmed cases'), t('Select region for which to plot confirmed case and death counts.'))}
options={caseCountOptions}
errors={errors}
touched={touched}
@@ -106,8 +111,11 @@ function ScenarioCardPopulation({ scenarioState, errors, touched, scenarioDispat
diff --git a/src/components/Main/Scenario/SeverityCard.tsx b/src/components/Main/Scenario/SeverityCard.tsx
index 2783fccdc..14f6bfadf 100644
--- a/src/components/Main/Scenario/SeverityCard.tsx
+++ b/src/components/Main/Scenario/SeverityCard.tsx
@@ -3,6 +3,7 @@ import React from 'react'
import { useTranslation } from 'react-i18next'
import { CollapsibleCard } from '../../Form/CollapsibleCard'
+import { help } from '../../Form/FormHelpButton'
import { SeverityTable, SeverityTableRow } from './SeverityTable'
@@ -24,7 +25,10 @@ function SeverityCard({ severity, setSeverity }: SeverityCardProps) {
>
}
- help={t('Assumptions on severity which are informed by epidemiological and clinical observations in China')}
+ help={help(
+ `${t('based on data from')} ${t('China')}`,
+ t('Assumptions on severity which are informed by epidemiological and clinical observations in China'),
+ )}
defaultCollapsed
>
diff --git a/yarn.lock b/yarn.lock
index e20fbd7b7..77c590cb7 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -12535,11 +12535,6 @@ rc@^1.0.1, rc@^1.1.6:
minimist "^1.2.0"
strip-json-comments "~2.0.1"
-react-children-utilities@2.0.12:
- version "2.0.12"
- resolved "https://registry.yarnpkg.com/react-children-utilities/-/react-children-utilities-2.0.12.tgz#75dcb4eded7d1a2509d68f52a0b13fc00694165f"
- integrity sha512-SqoczHew6ZQahJmI2EE3JZWefVHtwknqIx0zhdpJNYdyCXZNDm+7k+1ZAnZCOUY9anXh+O52b0eeLrqOdXvTeQ==
-
react-dates@21.8.0:
version "21.8.0"
resolved "https://registry.yarnpkg.com/react-dates/-/react-dates-21.8.0.tgz#355c3c7a243a7c29568fe00aca96231e171a5e94"