import { ChangeDetectionStrategy , Component , EventEmitter , Input , OnDestroy , OnInit , Output , } from '@angular/core' ; import { BehaviorSubject , Observable , of } from 'rxjs' ; import { ApiResponse , ApiService } from '../../../../common/api/api.service' ; import { debounceTime , map , switchAll } from 'rxjs/operators' ; /**
 * Output binding response
 */ export interface LocationTypeaheadResponse { location : string ; coordinates ? : string ; } /**
 * Channel location typeahead input component
 */ @ Component ( { selector : 'm-channel__locationTypeahead' , changeDetection : ChangeDetectionStrategy . OnPush , templateUrl : 'location-typeahead.component.html' , } ) export class ChannelLocationTypeaheadComponent implements OnInit , OnDestroy { /**
     * Location state
     */ location : string = '' ; param location private @ Input ( 'location' ) set _location ( location ) { this . onLocationChange ( location , false ) ; } /**
     * Location change emitter
     */ @ Output ( 'locationChange' ) locationChangeEmitter : EventEmitter < LocationTypeaheadResponse > = new EventEmitter < LocationTypeaheadResponse > ( ) ; /**
     * Current suggestion query
     */ readonly locationSuggestionQuery$ : BehaviorSubject < string > = new BehaviorSubject < string > ( '' ) ; /**
     * Suggestions array from API
     */ readonly locationSuggestions$ : Observable < Array < LocationTypeaheadResponse > > ; /**
     * Is the dropdown open?
     */ readonly isOpen$ : BehaviorSubject < boolean > = new BehaviorSubject < boolean > ( false ) ; /**
     * Timer for dropdown close operation
     */ protected dropdownCloseTimer : any ; /**
     * Dirty flag for manual set
     */ protected dirty : boolean = false ; param api constructor ( protected api ) { this . locationSuggestions$ = this . locationSuggestionQuery$ . pipe ( debounceTime ( 300 ) , map ( locationSuggestionQuery => this . fetch ( locationSuggestionQuery ) ) , switchAll ( ) , map ( response => { if ( ! response || ! response . results ) { return [ ] ; } return response . results . map ( entry => this . fromApiResponse ( entry ) ) . filter ( Boolean ) ; } ) ) ; } /**
     * Component initialization
     */ ngOnInit ( ) { if ( ! this . location ) { this . dirty = true ; } } /**
     * Component destruction
     */ ngOnDestroy ( ) { if ( this . dropdownCloseTimer ) { clearTimeout ( this . dropdownCloseTimer ) ; } } param q protected fetch ( q ) { if ( ! q ) { return of ( null ) ; } return this . api . get ( 'api/v1/geolocation/list' , { q } ) ; } param data protected fromApiResponse ( data ) { if ( ! data || ( ! data . address . city && ! data . address . state ) ) { return null ; } return { location : [ data . address . city , data . address . state ] . filter ( Boolean ) . join ( ', ' ) , coordinates : `${ data . lat },${ data . lon }` , } ; } param location param markAsDirty onLocationChange ( location , markAsDirty = true ) { this . location = location ; this . locationSuggestionQuery$ . next ( location ) ; if ( markAsDirty ) { this . dirty = true ; } } param location param emit setLocation ( location , emit = true ) { this . location = location . location ; this . locationSuggestionQuery$ . next ( '' ) ; if ( emit ) { this . locationChangeEmitter . emit ( location ) ; } } /**
     * Opens the dropdown
     */ onInputFocus ( ) { if ( this . dropdownCloseTimer ) { clearTimeout ( this . dropdownCloseTimer ) ; } this . isOpen$ . next ( true ) ; } /**
     * Sets a manual location when user changes the dropdown focus, if dirty flag is set. Closes dropdown.
     */ onInputBlur ( ) { if ( this . dropdownCloseTimer ) { clearTimeout ( this . dropdownCloseTimer ) ; } this . dropdownCloseTimer = setTimeout ( ( ) => { this . isOpen$ . next ( false ) ; } , 200 ) ; if ( this . dirty ) { this . locationChangeEmitter . emit ( { location : this . location , coordinates : '' , } ) ; } } }