// Angular import { Pipe, PipeTransform, OnDestroy, ChangeDetectorRef, NgZone } from '@angular/core'; /** * https://github.com/AndrewPoyntz/time-ago-pipe * An Angular pipe for converting a date string into a time ago * * Example : * Last {{ date | kTimeElapsed}} ago */ @Pipe({ name: 'kTimeElapsed' }) export class TimeElapsedPipe implements PipeTransform, OnDestroy { private _timer: number; /** * Pipe Constructor * * @param changeDetectorRef: ChangeDetectorRef * @param ngZone: NgZone */ constructor( private changeDetectorRef: ChangeDetectorRef, private ngZone: NgZone ) {} /** * @ Lifecycle sequences => https://angular.io/guide/lifecycle-hooks */ ngOnDestroy(): void { this.removeTimer(); } /** * Transform * * @param value: string time * @param textBefore: string - text Before calculated time * @param textAfter: string - text after calculated time */ transform(value: string, textBefore?: string, textAfter?: string): string { this.removeTimer(); let timeElapsed: string = ''; if (!value) { return timeElapsed; } const d = new Date(value); const now = new Date(); const seconds = Math.round(Math.abs((now.getTime() - d.getTime()) / 1000)); const timeToUpdate = this.getSecondsUntilUpdate(seconds) * 1000; this._timer = this.ngZone.runOutsideAngular(() => { if (typeof window !== 'undefined') { return window.setTimeout(() => { this.ngZone.run(() => this.changeDetectorRef.markForCheck() ); }, timeToUpdate); } return null; }); const minutes = Math.round(Math.abs(seconds / 60)); const hours = Math.round(Math.abs(minutes / 60)); const days = Math.round(Math.abs(hours / 24)); const months = Math.round(Math.abs(days / 30.416)); const years = Math.round(Math.abs(days / 365)); if (seconds <= 45) { timeElapsed = 'just now'; } else if (seconds <= 90) { timeElapsed = `${textBefore} 1 min ${textAfter}`; } else if (minutes <= 45) { timeElapsed = `${textBefore} ${minutes} mins ${textAfter}`; } else if (minutes <= 90) { timeElapsed = `${textBefore} 1 hr ${textAfter}`; } else if (hours <= 22) { timeElapsed = `${textBefore} ${hours} hrs ${textAfter}`; } else if (hours <= 36) { timeElapsed = `${textBefore} 1 day ${textAfter}`; } else if (days <= 25) { timeElapsed = `${textBefore} ${days} days ${textAfter}`; } else if (days <= 45) { timeElapsed = `${textBefore} 1 month ${textAfter}`; } else if (days <= 345) { timeElapsed = `${textBefore} ${months} months ${textAfter}`; } else if (days <= 545) { timeElapsed = `${textBefore} 1 year ${textAfter}`; } else { // (days > 545) timeElapsed = `${textBefore} ${years} years ${textAfter}`; } return this.capitalizeFirstLetter(timeElapsed); } /** * Remove _timer */ private removeTimer(): void { if (this._timer) { window.clearTimeout(this._timer); this._timer = null; } } /** * Returns Seconds Until Update * @param seconds: number */ private getSecondsUntilUpdate(seconds: number): number { const min = 60; const hr = min * 60; const day = hr * 24; if (seconds < min) { // less than 1 min, update ever 2 secs return 2; } else if (seconds < hr) { // less than an hour, update every 30 secs return 30; } else if (seconds < day) { // less then a day, update every 5 mins return 300; } else { // update every hour return 3600; } } private capitalizeFirstLetter(str: string): string { return str.charAt(0).toUpperCase() + str.slice(1); } }