File

src/app/pages/photographer-search-page/photographer-search-page.component.ts

Description

Photographer search page component

Implements

OnInit

Example

Metadata

selector app-photographer-search-page
styleUrls photographer-search-page.component.scss
templateUrl ./photographer-search-page.component.html

Index

Properties
Methods

Constructor

constructor(geolocation: GeolocationService, afs: FirebaseFirestoreService, service: AlertService)

Constructor

Parameters :
Name Type Optional Description
geolocation GeolocationService

Geolocation Service

afs FirebaseFirestoreService

Firebase Firestore Service

service AlertService

Methods

addPhotographerInCircle
addPhotographerInCircle(circle: number)
Parameters :
Name Type Optional Description
circle number
Returns : void
getPhotographerDistance
getPhotographerDistance(photographer: PhotographerProfile)

return number of kilometres between a certain photographer and the user position

Parameters :
Name Type Optional Description
photographer PhotographerProfile

Photographer profile

Returns : number
handleEnteredZip
handleEnteredZip(zip: string)

get entered zip, convert zip to coordinates, refresh map

Parameters :
Name Type Optional Description
zip string

ZIP

Returns : void
ngOnInit
ngOnInit()

Initialize component

Returns : void
onKey
onKey(event: any)

return input value

Parameters :
Name Type Optional Description
event any
Returns : void
refreshPhotographerList
refreshPhotographerList()

add photographers to displayed list when they are in the users area

Returns : void
setPosition
setPosition(latitude: number, longitude: number)

Set the position on the map

Parameters :
Name Type Optional Description
latitude number

Latitude

longitude number

Longitude

Returns : void
sortPhotographerByDistance
sortPhotographerByDistance()
Returns : void

Properties

Public agmMap
agmMap: AgmMap
Type : AgmMap
Decorators : ViewChild

Google maps ref

Public editedPhotographer
editedPhotographer: PhotographerProfile[]
Type : PhotographerProfile[]
Default value : []

Edited photographer profiles collection

Public hasBothProfiles
hasBothProfiles: boolean
Type : boolean

indicator for parting line

Private log
log:
Default value : Log.create('PhotographerSearchPageComponent')

Logger

Public photograph
photograph: PhotographerProfile
Type : PhotographerProfile
Default value : { about: '', email: '', facebook: '', instagram: '', name: '', phone: '', tumbler: '', twitter: '', uid: '', website: '', premium: false, profileUrl: '', location: { lat: 0, lng: 0 } }

Photographer profile

Public photographer
photographer: PhotographerProfile[]
Type : PhotographerProfile[]
Default value : []

Photographer profiles collection

Private userLat
userLat: number
Type : number

Users Latitutde

Private userLng
userLng: number
Type : number

Users Longitude

import { AgmMap } from '@agm/core';
import { Component, OnInit, ViewChild } from '@angular/core';
import { Log } from 'ng2-logger';

import { Alert } from '../../interfaces/alert';
import { PhotographerProfile } from '../../interfaces/photographer-profile';
import { AlertService } from '../../services/alert/alert.service';
import { FirebaseFirestoreService } from '../../services/firebase/firestore/firebase-firestore.service';
import { GeolocationService } from '../../services/geolocation/geolocation.service';

/**
 * Photographer search page component
 * @author Daniel Sogl, Tim Krießler
 */
@Component({
  selector: 'app-photographer-search-page',
  templateUrl: './photographer-search-page.component.html',
  styleUrls: ['./photographer-search-page.component.scss']
})
export class PhotographerSearchPageComponent implements OnInit {
  /** Logger */
  private log = Log.create('PhotographerSearchPageComponent');

  /** Photographer profiles collection */
  public photographer: PhotographerProfile[] = [];

  /** Edited photographer profiles collection */
  public editedPhotographer: PhotographerProfile[] = [];

  /** indicator for parting line */
  public hasBothProfiles: boolean;

  /** Photographer profile */
  public photograph: PhotographerProfile = {
    about: '',
    email: '',
    facebook: '',
    instagram: '',
    name: '',
    phone: '',
    tumbler: '',
    twitter: '',
    uid: '',
    website: '',
    premium: false,
    profileUrl: '',
    location: {
      lat: 0,
      lng: 0
    }
  };

  /** Users Latitutde */
  private userLat: number;
  /** Users Longitude */
  private userLng: number;

  /** Google maps ref */
  @ViewChild('map') public agmMap: AgmMap;

  /**
   * Constructor
   * @param  {GeolocationService} geolocation Geolocation Service
   * @param  {FirebaseFirestoreService} afs Firebase Firestore Service
   */
  constructor(
    private geolocation: GeolocationService,
    private afs: FirebaseFirestoreService,
    private service: AlertService
  ) {}

  /**
   * Initialize component
   */
  ngOnInit() {
    this.log.color = 'orange';
    this.log.d('Component initialized');

    // Init map
    this.agmMap.latitude = 51.165691;
    this.agmMap.longitude = 10.451526000000058;
    this.agmMap.zoom = 11;

    // Load all photographer profiles
    this.afs
      .getAllPhotographer()
      .valueChanges()
      .subscribe(photographer => {
        this.photographer = photographer;
        // Get browser geolocation
        if (!!navigator.geolocation) {
          /* geolocation is available */
          this.geolocation
            .getBrowserLocation()
            .then(position => {
              this.log.d('Current position', position.coords);
              this.setPosition(
                position.coords.latitude,
                position.coords.longitude
              );
              this.userLat = position.coords.latitude;
              this.userLng = position.coords.longitude;
              // Show photographer profiles of users area
              this.refreshPhotographerList();
            })
            .catch((err: any) => {
              this.log.er('Error getting location', err);
            });
        }
      });
  }

  /**
   * return number of kilometres between a certain photographer and the user position
   * @param  {PhotographerProfile} photographer Photographer profile
   * @returns {number}
   */
  getPhotographerDistance(photographer: PhotographerProfile): number {
    return this.geolocation.calculateGpsDistance(
      photographer.location.lat,
      photographer.location.lng,
      this.userLat,
      this.userLng
    );
  }

  /**
   * Set the position on the map
   * @param  {number} latitude Latitude
   * @param  {number} longitude Longitude
   */
  setPosition(latitude: number, longitude: number) {
    this.agmMap.latitude = latitude;
    this.agmMap.longitude = longitude;
    this.agmMap.zoom = 11;
    this.agmMap.triggerResize();
  }

  /**
   * return input value
   * @param  {any} eventm Event
   */
  onKey(event: any) {
    if (+event.target.value && event.target.value.length === 5) {
      this.handleEnteredZip(event.target.value);
    } else if (event.target.value.length === 5) {
      const alert: Alert = {
        title: 'Ungültige PLZ eingegeben!'
      };
      this.service.showError(alert);
    }
  }

  /**
   * get entered zip, convert zip to coordinates, refresh map
   * @param  {string} zip ZIP
   */
  handleEnteredZip(zip: string) {
    this.log.info('valid zip-length entered');
    this.geolocation.getCoordinatesFromZip(zip).then((result: any) => {
      if (result.results[0].geometry.location) {
        this.photograph.location = result.results[0].geometry.location;
        this.setPosition(
          this.photograph.location.lat,
          this.photograph.location.lng
        );
        this.userLat = this.photograph.location.lat;
        this.userLng = this.photograph.location.lng;
        this.refreshPhotographerList();
      } else {
        this.log.error('Cannot get location from Service');
      }
    });
  }

  /**
   * add photographers to displayed list when they are in the users area
   */
  refreshPhotographerList() {
    // clean displayed list
    if (this.editedPhotographer) {
      this.editedPhotographer.splice(0);
    }

    // add photographers in the circle of 10 kilometres
    this.addPhotographerInCircle(10);
    this.agmMap.zoom = 11;
    /** if there are no photographers in the circle of 10 kilometres,
     * add photographers in the circle of 25 kilometres
     */
    if (!this.editedPhotographer.length) {
      const alert: Alert = {
        title: 'Kein Fotograf gefunden. Umkreis auf 25km erhöht'
      };
      this.service.showInfo(alert);
      this.addPhotographerInCircle(25);
      this.agmMap.zoom = 10;
    }
  }

  addPhotographerInCircle(circle: number) {
    let hasPremium: boolean;
    let hasStandard: boolean;
    hasPremium = false;
    hasStandard = false;
    this.hasBothProfiles = false;

    for (let i = 0; i < this.photographer.length; i++) {
      let distance: number;
      distance = this.getPhotographerDistance(this.photographer[i]);

      // add all photographers in the circle
      if (distance <= circle) {
        this.editedPhotographer.push(this.photographer[i]);

        /** check whether parting line is required */
        if (this.photographer[i].premium) {
          hasPremium = true;
        } else if (!this.photographer[i].premium) {
          hasStandard = true;
        }
      }
      if (i === this.photographer.length - 1) {
        this.sortPhotographerByDistance();
      }
    }
    if (hasPremium && hasStandard) {
      this.hasBothProfiles = true;
    }
  }

  sortPhotographerByDistance() {
    if (this.editedPhotographer.length > 0) {
      this.editedPhotographer.sort((a, b) => {
        if (this.getPhotographerDistance(a) < this.getPhotographerDistance(b)) {
          return -1;
        }
        if (this.getPhotographerDistance(a) > this.getPhotographerDistance(b)) {
          return 1;
        }
        return 0;
      });
    }
  }
}
<div class="container-fluid">
  <div class="row mt-5 pt-5">
    <div class="col col-lg-4 text-center">
      <div class="md-form">
        <input mdbActive type="text" class="form-control" (keyup)="onKey($event)">
        <label class="active">{{ 'TEXTS.SEARCH_PHOTOGRAPHER' | translate }}</label>
      </div>
      <div class="scrollable">
        <div *ngIf="editedPhotographer.length; else noPhotographer">
          <div *ngFor="let p of editedPhotographer">
            <div *ngIf="p.premium == true">
              <a [routerLink]="['/photographer', p.profileUrl]">
                <div class="card">
                  <div class="card-body">
                    <p class="name">{{ p.name }}</p>
                    <div class="content">
                      <img class="profile-img" [src]="p.photoUrl">
                      <div *ngIf="p.address" class="address">{{p.address.street}} {{p.address.streetnumber}}
                        <br/> {{p.address.zip}} {{p.address.city}}
                        <br/>
                      </div>
                    </div>
                    <br/>
                    <div class="distance">
                      {{getPhotographerDistance(p) | number:'0.2-2' | replace:'.':','}} km
                    </div>
                  </div>
                </div>
              </a>
            </div>
          </div>
          <hr *ngIf="hasBothProfiles" class="mt-4 mb-4 border">
          <div *ngFor="let p of editedPhotographer">
            <div *ngIf="!p.premium">
              <a [routerLink]="['/photographer', p.profileUrl]">
                <div class="card">
                  <div class="card-body">
                    <p class="name">{{ p.name }}</p>
                    <div>
                      <div *ngIf="p.address" class="address">{{p.address.street}} {{p.address.streetnumber}}
                        <br/> {{p.address.zip}} {{p.address.city}}
                        <br/>
                      </div>
                    </div>
                    <br/>
                    <div class="distance">
                      {{getPhotographerDistance(p) | number:'0.2-2' | replace:'.':','}} km
                    </div>
                  </div>
                </div>
              </a>
            </div>
          </div>
        </div>
        <ng-template #noPhotographer>
          <p>{{ 'TEXTS.NO_PHOTOGRAPHERS_FOUND' | translate}}</p>
        </ng-template>
      </div>
    </div>
    <div class="col col-lg-8 text-center">
      <agm-map #map class="card mapformat">
        <agm-marker *ngFor="let p of editedPhotographer; let i = index" [latitude]="p.location.lat" [longitude]="p.location.lng"
          [title]="p.name" [zIndex]="i">
          <agm-snazzy-info-window [maxWidth]="300" [closeWhenOthersOpen]="true" [maxHeight]="300">
            <ng-template>
              <div>
                <span class="name">
                  <b>{{ p.name }}</b>
                </span>
                <div class="content">
                  <div>
                    <img *ngIf="p.premium" class="content-img" [src]="p.photoUrl">
                    <br/>
                  </div>
                  <span *ngIf="p.address.street">{{ p.address.street }} {{p.address.streetnumber}}
                    <br> {{ p.address.zip }} {{ p.address.city }}</span>
                  <br>
                  <span *ngIf="p.phone">Tel: {{ p.phone }}</span>
                  <br>
                </div>
                <a [routerLink]="['/photographer', p.profileUrl]">Profile</a>
              </div>
            </ng-template>
          </agm-snazzy-info-window>
        </agm-marker>
      </agm-map>
    </div>
  </div>
</div>
Legend
Html element
Component
Html element with directive

results matching ""

    No results matching ""