All files / src/app/extensions/store-locator/services/stores-map stores-map.service.ts

27.27% Statements 12/44
41.66% Branches 5/12
7.14% Functions 1/14
27.9% Lines 12/43

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 983x 3x 3x   3x   3x   3x 3x       3x     3x     1x     1x 1x                                                                                                                                                    
import { Inject, Injectable, InjectionToken } from '@angular/core';
import { Loader } from '@googlemaps/js-api-loader';
import { Store, select } from '@ngrx/store';
 
import { InjectSingle } from 'ish-core/utils/injection';
 
import { StoreLocationHelper } from '../../models/store-location/store-location.helper';
import { StoreLocation } from '../../models/store-location/store-location.model';
import { getGMAKey } from '../../store/store-locator-config';
import { getHighlightedStore, getStores, highlightStore } from '../../store/stores';
 
type IconConfiguration = { default: string; highlight: string };
 
export const STORE_MAP_ICON_CONFIGURATION = new InjectionToken<IconConfiguration>('Store Map Icon Configuration');
 
@Injectable({ providedIn: 'root' })
export class StoresMapService {
  private map: google.maps.Map;
  private infoWindow: google.maps.InfoWindow;
  private entries: { store: StoreLocation; marker: google.maps.Marker }[] = [];
 
  constructor(
    private store: Store,
    @Inject(STORE_MAP_ICON_CONFIGURATION) private icons: InjectSingle<typeof STORE_MAP_ICON_CONFIGURATION>
  ) {}
 
  initialize(container: HTMLElement) {
    this.store.pipe(select(getGMAKey)).subscribe((gmaKey: string) => {
      this.initializeMap(container, gmaKey);
    });
  }
 
  private initializeMap(container: HTMLElement, gmaKey: string) {
    const loader = new Loader({
      apiKey: gmaKey,
      version: 'weekly',
    });
    // eslint-disable-next-line @typescript-eslint/naming-convention
    loader.importLibrary('maps').then(({ Map }) => {
      this.map = new Map(container, {
        center: { lat: 0, lng: 0 },
        zoom: 2,
        minZoom: 2,
        mapTypeId: 'roadmap',
        fullscreenControl: false,
        streetViewControl: false,
      });
      this.infoWindow = new google.maps.InfoWindow();
      this.store.pipe(select(getStores)).subscribe(stores => {
        this.placeMarkers(stores.filter(store => store.longitude && store.latitude));
      });
      this.store.pipe(select(getHighlightedStore)).subscribe(data => {
        this.highlightMarkers(data);
      });
    });
  }
 
  private placeMarkers(stores: StoreLocation[]) {
    this.entries.forEach(entry => {
      entry.marker.setMap(undefined);
    });
    this.entries = [];
    const bounds = new google.maps.LatLngBounds();
    stores.forEach(store => {
      const marker = new google.maps.Marker({
        map: this.map,
        position: { lat: store.latitude, lng: store.longitude },
        icon: this.icons?.default,
      });
      bounds.extend(marker.getPosition());
      marker.addListener('click', () => {
        this.store.dispatch(highlightStore({ storeId: store.id }));
      });
      this.entries.push({ store, marker });
    });
    this.map.fitBounds(bounds);
  }
 
  private highlightMarkers(store: StoreLocation) {
    this.entries.forEach(entry => {
      if (StoreLocationHelper.equal(entry.store, store)) {
        entry.marker.setIcon(this.icons?.highlight);
        entry.marker.setZIndex(1);
        this.map.panTo(entry.marker.getPosition());
        this.infoWindow.close();
        this.infoWindow.setContent(entry.store.name);
        this.infoWindow.open({
          map: this.map,
          anchor: entry.marker,
        });
      } else {
        entry.marker.setIcon(this.icons?.default);
        entry.marker.setZIndex(0);
      }
    });
  }
}