Skip to content

Commit 1024e56

Browse files
Merge branch 'release/2.1.0'
2 parents 9af6fbf + 9c54807 commit 1024e56

File tree

13 files changed

+1946
-2119
lines changed

13 files changed

+1946
-2119
lines changed

deployment/amplify/production/amplify/backend/auth/echolocatorProdAuth/parameters.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
"smsAuthenticationMessage": "Your authentication code is {####}",
1414
"smsVerificationMessage": "Your verification code is {####}",
1515
"emailVerificationSubject": "Your ECHOLocator verification code",
16-
"emailVerificationMessage": "Welcome to the ECHOLocator!\\n\\nYour ECHOLocator verification code is {####}.\\nYour username is your email address.\\n\\nClick <a href=\\\"https://echolocator.org/\\\">here</a> to log in to your account, set a new password, and continue your housing search.\\n\\nRegards,\\nThe Boston Housing Authority ECHOLocator Team",
16+
"emailVerificationMessage": "Welcome to the ECHOLocator!\\n\\nYour ECHOLocator verification code is {####}\\nYour username is your email address.\\n\\nClick <a href=\\\"https://echolocator.org/\\\">here</a> to log in to your account, set a new password, and continue your housing search.\\n\\nRegards,\\nThe Boston Housing Authority ECHOLocator Team",
1717
"defaultPasswordPolicy": false,
1818
"passwordPolicyMinLength": 8,
1919
"passwordPolicyCharacters": [],

neighborhood_data/generate_neighborhood_json.py

-1
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,6 @@
5555
'school': 'str',
5656
'town_square': 'str',
5757
'open_space_or_landmark': 'str',
58-
'zviolentcrimeflip': 'float',
5958
'crime_percentile': 'float'
6059
}
6160

neighborhood_data/neighborhood_centroids.csv

+248-248
Large diffs are not rendered by default.

neighborhood_data/neighborhood_centroids_descriptions.csv

+259-591
Large diffs are not rendered by default.

neighborhood_data/neighborhoods.csv

+248-248
Large diffs are not rendered by default.

taui/configurations/default/messages.yml

+5-5
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ NeighborhoodDetails:
6060
GoogleMapsLink: Google Maps
6161
GoSection8SearchLink: GoSection8
6262
HotpadsSearchLink: Hotpads
63-
MassHousingLink: Mass Housing
63+
MetroHousingLink: Metro Housing
6464
MaxRent: Est. max rent
6565
ModeSummary: via
6666
MoreSearchToolsLinksHeading: More search tools
@@ -108,7 +108,7 @@ Accounts:
108108
CreateError: Failed to create profile. Please try again.
109109
InvalidVoucherNumber: Client ID should be six to eight digits or letters.
110110
MissingVoucherNumber: Enter a client ID to create a profile.
111-
Name: Name of head of household
111+
Name: Your full name
112112
Search: Search
113113
SelectError: Failed to set profile. Please try again.
114114
NoResults: Profile not found. Create one now?
@@ -121,7 +121,7 @@ Profile:
121121
ByCar: Car
122122
ByTransit: Transit
123123
ByTransitExplanation: Search results will include subway and local bus.
124-
ChooseTravelMode: Will travel by
124+
ChooseTravelMode: How will you most often get to the above addresses?
125125
DeleteAddress: Delete this address
126126
DeletePrimaryAddressError: Cannot delete primary destination. Set another as the primary first.
127127
Cancel: Cancel
@@ -135,12 +135,12 @@ Profile:
135135
DeleteProfileError: Failed to delete profile. Please try again.
136136
Destinations: Where do you go most frequently (besides your home)?
137137
ImportanceAccessibility: Commute time
138-
ImportanceHeading: How important are these factors when choosing a home?
138+
ImportanceHeading: How important are the factors below when choosing a place to live?
139139
ImportanceSchools: School quality
140140
ImportanceViolentCrime: Public safety
141141
Primary: Primary
142142
Purpose: Purpose
143-
Rooms: Number of bedrooms in voucher
143+
Rooms: Number of bedrooms on your voucher
144144
Go: Save profile
145145
NameRequired: Please enter a name for the head of household.
146146
SaveError: Failed to save profile. Please try again.

taui/neighborhood_bounds.json

+50-50
Large diffs are not rendered by default.

taui/neighborhoods.json

+236-236
Large diffs are not rendered by default.

taui/package.json

+3-3
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,8 @@
5454
"lodash": "~4.17.15",
5555
"logrocket": "^1.0.6",
5656
"logrocket-react": "~4.0.1",
57-
"react": "~16.12.0",
58-
"react-dom": "~16.12.0",
57+
"react": "~16.13.0",
58+
"react-dom": "~16.13.0",
5959
"react-ga": "~2.7.0",
6060
"react-leaflet": "~1.9.1",
6161
"react-leaflet-vectorgrid": "~2.2.1",
@@ -74,7 +74,7 @@
7474
"devDependencies": {
7575
"core-js": "~2.6.10",
7676
"mastarm": "https://github.com/azavea/mastarm.git#dev",
77-
"semantic-release": "^15.13.31",
77+
"semantic-release": "^17.0.4",
7878
"stylelint": "^9.6.0",
7979
"stylelint-azavea": "https://github.com/azavea/stylelint-azavea#develop"
8080
},

taui/src/components/edit-profile.js

+11-11
Original file line numberDiff line numberDiff line change
@@ -738,6 +738,17 @@ export default class EditProfile extends PureComponent<Props> {
738738
rooms={rooms}
739739
changeField={changeField} />
740740
</div>
741+
<DestinationsList
742+
addAddress={addAddress}
743+
deleteAddress={deleteAddress}
744+
destinations={destinations}
745+
editAddress={editAddress}
746+
geocode={geocode}
747+
reverseGeocode={reverseGeocode}
748+
setGeocodeLocation={setGeocodeLocation}
749+
setPrimaryAddress={setPrimaryAddress}
750+
TripPurposeOptions={TripPurposeOptions}
751+
/>
741752
<div className='account-profile__field'>
742753
<div
743754
className='account-profile__label'
@@ -796,17 +807,6 @@ export default class EditProfile extends PureComponent<Props> {
796807
: message('Profile.ByTransitExplanation')}
797808
</div>}
798809
</div>
799-
<DestinationsList
800-
addAddress={addAddress}
801-
deleteAddress={deleteAddress}
802-
destinations={destinations}
803-
editAddress={editAddress}
804-
geocode={geocode}
805-
reverseGeocode={reverseGeocode}
806-
setGeocodeLocation={setGeocodeLocation}
807-
setPrimaryAddress={setPrimaryAddress}
808-
TripPurposeOptions={TripPurposeOptions}
809-
/>
810810
<div className='account-profile__importance-options'>
811811
<h3 className='account-profile__label'>
812812
{message('Profile.ImportanceHeading')}

taui/src/components/neighborhood-details.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -169,10 +169,10 @@ export default class NeighborhoodDetails extends PureComponent<Props> {
169169
<div className='neighborhood-details__links'>
170170
<a
171171
className='neighborhood-details__link'
172-
href='https://www.masshousing.com/portal/server.pt/community/rental_housing/240/looking_for_an_affordable_apartment_'
172+
href='https://www.metrohousingboston.org/apartment-listings/'
173173
target='_blank'
174174
>
175-
{message('NeighborhoodDetails.MassHousingLink')}
175+
{message('NeighborhoodDetails.MetroHousingLink')}
176176
</a>
177177
<a
178178
className='neighborhood-details__link'

taui/src/selectors/neighborhoods-sorted-with-routes.js

+58-29
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,17 @@ const MAX_DISTANCE = 130000
2929
const MAX_TRAVEL_TIME = 120
3030
const MIN_QUINTILE = 1
3131
const MAX_QUINTILE = 5
32+
// stored profile importance is offset by one from MAX_IMPORTANCE
33+
const PROFILE_MAX_IMPORTANCE = MAX_IMPORTANCE - 1
3234

3335
// default to worst, if unknown
3436
const DEFAULT_EDUCATION_QUINTILE = 5
3537
const DEFAULT_CRIME_QUINTILE = 5
3638

3739
// extra constant weighting always given to travel time over the other two factors
38-
const EXTRA_ACCESS_WEIGHT = 1
40+
const EXTRA_ACCESS_WEIGHT = 2
3941

42+
/* eslint complexity: 0 */
4043
export default createSelector(
4144
selectNeighborhoodRoutes,
4245
neighborhoodTravelTimes,
@@ -64,63 +67,89 @@ export default createSelector(
6467
accessibilityImportance = crimeImportance = schoolsImportance = 1
6568
}
6669

67-
// Give accessibility (travel time) extra weighting
70+
if (accessibilityImportance === PROFILE_MAX_IMPORTANCE) {
71+
// if set to very important, add more extra weight to travel time
72+
accessibilityImportance += 1
73+
}
74+
75+
// Alwasy give accessibility (travel time) some extra weighting
6876
accessibilityImportance += EXTRA_ACCESS_WEIGHT
6977

7078
const totalImportance = accessibilityImportance + crimeImportance + schoolsImportance
7179

72-
let accessibilityPercent = accessibilityImportance / totalImportance
73-
let crimePercent = crimeImportance / totalImportance
74-
let schoolPercent = schoolsImportance / totalImportance
75-
7680
const neighborhoodsWithRoutes = filter(neighborhoods.features.map((n, index) => {
81+
let accessibilityPercent = accessibilityImportance / totalImportance
82+
let crimePercent = crimeImportance / totalImportance
83+
let schoolPercent = schoolsImportance / totalImportance
84+
7785
const properties: NeighborhoodProperties = n.properties
7886
const route = neighborhoodRoutes[index]
7987
const segments = useTransit ? route.routeSegments : []
8088
const time = useTransit ? travelTimes[index] : distanceTime(origin, n)
81-
82-
// Map weighting values to percentages
83-
8489
// Routable neighborhoods outside the max travel time window will be filtered out.
8590
// Smaller travel time is better; larger timeWeight is better (reverse range).
8691
const timeWeight = time < MAX_TRAVEL_TIME ? scale(time, 0, MAX_TRAVEL_TIME, 1, 0) : 1
87-
8892
// Weight schools either by percentile binned into quarters if given max importance,
8993
// or otherwise weight by quintile.
9094
let educationWeight
91-
if (schoolsImportance === (MAX_IMPORTANCE - 1)) {
92-
// Group percentile ranking into quarters instead of using quintiles
93-
// if the importance of schools is the max importance.
95+
if (schoolsImportance === PROFILE_MAX_IMPORTANCE) {
96+
// "very important": instead of quintiles, group percentile ranking into quarters
9497
const edPercent = properties.education_percentile
9598
? properties.education_percentile
9699
: (DEFAULT_EDUCATION_QUINTILE - 1) * 20
97-
const edPercentQuarter = Math.round(scale(edPercent, 0, 100, 3, 0))
100+
let edPercentQuarter = Math.round(scale(edPercent, 0, 100, 3, 0))
101+
// Treat all schools not in the top quarter as being in the bottom quarter
102+
// to strongly prioritize the top quarter
103+
if (edPercentQuarter > 0) {
104+
edPercentQuarter = 3
105+
}
98106
educationWeight = scale(edPercentQuarter, 0, 3, 1, 0)
99-
} else {
100-
// Use quintiles if the importance of schools is anything less than the max importance.
101-
const educationQuintile = properties.education_percentile_quintile
107+
} else if (schoolsImportance > 0) {
108+
// For "somewhat important", prioritize quintile 2 and below
109+
// For "important", quintile 3 and below (lower is better)
110+
const prioritizeQuintile = schoolsImportance === 1 ? 2 : 3
111+
let educationQuintile = properties.education_percentile_quintile
102112
? properties.education_percentile_quintile
103113
: DEFAULT_EDUCATION_QUINTILE
104-
114+
// Treat all quintiles above the maximum to prioritize as being in the worst quintile
115+
if (educationQuintile > prioritizeQuintile) {
116+
educationQuintile = MAX_QUINTILE
117+
}
105118
// Lowest education quintile is best (reverse range).
106119
educationWeight = scale(educationQuintile, MIN_QUINTILE, MAX_QUINTILE, 1, 0)
120+
} else {
121+
educationWeight = 0 // Not important
107122
}
108-
let crimeQuintile = properties.violentcrime_quintile
109-
? properties.violentcrime_quintile : DEFAULT_CRIME_QUINTILE
110-
// Treat lowest two (safest) violent crime quintiles equally
111-
if (crimeQuintile === 2) {
112-
crimeQuintile = 1
113-
}
114-
// Lowest crime quintile is best (reverse range).
115-
const crimeWeight = scale(crimeQuintile, MIN_QUINTILE, MAX_QUINTILE, 1, 0)
116-
123+
let crimeWeight = 0
117124
// Handle missing values (zero in spreadsheet) by re-assigning crime weight
118-
// evenly to the other two factors
119-
if (properties.violentcrime_quintile === 0) {
125+
// evenly to the other two factors. Also do so if crime set as unimportant.
126+
if (properties.violentcrime_quintile === 0 || crimeImportance === 0) {
120127
const halfCrimePercent = crimePercent / 2
121128
schoolPercent += halfCrimePercent
122129
accessibilityPercent += halfCrimePercent
123130
crimePercent = 0
131+
} else {
132+
let crimeQuintile = properties.violentcrime_quintile
133+
? properties.violentcrime_quintile : DEFAULT_CRIME_QUINTILE
134+
// Treat lowest two (safest) violent crime quintiles equally
135+
if (crimeQuintile === 2) {
136+
crimeQuintile = 1
137+
}
138+
if (crimeImportance === 1 && crimeQuintile < 5) {
139+
// somewhat important; treat all but worst quintile the same
140+
crimeQuintile = 1
141+
} else if (crimeImportance === 2 && crimeQuintile < 4) {
142+
// "important"; treat all but worst two quintiles the same
143+
crimeQuintile = 1
144+
} else if (crimeImportance === PROFILE_MAX_IMPORTANCE && crimeQuintile > 3) {
145+
// "very important"; push results for worst two quintiles to bottom
146+
// by reassigning weights for those quintiles to be 90% crime
147+
crimePercent = 0.9
148+
schoolPercent /= 10
149+
accessibilityPercent /= 10
150+
}
151+
// Lowest crime quintile is best (reverse range).
152+
crimeWeight = scale(crimeQuintile, MIN_QUINTILE, MAX_QUINTILE, 1, 0)
124153
}
125154

126155
// Calculate weighted overall score from the percentages. Larger score is better.

0 commit comments

Comments
 (0)