diff --git a/frontend/playwright-tests/cawp.ci.spec.ts b/frontend/playwright-tests/cawp.ci.spec.ts index 5ccf444697..c17bd35ab4 100644 --- a/frontend/playwright-tests/cawp.ci.spec.ts +++ b/frontend/playwright-tests/cawp.ci.spec.ts @@ -15,10 +15,8 @@ test('CAWP: Congress', async ({ page }) => { await page.getByText('Expand rates over time table').click(); await page.getByRole('cell', { name: '1951' }).click(); await page.getByRole('cell', { name: '1952' }).click(); - - - await page.waitForSelector('text=No unknown values for race and ethnicity reported in this dataset at the state/territory level.', { timeout: 1200000 }); - + + await page.waitForSelector('div[role="note"] >> text=No unknown values for race', { timeout: 120000 }); await page.getByText('No unknown values for race and ethnicity reported in this dataset at the state/territory level.').click(); await page.locator('#inequities-over-time').getByLabel('Include Black or African American women').click(); await page.getByText('Expand inequities over time table').click(); diff --git a/frontend/src/cards/MapCard.tsx b/frontend/src/cards/MapCard.tsx index e028c9038e..fed2015ef0 100644 --- a/frontend/src/cards/MapCard.tsx +++ b/frontend/src/cards/MapCard.tsx @@ -1,5 +1,5 @@ import ChoroplethMap from '../charts/ChoroplethMap' -import { type MetricId, type DataTypeConfig } from '../data/config/MetricConfig' +import type { MetricId, DataTypeConfig } from '../data/config/MetricConfig' import { exclude } from '../data/query/BreakdownFilter' import { Breakdowns, @@ -23,7 +23,7 @@ import { RACE, AGE, } from '../data/utils/Constants' -import { type Row } from '../data/utils/DatasetTypes' +import type { Row } from '../data/utils/DatasetTypes' import { getExtremeValues } from '../data/utils/datasetutils' import { Fips } from '../data/utils/Fips' import { @@ -41,8 +41,8 @@ import { findVerboseRating } from './ui/SviAlert' import { useGuessPreloadHeight } from '../utils/hooks/useGuessPreloadHeight' import { generateChartTitle, generateSubtitle } from '../charts/utils' import { useLocation } from 'react-router-dom' -import { type ScrollableHashId } from '../utils/hooks/useStepObserver' -import { useEffect, useMemo, useState } from 'react' +import type { ScrollableHashId } from '../utils/hooks/useStepObserver' +import { useMemo, useState } from 'react' import { getHighestLowestGroupsByFips } from '../charts/mapHelperFunctions' import { Legend } from '../charts/Legend' import GeoContext, { @@ -67,17 +67,16 @@ import ChartTitle from './ChartTitle' import { useParamState } from '../utils/hooks/useParamState' import { POPULATION, SVI } from '../data/providers/GeoContextProvider' import { type CountColsMap, RATE_MAP_SCALE } from '../charts/mapGlobals' -import { type ElementHashIdHiddenOnScreenshot } from '../utils/hooks/useDownloadCardImage' +import type { ElementHashIdHiddenOnScreenshot } from '../utils/hooks/useDownloadCardImage' import { PHRMA_METRICS } from '../data/providers/PhrmaProvider' -import { type MadLibId } from '../utils/MadLibs' +import type { MadLibId } from '../utils/MadLibs' import { useIsBreakpointAndUp } from '../utils/hooks/useIsBreakpointAndUp' import HetLinkButton from '../styles/HetComponents/HetLinkButton' import HetDivider from '../styles/HetComponents/HetDivider' import { dataSourceMetadataMap } from '../data/config/MetadataMap' -import { DatasetId } from '../data/config/DatasetMetadata' +import type { DatasetId } from '../data/config/DatasetMetadata' import HetNotice from '../styles/HetComponents/HetNotice' import HetTerm from '../styles/HetComponents/HetTerm' -import HetCloseButton from '../styles/HetComponents/HetCloseButton' const SIZE_OF_HIGHEST_LOWEST_GEOS_RATES_LIST = 5 const HASH_ID: ScrollableHashId = 'rate-map' @@ -121,14 +120,18 @@ function MapCardWithKey(props: MapCardProps) { ? EXTREMES_2_PARAM_KEY : EXTREMES_1_PARAM_KEY - const [extremesMode, setExtremesMode] = - useParamState(extremesParamsKey, false) + const [extremesMode, setExtremesMode] = useParamState( + extremesParamsKey, + false, + ) + const MULTIMAP_PARAM_KEY = props.isCompareCard ? MULTIPLE_MAPS_2_PARAM_KEY : MULTIPLE_MAPS_1_PARAM_KEY + const [multimapOpen, setMultimapOpen] = useParamState( MULTIMAP_PARAM_KEY, - false + false, ) const MAP_GROUP_PARAM = props.isCompareCard ? MAP2_GROUP_PARAM @@ -180,7 +183,7 @@ function MapCardWithKey(props: MapCardProps) { const metricQuery = ( metricIds: MetricId[], geographyBreakdown: Breakdowns, - countColsMap?: CountColsMap + countColsMap?: CountColsMap, ) => { countColsMap?.numeratorConfig && metricIds.push(countColsMap.numeratorConfig.metricId) @@ -195,10 +198,10 @@ function MapCardWithKey(props: MapCardProps) { demographicType, demographicType === RACE ? exclude(NON_HISPANIC, UNKNOWN, UNKNOWN_RACE, UNKNOWN_ETHNICITY) - : exclude(UNKNOWN) + : exclude(UNKNOWN), ), /* dataTypeId */ props.dataTypeConfig.dataTypeId, - /* timeView */ 'current' + /* timeView */ 'current', ) } @@ -216,7 +219,7 @@ function MapCardWithKey(props: MapCardProps) { metricQuery( initialMetridIds, Breakdowns.forChildrenFips(props.fips), - countColsMap + countColsMap, ), metricQuery(initialMetridIds, Breakdowns.forFips(props.fips)), ] @@ -254,11 +257,11 @@ function MapCardWithKey(props: MapCardProps) { let subtitle = generateSubtitle( activeDemographicGroup, demographicType, - props.dataTypeConfig + props.dataTypeConfig, ) - const pluralChildFips = props.fips.getPluralChildFipsTypeDisplayName() ?? 'places' - if (extremesMode) - subtitle += ` (only ${pluralChildFips} with rate extremes)` + const pluralChildFips = + props.fips.getPluralChildFipsTypeDisplayName() ?? 'places' + if (extremesMode) subtitle += ` (only ${pluralChildFips} with rate extremes)` const filename = `${title} ${subtitle ? `for ${subtitle}` : ''}` function handleScaleChange(domain: number[], range: number[]) { @@ -279,7 +282,6 @@ function MapCardWithKey(props: MapCardProps) { isCompareCard={props.isCompareCard} > {(queryResponses, metadata, geoData) => { - // contains rows for sub-geos (if viewing US, this data will be STATE level) const childGeoQueryResponse: MetricQueryResponse = queryResponses[0] // contains data rows current level (if viewing US, this data will be US level) @@ -289,17 +291,22 @@ function MapCardWithKey(props: MapCardProps) { childGeoQueryResponse.data.filter((row) => row[metricConfig.metricId]) .length === 0 && parentGeoQueryResponse.data.filter( - (row) => row[metricConfig.metricId] + (row) => row[metricConfig.metricId], ).length > 0 const mapQueryResponse = hasSelfButNotChildGeoData ? parentGeoQueryResponse : childGeoQueryResponse const totalPopulationPhrase = getTotalACSPopulationPhrase( - acsPopulationQueryResponse.data + acsPopulationQueryResponse.data, ) - let subPopSourceLabel = Object.values(dataSourceMetadataMap).find((metadata) => metadata.dataset_ids.includes(parentGeoQueryResponse.consumedDatasetIds[0] as DatasetId))?.data_source_acronym ?? '' + let subPopSourceLabel = + Object.values(dataSourceMetadataMap).find((metadata) => + metadata.dataset_ids.includes( + parentGeoQueryResponse.consumedDatasetIds[0] as DatasetId, + ), + )?.data_source_acronym ?? '' // US Congress denominators come from @unitestedstates not CAWP if (props.dataTypeConfig.dataTypeId === 'women_in_us_congress') { @@ -310,7 +317,7 @@ function MapCardWithKey(props: MapCardProps) { parentGeoQueryResponse.data, subPopSourceLabel, demographicType, - props.dataTypeConfig + props.dataTypeConfig, ) const sviQueryResponse: MetricQueryResponse = queryResponses[3] || null @@ -321,7 +328,7 @@ function MapCardWithKey(props: MapCardProps) { const fieldValues = mapQueryResponse.getFieldValues( /* fieldName: DemographicType */ demographicType, - /* relevantMetric: MetricId */ metricConfig.metricId + /* relevantMetric: MetricId */ metricConfig.metricId, ) const demographicGroups: DemographicGroup[] = @@ -332,7 +339,7 @@ function MapCardWithKey(props: MapCardProps) { .filter((row: Row) => row[demographicType] === activeDemographicGroup) const allDataForActiveDemographicGroup = mapQueryResponse.data.filter( - (row: Row) => row[demographicType] === activeDemographicGroup + (row: Row) => row[demographicType] === activeDemographicGroup, ) const dataForSvi: Row[] = @@ -340,28 +347,28 @@ function MapCardWithKey(props: MapCardProps) { ?.getValidRowsForField(SVI) ?.filter((row) => dataForActiveDemographicGroup.find( - ({ fips }) => row.fips === fips - ) + ({ fips }) => row.fips === fips, + ), ) || [] if (!props.fips.isUsa()) { dataForActiveDemographicGroup = dataForActiveDemographicGroup.map( (row) => { const thisCountySviRow = dataForSvi.find( - (sviRow) => sviRow.fips === row.fips + (sviRow) => sviRow.fips === row.fips, ) return { ...row, rating: findVerboseRating(thisCountySviRow?.svi), } - } + }, ) } const { highestValues, lowestValues } = getExtremeValues( dataForActiveDemographicGroup, metricConfig.metricId, - SIZE_OF_HIGHEST_LOWEST_GEOS_RATES_LIST + SIZE_OF_HIGHEST_LOWEST_GEOS_RATES_LIST, ) // Create and populate a map of demographicType display name to options @@ -379,7 +386,7 @@ function MapCardWithKey(props: MapCardProps) { let dropdownValue = ALL if ( filterOptions[DEMOGRAPHIC_DISPLAY_TYPES[demographicType]].includes( - activeDemographicGroup + activeDemographicGroup, ) ) { dropdownValue = activeDemographicGroup @@ -404,8 +411,7 @@ function MapCardWithKey(props: MapCardProps) { const mapConfig = props.dataTypeConfig.mapConfig if (isSummaryLegend) mapConfig.min = mapConfig.mid - if (dataForActiveDemographicGroup?.length <= 1) - setExtremesMode(false) + if (dataForActiveDemographicGroup?.length <= 1) setExtremesMode(false) if (!dataForActiveDemographicGroup?.length || !metricConfig) return ( @@ -437,7 +443,9 @@ function MapCardWithKey(props: MapCardProps) { const isPhrmaAdherence = PHRMA_METRICS.includes(metricId) && metricConfig.type === 'pct_rate' - const percentRateTooHigh = metricConfig.type === 'pct_rate' && mapQueryResponse.data.some((row) => row[metricConfig.metricId] > 100) + const percentRateTooHigh = + metricConfig.type === 'pct_rate' && + mapQueryResponse.data.some((row) => row[metricConfig.metricId] > 100) const fieldRange = useMemo(() => { return mapQueryResponse.getFieldRange(metricConfig.metricId) @@ -462,7 +470,7 @@ function MapCardWithKey(props: MapCardProps) { hasSelfButNotChildGeoData={hasSelfButNotChildGeoData} metadata={metadata} metricConfig={metricConfig} - open={Boolean(multimapOpen)} + open={Boolean(multimapOpen)} // Use local state for multimapOpen queries={queries} queryResponses={queryResponses} totalPopulationPhrase={totalPopulationPhrase} @@ -510,7 +518,20 @@ function MapCardWithKey(props: MapCardProps) {
- setExtremesMode(false)} >Reset to show all {pluralChildFips} : null} /> + setExtremesMode(false)} + > + Reset to show all {pluralChildFips} + + ) : null + } + />
@@ -623,10 +644,26 @@ function MapCardWithKey(props: MapCardProps) { /> )} {percentRateTooHigh && ( - - <>In some locations, the percent rates exceed 100%, which can be confusing and may indicate inconsistency in the source data. - {metricId === 'vaccinated_pct_rate' && <> - {" "}In the case of COVID-19 vaccinations, the number of first-dose vaccines administered in a location could have been higher than the population of that location if individuals came from other locations to receive the vaccine, and also if individuals chose to receive more than a single "first-dose" vaccine.} + + <> + In some locations, the percent rates{' '} + exceed 100%, which can be confusing and may indicate + inconsistency in the source data. + + {metricId === 'vaccinated_pct_rate' && ( + <> + {' '} + In the case of COVID-19 vaccinations, + the number of first-dose vaccines administered in a + location could have been higher than the population of + that location if individuals came from other locations + to receive the vaccine, and also if individuals chose to + receive more than a single "first-dose" vaccine. + + )} )}
@@ -637,4 +674,3 @@ function MapCardWithKey(props: MapCardProps) { ) } - diff --git a/frontend/src/pages/ExploreData/DefaultHelperBox.tsx b/frontend/src/pages/ExploreData/DefaultHelperBox.tsx index 7d73466aca..8c689cb257 100644 --- a/frontend/src/pages/ExploreData/DefaultHelperBox.tsx +++ b/frontend/src/pages/ExploreData/DefaultHelperBox.tsx @@ -1,79 +1,82 @@ -import { EXPLORE_DATA_PAGE_LINK } from "../../utils/internalRoutes"; -import HetTextArrowLink from "../../styles/HetComponents/HetTextArrowLink"; -import { HetTags } from "../../styles/HetComponents/HetTags"; -import { reportMapping } from "./DefaultHelperBoxData"; -import { ToggleIframeComponent } from "./ToggleIframeComponent"; +import { EXPLORE_DATA_PAGE_LINK } from '../../utils/internalRoutes' +import HetTextArrowLink from '../../styles/HetComponents/HetTextArrowLink' +import { HetTags } from '../../styles/HetComponents/HetTags' +import { reportMappings } from './DefaultHelperBoxData' +import TogglePreview from './TogglePreview' export default function DefaultHelperBox() { - return ( -
-
-
-

- Select a topic above -

-

- or explore one of the following reports: -

- -
-
-
- ); -} \ No newline at end of file + return ( +
+
+
+

+ Select a topic above +

+

+ or explore one of the following reports: +

+ +
+
+
+ ) +} diff --git a/frontend/src/pages/ExploreData/DefaultHelperBoxData.tsx b/frontend/src/pages/ExploreData/DefaultHelperBoxData.tsx index 250b1e4888..f6005adf38 100644 --- a/frontend/src/pages/ExploreData/DefaultHelperBoxData.tsx +++ b/frontend/src/pages/ExploreData/DefaultHelperBoxData.tsx @@ -1,78 +1,93 @@ -import { HIV_PREVALENCE_RACE_USA_SETTING, COVID_DEATHS_AGE_FULTON_COUNTY_SETTING, PRISON_VS_POVERTY_RACE_GA_SETTING, UNINSURANCE_SEX_FL_VS_CA_SETTING, PHRMA_HIV_ELIGIBILITY_USA_MULTIMAP_SETTING } from "../../utils/internalRoutes"; +import { + HIV_PREVALENCE_RACE_USA_SETTING, + COVID_DEATHS_AGE_FULTON_COUNTY_SETTING, + PRISON_VS_POVERTY_RACE_GA_SETTING, + UNINSURANCE_SEX_FL_VS_CA_SETTING, + PHRMA_HIV_ELIGIBILITY_USA_MULTIMAP_SETTING, +} from '../../utils/internalRoutes' +import Custom100kBarChartCompare from '../../reports/Custom100kBarChartCompare' +import CustomDisparityBarChartCompare from '../../reports/CustomDisparityBarChartCompare' +import CustomRateTrendsLineChart from '../../reports/CustomRateTrendsLineChart' +import CustomShareTrendsLineChart from '../../reports/CustomShareTrendsLineChart' import FiberNewIcon from '@mui/icons-material/FiberNew' -export const reportMapping = [ - { - setting: PHRMA_HIV_ELIGIBILITY_USA_MULTIMAP_SETTING, - title: 'HIV Disparity Maps by Medicare Eligibility', - preview: 'Medicare HIV Cases', - description: - 'Visualize HIV disparities among Medicare beneficiaries. These insights are essential for optimizing treatment and reducing health inequities.', - categories: [ - 'HIV', - 'Medication Utilization in the Medicare Population', - 'Multiple Maps', - 'National-Level', - ], - icon: , - previewImg: '/img/screenshots/sample-report_medicare.png', - iframeSrc: - 'https://healthequitytracker.org/exploredata?mls=1.medicare_hiv-3.00&group1=All&demo=eligibility&dt1=medicare_hiv&multiple-maps=true', - }, - { - setting: HIV_PREVALENCE_RACE_USA_SETTING, - title: 'HIV by Race/Ethnicity', - preview: 'HIV Cases', - description: - 'Uncover disparities in HIV prevalence across different racial and ethnic groups in the U.S. Understanding these patterns is vital for targeted interventions and improved health equity.', - categories: ['HIV', 'Prevalence', 'Race/Ethnicity', 'National-Level'], - previewImg: '/img/screenshots/sample-report_hiv.png', - iframeSrc: - 'https://healthequitytracker.org/exploredata?mls=1.hiv-3.00&mlp=disparity&dt1=hiv_prevalence#rate-map', - }, - { - setting: COVID_DEATHS_AGE_FULTON_COUNTY_SETTING, - title: 'COVID-19 Deaths in Fulton County by Age', - preview: 'COVID-19 Deaths', - description: - 'Analyze COVID-19 mortality in Fulton County, GA, by age. Highlighting vulnerable populations helps to inform public health strategies and resource allocation.', - categories: ['COVID-19', 'Deaths', 'Age', 'County-Level'], - previewImg: '/img/screenshots/sample-report_covid.png', - iframeSrc: - 'https://healthequitytracker.org/exploredata?mls=1.covid-3.13121&group1=All&group2=All&dt1=covid_deaths&demo=age#population-vs-distribution', - }, - { - setting: PRISON_VS_POVERTY_RACE_GA_SETTING, - title: 'Prison & Poverty in Georgia by Race', - preview: 'Prison + Poverty', - description: - 'Explore the intersection of incarceration, poverty, and race in Georgia. Addressing these disparities is key to improving health outcomes and social justice.', - categories: [ - 'Social Determinants of Health', - 'Political Determinants of Health', - 'Race/Ethnicity', - 'State-Level', - 'Compare Topics', - ], - previewImg: '/img/screenshots/sample-report_ga.png', - iframeSrc: - 'https://healthequitytracker.org/exploredata?mls=1.incarceration-3.poverty-5.13&mlp=comparevars&dt1=prison#rate-map', - }, - { - setting: UNINSURANCE_SEX_FL_VS_CA_SETTING, - title: 'Uninsurance in FL & CA by Sex', - preview: 'Uninsured', - description: - 'Examine uninsurance rates by sex in Florida and California. Identifying these gaps is crucial for advancing equitable healthcare access.', - categories: [ - 'Social Determinants of Health', - 'State-Level', - 'Sex', - 'Compare Places', - ], - previewImg: '/img/screenshots/sample-report_uninsured.png', - iframeSrc: - 'https://healthequitytracker.org/exploredata?mls=1.health_insurance-3.12-5.06&mlp=comparegeos&demo=sex#rates-over-time', - }, +type ReportMapping = { + setting: string + title: string + preview: string + description: string + categories: string[] + icon?: JSX.Element + previewImg: string + customCard: JSX.Element | null +} +export const reportMappings: ReportMapping[] = [ + { + setting: PHRMA_HIV_ELIGIBILITY_USA_MULTIMAP_SETTING, + title: 'HIV Disparity Maps by Medicare Eligibility', + preview: 'Medicare HIV Cases', + description: + 'Visualize HIV disparities among Medicare beneficiaries. These insights are essential for optimizing treatment and reducing health inequities.', + categories: [ + 'HIV', + 'Medication Utilization in the Medicare Population', + 'Multiple Maps', + 'National-Level', + ], + icon: , + previewImg: '/img/screenshots/sample-report_medicare.png', + customCard: null, + }, + { + setting: HIV_PREVALENCE_RACE_USA_SETTING, + title: 'HIV by Race/Ethnicity', + preview: 'HIV Cases', + description: + 'Uncover disparities in HIV prevalence across different racial and ethnic groups in the U.S. Understanding these patterns is vital for targeted interventions and improved health equity.', + categories: ['HIV', 'Prevalence', 'Race/Ethnicity', 'National-Level'], + previewImg: '/img/screenshots/sample-report_hiv.png', + customCard: , + }, + { + setting: COVID_DEATHS_AGE_FULTON_COUNTY_SETTING, + title: 'COVID-19 Deaths in Fulton County by Age', + preview: 'COVID-19 Deaths', + description: + 'Analyze COVID-19 mortality in Fulton County, GA, by age. Highlighting vulnerable populations helps to inform public health strategies and resource allocation.', + categories: ['COVID-19', 'Deaths', 'Age', 'County-Level'], + previewImg: '/img/screenshots/sample-report_covid.png', + customCard: , + }, + { + setting: PRISON_VS_POVERTY_RACE_GA_SETTING, + title: 'Prison & Poverty in Georgia by Race', + preview: 'Prison + Poverty', + description: + 'Explore the intersection of incarceration, poverty, and race in Georgia. Addressing these disparities is key to improving health outcomes and social justice.', + categories: [ + 'Social Determinants of Health', + 'Political Determinants of Health', + 'Race/Ethnicity', + 'State-Level', + 'Compare Topics', + ], + previewImg: '/img/screenshots/sample-report_ga.png', + customCard: , + }, + { + setting: UNINSURANCE_SEX_FL_VS_CA_SETTING, + title: 'Uninsurance in FL & CA by Sex', + preview: 'Uninsured', + description: + 'Examine uninsurance rates by sex in Florida and California. Identifying these gaps is crucial for advancing equitable healthcare access.', + categories: [ + 'Social Determinants of Health', + 'State-Level', + 'Sex', + 'Compare Places', + ], + previewImg: '/img/screenshots/sample-report_uninsured.png', + customCard: , + }, ] diff --git a/frontend/src/pages/ExploreData/ToggleIframeComponent.tsx b/frontend/src/pages/ExploreData/ToggleIframeComponent.tsx deleted file mode 100644 index 8660d3fdd4..0000000000 --- a/frontend/src/pages/ExploreData/ToggleIframeComponent.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import { ArrowDropUp, ArrowDropDown } from "@mui/icons-material"; -import { useState } from "react"; -import { EmbeddedIframe } from "./EmbeddedIframe"; - -export const ToggleIframeComponent: React.FC<{ - index: number; - report: any; -}> = ({ index, report }) => { - const [showIframe, setShowIframe] = useState<{ [key: number]: boolean }>({}); - - const toggleIframe = (index: number) => { - setShowIframe((prev) => ({ - ...prev, - [index]: !prev[index], - })); - }; - - return ( -
- - {showIframe[index] && ( - - )} -
- ); -}; diff --git a/frontend/src/pages/ExploreData/TogglePreview.tsx b/frontend/src/pages/ExploreData/TogglePreview.tsx new file mode 100644 index 0000000000..f9fe1fbf2f --- /dev/null +++ b/frontend/src/pages/ExploreData/TogglePreview.tsx @@ -0,0 +1,39 @@ +import React, { useState } from 'react'; +import { ArrowDropUp, ArrowDropDown } from '@mui/icons-material'; + +const TogglePreview: React.FC<{ index: number; report: any }> = ({ index, report }) => { + const [showPreview, setShowPreview] = useState<{ [key: number]: boolean }>({}); + + const togglePreview = (index: number) => { + setShowPreview((prev) => ({ + ...prev, + [index]: !prev[index], + })); + }; + + return ( +
+ + {showPreview[index] && ( +
+ {React.cloneElement(report.customCard, { openMultiMap: report.setting === 'medicare-hiv' })} +
+ )} +
+ ); +}; + +export default TogglePreview; \ No newline at end of file