diff --git a/packages/client/src/data_commons_web_client.ts b/packages/client/src/data_commons_web_client.ts index cfcb4ad08a..9f73813449 100644 --- a/packages/client/src/data_commons_web_client.ts +++ b/packages/client/src/data_commons_web_client.ts @@ -22,6 +22,7 @@ import { ApiNodePropvalOutResponse, ObservationDatesApiResponse, PlaceChartsApiResponse, + PlaceOverviewTableApiResponse, PointApiResponse, RelatedPlacesApiResponse, SeriesApiResponse, @@ -234,6 +235,7 @@ class DataCommonsWebClient { * Gets related place info charts for the given place * Uses /api/dev-place/related-places/ endpoint * @param params.placeDcid place dcid to fetch data for + * @param params.locale [optional] locale to fetch data for */ async getRelatedPLaces(params: { placeDcid: string; @@ -248,6 +250,26 @@ class DataCommonsWebClient { const response = await fetch(url); return (await response.json()) as RelatedPlacesApiResponse; } + + /** + * Gets place overview table for the given place + * Uses /api/dev-place/overview-table/ endpoint + * @param params.placeDcid place dcid to fetch data for + * @param params.locale [optional] locale to fetch data for + */ + async getPlaceOverviewTable(params: { + placeDcid: string; + locale?: string; + }): Promise { + const queryString = toURLSearchParams({ + [LOCALE_PARAM]: params.locale, + }); + const url = `${this.apiRoot || ""}/api/dev-place/overview-table/${ + params.placeDcid + }?${queryString}`; + const response = await fetch(url); + return (await response.json()) as PlaceOverviewTableApiResponse; + } } export { DataCommonsWebClient }; diff --git a/packages/client/src/data_commons_web_client_types.ts b/packages/client/src/data_commons_web_client_types.ts index 4a5d8578b0..db753ea9c9 100644 --- a/packages/client/src/data_commons_web_client_types.ts +++ b/packages/client/src/data_commons_web_client_types.ts @@ -201,3 +201,19 @@ export interface RelatedPlacesApiResponse { parentPlaces: Place[]; peersWithinParent: string[]; } + +export interface OverviewTableDataRow { + date: string; + name: string; + provenanceUrl: string; + value: number; + variableDcid: string; + unit?: string; +} + +/** + * Website API response for /api/dev-place/overview-table/ + */ +export interface PlaceOverviewTableApiResponse { + data: OverviewTableDataRow[]; +} diff --git a/server/i18n/de/LC_MESSAGES/all.mo b/server/i18n/de/LC_MESSAGES/all.mo index 3be7293be9..24878c5aa8 100644 Binary files a/server/i18n/de/LC_MESSAGES/all.mo and b/server/i18n/de/LC_MESSAGES/all.mo differ diff --git a/server/i18n/de/LC_MESSAGES/all.po b/server/i18n/de/LC_MESSAGES/all.po index 76d9657cb0..71e13739d6 100644 --- a/server/i18n/de/LC_MESSAGES/all.po +++ b/server/i18n/de/LC_MESSAGES/all.po @@ -748,4 +748,15 @@ msgid "singular_village" msgstr "Dorf" msgid "singular_zip_code" -msgstr "Postleitzahl" \ No newline at end of file +msgstr "Postleitzahl" +msgid "VARIABLE_NAME-Count_Person" +msgstr "Population" + +msgid "VARIABLE_NAME-Median_Income_Person" +msgstr "Median Income" + +msgid "VARIABLE_NAME-Median_Age_Person" +msgstr "Median Age" + +msgid "VARIABLE_NAME-UnemploymentRate_Person" +msgstr "Unemployment Rate" diff --git a/server/i18n/en/LC_MESSAGES/all.mo b/server/i18n/en/LC_MESSAGES/all.mo index d3c8dd5c3a..b0d1c8fdf8 100644 Binary files a/server/i18n/en/LC_MESSAGES/all.mo and b/server/i18n/en/LC_MESSAGES/all.mo differ diff --git a/server/i18n/en/LC_MESSAGES/all.po b/server/i18n/en/LC_MESSAGES/all.po index 4f7b79d7dc..478b4d9243 100644 --- a/server/i18n/en/LC_MESSAGES/all.po +++ b/server/i18n/en/LC_MESSAGES/all.po @@ -1045,6 +1045,22 @@ msgstr "ZIP Code" msgid "plural_zip_code" msgstr "ZIP Codes" +#. Name describing the statistical variable for population +msgid "VARIABLE_NAME-Count_Person" +msgstr "Population" + +#. Name describing the statistical variable for median income of the population +msgid "VARIABLE_NAME-Median_Income_Person" +msgstr "Median Income" + +#. Name describing the statistical variable for median age of the population +msgid "VARIABLE_NAME-Median_Age_Person" +msgstr "Median Age" + +#. Name describing the statistical variable for unemployment rate of the population +msgid "VARIABLE_NAME-UnemploymentRate_Person" +msgstr "Unemployment Rate" + #~ msgid "CHART_TITLE-nitrous_oxide_emissions_nonbiogenic" #~ msgstr "Nitrous oxide emissions (non-biogenic)" @@ -1158,4 +1174,3 @@ msgstr "ZIP Codes" #~ msgid "CHART_TITLE-CHART_CATEGORY-Climate" #~ msgstr "Climate" - diff --git a/server/i18n/es/LC_MESSAGES/all.mo b/server/i18n/es/LC_MESSAGES/all.mo index 47ae8b62b2..d70f978c1b 100644 Binary files a/server/i18n/es/LC_MESSAGES/all.mo and b/server/i18n/es/LC_MESSAGES/all.mo differ diff --git a/server/i18n/es/LC_MESSAGES/all.po b/server/i18n/es/LC_MESSAGES/all.po index 1674f19d51..e5a41e75c0 100644 --- a/server/i18n/es/LC_MESSAGES/all.po +++ b/server/i18n/es/LC_MESSAGES/all.po @@ -749,3 +749,15 @@ msgstr "Pueblo" msgid "singular_zip_code" msgstr "Código postal" + +msgid "VARIABLE_NAME-Count_Person" +msgstr "Population" + +msgid "VARIABLE_NAME-Median_Income_Person" +msgstr "Median Income" + +msgid "VARIABLE_NAME-Median_Age_Person" +msgstr "Median Age" + +msgid "VARIABLE_NAME-UnemploymentRate_Person" +msgstr "Unemployment Rate" diff --git a/server/i18n/fr/LC_MESSAGES/all.mo b/server/i18n/fr/LC_MESSAGES/all.mo index 303939d7f2..01a2f7ed41 100644 Binary files a/server/i18n/fr/LC_MESSAGES/all.mo and b/server/i18n/fr/LC_MESSAGES/all.mo differ diff --git a/server/i18n/fr/LC_MESSAGES/all.po b/server/i18n/fr/LC_MESSAGES/all.po index 2355668963..93e72ae24b 100644 --- a/server/i18n/fr/LC_MESSAGES/all.po +++ b/server/i18n/fr/LC_MESSAGES/all.po @@ -748,4 +748,16 @@ msgid "singular_village" msgstr "Village" msgid "singular_zip_code" -msgstr "Code postal" \ No newline at end of file +msgstr "Code postal" + +msgid "VARIABLE_NAME-Count_Person" +msgstr "Population" + +msgid "VARIABLE_NAME-Median_Income_Person" +msgstr "Median Income" + +msgid "VARIABLE_NAME-Median_Age_Person" +msgstr "Median Age" + +msgid "VARIABLE_NAME-UnemploymentRate_Person" +msgstr "Unemployment Rate" diff --git a/server/i18n/hi/LC_MESSAGES/all.mo b/server/i18n/hi/LC_MESSAGES/all.mo index 2ef605e1bd..a2b6380118 100644 Binary files a/server/i18n/hi/LC_MESSAGES/all.mo and b/server/i18n/hi/LC_MESSAGES/all.mo differ diff --git a/server/i18n/hi/LC_MESSAGES/all.po b/server/i18n/hi/LC_MESSAGES/all.po index 0476d24790..2d5d661419 100644 --- a/server/i18n/hi/LC_MESSAGES/all.po +++ b/server/i18n/hi/LC_MESSAGES/all.po @@ -748,4 +748,16 @@ msgid "singular_village" msgstr "गांव" msgid "singular_zip_code" -msgstr "पिन कोड" \ No newline at end of file +msgstr "पिन कोड" + +msgid "VARIABLE_NAME-Count_Person" +msgstr "Population" + +msgid "VARIABLE_NAME-Median_Income_Person" +msgstr "Median Income" + +msgid "VARIABLE_NAME-Median_Age_Person" +msgstr "Median Age" + +msgid "VARIABLE_NAME-UnemploymentRate_Person" +msgstr "Unemployment Rate" diff --git a/server/i18n/it/LC_MESSAGES/all.mo b/server/i18n/it/LC_MESSAGES/all.mo index 638001ae31..6b8bf15d43 100644 Binary files a/server/i18n/it/LC_MESSAGES/all.mo and b/server/i18n/it/LC_MESSAGES/all.mo differ diff --git a/server/i18n/it/LC_MESSAGES/all.po b/server/i18n/it/LC_MESSAGES/all.po index 747f531731..4e2dd7281f 100644 --- a/server/i18n/it/LC_MESSAGES/all.po +++ b/server/i18n/it/LC_MESSAGES/all.po @@ -748,4 +748,16 @@ msgid "singular_village" msgstr "Villaggio" msgid "singular_zip_code" -msgstr "Codice postale" \ No newline at end of file +msgstr "Codice postale" + +msgid "VARIABLE_NAME-Count_Person" +msgstr "Population" + +msgid "VARIABLE_NAME-Median_Income_Person" +msgstr "Median Income" + +msgid "VARIABLE_NAME-Median_Age_Person" +msgstr "Median Age" + +msgid "VARIABLE_NAME-UnemploymentRate_Person" +msgstr "Unemployment Rate" diff --git a/server/i18n/ja/LC_MESSAGES/all.mo b/server/i18n/ja/LC_MESSAGES/all.mo index 9ab25a7a10..a0ba20a2d2 100644 Binary files a/server/i18n/ja/LC_MESSAGES/all.mo and b/server/i18n/ja/LC_MESSAGES/all.mo differ diff --git a/server/i18n/ja/LC_MESSAGES/all.po b/server/i18n/ja/LC_MESSAGES/all.po index f0b3966b2d..d7bf00a846 100644 --- a/server/i18n/ja/LC_MESSAGES/all.po +++ b/server/i18n/ja/LC_MESSAGES/all.po @@ -748,4 +748,16 @@ msgid "singular_village" msgstr "村" msgid "singular_zip_code" -msgstr "郵便番号" \ No newline at end of file +msgstr "郵便番号" + +msgid "VARIABLE_NAME-Count_Person" +msgstr "Population" + +msgid "VARIABLE_NAME-Median_Income_Person" +msgstr "Median Income" + +msgid "VARIABLE_NAME-Median_Age_Person" +msgstr "Median Age" + +msgid "VARIABLE_NAME-UnemploymentRate_Person" +msgstr "Unemployment Rate" diff --git a/server/i18n/ko/LC_MESSAGES/all.mo b/server/i18n/ko/LC_MESSAGES/all.mo index 67f5f1fa07..0f42094c1c 100644 Binary files a/server/i18n/ko/LC_MESSAGES/all.mo and b/server/i18n/ko/LC_MESSAGES/all.mo differ diff --git a/server/i18n/ko/LC_MESSAGES/all.po b/server/i18n/ko/LC_MESSAGES/all.po index 961e075e25..ac1a8db586 100644 --- a/server/i18n/ko/LC_MESSAGES/all.po +++ b/server/i18n/ko/LC_MESSAGES/all.po @@ -748,4 +748,16 @@ msgid "singular_village" msgstr "마을" msgid "singular_zip_code" -msgstr "우편번호" \ No newline at end of file +msgstr "우편번호" + +msgid "VARIABLE_NAME-Count_Person" +msgstr "Population" + +msgid "VARIABLE_NAME-Median_Income_Person" +msgstr "Median Income" + +msgid "VARIABLE_NAME-Median_Age_Person" +msgstr "Median Age" + +msgid "VARIABLE_NAME-UnemploymentRate_Person" +msgstr "Unemployment Rate" diff --git a/server/i18n/ru/LC_MESSAGES/all.mo b/server/i18n/ru/LC_MESSAGES/all.mo index bbaa4a2eab..9a1789e36f 100644 Binary files a/server/i18n/ru/LC_MESSAGES/all.mo and b/server/i18n/ru/LC_MESSAGES/all.mo differ diff --git a/server/i18n/ru/LC_MESSAGES/all.po b/server/i18n/ru/LC_MESSAGES/all.po index a969488ae0..d712cb31da 100644 --- a/server/i18n/ru/LC_MESSAGES/all.po +++ b/server/i18n/ru/LC_MESSAGES/all.po @@ -749,3 +749,15 @@ msgstr "Поселок" msgid "singular_zip_code" msgstr "Почтовый индекс" + +msgid "VARIABLE_NAME-Count_Person" +msgstr "Population" + +msgid "VARIABLE_NAME-Median_Income_Person" +msgstr "Median Income" + +msgid "VARIABLE_NAME-Median_Age_Person" +msgstr "Median Age" + +msgid "VARIABLE_NAME-UnemploymentRate_Person" +msgstr "Unemployment Rate" diff --git a/server/routes/dev_place/api.py b/server/routes/dev_place/api.py index 1b35cbc981..4e2c93681e 100644 --- a/server/routes/dev_place/api.py +++ b/server/routes/dev_place/api.py @@ -26,6 +26,7 @@ from server.routes import TIMEOUT from server.routes.dev_place import utils as place_utils from server.routes.dev_place.types import PlaceChartsApiResponse +from server.routes.dev_place.types import PlaceOverviewTableApiResponse from server.routes.dev_place.types import RelatedPlacesApiResponse # Define blueprint @@ -186,3 +187,16 @@ def related_places(place_dcid: str): parentPlaces=parent_places, peersWithinParent=peers_within_parent) return jsonify(response) + + +@bp.route('/overview-table/') +@log_execution_time +@cache.cached(timeout=TIMEOUT, query_string=True) +def overview_table(place_dcid: str): + """ + Fetches and returns overview table data for the specified place. + """ + data_rows = place_utils.fetch_overview_table_data(place_dcid, locale=g.locale) + + response = PlaceOverviewTableApiResponse(data=data_rows) + return jsonify(response) diff --git a/server/routes/dev_place/types.py b/server/routes/dev_place/types.py index 333928914c..8ec4058cab 100644 --- a/server/routes/dev_place/types.py +++ b/server/routes/dev_place/types.py @@ -118,3 +118,24 @@ class ServerChartConfiguration: scaling: Optional[int] = None non_dividable: bool = False # Read in from configs scale: bool = False + + +@dataclass +class OverviewTableDataRow: + """ + A single row of overview table data for a place. + """ + date: str + name: str + provenanceUrl: str + unit: Optional[str] + value: float + variableDcid: str + + +@dataclass +class PlaceOverviewTableApiResponse: + """ + API Response for /api/dev-place/overview-table/ + """ + data: List[OverviewTableDataRow] diff --git a/server/routes/dev_place/utils.py b/server/routes/dev_place/utils.py index bcf943a61e..7736848e50 100644 --- a/server/routes/dev_place/utils.py +++ b/server/routes/dev_place/utils.py @@ -29,6 +29,7 @@ from server.routes.dev_place.types import BlockConfig from server.routes.dev_place.types import Category from server.routes.dev_place.types import Chart +from server.routes.dev_place.types import OverviewTableDataRow from server.routes.dev_place.types import Place from server.routes.dev_place.types import ServerBlockMetadata from server.routes.dev_place.types import ServerChartConfiguration @@ -62,6 +63,27 @@ PLACE_TYPE_IN_PARENT_PLACES_STR = '%(placeType)s in %(parentPlaces)s' NEIGHBORING_PLACES_IN_PARENT_PLACE_STR = 'Neighboring %(placeType)s in %(parentPlace)s' +# Variables to include in overview table +PLACE_OVERVIEW_TABLE_VARIABLES: List[Dict[str, str]] = [ + { + "variable_dcid": "Count_Person", + "i18n_message_id": "VARIABLE_NAME-Count_Person" + }, + { + "variable_dcid": "Median_Income_Person", + "i18n_message_id": "VARIABLE_NAME-Median_Income_Person" + }, + { + "variable_dcid": "Median_Age_Person", + "i18n_message_id": "VARIABLE_NAME-Median_Age_Person" + }, + { + "variable_dcid": "UnemploymentRate_Person", + "i18n_message_id": "VARIABLE_NAME-UnemploymentRate_Person", + "unit": "Percent" + }, +] + def get_place_html_link(place_dcid: str, place_name: str) -> str: """Get tag linking to the place page for a place @@ -870,3 +892,53 @@ def fetch_similar_place_dcids(place: Place, locale=DEFAULT_LOCALE) -> List[str]: # Return the list of similar place dcids return place_cohort_member_dcids + + +def fetch_overview_table_data(place_dcid: str, + locale=DEFAULT_LOCALE + ) -> List[OverviewTableDataRow]: + """ + Fetches overview table data for the specified place. + """ + data_rows = [] + variables = [v["variable_dcid"] for v in PLACE_OVERVIEW_TABLE_VARIABLES] + + # Fetch the most recent observation for each variable + resp = dc.obs_point([place_dcid], variables) + facets = resp.get("facets", {}) + + # Iterate over each variable and extract the most recent observation + for item in PLACE_OVERVIEW_TABLE_VARIABLES: + variable_dcid = item["variable_dcid"] + name = gettext(item["i18n_message_id"]) + ordered_facet_observations = resp.get("byVariable", {}).get( + variable_dcid, {}).get("byEntity", {}).get(place_dcid, + {}).get("orderedFacets", []) + most_recent_facet = ordered_facet_observations[ + 0] if ordered_facet_observations else None + if not most_recent_facet: + continue + + observations = most_recent_facet.get("observations", []) + most_recent_observation = observations[0] if observations else None + if not most_recent_observation: + continue + + facet_id = most_recent_facet.get("facetId", "") + date = most_recent_observation.get("date", "") + value = most_recent_observation.get("value", "") + provenance_url = facets.get(facet_id, {}).get("provenanceUrl", "") + # Use the unit from the facet if available, otherwise use the unit from the variable definition + unit = facets.get(facet_id, {}).get("unit", None) or item.get("unit", None) + + data_rows.append( + OverviewTableDataRow( + date=date, + name=name, + provenanceUrl=provenance_url, + unit=unit, + value=value, + variableDcid=variable_dcid, + )) + + return data_rows diff --git a/static/js/i18n/i18n.test.ts b/static/js/i18n/i18n.test.ts index f9b0af0f75..6e2f3ed72d 100644 --- a/static/js/i18n/i18n.test.ts +++ b/static/js/i18n/i18n.test.ts @@ -14,7 +14,12 @@ * limitations under the License. */ -import { formatNumber, loadLocaleData, translateUnit } from "./i18n"; +import { + formatDate, + formatNumber, + loadLocaleData, + translateUnit, +} from "./i18n"; /** * Prints a string as hex - useful to displaying non-breaking spaces and other @@ -383,3 +388,39 @@ test("translateUnit", async () => { } } }); + +test("formatDate", async () => { + const cases: { + date: string; + expected: { [lang: string]: string }; + }[] = [ + { + date: "2024", + expected: { + en: "2024", + de: "2024", + }, + }, + { + date: "2024-11", + expected: { + en: "Nov 2024", + de: "Nov. 2024", + }, + }, + { + date: "2024-11-01", + expected: { + en: "Nov 1, 2024", + de: "1. Nov. 2024", + }, + }, + ]; + + for (const locale of ["en", "de"]) { + for (const c of cases) { + const text = formatDate(c.date, locale); + expect(text).toEqual(c.expected[locale]); + } + } +}); diff --git a/static/js/i18n/i18n.tsx b/static/js/i18n/i18n.tsx index 985eb4a0e6..ebf49a4b8c 100644 --- a/static/js/i18n/i18n.tsx +++ b/static/js/i18n/i18n.tsx @@ -177,7 +177,8 @@ function formatNumber( value: number, unit?: string, useDefaultFormat?: boolean, - numFractionDigits?: number + numFractionDigits?: number, + options?: Intl.NumberFormatOptions ): string { if (isNaN(value)) { return "-"; @@ -185,7 +186,7 @@ function formatNumber( if (useDefaultFormat) { return Intl.NumberFormat(intl.locale).format(value); } - const formatOptions: any = { + const formatOptions: Intl.NumberFormatOptions = options || { /* any is used since not all available options are defined in NumberFormatOptions */ compactDisplay: "short", maximumSignificantDigits: 3, @@ -218,6 +219,11 @@ function formatNumber( formatOptions.style = "percent"; value = value / 100; // Values are scaled by formatter for percent display break; + case "Year": + formatOptions.style = "unit"; + formatOptions.unit = "year"; + formatOptions.unitDisplay = "short"; + break; case "MetricTon": case "t": unitKey = "metric-ton"; @@ -340,7 +346,68 @@ function translateUnit(unit: string): string { return displayUnit; } +/** + * Formats an ISO date string to the current locale. + * + * @param dateString: ISO date string + * @param locale: (optional) locale to use for formatting + * + * Example: + * 2024-11-01 -> November 1, 2024 + * 2024-11 -> November 2024 + * 2024 -> 2024 + * + * @return formatted date string + */ +function formatDate(dateString: string, locale?: string) { + // Regex to match: + // - Year (required): 4 digits + // - Optional month: -MM + // - Optional day: -DD + const pattern = /^(\d{4})(?:-(\d{2})(?:-(\d{2}))?)?$/; + const match = dateString.match(pattern); + + // If the date string doesn't match the pattern, return it as is + if (!match) { + return dateString; + } + + const year = parseInt(match[1], 10); + const month = match[2] ? parseInt(match[2], 10) : null; + const day = match[3] ? parseInt(match[3], 10) : null; + + // Case 1: Year only + if (!month) { + return dateString; + } + + // Otherwise, construct a Date + // - If day is missing, default to 1 + // so “2024-11” becomes 2024-11-01 + const date = new Date(year, month - 1, day || 1); + + // Ensure that date is valid + if (isNaN(date.getTime())) { + return dateString; + } + + // Determine how to format: + // - Year & month -> "November 2024" + // - Full date -> "November 1, 2024" + const options: Intl.DateTimeFormatOptions = { + year: "numeric", + month: "short", + }; + if (day) { + options.day = "numeric"; + } + + // Format using locale + return date.toLocaleDateString(locale || intl.locale, options); +} + export { + formatDate, formatNumber, intl, loadLocaleData, diff --git a/static/js/place/dev_place_main.tsx b/static/js/place/dev_place_main.tsx index a849f46780..350ab40d3e 100644 --- a/static/js/place/dev_place_main.tsx +++ b/static/js/place/dev_place_main.tsx @@ -18,6 +18,7 @@ import { Category, PlaceChartsApiResponse, + PlaceOverviewTableApiResponse, RelatedPlacesApiResponse, } from "@datacommonsorg/client/dist/data_commons_web_client_types"; import { ThemeProvider } from "@emotion/react"; @@ -257,6 +258,8 @@ export const DevPlaceMain = (): React.JSX.Element => { useState(); const [placeChartsApiResponse, setPlaceChartsApiResponse] = useState(); + const [placeOverviewTableApiResponse, setPlaceOverviewTableApiResponse] = + useState(); // Derived place data const [childPlaceType, setChildPlaceType] = useState(); @@ -323,24 +326,32 @@ export const DevPlaceMain = (): React.JSX.Element => { } setIsLoading(true); (async (): Promise => { - const [placeChartsApiResponse, relatedPlacesApiResponse] = - await Promise.all([ - defaultDataCommonsWebClient.getPlaceCharts({ - category, - locale, - placeDcid: place.dcid, - }), - defaultDataCommonsWebClient.getRelatedPLaces({ - locale, - placeDcid: place.dcid, - }), - ]); + const [ + placeChartsApiResponse, + relatedPlacesApiResponse, + placeOverviewTableApiResponse, + ] = await Promise.all([ + defaultDataCommonsWebClient.getPlaceCharts({ + category, + locale, + placeDcid: place.dcid, + }), + defaultDataCommonsWebClient.getRelatedPLaces({ + locale, + placeDcid: place.dcid, + }), + defaultDataCommonsWebClient.getPlaceOverviewTable({ + locale, + placeDcid: place.dcid, + }), + ]); setPlaceChartsApiResponse(placeChartsApiResponse); setRelatedPlacesApiResponse(relatedPlacesApiResponse); setChildPlaceType(relatedPlacesApiResponse.childPlaceType); setChildPlaces(relatedPlacesApiResponse.childPlaces); setParentPlaces(relatedPlacesApiResponse.parentPlaces); + setPlaceOverviewTableApiResponse(placeOverviewTableApiResponse); setIsLoading(false); const config = placeChartsApiResponsesToPageConfig( placeChartsApiResponse, @@ -380,13 +391,16 @@ export const DevPlaceMain = (): React.JSX.Element => { place={place} forceDevPlaces={forceDevPlaces} /> - {isOverview && categories.length > 0 && placeSummary != "" && ( - - )} + {isOverview && + placeOverviewTableApiResponse && + placeOverviewTableApiResponse.data.length > 0 && ( + + )} {hasPlaceCharts && ( { const theme = useTheme(); - const { placeDcid } = props; - const [dataRows, setDataRows] = useState([]); const containerRef = useRef(null); - // Fetch key demographic statistics for the place when it changes - useEffect(() => { - (async (): Promise => { - const placeOverviewDataRows = await defaultDataCommonsClient.getDataRows({ - entities: [placeDcid], - variables: [ - "Count_Person", - "Median_Income_Person", - "Median_Age_Person", - "UnemploymentRate_Person", - ], - }); - setDataRows(placeOverviewDataRows); - })(); - }, [placeDcid]); - if (!dataRows) { - return null; - } + const dataRows = props.placeOverviewTableApiResponse.data; + const sourceUrls = new Set( dataRows.map((dataRow) => { - return dataRow.variable.observation.metadata.provenanceUrl; + return dataRow.provenanceUrl; }) ); - const statVarDcids = dataRows.map((dr) => { - return dr.variable.dcid; - }); - - const statVarSpecs: StatVarSpec[] = statVarDcids.map((dcid) => { - return { - statVar: dcid, - denom: "", // Initialize with an empty string or a default denominator if applicable - unit: "", // Initialize with an empty string or a default unit if applicable - scaling: 1, // Initialize with a default scaling factor - log: false, // Initialize with a default log value - }; + const statVarDcids = dataRows.map((row) => { + return row.variableDcid; }); return ( @@ -118,17 +90,27 @@ const PlaceOverviewTable = (props: { {dataRows.map((dataRow, index) => { - const unit = dataRow.variable.observation.metadata.unitDisplayName - ? dataRow.variable.observation.metadata.unitDisplayName - : ""; - const formattedObservationValue = - dataRow.variable.observation.value.toLocaleString(); + const unit = dataRow.unit; + const value = dataRow.value; + + // Format the observation value with the unit + const formattedObservationValue = formatNumber( + value, + unit, + undefined, + undefined, + { + maximumFractionDigits: 2, + minimumFractionDigits: 0, + style: "decimal", + } + ); + const formattedDate = formatDate(dataRow.date); return ( - {dataRow.variable.properties.name} + {dataRow.name} - {formattedObservationValue} {unit} ( - {dataRow.variable.observation.date}) + {formattedObservationValue} ({formattedDate}) @@ -166,10 +148,12 @@ const PlaceOverviewTable = (props: { */ export const PlaceOverview = (props: { place: NamedTypedPlace; - placeSummary: string; + placeSummary?: string; parentPlaces: NamedTypedPlace[]; + placeOverviewTableApiResponse: PlaceOverviewTableApiResponse; }): React.JSX.Element => { - const { place, placeSummary, parentPlaces } = props; + const { place, placeSummary, parentPlaces, placeOverviewTableApiResponse } = + props; const isInUsa = isPlaceContainedInUsa( parentPlaces.map((place) => place.dcid) ); @@ -200,15 +184,18 @@ export const PlaceOverview = (props: { {intl.formatMessage(pageMessages.SummaryOverview)} -
- {placeSummary} -
+ {placeSummary && ( +
+ {placeSummary} +
+ )} +
{!isInUsa &&

} - +