Skip to content

Commit 314d47d

Browse files
authored
Update the message on adjusted age and date range in Find a Stop. (#360)
1 parent 60b80f5 commit 314d47d

File tree

4 files changed

+85
-122
lines changed

4 files changed

+85
-122
lines changed

frontend/src/Components/FindAStopResults/FindAStopResults.js

Lines changed: 5 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,7 @@ function FindAStopResults() {
5656
const [stops, setStops] = useState([]);
5757
const [loading, setLoading] = useState(false);
5858
const [lastReportedStop, setLastReportedStop] = useState(null);
59-
const [age, setAge] = useState(null);
60-
const [startDate, setStartDate] = useState(null);
61-
const [endDate, setEndDate] = useState(null);
59+
const [extraResultsMessage, setExtraResultsMessage] = useState('');
6260

6361
useEffect(() => {
6462
async function _fetchStops() {
@@ -78,39 +76,7 @@ function FindAStopResults() {
7876
} else {
7977
setLastReportedStop(null);
8078
}
81-
if (data.start_date) {
82-
setStartDate({
83-
entered: new Intl.DateTimeFormat('en-US', {
84-
year: 'numeric',
85-
month: 'short',
86-
day: 'numeric',
87-
}).format(new Date(data.start_date.entered)),
88-
adjusted: new Intl.DateTimeFormat('en-US', {
89-
year: 'numeric',
90-
month: 'short',
91-
day: 'numeric',
92-
}).format(new Date(data.start_date.adjusted)),
93-
});
94-
} else {
95-
setStartDate(null);
96-
}
97-
if (data.end_date) {
98-
setEndDate({
99-
entered: new Intl.DateTimeFormat('en-US', {
100-
year: 'numeric',
101-
month: 'short',
102-
day: 'numeric',
103-
}).format(new Date(data.end_date.entered)),
104-
adjusted: new Intl.DateTimeFormat('en-US', {
105-
year: 'numeric',
106-
month: 'short',
107-
day: 'numeric',
108-
}).format(new Date(data.end_date.adjusted)),
109-
});
110-
} else {
111-
setEndDate(null);
112-
}
113-
setAge(data.age);
79+
setExtraResultsMessage(data.extra_results_message || '');
11480
} catch (e) {
11581
// eslint-disable-next-line no-console
11682
console.warn(e);
@@ -142,23 +108,9 @@ function FindAStopResults() {
142108
<P size={SIZES[0]} color={COLORS[0]}>
143109
{stops.length === MAX_STOPS_RESULTS
144110
? `Returned maximum number of results (${MAX_STOPS_RESULTS}). Try limiting your search`
145-
: `${stops.length} results found`}
146-
</P>
147-
)}
148-
{!loading && age && (
149-
<P size={SIZES[0]} color={COLORS[0]}>
150-
You entered {age.entered} for Age but we used {age.adjusted[0]} - {age.adjusted[1]}{' '}
151-
instead.
152-
</P>
153-
)}
154-
{!loading && startDate && (
155-
<P size={SIZES[0]} color={COLORS[0]}>
156-
You entered {startDate.entered} for Start Date but we used {startDate.adjusted} instead.
157-
</P>
158-
)}
159-
{!loading && endDate && (
160-
<P size={SIZES[0]} color={COLORS[0]}>
161-
You entered {endDate.entered} for End Date but we used {endDate.adjusted} instead.
111+
: `${stops.length} results found` +
112+
(extraResultsMessage &&
113+
` ${extraResultsMessage}. We show you extra results in case the officer made a mistake in their report or your search details had an error.`)}
162114
</P>
163115
)}
164116
</S.Heading>

nc/filters.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,19 +32,21 @@ def filter_agency(self, queryset, name, value):
3232
def filter_stop_date(self, queryset, name, value):
3333
start_date = value.start
3434
end_date = value.stop
35+
adjusted_start_date = adjusted_end_date = None
3536
query = Q()
3637
if start_date:
3738
# Adjust it to 2 days earlier
3839
adjusted_start_date = start_date - timedelta(2)
3940
query &= Q(stop__date__gte=adjusted_start_date)
40-
if self.request:
41-
self.request.adjusted_start_date = start_date.date(), adjusted_start_date.date()
4241
if end_date:
4342
# Adjust it to 2 days later
4443
adjusted_end_date = end_date + timedelta(2)
4544
query &= Q(stop__date__lte=adjusted_end_date)
46-
if self.request:
47-
self.request.adjusted_end_date = end_date.date(), adjusted_end_date.date()
45+
if self.request and (adjusted_start_date or adjusted_end_date):
46+
self.request.adjusted_date_range = [
47+
adjusted_start_date and adjusted_start_date.date(),
48+
adjusted_end_date and adjusted_end_date.date(),
49+
]
4850
return queryset.filter(query)
4951

5052
def filter_officer(self, queryset, name, value):
@@ -61,7 +63,7 @@ def filter_age(self, queryset, name, value):
6163
value = int(value)
6264
age_range = max(value - 2, 0), value + 2
6365
if self.request:
64-
self.request.adjusted_age = value, age_range
66+
self.request.adjusted_age = age_range
6567
return queryset.filter(age__gte=age_range[0], age__lte=age_range[1])
6668

6769
class Meta:

nc/tests/api/test_basic_search.py

Lines changed: 56 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
from rest_framework import status
77

8-
from nc.models import RACE_CHOICES
8+
from nc.models import RACE_CHOICES, Person
99
from nc.tests import factories
1010

1111
pytestmark = pytest.mark.django_db
@@ -48,12 +48,6 @@ def test_response_person_fields(client, search_url, durham):
4848
assert result == expected
4949
# 'last_reported_stop' should only be included if no matching stops were found
5050
assert "last_reported_stop" not in response.data
51-
# 'age' should only be included if the user entered an age
52-
assert "age" not in response.data
53-
# 'start_date' should only be included if the user entered a start date
54-
assert "start_date" not in response.data
55-
# 'end_date' should only be included if the user entered an end date
56-
assert "end_date" not in response.data
5751

5852

5953
@pytest.mark.django_db(databases=["traffic_stops_nc"])
@@ -81,61 +75,69 @@ def test_no_stops_found(client, search_url):
8175
assert response.data.get("last_reported_stop") == agency.last_reported_stop
8276

8377

78+
@pytest.mark.parametrize("search_age", [True, False])
79+
@pytest.mark.parametrize("search_start_date", [True, False])
80+
@pytest.mark.parametrize("search_end_date", [True, False])
8481
@pytest.mark.django_db(databases=["traffic_stops_nc"])
85-
def test_age_adjusted(client, search_url, durham):
86-
"""Ensure people aged + or - 2 years of the age the user entered are included
87-
in search results.
82+
def test_stop_date_range_and_age_adjusted(
83+
client, search_url, durham, search_age, search_start_date, search_end_date
84+
):
85+
"""Ensure the date range and age entered by the user is adjusted such that:
86+
- age is up to 2 years younger or older
87+
- start date is 2 days earlier
88+
- end date is 2 days later
8889
"""
8990
age = 18
90-
# Create 5 stops with people within the expected age range
91-
people = [factories.PersonFactory(stop__agency=durham, age=i) for i in range(age - 2, age + 3)]
92-
# Create 2 stops with people outside the expected age range. These should not
93-
# be included in the search results
94-
factories.PersonFactory(stop__agency=durham, age=age - 3)
95-
factories.PersonFactory(stop__agency=durham, age=age + 3)
96-
97-
response = client.get(search_url, data={"agency": durham.pk, "age": age}, format="json")
98-
99-
assert len(response.data["results"]) == len(people)
100-
stop_ids = {stop["stop_id"] for stop in response.data["results"]}
101-
assert {p.stop.stop_id for p in people} == stop_ids
102-
# 'age' should be included in the response data, with the entered age and
103-
# the adjusted age range
104-
assert response.data["age"] == {"entered": age, "adjusted": (age - 2, age + 2)}
105-
106-
107-
@pytest.mark.django_db(databases=["traffic_stops_nc"])
108-
def test_stop_date_range_adjusted(client, search_url, durham):
109-
"""Ensure the date range entered by the user is adjusted such that the start_date
110-
is 2 days earlier and end_date is 2 days later.
111-
"""
11291
start_date = fake.past_date()
11392
end_date = fake.past_date(start_date=start_date)
114-
# Create some stops within the expected date range
93+
# Create some stops within the expected date range and age range
11594
dates = (
11695
[start_date, end_date]
11796
+ [start_date - timedelta(d) for d in [1, 2]]
11897
+ [end_date + timedelta(d) for d in [1, 2]]
11998
)
120-
people = [factories.PersonFactory(stop__agency=durham, stop__date=d) for d in dates]
121-
# Create 2 stops outside the expected date range. These should not be included
122-
# in the search results
123-
factories.PersonFactory(stop__agency=durham, stop__date=start_date - timedelta(3))
124-
factories.PersonFactory(stop__agency=durham, stop__date=end_date + timedelta(3))
125-
126-
response = client.get(
127-
search_url,
128-
data={"agency": durham.pk, "stop_date_after": start_date, "stop_date_before": end_date},
129-
format="json",
130-
)
131-
132-
assert len(response.data["results"]) == len(people)
99+
people = [
100+
factories.PersonFactory(
101+
stop__agency=durham, stop__date=d, age=fake.random_int(age - 2, age + 2)
102+
)
103+
for d in dates
104+
]
105+
# Create 2 stops outside the expected date range and age range
106+
factories.PersonFactory(stop__agency=durham, stop__date=start_date - timedelta(3), age=age - 3)
107+
factories.PersonFactory(stop__agency=durham, stop__date=end_date + timedelta(3), age=age + 3)
108+
109+
expected_results = Person.objects.filter(stop__agency=durham)
110+
expected_results_message = ""
111+
search_params = {"agency": durham.pk}
112+
if search_age:
113+
search_params["age"] = age
114+
expected_results = expected_results.filter(age__gte=age - 2, age__lte=age + 2)
115+
expected_results_message = f"with drivers aged {age - 2}-{age + 2}"
116+
if search_start_date:
117+
search_params["stop_date_after"] = start_date
118+
used_start_date = start_date - timedelta(2)
119+
expected_results = expected_results.filter(stop__date__gte=used_start_date)
120+
if search_end_date:
121+
expected_results_message += f" between {used_start_date:%B %d, %Y}"
122+
else:
123+
expected_results_message += f" after {used_start_date:%B %d, %Y}"
124+
if search_end_date:
125+
search_params["stop_date_before"] = end_date
126+
used_end_date = end_date + timedelta(2)
127+
expected_results = expected_results.filter(stop__date__lte=used_end_date)
128+
if search_start_date:
129+
expected_results_message += f" and {used_end_date:%B %d, %Y}"
130+
else:
131+
expected_results_message += f" before {used_end_date:%B %d, %Y}"
132+
133+
response = client.get(search_url, data=search_params, format="json")
134+
135+
assert len(response.data["results"]) == len(expected_results)
133136
stop_ids = {stop["stop_id"] for stop in response.data["results"]}
134-
assert {p.stop.stop_id for p in people} == stop_ids
135-
# 'start_date' and 'end_date' should be included in the response data, with
136-
# the entered and adjusted date for each
137-
assert response.data["start_date"] == {
138-
"entered": start_date,
139-
"adjusted": start_date - timedelta(2),
140-
}
141-
assert response.data["end_date"] == {"entered": end_date, "adjusted": end_date + timedelta(2)}
137+
assert {p.stop.stop_id for p in expected_results} == stop_ids
138+
# If the user entered an age and/or a date range, the 'extra_results_message'
139+
# should be included in the response data
140+
if expected_results_message:
141+
assert response.data["extra_results_message"] == expected_results_message.strip()
142+
else:
143+
assert "extra_results_message" not in response.data

nc/views/main.py

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -274,16 +274,23 @@ class DriverStopsViewSet(viewsets.ReadOnlyModelViewSet):
274274
def list(self, request, *args, **kwargs):
275275
response = super().list(request, *args, **kwargs)
276276
if response.data["results"]:
277-
# If the user entered an age or date range, add the values entered
278-
# and the adjusted values to the response, so they can be included
279-
# in a message on the frontend
280-
for field in ("age", "start_date", "end_date"):
281-
adjusted = getattr(request, f"adjusted_{field}", None)
282-
if adjusted:
283-
response.data[field] = {
284-
"entered": adjusted[0],
285-
"adjusted": adjusted[1],
286-
}
277+
# If the user entered an age and/or date range, add a message indicating
278+
# the adjusted search parameters
279+
message_parts = []
280+
age_range = getattr(request, "adjusted_age", None)
281+
date_range = getattr(request, "adjusted_date_range", None)
282+
if age_range:
283+
message_parts.append(f"with drivers aged {age_range[0]}-{age_range[1]}")
284+
if date_range:
285+
date_range = [i and i.strftime("%B %d, %Y") for i in date_range]
286+
if all(date_range):
287+
message_parts.append(f"between {date_range[0]} and {date_range[1]}")
288+
elif date_range[0]:
289+
message_parts.append(f"after {date_range[0]}")
290+
else:
291+
message_parts.append(f"before {date_range[1]}")
292+
if message_parts:
293+
response.data["extra_results_message"] = " ".join(message_parts)
287294
else:
288295
# No stops were found. Add the agency's last_reported_stop to the
289296
# response data

0 commit comments

Comments
 (0)