import { Component, ElementRef, EventEmitter, Input, OnDestroy, Output, ViewChild, ViewEncapsulation, } from '@angular/core'; import { Subject } from 'rxjs'; import { ChangeContext, Options } from '@angular-slider/ngx-slider'; import { ImageCropperComponent, ImageCroppedEvent, CropperPosition, ImageTransform, } from 'ngx-image-cropper'; // modules import { CommonModule } from '@angular/common'; // constants import { LogoChangeConstants } from './utils/constants/logo-change.constants'; // components import { CaNgxSliderComponent } from '../ca-ngx-slider/ca-ngx-slider.component'; // interfaces import { IFileConfig } from '../ca-upload-files/components/ca-upload-dropzone/interfaces'; // enums import { LogoChangeEnum } from './enums'; import { FileHelpers } from '../../utils/helpers/file.helpers'; @Component({ selector: 'app-ca-logo-change', imports: [CommonModule, CaNgxSliderComponent, ImageCropperComponent], encapsulation: ViewEncapsulation.ShadowDom, templateUrl: './ca-logo-change.component.html', styleUrls: ['./ca-logo-change.component.scss'] }) export class CaLogoChangeComponent implements OnDestroy { @ViewChild('fileInput') fileInput!: ElementRef; @Input() customClass: string | null = null; @Input() imageToCrop!: string | undefined; @Input() isRoundCropper: boolean = false; @Input() imageChangedEvent: Event | null = null; @Input() isDropzoneShown: boolean = false; @Input() hasBlobUrl: boolean = false; @Input() initialCropperPosition: CropperPosition = LogoChangeConstants.INITIAL_CROPPER_POSITION; @Input() containWithinAspectRatio: boolean = false; @Input() aspectRatio: number[] = [1, 1]; @Input() customWidth!: string; @Output() sendImageData = new EventEmitter<{ files: IFileConfig[]; action: string; }>(); private destroy$ = new Subject(); public imageUrl: string | null = null; public imageScale: number = 1; public hasSavedImage: boolean = false; public croppedImage: string | null = null; public cropperPosition: CropperPosition = { ...this.initialCropperPosition, }; public ngxLogoOptions: Options = LogoChangeConstants.LOGO_CHANGE_SLIDER_DATA; public ngxSliderPosition = 1; public transform: ImageTransform = { scale: 1, }; public fileChangeEvent(event: Event): void { this.imageChangedEvent = event; } public imageCropped(event: ImageCroppedEvent): void { this.croppedImage = event.base64 || ''; } public onCancel(): void { this.imageChangedEvent = null; this.imageUrl = null; this.croppedImage = null; this.imageToCrop = ''; this.hasSavedImage = false; if (this.fileInput) { this.fileInput.nativeElement.value = null; } this.sendImageData.emit({ files: [], action: 'delete' }); } public saveImage(): void { if (this.croppedImage) { if (this.hasBlobUrl) { const filesArray: IFileConfig[] = []; const base64 = this.croppedImage; const file = FileHelpers.base64ToFile( base64, LogoChangeEnum.CROPPED_IMAGE_PNG ); const blobUrl = URL.createObjectURL(file); this.imageToCrop = base64; this.hasSavedImage = true; filesArray.push({ url: blobUrl, realFile: file }); this.sendImageData.emit({ files: filesArray, action: LogoChangeEnum.REPLACE, }); } else { const filesArray: IFileConfig[] = []; const rawBlobUrl = this.croppedImage; this.imageToCrop = rawBlobUrl; this.hasSavedImage = true; filesArray.push({ url: rawBlobUrl }); this.sendImageData.emit({ files: filesArray, action: LogoChangeEnum.REPLACE, }); } } else { console.error('No cropped image available to save.'); } } public onZoomChange(event: number | ChangeContext): void { const zoomFactor = event as number; this.transform = { ...this.transform, scale: zoomFactor, }; } ngOnDestroy(): void { this.destroy$.next(); this.destroy$.complete(); } }