import { Component, ViewEncapsulation, Injector, OnInit, DoCheck, ViewChild, Input, AfterViewInit,ViewContainerRef, ChangeDetectorRef, EventEmitter, Output, ViewChildren, ElementRef } from "@angular/core"; import { appModuleAnimation } from "@shared/animations/routerTransition"; import { AppComponentBase } from "@shared/common/app-component-base"; import { Router, ActivatedRoute } from "@angular/router"; import * as moment from 'moment'; import { LocationServiceProxy, LocationListDto, LocatorServiceProxy,MoveOrder, MobileThemeServiceProxy, PagedResultDtoOfAddressAddressTypeLookupTableDto, RouteBuilderServiceProxy, ListResultDtoOfOrganizationUnitDto, OrganizationUnitServiceProxy, RouteBuilderRouteIdOutput, UpdateRouteByBuilderInput, GoogleDirectionOptimizationServiceProxy, OptimizeByRouteIdInput, RouteOptimizationServiceProxy, OptimizeRouteInput, RouteBuilderOrderList, UpdateEtaInput } from "@shared/service-proxies/service-proxies"; import { MapFlyOutComponent } from "@app/shared/layout/flyout/map/map-flyout.component"; import { empty } from "rxjs"; import { LaboratoryMapFlyOutComponent } from "@app/shared/layout/flyout/map/laboratory/laboratory-map-flyout.component"; import { finalize } from 'rxjs/operators'; import { ChangeDetectionStrategy } from "@angular/compiler/src/core"; import { AppConsts } from "@shared/AppConsts"; import { CommonModule, Location } from '@angular/common'; import { AppSessionService } from "@shared/common/session/app-session.service"; import { ArrayToTreeConverterService } from "@shared/utils/array-to-tree-converter.service"; import { TreeNode, MenuItem, LazyLoadEvent } from "primeng/api"; import { TreeDataHelperService } from "@shared/utils/tree-data-helper.service"; import { ILatLng } from "../fleet-management/driver-proximities/driver-proximities.directive"; import { UpdateEtaRouteBuilder } from "./update-eta..component"; import { AnyNaptrRecord } from "dns"; import { RouteBuilderFilter } from "./route-builder-filter.component"; //import { UpdateGeoCodeModalComponent } from "./update-geocode.component"; declare var $: any; @Component({ templateUrl: './route-builder.component.html', encapsulation: ViewEncapsulation.None, animations: [appModuleAnimation()], styleUrls: ['./route-builder.component.less'] }) export class RouteBuilderComponent extends AppComponentBase implements OnInit, AfterViewInit{ treeData: any; selectedOu: TreeNode; ouContextMenuItems: MenuItem[]; selection: Array = []; todaysDate = moment().format('MM/DD/YYYY'); zoom: number = 8; lat: number = 34.044971; lng: number = -118.291243; map: any; pin: { path: string; fillColor: string; fillOpacity: number; strokeColor: string; strokeWeight: number; scale: number; labelOrigin: { x: number; y: number; }; }; laboratoryMapFeatureEdition: boolean = false; @Output() refresh: EventEmitter = new EventEmitter(); @ViewChild('UpdateEtaRouteBuilder', { static: false }) UpdateEtaRouteBuilder: UpdateEtaRouteBuilder; @ViewChild('routeBuilderFilter', {static: false}) routeBuilderFilter: RouteBuilderFilter; routeId: any; data = []; displayDirections = true; origin: ILatLng; destination: ILatLng; waypoint:Array = []; dataUp = []; availableRoute: any; routeLabel: string; routeDateLabel: any; locationId: number; routeDate: string; routeIdA: number; orderList: Array = []; orderToUp: number; templateToUp: number; destinationId: number; eta: number; past: boolean; mySelection: any; changed = false; editmode: boolean = false; markedData: Array<{ id: number, index: number }> = new Array(); checkCount: number = 0; _isLab: boolean = false; routeName: string = ""; locationName: string = ""; reset: boolean = false; recordsTemp: any; loading: boolean; constructor( injector: Injector, private router: Router, private _locationServiceProxy: LocationServiceProxy, private activatedRoute: ActivatedRoute, private _locatorAppService: LocatorServiceProxy, private viewContainerRef: ViewContainerRef, private _location: Location, private _routeBuilderAppService: RouteBuilderServiceProxy, private _arrayToTreeConverterService: ArrayToTreeConverterService, private _organizationUnitService: OrganizationUnitServiceProxy, private _treeDataHelperService: TreeDataHelperService, private _googleDirectionOpyimization: GoogleDirectionOptimizationServiceProxy, private _routeOptimization: RouteOptimizationServiceProxy, private _elem: ElementRef ) { super(injector); if(abp.auth.isGranted('Pages.Shipping.Locator') === false) { this._location.back(); } this.laboratoryMapFeatureEdition = abp.features.isEnabled('App.LaboratoryMapFilter'); } getParentComponent() { return this.viewContainerRef[ '_data' ].componentView.component.viewContainerRef[ '_view' ].component } ngOnInit(): void { this.activatedRoute.paramMap.subscribe(params => { this.routeId = params.get("routeid"); }); this._isLab = abp.features.isEnabled('App.RouteDetails'); //this.getDetails(); } showFlyOut(){ this.routeBuilderFilter.loadFlyOut(); } getDetails(){ this.dataUp = []; this.waypoint = []; this.orderList = []; this.checkCount = 0; this.loading = false; this.spinnerService.show(); var bounds = new google.maps.LatLngBounds(); this._routeBuilderAppService.getRouteForRouteBuilder(this.routeId,[1]) .subscribe(result => { this.changed = false; this.routeDateLabel = result.routeDate; this.routeLabel = "Route : "+result.routeId + " Zone : " + result.route; this.data = result.routeOrder; this.routeName = result.route; this.locationName = result.locationName; this.locationId = result.locationId; this.routeIdA = result.routeId; this.routeDate = result.routeDate.toString(); this.past = result.routeOrder[0].pastDate; this.origin = { latitude: result.routeOrder[0].latitude, longitude: result.routeOrder[0].longitude } bounds.extend(new google.maps.LatLng({lat: this.origin.latitude, lng: this.origin.longitude})); this.destination = { latitude: result.routeOrder[result.routeOrder.length - 1].latitude, longitude: result.routeOrder[result.routeOrder.length - 1].longitude } bounds.extend(new google.maps.LatLng({lat: this.destination.latitude, lng: this.destination.longitude})); this.data.forEach(d => { let dt = { latitude: d.latitude, longitude: d.longitude }; if(!d.start){ this.waypoint.push(dt); } bounds.extend(new google.maps.LatLng({lat: dt.latitude, lng: dt.longitude})); if (d.start == false && d.end == false) { d.pinned = false; this.checkCount++; } }); this.dataUp = this.data; if (this.editmode) { this.initMarkedPins(); } this.primengTableHelper.totalRecordsCount = result.routeOrder.length; this.recordsTemp = result.routeOrder; this.primengTableHelper.records = result.routeOrder; this.map.fitBounds(bounds); this.spinnerService.hide(); this.loading = false; this.routeBuilderFilter.locationFilter = this.locationId; this.routeBuilderFilter.dateFilter = result.routeDate; this.routeBuilderFilter.getLocationsOnLoad(); }); } loadDataOnScroll(event: LazyLoadEvent) { //event.first = First row offset //event.rows = Number of rows per page //event.sortField = Field name to sort with //event.sortOrder = Sort order as number, 1 for asc and -1 for dec //filters: FilterMetadata object having field as key and filter value, filter matchMode as value //imitate db connection over a network if (this.recordsTemp) { console.log(event.first); console.log(event.rows); this.primengTableHelper.records = this.data.slice(event.first, (event.first + event.rows)); } } ngAfterViewInit(): void { } mapReady(event?: any) { this.map = event; } removeDestination(id: number, name: string){ this.message.confirm( "Remove " + name, '', (isConfirmed) => { if (isConfirmed) { this._routeBuilderAppService.removeDestinationDetail(id) .subscribe(r=>{ this.getDetails(); this.spinnerService.hide(); this.notify.info(this.l('RemovedSuccessfully')); }); } } ); } rowReorder(event){ this.data = []; if (this.orderList.length > 0) { let routeList: any = this.orderList; var index = 0; routeList.sort((a, b) => a.sortOrder - b.sortOrder).forEach((item) => { var dataIndex = this.primengTableHelper.records.findIndex(r => r.orderId == item.orderId); var data = this.primengTableHelper.records.find(r => r.orderId == item.orderId); this.primengTableHelper.records.splice(dataIndex, 1); this.primengTableHelper.records.splice(index == 0 ? event.dropIndex : index, 0, data); let click: HTMLElement = document.getElementsByClassName('tr-'+item.orderId)[0] as HTMLElement ; click.click(); index = this.primengTableHelper.records.findIndex(r => r.orderId == item.orderId); }); this.dataUp = this.data = this.primengTableHelper.records; } else { for (let index = 0; index < this.primengTableHelper.records.length; index++) { var element = this.primengTableHelper.records[index]; this.data.push(element); } this.dataUp = this.data; } this.changed = true; } markerClick(id: number, lat: number, long: number) { var existItem = this.data.filter(item => item.latitude == lat && item.longitude == long); var markedPin = this.markedData.filter(item => item.id == id); if (markedPin.length == 0) { existItem.forEach(item => { this.markedData.push({ id: item.orderId, index: this.data.findIndex(r => r.orderId == item.orderId) }); [this.data[this.markedData.length], this.data[this.markedData[this.markedData.length - 1].index]] = [this.data[this.markedData[this.markedData.length - 1].index], this.data[this.markedData.length]]; $('.marker-'+ item.orderId).css('background', '#f39c12'); }); } else if (this.markedData[this.markedData.length - 1].id == id && markedPin.length > 0) { existItem.sort((a, b) => a.orderId - b.orderId).forEach(item => { var previndex = this.markedData.find(r => r.id == item.orderId).index; var markedIndex = this.markedData.findIndex(r => r.id == item.orderId); var currIndex = this.data.findIndex(r => r.orderId == item.orderId); [this.data[currIndex], this.data[previndex]] = [this.data[previndex], this.data[currIndex]]; $('.marker-'+ item.orderId).css('background', '#bdc3c7'); this.markedData.splice(markedIndex, 1); }); } this.changed = true; } applyEditMode() { localStorage.removeItem('markedRoute'+this.routeId); this.dataUp = this.data; localStorage.setItem('markedRoute'+this.routeId, JSON.stringify(this.markedData)); } editMode(event) { this.editmode = event; this.getDetails(); } onRowSelect(event) { if (event.data.pinned == false) { event.data.pinned = true; } else { event.data.pinned = false; } } initMarkedPins() { let obj = JSON.parse(localStorage.getItem('markedRoute'+this.routeId)); this.markedData = []; if (obj != null) { for (var i = 0; i < obj.length; i++) { var pinIndex = this.data.findIndex(c => c.orderId == obj[i].id); var pinData = this.data.find(c => c.orderId == obj[i].id); if (pinIndex != -1) { obj[i].index = pinIndex; pinData.pinned = true; this.markedData.splice(pinIndex, 0, obj[i]); } } this.reset = true; localStorage.removeItem('markedRoute'+this.routeId); localStorage.setItem('markedRoute'+this.routeId, JSON.stringify(this.markedData)); } } resetMarkedPins(resetAll: boolean) { if (resetAll) { if (this.checkCount == this.markedData.length) { localStorage.removeItem('markedRoute'+this.routeId); this.reset = false; } } else { localStorage.removeItem('markedRoute'+this.routeId); this.reset = false; } this.getDetails(); } //Google generalOptimize(opt: number){ this.message.confirm( 'ETA of orders will be modified.', 'Are you sure you want to continue?', (isConfirmed) => { if (isConfirmed) { this.spinnerService.show(); let input = new UpdateRouteByBuilderInput(); input.routeOrder = this.dataUp; this._routeBuilderAppService.generalOptimizeBuilder(opt, input).subscribe(r=>{ this.resetMarkedPins(false); this.notify.info(this.l('SavedSuccessfully')); }); } } ); } updateETAOnly(){ if(this._isLab){ this.message.confirm( 'Will Call ETA will not be reverted', 'Are you sure you want to continue?', (isConfirmed) => { if (isConfirmed) { this.spinnerService.show(); let input = new UpdateEtaInput(); input.locationId = this.locationId; input.routeId = this.routeIdA; input.routeTemplateId = this.dataUp[1].routeTemplateId; this._routeOptimization.updateEta(input).subscribe(r=>{ let x = new OptimizeRouteInput({routeId : this.routeIdA}); this._routeOptimization.reSortByEtaLab(x).subscribe(result=>{ this.resetMarkedPins(false); this.notify.info(this.l('SavedSuccessfully')); }); }); } } ); } } //Google buildRoute(){ this.spinnerService.show(); let input = new UpdateRouteByBuilderInput(); input.routeOrder = this.dataUp; this._routeBuilderAppService.buildRoute(input).subscribe(r=>{ this.resetMarkedPins(false); this.notify.info(this.l('SavedSuccessfully')); }); } //Local buildRouteLocal(){ this.spinnerService.show(); let input = new UpdateRouteByBuilderInput(); input.routeOrder = this.dataUp; this._routeBuilderAppService.buildRouteLocal(input) .subscribe(r=>{ this.resetMarkedPins(false); this.notify.info(this.l('SavedSuccessfully')); }); } //Google saveOptimize(){ this.spinnerService.show(); let input = new UpdateRouteByBuilderInput(); if (this.editmode == true) { this.applyEditMode(); } input.routeOrder = this.dataUp; this._routeBuilderAppService.saveSortingRouteBuilder(input) .subscribe(r=>{ this.changed = false; this.resetMarkedPins(true); this.notify.info(this.l('SavedSuccessfully')); }); } //Local localSaveOptimize(){ this.spinnerService.show(); let input = new UpdateRouteByBuilderInput(); if (this.editmode == true) { this.applyEditMode(); } input.routeOrder = this.dataUp; this._routeBuilderAppService.saveSortingRouteBuilderLocal(input) .subscribe(r=>{ this.changed = false; this.resetMarkedPins(true); this.getDetails(); this.notify.info(this.l('SavedSuccessfully')); }); } //Google localNearestToFurthest(){ this.spinnerService.show(); let input = new UpdateRouteByBuilderInput(); input.routeOrder = this.dataUp; this._routeBuilderAppService.buildRouteLocalNearToFar(input).subscribe(r=>{ this.resetMarkedPins(false); this.notify.info(this.l('SavedSuccessfully')); }); } //Local nearestToFurthest(){ this.spinnerService.show(); let input = new UpdateRouteByBuilderInput(); input.routeOrder = this.dataUp; this._routeBuilderAppService.buildRouteNearToFar(input).subscribe(r=>{ this.resetMarkedPins(false); this.notify.info(this.l('SavedSuccessfully')); }); } //Google furthestToNearest(){ this.spinnerService.show(); let input = new UpdateRouteByBuilderInput(); input.routeOrder = this.dataUp; this._routeBuilderAppService.buildRouteReverse(input) .subscribe(r=>{ this.resetMarkedPins(false); this.notify.info(this.l('SavedSuccessfully')); }); } //Local localFurthestToNearest(){ this.spinnerService.show(); let input = new UpdateRouteByBuilderInput(); input.routeOrder = this.dataUp; this._routeBuilderAppService.buildRouteLocalReverse(input) .subscribe(r=>{ this.resetMarkedPins(false); this.notify.info(this.l('SavedSuccessfully')); }); } inverse() { this.spinnerService.show(); let input = new UpdateRouteByBuilderInput(); input.routeOrder = this.reverse(this.dataUp); this.spinnerService.hide(); this._routeBuilderAppService.saveSortingRouteBuilder(input) .subscribe(r=>{ this.resetMarkedPins(false); this.notify.info(this.l('SavedSuccessfully')); }); } localInverse() { this.message.confirm( 'ETA of orders will be modified.', 'Are you sure you want to continue?', (isConfirmed) => { if (isConfirmed) { this.spinnerService.show(); let input = new UpdateRouteByBuilderInput(); input.routeOrder = this.reverse(this.dataUp); this._routeBuilderAppService.generalOptimizeBuilder(1, input) .subscribe(r=>{ this.resetMarkedPins(false); this.notify.info(this.l('SavedSuccessfully')); }); } } ); } reverse(arr = []) { let t = arr[0].eta; let ti = arr[0].etaString; if(arr[0].orderId == 0){ var arrRev = arr.reverse(); [arrRev[0], arrRev[arr.length - 1]] = [arrRev[arr.length - 1], arrRev[0]]; }else{ var arrRev = arr.reverse(); let temp = arrRev[0]; arrRev.splice(0, 1); arrRev.push(temp); arrRev[0].eta = t; arrRev[0].etaString = ti; } return arrRev; } etaLock(i,b){ this.primengTableHelper.records[i].lockEta = b; } updateEta(record){ this.UpdateEtaRouteBuilder.show(record.destinationDetailsId, this.locationId,record.etaString, record.addressId, record.latitude, record.longitude); } checkData(event, record){ if(record.start) { if(event.target.checked){ this.templateToUp = record.routeTemplateId; }else{ this.templateToUp = undefined; } } else if(record.end) { if(event.target.checked){ this.templateToUp = record.routeTemplateId; }else{ this.templateToUp = undefined; } } else { if(event.target.checked){ this.orderList.push(record.orderId); this.destinationId = record.destinationDetailsId; this.eta = record.etaString; }else{ const index = this.orderList.indexOf(record.orderId, 0); if (index > -1) { this.orderList.splice(index, 1); } this.orderToUp = undefined; this.destinationId = undefined; this.eta = undefined; } } } isHasSameCoordinate(lat,lng){ let c = this.data.filter(d=>d.latitude == lat && d.longitude == lng).length; if(c > 1){ return true; }else{ return false; } } } // just an interface for type safety. interface marker { lat: number; lng: number; label?: string; draggable: boolean; icon?: { path: string; fillColor: string; fillOpacity: number; strokeColor: string; strokeWeight: number; scale: number; labelOrigin: { x: number; y: number; } }; driverName: string; orderId:string; eta:string; color?:string; companyName?:string; geocode?:number; vehicleColor?:string; statusCode?:string; statusTime?:string; statusDescription?:string; pickUpTime?:string; account?:string; routeCode?:string; orderType?:string; deliveryTime?:string; }