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) }