Skip to content
This repository was archived by the owner on Sep 20, 2023. It is now read-only.

Listing location#3797

Merged
sparrowDom merged 28 commits into
masterfrom
sparrowDom/listingLocation
Oct 30, 2019
Merged

Listing location#3797
sparrowDom merged 28 commits into
masterfrom
sparrowDom/listingLocation

Conversation

@sparrowDom

@sparrowDom sparrowDom commented Oct 28, 2019

Copy link
Copy Markdown
Member

Description:

Adds listing location functionality to For Rent / Housing listing types:

  • new versions of mobile apps need to be published for the current location feature to work
  • map also displayed on listing detail

Important (!):

  • before deploying add developer rate limit restricted api key to codebase
  • add a non restricted api key to envKey: GOOGLE_MAPS_API_KEY

Checklist:

@sparrowDom sparrowDom changed the title LIsting location Listing location Oct 29, 2019

@shahthepro shahthepro left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Great PR @sparrowDom. A couple of comments inline.

/>
)
const FractionalListing = props => {
const isHausing = props.listing.subCategory === 'schema.housing'

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

nit: isHousing

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

heh thanks 👍 fixed

}

steps.push({
step: isHausing ? 6 : 4,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

nit: Instead of the conditional check, you could perhaps have a variable counter that starts with 1 and replace the step values with counter++ in all steps. Would be less confusing.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Yup agreed, your idea is much cleaner

Comment on lines +23 to +38
const locationInput = () => {
let className = 'px-3'
if (formLocationError) {
className += ' is-invalid'
}

return {
value: formLocationValue,
className,
name: 'location',
onChange: e => {
setFormLocationValue(e.target.value)
setFormLocationError(null)
}
}
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Does this have to be a function? I see this being called once once. Calling a function each time a component renders seems like a unwanted (still negligible) overhead.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

It needs to be a function so when the formLocationError state changes, it adds the error class to the html node.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I might be wrong here. But changing that function definition (and it's call in the next line) to something like should work right?
Or am I missing something here?

    let className = 'px-3'
    if (formLocationError) {
      className += ' is-invalid'
    }

    const input = {
      value: formLocationValue,
      className,
      name: 'location',
      onChange: e => {
        setFormLocationValue(e.target.value)
        setFormLocationError(null)
      }
    }

The function gets called all the time and it only populates an object that inside input, AFAICT. Why not populate the object directly instead of a function call?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Ah yes, I don't know what I was thinking. You are right thanks!

Comment on lines +46 to +55
const saveLocation = (latitude, longitude) => {
listing.exactLocation = {
latitude,
longitude
}
onChange({ ...listing })
setFetchingLocation(false)
setCurrentLocationError(null)
setRedirect(true)
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Can probably use useCallback for these functions.

Ref: useCallback

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Yup good point 👍

Comment on lines +57 to +251
const fetchCurrentLocation = async e => {
e.preventDefault()
setFetchingLocation(true)
setCurrentLocationError(null)

if (window.webViewBridge) {
if (window.webViewBridge.send) {
const onSuccess = data => {
if (data.locationAvailable) {
saveLocation(
data.position.coords.latitude,
data.position.coords.longitude
)
} else {
setCurrentLocationError(data.error)
}
}

window.webViewBridge.send('getCurrentPosition', null, onSuccess)
}
} else if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(
position => {
saveLocation(position.coords.latitude, position.coords.longitude)
},
error => {
setCurrentLocationError(error.message)
setFetchingLocation(false)
}
)
}
}

const renderExistingLocationMap = () => {
let containerStyle = {
height: '400px'
}
if (isMobile) {
containerStyle = {
...containerStyle,
marginLeft: '-30px',
marginRight: '-30px'
}
}

return (
<LocationMap
googleMapURL={`https://maps.googleapis.com/maps/api/js?v=3.exp&libraries=geometry,drawing,places&key=${process
.env.GOOGLE_MAPS_API_KEY || DEFAULT_GOOGLE_MAPS_API_KEY}`}
loadingElement={<div style={{ height: '100%' }} />}
containerElement={
<div className="mt-3 mt-md-4" style={containerStyle} />
}
mapElement={<div style={{ height: '100%' }} />}
defaultCenter={{
latitude: listing.location.latitude,
longitude: listing.location.longitude
}}
circleOptions={{
latitude: listing.location.latitude,
longitude: listing.location.longitude,
radius: listing.location.accuracyInMeters
}}
readonly={true}
/>
)
}

const renderExistingLocation = () => {
return (
<>
<h1>
<Link to={prev} className="back d-md-none" />
<fbt desc="createListing.listingLocation">Listing Location</fbt>
</h1>
<div className="step-description mb-0">
<fbt desc="createListing.existingListingLocation">
This is the location currently set on the listing.
</fbt>
</div>
<div className="row location-obfuscation-map">
<div className="listing-step">
<div className="col-md-8 px-0 px-md-3">
<div className="form-group">{renderExistingLocationMap()}</div>
</div>
<div className="actions mt-auto">
<button
className="btn btn-outline-primary mb-3"
onClick={() => {
delete listing.location
setForceEditLocation(true)
}}
>
<fbt desc="editListing.editLocation">Edit location</fbt>
</button>
<button
className="btn btn-primary"
onClick={() => {
listing.skipLocationObfuscationForward = true
onChange({ ...listing })
setRedirect(true)
}}
>
<fbt desc="editListing.useCurrentLocation">
Use current location
</fbt>
</button>
</div>
</div>
</div>
</>
)
}

const renderInputLocation = () => {
return (
<>
<h1>
<Link to={prev} className="back d-md-none" />
<fbt desc="createListing.listingLocation">Listing Location</fbt>
</h1>
<div className="step-description mb-0 px-4 px-md-0">
<fbt desc="createListing.whereIsListingLocated">
Where is your listing located?
</fbt>
</div>
<div className="row location">
<div className="col-md-8">
<form
className="listing-step"
onSubmit={e => {
e.preventDefault()
Geocode.setApiKey(
process.env.GOOGLE_MAPS_API_KEY || DEFAULT_GOOGLE_MAPS_API_KEY
)
Geocode.enableDebug()
listing.locationAddress = formLocationValue
Geocode.fromAddress(formLocationValue).then(
response => {
const { lat, lng } = response.results[0].geometry.location
saveLocation(lat, lng)
},
error => {
setFormLocationError(error.message)
console.error(error.message)
}
)
}}
>
<div className="form-group">
<input
{...input}
placeholder={fbt(
'123 Main St.',
'createListing.locationPlaceholder'
)}
/>
<button
className={`btn btn-outline-primary btn-location d-flex align-items-center justify-content-center`}
onClick={fetchCurrentLocation}
>
{!fetchingLocation && (
<>
<img className="mr-2" src="images/location-icon.svg" />
<div>
<fbt desc="createListing.useCurrentLocation">
Use current location
</fbt>
</div>
</>
)}
{fetchingLocation && (
<fbt desc="createListing.fetchingLocation">
Fetching location
</fbt>
)}
</button>
{currentLocationError && (
<div className="invalid-feedback d-flex justify-content-center mt-3">
{currentLocationError}
</div>
)}
</div>

<div className="actions mt-auto">
<button type="submit" className="btn btn-primary">
<fbt desc="next">Next</fbt>
</button>
</div>
</form>
</div>
</div>
</>
)
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Same comment as above. Could use useCallback or may be break down into smaller components.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Yup have used useCallback thanks!

}

if (readonly && circleOptions && circleOptions.radius) {
// 30 is minRaidius. This is a reverse function of getCircleRadius in ListingObfscation

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Spelling

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

2 typos in 1 line -.- thanks!

Comment thread mobile/ios/OriginMarketplace/Info.plist Outdated
<string>We will not be using the location</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>We will not be using the location</string>
<string>We would like to determine listing&apos;s location. </string>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Maybe a bit more verbose since Apple has been so annoying about these:

We would like to use your location to add location data to any listings that you create

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

That sounds better thanks!

@tomlinton tomlinton left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Mobile looks good from my end, will test it out with the new release! Great work @sparrowDom!

@sparrowDom
sparrowDom merged commit da7e4fb into master Oct 30, 2019
@sparrowDom
sparrowDom deleted the sparrowDom/listingLocation branch October 30, 2019 15:54
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants