UNPKG

@salla.sa/twilight-components

Version:
603 lines (602 loc) 23.6 kB
/*! * Crafted with ❤ by Salla */ import { Host, h } from "@stencil/core"; import Location from "../../assets/svg/location.svg"; import Edit from "../../assets/svg/edit.svg"; import CurrentLocation from "../../assets/svg/location-target.svg"; import LocationMarker from "../../assets/svg/location-marker.svg"; import styles from "./map-styles"; // import google maps import { Loader } from "google-maps"; export class SallaMap { constructor() { this.defaultLat = 21.419421; //Mecca 🕋 this.defaultLng = 39.82553; //Mecca 🕋 // state variables this.modalActivityTitle = salla.lang.get('pages.checkout.select_your_address_from_map'); this.confirmButtonTitle = salla.lang.get('pages.checkout.confirm_address'); this.locateButtonTitle = salla.lang.get('pages.cart.detect_location'); this.locateButtonEdit = salla.lang.get('common.elements.edit'); this.searchPlaceholder = salla.lang.get('pages.checkout.search_for_address'); this.searchInputValue = null; this.formattedAddress = ''; this.geolocationError = false; /** * File input name for the native formData */ this.name = 'location'; /** * Set if the location input is required or not */ this.required = false; /** * Disable or enable actions */ this.readonly = false; /** * Sets the search bar visibility. */ this.searchable = false; /** * Sets start map zoom. */ this.zoom = 10; /** * Sets map style. */ this.theme = 'light'; salla.lang.onLoaded(() => { this.modalActivityTitle = salla.lang.get('pages.checkout.select_your_address_from_map'); this.confirmButtonTitle = salla.lang.get('pages.checkout.confirm_address'); this.locateButtonTitle = salla.lang.get('pages.cart.detect_location'); this.locateButtonEdit = salla.lang.get('common.elements.edit'); this.searchPlaceholder = salla.lang.get('pages.checkout.search_for_address'); }); salla.onReady(() => { this.apiKey = salla.config.get('store.settings.keys.maps', 'AIzaSyBFgFISAizDP3YVWj0y5rF8JKKNQ2vohdc'); }); } formatAddress(address) { return address.length > 25 ? address.substring(0, 25) + '...' : address; } getLatLng() { return this.selectedLat && this.selectedLng ? `${this.selectedLat}, ${this.selectedLng}` : null; } getPositionAddress(location, submit = false) { // get address and set it to search input const Geocoder = new google.maps.Geocoder(); Geocoder.geocode({ location, }, (results, status) => { if (status === google.maps.GeocoderStatus.OK) { if (this.searchable) { this.searchInputValue = results[0].formatted_address; this.searchInput.value = results[0].formatted_address; } if (submit) { this.formattedAddress = results[0].formatted_address; } } }); } initGoogleMaps(options, mapDOM) { const loader = new Loader(this.apiKey, options); loader.load().then(google => { this.map = new google.maps.Map(mapDOM, { center: (this.lat || this.lng) ? { lat: this.lat, lng: this.lng, } : { lat: this.defaultLat, lng: this.defaultLng, }, zoom: this.zoom, zoomControl: true, mapTypeControl: false, scaleControl: false, streetViewControl: false, rotateControl: false, fullscreenControl: false, disableDefaultUI: false, }); this.map.setOptions({ styles: this.theme === 'light' ? styles.light : styles.dark, }); this.marker = new google.maps.Marker({ position: this.map.getCenter(), map: this.map, icon: { url: 'data:image/svg+xml;utf8,' + encodeURIComponent(LocationMarker), scaledSize: new google.maps.Size(30, 30), }, }); if (this.searchable) { const searchBox = new google.maps.places.SearchBox(this.searchInput); google.maps.event.addListener(searchBox, 'places_changed', () => { const places = searchBox.getPlaces(); // goto first place if (places.length > 0 && this.map) { this.map.setCenter(places[0].geometry.location); this.lat = places[0].geometry.location.lat(); this.lng = places[0].geometry.location.lng(); // set marker this.marker.setPosition(places[0].geometry.location); this.searchInputValue = places[0].formatted_address; this.formattedAddress = places[0].formatted_address; } }); } // add listener to map google.maps.event.addListener(this.map, 'click', e => { if (this.readonly) return; this.marker.setPosition(e.latLng); this.lat = e.latLng.lat(); this.lng = e.latLng.lng(); this.getPositionAddress(e.latLng); this.mapClicked.emit({ lat: e.latLng.lat(), lng: e.latLng.lng(), address: this.formattedAddress ? this.formattedAddress : null, }); }); if (!this.lat && !this.lng) { this.getCurrentLocation(); if (this.geolocationError) { this.map.setCenter({ lat: this.lat, lng: this.lng, }); this.marker.setPosition({ lat: this.lat, lng: this.lng, }); } } }); } getCurrentLocation() { if (navigator.geolocation && this.map) { navigator.geolocation.getCurrentPosition(position => { // set map to this location const mapOptions = { center: new google.maps.LatLng(position.coords.latitude, position.coords.longitude), zoom: 15, }; this.map.setOptions(mapOptions); // set marker this.marker.setPosition(mapOptions.center); this.getPositionAddress(mapOptions.center); this.lat = position.coords.latitude; this.lng = position.coords.longitude; this.currentLocationChanged.emit({ lat: position.coords.latitude, lng: position.coords.longitude, address: this.formattedAddress ? this.formattedAddress : null, }); }, this.handleLocationError.bind(this)); } else { salla.log('Geolocation is not supported by this browser.'); this.geolocationError = true; } } handleLocationError(error) { this.geolocationError = true; switch (error.code) { case error.PERMISSION_DENIED: salla.log('User denied the request for Geolocation.'); break; case error.POSITION_UNAVAILABLE: salla.log('Location information is unavailable.'); break; case error.TIMEOUT: salla.log('The request to get user location timed out.'); break; case error.UNKNOWN_ERROR: salla.log('An unknown error occurred.'); break; } } componentDidLoad() { // if lat and lng provided then get the formatted address if (this.lat && this.lng) { // get address fetch(`https://maps.googleapis.com/maps/api/geocode/json?latlng=${this.lat},${this.lng}&key=${this.apiKey}&language=${salla.config.get('user.language_code') || document.documentElement.lang || 'ar'}`) .then(res => res.json()) .then(res => { if (res.status === 'OK') { this.formattedAddress = res.results[0].formatted_address; this.searchInputValue = res.results[0].formatted_address; this.searchInput.value = res.results[0].formatted_address; this.selectedLng = this.lng; this.selectedLat = this.lat; } }); } this.mapInput.addEventListener('invalid', e => { this.invalidInput.emit(e); }); this.mapInput.addEventListener('input', () => { this.mapInput.setCustomValidity(''); this.mapInput.reportValidity(); }); } /** * Open location component */ async open() { // only init google maps on modal open :) to save resources if (!this.map) this.initGoogleMaps({ libraries: this.searchable ? ['places', 'search'] : [], language: salla.config.get('user.language_code') || document.documentElement.lang || 'ar', }, this.mapElement); return await this.locationModal.open(); } // rendering functions getLocationModal() { return (h("div", null, h("div", { class: "s-map-modal-title" }, !!this.modalTitle ? this.modalTitle : this.modalActivityTitle), h("div", { class: "s-map-modal-body" }, h("div", { class: "s-map-element", ref: el => (this.mapElement = el) }), this.readonly ? "" : [ this.searchable && (h("div", { class: "s-map-search-wrapper" }, h("input", { class: "s-map-search-input", ref: el => (this.searchInput = el), placeholder: this.searchPlaceholder }))), h("salla-button", { class: "s-map-my-location-button", onClick: () => { this.getCurrentLocation(); }, shape: "icon", color: "primary" }, h("span", { innerHTML: CurrentLocation })), h("salla-button", { class: "s-map-submit-button", color: "primary", width: "wide", onClick: () => { let points = { lat: this.lat, lng: this.lng, address: this.formattedAddress ? this.formattedAddress : null, }; salla.event.emit('salla-map::selected', points); this.selected.emit(points); this.selectedLat = points.lat; this.selectedLng = points.lng; this.getPositionAddress(new google.maps.LatLng(points.lat, points.lng), true); if (!this.selectedLat || !this.selectedLng) { this.mapInput.value = null; } else { this.mapInput.value = `${this.selectedLat}, ${this.selectedLng}`; } this.mapInput.dispatchEvent(new window.Event('change', { bubbles: true })); this.locationModal.close(); } }, this.confirmButtonTitle) ]))); } // render render() { return (h(Host, { key: '32e58284c1d8fb6bb5d7bc38de51d3e1deb6e79b', class: "s-map-wrapper" }, h("salla-modal", { key: '5988ed607361ceb502c6b4a97fd04d87ac300221', class: "s-map-modal-wrapper", noPadding: true, ref: modal => { this.locationModal = modal; } }, this.getLocationModal()), h("slot", { key: 'cd24c7c34b7f221f0772cb844183a4a3bd440b38', name: "button" }, h("salla-button", { key: '1706149662154cedbb3bddf3276fba9024f155e7', onClick: () => { this.open(); }, color: "primary", class: "s-map-location-button" }, h("span", { key: 'f5e1e3bea2bbf16243dfb1aa37436019bbc8db59', class: "s-map-location-icon", innerHTML: this.formattedAddress ? Edit : Location }), this.formattedAddress ? (h("div", null, this.locateButtonEdit, " | ", this.formatAddress(this.formattedAddress))) : (this.locateButtonTitle))), h("input", { key: '3998786709bb948a0eb3b57750908cabff9c32a1', class: "s-hidden", name: this.name, required: this.required, value: this.getLatLng(), ref: color => this.mapInput = color }))); } static get is() { return "salla-map"; } static get originalStyleUrls() { return { "$": ["salla-map.scss"] }; } static get styleUrls() { return { "$": ["salla-map.css"] }; } static get properties() { return { "name": { "type": "string", "attribute": "name", "mutable": false, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "File input name for the native formData" }, "getter": false, "setter": false, "reflect": false, "defaultValue": "'location'" }, "required": { "type": "boolean", "attribute": "required", "mutable": false, "complexType": { "original": "boolean", "resolved": "boolean", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "Set if the location input is required or not" }, "getter": false, "setter": false, "reflect": false, "defaultValue": "false" }, "readonly": { "type": "boolean", "attribute": "readonly", "mutable": false, "complexType": { "original": "boolean", "resolved": "boolean", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "Disable or enable actions" }, "getter": false, "setter": false, "reflect": false, "defaultValue": "false" }, "searchable": { "type": "boolean", "attribute": "searchable", "mutable": true, "complexType": { "original": "boolean", "resolved": "boolean", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "Sets the search bar visibility." }, "getter": false, "setter": false, "reflect": false, "defaultValue": "false" }, "lat": { "type": "number", "attribute": "lat", "mutable": true, "complexType": { "original": "number", "resolved": "number", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "Latitude coordinate, defaults to current user location" }, "getter": false, "setter": false, "reflect": false }, "lng": { "type": "number", "attribute": "lng", "mutable": true, "complexType": { "original": "number", "resolved": "number", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "Longitude coordinate, defaults to current user location" }, "getter": false, "setter": false, "reflect": false }, "apiKey": { "type": "string", "attribute": "api-key", "mutable": true, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "Sets google api key value, default Merchant key" }, "getter": false, "setter": false, "reflect": false }, "modalTitle": { "type": "string", "attribute": "modal-title", "mutable": false, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "Modal Title" }, "getter": false, "setter": false, "reflect": false }, "zoom": { "type": "number", "attribute": "zoom", "mutable": true, "complexType": { "original": "number", "resolved": "number", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "Sets start map zoom." }, "getter": false, "setter": false, "reflect": false, "defaultValue": "10" }, "theme": { "type": "string", "attribute": "theme", "mutable": true, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "Sets map style." }, "getter": false, "setter": false, "reflect": false, "defaultValue": "'light'" } }; } static get states() { return { "modalActivityTitle": {}, "confirmButtonTitle": {}, "locateButtonTitle": {}, "locateButtonEdit": {}, "searchPlaceholder": {}, "searchInputValue": {}, "formattedAddress": {}, "geolocationError": {}, "searchInput": {}, "mapInput": {}, "mapElement": {}, "selectedLat": {}, "selectedLng": {} }; } static get events() { return [{ "method": "selected", "name": "selected", "bubbles": true, "cancelable": true, "composed": true, "docs": { "tags": [], "text": "Custom DOM event emitter when location is selected" }, "complexType": { "original": "any", "resolved": "any", "references": {} } }, { "method": "mapClicked", "name": "mapClicked", "bubbles": true, "cancelable": true, "composed": true, "docs": { "tags": [], "text": "Custom DOM event emitter when map is clicked" }, "complexType": { "original": "any", "resolved": "any", "references": {} } }, { "method": "currentLocationChanged", "name": "currentLocationChanged", "bubbles": true, "cancelable": true, "composed": true, "docs": { "tags": [], "text": "Custom DOM event emitter when current location is selected" }, "complexType": { "original": "any", "resolved": "any", "references": {} } }, { "method": "invalidInput", "name": "invalidInput", "bubbles": true, "cancelable": true, "composed": true, "docs": { "tags": [], "text": "Event emitted when the input is invalid." }, "complexType": { "original": "any", "resolved": "any", "references": {} } }]; } static get methods() { return { "open": { "complexType": { "signature": "() => Promise<HTMLElement>", "parameters": [], "references": { "Promise": { "location": "global", "id": "global::Promise" }, "HTMLElement": { "location": "global", "id": "global::HTMLElement" }, "HTMLSallaModalElement": { "location": "global", "id": "global::HTMLSallaModalElement" } }, "return": "Promise<HTMLElement>" }, "docs": { "text": "Open location component", "tags": [] } } }; } static get elementRef() { return "host"; } } //# sourceMappingURL=salla-map.js.map