Skip to content

Commit

Permalink
DSS-918: FE: Adding icon multi-host listings + click through to results
Browse files Browse the repository at this point in the history
  • Loading branch information
OleksandrBohuslavskyi committed Nov 21, 2024
1 parent b0a06e4 commit fd87ef4
Show file tree
Hide file tree
Showing 10 changed files with 162 additions and 36 deletions.
1 change: 1 addition & 0 deletions frontend/src/app/common/models/listing-details.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ export interface ListingDetails {
hasAtLeastOneValidHostEmail: boolean;
hostsInfo: Array<ListingDetailsHostInfo>;
bizLicenceInfo: BusinessLicence;
hasMultipleProperties: boolean;
}

export interface ListingDetailsWithHostCheckboxExtension extends ListingDetails {
Expand Down
1 change: 1 addition & 0 deletions frontend/src/app/common/models/listing-table-row.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ export interface AggregatedListingTableRow {
listingCount: number;
listings: Array<ListingTableRow>;

hasMultipleProperties: boolean;
selected?: boolean;
id?: string;
}
38 changes: 19 additions & 19 deletions frontend/src/app/common/services/listing-data.service.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { forkJoin, Observable } from 'rxjs';
import { forkJoin, map, Observable } from 'rxjs';
import { environment } from '../../../environments/environment';
import { PagingResponse } from '../models/paging-response';
import { ListingUploadHistoryRecord } from '../models/listing-upload-history-record';
Expand All @@ -22,7 +22,7 @@ export class ListingDataService {

textHeaders = new HttpHeaders().set('Content-Type', 'text/plain; charset=utf-8');

constructor(private httpClient: HttpClient) {}
constructor(private httpClient: HttpClient) { }

uploadListings(reportPeriod: string, organizationId: number, file: any): Observable<unknown> {
const formData = new FormData();
Expand Down Expand Up @@ -108,14 +108,12 @@ export class ListingDataService {
if (filter) {
if (filter.byLocation) {
if (!!filter.byLocation?.isPrincipalResidenceRequired) {
endpointUrl += `&prRequirement=${
filter.byLocation.isPrincipalResidenceRequired == 'Yes'
}`;
endpointUrl += `&prRequirement=${filter.byLocation.isPrincipalResidenceRequired == 'Yes'
}`;
}
if (!!filter.byLocation?.isBusinessLicenceRequired) {
endpointUrl += `&blRequirement=${
filter.byLocation.isBusinessLicenceRequired == 'Yes'
}`;
endpointUrl += `&blRequirement=${filter.byLocation.isBusinessLicenceRequired == 'Yes'
}`;
}
}
if (filter.byStatus) {
Expand Down Expand Up @@ -149,6 +147,11 @@ export class ListingDataService {
return this.httpClient.get<PagingResponse<ListingTableRow>>(endpointUrl);
}

getHostListingsCount(primaryHostNm: string): Observable<{ primaryHostNm: string, hasMultipleProperties: boolean }> {
return this.httpClient.get<number>(`${environment.API_HOST}/rentallistings/grouped/count?hostName=${primaryHostNm}`)
.pipe(map(count => ({ primaryHostNm, hasMultipleProperties: count > 1 })));
}

getAggregatedListings(
pageNumber: number = 1,
pageSize: number = 10,
Expand Down Expand Up @@ -185,14 +188,12 @@ export class ListingDataService {
if (filter) {
if (filter.byLocation) {
if (!!filter.byLocation?.isPrincipalResidenceRequired) {
listingsEndpointUrl += `&prRequirement=${
filter.byLocation.isPrincipalResidenceRequired == 'Yes'
}`;
listingsEndpointUrl += `&prRequirement=${filter.byLocation.isPrincipalResidenceRequired == 'Yes'
}`;
}
if (!!filter.byLocation?.isBusinessLicenceRequired) {
listingsEndpointUrl += `&blRequirement=${
filter.byLocation.isBusinessLicenceRequired == 'Yes'
}`;
listingsEndpointUrl += `&blRequirement=${filter.byLocation.isBusinessLicenceRequired == 'Yes'
}`;
}
}
if (filter.byStatus) {
Expand Down Expand Up @@ -224,11 +225,10 @@ export class ListingDataService {
}
}

const listingsCountEndpointUrl = `${
environment.API_HOST
}/rentallistings/grouped/count${listingsEndpointUrl.substring(
listingsEndpointUrl.indexOf('?'),
)}`;
const listingsCountEndpointUrl = `${environment.API_HOST
}/rentallistings/grouped/count${listingsEndpointUrl.substring(
listingsEndpointUrl.indexOf('?'),
)}`;

//return this.httpClient.get<PagingResponse<AggregatedListingTableRow>>(listingsEndpointUrl);
return forkJoin({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,13 @@ <h2 class="title">Aggregated Listings</h2>
<i class="pi" [ngClass]="expanded ? 'pi pi-chevron-down' : 'pi pi-chevron-right'"></i>
</button>
</td>
<td>{{ row.primaryHostNm }}</td>
<td>
<div class="host-name">
{{ row.primaryHostNm }}
<i *ngIf="row.hasMultipleProperties" pTooltip="This Host May have Multiple Properties."
class="multi-host multihost-icon"></i>
</div>
</td>
<td>{{ row.matchAddressTxt }} </td>
<td>
<span [class.night-stayed-exceeded]="row.nightsBookedYtdQty>=90">
Expand Down Expand Up @@ -386,4 +392,4 @@ <h2 class="title">Aggregated Listings</h2>
(click)="onCancelFilters()"></button>
</div>
</ng-template>
</p-sidebar>
</p-sidebar>
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,23 @@
font-size: 12px;
word-break: break-word;

.host-name {
width: 100%;
display: flex;
justify-content: start;
align-items: center;
gap: 12px;

.multihost-icon {
width: 24px;
height: 24px;
background-image: url(../../../../../assets/images/house-blue.svg);
background-position: center center;
background-repeat: no-repeat;
background-size: cover;
}
}

&.listings-count {
font-size: smaller;
color: #afadad;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import { SidebarModule } from 'primeng/sidebar';
import { TableModule } from 'primeng/table';
import { TagModule } from 'primeng/tag';
import { TooltipModule } from 'primeng/tooltip';
import { ListingDetailsComponent } from '../listing-details/listing-details.component';
import { ListingFilter } from '../../../../common/models/listing-filter';
import { environment } from '../../../../../environments/environment';
import { PagingResponsePageInfo } from '../../../../common/models/paging-response';
Expand All @@ -36,6 +35,7 @@ import { ListingSearchRequest } from '../../../../common/models/listing-search-r
import { ListingDetails } from '../../../../common/models/listing-details';
import { OrganizationService } from '../../../../common/services/organization.service';
import { UrlProtocolPipe } from '../../../../common/pipes/url-protocol.pipe';
import { forkJoin, tap } from 'rxjs';

@Component({
selector: 'app-aggregated-listings-table',
Expand All @@ -52,7 +52,6 @@ import { UrlProtocolPipe } from '../../../../common/pipes/url-protocol.pipe';
PanelModule,
RouterModule,
TooltipModule,
ListingDetailsComponent,
TagModule,
SidebarModule,
AccordionModule,
Expand All @@ -74,6 +73,7 @@ export class AggregatedListingsTableComponent implements OnInit {
searchColumns = new Array<DropdownOption>();
communities = new Array<DropdownOptionOrganization>();
groupedCommunities = new Array();
hosts = new Array<{ primaryHostNm: string, hasMultipleProperties: boolean }>();

isCEU = false;
isLegendShown = false;
Expand Down Expand Up @@ -137,6 +137,11 @@ export class AggregatedListingsTableComponent implements OnInit {
if (prms['searchTerm']) {
this.searchTerm = prms['searchTerm'];
}
if (prms['hostName']) {
this.searchColumn = 'hostName';
this.searchTerm = prms['hostName'];
}
this.cd.detectChanges();
this.cloakParams();

this.userService.getCurrentUser().subscribe({
Expand Down Expand Up @@ -212,7 +217,9 @@ export class AggregatedListingsTableComponent implements OnInit {
}

onDetailsOpen(row: ListingTableRow): void {
this.router.navigateByUrl(`/listings/${row.rentalListingId}`);
this.router.navigate([`/listings/${row.rentalListingId}`], {
queryParams: { returnUrl: this.getUrlFromState() },
});
}

onNoticeOpen(): void {
Expand Down Expand Up @@ -377,6 +384,8 @@ export class AggregatedListingsTableComponent implements OnInit {
this.sort?.dir || 'asc',
searchReq,
this.currentFilter,
).pipe(
tap(res => { this.calculateIfHostsHaveMoreThanOneProperty(res.listings.sourceList); })
)
.subscribe({
next: (res) => {
Expand Down Expand Up @@ -443,6 +452,24 @@ export class AggregatedListingsTableComponent implements OnInit {
this.cd.detectChanges();
}

private calculateIfHostsHaveMoreThanOneProperty(listings: Array<AggregatedListingTableRow>): void {
const uniqueObjects = new Map<string, AggregatedListingTableRow>();

listings.forEach(obj => {
uniqueObjects.set(obj.primaryHostNm, obj);
});

const hosts = Array.from(uniqueObjects.values()).map(x => ({ primaryHostNm: x.primaryHostNm, hasMultipleProperties: false }));

forkJoin(hosts.map(h => this.listingService.getHostListingsCount(h.primaryHostNm)))
.subscribe(hostCount => {
this.aggregatedListings.forEach(al => {
al.hasMultipleProperties = hostCount.find(x => x.primaryHostNm === al.primaryHostNm)?.hasMultipleProperties ?? false;
this.cd.detectChanges();
})
});
}

private getUrlFromState(): string {
const state = {
pageNumber: this.currentPage?.pageNumber || 0,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,24 @@ <h2>Detailed Listing Information for</h2>
<ng-template ngFor let-host [ngForOf]="listing.hosts" let-i="index">
<div class="row">
<span class="label">{{host.isPropertyOwner?'Property':'STR'}} Host (Platform Listing):</span>
<span class="value">{{host.fullNm}}</span>
<span class="value" [class.has-multiple-properties]="listing.hasMultipleProperties">
@if (host.isPropertyOwner) {

@if(listing.hasMultipleProperties){
<button pButton class="p-button-link zero-padding"
(click)="navigateToListingsByHost()">{{host.fullNm}}</button>
<i pTooltip="This host may have multiple properties in B.C. Click the host name to view more listings. Note: you can only view listings within your own jurisdiction."
class="multi-host multihost-icon"></i>
}
@else{
{{host.fullNm}}
}

}
@else {
{{host.fullNm}}
}
</span>
</div>
<div class="row">
<span class="label">{{host.isPropertyOwner?'Property':'STR'}} Host Address:</span>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -451,4 +451,19 @@
}
}
}

.has-multiple-properties {
display: flex;
gap: 8px;
align-items: center;

.multihost-icon {
width: 24px;
height: 24px;
background-image: url(../../../../../assets/images/house-blue.svg);
background-position: center center;
background-repeat: no-repeat;
background-size: cover;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { PanelModule } from 'primeng/panel';
import { ButtonModule } from 'primeng/button';
import { TableModule } from 'primeng/table';
import { CommonModule } from '@angular/common';
import { ActivatedRoute, Router } from '@angular/router';
import { ActivatedRoute, Router, RouterModule } from '@angular/router';
import { ListingDataService } from '../../../../common/services/listing-data.service';
import { ListingAddressCandidate, ListingDetails } from '../../../../common/models/listing-details';
import { DialogModule } from 'primeng/dialog';
Expand All @@ -24,6 +24,7 @@ import { BusinessLicenceService } from '../../../../common/services/business-lic
import { BLSearchResultRow } from '../../../../common/models/bl-search-result-row';
import { UrlProtocolPipe } from '../../../../common/pipes/url-protocol.pipe';
import { TextCleanupPipe } from '../../../../common/pipes/text-cleanup.pipe';
import { tap } from 'rxjs';

@Component({
selector: 'app-listing-details',
Expand All @@ -42,6 +43,7 @@ import { TextCleanupPipe } from '../../../../common/pipes/text-cleanup.pipe';
TagModule,
UrlProtocolPipe,
TextCleanupPipe,
RouterModule,
],
templateUrl: './listing-details.component.html',
styleUrl: './listing-details.component.scss'
Expand All @@ -67,6 +69,7 @@ export class ListingDetailsComponent implements OnInit {
selectedBl!: BLSearchResultRow | null;
searchBlText = '';
noBlsFound = false;
returnUrl!: string;

constructor(
private route: ActivatedRoute,
Expand All @@ -84,6 +87,9 @@ export class ListingDetailsComponent implements OnInit {
this.loaderService.loadingStart();
this.id = this.route.snapshot.params['id'];

this.route.queryParams.subscribe(
(param) => { this.returnUrl = param['returnUrl']; });

this.userDataService.getCurrentUser().subscribe({
next: (user) => {
this.isCEU = user.organizationType === 'BCGov';
Expand Down Expand Up @@ -223,6 +229,17 @@ export class ListingDetailsComponent implements OnInit {
this.addressChangeCandidates = [];
}

navigateToListingsByHost(): void {
const owner = this.listing.hosts.find(x => x.isPropertyOwner);
if (owner) {
const url = this.router.serializeUrl(this.router.createUrlTree([`/aggregated-listings`], { queryParams: { hostName: owner.fullNm } }));
window.open(url, '_blank');
}
else {
this.errorService.showError(`Unable to retrieve the host's name. Neither host is the owner`);
}
}

onSubmitAddressChange(): void {
let observableRef;
this.loaderService.loadingStart();
Expand Down Expand Up @@ -262,15 +279,30 @@ export class ListingDetailsComponent implements OnInit {

private getListingDetailsById(id: number): void {
this.loaderService.loadingStart();
this.listingService.getListingDetailsById(id).subscribe({
next: (response: ListingDetails) => {
this.listing = response;
this.blInfo = response.bizLicenceInfo;
},
complete: () => {
this.loaderService.loadingEnd();
this.cd.detectChanges();
}
});
this.listingService.getListingDetailsById(id)
.pipe(
tap((listing) => {
if (listing.hosts.length) {
const owner = listing.hosts.find(x => x.isPropertyOwner);

if (owner) {
this.listingService.getHostListingsCount(owner.fullNm)
.subscribe(x => {
this.listing.hasMultipleProperties = x.hasMultipleProperties;
this.cd.detectChanges();
});
}
}
})
).subscribe({
next: (response: ListingDetails) => {
this.listing = response;
this.blInfo = response.bizLicenceInfo;
},
complete: () => {
this.loaderService.loadingEnd();
this.cd.detectChanges();
}
});
}
}
10 changes: 10 additions & 0 deletions frontend/src/assets/images/house-blue.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit fd87ef4

Please sign in to comment.