Skip to content

Commit

Permalink
Merge branch 'develop' into Issue-#1583
Browse files Browse the repository at this point in the history
  • Loading branch information
koliaBp authored Aug 29, 2022
2 parents ee55af7 + bc1ce21 commit 4d5dfdd
Show file tree
Hide file tree
Showing 23 changed files with 223 additions and 287 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
<div class="city-confirmation" *ngIf="isDispalyed && !(isConfirmCity$ | async)">
<div fxLayout="row" fxLayoutAlign="space-between start">
<p>
Ви знаходитесь в місті <span>{{ settlement.settlement }}</span
Ви знаходитесь в населеному пункті <span>{{ settlement.settlement }}</span
>?
</p>
<mat-icon (click)="isDispalyed = false">clear</mat-icon>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ h4{
text-align: center;
font-size: 19px;
margin-bottom: 0;
line-height: 1.3rem;
span {
font-weight: 700;
}
Expand Down
2 changes: 1 addition & 1 deletion src/app/shared/components/map/map.component.html
Original file line number Diff line number Diff line change
@@ -1 +1 @@
<div id="map"></div>
<div id="map"></div>
203 changes: 99 additions & 104 deletions src/app/shared/components/map/map.component.ts
Original file line number Diff line number Diff line change
@@ -1,58 +1,57 @@
import { Codeficator } from './../../models/codeficator.model';

import { Component, AfterViewInit, Input, Output, EventEmitter, OnDestroy } from '@angular/core';
import * as Layer from 'leaflet';
import { FormGroup } from '@angular/forms';
import { GeolocationService } from 'src/app/shared/services/geolocation/geolocation.service';
import { Coords } from '../../models/coords.model';
import { Address, MapAddress } from '../../models/address.model';
import { Address } from '../../models/address.model';
import { Workshop, WorkshopCard, WorkshopFilterCard } from '../../models/workshop.model';
import { Select } from '@ngxs/store';
import { FilterState } from '../../store/filter.state';
import { Observable } from 'rxjs';
import { Subject } from 'rxjs';
import { takeUntil, filter, debounceTime } from 'rxjs/operators';
import { GeolocationAddress } from '../../models/geolocationAddress.model';
import { UserState } from '../../store/user.state';
import { PreviousUrlService } from '../../services/previousUrl/previous-url.service';
import { WorkshopMarker } from '../../models/workshopMarker.model';
import { GeocoderService } from './../../services/geolocation/geocoder.service';
import { Geocoder } from './../../models/geolocation';
import { Codeficator } from './../../models/codeficator.model';
import { FilterState } from '../../store/filter.state';

@Component({
selector: 'app-map',
templateUrl: './map.component.html',
styleUrls: ['./map.component.scss'],
})
export class MapComponent {
export class MapComponent implements AfterViewInit, OnDestroy {
@Input() addressFormGroup: FormGroup;
@Input() isCreateWorkShops: boolean;
@Input() filteredWorkshops$: Observable<WorkshopFilterCard>;

@Output() wrongMapAddress = new EventEmitter<boolean>();
@Output() selectedAddress = new EventEmitter<any>();

@Select(UserState.selectedWorkshop)
selectedWorkshop$: Observable<Workshop>;
public defaultCoords: Coords;
public zoom = 11;
public workshops: WorkshopCard[];

@Select(FilterState.settlement)
settlement$: Observable<Codeficator>;
destroy$: Subject<boolean> = new Subject<boolean>();

@Input() addressFormGroup: FormGroup;
@Input() isCreateWorkShops: boolean;
@Input() filteredWorkshops$: Observable<WorkshopFilterCard>;
@Output() setAddressEvent = new EventEmitter<MapAddress>();
@Output() selectedAddress = new EventEmitter<MapAddress>();

constructor(private geolocationService: GeolocationService, private previousUrlService: PreviousUrlService) {}
destroy$: Subject<boolean> = new Subject<boolean>();
map: Layer.Map;
singleMarker: Layer.Marker;
workshopMarkers: WorkshopMarker[] = [];

unselectedMarkerIcon: Layer.Icon = Layer.icon({
private singleMarker: Layer.Marker;
private workshopMarkers: WorkshopMarker[] = [];
private defaultCoords: Coords;
private zoom = 11;
private workshops: WorkshopCard[];
private unselectedMarkerIcon: Layer.Icon = Layer.icon({
iconSize: [25, 25],
shadowSize: [0, 0],
iconAnchor: [10, 41],
shadowAnchor: [0, 0],
popupAnchor: [-3, -76],
iconUrl: '/assets/icons/marker.png',
});

selectedMarkerIcon: Layer.Icon = Layer.icon({
private selectedMarkerIcon: Layer.Icon = Layer.icon({
iconSize: [25, 25],
shadowSize: [0, 0],
iconAnchor: [10, 41],
Expand All @@ -61,6 +60,68 @@ export class MapComponent {
iconUrl: '/assets/icons/selectMarker.png',
});

constructor(private geocoderService: GeocoderService, private previousUrlService: PreviousUrlService) {}

/**
* before map creation gets user coords from GeolocationService. If no user coords uses default coords
* Creates and sets map after div with is "map" renders.
* Adds onclick event handler which translates map coords into address
* subscribes on @input address change and on every change calls method to translate address into coords
*/
ngAfterViewInit(): void {
this.settlement$
.pipe(
takeUntil(this.destroy$),
filter((settlement: Codeficator) => !!settlement)
)
.subscribe((settlement: Codeficator) => {
this.defaultCoords = { lat: settlement.latitude, lng: settlement.longitude };
this.map || this.initMap();
this.flyTo(this.defaultCoords);

// checking if there are filtered workshops on the map for teh result page view
if (!!this.filteredWorkshops$) {
this.setFilteredWorkshops();
}
// checking if user edit workshop information to create adress for workshop
if (this.addressFormGroup) {
this.setAddress();
}
});
}

private setFilteredWorkshops(): void {
this.filteredWorkshops$.pipe(takeUntil(this.destroy$)).subscribe((filteredWorkshops: WorkshopFilterCard) => {
this.workshopMarkers.forEach((workshopMarker: WorkshopMarker) => this.map.removeLayer(workshopMarker.marker));
this.workshopMarkers = [];
if (filteredWorkshops) {
this.workshops = filteredWorkshops.entities;
filteredWorkshops.entities.forEach((workshop: WorkshopCard) => this.setAddressLocation(workshop.address));
this.setPrevWorkshopMarker();
}
});
}

private setAddress(): void {
const address: Geocoder = this.addressFormGroup.getRawValue();
if (address.catottgId) {
this.geocoderService.addressDecode(address, (result: Geocoder) => {
if (result) {
this.setNewSingleMarker([result.latitude, result.longitude]);
}
this.wrongMapAddress.emit(!result);
});
}

this.addressFormGroup.valueChanges
.pipe(
debounceTime(500),
takeUntil(this.destroy$),
filter((address: Geocoder) => !!(address.longitude && address.latitude))
)
.subscribe((address: Geocoder) => this.setNewSingleMarker([address.latitude, address.longitude]));
}

/**
* changing position on map
* @param coords:Coords
Expand Down Expand Up @@ -93,106 +154,37 @@ export class MapComponent {
});
}

/**
* before map creation gets user coords from GeolocationService. If no user coords uses default coords
* Creates and sets map after div with is "map" renders.
* Adds onclick event handler which translates map coords into address
* subscribes on @input address change and on every change calls method to translate address into coords
*/
ngAfterViewInit(): void {
this.settlement$
.pipe(
takeUntil(this.destroy$),
filter((settlement: Codeficator) => !!settlement)
)
.subscribe((settlement: Codeficator) => {
this.defaultCoords = { lat: settlement.latitude, lng: settlement.longitude };
this.map || this.initMap();
this.flyTo(this.defaultCoords);

// cheking if there are filtered workshops on the map
if (!!this.filteredWorkshops$) {
this.filteredWorkshops$.pipe(takeUntil(this.destroy$)).subscribe((filteredWorkshops: WorkshopFilterCard) => {
this.workshopMarkers.forEach((workshopMarker: WorkshopMarker) =>
this.map.removeLayer(workshopMarker.marker)
);
this.workshopMarkers = [];
if (filteredWorkshops) {
this.workshops = filteredWorkshops.entities;
filteredWorkshops.entities.forEach((workshop: WorkshopCard) => this.setAddressLocation(workshop.address));
this.setPrevWorkshopMarker();
}
});
}
});

// cheking if user edit workshop information
if (this.addressFormGroup) {
this.addressFormGroup.value.latitude && this.setLocation(this.addressFormGroup.value);

this.addressFormGroup.valueChanges.pipe(debounceTime(500)).subscribe((address: MapAddress) => {
if (!address.street && !address.buildingNumber) {
this.setAddressLocation(address);
}
if (address.codeficatorAddressDto && address.street && address.buildingNumber) {
this.setLocation(address);
}
});
}
}

/**
* uses GoelocationService to translate address into coords and sets marker on efault
* @param address - type Address
*/
setAddressLocation(address: Address): void {
this.workshops ? this.setWorkshopMarkers(address) : this.setNewSingleMarker([address.codeficatorAddressDto.latitude, address.codeficatorAddressDto.longitude]);
this.workshops
? this.setWorkshopMarkers(address)
: this.setNewSingleMarker([address.codeficatorAddressDto.latitude, address.codeficatorAddressDto.longitude]);
}

/**
* uses GoelocationService to translate coords into address and sets emits event to update address in parent component
* @param coords - type Coords
*/
setMapLocation(coords: Coords): void {
this.geolocationService.locationDecode(coords, (result: GeolocationAddress) => {
if (result.address || (Array.isArray(result) && result.length)) {
const location = result.address || result[0].properties.address;
const codeficatorAddressDto = {
settlement:location.city || location.village || location.town || location.hamlet
} as Codeficator;
const street = location.road;
const buildingNumber = location.house_number;
const longitude = result.lon || result[0].lon;
const latitude = result.lat || result[0].lat;
this.setAddressEvent.emit({ codeficatorAddressDto, street, buildingNumber, longitude, latitude });
private setMapLocation(coords: Coords): void {
this.geocoderService.locationDecode(coords, (result: Geocoder) => {
if (result) {
this.addressFormGroup.patchValue(result);
} else {
this.setAddressEvent.emit({
codeficatorAddressDto: null,
street: null,
buildingNumber: null,
});
}
});
}

/**
* uses GeolocationService to translate address into coords and sets marker on default
* @param address - type Address
*/
setLocation(address: MapAddress): void {
this.geolocationService.addressDecode(address, (result: GeolocationAddress) => {
if (result.address || (Array.isArray(result) && result.length)) {
const coords: [number, number] = [result.lat || result[0].lat, result.lon || result[0].lon];
this.setNewSingleMarker(coords);
this.addressFormGroup.reset();
this.map.removeLayer(this.singleMarker);
}
this.wrongMapAddress.emit(!result);
});
}

/**
* This method remove existed marker and set the new marke to the map
* @param coords - type [number, number]
*/
setNewSingleMarker(coords: [number, number]): void {
private setNewSingleMarker(coords: [number, number]): void {
this.singleMarker && this.map.removeLayer(this.singleMarker);
this.singleMarker = this.createMarker(coords);
this.map.addLayer(this.singleMarker);
Expand Down Expand Up @@ -230,7 +222,10 @@ export class MapComponent {
.subscribe((workshop: Workshop) => {
const targetMarkers = this.workshopMarkers.filter((workshopMarker: WorkshopMarker) => {
const { lat, lng } = workshopMarker.marker.getLatLng();
return lat === workshop.address.codeficatorAddressDto.latitude && lng === workshop.address.codeficatorAddressDto.longitude;
return (
lat === workshop.address.codeficatorAddressDto.latitude &&
lng === workshop.address.codeficatorAddressDto.longitude
);
});
targetMarkers.forEach((targetMarker: WorkshopMarker) => {
targetMarker.isSelected = true;
Expand Down
9 changes: 0 additions & 9 deletions src/app/shared/models/address.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,4 @@ export class Address {
this.id = address.id;
}
}
}

export interface MapAddress {
codeficatorAddressDto: Codeficator;
street: string;
buildingNumber: string;
latitude?: number;
longitude?: number;
catottgId?: number;
}
18 changes: 18 additions & 0 deletions src/app/shared/models/geolocation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,21 @@ export interface GeolocationCoordinates {
longitude: number;
speed: number | null;
}

export interface BaseGeocoder {
catottgId?: number;
street?: string;
buildingNumber?: string;
latitude?: number;
longitude?: number;
isReverse?: boolean;
}
export interface Geocoder extends BaseGeocoder {
latitude?: number;
longitude?: number;
}

export interface GeocoderDTO extends BaseGeocoder {
lat: number;
lon: number;
}
21 changes: 16 additions & 5 deletions src/app/shared/services/codeficator/codeficator.service.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { HttpClient, HttpParams } from '@angular/common/http';
import { Observable } from 'rxjs';
import { Codeficator, CodeficatorCityDistrict } from '../../models/codeficator.model';

@Injectable({
providedIn: 'root'
providedIn: 'root',
})
export class CodeficatorService {

constructor(private http: HttpClient) {
}
constructor(private http: HttpClient) {}

/**
* This method to get all Codeficators from the database
Expand All @@ -34,4 +32,17 @@ export class CodeficatorService {
searchCodeficatorCityDistrict(id: number): Observable<CodeficatorCityDistrict[]> {
return this.http.get<CodeficatorCityDistrict[]>(`/api/v1/Codeficator/children?id=${id}`);
}

/**
* This method to get teh nearst settlemnt by coordinates
* @param lat number
* @param lon number
*/
getNearestByCoordinates(lat: number, lon: number): Observable<Codeficator> {
let params = new HttpParams();
params = params.set('Lat', lat.toString());
params = params.set('Lon', lon.toString());

return this.http.get<Codeficator>(`/api/v1/Codeficator/NearestByCoordinates`, { params });
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,15 @@ import { Observable } from 'rxjs';
import { FeaturesList } from '../../models/featuresList.model';

@Injectable({
providedIn: 'root'
providedIn: 'root',
})
export class FeatureManagementService {
constructor(private http: HttpClient) {}

constructor(private http: HttpClient) { }

/**
/**
* This method get features flags depending on releases
*/
getFeaturesList(): Observable<FeaturesList> {
return this.http.get<FeaturesList>('/api/v1/FeatureManagement/Get');
}

getFeaturesList(): Observable<FeaturesList> {
return this.http.get<FeaturesList>('/api/v1/FeatureManagement/Get');
}
}
Loading

0 comments on commit 4d5dfdd

Please sign in to comment.