<repo_name>princenishchal/tllr<file_sep>/src/pages/transdetail/transdetail.ts
import { Component, Input, ViewChild, ElementRef, Renderer2, NgZone, ChangeDetectorRef} from '@angular/core';
import { NavController, NavParams, AlertController, Platform, Events } from 'ionic-angular';

/**
 * import pages here 
 */
import {TransdetailChatPage} from './transdetail-chat/transdetail-chat';
import {SendLocationPage} from '../send-location/send-location'
import {SelectPhotosPage} from '../select-photos/select-photos';
import {ImagePreviewPage} from '../image-preview/image-preview';
import {Observable} from 'rxjs';


@Component({
  selector: 'page-transdetail',
  templateUrl: 'transdetail.html',
})
export class TransdetailPage {
	// the main transaction details object.
	transactionDetails:any = {
		photos:null,
		location:null,
		friends:[],
		chat:{}
	}
	chatPage = TransdetailChatPage;
	chatParams = {}; 
	@ViewChild('transDetailBlock') transDetailBlock:ElementRef;
	@ViewChild('transDetailTags') transDetailTags:ElementRef;
	@ViewChild('transDetailTagSpan') transDetailTagSpan:ElementRef;
	@ViewChild('transDetailNotes') transDetailNotes:ElementRef;
	@ViewChild('transDetailNotesSpan') transDetailNotesSpan:ElementRef;
	@ViewChild('chatsDetailBlock') chatsDetailBlock:ElementRef;
	@ViewChild('tagFriendsDivBlock') tagFriendsDivBlock:ElementRef;

	constructor(private ref:ChangeDetectorRef,   public navCtrl: NavController, public navParams: NavParams, public alertCtrl: AlertController, public renderer: Renderer2) {


	}

	ionViewDidLoad() {
		console.log('ionViewDidLoad TransdetailPage');
	}

	// pushes the add photos page with a call back to do processing after the photos have been collected
	selectPhotos(){
		this.navCtrl.push(SelectPhotosPage,{
			callback:(photos)=>{
				
				return new Promise((resolve,reject)=>{

			
				let photostoUpload = photos.map(p=>{
					return p.blob
				});


				this.transactionDetails.photos = photos.map(p=> {
					return	p.src
				});
				//TODO: upload images and then show them in the images.
				
				resolve();
				this.ref.detectChanges();
			})
			}
		})
	}

	// fetches a location object and shows it in the transaction details page
	addLocation(){
		this.navCtrl.push(SendLocationPage,{
			callback:(location)=>{
				return new Promise((resolve,reject)=>{

					//TODO: uplaod the location and then add it to the local object
					console.log(location)
					this.transactionDetails.location = location;

				 resolve();
				})
			}
		})
	}


	previewImages(images,startAt){
		this.navCtrl.push(ImagePreviewPage,{
			images:images,
			startAt:startAt,
			title:"chic-fill-a"
		})
	}





}

<file_sep>/src/providers/chat-service/chat-service.ts

import { Injectable } from '@angular/core';
import { Socket } from 'ng-socket-io';
import {Observable,Subject} from 'rxjs'

/*
  Generated class for the ChatServiceProvider provider.

  See https://angular.io/guide/dependency-injection for more info on providers
  and Angular DI.
*/
@Injectable()
export class ChatServiceProvider {
  private  // messages queued in thread
  private _newMessage:Subject<any>;
  newMessage:Observable<any>;

  


  constructor(private socket:Socket) {
    console.log('Hello ChatServiceProvider Provider');
    this._newMessage = new Subject<any>();
    this.newMessage =  this._newMessage.asObservable();
  


    this.socket.on('message',(message)=>{
      this._newMessage.next(message);
    })


  }

  send(message){
    //TODO; do something with the message object
    this.socket.emit('message',message);
  }

}
<file_sep>/src/pages/select-photos/select-photos.ts
import { Component, ChangeDetectorRef } from '@angular/core';
import { DomSanitizer } from '@angular/platform-browser';
import { NavController, NavParams } from 'ionic-angular';
declare var cordova: any;
import { PhotoLibrary, LibraryItem, GetLibraryOptions, } from '@ionic-native/photo-library';
import { Subject } from 'rxjs';

/**
 * Generated class for the SelectPhotosPage page.
 *
 * See https://ionicframework.com/docs/components/#navigation for more info on
 * Ionic pages and navigation.
 */

@Component({
  selector: 'page-select-photos',
  templateUrl: 'select-photos.html',
})
export class SelectPhotosPage {
  images = [];
  private gallaryImages = null;
  private pauser: Subject<boolean>; // used for pausing the library sequesnce
  private infiniteScrollHandle: any;
  private page = 0;
  private chunk = 30;
  private callback: Function; // a pomise type function 
  listNotEmpty: boolean;
  isLoading: boolean = true;
  constructor(public navCtrl: NavController, public navParams: NavParams, private photoLibrary: PhotoLibrary, private changeRef: ChangeDetectorRef, private sanitizer: DomSanitizer) {

    this.callback = this.navParams.data.callback;

    /**
  * TODO : remove this after testing 
  */


    /* this.images = new Array(100).fill({
       creationDate:Date.now(),
       thumbnailURL: "https://placeholdit.co//i/71x76?&bg=9b9b9b"
     }).map((img,index,arr)=>{
       img.index = index;
       return img
     }) */

    this.listNotEmpty = false;
    let opts: GetLibraryOptions = {};
    opts.thumbnailHeight = 76;
    opts.thumbnailWidth = 71;
    opts.includeAlbumData = true;

    this.photoLibrary.requestAuthorization().then(() => {
      this.photoLibrary.getLibrary(opts).subscribe({
        next: library => {



          /* library.forEach(function(libraryItem) {
             console.log(libraryItem.id);          // ID of the photo
             console.log(libraryItem.photoURL);    // Cross-platform access to photo
             console.log(libraryItem.thumbnailURL);// Cross-platform access to thumbnail
             console.log(libraryItem.fileName);
             console.log(libraryItem.width);
             console.log(libraryItem.height);
             console.log(libraryItem.creationDate);
             console.log(libraryItem.latitude);
             console.log(libraryItem.longitude);
             console.log(libraryItem.albumIds);    // array of ids of appropriate AlbumItem, only of includeAlbumsData was used
           });*/






          this.gallaryImages = library.sort(
            (a: LibraryItem, b: LibraryItem) => {
              return new Date(a.creationDate) >= new Date(b.creationDate) ? -1 : 1;
            }
          );



          this.gallaryImages.slice(this.page * this.chunk, (this.page + 1) * this.chunk).map(img => {

            let imjObj = {
              thumbnailURL: this.sanitizer.bypassSecurityTrustUrl(img.thumbnailURL),
              photoUrl:this.sanitizer.bypassSecurityTrustUrl(img.photoURL),
              fileName: img.fileName,
              id: img.id,
              creationDate: img.creationDate,
              index: this.images.length,
              selected: false
            }
            // sanitize the urls before pushing 

            this.images.push(imjObj);

          })

          console.log(this.images);
          this.page += 1;
          this.isLoading = false;
          this.changeRef.detectChanges();

        },
        error: err => { console.log('could not get photos'); },
        complete: () => { console.log('done getting photos'); }
      });
    })
      .catch(err => console.log('permissions weren\'t granted'));


  }

  doInfinite(infiniteScroll) {
    this.gallaryImages.slice(this.page * this.chunk, (this.page + 1) * this.chunk).map(img => {

      let imjObj = {
        thumbnailURL: this.sanitizer.bypassSecurityTrustUrl(img.thumbnailURL),
        fileName: img.fileName,
        id: img.id,
        creationDate: img.creationDate,
        index: this.images.length
      }
      // sanitize the urls before pushing 

      this.images.push(imjObj);

    })

    infiniteScroll.complete();
    this.page += 1;

    this.changeRef.detectChanges();
  }

  shouldAddStamp(img) {

    if (this.images.length >= 2 && img.index != 0)
      return !this.sameDay(img.creationDate, this.images[img.index - 1].creationDate);
    else
      return true;



  }

  select(index) {
    this.images[index].selected = true;
    this.checkListEmpty();
    this.changeRef.detectChanges();
  }

  unselect(index) {
    this.images[index].selected = false;
    this.checkListEmpty();
    this.changeRef.detectChanges();
  }

  // get actual iamges
  getPhotos() {
    let selectedPhotos = this.images.filter(i => i.selected);

    // fetch photos from the ionic native 
    Promise.all(
      selectedPhotos.map(sp => {
        return this.photoLibrary.getPhoto(sp.id)
      })
    ).then(photos => {
      
        // send back selected photos with local urls 
        
       let imagestoReurn = selectedPhotos.map((sp,i)=>{

         return {
          src: sp.photoUrl,
          blob: photos[i] 
         };

        })

          console.log("photso fetched", imagestoReurn);
          this.callback(imagestoReurn).then(() => {
            this.navCtrl.pop()
          })

      
    })

  }


  private checkListEmpty() {
    this.listNotEmpty = this.images.filter(i => i.selected).length ? true : false;
  }

  private sameDay(date1, date2) {

    let d1 = new Date(date1);
    let d2 = new Date(date2);

    return d1.getFullYear() === d2.getFullYear() &&
      d1.getMonth() === d2.getMonth() &&
      d1.getDate() === d2.getDate();
  }

  ionViewDidLoad() {
    console.log('ionViewDidLoad SelectPhotosPage');
  }

 


}
<file_sep>/src/components/components.module.ts
import { NgModule } from '@angular/core';
import { CommonModule} from '@angular/common';  
import { AvatarComponent } from './avatar/avatar';
import { PlacesAutoCompleteComponent } from './places-auto-complete/places-auto-complete';
import {  IonicModule } from 'ionic-angular';
import { FormsModule } from '@angular/forms';

@NgModule({
	declarations: [AvatarComponent,
    PlacesAutoCompleteComponent],
	imports: [CommonModule,FormsModule, IonicModule],
	exports: [AvatarComponent,
    PlacesAutoCompleteComponent]
})
export class ComponentsModule {}
<file_sep>/README.md
# tllr
# Setup:
 1. clone the master branch
 2. run npm install 
 3. run cordova plugins install
 
 #  Desccription:
 Contains the location picker and select-contacts plugins.
 
 #  TRANSFERING COPONENTS AND SETUP
 1.dependencies:
  1. Make sure that package @ngui/map is installed ( for the maps component)
  2. Make sure cordova-plugin-contacts-phonenumbers is installed via cordova plugin add cordova-plugin-contacts-phonenumbers
        [https://github.com/dbaq/cordova-plugin-contacts-phone-numbers](link to plugin github)
 2.Copying code:
  1. From the app.module.ts file .. copy over the lines marked with  /** COPY THIS */
  2. From the app.scss file , copy over css marked with  /** COPY THIS */
  3. Copy the select-contacts and the location-picker folders into the destiantion , keeping the same hirarchy
 
 # using the components
 1. the location picker is invoked declaratively from a button , link etc via the navPush attribut. In this repo , you will find the example in the home component:
 **<button ion-button [navPush]="pushPage" [navParams]="params">select location</button>**.
 YOU MUST IMPORT THE locationPickerPageComponent in the page from where you are goign to invoke this.
  
 2. when the locaiton picker is invoked and a location is selected , the location picker pushes the select contacts component , passing the selected address to it.
 once the contacts are selected and the continue button is clicked , the **confirm()** function in the component collects the address and selected contacts for passing on. This function has been stubbed for now.
 
 #  Important 
 the contacts page will not work in the browser and will fail, please test it with emulation or a real device.
 
 # Select Photos component
 
 ## plugins used:
 1. ionic native photos - https://ionicframework.com/docs/native/photo-library/   . follow installation steps in the page
 
 ## copy contents
 1. copy the select-photos folder and add component class to app.module.

## notes:
1. The getPhotos function returns an array of photo blobs .. These can be directly uploaded using formData.
2. The photos will not show up in the latest webview (Wk) .. when testing ensure that the app has the older webview .


# add-locaiton
1. copy contents of components folder 
2. install ionic native geolocation , follow steps mentioned 
3. add this config in xml

`<edit-config file="*-Info.plist" mode="merge" target="NSLocationWhenInUseUsageDescription">
        <string>To get your location </string>
    </edit-config>`<file_sep>/src/pages/image-preview/image-preview.ts
import { Component, ViewChild } from '@angular/core';
import { NavController, NavParams ,Slides} from 'ionic-angular';
import { Slide } from 'ionic-angular/components/slides/slide';

/**
 * Generated class for the ImagePreviewPage page.
 *
 * See https://ionicframework.com/docs/components/#navigation for more info on
 * Ionic pages and navigation.
 */

@Component({
  selector: 'page-image-preview',
  templateUrl: 'image-preview.html',
})

export class ImagePreviewPage {
 images:any[];
 private startAt:number;
 title:string= "";
 currentSlide:number;

 @ViewChild('slider') slider :Slides;

  constructor(public navCtrl: NavController, public navParams: NavParams) {
    this.images = navParams.data.images;
    this.startAt = navParams.data.startAt;
    this.title = navParams.data.title;
    this.currentSlide = this.startAt+1;

    
    

  }

  onSlideChange(val){
    
    this.currentSlide = this.slider.getActiveIndex()+1;
  }

}
<file_sep>/src/app/app.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { ErrorHandler, NgModule } from '@angular/core';
import { IonicApp, IonicErrorHandler, IonicModule } from 'ionic-angular';
import { SplashScreen } from '@ionic-native/splash-screen';
import { StatusBar } from '@ionic-native/status-bar';

import { MyApp } from './app.component';
import { HomePage } from '../pages/home/home';
import { TransdetailPage } from '../pages/transdetail/transdetail';



 /** COPY THIS */
import {LocationPickerPage} from '../pages/location-picker/location-picker';
import {SelectContactsPage}  from '../pages/select-contacts/select-contacts'
import { NguiMapModule} from '@ngui/map';
import { EmojifyModule } from 'angular2-emojify';
import { TransdetailChatPage } from '../pages/transdetail/transdetail-chat/transdetail-chat';
import { ChatMessageComponent } from '../pages/transdetail/transdetail-chat/chat-message/chat-message';
import { SelectPhotosPage} from '../pages/select-photos/select-photos';
import {SendLocationPage} from '../pages/send-location/send-location';
import {ImagePreviewPage} from '../pages/image-preview/image-preview';
import { SocketIoModule, SocketIoConfig } from 'ng-socket-io';
import {MomentModule} from 'angular2-moment';
import {PhotoLibrary} from '@ionic-native/photo-library';
import { Geolocation } from '@ionic-native/geolocation';

/** import the components module here */
import {ComponentsModule} from '../components/components.module';

/** COPY this config for socet io */

const config: SocketIoConfig = { url: 'http://finterest.co:5500/', options: {} };


@NgModule({
  declarations: [
    MyApp,
    HomePage,
    LocationPickerPage,
    SelectContactsPage,
    TransdetailPage,
    TransdetailChatPage,
    ChatMessageComponent,
    SelectPhotosPage,
    SendLocationPage,
    ImagePreviewPage
  ],
  imports: [
    BrowserModule,
    IonicModule.forRoot(MyApp),
    /** place api key here */
    /** COPY THIS */
    ComponentsModule,
    MomentModule,
    NguiMapModule.forRoot({apiUrl: 'https://maps.google.com/maps/api/js?v=3&key=<KEY>&libraries=places'}),
    EmojifyModule,
    SocketIoModule.forRoot(config) 
  ],
  bootstrap: [IonicApp],
  entryComponents: [
    MyApp,
    HomePage,
     /** COPY THIS */
    LocationPickerPage,
    SelectContactsPage,
    TransdetailPage,
    TransdetailChatPage,
    ChatMessageComponent,
    SelectPhotosPage,
    SendLocationPage,
    ImagePreviewPage
  ],
  providers: [
    StatusBar,
    SplashScreen,
    {provide: ErrorHandler, useClass: IonicErrorHandler},
    PhotoLibrary,
    Geolocation
  ]
})
export class AppModule {}
<file_sep>/src/pages/select-contacts/select-contacts.ts
import { Component, ChangeDetectorRef } from '@angular/core';
import { NavController, NavParams } from 'ionic-angular';
import { DomSanitizer } from '@angular/platform-browser';
declare var navigator: any;
/**
 * Generated class for the SelectContactsPage page.
 *
 * See https://ionicframework.com/docs/components/#navigation for more info on
 * Ionic pages and navigation.
 */

@Component({
  selector: 'page-select-contacts',
  templateUrl: 'select-contacts.html',
})
export class SelectContactsPage {
  contacts: any[] = []
  private address: any;
  listNotEmpty: boolean = false;
  private infiniteScrollHandle: any;
  private allContacts: any[];
  private searchResults:any[] = [];
  private page = 0;
  private chunk = 30;
  search:string = null;
  isLoading: boolean = true;

  constructor(public navCtrl: NavController, public navParams: NavParams, private changeRef: ChangeDetectorRef, private domsanitizer: DomSanitizer) {
    this.address = navParams.data; // just keep the data here
  }

  ionViewDidLoad() {
    console.log('ionViewDidLoad SelectContactsPage');

    if (navigator.contactsPhoneNumbers)
      navigator.contactsPhoneNumbers.list((contacts: any[]) => {
        this.contacts = [];

        // sort in asc
        this.allContacts = contacts.sort((a, b) => a.displayName >= b.displayName ? 1 : -1).map((ac,i)=>{
          return {
          
            idx: i,
            id: ac.id,
            picture: ac.thumbnail ? this.domsanitizer.bypassSecurityTrustUrl(ac.thumbnail) : null,
            phone: ac.phoneNumbers[0].normalizedNumber,
            name: ac.displayName,
            selected: false
          }
          
        })




        this.allContacts.slice(this.page * this.chunk, (this.page + 1) * this.chunk).map((contact, i) => {

        
          this.contacts.push({
            idx: contact.idx,
            idy: i,
            id: contact.id,
            picture: contact.thumbnail ? this.domsanitizer.bypassSecurityTrustUrl(contact.thumbnail) : null,
            phone: contact.phone,
            name: contact.name,
            selected: contact.selected
          });

        })


        this.page += 1;
        this.isLoading = false;
        this.changeRef.detectChanges();


        this.changeRef.detectChanges();
      }, (error) => {
        console.error(error);
      });

  }

  selectContact(idx,idy) {
    this.allContacts[idx].selected = true;
     if( idy && this.contacts[idy])  this.contacts[idy].selected = true;
     else{
       this.contacts.map((c,i)=>{
         if(c.idx == idx)  this.contacts[i].selected = true;
       })
     }
    this.isListEmpty()
    this.changeRef.detectChanges();
  }

  removeContact(idx,idy) {
    this.allContacts[idx].selected = false;
    if( idy && this.contacts[idy]) this.contacts[idy].selected = false;
    else{
      this.contacts.map((c,i)=>{
        if(c.idx == idx)  this.contacts[i].selected = false;
      })
    }
    this.isListEmpty();
    this.changeRef.detectChanges();
  }

  isListEmpty() {
    this.listNotEmpty = this.contacts.filter(c => c.selected).length ? true : false;
  }

  confirm() {
    // do something with the selected contacts and address
    let dataToSubmit = {
      selectedContacts: this.contacts.filter(c => c.selected == true),
      selectedAddress: this.address
    }
    console.log(dataToSubmit);
    this.navCtrl.popToRoot();
  }


  doInfinite(infiniteScroll) {
    this.allContacts.slice(this.page * this.chunk, (this.page + 1) * this.chunk).map((contact, i) => {
      
                this.contacts.push({
                  idx: contact.idx,
                  idy:i,
                  id: contact.id,
                  picture: contact.thumbnail ? this.domsanitizer.bypassSecurityTrustUrl(contact.thumbnail) : null,
                  phone: contact.phone,
                  name: contact.name,
                  selected: contact.selected
                });
      
              })

    infiniteScroll.complete();
    this.page += 1;

    this.changeRef.detectChanges();
  }

  searchEmployee(name){
    this.searchResults = name? this.allContacts.filter(c=>c.name.indexOf(name) > -1) || [] : [];
  }

  addFromSearch(contact){
    this.searchResults = [];
    this.search = null;
    
    // mark as selected in all contacts 
    this.selectContact(contact.idx, contact.idy || null)

  }

}
<file_sep>/src/pages/home/home.ts
import { Component } from '@angular/core';
import { NavController } from 'ionic-angular';
import {LocationPickerPage} from '../location-picker/location-picker';
import { TransdetailPage } from '../transdetail/transdetail';
import {SelectPhotosPage} from '../select-photos/select-photos';
import {SendLocationPage} from '../send-location/send-location';
import {SelectContactsPage} from '../select-contacts/select-contacts';



@Component({
  selector: 'page-home',
  templateUrl: 'home.html'
})
export class HomePage {
  public params = {}
  public pushPage = LocationPickerPage; // the page to be pushed 
  public pushTransPage = TransdetailPage;
  public photosPage = SelectPhotosPage;
  public sendLocation = SendLocationPage;
  public selectContacts = SelectContactsPage;
 
  constructor(public navCtrl: NavController) {

  }

  

  
}
<file_sep>/src/pages/location-picker/location-picker.ts
import { Component, ChangeDetectorRef } from '@angular/core';
import { NavController, NavParams } from 'ionic-angular';
import {SelectContactsPage} from '../select-contacts/select-contacts'


/**
 * Generated class for the LocationPickerPage page.
 *
 * See https://ionicframework.com/docs/components/#navigation for more info on
 * Ionic pages and navigation.
 */

@Component({
  selector: 'page-location-picker',
  templateUrl: 'location-picker.html',
})
export class LocationPickerPage {

   /** view vars used by ngui-maps */
   autocomplete: any;
   address: any = {};
   center: any = "RR Nagar, Bengaluru, Karnataka, India";
   code: string;
   canContinue = false;

  constructor(public navCtrl: NavController, public navParams: NavParams, private ref: ChangeDetectorRef) {
  }

  ionViewDidLoad() {
    console.log('ionViewDidLoad LocationPickerPage');
  }

  // recenters the map to the location selected from auto complete 
  placeChanged(place) {
    if(place && place.geometry){
    this.center = place.geometry.location;
    for (let i = 0; i < place.address_components.length; i++) {
      let addressType = place.address_components[i].types[0];
      this.address[addressType] = place.address_components[i].long_name;
    }

    this.address.name = place.name;
    this.address.formatted_address = place.formatted_address;
    this.canContinue = true;
    }
    else{
      this.center = {};
      this.address = {};
      this.canContinue = false;
    }

    this.ref.detectChanges();
  }

  checkIfnotEmpty(event){
    if(!event.target.value){
      this.canContinue = false;
    }
  }

  // push in the contacts select page
  confirm(){
    this.navCtrl.push(SelectContactsPage,this.address);
  }

}
<file_sep>/src/pages/transdetail/transdetail-chat/chat-message/chat-message.ts
import { Component,Input } from '@angular/core';


/**
 * Generated class for the ChatMessageComponent component.
 *
 * See https://angular.io/api/core/Component for more info on Angular
 * Components.
 */
@Component({
  selector: 'chat-message',
  templateUrl: 'chat-message.html'
})
export class ChatMessageComponent {

  text: string;
  emojiOnly: string;
  // TODO: get this value from service
  currentUserID:string = '1';
  
  @Input('data') data :any;


  constructor() {
    console.log('Hello ChatMessageComponent Component');
    this.text = `It's a :laughing:`;
    this.emojiOnly = `:laughing:`;

 

  }





}
<file_sep>/src/components/avatar/avatar.ts
import { Component, Input } from '@angular/core';

/**
 * Generated class for the AvatarComponent component.
 *
 * See https://angular.io/api/core/Component for more info on Angular
 * Components.
 */
@Component({
  selector: 'avatar',
  templateUrl: 'avatar.html'
})
export class AvatarComponent {

  initials: string;
  @Input('img') img: any;
  @Input('userName') set getInitials(val) {

    try {
      if (!val || val == "" || val == " ") {
        this.initials = "?";
        return;
      };

      let tmp = val.split(' ');


      switch (tmp.length) {
        case 1: {

          this.initials = tmp[0].length > 1 ? tmp[0].split('')[0].toUpperCase() + tmp[0].split('')[1].toUpperCase() : tmp[0].split('')[0].toUpperCase();
          break;
        }

        case 2: {

          // make sure the second character is not a special character

          this.initials = new RegExp(/[a-zA-Z]/).test(tmp[1].split('1')[0]) ? tmp[0].split('')[0].toUpperCase() + tmp[1].split('')[0].toUpperCase() : tmp[0].split('')[0].toUpperCase() + tmp[0].split('')[1].toUpperCase()
          break;
        }

        case 0: {
          this.initials = "?";
          break;
        }


        default: {

          // make sure the second character is not a special character

          this.initials = new RegExp(/[a-zA-Z]/).test(tmp[1].split('1')[0]) ? tmp[0].split('')[0].toUpperCase() + tmp[1].split('')[0].toUpperCase() : tmp[0].split('')[0].toUpperCase() + tmp[0].split('')[1].toUpperCase()
          break;
        }

      }

    }
    catch (e) {
      this.initials = "?";
      console.log('error with initials :', val)
    }


  }


  constructor() {
    console.log('Hello AvatarComponent Component');

  }

}
<file_sep>/src/pages/transdetail/transdetail-chat/transdetail-chat.ts
import { Component,ViewChild , ElementRef} from '@angular/core';
import { NavController, NavParams } from 'ionic-angular';
import { Observable } from 'rxjs';
import {ChatServiceProvider} from "../../../providers/chat-service/chat-service"




/**
 * Generated class for the TransdetailChatPage page.
 *
 * See https://ionicframework.com/docs/components/#navigation for more info on
 * Ionic pages and navigation.
 */

@Component({
  selector: 'page-transdetail-chat',
  templateUrl: 'transdetail-chat.html',
  providers: [ChatServiceProvider]
})
export class TransdetailChatPage {

 
  chatName = "some random place";
  private TransId: string ;
  userDisplayName = "<NAME>";
  currentUserID = 1; // this should come from a service or localstorage 
  message = '';
  
   
  
    // actual messages shown in the window.
  
    chatMessages:any = [];
    private chatSubscription:any;
  constructor(public navCtrl: NavController, public navParams: NavParams, private chatService: ChatServiceProvider) {

    // get the trans id 

    this.TransId = this.navParams.data.transactionID; 

    // pre-populate the chat page with data received in navparams.

    let chatHistory = navParams.data.chatHistory;
    

    

    if(chatHistory && chatHistory.length){
      chatHistory.map(chat=> this.onMessage(chat));
    }


      // start listening for new chats 
    this.chatSubscription = chatService.newMessage.subscribe(message=>{
       this.onMessage(message);
     });

     

  }

  ionViewDidLoad() {
    console.log('ionViewDidLoad TransactionDetailsChatPage');
  }


  shouldAddStamp(message,index){

     if(this.chatMessages.length >=2 && index!= 0 )
      return !this.sameDay(message.time, this.chatMessages[index-1].time );
     else 
      return true;

    

  }

 

  private  sameDay(date1, date2) {

   let d1 = new Date(date1);
   let d2 = new Date(date2);

    return d1.getFullYear() === d2.getFullYear() &&
      d1.getMonth() === d2.getMonth() &&
      d1.getDate() === d2.getDate();
  }

  // add the message in the chat window 
  onMessage(message) {
    
    
      // create a new chat message object 
    
      let chatMessageObj ={
        displayName: message.displayName,
        userID: message.userID,
        time: message.time,
        data : [{
         payload:  message.data,
         messageType : message.messageType
        }]
      }

      console.log(chatMessageObj)
    
        switch(this.chatMessages.length!=0){
          case false: {
            // push the existing chat message 
            this.chatMessages.push(chatMessageObj)
            break;
          }
    
          case true: {
                // if it's a message from the same user .. add it to the existing chat message obj
                switch(chatMessageObj.userID === this.chatMessages[this.chatMessages.length-1].userID){
    
                  case true:{
                    // push the message into an existing chat message
                    this.chatMessages[this.chatMessages.length-1].data.push(chatMessageObj.data[0]);
                    break;
                  }
    
                  case false:{
                    this.chatMessages.push(chatMessageObj);
                  }
    
                }
          }
    
    
        }

        this.scrollToBottom()
    
      }

      sendMessage(message,type){

      

        let chatMessageObj ={
          displayName: this.userDisplayName,
          userID: this.currentUserID,
          messageType :  new RegExp(/^@|:$/).test(message.trim()) == true ? 'emoji-only' : 'text' ,
          data: message.trim(),
          transactionID: this.TransId,
          time:Date.now()
        }


        // send the message via the chat service :
        this.chatService.send(chatMessageObj);
        // clear the text area
        this.message = '';

        /**TODO: remove below code  */
        /** emulate other person talking  */

        let chatMessageObj2 ={
          displayName: "<NAME>",
          userID: 2,
          messageType :  new RegExp(/^@|:$/).test(message.trim()) == true ? 'emoji-only' : 'text' ,
          data: message.trim(),
          transactionID: this.TransId,
          time:Date.now()
          
        }

        this.chatService.send(chatMessageObj2);

      }

      scrollToBottom(){
        var element = document.getElementById("myScrollLabel");
        setTimeout(()=>{element.scrollIntoView(true)},100); 
      }

      getDateStamp(date){
        let d = new Date(date);
        return d;
      }
}
