Skip to content
Open
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
28 changes: 6 additions & 22 deletions map/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,29 +6,13 @@
class CommunityAreaSerializer(serializers.ModelSerializer):
class Meta:
model = CommunityArea
fields = ["name", "num_permits"]
fields = ["name", "area_id", "num_permits"]
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I veered slightly from the instructions, but I took inspiration from the TODO example object in get_num_permits. I would prefer to include the area_id for use on the frontend. I checked the raw data, and while it appears clean, it's just better practice to match on an id if one is present.


num_permits = serializers.SerializerMethodField()

def get_num_permits(self, obj):
"""
TODO: supplement each community area object with the number
of permits issued in the given year.

e.g. The endpoint /map-data/?year=2017 should return something like:
[
{
"ROGERS PARK": {
area_id: 17,
num_permits: 2
},
"BEVERLY": {
area_id: 72,
num_permits: 2
},
...
}
]
"""

pass
year = self.context.get("year")
permits = RestaurantPermit.objects.filter(community_area_id=obj.area_id)
if year:
permits = permits.filter(issue_date__year=year)
return permits.count()
47 changes: 27 additions & 20 deletions map/static/js/RestaurantPermitMap.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,39 +40,46 @@ export default function RestaurantPermitMap() {
const communityAreaColors = ["#eff3ff", "#bdd7e7", "#6baed6", "#2171b5"]

const [currentYearData, setCurrentYearData] = useState([])
const [areaDataMap, setAreaDataMap] = useState({})
const [year, setYear] = useState(2026)

const yearlyDataEndpoint = `/map-data/?year=${year}`
const totalNumPermits = currentYearData.reduce((sum, { num_permits}) => sum + num_permits, 0)
const maxNumPermits = currentYearData.reduce((max, { num_permits }) => Math.max(max, num_permits), 0)

useEffect(() => {
fetch()
fetch(yearlyDataEndpoint)
.then((res) => res.json())
.then((data) => {
/**
* TODO: Fetch the data needed to supply to map with data
*/
setCurrentYearData(data)
const map = data.reduce((acc, area) => {
acc[area.area_id] = area
return acc
}, {})
setAreaDataMap(map)
Comment on lines +55 to +59
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I veered slightly from the instructions here as well. I added a state variable to map the area data on the same fetch response as setting the current year data. I'm storing the fetched data in two shapes for convenience, as they serve two different purposes.

currentYearData is the array, used for computing totalNumPermits and maxNumPermits with .reduce()

areaDataMap is the same data keyed by area_id, used for fast lookups in setAreaInteraction where we need to find a specific area by its ID.

})
}, [yearlyDataEndpoint])


function getColor(percentageOfPermits) {
/**
* TODO: Use this function in setAreaInteraction to set a community
* area's color using the communityAreaColors constant above
*/
if (percentageOfPermits > 0.75) return communityAreaColors[3]
if (percentageOfPermits > 0.5) return communityAreaColors[2]
if (percentageOfPermits > 0.25) return communityAreaColors[1]
return communityAreaColors[0]
}

function setAreaInteraction(feature, layer) {
/**
* TODO: Use the methods below to:
* 1) Shade each community area according to what percentage of
* permits were issued there in the selected year
* 2) On hover, display a popup with the community area's raw
* permit count for the year
*/
layer.setStyle()
layer.on("", () => {
layer.bindPopup("")
const areaId = feature.properties.area_num_1
const areaData = areaDataMap[areaId]
const percentage = maxNumPermits > 0 ? areaData.num_permits / maxNumPermits : 0
layer.setStyle({
fillColor: getColor(percentage),
fillOpacity: 0.7,
color: "#808080",
weight: 1,
})
layer.on("mouseover", () => {
layer.bindPopup(`<b>${areaData.name}</b><br/>Permits: ${areaData.num_permits}`)
layer.openPopup()
})
}
Expand All @@ -81,11 +88,11 @@ export default function RestaurantPermitMap() {
<>
<YearSelect filterVal={year} setFilterVal={setYear} />
<p className="fs-4">
Restaurant permits issued this year: {/* TODO: display this value */}
Restaurant permits issued this year: {totalNumPermits}
</p>
<p className="fs-4">
Maximum number of restaurant permits in a single area:
{/* TODO: display this value */}
{maxNumPermits}
</p>
<MapContainer
id="restaurant-map"
Expand Down
13 changes: 10 additions & 3 deletions tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,13 @@ def test_map_data_view():
client = APIClient()
response = client.get(reverse("map_data", query={"year": 2021}))

# TODO: Complete the test by asserting that the /map-data/ endpoint
# returns the correct number of permits for Beverly and Lincoln
# Park in 2021
assert response.status_code == 200

expected_response = [
{"name": "Beverly", "area_id": 1, "num_permits": 2},
{"name": "Lincoln Park", "area_id": 2, "num_permits": 3},
]

assert (
response.json() == expected_response
), "Should return the correct number of permits for each community area"