Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Agency Dashboard] Create agency data store to fetch published data #189

Merged
merged 9 commits into from
Dec 2, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 25 additions & 57 deletions agency-dashboard/src/AgencyOverview.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,56 +25,24 @@ beforeEach(() => {
fetchMock.resetMocks();
});

// test("renders loading state", () => {
// fetchMock.mockResponseOnce(
// JSON.stringify({
// datapoints: [],
// dimension_names_by_metric_and_disaggregation: {},
// })
// );

// render(
// <StoreProvider>
// <MemoryRouter initialEntries={["/agency/1"]}>
// <AgencyOverview />
// </MemoryRouter>
// </StoreProvider>
// );
// const loadingElement = screen.getByText(/Loading.../i);
// expect(loadingElement).toBeInTheDocument();
// });

test("renders 'No published metrics' state", async () => {
fetchMock.mockResponseOnce(
JSON.stringify({
datapoints: [],
dimension_names_by_metric_and_disaggregation: {},
})
);

render(
<StoreProvider>
<MemoryRouter initialEntries={["/agency/1"]}>
<AgencyOverview />
</MemoryRouter>
</StoreProvider>
);

const textElement = await screen.findByText(/No published metrics./i);
expect(textElement).toBeInTheDocument();
});

test("renders list of metrics", async () => {
fetchMock.mockResponseOnce(
JSON.stringify({
datapoints: [{}],
dimension_names_by_metric_and_disaggregation: {
LAW_ENFORCEMENT_ARRESTS: {},
LAW_ENFORCEMENT_BUDGET: {},
LAW_ENFORCEMENT_CALLS_FOR_SERVICE: {},
fetchMock.mockResponses([
JSON.stringify([
{
key: "LAW_ENFORCEMENT_ARRESTS",
display_name: "Total Arrests",
},
})
);
{
key: "LAW_ENFORCEMENT_BUDGET",
display_name: "Annual Budget",
},
{
key: "LAW_ENFORCEMENT_CALLS_FOR_SERVICE",
display_name: "Calls for Service",
},
]),
{},
]);

render(
<StoreProvider>
Expand All @@ -83,16 +51,16 @@ test("renders list of metrics", async () => {
</MemoryRouter>
</StoreProvider>
);
const textElement1 = await screen.findByText(
const textElementClickOnAMetricToViewChart = await screen.findByText(
/Click on a metric to view chart:/i
);
expect(textElement1).toBeInTheDocument();
const textElement2 = await screen.findByText(/LAW_ENFORCEMENT_ARRESTS/i);
expect(textElement2).toBeInTheDocument();
const textElement3 = await screen.findByText(/LAW_ENFORCEMENT_BUDGET/i);
expect(textElement3).toBeInTheDocument();
const textElement4 = await screen.findByText(
/LAW_ENFORCEMENT_CALLS_FOR_SERVICE/i
expect(textElementClickOnAMetricToViewChart).toBeInTheDocument();
const textElementTotalArrests = await screen.findByText(/Total Arrests/i);
expect(textElementTotalArrests).toBeInTheDocument();
const textElementAnnualBudget = await screen.findByText(/Annual Budget/i);
expect(textElementAnnualBudget).toBeInTheDocument();
const textElementCallsForService = await screen.findByText(
/Calls for Service/i
);
expect(textElement4).toBeInTheDocument();
expect(textElementCallsForService).toBeInTheDocument();
});
47 changes: 20 additions & 27 deletions agency-dashboard/src/AgencyOverview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,44 +27,37 @@ const AgencyOverview = () => {
const navigate = useNavigate();
const params = useParams();
const agencyId = Number(params.id);
const { datapointsStore } = useStore();
const { agencyDataStore } = useStore();

const fetchDatapoints = async () => {
try {
await datapointsStore.getDatapoints(agencyId);
} catch (error) {
showToast("Error fetching data.", false, "red", 4000);
}
};
useEffect(() => {
fetchDatapoints();
const fetchData = async () => {
try {
await agencyDataStore.fetchAgencyData(agencyId);
} catch (error) {
showToast("Error fetching data.", false, "red", 4000);
}
};
fetchData();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

if (datapointsStore.loading) {
if (agencyDataStore.loading) {
return <>Loading...</>;
}

const metrics = Object.keys(datapointsStore.datapointsByMetric);
if (metrics.length === 0) {
return <>No published metrics.</>;
}

return (
<>
Click on a metric to view chart:
{Object.keys(datapointsStore.dimensionNamesByMetricAndDisaggregation).map(
(metricKey) => (
<MetricCategory
key={metricKey}
onClick={() => {
navigate(`/agency/${agencyId}/dashboard?metric=${metricKey}`);
}}
>
{datapointsStore.metricKeyToDisplayName[metricKey] || metricKey}
</MetricCategory>
)
)}
{agencyDataStore.metrics.map((metric) => (
<MetricCategory
key={metric.key}
onClick={() => {
navigate(`/agency/${agencyId}/dashboard?metric=${metric.key}`);
}}
>
{agencyDataStore.metricKeyToDisplayName[metric.key] || metric.key}
</MetricCategory>
))}
</>
);
};
Expand Down
55 changes: 20 additions & 35 deletions agency-dashboard/src/DashboardView.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,42 +25,27 @@ beforeEach(() => {
fetchMock.resetMocks();
});

// test("renders loading state", () => {
// fetchMock.mockResponseOnce(
// JSON.stringify({
// datapoints: [{}],
// dimension_names_by_metric_and_disaggregation: {
// LAW_ENFORCEMENT_ARRESTS: {},
// LAW_ENFORCEMENT_BUDGET: {},
// LAW_ENFORCEMENT_CALLS_FOR_SERVICE: {},
// },
// })
// );

// render(
// <StoreProvider>
// <MemoryRouter
// initialEntries={["/agency/1/dashboard?metric=LAW_ENFORCEMENT_ARRESTS"]}
// >
// <DashboardView />
// </MemoryRouter>
// </StoreProvider>
// );
// const loadingElement = screen.getByText(/Loading.../i);
// expect(loadingElement).toBeInTheDocument();
// });

test("renders 'No reported data for this metric.' state", async () => {
fetchMock.mockResponseOnce(
JSON.stringify({
datapoints: [{}],
dimension_names_by_metric_and_disaggregation: {
LAW_ENFORCEMENT_ARRESTS: {},
LAW_ENFORCEMENT_BUDGET: {},
LAW_ENFORCEMENT_CALLS_FOR_SERVICE: {},
fetchMock.mockResponses([
JSON.stringify([
{
key: "LAW_ENFORCEMENT_ARRESTS",
display_name: "Total Arrests",
disaggregations: [],
},
})
);
{
key: "LAW_ENFORCEMENT_BUDGET",
display_name: "Annual Budget",
disaggregations: [],
},
{
key: "LAW_ENFORCEMENT_CALLS_FOR_SERVICE",
display_name: "Calls for Service",
disaggregations: [],
},
]),
{},
]);

render(
<StoreProvider>
Expand All @@ -72,7 +57,7 @@ test("renders 'No reported data for this metric.' state", async () => {
</StoreProvider>
);

const textElements = await screen.findAllByText(/LAW_ENFORCEMENT_ARRESTS/i);
const textElements = await screen.findAllByText(/Total Arrests/i);
expect(textElements[0]).toBeInTheDocument();
expect(textElements[1]).toBeInTheDocument();
});
49 changes: 32 additions & 17 deletions agency-dashboard/src/DashboardView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import { DatapointsView } from "@justice-counts/common/components/DataViz/Datapo
import { MetricInsights } from "@justice-counts/common/components/DataViz/MetricInsights";
import { transformDataForMetricInsights } from "@justice-counts/common/components/DataViz/utils";
import { COMMON_DESKTOP_WIDTH } from "@justice-counts/common/components/GlobalStyles";
import { showToast } from "@justice-counts/common/components/Toast";
import { DataVizTimeRangesMap } from "@justice-counts/common/types";
import { observer } from "mobx-react-lite";
import React, { useEffect, useState } from "react";
Expand Down Expand Up @@ -93,7 +94,7 @@ const DashboardView = () => {
const navigate = useNavigate();
const params = useParams();
const agencyId = Number(params.id);
const { datapointsStore, dataVizStore } = useStore();
const { agencyDataStore, dataVizStore } = useStore();

const {
timeRange,
Expand All @@ -107,22 +108,30 @@ const DashboardView = () => {
const { search } = useLocation();
const query = new URLSearchParams(search);
const metricKey = query.get("metric");

useEffect(() => {
datapointsStore.getDatapoints(agencyId);
const fetchData = async () => {
try {
await agencyDataStore.fetchAgencyData(agencyId);
} catch (error) {
showToast("Error fetching data.", false, "red", 4000);
}
};
fetchData();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

useEffect(() => {
if (
metricKey &&
!datapointsStore.loading &&
!datapointsStore.dimensionNamesByMetricAndDisaggregation[metricKey]
!agencyDataStore.loading &&
!agencyDataStore.dimensionNamesByMetricAndDisaggregation[metricKey]
) {
navigate(`/agency/${agencyId}`);
}

// eslint-disable-next-line react-hooks/exhaustive-deps
}, [datapointsStore.loading]);
}, [agencyDataStore.loading]);

useEffect(() => {
const resizeListener = () => {
Expand All @@ -145,25 +154,25 @@ const DashboardView = () => {

if (
!metricKey ||
(!datapointsStore.loading &&
!datapointsStore.dimensionNamesByMetricAndDisaggregation[metricKey])
(!agencyDataStore.loading &&
!agencyDataStore.dimensionNamesByMetricAndDisaggregation[metricKey])
) {
return null;
}

if (datapointsStore.loading) {
if (agencyDataStore.loading) {
return <>Loading...</>;
}

const metricNames = Object.keys(
datapointsStore.dimensionNamesByMetricAndDisaggregation
const metricNames = agencyDataStore.metrics.map(
(metric) => metric.display_name
);

const metricName =
datapointsStore.metricKeyToDisplayName[metricKey] || metricKey;
agencyDataStore.metricKeyToDisplayName[metricKey] || metricKey;

const filteredAggregateData = transformDataForMetricInsights(
datapointsStore.datapointsByMetric[metricKey]?.aggregate || [],
agencyDataStore.datapointsByMetric[metricKey]?.aggregate || [],
DataVizTimeRangesMap[dataVizStore.timeRange]
);

Expand All @@ -189,10 +198,10 @@ const DashboardView = () => {
<RightPanelMetricTitle>{metricName}</RightPanelMetricTitle>
<DatapointsView
datapointsGroupedByAggregateAndDisaggregations={
datapointsStore.datapointsByMetric[metricKey]
agencyDataStore.datapointsByMetric[metricKey]
}
dimensionNamesByDisaggregation={
datapointsStore.dimensionNamesByMetricAndDisaggregation[metricKey]
agencyDataStore.dimensionNamesByMetricAndDisaggregation[metricKey]
}
timeRange={timeRange}
disaggregationName={disaggregationName}
Expand All @@ -201,9 +210,15 @@ const DashboardView = () => {
setDisaggregationName={setDisaggregationName}
setCountOrPercentageView={setCountOrPercentageView}
metricNames={metricNames}
onMetricsSelect={(metric) =>
navigate(`/agency/${agencyId}/dashboard?metric=${metric}`)
}
onMetricsSelect={(selectedMetricName) => {
const selectedMetricKey =
agencyDataStore.metricDisplayNameToKey[selectedMetricName];
if (selectedMetricKey) {
navigate(
`/agency/${agencyId}/dashboard?metric=${selectedMetricKey}`
);
}
}}
showBottomMetricInsights={!isDesktopWidth}
resizeHeight={isDesktopWidth}
/>
Expand Down
Loading