From d2e5562602aaef9b4099a14d5d4b089a8656942c Mon Sep 17 00:00:00 2001 From: Andreas Knuth Date: Tue, 14 May 2024 11:53:20 -0500 Subject: [PATCH] history service, mail template improved, general listing entry --- bizmatch-server/src/mail/mail.service.ts | 2 + .../src/mail/templates/inquiry.hbs | 114 ++++++++++++++++-- bizmatch/src/app/app.routes.ts | 7 ++ .../not-found/not-found.component.html | 1 + .../not-found/not-found.component.scss | 0 .../not-found/not-found.component.ts | 8 ++ .../src/app/guards/listing-category.guard.ts | 35 ++++++ .../details-business-listing.component.html | 16 ++- .../details-business-listing.component.ts | 20 +-- ...commercial-property-listing.component.html | 6 +- ...s-commercial-property-listing.component.ts | 11 +- .../details-user/details-user.component.html | 10 +- .../details-user/details-user.component.ts | 8 +- .../edit-business-listing.component.html | 22 +++- ...commercial-property-listing.component.html | 15 ++- bizmatch/src/app/services/history.service.ts | 32 +++++ bizmatch/src/app/services/listings.service.ts | 3 - 17 files changed, 261 insertions(+), 49 deletions(-) create mode 100644 bizmatch/src/app/components/not-found/not-found.component.html create mode 100644 bizmatch/src/app/components/not-found/not-found.component.scss create mode 100644 bizmatch/src/app/components/not-found/not-found.component.ts create mode 100644 bizmatch/src/app/guards/listing-category.guard.ts create mode 100644 bizmatch/src/app/services/history.service.ts diff --git a/bizmatch-server/src/mail/mail.service.ts b/bizmatch-server/src/mail/mail.service.ts index 712aaca..6cde419 100644 --- a/bizmatch-server/src/mail/mail.service.ts +++ b/bizmatch-server/src/mail/mail.service.ts @@ -34,6 +34,8 @@ export class MailService { iname: mailInfo.sender.name, phone: mailInfo.sender.phoneNumber, email: mailInfo.sender.email, + id: mailInfo.listing.id, + url: 'http://localhost:4200', }, }); return user; diff --git a/bizmatch-server/src/mail/templates/inquiry.hbs b/bizmatch-server/src/mail/templates/inquiry.hbs index a09bde3..319fcb7 100644 --- a/bizmatch-server/src/mail/templates/inquiry.hbs +++ b/bizmatch-server/src/mail/templates/inquiry.hbs @@ -1,12 +1,104 @@ -

Dear {{ name }},

-

You got an inquiry regarding your '{{title}}'' listing

-

- Buyers Information -

-

Contact Name: {{iname}}

-

Contact Phone: {{phone}}

-

Contact Mail: {{email}}

-

Contact Name: {{iname}}

-

Comments: {{inquiry}}

+ + + + + + Notification: New Buyer Lead + + + +
+
Notification: New buyer lead from the Bizmatch Network
+
Dear {{name}},
+

You've received a message regarding your "{{title}}" listing.

+ +
+
Buyer Information
+
+ Contact Name: + {{iname}} +
+
+ Contact Email: + {{email}} +
+
+ Contact Phone: + {{phone}} +
+
+ Comments: + {{inquiry}} +
+
-

Internal Listing Number: {{internalListingNumber}}

\ No newline at end of file +
+
Listing Information
+
+ Headline: + {{title}} +
+
+ Listing ID: + {{id}} +
+ {{#if internalListingNumber}} +
+ Ref ID: + {{internalListingNumber}} +
+ {{/if}} +
+
+ + \ No newline at end of file diff --git a/bizmatch/src/app/app.routes.ts b/bizmatch/src/app/app.routes.ts index 3e069b0..25d2c2c 100644 --- a/bizmatch/src/app/app.routes.ts +++ b/bizmatch/src/app/app.routes.ts @@ -1,6 +1,8 @@ import { Routes } from '@angular/router'; import { LogoutComponent } from './components/logout/logout.component'; +import { NotFoundComponent } from './components/not-found/not-found.component'; import { authGuard } from './guards/auth.guard'; +import { ListingCategoryGuard } from './guards/listing-category.guard'; import { DetailsBusinessListingComponent } from './pages/details/details-business-listing/details-business-listing.component'; import { DetailsCommercialPropertyListingComponent } from './pages/details/details-commercial-property-listing/details-commercial-property-listing.component'; import { DetailsUserComponent } from './pages/details/details-user/details-user.component'; @@ -46,6 +48,11 @@ export const routes: Routes = [ path: 'details-commercial-property-listing/:id', component: DetailsCommercialPropertyListingComponent, }, + { + path: 'listing/:id', + canActivate: [ListingCategoryGuard], + component: NotFoundComponent, // Dummy-Komponente, wird nie angezeigt, da der Guard weiterleitet + }, // ######### // User Details { diff --git a/bizmatch/src/app/components/not-found/not-found.component.html b/bizmatch/src/app/components/not-found/not-found.component.html new file mode 100644 index 0000000..8071020 --- /dev/null +++ b/bizmatch/src/app/components/not-found/not-found.component.html @@ -0,0 +1 @@ +

not-found works!

diff --git a/bizmatch/src/app/components/not-found/not-found.component.scss b/bizmatch/src/app/components/not-found/not-found.component.scss new file mode 100644 index 0000000..e69de29 diff --git a/bizmatch/src/app/components/not-found/not-found.component.ts b/bizmatch/src/app/components/not-found/not-found.component.ts new file mode 100644 index 0000000..f444acf --- /dev/null +++ b/bizmatch/src/app/components/not-found/not-found.component.ts @@ -0,0 +1,8 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'app-not-found', + standalone: true, + template: '

Page not found

', +}) +export class NotFoundComponent {} diff --git a/bizmatch/src/app/guards/listing-category.guard.ts b/bizmatch/src/app/guards/listing-category.guard.ts new file mode 100644 index 0000000..10e2a48 --- /dev/null +++ b/bizmatch/src/app/guards/listing-category.guard.ts @@ -0,0 +1,35 @@ +import { HttpClient } from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot, UrlTree } from '@angular/router'; +import { Observable, of } from 'rxjs'; +import { catchError, map } from 'rxjs/operators'; +import { environment } from '../../environments/environment'; + +@Injectable({ + providedIn: 'root', +}) +export class ListingCategoryGuard implements CanActivate { + private apiBaseUrl = environment.apiBaseUrl; + constructor(private http: HttpClient, private router: Router) {} + + canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable { + const id = route.paramMap.get('id'); + const url = `${this.apiBaseUrl}/bizmatch/listings/undefined/${id}`; + + return this.http.get(url).pipe( + map(response => { + const category = response.listingsCategory; + if (category === 'business') { + return this.router.createUrlTree([`/details-business-listing/${id}`]); + } else if (category === 'commercialProperty') { + return this.router.createUrlTree([`/details-commercial-property-listing/${id}`]); + } else { + return this.router.createUrlTree(['/not-found']); + } + }), + catchError(() => { + return of(this.router.createUrlTree(['/not-found'])); + }), + ); + } +} diff --git a/bizmatch/src/app/pages/details/details-business-listing/details-business-listing.component.html b/bizmatch/src/app/pages/details/details-business-listing/details-business-listing.component.html index 22a1ba7..ec8187b 100644 --- a/bizmatch/src/app/pages/details/details-business-listing/details-business-listing.component.html +++ b/bizmatch/src/app/pages/details/details-business-listing/details-business-listing.component.html @@ -4,7 +4,9 @@
{{ listing?.title }}
- + @if(historyService.canGoBack()){ + + }
@if(listing){ @@ -12,8 +14,8 @@
  • -
    Description
    -
    +
    Description
    +
  • Category
    @@ -45,6 +47,14 @@
    Employees
    {{ listing.employees }}
  • +
  • +
    Support & Training
    +
    {{ listing.supportAndTraining }}
    +
  • +
  • +
    Reason for Sale
    +
    {{ listing.reasonForSale }}
    +
  • Broker licensing
    {{ listing.brokerLicencing }}
    diff --git a/bizmatch/src/app/pages/details/details-business-listing/details-business-listing.component.ts b/bizmatch/src/app/pages/details/details-business-listing/details-business-listing.component.ts index cf760dc..f881739 100644 --- a/bizmatch/src/app/pages/details/details-business-listing/details-business-listing.component.ts +++ b/bizmatch/src/app/pages/details/details-business-listing/details-business-listing.component.ts @@ -1,7 +1,6 @@ -import { Location } from '@angular/common'; import { Component } from '@angular/core'; import { DomSanitizer, SafeHtml } from '@angular/platform-browser'; -import { ActivatedRoute, Router } from '@angular/router'; +import { ActivatedRoute, NavigationEnd, Router } from '@angular/router'; import onChange from 'on-change'; import { MessageService } from 'primeng/api'; import { GalleriaModule } from 'primeng/galleria'; @@ -9,6 +8,7 @@ import { lastValueFrom } from 'rxjs'; import { BusinessListing, User } from '../../../../../../bizmatch-server/src/models/db.model'; import { ListingCriteria, MailInfo } from '../../../../../../bizmatch-server/src/models/main.model'; import { environment } from '../../../../environments/environment'; +import { HistoryService } from '../../../services/history.service'; import { ListingsService } from '../../../services/listings.service'; import { MailService } from '../../../services/mail.service'; import { SelectOptionsService } from '../../../services/select-options.service'; @@ -49,7 +49,9 @@ export class DetailsBusinessListingComponent { mailinfo: MailInfo; environment = environment; user: User; + listingUser: User; description: SafeHtml; + private history: string[] = []; constructor( private activatedRoute: ActivatedRoute, private listingsService: ListingsService, @@ -59,8 +61,13 @@ export class DetailsBusinessListingComponent { private mailService: MailService, private messageService: MessageService, private sanitizer: DomSanitizer, - private location: Location, + public historyService: HistoryService, ) { + this.router.events.subscribe(event => { + if (event instanceof NavigationEnd) { + this.history.push(event.urlAfterRedirects); + } + }); this.mailinfo = { sender: {}, userId: '', email: '' }; this.userService.getUserObservable().subscribe(user => { this.user = user; @@ -70,16 +77,15 @@ export class DetailsBusinessListingComponent { async ngOnInit() { this.listing = await lastValueFrom(this.listingsService.getListingById(this.id, 'business')); + this.listingUser = await this.userService.getById(this.listing.userId); this.description = this.sanitizer.bypassSecurityTrustHtml(this.listing.description); } - back() { - this.location.back(); - } + isAdmin() { return this.userService.hasAdminRole(); } async mail() { - this.mailinfo.email = this.user.email; + this.mailinfo.email = this.listingUser.email; this.mailinfo.userId = this.listing.userId; this.mailinfo.listing = this.listing; await this.mailService.mail(this.mailinfo); diff --git a/bizmatch/src/app/pages/details/details-commercial-property-listing/details-commercial-property-listing.component.html b/bizmatch/src/app/pages/details/details-commercial-property-listing/details-commercial-property-listing.component.html index cddc4f8..083dcef 100644 --- a/bizmatch/src/app/pages/details/details-commercial-property-listing/details-commercial-property-listing.component.html +++ b/bizmatch/src/app/pages/details/details-commercial-property-listing/details-commercial-property-listing.component.html @@ -4,7 +4,9 @@
    {{ listing?.title }}
    - + @if(historyService.canGoBack()){ + + }
    @if(listing){ @@ -12,7 +14,7 @@
    • -
      Description
      +
      Description
    • diff --git a/bizmatch/src/app/pages/details/details-commercial-property-listing/details-commercial-property-listing.component.ts b/bizmatch/src/app/pages/details/details-commercial-property-listing/details-commercial-property-listing.component.ts index 1c4efef..d6fcc70 100644 --- a/bizmatch/src/app/pages/details/details-commercial-property-listing/details-commercial-property-listing.component.ts +++ b/bizmatch/src/app/pages/details/details-commercial-property-listing/details-commercial-property-listing.component.ts @@ -1,4 +1,3 @@ -import { Location } from '@angular/common'; import { Component } from '@angular/core'; import { DomSanitizer, SafeHtml } from '@angular/platform-browser'; import { ActivatedRoute, Router } from '@angular/router'; @@ -9,6 +8,7 @@ import { lastValueFrom } from 'rxjs'; import { CommercialPropertyListing, User } from '../../../../../../bizmatch-server/src/models/db.model'; import { ListingCriteria, MailInfo } from '../../../../../../bizmatch-server/src/models/main.model'; import { environment } from '../../../../environments/environment'; +import { HistoryService } from '../../../services/history.service'; import { ListingsService } from '../../../services/listings.service'; import { MailService } from '../../../services/mail.service'; import { SelectOptionsService } from '../../../services/select-options.service'; @@ -50,6 +50,7 @@ export class DetailsCommercialPropertyListingComponent { propertyImages: string[] = []; environment = environment; user: User; + listingUser: User; description: SafeHtml; constructor( private activatedRoute: ActivatedRoute, @@ -60,7 +61,7 @@ export class DetailsCommercialPropertyListingComponent { private mailService: MailService, private messageService: MessageService, private sanitizer: DomSanitizer, - private location: Location, + public historyService: HistoryService, ) { this.mailinfo = { sender: {}, userId: '', email: '' }; this.userService.getUserObservable().subscribe(user => { @@ -72,16 +73,14 @@ export class DetailsCommercialPropertyListingComponent { async ngOnInit() { this.listing = await lastValueFrom(this.listingsService.getListingById(this.id, 'commercialProperty')); this.propertyImages = await this.listingsService.getPropertyImages(this.listing.id); + this.listingUser = await this.userService.getById(this.listing.userId); this.description = this.sanitizer.bypassSecurityTrustHtml(this.listing.description); } - back() { - this.location.back(); - } isAdmin() { return this.userService.hasAdminRole(); } async mail() { - this.mailinfo.email = this.user.email; + this.mailinfo.email = this.listingUser.email; this.mailinfo.userId = this.listing.userId; this.mailinfo.listing = this.listing; await this.mailService.mail(this.mailinfo); diff --git a/bizmatch/src/app/pages/details/details-user/details-user.component.html b/bizmatch/src/app/pages/details/details-user/details-user.component.html index 5756878..0001a40 100644 --- a/bizmatch/src/app/pages/details/details-user/details-user.component.html +++ b/bizmatch/src/app/pages/details/details-user/details-user.component.html @@ -2,10 +2,6 @@
      @if (user){
      -
      @@ -44,7 +40,9 @@
      - + @if(historyService.canGoBack()){ + + }

      {{ user.description }}

      @@ -123,7 +121,7 @@
      @if (listing.imageOrder?.length>0){ - + } @else { } diff --git a/bizmatch/src/app/pages/details/details-user/details-user.component.ts b/bizmatch/src/app/pages/details/details-user/details-user.component.ts index 663449b..ab50d08 100644 --- a/bizmatch/src/app/pages/details/details-user/details-user.component.ts +++ b/bizmatch/src/app/pages/details/details-user/details-user.component.ts @@ -1,4 +1,3 @@ -import { Location } from '@angular/common'; import { Component } from '@angular/core'; import { DomSanitizer, SafeHtml } from '@angular/platform-browser'; import { ActivatedRoute, Router } from '@angular/router'; @@ -8,6 +7,7 @@ import { Observable } from 'rxjs'; import { BusinessListing, CommercialPropertyListing, User } from '../../../../../../bizmatch-server/src/models/db.model'; import { ListingCriteria } from '../../../../../../bizmatch-server/src/models/main.model'; import { environment } from '../../../../environments/environment'; +import { HistoryService } from '../../../services/history.service'; import { ImageService } from '../../../services/image.service'; import { ListingsService } from '../../../services/listings.service'; import { SelectOptionsService } from '../../../services/select-options.service'; @@ -42,7 +42,7 @@ export class DetailsUserComponent { public selectOptions: SelectOptionsService, private sanitizer: DomSanitizer, private imageService: ImageService, - private location: Location, + public historyService: HistoryService, ) {} async ngOnInit() { @@ -56,9 +56,7 @@ export class DetailsUserComponent { this.companyOverview = this.sanitizer.bypassSecurityTrustHtml(this.user.companyOverview); this.offeredServices = this.sanitizer.bypassSecurityTrustHtml(this.user.offeredServices); } - back() { - this.location.back(); - } + isAdmin() { return this.userService.hasAdminRole(); } diff --git a/bizmatch/src/app/pages/subscription/edit-business-listing/edit-business-listing.component.html b/bizmatch/src/app/pages/subscription/edit-business-listing/edit-business-listing.component.html index 31dd5c0..0571ee7 100644 --- a/bizmatch/src/app/pages/subscription/edit-business-listing/edit-business-listing.component.html +++ b/bizmatch/src/app/pages/subscription/edit-business-listing/edit-business-listing.component.html @@ -28,7 +28,6 @@
      - @@ -36,13 +35,26 @@
      - +
      - +
      - +
      @@ -119,7 +131,7 @@
      - +
      diff --git a/bizmatch/src/app/pages/subscription/edit-commercial-property-listing/edit-commercial-property-listing.component.html b/bizmatch/src/app/pages/subscription/edit-commercial-property-listing/edit-commercial-property-listing.component.html index a850dee..ed69856 100644 --- a/bizmatch/src/app/pages/subscription/edit-commercial-property-listing/edit-commercial-property-listing.component.html +++ b/bizmatch/src/app/pages/subscription/edit-commercial-property-listing/edit-commercial-property-listing.component.html @@ -38,6 +38,8 @@
      - +
      diff --git a/bizmatch/src/app/services/history.service.ts b/bizmatch/src/app/services/history.service.ts new file mode 100644 index 0000000..404fbb2 --- /dev/null +++ b/bizmatch/src/app/services/history.service.ts @@ -0,0 +1,32 @@ +import { Injectable } from '@angular/core'; +import { NavigationEnd, Router } from '@angular/router'; + +@Injectable({ + providedIn: 'root', +}) +export class HistoryService { + private history: string[] = []; + + constructor(private router: Router) { + this.router.events.subscribe(event => { + if (event instanceof NavigationEnd) { + this.history.push(event.urlAfterRedirects); + } + }); + } + + public getHistory(): string[] { + return this.history; + } + + public canGoBack(): boolean { + return this.history.length > 1; + } + + public goBack(): void { + if (this.canGoBack()) { + this.history.pop(); + this.router.navigateByUrl(this.history[this.history.length - 1]); + } + } +} diff --git a/bizmatch/src/app/services/listings.service.ts b/bizmatch/src/app/services/listings.service.ts index ed22c9c..2dfdb14 100644 --- a/bizmatch/src/app/services/listings.service.ts +++ b/bizmatch/src/app/services/listings.service.ts @@ -12,9 +12,6 @@ export class ListingsService { private apiBaseUrl = environment.apiBaseUrl; constructor(private http: HttpClient) {} - // getAllListings():Observable{ - // return this.http.get(`${this.apiBaseUrl}/bizmatch/business-listings`); - // } async getListings(criteria: ListingCriteria, listingsCategory: 'business' | 'professionals_brokers' | 'commercialProperty'): Promise { const result = await lastValueFrom(this.http.post(`${this.apiBaseUrl}/bizmatch/listings/${listingsCategory}/search`, criteria)); return result;