image-cropper component, drag & drop bilder

This commit is contained in:
2024-03-29 20:59:34 +01:00
parent 840d7a63b1
commit 89bb85a512
20 changed files with 478 additions and 261 deletions

View File

@@ -56,34 +56,14 @@
</div>
<div class="mb-4">
<label for="companyOverview" class="block font-medium text-900 mb-2">Company Overview</label>
<p-editor [(ngModel)]="user.companyOverview" [style]="{ height: '320px' }">
<ng-template pTemplate="header">
<span class="ql-formats">
<button type="button" class="ql-bold" aria-label="Bold"></button>
<button type="button" class="ql-italic" aria-label="Italic"></button>
<button type="button" class="ql-underline" aria-label="Underline"></button>
<button value="ordered" aria-label="Ordered List" type="button"
class="ql-list"></button>
<button value="bullet" aria-label="Unordered List" type="button"
class="ql-list"></button>
</span>
</ng-template>
<p-editor [(ngModel)]="user.companyOverview" [style]="{ height: '320px' }" [modules]="editorModules">
<ng-template pTemplate="header"></ng-template>
</p-editor>
</div>
<div class="mb-4">
<label for="companyOverview" class="block font-medium text-900 mb-2">Services We offer</label>
<p-editor [(ngModel)]="user.offeredServices" [style]="{ height: '320px' }">
<ng-template pTemplate="header">
<span class="ql-formats">
<button type="button" class="ql-bold" aria-label="Bold"></button>
<button type="button" class="ql-italic" aria-label="Italic"></button>
<button type="button" class="ql-underline" aria-label="Underline"></button>
<button value="ordered" aria-label="Ordered List" type="button"
class="ql-list"></button>
<button value="bullet" aria-label="Unordered List" type="button"
class="ql-list"></button>
</span>
</ng-template>
<p-editor [(ngModel)]="user.offeredServices" [style]="{ height: '320px' }" [modules]="editorModules">
<ng-template pTemplate="header"></ng-template>
</p-editor>
</div>
@@ -126,7 +106,7 @@
<span class="font-medium text-900 mb-2">Company Logo</span>
<span class="font-medium text-xs mb-2">(is shown in every offer)</span>
@if(user.hasCompanyLogo){
<img src="{{environment.apiBaseUrl}}/logo/{{user.id}}.avif" class="rounded-profile" />
<img src="{{companyLogoUrl}}" class="rounded-profile" />
} @else {
<img src="assets/images/placeholder.png" class="rounded-profile" />
}
@@ -138,7 +118,7 @@
<div class="flex flex-column align-items-center flex-or">
<span class="font-medium text-900 mb-2">Your Profile Picture</span>
@if(user.hasProfile){
<img src="{{environment.apiBaseUrl}}/profile/{{user.id}}.avif" class="rounded-profile" />
<img src="{{profileUrl}}" class="rounded-profile" />
} @else {
<img src="assets/images/person_placeholder.jpg" class="rounded-profile" />
}
@@ -212,8 +192,7 @@
</div>
</div>
</div>
<p-dialog header="Edit Image" [visible]="imageUrl" [modal]="true" [style]="{ width: '50vw' }" [draggable]="false" [resizable]="false">
<!-- <app-cropper #cropper [imageUrl]="imageUrl"></app-cropper> -->
<!-- <p-dialog header="Edit Image" [visible]="imageUrl" [modal]="true" [style]="{ width: '50vw' }" [draggable]="false" [resizable]="false">
<angular-cropper #cropper [imageUrl]="imageUrl" [cropperOptions]="config"></angular-cropper>
<ng-template pTemplate="footer" let-config="config">
<div class="flex justify-content-between">
@@ -230,4 +209,4 @@
</div>
</div>
</ng-template>
</p-dialog>
</p-dialog> -->

View File

@@ -32,69 +32,64 @@ import { AngularCropperjsModule, CropperComponent } from 'angular-cropperjs';
import { ImageService } from '../../../services/image.service';
import { DialogModule } from 'primeng/dialog';
import { SelectButtonModule } from 'primeng/selectbutton';
import { DialogService, DynamicDialogModule, DynamicDialogRef } from 'primeng/dynamicdialog';
import { ImageCropperComponent, stateOptions } from '../../../components/image-cropper/image-cropper.component';
import Quill from 'quill'
import { TOOLBAR_OPTIONS } from '../../utils/defaults';
@Component({
selector: 'app-account',
standalone: true,
imports: [SharedModule,FileUploadModule,EditorModule,AngularCropperjsModule,DialogModule,SelectButtonModule],
providers:[MessageService],
imports: [SharedModule, FileUploadModule, EditorModule, AngularCropperjsModule, DialogModule, SelectButtonModule, DynamicDialogModule],
providers: [MessageService, DialogService],
templateUrl: './account.component.html',
styleUrl: './account.component.scss'
})
export class AccountComponent {
@ViewChild(CropperComponent) public angularCropper: CropperComponent;
@ViewChild('companyUpload') public companyUpload: FileUpload;
@ViewChild('profileUpload') public profileUpload: FileUpload;
private id: string | undefined = this.activatedRoute.snapshot.params['id'] as string | undefined;
user:User;
subscriptions:Array<Subscription>;
userSubscriptions:Array<Subscription>=[];
maxFileSize=1000000;
companyLogoUrl:string;
profileUrl:string;
imageUrl;
type:'company'|'profile'
stateOptions:KeyValueRatio[]=[
{label:'16/9',value:16/9},
{label:'1/1',value:1},
{label:'2/3',value:2/3},
]
value:number = this.stateOptions[0].value;
config={aspectRatio: this.value}
environment=environment
constructor(public userService: UserService,
private subscriptionService: SubscriptionsService,
private messageService: MessageService,
private geoService:GeoService,
public selectOptions:SelectOptionsService,
private cdref:ChangeDetectorRef,
private activatedRoute: ActivatedRoute,
private loadingService:LoadingService,
private imageUploadService: ImageService) {
}
async ngOnInit(){
this.user=await this.userService.getById(this.id);
this.userSubscriptions=await lastValueFrom(this.subscriptionService.getAllSubscriptions());
if (!this.user.licensedIn || this.user.licensedIn?.length===0){
this.user.licensedIn = [{name:'',value:''}]
user: User;
subscriptions: Array<Subscription>;
userSubscriptions: Array<Subscription> = [];
maxFileSize = 1000000;
companyLogoUrl: string;
profileUrl: string;
type: 'company' | 'profile'
dialogRef: DynamicDialogRef | undefined;
environment = environment
editorModules = TOOLBAR_OPTIONS
constructor(public userService: UserService,
private subscriptionService: SubscriptionsService,
private messageService: MessageService,
private geoService: GeoService,
public selectOptions: SelectOptionsService,
private cdref: ChangeDetectorRef,
private activatedRoute: ActivatedRoute,
private loadingService: LoadingService,
private imageUploadService: ImageService,
public dialogService: DialogService) {}
async ngOnInit() {
this.user = await this.userService.getById(this.id);
this.userSubscriptions = await lastValueFrom(this.subscriptionService.getAllSubscriptions());
if (!this.user.licensedIn || this.user.licensedIn?.length === 0) {
this.user.licensedIn = [{ name: '', value: '' }]
}
this.user=await this.userService.getById(this.user.id);
this.profileUrl = this.user.hasProfile?`${environment.apiBaseUrl}/profile/${this.user.id}.avif`:`/assets/images/placeholder.png`
this.companyLogoUrl = this.user.hasCompanyLogo?`${environment.apiBaseUrl}/logo/${this.user.id}.avif`:`/assets/images/placeholder.png`
this.user = await this.userService.getById(this.user.id);
this.profileUrl = this.user.hasProfile ? `${environment.apiBaseUrl}/profile/${this.user.id}.avif` : `/assets/images/placeholder.png`
this.companyLogoUrl = this.user.hasCompanyLogo ? `${environment.apiBaseUrl}/logo/${this.user.id}.avif` : `/assets/images/placeholder.png`
}
printInvoice(invoice:Invoice){}
printInvoice(invoice: Invoice) { }
async updateProfile(user:User){
//this.messageService.add({ severity: 'warn', summary: 'Information', detail: 'This function is not yet available, please send an email to info@bizmatch.net for changes to your customer data', life: 15000 });
async updateProfile(user: User) {
await this.userService.save(this.user);
}
onUploadCompanyLogo(event:any){
onUploadCompanyLogo(event: any) {
const uniqueSuffix = '?_ts=' + new Date().getTime();
this.companyLogoUrl = `${environment.apiBaseUrl}/logo/${this.user.id}${uniqueSuffix}` //`http://IhrServer:Port/${newImagePath}${uniqueSuffix}`;
}
onUploadProfilePicture(event:any){
onUploadProfilePicture(event: any) {
const uniqueSuffix = '?_ts=' + new Date().getTime();
this.profileUrl = `${environment.apiBaseUrl}/profile/${this.user.id}${uniqueSuffix}` //`http://IhrServer:Port/${newImagePath}${uniqueSuffix}`;
}
@@ -102,73 +97,63 @@ export class AccountComponent {
(event.target as HTMLImageElement).src = `/assets/images/placeholder.png`; // Pfad zum Platzhalterbild
}
suggestions: string[] | undefined;
async search(event: AutoCompleteCompleteEvent) {
const result = await lastValueFrom(this.geoService.findCitiesStartingWith(event.query))
this.suggestions = result.map(r=>`${r.city} - ${r.state_code}`).slice(0,5);
const result = await lastValueFrom(this.geoService.findCitiesStartingWith(event.query))
this.suggestions = result.map(r => `${r.city} - ${r.state_code}`).slice(0, 5);
}
addLicence(){
this.user.licensedIn.push({name:'',value:''});
addLicence() {
this.user.licensedIn.push({ name: '', value: '' });
}
removeLicence(){
this.user.licensedIn.splice(this.user.licensedIn.length-2,1);
removeLicence() {
this.user.licensedIn.splice(this.user.licensedIn.length - 2, 1);
}
select(event:any,type:'company'|'profile'){
this.imageUrl = URL.createObjectURL(event.files[0]);
this.type=type
this.config={aspectRatio: type==='company'?this.stateOptions[0].value:this.stateOptions[2].value}
}
sendImage(){
this.imageUrl=null
this.loadingService.startLoading('uploadImage');
this.angularCropper.cropper.getCroppedCanvas().toBlob(async(blob) => {
if (this.type==='company'){
this.imageUploadService.uploadCompanyLogo(blob,this.user.id).subscribe(async(event) => {
select(event: any, type: 'company' | 'profile') {
const imageUrl = URL.createObjectURL(event.files[0]);
this.type = type
const config = { aspectRatio: type === 'company' ? stateOptions[0].value : stateOptions[2].value }
this.dialogRef = this.dialogService.open(ImageCropperComponent, {
data: {
imageUrl: imageUrl,
fileUpload: type === 'company' ? this.companyUpload : this.profileUpload,
config: config,
ratioVariable: type === 'company' ? true : false
},
header: 'Edit Image',
width: '50vw',
modal: true,
closeOnEscape: true,
keepInViewport: true,
closable: false,
breakpoints: {
'960px': '75vw',
'640px': '90vw'
},
});
this.dialogRef.onClose.subscribe(blob => {
if (blob) {
this.imageUploadService.uploadImage(blob, type==='company'?'uploadCompanyLogo':'uploadProfile',this.user.id).subscribe(async(event) => {
if (event.type === HttpEventType.UploadProgress) {
// Berechne und zeige den Fortschritt basierend auf event.loaded und event.total
const progress = event.total ? event.loaded / event.total : 0;
console.log(`Upload-Fortschritt: ${progress * 100}%`);
// Hier könntest du beispielsweise eine Fortschrittsanzeige aktualisieren
} else if (event.type === HttpEventType.Response) {
console.log('Upload abgeschlossen', event.body);
this.companyUpload.clear();
this.loadingService.stopLoading('uploadImage');
this.companyLogoUrl=`${environment.apiBaseUrl}/logo/${this.user.id}.avif?_ts=${new Date().getTime()}`
}
}, error => console.error('Fehler beim Upload:', error));
} else {
this.imageUploadService.uploadProfileImage(blob,this.user.id).subscribe(async(event) => {
if (event.type === HttpEventType.UploadProgress) {
// Berechne und zeige den Fortschritt basierend auf event.loaded und event.total
const progress = event.total ? event.loaded / event.total : 0;
console.log(`Upload-Fortschritt: ${progress * 100}%`);
// Hier könntest du beispielsweise eine Fortschrittsanzeige aktualisieren
} else if (event.type === HttpEventType.Response) {
console.log('Upload abgeschlossen', event.body);
this.profileUpload.clear();
this.loadingService.stopLoading('uploadImage');
this.profileUrl=`${environment.apiBaseUrl}/profile/${this.user.id}.avif?_ts=${new Date().getTime()}`
if (this.type==='company'){
this.user.hasCompanyLogo=true;
this.companyLogoUrl=`${environment.apiBaseUrl}/logo/${this.user.id}.avif?_ts=${new Date().getTime()}`
} else {
this.user.hasProfile=true;
this.profileUrl=`${environment.apiBaseUrl}/profile/${this.user.id}.avif?_ts=${new Date().getTime()}`
}
}
}, error => console.error('Fehler beim Upload:', error));
}
// this.fileUpload.upload();
}, 'image/png');
}
cancelUpload(){
this.imageUrl=null
if (this.type==='company'){
this.companyUpload.clear();
} else {
this.profileUpload.clear();
}
}
changeAspectRation(ratio:number){
this.config={aspectRatio: ratio}
this.angularCropper.cropper.setAspectRatio(ratio);
});
}
}

View File

@@ -20,7 +20,10 @@
<div>
<div class="mb-4">
<label for="description" class="block font-medium text-900 mb-2">Description</label>
<textarea id="description" type="text" pInputTextarea rows="5" [autoResize]="true" [(ngModel)]="listing.description"></textarea>
<!-- <textarea id="description" type="text" pInputTextarea rows="5" [autoResize]="true" [(ngModel)]="listing.description"></textarea> -->
<p-editor [(ngModel)]="listing.description" [style]="{ height: '320px' }" [modules]="editorModules">
<ng-template pTemplate="header"></ng-template>
</p-editor>
</div>
</div>
@if (listing.listingsCategory==='business'){
@@ -77,7 +80,7 @@
</div>
<div class="mb-4 col-12 md:col-6">
<div class="flex flex-column align-items-center flex-or">
<span class="font-medium text-900 mb-2">Property Picture</span>
<span class="font-medium text-900 mb-2">Property Pictures</span>
<!-- <img [src]="propertyPictureUrl" (error)="setImageToFallback($event)" class="image"/> -->
<p-fileUpload mode="basic"
chooseLabel="Upload"
@@ -91,7 +94,7 @@
</div>
</div>
</div>
<p-carousel [value]="propertyImages" [numVisible]="3" [numScroll]="3" [circular]="false" [responsiveOptions]="responsiveOptions">
<!-- <p-carousel [value]="propertyImages" [numVisible]="3" [numScroll]="3" [circular]="false" [responsiveOptions]="responsiveOptions">
<ng-template let-image pTemplate="item">
<div class="border-1 surface-border border-round m-2 text-center py-5 px-3">
<div class="mb-3">
@@ -100,12 +103,22 @@
<div>
<div class="mt-5 flex align-items-center justify-content-center gap-2">
<p-button icon="pi pi-file-edit" [rounded]="true" />
<p-button icon="fa-solid fa-trash-can" [rounded]="true" severity="danger"></p-button>
<p-button icon="fa-solid fa-trash-can" [rounded]="true" severity="danger" (click)="deleteConfirm(image.name)"></p-button>
</div>
</div>
</div>
</ng-template>
</p-carousel>
</p-carousel> -->
<div class="p-2 border-1 surface-border border-round mb-4 image-container" cdkDropList (cdkDropListDropped)="onDrop($event)"
cdkDropListOrientation="horizontal">
<ul >
<li *ngFor="let image of propertyImages" class="p-2 border-round shadow-1" >
<!-- <div class="image-container"> -->
<img src="{{environment.apiBaseUrl}}/property/{{listing.id}}/{{image.name}}" [alt]="image.name" class="shadow-2" cdkDrag/>
<!-- </div> -->
</li>
</ul>
</div>
}
@if (listing.listingsCategory==='business'){
<div class="grid">
@@ -195,12 +208,5 @@
</div>
</div>
</div>
<p-dialog header="Edit Image" [visible]="imageUrl" [modal]="true" [style]="{ width: '50vw' }" [draggable]="false" [resizable]="false">
<!-- <app-cropper #cropper [imageUrl]="imageUrl"></app-cropper> -->
<angular-cropper #cropper [imageUrl]="imageUrl" [cropperOptions]="config"></angular-cropper>
<ng-template pTemplate="footer">
<p-button icon="pi" (click)="imageUrl = null" label="Cancel" [outlined]="true"></p-button>
<p-button icon="pi pi-check" (click)="sendImage()" label="Finish" pAutoFocus [autofocus]="true"></p-button>
</ng-template>
</p-dialog>
<p-toast></p-toast>
<p-confirmDialog></p-confirmDialog>

View File

@@ -1,10 +1,87 @@
.translate-y-5{
.translate-y-5 {
transform: translateY(5px);
}
.image {
width: 120px;
height: 30px;
border: 1px solid #6b7280;
padding: 1px 1px;
object-fit: contain;
}
// .image {
// width: 120px;
// height: 30px;
// border: 1px solid #6b7280;
// padding: 1px 1px;
// object-fit: contain;
// }
// .image-container img {
// width: 200px;
// box-shadow: 0 3px 6px #00000029, 0 3px 6px #0000003b;
// margin-right: 1rem;
// }
// .container {
// width: 100%;
// min-height: 200px;
// border: 1px solid #ccc;
// display: flex;
// flex-wrap: wrap;
// }
.image-container {
width: 100%;
/* oder eine spezifische Breite */
overflow-x: auto;
/* Ermöglicht das Scrollen, wenn die Bilder zu breit sind */
}
.image-container ul {
display: flex;
padding: 0;
/* Entfernt den Standard-Abstand des ul-Elements */
margin: 0;
/* Entfernt den Standard-Außenabstand des ul-Elements */
list-style-type: none;
/* Entfernt die Listenpunkte */
}
.image-container li {
flex: 1 1 auto;
/* Erlaubt den li-Elementen, zu wachsen und zu schrumpfen, aber füllt den Raum gleichmäßig */
/* Optional: Füge hier Abstände zwischen den li-Elementen hinzu */
}
.image-container img {
max-width: 100%;
/* Stellt sicher, dass die Bilder nicht über ihre natürliche Größe hinaus wachsen */
height: auto;
/* Behält das Seitenverhältnis bei */
cursor: pointer;
}
.draggable-image {
margin: 8px;
cursor: grab;
}
.draggable-image:active {
box-shadow: 0 5px 5px -3px rgba(0, 0, 0, 0.2),
0 8px 10px 1px rgba(0, 0, 0, 0.14),
0 3px 14px 2px rgba(0, 0, 0, 0.12);
}
// .cdk-drag-preview {
// box-shadow: 0 5px 5px rgba(0, 0, 0, 0.2);
// }
// .cdk-drag-placeholder {
// background-color: #ccc;
// }
.drop-area {
border: 2px dashed #ccc;
padding: 20px;
text-align: center;
transition: all 0.3s;
}
/* CSS-Klasse für den Drop-Bereich, wenn ein Element darüber gezogen wird */
.drop-area-active {
border-color: #2196F3;
background-color: #E3F2FD;
}

View File

@@ -24,7 +24,7 @@ import { lastValueFrom } from 'rxjs';
import { ArrayToStringPipe } from '../../../pipes/array-to-string.pipe';
import { UserService } from '../../../services/user.service';
import { SharedModule } from '../../../shared/shared/shared.module';
import { MessageService } from 'primeng/api';
import { ConfirmationService, MessageService } from 'primeng/api';
import { AutoCompleteCompleteEvent, BusinessListing, CommercialPropertyListing, ImageProperty, ListingType, User } from '../../../../../../common-models/src/main.model';
import { GeoResult, GeoService } from '../../../services/geo.service';
import { InputNumberComponent, InputNumberModule } from '../../../components/inputnumber/inputnumber.component';
@@ -35,121 +35,177 @@ import { v4 as uuidv4 } from 'uuid';
import { DialogModule } from 'primeng/dialog';
import { AngularCropperjsModule, CropperComponent } from 'angular-cropperjs';
import { HttpClient, HttpEventType } from '@angular/common/http';
import {ImageService} from '../../../services/image.service'
import { ImageService } from '../../../services/image.service'
import { LoadingService } from '../../../services/loading.service';
import { TOOLBAR_OPTIONS } from '../../utils/defaults';
import { EditorModule } from 'primeng/editor';
import { DialogService, DynamicDialogModule, DynamicDialogRef } from 'primeng/dynamicdialog';
import { ImageCropperComponent } from '../../../components/image-cropper/image-cropper.component';
import { ConfirmDialogModule } from 'primeng/confirmdialog';
import { CdkDragDrop, CdkDragEnter, CdkDragExit, DragDropModule, moveItemInArray } from '@angular/cdk/drag-drop';
@Component({
selector: 'create-listing',
standalone: true,
imports: [SharedModule,ArrayToStringPipe, InputNumberModule,CarouselModule,DialogModule,AngularCropperjsModule,FileUploadModule],
providers:[MessageService],
imports: [SharedModule, ArrayToStringPipe, InputNumberModule, CarouselModule, DialogModule, AngularCropperjsModule, FileUploadModule, EditorModule, DynamicDialogModule, ConfirmDialogModule,DragDropModule],
providers: [MessageService, DialogService, ConfirmationService],
templateUrl: './edit-listing.component.html',
styleUrl: './edit-listing.component.scss'
})
export class EditListingComponent {
@ViewChild(CropperComponent) public angularCropper: CropperComponent;
@ViewChild(FileUpload) public fileUpload: FileUpload;
listingCategory:'Business'|'Commercial Property';
category:string;
location:string;
mode:'edit'|'create';
separator:'\n\n'
listing:ListingType
listingCategory: 'Business' | 'Commercial Property';
category: string;
location: string;
mode: 'edit' | 'create';
separator: '\n\n'
listing: ListingType
private id: string | undefined = this.activatedRoute.snapshot.params['id'] as string | undefined;
user:User;
maxFileSize=3000000;
uploadUrl:string;
environment=environment;
propertyImages:ImageProperty[]
user: User;
maxFileSize = 3000000;
uploadUrl: string;
environment = environment;
propertyImages: ImageProperty[]
responsiveOptions = [
{
breakpoint: '1199px',
numVisible: 1,
numScroll: 1
breakpoint: '1199px',
numVisible: 1,
numScroll: 1
},
{
breakpoint: '991px',
numVisible: 2,
numScroll: 1
breakpoint: '991px',
numVisible: 2,
numScroll: 1
},
{
breakpoint: '767px',
numVisible: 1,
numScroll: 1
breakpoint: '767px',
numVisible: 1,
numScroll: 1
}
];
imageUrl
config={aspectRatio: 16 / 9}
constructor(public selectOptions:SelectOptionsService,
private router: Router,
private activatedRoute: ActivatedRoute,
private listingsService:ListingsService,
public userService: UserService,
private messageService: MessageService,
private geoService:GeoService,
private imageUploadService: ImageService,
private loadingService:LoadingService){
this.user=this.userService.getUser();
config = { aspectRatio: 16 / 9 }
editorModules = TOOLBAR_OPTIONS
dialogRef: DynamicDialogRef | undefined;
draggedImage:ImageProperty
dropAreaActive = false;
constructor(public selectOptions: SelectOptionsService,
private router: Router,
private activatedRoute: ActivatedRoute,
private listingsService: ListingsService,
public userService: UserService,
private messageService: MessageService,
private geoService: GeoService,
private imageService: ImageService,
private loadingService: LoadingService,
public dialogService: DialogService,
private confirmationService: ConfirmationService) {
this.user = this.userService.getUser();
// Abonniere Router-Events, um den aktiven Link zu ermitteln
this.router.events.subscribe(event => {
if (event instanceof NavigationEnd) {
this.mode = event.url==='/createListing'?'create':'edit';
this.mode = event.url === '/createListing' ? 'create' : 'edit';
}
});
}
async ngOnInit(){
if (this.mode==='edit'){
this.listing=await lastValueFrom(this.listingsService.getListingById(this.id));
async ngOnInit() {
if (this.mode === 'edit') {
this.listing = await lastValueFrom(this.listingsService.getListingById(this.id));
} else {
const uuid = sessionStorage.getItem('uuid')?sessionStorage.getItem('uuid'):uuidv4();
sessionStorage.setItem('uuid',uuid);
this.listing=createGenericObject<BusinessListing>();
this.listing.id=uuid
this.listing.temporary=true;
this.listing.userId=this.user.id
this.listing.listingsCategory='business';
}
const uuid = sessionStorage.getItem('uuid') ? sessionStorage.getItem('uuid') : uuidv4();
sessionStorage.setItem('uuid', uuid);
this.listing = createGenericObject<BusinessListing>();
this.listing.id = uuid
this.listing.temporary = true;
this.listing.userId = this.user.id
this.listing.listingsCategory = 'business';
}
this.uploadUrl = `${environment.apiBaseUrl}/bizmatch/image/uploadPropertyPicture/${this.listing.id}`;
this.propertyImages=await this.listingsService.getPropertyImages(this.listing.id)
this.propertyImages = await this.listingsService.getPropertyImages(this.listing.id)
}
async save(){
async save() {
sessionStorage.removeItem('uuid')
await this.listingsService.save(this.listing,this.listing.listingsCategory);
await this.listingsService.save(this.listing, this.listing.listingsCategory);
this.messageService.add({ severity: 'info', summary: 'Confirmed', detail: 'Listing changes have been persisted', life: 3000 });
}
suggestions: string[] | undefined;
async search(event: AutoCompleteCompleteEvent) {
const result = await lastValueFrom(this.geoService.findCitiesStartingWith(event.query,this.listing.state))
this.suggestions = result.map(r=>r.city).slice(0,5);
const result = await lastValueFrom(this.geoService.findCitiesStartingWith(event.query, this.listing.state))
this.suggestions = result.map(r => r.city).slice(0, 5);
}
select(event:any){
this.imageUrl = URL.createObjectURL(event.files[0]);
}
sendImage(){
this.imageUrl=null
this.loadingService.startLoading('uploadImage');
this.angularCropper.cropper.getCroppedCanvas().toBlob(async(blob) => {
select(event: any) {
const imageUrl = URL.createObjectURL(event.files[0]);
this.dialogRef = this.dialogService.open(ImageCropperComponent, {
data: {
imageUrl: imageUrl,
fileUpload: this.fileUpload,
ratioVariable: false
},
header: 'Edit Image',
width: '50vw',
modal: true,
closeOnEscape: true,
keepInViewport: true,
closable: false,
breakpoints: {
'960px': '75vw',
'640px': '90vw'
},
});
this.dialogRef.onClose.subscribe(blob => {
if (blob) {
this.imageService.uploadImage(blob, 'uploadPropertyPicture', this.listing.id).subscribe(async (event) => {
if (event.type === HttpEventType.Response) {
console.log('Upload abgeschlossen', event.body);
this.loadingService.stopLoading('uploadImage');
this.propertyImages = await this.listingsService.getPropertyImages(this.listing.id)
}
}, error => console.error('Fehler beim Upload:', error));
}
this.imageUploadService.uploadPropertyImage(blob,this.listing.id).subscribe(async(event) => {
if (event.type === HttpEventType.UploadProgress) {
// Berechne und zeige den Fortschritt basierend auf event.loaded und event.total
const progress = event.total ? event.loaded / event.total : 0;
console.log(`Upload-Fortschritt: ${progress * 100}%`);
// Hier könntest du beispielsweise eine Fortschrittsanzeige aktualisieren
} else if (event.type === HttpEventType.Response) {
console.log('Upload abgeschlossen', event.body);
// Hier könntest du die Ladeanimation ausblenden
this.propertyImages=await this.listingsService.getPropertyImages(this.listing.id)
this.fileUpload.clear();
this.loadingService.stopLoading('uploadImage');
}
}, error => console.error('Fehler beim Upload:', error));
// this.fileUpload.upload();
}, 'image/png');
});
}
deleteConfirm(imageName: string) {
this.confirmationService.confirm({
target: event.target as EventTarget,
message: `Do you want to delete this image ${imageName}?`,
header: 'Delete Confirmation',
icon: 'pi pi-info-circle',
acceptButtonStyleClass: "p-button-danger p-button-text",
rejectButtonStyleClass: "p-button-text p-button-text",
acceptIcon: "none",
rejectIcon: "none",
accept: async () => {
await this.imageService.deleteListingImage(this.listing.id, imageName);
this.messageService.add({ severity: 'info', summary: 'Confirmed', detail: 'Image deleted' });
this.propertyImages = await this.listingsService.getPropertyImages(this.listing.id)
},
reject: () => {
// this.messageService.add({ severity: 'error', summary: 'Rejected', detail: 'You have rejected' });
console.log('deny')
}
});
}
onDrop(event: CdkDragDrop<string[]>) {
this.dropAreaActive = false;
moveItemInArray(this.propertyImages, event.previousIndex, event.currentIndex);
//console.log(event.previousIndex, event.currentIndex);
}
onDragEnter(event: CdkDragEnter<any,any>) {
this.dropAreaActive = true;
}
onDragExit(event: CdkDragExit<any,any>) {
this.dropAreaActive = false;
}
}