Skip to content

Commit

Permalink
Merge branch 'develop' into CU-86886y77w-celery-beat
Browse files Browse the repository at this point in the history
  • Loading branch information
copelco authored Apr 16, 2024
2 parents c3f3351 + 70519be commit f47746a
Show file tree
Hide file tree
Showing 21 changed files with 760 additions and 985 deletions.
24 changes: 24 additions & 0 deletions frontend/src/Components/AgencyData/AgencyData.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import AgencyHeader from './AgencyHeader';
import Sidebar from '../Sidebar/Sidebar';
import ChartRoutes from '../Charts/ChartRoutes';
import { CompareAlertBox } from '../Elements/Alert/Alert';
import { YEARS_DEFAULT } from '../Charts/chartUtils';
import axios from '../../Services/Axios';

function AgencyData(props) {
let { agencyId } = useParams();
Expand All @@ -27,6 +29,10 @@ function AgencyData(props) {
const [chartsOpen, setChartsOpen] = useState(false);
const [chartState] = useDataset(agencyId, AGENCY_DETAILS);

const [yearRange, setYearRange] = useState([YEARS_DEFAULT]);
const [year, setYear] = useState(YEARS_DEFAULT);
const [yearIdx, setYearIdx] = useState(null);

useEffect(() => {
if (chartState.data[AGENCY_DETAILS]) setSidebarOpen(true);
}, [chartState.data[AGENCY_DETAILS]]);
Expand All @@ -39,6 +45,18 @@ function AgencyData(props) {
if (chartState.data[AGENCY_DETAILS]) setChartsOpen(true);
}, [chartState.data[AGENCY_DETAILS]]);

useEffect(() => {
axios.get(`/api/agency/${agencyId}/year-range/`).then((res) => {
setYearRange([YEARS_DEFAULT].concat(res.data.year_range));
});
}, [agencyId]);

const handleYearSelect = (y, idx) => {
if (y === year) return;
setYear(y);
setYearIdx(idx); // Used for some pie chart graphs
};

return (
<S.AgencyData data-testid="AgencyData" {...props}>
{props.showCompare && !props.agencyId && <CompareAlertBox />}
Expand All @@ -48,6 +66,9 @@ function AgencyData(props) {
toggleShowCompare={props.toggleShowCompare}
showCompareDepartments={props.showCompare}
showCloseButton={!!props?.agencyId}
yearRange={yearRange}
year={year}
handleYearSelect={handleYearSelect}
/>
<S.ContentWrapper showCompare={props.showCompare}>
<AnimatePresence>
Expand All @@ -72,6 +93,9 @@ function AgencyData(props) {
agencyId={agencyId}
showCompare={props.showCompare}
agencyName={chartState.data[AGENCY_DETAILS].name}
yearRange={yearRange}
year={year}
yearIdx={yearIdx}
/>
)}
</S.ContentWrapper>
Expand Down
11 changes: 11 additions & 0 deletions frontend/src/Components/AgencyData/AgencyHeader.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,17 @@ import BackButton from '../Elements/BackButton';
import Button from '../Elements/Button';
import * as ChartHeaderStyles from '../Charts/ChartSections/ChartHeader.styled';
import CensusData from './CensusData';
import DataSubsetPicker from '../Charts/ChartSections/DataSubsetPicker/DataSubsetPicker';

function AgencyHeader({
agencyHeaderOpen,
agencyDetails,
toggleShowCompare,
showCompareDepartments,
showCloseButton,
yearRange,
year,
handleYearSelect,
}) {
const history = useHistory();
const { agencyId } = useParams();
Expand Down Expand Up @@ -92,6 +96,13 @@ function AgencyHeader({
showCompareDepartments={showCompareDepartments}
/>
</S.SubHeaderContentRow>
<DataSubsetPicker
label="Year"
value={year}
onChange={handleYearSelect}
options={yearRange}
dropDown
/>
{!showCloseButton && (
<S.AgencyHeaderButton>
<Button
Expand Down
119 changes: 38 additions & 81 deletions frontend/src/Components/Charts/Arrest/Arrests.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,12 @@
import React, { useEffect, useState } from 'react';
import ArrestsStyled from './Arrests.styles';

// Util
import { YEARS_DEFAULT } from '../chartUtils';

// Hooks
import useMetaTags from '../../../Hooks/useMetaTags';
import useTableModal from '../../../Hooks/useTableModal';

// Children
import DataSubsetPicker from '../ChartSections/DataSubsetPicker/DataSubsetPicker';
import PercentageOfStops from './Charts/PercentageOfStops';
import useYearSet from '../../../Hooks/useYearSet';
import PercentageOfSearches from './Charts/PercentageOfSearches';
import CountOfStopsAndArrests from './Charts/CountOfStopsAndArrests';
import PercentageOfStopsForStopPurposeGroup from './Charts/PercentageOfStopsForPurposeGroup';
Expand All @@ -23,8 +18,7 @@ import Switch from 'react-switch';
import { SwitchContainer } from '../TrafficStops/TrafficStops.styled';

function Arrests(props) {
const [year, setYear] = useState(YEARS_DEFAULT);
const [yearRange] = useYearSet();
const { year } = props;
const [togglePercentageOfStops, setTogglePercentageOfStops] = useState(true);
const [togglePercentageOfSearches, setTogglePercentageOfSearches] = useState(true);

Expand All @@ -37,60 +31,58 @@ function Arrests(props) {
}
}, []);

const handleYearSelect = (y) => {
if (y === year) return;
setYear(y);
};
const stopGraphToggle = () => (
<SwitchContainer>
<span>
Switch to view {togglePercentageOfStops ? 'all stop purposes' : 'grouped stop purposes '}
</span>
<Switch
onChange={() => setTogglePercentageOfStops(!togglePercentageOfStops)}
checked={togglePercentageOfStops}
className="react-switch"
/>
</SwitchContainer>
);

const searchGraphToggle = () => (
<SwitchContainer>
<span>
Switch to view {togglePercentageOfSearches ? 'all stop purposes' : 'grouped stop purposes '}
</span>
<Switch
onChange={() => setTogglePercentageOfSearches(!togglePercentageOfSearches)}
checked={togglePercentageOfSearches}
className="react-switch"
/>
</SwitchContainer>
);

return (
<ArrestsStyled>
{renderMetaTags()}
{renderTableModal()}
<div style={{ display: 'flex', justifyContent: 'center' }}>
<DataSubsetPicker
label="Year"
value={year}
onChange={handleYearSelect}
options={[YEARS_DEFAULT].concat(yearRange)}
dropDown
/>
</div>
<PercentageOfStops {...props} year={year} />
<PercentageOfSearches {...props} year={year} />
<CountOfStopsAndArrests {...props} year={year} />

<SwitchContainer>
<span>
Switch to view {togglePercentageOfStops ? 'all stop purposes' : 'grouped stop purposes '}
</span>
<Switch
onChange={() => setTogglePercentageOfStops(!togglePercentageOfStops)}
checked={togglePercentageOfStops}
className="react-switch"
/>
</SwitchContainer>
{togglePercentageOfStops ? (
<PercentageOfStopsForStopPurposeGroup {...props} year={year} />
<PercentageOfStopsForStopPurposeGroup {...props} year={year}>
{stopGraphToggle()}
</PercentageOfStopsForStopPurposeGroup>
) : (
<PercentageOfStopsForStopPurpose {...props} year={year} />
<PercentageOfStopsForStopPurpose {...props} year={year}>
{stopGraphToggle()}
</PercentageOfStopsForStopPurpose>
)}

<SwitchContainer>
<span>
Switch to view{' '}
{togglePercentageOfSearches ? 'all stop purposes' : 'grouped stop purposes '}
</span>
<Switch
onChange={() => setTogglePercentageOfSearches(!togglePercentageOfSearches)}
checked={togglePercentageOfSearches}
className="react-switch"
/>
</SwitchContainer>

{togglePercentageOfSearches ? (
<PercentageOfSearchesForStopPurposeGroup {...props} year={year} />
<PercentageOfSearchesForStopPurposeGroup {...props} year={year}>
{searchGraphToggle()}
</PercentageOfSearchesForStopPurposeGroup>
) : (
<PercentageOfSearchesPerStopPurpose {...props} year={year} />
<PercentageOfSearchesPerStopPurpose {...props} year={year}>
{searchGraphToggle()}
</PercentageOfSearchesPerStopPurpose>
)}

<PercentageOfStopsPerContrabandType {...props} year={year} />
Expand All @@ -99,38 +91,3 @@ function Arrests(props) {
}

export default Arrests;

export const ARRESTS_TABLE_COLUMNS = [
{
Header: 'Year',
accessor: 'year', // accessor is the "key" in the data
},
{
Header: 'White*',
accessor: 'white',
},
{
Header: 'Black*',
accessor: 'black',
},
{
Header: 'Native American*',
accessor: 'native_american',
},
{
Header: 'Asian*',
accessor: 'asian',
},
{
Header: 'Other*',
accessor: 'other',
},
{
Header: 'Hispanic',
accessor: 'hispanic',
},
{
Header: 'Total',
accessor: 'total',
},
];
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@ import axios from '../../../../Services/Axios';
import useOfficerId from '../../../../Hooks/useOfficerId';
import { ChartWrapper } from '../Arrests.styles';
import NewModal from '../../../NewCharts/NewModal';
import { ARRESTS_TABLE_COLUMNS } from '../Arrests';
import createTableData from '../../../../util/createTableData';
import { RACE_TABLE_COLUMNS } from '../../chartUtils';

const graphTitle = 'Traffic Stops Leading to Arrest by Count';

function CountOfStopsAndArrests(props) {
const { agencyId, agencyName, showCompare, year } = props;
Expand Down Expand Up @@ -40,25 +43,7 @@ function CountOfStopsAndArrests(props) {
axios
.get(url)
.then((res) => {
const tableData = [];
const resTableData = res.data.table_data.length
? JSON.parse(res.data.table_data)
: { data: [] };
resTableData.data.forEach((e) => {
const dataCounts = { ...e };
delete dataCounts.year;
// Need to assign explicitly otherwise the download data orders columns by alphabet.
tableData.unshift({
year: e.year,
white: e.white,
black: e.black,
native_american: e.native_american,
asian: e.asian,
other: e.other,
hispanic: e.hispanic,
total: Object.values(dataCounts).reduce((a, b) => a + b, 0),
});
});
const tableData = createTableData(res.data);
const labels = ['Stops With Arrests', 'Stops Without Arrests'];
const colors = ['#96a0fa', '#5364f4'];

Expand Down Expand Up @@ -104,27 +89,27 @@ function CountOfStopsAndArrests(props) {
return (
<S.ChartSection>
<ChartHeader
chartTitle="Stop Counts With/Without Arrests"
chartTitle={graphTitle}
handleViewData={() => setArrestData((state) => ({ ...state, isOpen: true }))}
/>
<S.ChartDescription>
<P>Percentage of stops that led to an arrest for a given race / ethnic group.</P>
<P>Count of stops and corresponding arrests for a given race/ethnic group.</P>
<NewModal
tableHeader="Stop Counts With/Without Arrests"
tableSubheader="Shows what numbers of stops led to an arrest for a given race / ethnic group."
tableHeader={graphTitle}
tableSubheader="Shows count of stops and corresponding arrests for a given race/ethnic group."
agencyName={agencyName}
tableData={arrestData.tableData}
csvData={arrestData.csvData}
columns={ARRESTS_TABLE_COLUMNS}
tableDownloadName="Arrests_By_Percentage"
columns={RACE_TABLE_COLUMNS}
tableDownloadName={graphTitle}
isOpen={arrestData.isOpen}
closeModal={() => setArrestData((state) => ({ ...state, isOpen: false }))}
/>
</S.ChartDescription>
<S.ChartSubsection showCompare={showCompare}>
<ChartWrapper>
<HorizontalBarChart
title="Stop Counts With/Without Arrests"
title={graphTitle}
data={arrestData}
pinMaxValue={false}
xStacked
Expand All @@ -133,12 +118,12 @@ function CountOfStopsAndArrests(props) {
stepSize={50000}
tooltipLabelCallback={formatTooltipValue}
modalConfig={{
tableHeader: 'Stop Counts With/Without Arrests',
tableHeader: graphTitle,
tableSubheader: getBarChartModalSubHeading(
'Shows what number of stops led to an arrest for a given race / ethnic group'
'Shows count of stops and corresponding arrests for a given race/ethnic group'
),
agencyName,
chartTitle: getBarChartModalSubHeading('Stop Counts With/Without Arrests'),
chartTitle: getBarChartModalSubHeading(graphTitle),
}}
/>
</ChartWrapper>
Expand Down
Loading

0 comments on commit f47746a

Please sign in to comment.