From a437851f6d535c87a73a58b2897562be622b5ab1 Mon Sep 17 00:00:00 2001 From: Andreas Knuth Date: Sun, 31 Mar 2024 19:44:08 +0200 Subject: [PATCH] drag & drop renewed, imageCropper revisited, imageOrder persisted, css quirks --- bizmatch-server/src/file/file.service.ts | 3 +- bizmatch-server/src/image/image.controller.ts | 22 +- bizmatch-server/src/image/image.module.ts | 3 + ...commercial-property-listings.controller.ts | 9 +- .../src/listings/listings.module.ts | 3 +- .../src/listings/listings.service.ts | 26 ++- bizmatch/package.json | 1 + .../image-cropper/image-cropper.component.ts | 16 +- .../src/app/pages/home/home.component.html | 2 +- .../pages/listings/listings.component.html | 65 +++--- .../app/pages/listings/listings.component.ts | 2 + .../subscription/account/account.component.ts | 37 ++-- .../edit-listing/edit-listing.component.html | 35 ++-- .../edit-listing/edit-listing.component.scss | 120 ++++------- .../edit-listing/edit-listing.component.ts | 63 +++--- bizmatch/src/app/services/image.service.ts | 2 +- bizmatch/src/app/services/listings.service.ts | 3 + .../assets/images/placeholder_properties.jpg | Bin 0 -> 86586 bytes ...placeholder_properties.jpg:Zone.Identifier | 3 + common-models/src/main.model.ts | 2 +- crawler/data/listings.json | 192 +++++++++++++++++ .../listings_bizmatch.json} | 0 crawler/data/listings_cp.json | 142 +++++++++++++ crawler/{ => data}/users.json | 0 crawler/filechooser.ts | 193 ++++++++++++++++++ crawler/importListing.ts | 16 +- crawler/package.json | 2 + crawler/tsconfig.json | 8 +- 28 files changed, 767 insertions(+), 203 deletions(-) create mode 100644 bizmatch/src/assets/images/placeholder_properties.jpg create mode 100644 bizmatch/src/assets/images/placeholder_properties.jpg:Zone.Identifier create mode 100644 crawler/data/listings.json rename crawler/{listings.json => data/listings_bizmatch.json} (100%) create mode 100644 crawler/data/listings_cp.json rename crawler/{ => data}/users.json (100%) create mode 100644 crawler/filechooser.ts diff --git a/bizmatch-server/src/file/file.service.ts b/bizmatch-server/src/file/file.service.ts index 11d9b16..88f23e6 100644 --- a/bizmatch-server/src/file/file.service.ts +++ b/bizmatch-server/src/file/file.service.ts @@ -80,13 +80,14 @@ export class FileService { return false } } - async storePropertyPicture(file: Express.Multer.File, listingId: string) { + async storePropertyPicture(file: Express.Multer.File, listingId: string) : Promise { const suffix = file.mimetype.includes('png') ? 'png' : 'jpg' const directory = `./pictures/property/${listingId}` fs.ensureDirSync(`${directory}`); const imageName = await this.getNextImageName(directory); //await fs.outputFile(`${directory}/${imageName}`, file.buffer); await this.resizeImageToAVIF(file.buffer,150 * 1024,imageName,directory); + return `${imageName}.avif` } async getNextImageName(directory) { try { diff --git a/bizmatch-server/src/image/image.controller.ts b/bizmatch-server/src/image/image.controller.ts index 01d14ac..12a9232 100644 --- a/bizmatch-server/src/image/image.controller.ts +++ b/bizmatch-server/src/image/image.controller.ts @@ -4,11 +4,15 @@ import { Logger } from 'winston'; import { FileInterceptor } from '@nestjs/platform-express'; import { FileService } from '../file/file.service.js'; import { SelectOptionsService } from '../select-options/select-options.service.js'; +import { ListingsService } from '../listings/listings.service.js'; +import { CommercialPropertyListing } from 'src/models/main.model.js'; +import { Entity, EntityData } from 'redis-om'; @Controller('image') export class ImageController { constructor(private fileService:FileService, + private listingService:ListingsService, @Inject(WINSTON_MODULE_PROVIDER) private readonly logger: Logger, private selectOptions:SelectOptionsService) { } @@ -16,7 +20,8 @@ export class ImageController { @Post('uploadPropertyPicture/:id') @UseInterceptors(FileInterceptor('file'),) async uploadPropertyPicture(@UploadedFile() file: Express.Multer.File,@Param('id') id:string) { - await this.fileService.storePropertyPicture(file,id); + const imagename = await this.fileService.storePropertyPicture(file,id); + await this.listingService.addImage(id,imagename); } @Post('uploadProfile/:id') @@ -33,7 +38,16 @@ export class ImageController { @Get(':id') async getPropertyImagesById(@Param('id') id:string): Promise { - return await this.fileService.getPropertyImages(id); + const result = await this.listingService.getCommercialPropertyListingById(id); + const listing = result as CommercialPropertyListing; + if (listing.imageOrder){ + return listing.imageOrder + } else { + const imageOrder = await this.fileService.getPropertyImages(id); + listing.imageOrder=imageOrder; + this.listingService.saveListing(listing); + return imageOrder; + } } @Get('profileImages/:userids') async getProfileImagesForUsers(@Param('userids') userids:string): Promise { @@ -43,9 +57,11 @@ export class ImageController { async getCompanyLogosForUsers(@Param('userids') userids:string): Promise { return await this.fileService.getCompanyLogosForUsers(userids); } + @Delete('propertyPicture/:listingid/:imagename') async deletePropertyImagesById(@Param('listingid') listingid:string,@Param('imagename') imagename:string): Promise { - this.fileService.deleteImage(`pictures/property/${listingid}/${imagename}`) + this.fileService.deleteImage(`pictures/property/${listingid}/${imagename}`); + await this.listingService.deleteImage(listingid,imagename); } @Delete('logo/:userid/') async deleteLogoImagesById(@Param('id') id:string): Promise { diff --git a/bizmatch-server/src/image/image.module.ts b/bizmatch-server/src/image/image.module.ts index c9db704..57d2b89 100644 --- a/bizmatch-server/src/image/image.module.ts +++ b/bizmatch-server/src/image/image.module.ts @@ -3,8 +3,11 @@ import { ImageController } from './image.controller.js'; import { ImageService } from './image.service.js'; import { FileService } from '../file/file.service.js'; import { SelectOptionsService } from '../select-options/select-options.service.js'; +import { ListingsService } from '../listings/listings.service.js'; +import { ListingsModule } from '../listings/listings.module.js'; @Module({ + imports: [ListingsModule], controllers: [ImageController], providers: [ImageService,FileService,SelectOptionsService] }) diff --git a/bizmatch-server/src/listings/commercial-property-listings.controller.ts b/bizmatch-server/src/listings/commercial-property-listings.controller.ts index 61be7e5..6577ee0 100644 --- a/bizmatch-server/src/listings/commercial-property-listings.controller.ts +++ b/bizmatch-server/src/listings/commercial-property-listings.controller.ts @@ -1,9 +1,10 @@ -import { Body, Controller, Delete, Get, Inject, Param, Post, UploadedFile, UseInterceptors } from '@nestjs/common'; +import { Body, Controller, Delete, Get, Inject, Param, Post, Put, UploadedFile, UseInterceptors } from '@nestjs/common'; import { ListingsService } from './listings.service.js'; import { WINSTON_MODULE_PROVIDER } from 'nest-winston'; import { Logger } from 'winston'; import { FileInterceptor } from '@nestjs/platform-express'; import { FileService } from '../file/file.service.js'; +import { CommercialPropertyListing, ImageProperty } from 'src/models/main.model.js'; @Controller('listings/commercialProperty') export class CommercialPropertyListingsController { @@ -21,7 +22,11 @@ export class CommercialPropertyListingsController { find(@Body() criteria: any): any { return this.listingsService.findCommercialPropertyListings(criteria); } - + + @Put('imageOrder/:id') + async changeImageOrder(@Param('id') id:string,@Body() imageOrder: ImageProperty[]) { + this.listingsService.updateImageOrder(id, imageOrder) + } /** * @param listing creates a new listing */ diff --git a/bizmatch-server/src/listings/listings.module.ts b/bizmatch-server/src/listings/listings.module.ts index 1bb5da1..bb9815d 100644 --- a/bizmatch-server/src/listings/listings.module.ts +++ b/bizmatch-server/src/listings/listings.module.ts @@ -12,6 +12,7 @@ import { UserService } from '../user/user.service.js'; @Module({ imports: [RedisModule], controllers: [BusinessListingsController, CommercialPropertyListingsController,UnknownListingsController,BrokerListingsController], - providers: [ListingsService,FileService,UserService] + providers: [ListingsService,FileService,UserService], + exports: [ListingsService], }) export class ListingsModule {} diff --git a/bizmatch-server/src/listings/listings.service.ts b/bizmatch-server/src/listings/listings.service.ts index 72812f0..4b0a48c 100644 --- a/bizmatch-server/src/listings/listings.service.ts +++ b/bizmatch-server/src/listings/listings.service.ts @@ -3,7 +3,8 @@ import { BusinessListing, CommercialPropertyListing, ListingCriteria, - ListingType + ListingType, + ImageProperty } from '../models/main.model.js'; import { convertStringToNullUndefined } from '../utils.js'; import { WINSTON_MODULE_PROVIDER } from 'nest-winston'; @@ -77,8 +78,8 @@ export class ListingsService { } return result; } - async getCommercialPropertyListingById(id: string) { - return await this.commercialPropertyListingRepository.fetch(id) + async getCommercialPropertyListingById(id: string): Promise{ + return await this.commercialPropertyListingRepository.fetch(id) as unknown as CommercialPropertyListing; } async getBusinessListingById(id: string) { return await this.businessListingRepository.fetch(id) @@ -134,4 +135,23 @@ export class ListingsService { } return listings } + + async updateImageOrder(id:string,imageOrder: ImageProperty[]){ + const listing = await this.getCommercialPropertyListingById(id) as unknown as CommercialPropertyListing + listing.imageOrder=imageOrder; + this.saveListing(listing); + } + async deleteImage(listingid:string,name:string,){ + const listing = await this.getCommercialPropertyListingById(listingid) as unknown as CommercialPropertyListing + const index = listing.imageOrder.findIndex(im=>im.name===name); + if (index>-1){ + listing.imageOrder.splice(index,1); + this.saveListing(listing); + } + } + async addImage(id:string,imagename: string){ + const listing = await this.getCommercialPropertyListingById(id) as unknown as CommercialPropertyListing + listing.imageOrder.push({name:imagename,code:'',id:''}); + this.saveListing(listing); + } } diff --git a/bizmatch/package.json b/bizmatch/package.json index 008142f..ae089e1 100644 --- a/bizmatch/package.json +++ b/bizmatch/package.json @@ -30,6 +30,7 @@ "@fortawesome/free-solid-svg-icons": "^6.5.1", "@types/uuid": "^9.0.8", "angular-cropperjs": "^14.0.1", + "angular-mixed-cdk-drag-drop": "^2.2.3", "browser-bunyan": "^1.8.0", "cropperjs": "^1.6.1", "express": "^4.18.2", diff --git a/bizmatch/src/app/components/image-cropper/image-cropper.component.ts b/bizmatch/src/app/components/image-cropper/image-cropper.component.ts index e44c561..ee13b12 100644 --- a/bizmatch/src/app/components/image-cropper/image-cropper.component.ts +++ b/bizmatch/src/app/components/image-cropper/image-cropper.component.ts @@ -44,13 +44,15 @@ export class ImageCropperComponent { } } sendImage(){ - this.loadingService.startLoading('uploadImage'); - setTimeout(()=>{ - this.angularCropper.cropper.getCroppedCanvas().toBlob(async(blob) => { - this.fileUpload.clear() - this.ref.close(blob); - }, 'image/png'); - }) + // setTimeout(()=>{ + // this.angularCropper.cropper.getCroppedCanvas().toBlob(async(blob) => { + // this.ref.close(blob); + // this.fileUpload.clear() + // }, 'image/jpg'); + // },0) + + this.fileUpload.clear() + this.ref.close(this.angularCropper.cropper); } cancelUpload(){ diff --git a/bizmatch/src/app/pages/home/home.component.html b/bizmatch/src/app/pages/home/home.component.html index 9a120e7..41de0c6 100644 --- a/bizmatch/src/app/pages/home/home.component.html +++ b/bizmatch/src/app/pages/home/home.component.html @@ -8,7 +8,7 @@
@if(userService.isLoggedIn()){ - + } @else { } diff --git a/bizmatch/src/app/pages/listings/listings.component.html b/bizmatch/src/app/pages/listings/listings.component.html index 9bc1a14..6c9cc27 100644 --- a/bizmatch/src/app/pages/listings/listings.component.html +++ b/bizmatch/src/app/pages/listings/listings.component.html @@ -86,37 +86,38 @@
} @for (listing of filteredListings; track listing.id) { -
-
-
-
- Image -

{{selectOptions.getState(listing.state)}}

-
-
-
-

{{listing.title}}

- +
+
+
+
+ @if (listing.imageOrder.length>0){ + Image + } @else { + + Image + } +

{{selectOptions.getState(listing.state)}}

-

{{listing.city}}

-
-

- - {{selectOptions.getCommercialProperty(listing.type)}} -

- +
+
+

{{listing.title}}

+ +
+

{{listing.city}}

+
+

+ + {{selectOptions.getCommercialProperty(listing.type)}} +

+
+

{{listing.price | currency}}

-

{{listing.price | currency}}

-
-
-
- -
-
+
+
+ +
+
} @@ -126,7 +127,7 @@
@if(user.hasProfile){ - + } @else { } @@ -147,9 +148,7 @@ class="p-button-rounded p-button-success" [routerLink]="['/details-user',user.id]">
- + } diff --git a/bizmatch/src/app/pages/listings/listings.component.ts b/bizmatch/src/app/pages/listings/listings.component.ts index bcb2307..b04cb6a 100644 --- a/bizmatch/src/app/pages/listings/listings.component.ts +++ b/bizmatch/src/app/pages/listings/listings.component.ts @@ -43,6 +43,7 @@ export class ListingsComponent { first: number = 0; rows: number = 12; totalRecords:number = 0; + ts = new Date().getTime() public category: 'business' | 'commercialProperty' | 'professionals_brokers' | undefined; constructor(public selectOptions: SelectOptionsService, @@ -118,4 +119,5 @@ export class ListingsComponent { imageErrorHandler(listing: ListingType) { listing.hideImage = true; // Bild ausblenden, wenn es nicht geladen werden kann } + } diff --git a/bizmatch/src/app/pages/subscription/account/account.component.ts b/bizmatch/src/app/pages/subscription/account/account.component.ts index bd2a87e..d392cbf 100644 --- a/bizmatch/src/app/pages/subscription/account/account.component.ts +++ b/bizmatch/src/app/pages/subscription/account/account.component.ts @@ -133,27 +133,24 @@ export class AccountComponent { '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) { - const progress = event.total ? event.loaded / event.total : 0; - console.log(`Upload-Fortschritt: ${progress * 100}%`); - } else if (event.type === HttpEventType.Response) { - console.log('Upload abgeschlossen', event.body); - this.loadingService.stopLoading('uploadImage'); - 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()}` + this.dialogRef.onClose.subscribe(cropper => { + if (cropper){ + this.loadingService.startLoading('uploadImage'); + cropper.getCroppedCanvas().toBlob(async (blob) => { + this.imageUploadService.uploadImage(blob, type==='company'?'uploadCompanyLogo':'uploadProfile',this.user.id).subscribe(async(event) => { + if (event.type === HttpEventType.Response) { + this.loadingService.stopLoading('uploadImage'); + 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)); + }, error => console.error('Fehler beim Upload:', error)); + }) } - - }); + }) } - } diff --git a/bizmatch/src/app/pages/subscription/edit-listing/edit-listing.component.html b/bizmatch/src/app/pages/subscription/edit-listing/edit-listing.component.html index 5312f7e..df65275 100644 --- a/bizmatch/src/app/pages/subscription/edit-listing/edit-listing.component.html +++ b/bizmatch/src/app/pages/subscription/edit-listing/edit-listing.component.html @@ -94,30 +94,19 @@ - -
-
    -
  • - - - -
  • -
+ @for (image of propertyImages; track image) { + +
+ + + +
+
+ }
} @if (listing.listingsCategory==='business'){ diff --git a/bizmatch/src/app/pages/subscription/edit-listing/edit-listing.component.scss b/bizmatch/src/app/pages/subscription/edit-listing/edit-listing.component.scss index 9779c9c..88018d9 100644 --- a/bizmatch/src/app/pages/subscription/edit-listing/edit-listing.component.scss +++ b/bizmatch/src/app/pages/subscription/edit-listing/edit-listing.component.scss @@ -2,86 +2,56 @@ transform: translateY(5px); } -// .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 */ -} + display: flex; /* Erlaubt ein flexibles Box-Layout */ + flex-wrap: wrap; /* Erlaubt das Umfließen der Elemente auf die nächste Zeile */ + justify-content: flex-start; /* Startet die Anordnung der Elemente am Anfang des Containers */ + align-items: flex-start; /* Ausrichtung der Elemente am Anfang der Querachse */ + padding: 10px; /* Abstand zwischen den Inhalten des Containers und dessen Rand */ + } -.image-container ul { +.image-container span { + flex-flow: row; 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 */ + width: fit-content; + height: fit-content; } -.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 */ +.image-container span img { + max-height: 150px; /* Maximale Höhe der Bilder */ + width: auto; /* Die Breite der Bilder passt sich automatisch an die Höhe an */ cursor: pointer; + margin: 10px; } +// .image-container fa-icon { +// top: 0; /* Positioniert das Icon am oberen Rand des Bildes */ +// right: 0; /* Positioniert das Icon am rechten Rand des Bildes */ +// color: #fff; /* Weiße Farbe für das Icon */ +// background-color: rgba(0,0,0,0.5); /* Halbtransparenter Hintergrund für bessere Sichtbarkeit */ +// padding: 5px; /* Ein wenig Platz um das Icon */ +// cursor: pointer; /* Verwandelt den Cursor in eine Hand, um Interaktivität anzudeuten */ +// } -.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; -} \ No newline at end of file + .image-wrap { + position: relative; /* Ermöglicht die absolute Positionierung des Icons bezogen auf diesen Container */ + display: inline-block; /* Erlaubt die Inline-Anordnung, falls mehrere Bilder vorhanden sind */ + } + + /* Stil für das Bild */ + .image-wrap img { + max-height: 150px; + width: auto; + display: block; /* Verhindert unerwünschten Abstand unter dem Bild */ + } + + /* Stil für das FontAwesome Icon */ + .image-wrap fa-icon { + position: absolute; + top: 15px; /* Positioniert das Icon am oberen Rand des Bildes */ + right: 15px; /* Positioniert das Icon am rechten Rand des Bildes */ + color: #fff; /* Weiße Farbe für das Icon */ + background-color: rgba(0,0,0,0.5); /* Halbtransparenter Hintergrund für bessere Sichtbarkeit */ + padding: 5px; /* Ein wenig Platz um das Icon */ + cursor: pointer; /* Verwandelt den Cursor in eine Hand, um Interaktivität anzudeuten */ + border-radius: 8px; /* Optional: Abrunden der linken unteren Ecke für ästhetische Zwecke */ + } \ No newline at end of file diff --git a/bizmatch/src/app/pages/subscription/edit-listing/edit-listing.component.ts b/bizmatch/src/app/pages/subscription/edit-listing/edit-listing.component.ts index 98f0c8e..9de170c 100644 --- a/bizmatch/src/app/pages/subscription/edit-listing/edit-listing.component.ts +++ b/bizmatch/src/app/pages/subscription/edit-listing/edit-listing.component.ts @@ -43,10 +43,14 @@ import { DialogService, DynamicDialogModule, DynamicDialogRef } from 'primeng/dy 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'; +import { MixedCdkDragDropModule } from 'angular-mixed-cdk-drag-drop'; +import { faTrash } from '@fortawesome/free-solid-svg-icons'; @Component({ selector: 'create-listing', standalone: true, - imports: [SharedModule, ArrayToStringPipe, InputNumberModule, CarouselModule, DialogModule, AngularCropperjsModule, FileUploadModule, EditorModule, DynamicDialogModule, ConfirmDialogModule,DragDropModule], + imports: [SharedModule, ArrayToStringPipe, InputNumberModule, CarouselModule, + DialogModule, AngularCropperjsModule, FileUploadModule, EditorModule, DynamicDialogModule, DragDropModule, + ConfirmDialogModule, MixedCdkDragDropModule], providers: [MessageService, DialogService, ConfirmationService], templateUrl: './edit-listing.component.html', styleUrl: './edit-listing.component.scss' @@ -85,8 +89,8 @@ export class EditListingComponent { config = { aspectRatio: 16 / 9 } editorModules = TOOLBAR_OPTIONS dialogRef: DynamicDialogRef | undefined; - draggedImage:ImageProperty - dropAreaActive = false; + draggedImage: ImageProperty + faTrash = faTrash; constructor(public selectOptions: SelectOptionsService, private router: Router, private activatedRoute: ActivatedRoute, @@ -155,18 +159,35 @@ export class EditListingComponent { '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.dialogRef.onClose.subscribe(cropper => { + if (cropper){ + this.loadingService.startLoading('uploadImage'); + cropper.getCroppedCanvas().toBlob(async (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)); + }, 'image/jpg'); + cropper.destroy(); } - - }); + }) + // this.dialogRef.onClose.subscribe(blob => { + // if (blob) { + // // this.loadingService.startLoading('uploadImage'); + // setTimeout(()=>{ + // 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)); + // },10) + // } + // }); } deleteConfirm(imageName: string) { @@ -193,19 +214,9 @@ export class EditListingComponent { }); } - onDrop(event: CdkDragDrop) { - this.dropAreaActive = false; + onDrop(event: { previousIndex: number; currentIndex: number }) { moveItemInArray(this.propertyImages, event.previousIndex, event.currentIndex); - //console.log(event.previousIndex, event.currentIndex); - } - - - onDragEnter(event: CdkDragEnter) { - this.dropAreaActive = true; - } - - onDragExit(event: CdkDragExit) { - this.dropAreaActive = false; + this.listingsService.changeImageOrder(this.listing.id, this.propertyImages) } } diff --git a/bizmatch/src/app/services/image.service.ts b/bizmatch/src/app/services/image.service.ts index 2902ab0..a3eacee 100644 --- a/bizmatch/src/app/services/image.service.ts +++ b/bizmatch/src/app/services/image.service.ts @@ -20,7 +20,7 @@ export class ImageService { return this.http.post(uploadUrl, formData,{ // headers: this.headers, - reportProgress: true, + //reportProgress: true, observe: 'events', }); } diff --git a/bizmatch/src/app/services/listings.service.ts b/bizmatch/src/app/services/listings.service.ts index bdc30cc..ef98b0f 100644 --- a/bizmatch/src/app/services/listings.service.ts +++ b/bizmatch/src/app/services/listings.service.ts @@ -36,4 +36,7 @@ export class ListingsService { async getPropertyImages(id:string):Promise{ return await lastValueFrom(this.http.get(`${this.apiBaseUrl}/bizmatch/image/${id}`)); } + async changeImageOrder(id:string, propertyImages: ImageProperty[]):Promise{ + return await lastValueFrom(this.http.put(`${this.apiBaseUrl}/bizmatch/listings/commercialProperty/imageOrder/${id}`,propertyImages)); + } } diff --git a/bizmatch/src/assets/images/placeholder_properties.jpg b/bizmatch/src/assets/images/placeholder_properties.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e4112078c35ddb331c46f2340c11631f27d002a3 GIT binary patch literal 86586 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 YbtXkBqvV;OCommunity-Centric Café

A beloved local coffee shop offering a wide variety of gourmet coffees, teas, and handmade pastries. Known for its cozy atmosphere and strong community ties. Ideal for someone passionate about coffee and community engagement.

", + "type": "2", + "state": "CA", + "city": "San Francisco", + "id": "02JRPQ2YPK7CMXS55XP9G8UIJ2", + "price": 220000, + "salesRevenue": 340000, + "temporary": false, + "leasedLocation": false, + "established": 2015, + "employees": 10, + "reasonForSale": "Retirement", + "supportAndTraining": "2 weeks of training provided.", + "cashFlow": 95000 + }, + { + "userId": "4q5r6s7t-8u9v-0w1x-2y3z-4a5b6c7d8e9f", + "listingsCategory": "business", + "title": "Organic Farm Supply", + "description": "

Sustainable Agriculture

Offering a range of products for organic farming, including seeds, tools, and fertilizers. Committed to promoting sustainable farming practices. A great opportunity for someone with a green thumb and a passion for sustainability.

", + "type": "3", + "state": "OR", + "city": "Portland", + "id": "03KRQQ3ZPL8DNYS66YQ1H9VJK3", + "price": 180000, + "salesRevenue": 260000, + "temporary": false, + "leasedLocation": true, + "established": 2017, + "employees": 6, + "reasonForSale": "Focusing on other ventures", + "supportAndTraining": "1 month of comprehensive training.", + "cashFlow": 78000 + }, + { + "userId": "3m4n5o6p-7q8r-9s0t-1u2v-3w4x5y6z7a8b", + "listingsCategory": "business", + "title": "Modern Italian Restaurant", + "description": "

Authentic Italian Cuisine

An upscale Italian restaurant known for its modern twist on traditional dishes. Features a full bar and an elegant dining room. A fantastic opportunity for a culinary entrepreneur or chef.

", + "type": "4", + "state": "NY", + "city": "New York", + "id": "04LRPP4AOQ9ENZT77ZR2I0WKL4", + "price": 450000, + "salesRevenue": 670000, + "temporary": false, + "leasedLocation": false, + "established": 2012, + "employees": 15, + "reasonForSale": "New business interests", + "supportAndTraining": "Owner willing to consult for 3 months.", + "cashFlow": 220000 + }, + { + "userId": "4q5r6s7t-8u9v-0w1x-2y3z-4a5b6c7d8e9f", + "listingsCategory": "business", + "title": "Boutique Clothing Store", + "description": "

High-End Fashion

A boutique store offering an exclusive selection of women's clothing and accessories from top designers. Located in a prime shopping district, it's known for its exceptional customer service and unique fashion finds.

", + "type": "5", + "state": "IL", + "city": "Chicago", + "id": "05MSQQ5BPRAFO1U88ZS3J1XML5", + "price": 310000, + "salesRevenue": 430000, + "temporary": false, + "leasedLocation": true, + "established": 2018, + "employees": 8, + "reasonForSale": "Personal reasons", + "supportAndTraining": "3 weeks of training and support.", + "cashFlow": 120000 + }, + { + "userId": "3m4n5o6p-7q8r-9s0t-1u2v-3w4x5y6z7a8b", + "listingsCategory": "business", + "title": "Tech Startup - Mobile Apps", + "description": "

Innovative Technology Solutions

A tech startup specializing in developing cutting-edge mobile applications for both iOS and Android. With several successful apps already in the market, this is an exciting opportunity for tech enthusiasts or investors.

", + "type": "6", + "state": "WA", + "city": "Seattle", + "id": "06NTQR6CQSBGP2V99AT4K2YNM6", + "price": 500000, + "salesRevenue": 800000, + "temporary": false, + "leasedLocation": false, + "established": 2020, + "employees": 20, + "reasonForSale": "Seeking new challenges", + "supportAndTraining": "Technical and business support for 1 month.", + "cashFlow": 300000 + }, + { + "userId": "8a2b1c5d-7e6f-4g3h-9i1j-2k3l4m5n6o7p", + "listingsCategory": "business", + "title": "Eco-Friendly Cleaning Service", + "description": "

Green Home and Office Cleaning

A fast-growing cleaning service that uses eco-friendly products. Offers home and office cleaning with a focus on sustainability and environmentally friendly practices. A perfect venture for those passionate about the environment.

", + "type": "7", + "state": "CO", + "city": "Denver", + "id": "07OUQR7DRTCGQ3WAAAU5L3ZON7", + "price": 90000, + "salesRevenue": 150000, + "temporary": false, + "leasedLocation": true, + "established": 2021, + "employees": 12, + "reasonForSale": "Expanding to new markets", + "supportAndTraining": "Comprehensive eco-friendly cleaning training.", + "cashFlow": 65000 + }, + { + "userId": "3m4n5o6p-7q8r-9s0t-1u2v-3w4x5y6z7a8b", + "listingsCategory": "business", + "title": "Independent Bookstore", + "description": "

A Haven for Book Lovers

An independent bookstore with a strong community presence, offering a wide range of books, from bestsellers to local authors. Includes a cozy café space for readers to relax and enjoy their books.

", + "type": "8", + "state": "MA", + "city": "Boston", + "id": "08PVRS8ESUDHR4XBBBV6M4APO8", + "price": 130000, + "salesRevenue": 210000, + "temporary": false, + "leasedLocation": false, + "established": 2016, + "employees": 5, + "reasonForSale": "Owner relocating", + "supportAndTraining": "Training on operations and inventory management.", + "cashFlow": 70000 + }, + { + "userId": "7w8x9y0z-1a2b-3c4d-5e6f-7g8h9i0j1k2l", + "listingsCategory": "business", + "title": "Luxury Spa and Wellness Center", + "description": "

Ultimate Relaxation and Wellness

A luxury spa offering a comprehensive range of services, including massages, facials, and wellness programs. Situated in a tranquil and upscale area, it's the perfect retreat for health and wellness enthusiasts.

", + "type": "9", + "state": "FL", + "city": "Miami", + "id": "09QWTR9FTVEIS5YCCDW7N5BQP9", + "price": 350000, + "salesRevenue": 520000, + "temporary": false, + "leasedLocation": true, + "established": 2014, + "employees": 18, + "reasonForSale": "Pursuing other interests", + "supportAndTraining": "Owner available for a smooth transition over 2 months.", + "cashFlow": 190000 + }, + { + "userId": "1g2h3i4j-5k6l-7m8n-9o0p-1q2r3s4t5u6v", + "listingsCategory": "business", + "title": "Custom Jewelry Shop", + "description": "

Exquisite Handcrafted Jewelry

A shop specializing in custom-made jewelry, from engagement rings to unique pieces for special occasions. Utilizes high-quality materials and offers a personalized design service.

", + "type": "10", + "state": "NV", + "city": "Las Vegas", + "id": "10RXUS0GUWFJT6ZDDDX8O6CQR0", + "price": 275000, + "salesRevenue": 400000, + "temporary": false, + "leasedLocation": false, + "established": 2018, + "employees": 4, + "reasonForSale": "Health reasons", + "supportAndTraining": "Design and crafting training provided.", + "cashFlow": 110000 + }, + { + "userId": "4q5r6s7t-8u9v-0w1x-2y3z-4a5b6c7d8e9f", + "listingsCategory": "business", + "title": "Digital Marketing Agency", + "description": "

Online Branding and Marketing Solutions

A full-service digital marketing agency offering SEO, PPC, social media marketing, and web design services. Known for its innovative strategies and results-driven approach. Ideal for those with a background in marketing or business.

", + "type": "11", + "state": "TX", + "city": "Dallas", + "id": "11SYVT1HVXGKU7AEEEX9P7DRR1", + "price": 400000, + "salesRevenue": 600000, + "temporary": false, + "leasedLocation": true, + "established": 2019, + "employees": 25, + "reasonForSale": "Scaling down", + "supportAndTraining": "4 weeks of digital marketing training.", + "cashFlow": 250000 + } +] diff --git a/crawler/listings.json b/crawler/data/listings_bizmatch.json similarity index 100% rename from crawler/listings.json rename to crawler/data/listings_bizmatch.json diff --git a/crawler/data/listings_cp.json b/crawler/data/listings_cp.json new file mode 100644 index 0000000..fe77346 --- /dev/null +++ b/crawler/data/listings_cp.json @@ -0,0 +1,142 @@ +[ + { + "id": "2b5c900f-894d-5e48-c987-8cf735170b5f", + "temporary": false, + "userId": "", + "listingsCategory": "commercialProperty", + "title": "Downtown Retail Space", + "state": "NY", + "hasImages": true, + "price": 3200000, + "city": "New York", + "description": "

Prime retail space in the heart of New York City. An excellent opportunity for investors to own a piece of the vibrant downtown shopping district. High foot traffic and visibility make this an ideal location for any retail business.

", + "type": "100", + "imageOrder": [] + }, + { + "id": "3c6d901g-905e-6f59-d098-9dg846280c6g", + "temporary": false, + "userId": "", + "listingsCategory": "commercialProperty", + "title": "Expansive Land Development Opportunity", + "state": "CA", + "hasImages": true, + "price": 5000000, + "city": "Los Angeles", + "description": "

Offering a unique opportunity to purchase vast acreage in Los Angeles. Perfect for developers looking to create a new residential community or commercial complex. Accessibility to major highways and urban centers.

", + "type": "101", + "imageOrder": [] + }, + { + "id": "4d7ea012-h16f-7g6a-e109-feh957390d7h", + "temporary": false, + "userId": "", + "listingsCategory": "commercialProperty", + "title": "Industrial Warehouse Complex", + "state": "IL", + "hasImages": true, + "price": 7500000, + "city": "Chicago", + "description": "

A modern industrial warehouse complex suitable for manufacturing or distribution businesses. Features multiple loading docks, office spaces, and state-of-the-art facilities. Strategically located for easy transport access.

", + "type": "102", + "imageOrder": [] + }, + { + "id": "5e8fb123-i27g-8h7b-f210-gfi0684a1e8i", + "temporary": false, + "userId": "", + "listingsCategory": "commercialProperty", + "title": "Luxury Office Building", + "state": "TX", + "hasImages": true, + "price": 8900000, + "city": "Houston", + "description": "

An architectural masterpiece, this luxury office building offers state-of-the-art amenities, including a fitness center, conference rooms, and rooftop gardens. Ideal for businesses looking for a prestigious address.

", + "type": "103", + "imageOrder": [] + }, + { + "id": "6f9gc234-j38h-9i8c-g311-hgj1795b2f9j", + "temporary": false, + "userId": "", + "listingsCategory": "commercialProperty", + "title": "Mixed-Use Building Downtown", + "state": "FL", + "hasImages": true, + "price": 4200000, + "city": "Miami", + "description": "

A prominent mixed-use building featuring retail spaces on the ground floor and modern apartments above. Located in the bustling downtown area, it offers a perfect blend of commercial and residential opportunities.

", + "type": "104", + "imageOrder": [] + }, + { + "id": "7hagd345-k49i-aj9d-h422-ikj2806c3gak", + "temporary": false, + "userId": "", + "listingsCategory": "commercialProperty", + "title": "Multifamily Residential Complex", + "state": "WA", + "hasImages": true, + "price": 6700000, + "city": "Seattle", + "description": "

This modern multifamily complex features a variety of amenities including a gym, pool, and community center. Offering a mix of one, two, and three-bedroom units, it's a perfect investment for steady rental income.

", + "type": "105", + "imageOrder": [] + }, + { + "id": "8ibhe456-l5aj-bk0e-i533-jkl3917d4hab", + "temporary": false, + "userId": "", + "listingsCategory": "commercialProperty", + "title": "Versatile Commercial Property", + "state": "CO", + "hasImages": true, + "price": 3900000, + "city": "Denver", + "description": "

A versatile commercial property that can accommodate various business types, from retail to offices. Located in a high-traffic area, it offers great visibility and accessibility. Ample parking and flexible space configurations available.

", + "type": "106", + "imageOrder": [] + }, + { + "id": "9jcfi567-m6bk-cl1f-j644-kml4028e5icm", + "temporary": false, + "userId": "", + "listingsCategory": "commercialProperty", + "title": "Premier Shopping Center", + "state": "AZ", + "hasImages": true, + "price": 12000000, + "city": "Phoenix", + "description": "

A leading shopping center with a mix of national and local retailers, restaurants, and entertainment options. High annual foot traffic and a loyal customer base make this a highly desirable investment.

", + "type": "100", + "imageOrder": [] + }, + { + "id": "akdjh678-n7cl-dm2g-k755-lnm5139f6jdn", + "temporary": false, + "userId": "", + "listingsCategory": "commercialProperty", + "title": "Expansive Industrial Park", + "state": "NV", + "hasImages": true, + "price": 15000000, + "city": "Las Vegas", + "description": "

An expansive industrial park offering a range of facilities for light manufacturing, warehousing, and logistics. Includes customizable units, ample parking, and is strategically located for easy access to major transport routes.

", + "type": "102", + "imageOrder": [] + }, + { + "id": "blemj789-o8dm-en3h-l866-mno6240g7keo", + "temporary": false, + "userId": "", + "listingsCategory": "commercialProperty", + "title": "High-End Office Suites", + "state": "GA", + "hasImages": true, + "price": 5300000, + "city": "Atlanta", + "description": "

Elegant and modern office suites in a prestigious part of Atlanta. Offers businesses a high-profile location with top-notch amenities, including secure parking, high-speed internet, and on-site management.

", + "type": "103", + "imageOrder": [] + } +] diff --git a/crawler/users.json b/crawler/data/users.json similarity index 100% rename from crawler/users.json rename to crawler/data/users.json diff --git a/crawler/filechooser.ts b/crawler/filechooser.ts new file mode 100644 index 0000000..2d93e7e --- /dev/null +++ b/crawler/filechooser.ts @@ -0,0 +1,193 @@ +import fs from 'fs-extra'; +import path from 'path'; +// import { prompt, Question} from 'inquirer'; +import inquirer from 'inquirer'; +import chalk from 'chalk'; + + +const COMPLETED = 'SELECTION_COMPLETED'; +const CANCELLED = 'SELECTION_CANCELLED'; +const CHECKMARK = '\u2713'; + +class FilesSystemService { + directories(directoryPath, directoryFilter ?: (joinedPath) => true) { + return fs.readdirSync(directoryPath).filter((name) => { + const joinedPath = path.join(directoryPath, name); + return this.isDirectory(joinedPath) && directoryFilter(joinedPath); + }); + } + + files(directoryPath, fileFilter = (joinedPath) => true) { + return fs.readdirSync(directoryPath).filter((name) => { + const joinedPath = path.join(directoryPath, name); + return this.isFile(joinedPath) && fileFilter(joinedPath); + }); + } + + isDirectory(directoryPath) { + return fs.statSync(directoryPath).isDirectory(); + } + + isFile(filePath) { + return fs.statSync(filePath).isFile(); + } +} + +class FilesSelectionService extends Set { + lastFileSelected = null; + constructor(selectedFiles) { + super(selectedFiles); + } + + get selectedFiles() { + return Array.from(this); + } + + isSelected(file) { + return this.has(file); + } + + selectFile(file) { + this.add(file); + this.lastFileSelected = file; + } + + removeFile(file) { + this.delete(file); + } +} + +class LocationService { + constructor(public currentPath) { + this.currentPath = currentPath; + } +} + +class OptionsService { + constructor(public options) { + this.options = { ...this.defaultOptions, ...options }; + } + + get defaultOptions() { + return { + directoryFilter: () => true, + fileFilter: () => true, + root: process.cwd(), + startingPath: process.cwd(), + multi: true, + pageSize: 10, + selectedFiles: [], + clearConsole: true, + }; + } +} + +export const selectFiles = function (options = {}) { + const optionsService = new OptionsService(options); + const locationService = new LocationService( + optionsService.options.startingPath + ); + const fileSystemService = new FilesSystemService(); + const filesSelectionService = new FilesSelectionService( + optionsService.options.selectedFiles + ); + + return new Promise((resolve):FCResult|void => { + (async function promptUserToSelectFiles() { + const directories = fileSystemService.directories( + locationService.currentPath, + optionsService.options.directoryFilter + ); + + if (locationService.currentPath !== optionsService.options.root) { + directories.unshift('..'); + } + + const files = fileSystemService.files( + locationService.currentPath, + optionsService.options.fileFilter + ); + + const choices = [ + ...directories.map((directoryName) => { + const value = path.join(locationService.currentPath, directoryName); + const name = chalk.yellow(directoryName); + return { value, name }; + }), + ...files.map((fileName) => { + const value = path.join(locationService.currentPath, fileName); + const name = `${fileName} ${ + filesSelectionService.isSelected(value) + ? chalk.green(CHECKMARK) + : '' + }`; + return { value, name }; + }), + ]; + + if (filesSelectionService.selectedFiles.length) { + choices.push({ + name: chalk.green('-- File Selection Complete --'), + value: COMPLETED, + }); + } + + choices.push({ + name: chalk.red('-- Cancel File Selection --'), + value: CANCELLED, + }); + + if (optionsService.options.clearConsole) { + console.clear(); + } + + const { selection } = await inquirer.prompt([ + { + type: 'list', + message: `Select file(s) in ${locationService.currentPath}`, + name: 'selection', + pageSize: optionsService.options.pageSize, + choices, + default: () => filesSelectionService.lastFileSelected, + }, + ]); + + if (optionsService.options.clearConsole) { + console.clear(); + } + + if (selection === COMPLETED || selection === CANCELLED) { + return resolve({ + selectedFiles: filesSelectionService.selectedFiles, + status: selection, + }); + } else if (!optionsService.options.multi) { + return resolve({ + selectedFiles: [selection], + status: COMPLETED, + }); + } + + if (fileSystemService.isDirectory(selection)) { + locationService.currentPath = selection; + } else { + if (filesSelectionService.isSelected(selection)) { + filesSelectionService.removeFile(selection); + } else { + filesSelectionService.selectFile(selection); + } + } + + promptUserToSelectFiles(); + })(); + }); +}; +export type FCResult = { + selectedFiles:Array + status:'SELECTION_COMPLETED'|'SELECTION_CANCELLED' +} +// const exports = { +// COMPLETED, +// CANCELLED, +// selectFiles, +// }; \ No newline at end of file diff --git a/crawler/importListing.ts b/crawler/importListing.ts index 6408ae8..85ea603 100644 --- a/crawler/importListing.ts +++ b/crawler/importListing.ts @@ -1,10 +1,22 @@ import fs from 'fs-extra'; +import { selectFiles } from './filechooser.js'; +import path from 'path'; (async () => { - const listings = await fs.readJson('./listings.json'); + const result = await selectFiles({startingPath:'./data',directoryFilter: (directoryName)=>{ + return false; + },fileFilter: (fileName) => { + return /\.json$/gi.test(fileName); + },pageSize:10,multi:false}); + console.log(result['selectedFiles'][0]); + const file = result['selectedFiles'][0]; + // const extension = path.extname(file); + // const basefileName = path.basename(file,extension); + const listings = await fs.readJson(file); //listings.forEach(element => { for (const listing of listings) { - const response = await fetch('http://localhost:3000/bizmatch/listings', { + const type = listing.listingsCategory + const response = await fetch(`http://localhost:3000/bizmatch/listings/${type}`, { method: 'POST', body: JSON.stringify(listing), headers: { 'Content-Type': 'application/json' }, diff --git a/crawler/package.json b/crawler/package.json index df855a0..ba42da6 100644 --- a/crawler/package.json +++ b/crawler/package.json @@ -3,6 +3,7 @@ "version": "1.0.0", "description": "", "main": "index.js", + "type": "module", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, @@ -15,6 +16,7 @@ "dependencies": { "currency.js": "^2.0.4", "fs-extra": "^11.2.0", + "inquirer": "^9.2.17", "ioredis": "^5.3.2", "node-fetch": "^3.3.2", "puppeteer": "^22.1.0", diff --git a/crawler/tsconfig.json b/crawler/tsconfig.json index 7b99a6b..684a21e 100644 --- a/crawler/tsconfig.json +++ b/crawler/tsconfig.json @@ -11,7 +11,7 @@ // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ /* Language and Environment */ - "target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ + "target": "ES2017", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ // "jsx": "preserve", /* Specify what JSX code is generated. */ // "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */ @@ -25,9 +25,9 @@ // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ /* Modules */ - "module": "commonjs", /* Specify what module code is generated. */ + "module": "ESNext", /* Specify what module code is generated. */ // "rootDir": "./", /* Specify the root folder within your source files. */ - // "moduleResolution": "node10", /* Specify how TypeScript looks up a file from a given module specifier. */ + "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */ // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ @@ -55,7 +55,7 @@ "sourceMap": true, /* Create source map files for emitted JavaScript files. */ // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ - // "outDir": "./", /* Specify an output folder for all emitted files. */ + "outDir": "./build", /* Specify an output folder for all emitted files. */ // "removeComments": true, /* Disable emitting comments. */ // "noEmit": true, /* Disable emitting files from a compilation. */ // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */