415 lines
9.1 KiB
JavaScript
415 lines
9.1 KiB
JavaScript
import {markSeen} from './api'
|
|
import {defaultContactMessage, listingUrl} from './helpers'
|
|
|
|
const setMaxPrice = ({type, action}, component) => {
|
|
const maxPrice = parseFloat(action.maxPrice)
|
|
component.setState({
|
|
page: 0,
|
|
filters: {
|
|
...component.state.filters,
|
|
maxPrice: isNaN(maxPrice) ? undefined : maxPrice,
|
|
priceDirty: true
|
|
}
|
|
})
|
|
}
|
|
|
|
const setMinPrice = ({type, action}, component) => {
|
|
const minPrice = parseFloat(action.minPrice)
|
|
component.setState({
|
|
page: 0,
|
|
filters: {
|
|
...component.state.filters,
|
|
minPrice: isNaN(minPrice) ? undefined : minPrice,
|
|
priceDirty: true
|
|
}
|
|
})
|
|
}
|
|
|
|
const setMinSize = ({type, action}, component) => {
|
|
const minSize = parseFloat(action.minSize)
|
|
component.setState({
|
|
page: 0,
|
|
filters: {
|
|
...component.state.filters,
|
|
minSize: isNaN(minSize) ? undefined : minSize,
|
|
sizeDirty: true
|
|
}
|
|
})
|
|
}
|
|
|
|
const setMaxSize = ({type, action}, component) => {
|
|
const maxSize = parseFloat(action.maxSize)
|
|
component.setState({
|
|
page: 0,
|
|
filters: {
|
|
...component.state.filters,
|
|
maxSize: isNaN(maxSize) ? undefined : maxSize,
|
|
sizeDirty: true
|
|
}
|
|
})
|
|
}
|
|
|
|
const getScrollElem = (component) => {
|
|
const {mobileView} = component.state
|
|
const scrollElem = mobileView === 'LIST' ?
|
|
document.querySelector('.map-list-view') : document.querySelector('.right-content')
|
|
|
|
return scrollElem
|
|
}
|
|
|
|
const viewListingDetails = ({type, action}, component) => {
|
|
const scrollElem = getScrollElem(component)
|
|
component.savedScrollTop = scrollElem.scrollTop
|
|
|
|
component.setState(
|
|
{
|
|
listingDetails: true,
|
|
listingId: action.id,
|
|
descriptionExpanded: false,
|
|
imageIndex: 0,
|
|
listing: action.listing
|
|
},
|
|
() => {
|
|
markSeen(action.id)
|
|
const m = component.findMarker(action.id)
|
|
if (m) {
|
|
m.marker.setIcon(component.selectedMarkerIcon())
|
|
}
|
|
|
|
scrollElem.scrollTop = 0
|
|
}
|
|
)
|
|
}
|
|
|
|
const listingsLoaded = ({type, action}, component) => {
|
|
const currentListings = new Map()
|
|
|
|
for (const listing of action.listings) {
|
|
currentListings.set(listing._id, listing)
|
|
}
|
|
|
|
component.setState({
|
|
listings: action.more
|
|
? new Map([...component.state.listings, ...currentListings])
|
|
: currentListings,
|
|
loadingMore: false,
|
|
totalCount: action.totalCount
|
|
})
|
|
}
|
|
|
|
const pinsLoaded = ({type, action}, component) => {
|
|
component.setState({}, () => {
|
|
component.markers = action.newMarkers
|
|
})
|
|
}
|
|
|
|
const expandDescription = ({type, action}, component) => {
|
|
component.setState({
|
|
descriptionExpanded: true
|
|
})
|
|
}
|
|
|
|
const prevImage = ({type, action}, component) => {
|
|
const index = component.state.imageIndex
|
|
if (index > 0) {
|
|
component.setState({
|
|
imageIndex: index - 1
|
|
})
|
|
}
|
|
}
|
|
|
|
const nextImage = ({type, action}, component) => {
|
|
const index = component.state.imageIndex
|
|
component.setState({
|
|
imageIndex: index + 1
|
|
})
|
|
}
|
|
|
|
const viewImage = ({type, action}, component) => {
|
|
component.setState({
|
|
imageIndex: action.index
|
|
})
|
|
}
|
|
|
|
const searchPlaceChanged = ({type, action}, component) => {
|
|
component.setState({
|
|
listingDetails: false,
|
|
listingId: null,
|
|
page: 0
|
|
})
|
|
}
|
|
|
|
const setRooms = ({type, action}, component) => {
|
|
const prevRooms = component.state.filters.rooms || {}
|
|
|
|
component.setState(
|
|
{
|
|
page: 0,
|
|
filters: {
|
|
...component.state.filters,
|
|
rooms: {
|
|
...prevRooms,
|
|
[action.rooms]: !prevRooms[action.rooms]
|
|
}
|
|
}
|
|
},
|
|
() => {
|
|
component.refreshListings()
|
|
}
|
|
)
|
|
}
|
|
|
|
const updateSearch = ({type, action}, component) => {
|
|
component.setState(
|
|
{
|
|
filters: {
|
|
...component.state.filters,
|
|
sizeDirty: false,
|
|
priceDirty: false
|
|
}
|
|
},
|
|
() => {
|
|
component.refreshListings()
|
|
}
|
|
)
|
|
}
|
|
|
|
const setCategory = ({type, action}, component) => {
|
|
const prevCategory = component.state.filters.category || {}
|
|
|
|
component.setState(
|
|
{
|
|
page: 0,
|
|
filters: {
|
|
...component.state.filters,
|
|
category: {
|
|
...prevCategory,
|
|
[action.category]: !prevCategory[action.category]
|
|
}
|
|
}
|
|
},
|
|
() => {
|
|
component.refreshListings()
|
|
}
|
|
)
|
|
}
|
|
|
|
const onListingMouseOver = ({type, action}, component) => {
|
|
const marker = component.findMarker(action.id)
|
|
if (marker) {
|
|
const seen = component.isSeen(action.id)
|
|
if (seen) {
|
|
marker.marker.setIcon(component.visitedHoveredMarkerIcon())
|
|
} else {
|
|
marker.marker.setIcon(component.hoveredMarkerIcon())
|
|
}
|
|
|
|
marker.marker.setAnimation(google.maps.Animation.BOUNCE)
|
|
setTimeout(
|
|
() => {
|
|
marker.marker.setAnimation(null)
|
|
|
|
if (seen) {
|
|
marker.marker.setIcon(component.visitedMarkerIcon())
|
|
} else {
|
|
marker.marker.setIcon(component.defaultMarkerIcon())
|
|
}
|
|
},
|
|
710
|
|
)
|
|
}
|
|
}
|
|
|
|
const backToResults = ({type, action}, component) => {
|
|
const prevSelected = component.findMarker(component.state.listingId)
|
|
component.setState(
|
|
{
|
|
listingId: null,
|
|
listingDetails: false
|
|
},
|
|
() => {
|
|
if (prevSelected) {
|
|
prevSelected.marker.setIcon(component.visitedMarkerIcon())
|
|
}
|
|
|
|
//const scrollElem = document.querySelector('.right-content')
|
|
const scrollElem = getScrollElem(component)
|
|
scrollElem.scrollTop = component.savedScrollTop
|
|
}
|
|
)
|
|
}
|
|
|
|
const loadMoreListings = ({type, action}, component) => {
|
|
const currentPage = component.state.page
|
|
if (currentPage * 20 < component.state.totalCount) {
|
|
component.setState(
|
|
{
|
|
loadingMore: true,
|
|
page: currentPage + 1
|
|
},
|
|
() => {
|
|
component.refreshListings(true)
|
|
}
|
|
)
|
|
}
|
|
}
|
|
|
|
const mapIdle = ({type, action}, component) => {
|
|
component.setState(
|
|
{
|
|
page: 0
|
|
},
|
|
() => {
|
|
const scrollElem = getScrollElem(component)
|
|
//const scrollElem = document.querySelector('.right-content')
|
|
scrollElem.scrollTop = 0
|
|
component.refreshListings()
|
|
}
|
|
)
|
|
}
|
|
|
|
const sortChange = ({type, action}, component) => {
|
|
component.setState(
|
|
{
|
|
sort: action.sort,
|
|
page: 0
|
|
},
|
|
() => {
|
|
component.refreshListings()
|
|
}
|
|
)
|
|
}
|
|
|
|
const updateRoute = ({type, action}, component) => {
|
|
component.router.update(action)
|
|
}
|
|
|
|
const openContact = ({type, action}, component) => {
|
|
component.setState({
|
|
contactFormOpen: true,
|
|
contact: {
|
|
...component.state.contact,
|
|
message: defaultContactMessage(listingUrl(component.state.listingId)),
|
|
emailInvalid: false,
|
|
nameInvalid: false,
|
|
name: '',
|
|
email: '',
|
|
phone: ''
|
|
}
|
|
})
|
|
}
|
|
|
|
const closeContact = ({type, action}, component) => {
|
|
component.setState({
|
|
contactFormOpen: false
|
|
})
|
|
}
|
|
|
|
const updateContactInfo = ({type, action}, component) => {
|
|
|
|
let nameInvalid = component.state.contact.nameInvalid
|
|
let emailInvalid = component.state.contact.emailInvalid
|
|
|
|
if (action.field === 'name') {
|
|
nameInvalid = !action.value
|
|
}
|
|
|
|
if (action.field === 'email') {
|
|
emailInvalid = !action.value
|
|
}
|
|
|
|
component.setState({
|
|
contact: {
|
|
...component.state.contact,
|
|
[action.field]: action.value,
|
|
...{nameInvalid, emailInvalid}
|
|
}
|
|
})
|
|
}
|
|
|
|
const invalidContact = ({type, action}, component) => {
|
|
const {name, email} = component.state.contact
|
|
|
|
component.setState({
|
|
contact: {
|
|
...component.state.contact,
|
|
...{nameInvalid: !name, emailInvalid: !email}
|
|
}
|
|
})
|
|
}
|
|
|
|
const submitContactStart = ({type, action}, component) => {
|
|
component.setState({
|
|
contact: {
|
|
sending: true
|
|
}
|
|
})
|
|
}
|
|
|
|
const submitContactEnd = ({type, action}, component) => {
|
|
component.setState({
|
|
contactFormOpen: false,
|
|
contact: {
|
|
sending: false,
|
|
}
|
|
})
|
|
}
|
|
|
|
const mobileMapView = ({type, action}, component) => {
|
|
|
|
component.setState({
|
|
mobileView: 'MAP'
|
|
}, () => {
|
|
backToResults({type, action}, component)
|
|
})
|
|
}
|
|
|
|
const mobileListView = ({type, action}, component) => {
|
|
component.setState({
|
|
mobileView: 'LIST'
|
|
}, () => {
|
|
backToResults({type, action}, component)
|
|
})
|
|
}
|
|
|
|
const handlers = {
|
|
SET_MIN_PRICE: setMinPrice,
|
|
SET_MAX_PRICE: setMaxPrice,
|
|
SET_MIN_SIZE: setMinSize,
|
|
SET_MAX_SIZE: setMaxSize,
|
|
LISTINGS_LOADED: listingsLoaded,
|
|
EXPAND_DESCRIPTION: expandDescription,
|
|
PREV_IMAGE: prevImage,
|
|
NEXT_IMAGE: nextImage,
|
|
VIEW_IMAGE: viewImage,
|
|
SEARCH_PLACE_CHANGED: searchPlaceChanged,
|
|
SET_ROOMS: setRooms,
|
|
VIEW_LISTING_DETAILS: viewListingDetails,
|
|
UPDATE_SEARCH: updateSearch,
|
|
SET_CATEGORY: setCategory,
|
|
ON_LISTING_MOUSE_OVER: onListingMouseOver,
|
|
BACK_TO_RESULTS: backToResults,
|
|
LOAD_MORE_LISTINGS: loadMoreListings,
|
|
MAP_IDLE: mapIdle,
|
|
PINS_LOADED: pinsLoaded,
|
|
SORT_CHANGE: sortChange,
|
|
UPDATE_ROUTE: updateRoute,
|
|
OPEN_CONTACT: openContact,
|
|
CLOSE_CONTACT: closeContact,
|
|
UPDATE_CONTACT_INFO: updateContactInfo,
|
|
SUBMIT_CONTACT_START: submitContactStart,
|
|
SUBMIT_CONTACT_END: submitContactEnd,
|
|
INVALID_CONTACT: invalidContact,
|
|
MOBILE_MAP_VIEW: mobileMapView,
|
|
MOBILE_LIST_VIEW: mobileListView
|
|
}
|
|
|
|
export const handleMessage = ({type, action}, component) => {
|
|
if (!handlers[type]) {
|
|
throw new `Unhandled message: ${type}`()
|
|
}
|
|
|
|
console.log(type, action);
|
|
return handlers[type]({type, action}, component)
|
|
}
|