UNPKG

@gfsdeliver/gfs-droppoint

Version:

The gfs-droppoint widget is used to show the available droppoints on the map

759 lines (630 loc) 27.3 kB
import { PolymerElement, html } from '@polymer/polymer/polymer-element.js'; import '@polymer/paper-spinner/paper-spinner.js'; import '@polymer/iron-ajax/iron-ajax.js'; import '@gfsdeliver/gfs-toast/gfs-toast.js'; import '@gfsdeliver/gfs-button/gfs-button.js'; import './gfs-droppoint-styles'; export class GfsDroppointMap extends PolymerElement { static get template() { return html` <style include="gfs-droppoint-styles"> :host { width: 100%; display: block; position: relative; } </style> <iron-ajax id="getDroppointInfo" method="GET" handle-as="json" content-type="application/json" on-response="_handleDroppointInfoResponse" on-error="_handleError" timeout="10000"> </iron-ajax> <iron-ajax id="ajaxGetPostcode" method="GET" handle-as="json" content-type="application/json" on-response="_handleGetPostcodeResponse" on-error="_handleError" timeout="10000"> </iron-ajax> <iron-ajax id="getOpeningHours" method="GET" handle-as="json" content-type="application/json" on-response="_handleOpeningHoursResponse" on-error="_handleError" timeout="10000"> </iron-ajax> <iron-ajax id="ajaxPostPostcode" method="POST" handle-as="json" content-type="application/json" on-response="_handlePostPostcodeResponse"> </iron-ajax> <div id="dropPointLocation"> <div id="droppointMap" style="height: {{mapHeight}}px"></div> </div> <div class="hidden"> <div id="droppointInfoWindow"> <div id="loader"> <paper-spinner active></paper-spinner> </div> <div class$="{{isVisible}} carrier-icon"> <img src="{{carrierIcon}}" /> </div> <div id="dp-address"> <div class="store-name-map"> {{droppointData.title}} </div> <div class="store-address-wrap"> <iron-icon icon="maps:my-location"></iron-icon> <dom-repeat items="{{droppointData.address}}"> <template> <div class="store-address-map"> {{item}}, </div> </template> </dom-repeat> <div class="store-location-map"> {{droppointData.town}}, {{droppointData.zip}} </div> </div> </div> <gfs-button class="default choose-droppoint map-btn" on-click="_getOpeningHours">View Opening Times</gfs-button> <div class="weekCollection"> <template is="dom-repeat" items="{{_weekCollection}}"> <div class="wrap-opening-hours"> <div class="dp-day-name"> <ul> <li>{{item.dayOfWeek}}</li> </ul> </div> <div class="dp-day-time-slots"> <ul> <template is="dom-repeat" items="{{item.slots}}"> <li class="dp-day-time-slot">{{item.fromTime}} - {{item.toTime}}</li> </template> </ul> </div> </div> </template> </div> </div> </div> <div id="dropPointDetails" class$="{{_droppointDetailsClass}}"> <div id="droppoint_overlay" style="height: {{mapHeight}}px; display: block"> <div id="droppoint_overlay_close" on-click="_hideDroppointDetails"> <img src="//gfswidgetcdn.azurewebsites.net/images/widgets/x.png" alt="close" /> </div> <gfs-droppoint id="overlay-droppoint" checkout-token="[[checkoutToken]]" droppoint-data="{{_selectedDroppoint}}" checkout-uri="{{checkoutUri}}" container-class="overlay" show-opening-hours></gfs-droppoint> </div> </div> <gfs-toast error id="notificationError"></gfs-toast> `; } static get properties() { return { token: String, countryCode: String, postCode: String, carrierIcon: String, droppointData: { type: Object, value: {} }, /* Array of carriers to display drop points for */ carriers: { type: Array, value: function() { return [] } }, searchResultText: { type: String, value: "Last searched postcode:" }, map: Object, mapHeight: { type: String, value: 500 }, startingZoomLevel: { type: Number, value: 14 }, endingZoomLevel: { type: Number, value: 4 }, storeMapIcon: String, checkoutToken: { type: String, value: "" }, checkoutRequest: String, _infoWindow: Object, _droppointDetailsClass: { type: String, value: "hidden" }, _markers: { type: Array, value: [] }, _droppointMarkers: { type: Array, value: [] }, _storeMarkers: { type: Array, value: [] }, checkoutUri: String, checkoutToken: String, } } static get observers() { return [ ] } connectedCallback() { super.connectedCallback(); window.addEventListener('newDroppoints', this._loadMarkers.bind(this)); window.addEventListener('droppoint-selected', this._droppointSelected.bind(this)); window.addEventListener('droppoint-unselected', this._droppointUnSelected.bind(this)); window.addEventListener('clearMarkers', this._clearMarkers.bind(this)); window.addEventListener('loadDroppointMarkers', this._loadMarkers.bind(this)); } disconnectedCallback() { super.disconnectedCallback(); window.removeEventListener('newDroppoints', this._loadMarkers.bind(this)); window.removeEventListener('droppoint-selected', this._droppointSelected.bind(this)); window.removeEventListener('droppoint-unselected', this._droppointUnSelected.bind(this)); window.removeEventListener('clearMarkers', this._clearMarkers.bind(this)); window.removeEventListener('loadDroppointMarkers', this._loadMarkers.bind(this)); } ready() { super.ready(); this.buildDroppointMap(); } buildDroppointMap() { var elem = this; var mapOptions = { zoom: this.startingZoomLevel, minZoom: this.startingZoomLevel - this.endingZoomLevel, // type of map (ROADMAP, SATELLITE, TERRAIN, HYBRID) mapTypeId: google.maps.MapTypeId.TERRAIN, streetViewControl: false, disableDefaultUI: false, mapTypeControl: true, mapTypeControlOptions: { style: google.maps.MapTypeControlStyle.DROPDOWN_MENU, position: google.maps.ControlPosition.TOP_RIGHT, }, zoomControlOptions: { style: google.maps.ZoomControlStyle.SMALL, position: google.maps.ControlPosition.TOP_RIGHT }, // remove points of interest from the map so as not to interfere styles: [{ "featureType": "poi", "elementType": "labels", "stylers": [{ "visibility": "off" }] }] }; this._infoWindow = new google.maps.InfoWindow({ content: elem.$.droppointInfoWindow }); this._map = new google.maps.Map(this.shadowRoot.querySelector('#droppointMap'), mapOptions); const geocoder = new google.maps.Geocoder(); geocoder.geocode({ componentRestrictions: { country: this.countryCode, postalCode: this.postCode } }, (results, status) => { if (status == google.maps.GeocoderStatus.OK) { let homeMarkerConfig = { position: results[0].geometry.location, // map: self._map, animation: google.maps.Animation.DROP, title: 'Home', html: 'Home', icon: this._getHomeIcon() }; let marker = new google.maps.Marker(homeMarkerConfig); this._map.setCenter(homeMarkerConfig.position); marker.setMap(this._map); } else { console.log('Google Maps API ERROR - Geocode was not successful for the following reason: ' + status); this.$.notificationError.text = 'Google Maps API ERROR - Geocode was not successful for the following reason: ' + status; this.$.notificationError.duration = 5000; this.$.notificationError.open(); } }); } _getHomeIcon() { if (this.homeIcon) { return this.homeIcon; } else { return this.resolveUrl('//gfswidgetcdn.azurewebsites.net/images/widgets2.0/home.png'); } } _loadMarkers(checkoutData) { let _elem = this; let markers = checkoutData.detail.data; let isDroppoint = checkoutData.detail.droppoint; let isStore = checkoutData.detail.store; markers.forEach((pointItem) => { let getCountryCode = _elem.countryCode; pointItem.countryCode = _elem.countryCode; pointItem.isDroppoint = isDroppoint; pointItem.isStore = isStore; let markerConfig = { position: new google.maps.LatLng(pointItem.geo.lat, pointItem.geo.long), map: this._map, animation: google.maps.Animation.vn, title: pointItem.title, customData: pointItem, icon: isDroppoint ? this._droppointMapIco(getCountryCode) + '/' + pointItem.provider.toLowerCase() + '.png' : this._storeIcon(), zIndex: google.maps.Marker.MAX_ZINDEX + 1 }; let marker = new google.maps.Marker(markerConfig); isDroppoint ? this.push('_droppointMarkers', marker) : this.push('_storeMarkers', marker); marker.addListener('click', function(elem) { _elem._selectDroppoint(this, isDroppoint, isStore); const icon = isDroppoint ? _elem._droppointMapIco(getCountryCode) + '/' + pointItem.provider.toLowerCase() + '-selected.png' : _elem._storeIcon(); this.setIcon(icon); _elem._getDroppointsDetails(this.customData.id, isDroppoint); _elem._infoWindow.open(_elem._map, this); _elem._infoWindow.opened = true; _elem._map.panTo(this.customData.marker.getPosition()); _elem.set('_weekCollection', ""); _elem.$.loader.style.display = 'block'; }); // add a link to the marker to get to it from the droppoint, need to animate and centre the marker if selecting from list view pointItem.marker = marker; }); google.maps.event.addListener(this._map, 'click', () => { this._clearSelectedDroppoint(); }); google.maps.event.addListener(this._infoWindow,'closeclick', () => { this._unselectDroppoint(); }); } _droppointMapIco(countryCode) { var url = this.resolveUrl('//gfswidgetcdn.azurewebsites.net/images/widgets2.0/carriers/'); switch (countryCode) { case "DE": return url + 'DE'; case "FR": case "BE": case "ES": return url + 'FR'; default: return url + 'GB'; } } _droppointInfoWindowIco(countryCode, provider) { let url; if (provider === 'DPD') { provider = 'dpdpickup' } if (provider === 'dpdpickup' || provider === 'HERMES' || provider === 'DODDLE' || provider === 'COLLECT PLUS' || provider === 'INPOST') { url = this.resolveUrl('//gfswidgetcdn.azurewebsites.net/images/widgets/carriers'); switch(countryCode) { case "DE": return url + '/DE/' + provider.toLowerCase() + '.png'; case "FR": case "BE": case "ES": return url + '/FR/' + provider.toLowerCase() + '.png'; default: return url + '/GB/' + provider.toLowerCase() + '.png'; } } } _selectDroppoint(marker, isDroppoint, isStore) { marker.customData.chosen = true; this._selectedDroppoint = marker.customData; this._hideDroppointDetails(); if (isDroppoint) { this._fire("droppoint-changed", marker.customData, isDroppoint, isStore); } else { this._fire("store-changed", marker.customData, isDroppoint, isStore); } } _unselectDroppoint() { if (this._selectedDroppoint) { this._selectedDroppoint.chosen = false; if (this._selectedDroppoint.isDroppoint) { let icon = this._droppointMapIco(this.countryCode) + '/' + this._selectedDroppoint.provider.toLowerCase() + '.png'; this._selectedDroppoint.marker.setIcon(icon) } this._fire("droppoint-changed", this._selectedDroppoint); if (this._currentMarker) { this._currentMarker.setAnimation(null); } if (this._infoWindow) { this._infoWindow.close(); this._infoWindow.opened = false; } } } _clearSelectedDroppoint() { if (this._selectedDroppoint) { this._selectedDroppoint.chosen = false; if (this._selectedDroppoint.isDroppoint) { let icon = this._droppointMapIco(this.countryCode) + '/' + this._selectedDroppoint.provider.toLowerCase() + '.png'; this._selectedDroppoint.marker.setIcon(icon) } if (this._currentMarker) { this._currentMarker.setAnimation(null); } if (this._infoWindow) { this._infoWindow.close(); this._infoWindow.opened = false; } this._fire("clear-selected-droppoint"); } } _droppointSelected(e) { let isDroppoint = e.detail.droppoint; let countryCode = e.detail.data.countryCode; let icon = isDroppoint ? this._droppointMapIco(countryCode) + '/' + e.detail.data.provider.toLowerCase() + '-selected.png' : this._storeIcon(); e.detail.data.marker.setIcon(icon); this._selectedDroppoint = e.detail.data; this.droppointData = e.detail.data; if (isDroppoint) { this.carrierIcon = this._droppointInfoWindowIco(e.detail.data.countryCode, e.detail.data.provider); this.isVisible = ""; } else { this.isVisible = "hidden"; } this._infoWindow.open(this._map, e.detail.data.marker); this._infoWindow.opened = true; this._weekCollection = null; } _droppointUnSelected(e) { let isDroppoint = e.detail.droppoint; let countryCode = e.detail.data.countryCode; let icon = isDroppoint ? this._droppointMapIco(countryCode) + '/' + e.detail.data.provider.toLowerCase() + '.png' : this._storeIcon(); e.detail.data.marker.setIcon(icon); } _searchPostcode(e, gfsCheckoutElem) { e.preventDefault(); const target = e.currentTarget; const elem = e.currentTarget.id; var ddSearchTerms = e.target.parentElement.parentElement.querySelector('#droppointAddress').value; const checkoutRequest = JSON.parse(atob(gfsCheckoutElem.checkoutRequest)); const postcode = checkoutRequest.order.delivery.destination.zip; if (postcode !== ddSearchTerms) { if (this.useDroppointsStores) { this.shadowRoot.querySelector('#toggleStoreOnMap').checked = false; this.shadowRoot.querySelector('#toggleDroppointsOnMap').checked = false; this._storeDetailsClass = "fade-out"; this._droppointDetailsClass = "fade-out"; } this._fire('hide-collectionInfo'); switch (elem) { case "droppointSubmit": return [ e.target.parentElement.parentElement.querySelector('#lastddPostcode').innerText = this.searchResultText + " " + ddSearchTerms, this._returnPostcode(ddSearchTerms, "dropPoint", target, gfsCheckoutElem), ddSearchTerms = "" ]; case "storeSubmit": return [ e.target.parentElement.parentElement.querySelector('#lastStorePostcode').innerText = "Last searched postcode: " + this.$.storeAddress.value, this._returnPostcode(this.$.storeAddress, "store", target, gfsCheckoutElem), this.$.storeAddress = "" ]; default: } } else { gfsCheckoutElem.shadowRoot.querySelectorAll('#mapLoader')[0].style.display = 'none'; } } _returnPostcode(postcode, deliveryType, target, gfsCheckoutElem) { var emptyPostcode = new RegExp(/^\s\s*/); var obj = {}; var detail = {}; if (postcode === "" || postcode.match(emptyPostcode)) { this.$.notificationError.text = "Please enter a valid postcode"; this.$.notificationError.fitInto = this.$.gfsMapCanvas; this.$.notificationError.duration = 5000; this.$.notificationError.open(); return; } if (!!this._droppointMarkers && deliveryType === 'dropPoint') { detail.data = "dropPointMap"; detail.droppoint = true; detail.store = false; obj.detail = detail; this._clearMarkers(obj); if (this.useDroppointsStores) { detail.data = "dropPointMap"; detail.droppoint = false; detail.store = true; obj.detail = detail; this._clearMarkers(obj); } } const geocoder = new google.maps.Geocoder(); geocoder.geocode({ componentRestrictions: { country: this.countryCode, postalCode: postcode } }, (results, status) => { if (status == google.maps.GeocoderStatus.OK) { var position = results[0].geometry.location; if (deliveryType === 'dropPoint') { this._map.setCenter(position); } else { this._storeMap.setCenter(position); } const checkoutRequest = JSON.parse(atob(gfsCheckoutElem.checkoutRequest)); checkoutRequest.order.delivery.destination.zip = postcode; gfsCheckoutElem.checkoutRequest = btoa(JSON.stringify(checkoutRequest)); } else { console.log('Google Maps API ERROR - Geocode was not successful for the following reason: ' + status); this.$.notificationError.text = "Postcode not found in " + this.countryCode; this.$.notificationError.classList.remove('fit-top'); this.$.notificationError.horizontalAlign = "left"; this.$.notificationError.verticalAlign = "top"; gfsCheckoutElem.shadowRoot.querySelectorAll('#mapLoader')[0].style.display = 'none'; const checkoutData = {} checkoutData.detail = {} if (deliveryType === 'dropPoint') { this.$.notificationError.fitInto = this.$.droppointMap; checkoutData.detail.droppoint = true; checkoutData.detail.store = false; checkoutData.detail.data = gfsCheckoutElem.dropPoints this._loadMarkers(checkoutData); } else { this.$.notificationError.fitInto = this.$.storeMapCanvas; checkoutData.detail.droppoint = false; checkoutData.detail.store = true; checkoutData.detail.data = gfsCheckoutElem.stores this._loadMarkers(checkoutData); } this.$.notificationError.duration = 5000; this.$.notificationError.open(); target.disabled = false; return; } target.disabled = false; }); } _hideDropPoints(obj, val) { this._clearMarkers(obj, val); } _storeIcon() { var icon; if (!!this.storeMapIcon) { icon = this.resolveUrl(this.storeMapIcon); } else { icon = this.resolveUrl('//gfswidgetcdn.azurewebsites.net/images/widgets2.0/store-map-icon.png'); } return icon; } _clearMarkers(obj) { let markers; let isDroppoint = obj.detail.droppoint; if (isDroppoint) { markers = this._droppointMarkers; for (var i = 0; i < markers.length; i++) { markers[i].setMap(null); } } else { markers = this._storeMarkers; for (var i = 0; i < markers.length; i++) { markers[i].setMap(null); } } } _showDroppointDetails() { this.mapHeight = this.$.droppointMap.clientHeight; this._storeDetailsClass = "fade-out"; this._droppointDetailsClass = "fade-in"; this._fire('show-opening-hours', this._selectedDroppoint); } _hideDroppointDetails() { this._droppointDetailsClass = "fade-out"; } _getDroppointsDetails(droppointID, isDroppoint) { this.isDroppoint = isDroppoint; let createSession = this.$.getDroppointInfo; createSession.url = this.checkoutUri + (isDroppoint ? '/api/droppoints/' : '/api/stores/') + droppointID; createSession.headers = this._getBearerToken(); createSession.generateRequest(); } _getOpeningHours(e) { if (this.droppointData.weekCollection == undefined && !(!!this._selectedDroppoint.weekCollection)) { let createSession = this.$.getOpeningHours; createSession.url = this.checkoutUri + this._selectedDroppoint.detail; createSession.headers = this._getBearerToken(); createSession.generateRequest(); this.shadowRoot.querySelector('#loader').style.display = 'block'; } else { this._weekCollection = this.droppointData.weekCollection ? this.droppointData.weekCollection : this._selectedDroppoint.weekCollection; } } _fire(ev, el, isDroppoint, isStore) { this.dispatchEvent(new CustomEvent(ev, { bubbles: true, composed: true, detail: { data: el, droppoint: isDroppoint, store: isStore } })); } _getBearerToken() { return { "Authorization": "Bearer " + atob(this.checkoutToken) }; } _handleDroppointInfoResponse(e) { this.droppointData = e.detail.response; if (this.isDroppoint) { this.shadowRoot.querySelector('.carrier-icon').style.display = 'block'; this.carrierIcon = this._droppointInfoWindowIco(e.detail.response.country, e.detail.response.provider); } else { this.shadowRoot.querySelector('.carrier-icon').style.display = 'none'; } this.$.loader.style.display = 'none'; } _handleOpeningHoursResponse(e) { var buildWeekCollection = []; var dayCount = 0; this._weekCollection = []; e.detail.response.days.forEach((collectionSlot) => { dayCount++; if (dayCount <= 7) { collectionSlot.slots.forEach((slot) => { slot.fromTime = slot.from; slot.toTime = slot.to; }); if (collectionSlot.slots.length > 0) { buildWeekCollection.push(collectionSlot); } } }); this.set('_weekCollection', buildWeekCollection); this.droppointData.weekCollection = this._weekCollection; this._selectedDroppoint.weekCollection = this._weekCollection; this.shadowRoot.querySelector('#loader').style.display = 'none'; } _handleError(e) { if (e.detail.error.type === "timeout") { this.$.notificationError.text = "Server Took Too Long To Respond"; this.$.notificationError.classList.add('fit-top'); this.$.notificationError.open(); this.$.loader.style.display = 'none'; } else { console.error('Error: ', e.detail.error.message); this.$.notificationError.text = e.detail.error.message; this.$.notificationError.classList.add('fit-top'); this.$.notificationError.open(); this.$.loader.style.display = 'none'; } } } window.customElements.define('gfs-droppoint-map', GfsDroppointMap);