Überarbeitung

This commit is contained in:
2024-08-09 17:59:49 +02:00
parent 6d1c50d5df
commit 1e1d5cea57
27 changed files with 135 additions and 112 deletions

View File

@@ -2,7 +2,13 @@
<div class="relative w-full max-w-4xl max-h-full">
<div class="relative bg-white rounded-lg shadow">
<div class="flex items-start justify-between p-4 border-b rounded-t">
@if(criteria.criteriaType==='businessListings'){
<h3 class="text-xl font-semibold text-gray-900">Business Listing Search</h3>
} @else if (criteria.criteriaType==='commercialPropertyListings'){
<h3 class="text-xl font-semibold text-gray-900">Property Listing Search</h3>
} @else {
<h3 class="text-xl font-semibold text-gray-900">Professional Listing Search</h3>
}
<button (click)="modalService.reject()" type="button" class="text-gray-400 bg-transparent hover:bg-gray-200 hover:text-gray-900 rounded-lg text-sm w-8 h-8 ml-auto inline-flex justify-center items-center">
<svg class="w-3 h-3" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 14 14">
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m1 1 6 6m0 0 6 6M7 7l6-6M7 7l-6 6" />
@@ -20,10 +26,12 @@
<div class="space-y-4">
<div>
<label for="state" class="block mb-2 text-sm font-medium text-gray-900">Location - State</label>
<ng-select class="custom" [items]="selectOptions?.states" bindLabel="name" bindValue="value" [ngModel]="criteria.state" (ngModelChange)="setState($event)" name="state"> </ng-select>
</div>
<div>
<app-validated-city label="Location - City" name="city" [ngModel]="criteria.city" (ngModelChange)="setCity($event)" labelClasses="text-gray-900 font-medium" [state]="criteria.state"></app-validated-city>
</div>
<!-- <div>
<label for="city" class="block mb-2 text-sm font-medium text-gray-900">Location - City</label>
<ng-select
@@ -42,7 +50,7 @@
<ng-option [value]="city">{{ city.city }} - {{ city.state }}</ng-option>
}
</ng-select>
</div>
</div> -->
<!-- New section for city search type -->
<div *ngIf="criteria.city">
<label class="block mb-2 text-sm font-medium text-gray-900">Search Type</label>
@@ -241,7 +249,7 @@
<ng-select class="custom" [items]="selectOptions?.states" bindLabel="name" bindValue="value" [ngModel]="criteria.state" (ngModelChange)="setState($event)" name="state"> </ng-select>
</div>
<div>
<label for="city" class="block mb-2 text-sm font-medium text-gray-900">Location - City</label>
<!-- <label for="city" class="block mb-2 text-sm font-medium text-gray-900">Location - City</label>
<ng-select
class="custom"
[multiple]="false"
@@ -257,7 +265,8 @@
@for (city of cities$ | async; track city.id) {
<ng-option [value]="city">{{ city.city }} - {{ selectOptions.getStateInitials(city.state) }}</ng-option>
}
</ng-select>
</ng-select> -->
<app-validated-city label="Location - City" name="city" [ngModel]="criteria.city" (ngModelChange)="setCity($event)" labelClasses="text-gray-900 font-medium" [state]="criteria.state"></app-validated-city>
</div>
<!-- New section for city search type -->
<div *ngIf="criteria.city">
@@ -363,13 +372,10 @@
[typeahead]="countyInput$"
[(ngModel)]="criteria.counties"
>
<!-- @for (county of counties$ | async; track county.id) {
<ng-option [value]="city.city">{{ city.city }} - {{ selectOptions.getStateInitials(city.state) }}</ng-option>
} -->
</ng-select>
</div>
<div>
<label for="city" class="block mb-2 text-sm font-medium text-gray-900">Location - City</label>
<!-- <label for="city" class="block mb-2 text-sm font-medium text-gray-900">Location - City</label>
<ng-select
class="custom"
[multiple]="false"
@@ -383,9 +389,10 @@
(ngModelChange)="setCity($event)"
>
@for (city of cities$ | async; track city.id) {
<ng-option [value]="city">{{ city.city }} - {{ selectOptions.getStateInitials(city.state) }}</ng-option>
<ng-option [value]="city">{{ city.name }} - {{ selectOptions.getStateInitials(city.state) }}</ng-option>
}
</ng-select>
</ng-select> -->
<app-validated-city label="Location - City" name="city" [ngModel]="criteria.city" (ngModelChange)="setCity($event)" labelClasses="text-gray-900 font-medium" [state]="criteria.state"></app-validated-city>
</div>
<!-- New section for city search type -->
<div *ngIf="criteria.city">

View File

@@ -10,12 +10,13 @@ import { ListingsService } from '../../services/listings.service';
import { SelectOptionsService } from '../../services/select-options.service';
import { UserService } from '../../services/user.service';
import { SharedModule } from '../../shared/shared/shared.module';
import { ValidatedCityComponent } from '../validated-city/validated-city.component';
import { ModalService } from './modal.service';
@UntilDestroy()
@Component({
selector: 'app-search-modal',
standalone: true,
imports: [SharedModule, AsyncPipe, NgIf, NgSelectModule],
imports: [SharedModule, AsyncPipe, NgIf, NgSelectModule, ValidatedCityComponent],
templateUrl: './search-modal.component.html',
styleUrl: './search-modal.component.scss',
})
@@ -98,7 +99,7 @@ export class SearchModalComponent {
}
setCity(city) {
if (city) {
this.criteria.city = city.city;
this.criteria.city = city;
this.criteria.state = city.state;
} else {
this.criteria.city = null;

View File

@@ -1,5 +1,5 @@
<div>
<label for="type" class="block text-sm font-bold text-gray-700 mb-1 relative w-fit"
<label for="type" class="block text-sm font-bold text-gray-700 mb-1 relative w-fit {{ labelClasses }}"
>{{ label }} @if(validationMessage){
<div
attr.data-tooltip-target="tooltip-{{ name }}"
@@ -19,11 +19,11 @@
[loading]="cityLoading"
typeToSearchText="Please enter 2 or more characters"
[typeahead]="cityInput$"
ngModel="{{ value?.city }} {{ value ? '-' : '' }} {{ value?.state }}"
ngModel="{{ value?.name }} {{ value ? '-' : '' }} {{ value?.state }}"
(ngModelChange)="onInputChange($event)"
>
@for (city of cities$ | async; track city.id) {
<ng-option [value]="city">{{ city.city }} - {{ city.state }}</ng-option>
<ng-option [value]="city">{{ city.name }} - {{ city.state }}</ng-option>
}
</ng-select>
</div>

View File

@@ -1,7 +1,7 @@
:host ::ng-deep .ng-select.custom .ng-select-container {
// --tw-bg-opacity: 1;
// background-color: rgb(249 250 251 / var(--tw-bg-opacity));
height: 42px;
// height: 42px;
border-radius: 0.5rem;
.ng-value-container .ng-input {
top: 10px;

View File

@@ -27,6 +27,8 @@ import { ValidationMessagesService } from '../validation-messages.service';
})
export class ValidatedCityComponent extends BaseInputComponent {
@Input() items;
@Input() labelClasses: string;
@Input() state: string;
cities$: Observable<GeoResult[]>;
cityInput$ = new Subject<string>();
countyInput$ = new Subject<string>();
@@ -50,7 +52,7 @@ export class ValidatedCityComponent extends BaseInputComponent {
distinctUntilChanged(),
tap(() => (this.cityLoading = true)),
switchMap(term =>
this.geoService.findCitiesStartingWith(term).pipe(
this.geoService.findCitiesStartingWith(term, this.state).pipe(
catchError(() => of([])), // empty list on error
// map(cities => cities.map(city => city.city)), // transform the list of objects to a list of city names
tap(() => (this.cityLoading = false)),

View File

@@ -121,7 +121,7 @@ export class DetailsBusinessListingComponent {
}
return [
{ label: 'Category', value: this.selectOptions.getBusiness(this.listing.type) },
{ label: 'Located in', value: `${this.listing.location.city}, ${this.selectOptions.getState(this.listing.location.state)}` },
{ label: 'Located in', value: `${this.listing.location.name}, ${this.selectOptions.getState(this.listing.location.state)}` },
{ label: 'Asking Price', value: `$${this.listing.price?.toLocaleString()}` },
{ label: 'Sales revenue', value: `$${this.listing.salesRevenue?.toLocaleString()}` },
{ label: 'Cash flow', value: `$${this.listing.cashFlow?.toLocaleString()}` },

View File

@@ -97,7 +97,7 @@ export class DetailsCommercialPropertyListingComponent {
this.propertyDetails = [
{ label: 'Property Category', value: this.selectOptions.getCommercialProperty(this.listing.type) },
{ label: 'Located in', value: this.selectOptions.getState(this.listing.location.state) },
{ label: 'City', value: this.listing.location.city },
{ label: 'City', value: this.listing.location.name },
{ label: 'Asking Price:', value: `$${this.listing.price?.toLocaleString()}` },
];
//this.initFlowbite();

View File

@@ -199,7 +199,7 @@
</div>
<div class="flex flex-col sm:flex-row sm:items-center">
<span class="font-semibold w-40 p-2">Company Location</span>
<span class="p-2 flex-grow">{{ user.companyLocation.city }} - {{ user.companyLocation.state }}</span>
<span class="p-2 flex-grow">{{ user.companyLocation.name }} - {{ user.companyLocation.state }}</span>
</div>
</div>

View File

@@ -113,8 +113,8 @@
placeholder="Enter City or State ..."
groupBy="type"
>
@for (city of cities$ | async; track city.id) {
<ng-option [value]="city">{{ city.name }} - {{ city.state }}</ng-option>
@for (city of cities$ | async; track city.id) { @let state = city.type==='city'?city.content.state:''; @let separator = city.type==='city'?' - ':'';
<ng-option [value]="city">{{ city.content.name }}{{ separator }}{{ state }}</ng-option>
}
</ng-select>
</div>

View File

@@ -64,6 +64,7 @@ export class HomeComponent {
}
async changeTab(tabname: 'business' | 'commercialProperty' | 'broker') {
this.activeTabAction = tabname;
this.cityOrState = null;
if ('business' === tabname) {
this.criteria = createEnhancedProxy(getCriteriaStateObject('businessListings'), this);
} else if ('commercialProperty' === tabname) {
@@ -74,22 +75,7 @@ export class HomeComponent {
this.criteria = undefined;
}
}
// private createEnhancedProxy(obj: any) {
// const component = this;
// const sessionStorageHandler = function (path, value, previous, applyData) {
// let criteriaType = this.criteriaType;
// sessionStorage.setItem(`${criteriaType}_criteria`, JSON.stringify(this));
// };
// return onChange(obj, function (path, value, previous, applyData) {
// // Call the original sessionStorageHandler
// sessionStorageHandler.call(this, path, value, previous, applyData);
// // Notify about the criteria change using the component's context
// component.criteriaChangeService.notifyCriteriaChange();
// });
// }
search() {
this.router.navigate([`${this.activeTabAction}Listings`]);
}
@@ -126,7 +112,6 @@ export class HomeComponent {
async openModal() {
const accepted = await this.modalService.showModal(this.criteria);
if (accepted) {
//this.searchService.search(this.criteria);
this.router.navigate([`${this.activeTabAction}Listings`]);
}
}
@@ -153,10 +138,10 @@ export class HomeComponent {
setCityOrState(cityOrState: CityAndStateResult) {
if (cityOrState) {
if (cityOrState.type === 'state') {
this.criteria.state = cityOrState.state;
this.criteria.state = cityOrState.content.state_code;
} else {
this.criteria.city = cityOrState.name;
this.criteria.state = cityOrState.state;
this.criteria.city = cityOrState.content as GeoResult;
this.criteria.state = cityOrState.content.state;
this.criteria.searchType = 'radius';
this.criteria.radius = 20;
}

View File

@@ -99,7 +99,7 @@
<p class="text-sm text-gray-600 mb-1">Asking price: {{ listing.price | currency }}</p>
<p class="text-sm text-gray-600 mb-1">Sales revenue: {{ listing.salesRevenue | currency }}</p>
<p class="text-sm text-gray-600 mb-1">Net profit: {{ listing.cashFlow | currency }}</p>
<p class="text-sm text-gray-600 mb-1">Location: {{ listing.location.city }} - {{ listing.location.state }}</p>
<p class="text-sm text-gray-600 mb-1">Location: {{ listing.location.name }} - {{ listing.location.state }}</p>
<p class="text-sm text-gray-600 mb-1">Established: {{ listing.established }}</p>
<img src="{{ env.imageBaseUrl }}/pictures/logo/{{ listing.imageName }}.avif?_ts={{ ts }}" alt="Company logo" class="absolute bottom-[70px] right-[30px] h-[35px] w-auto" />
<div class="flex-grow"></div>

View File

@@ -13,7 +13,7 @@
<span class="text-gray-600 text-sm"><i [class]="selectOptions.getIconTypeOfCommercials(listing.type)" class="mr-1"></i> {{ selectOptions.getCommercialProperty(listing.type) }}</span>
</div>
<h3 class="text-lg font-semibold mb-2">{{ listing.title }}</h3>
<p class="text-gray-600 mb-2">{{ listing.location.city }}</p>
<p class="text-gray-600 mb-2">{{ listing.location.name }}</p>
<p class="text-xl font-bold mb-4">{{ listing.price | currency }}</p>
<button [routerLink]="['/details-commercial-property-listing', listing.id]" class="bg-green-500 text-white px-4 py-2 rounded-full w-full hover:bg-green-600 transition duration-300">
View Full Listing <i class="fas fa-arrow-right ml-1"></i>

View File

@@ -100,7 +100,7 @@
<input type="text" id="description" name="description" [(ngModel)]="user.description" class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500" />
</div> -->
<app-validated-input label="Company Name" name="companyName" [(ngModel)]="user.companyName"></app-validated-input>
<app-validated-input label="Describe yourself" name="description" [(ngModel)]="user.description"></app-validated-input>
<app-validated-input label="Describe Yourself" name="description" [(ngModel)]="user.description"></app-validated-input>
</div>
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">

View File

@@ -169,7 +169,7 @@ export class AccountComponent {
async search(event: AutoCompleteCompleteEvent) {
const result = await lastValueFrom(this.geoService.findCitiesStartingWith(event.query));
this.suggestions = result.map(r => `${r.city} - ${r.state}`).slice(0, 5);
this.suggestions = result.map(r => `${r.name} - ${r.state}`).slice(0, 5);
}
addLicence() {
this.user.licensedIn.push({ registerNo: '', state: '' });

View File

@@ -140,7 +140,7 @@ export class EditBusinessListingComponent {
async search(event: AutoCompleteCompleteEvent) {
const result = await lastValueFrom(this.geoService.findCitiesStartingWith(event.query));
this.suggestions = result.map(r => r.city).slice(0, 5);
this.suggestions = result.map(r => r.name).slice(0, 5);
}
changeListingCategory(value: 'business' | 'commercialProperty') {

View File

@@ -177,7 +177,7 @@ export class EditCommercialPropertyListingComponent {
async search(event: AutoCompleteCompleteEvent) {
const result = await lastValueFrom(this.geoService.findCitiesStartingWith(event.query));
this.suggestions = result.map(r => r.city).slice(0, 5);
this.suggestions = result.map(r => r.name).slice(0, 5);
}
openFileDialog() {
this.fileInput.nativeElement.click();

View File

@@ -52,7 +52,7 @@
<div *ngFor="let listing of myListings" class="bg-white shadow-md rounded-lg p-4 mb-4">
<h2 class="text-xl font-semibold mb-2">{{ listing.title }}</h2>
<p class="text-gray-600 mb-2">Category: {{ listing.listingsCategory === 'commercialProperty' ? 'Commercial Property' : 'Business' }}</p>
<p class="text-gray-600 mb-4">Located in: {{ listing.location.city }} - {{ listing.location.state }}</p>
<p class="text-gray-600 mb-4">Located in: {{ listing.location.name }} - {{ listing.location.state }}</p>
<div class="flex justify-end">
<button class="bg-green-500 text-white p-2 rounded-full mr-2">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">

View File

@@ -93,8 +93,8 @@ export function createEmptyBusinessListingCriteria(): BusinessListingCriteria {
start: 0,
length: 0,
page: 0,
state: '',
city: '',
state: null,
city: null,
types: [],
prompt: '',
criteriaType: 'businessListings',
@@ -123,8 +123,8 @@ export function createEmptyCommercialPropertyListingCriteria(): CommercialProper
start: 0,
length: 0,
page: 0,
state: '',
city: '',
state: null,
city: null,
types: [],
prompt: '',
criteriaType: 'commercialPropertyListings',
@@ -141,7 +141,7 @@ export function createEmptyUserListingCriteria(): UserListingCriteria {
start: 0,
length: 0,
page: 0,
city: '',
city: null,
types: [],
prompt: '',
criteriaType: 'brokerListings',