import { CommonModule } from '@angular/common'; import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, QueryList, TemplateRef, ViewChildren, } from '@angular/core'; import moment from 'moment'; //Pipes import { CurrencyFormatPipe, ProgressExpirationAbsPipe, ProgressExpirationWidthPipe, TimeFormatPipe, } from './pipes'; //Utils import { ProgressExpirationConstants } from './utils'; //Models import { ProgressExpiration, ProgressExpirationColor, ProgressExpirationTitle, } from './models'; //Enum import { TimeUnits } from './enums'; //Directives import { TemplateContainerDirective } from '../ca-upload-files/components/ca-upload-dropzone/directives'; //Helpers import { ProgressExpirationHelper } from './helpers'; @Component({ imports: [ //Modules CommonModule, //Pipes CurrencyFormatPipe, TimeFormatPipe, //Directive TemplateContainerDirective ], providers: [ProgressExpirationWidthPipe, ProgressExpirationAbsPipe], selector: 'lib-ca-progress-expiration', templateUrl: './ca-progress-expiration.component.html', styleUrls: ['./ca-progress-expiration.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush }) export class CaProgressExpirationComponent { @ViewChildren(TemplateContainerDirective) templateRef!: QueryList; @Input() set config(data: ProgressExpiration[]) { setTimeout(() => { this._configArray = data; if (this._configArray.length > 0) { this._config = this._configArray[0]; } // Default title this.setTitleBasedOnConfig(); // Calculate the total days this.calculateDays(); this.setProgressWidth(); // set backgroundColor this.setBackgroundColor(); // set title this.setTitle(this._config); this.cdr.markForCheck(); }, 0); } public _config!: ProgressExpiration; public title!: ProgressExpirationTitle; public _configArray: ProgressExpiration[] = []; public totalDays: number = 0; public leftDays: number = 0; public progressWidth: string = '0%'; public progressBackgroundColor!: ProgressExpirationColor; constructor( private progressExpirationWidthPipe: ProgressExpirationWidthPipe, private progressExpirationAbsPipe: ProgressExpirationAbsPipe, private cdr: ChangeDetectorRef ) {} private calculateDays(): void { this.totalDays = ProgressExpirationHelper.calculateTotalDays( this._config.startDate ?? new Date(), this._config.expireDate, this._config?.completedDate ); this.leftDays = ProgressExpirationHelper.calculateLeftDays( this._config.expireDate, this._config?.completedDate ); } private setProgressWidth(): void { this.progressWidth = this.progressExpirationWidthPipe.transform( this._config.startDate ?? new Date(), this._config.expireDate, this._config?.completedDate ); } private setTitleBasedOnConfig(): void { if (this._config?.customTitle) { this.title = { ...this.title, before: this._config.customTitle, }; } else { this.setTitle(this._config); } } private generateTitle( data: ProgressExpiration, leftDays: number ): ProgressExpirationTitle { let before: string = ''; let after: string = ''; let days: string = ''; if (data.template === 'location') { const now = moment().utc(); const expireDate = moment(data.expireDate).utc(); const daysUntilExpiration = expireDate.diff(now, 'days'); before = daysUntilExpiration <= 7 ? 'Weekly Rent' : 'Monthly Rent'; } else if (data.completedDate) { if (moment(data.completedDate).utc().isBefore(data.expireDate)) { before = 'Completed'; after = `before deadline`; this.progressBackgroundColor = ProgressExpirationConstants.ProgressExpirationColors[ 'IN_TIME_DURATION' ]; } else if (moment(data.completedDate).utc().isSame(data.expireDate)) { before = 'Completed'; this.progressBackgroundColor = ProgressExpirationConstants.ProgressExpirationColors[ 'IN_TIME_DURATION' ]; } else { before = 'Completed'; after = `past deadline`; this.progressBackgroundColor = ProgressExpirationConstants.ProgressExpirationColors[ 'EXPIRED_DURATION' ]; } } else { if (data.template === 'todo-list') { before = moment(data.expireDate).utc().isAfter(moment().utc()) ? 'Deadline in' : 'Deadline was'; after = before === 'Deadline in' ? '' : 'ago'; } else { before = moment(data.expireDate).utc().isAfter(moment().utc()) ? 'Exp. in' : 'Exp. was'; after = before === 'Exp. in' ? '' : 'ago'; } } if (leftDays) { days = `${leftDays} ${leftDays > 1 ? TimeUnits.DAYS : TimeUnits.DAY}`; } else { const hours = ProgressExpirationHelper.calculateHours( data.expireDate, data.startDate! ); days = `${hours} ${hours > 1 ? TimeUnits.HOURS : TimeUnits.HOUR}`; } return { before, days, after, }; } private setTitle(data: ProgressExpiration): void { const leftDaysFormatted = this.progressExpirationAbsPipe.transform( this.leftDays ); this.title = this.generateTitle(data, leftDaysFormatted); } private setBackgroundColor(): void { // Checking if the time has expired if (this.leftDays <= 0) { this.progressBackgroundColor = ProgressExpirationConstants.ProgressExpirationColors[ 'EXPIRED_DURATION' ]; this.progressWidth = '0%'; return; } let percentageLeft: number = 0; if (this._config.template === 'location') { const daysInMonth = ProgressExpirationHelper.calculateDaysInCurrentMonth(); percentageLeft = this.leftDays < 7 ? (this.leftDays / 7) * 100 // Weekly : (this.leftDays / daysInMonth) * 100; // Monthly } else { percentageLeft = (this.leftDays / this.totalDays) * 100; // For other templates } if (percentageLeft > 50) { this.progressBackgroundColor = ProgressExpirationConstants.ProgressExpirationColors['LONG_DURATION']; } else if (percentageLeft > 20) { this.progressBackgroundColor = ProgressExpirationConstants.ProgressExpirationColors['MEDIUM_DURATION']; } else { this.progressBackgroundColor = ProgressExpirationConstants.ProgressExpirationColors['SHORT_DURATION']; } this.progressWidth = `${percentageLeft}%`; } //Template public getTemplate(template: string): TemplateRef { const templateRef: TemplateContainerDirective | undefined = this.templateRef?.find((temp) => temp.id === template); if (!templateRef) { throw new Error('Unavailable template!'); } return templateRef?.template as TemplateRef; } public identify(index: number): number { return index; } }