Ai Search finished, some makeup changes, guards, brokerSearch
This commit is contained in:
parent
8721be4a90
commit
ede8b66d83
|
|
@ -14,6 +14,5 @@ export class AppController {
|
||||||
@Get()
|
@Get()
|
||||||
getHello(@Request() req): string {
|
getHello(@Request() req): string {
|
||||||
return req.user;
|
return req.user;
|
||||||
//return 'dfgdf';
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,24 +1,30 @@
|
||||||
import { Controller, Get, Param } from '@nestjs/common';
|
import { Controller, Get, Param, UseGuards } from '@nestjs/common';
|
||||||
|
import { AdminAuthGuard } from '../jwt-auth/admin-auth.guard.js';
|
||||||
import { AuthService } from './auth.service.js';
|
import { AuthService } from './auth.service.js';
|
||||||
|
|
||||||
@Controller('auth')
|
@Controller('auth')
|
||||||
export class AuthController {
|
export class AuthController {
|
||||||
constructor(private readonly authService: AuthService) {}
|
constructor(private readonly authService: AuthService) {}
|
||||||
|
|
||||||
|
@UseGuards(AdminAuthGuard)
|
||||||
@Get()
|
@Get()
|
||||||
getAccessToken(): any {
|
getAccessToken(): any {
|
||||||
return this.authService.getAccessToken();
|
return this.authService.getAccessToken();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@UseGuards(AdminAuthGuard)
|
||||||
@Get('users')
|
@Get('users')
|
||||||
getUsers(): any {
|
getUsers(): any {
|
||||||
return this.authService.getUsers();
|
return this.authService.getUsers();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@UseGuards(AdminAuthGuard)
|
||||||
@Get('user/:userid')
|
@Get('user/:userid')
|
||||||
getUser(@Param('userid') userId: string): any {
|
getUser(@Param('userid') userId: string): any {
|
||||||
return this.authService.getUser(userId);
|
return this.authService.getUser(userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@UseGuards(AdminAuthGuard)
|
||||||
@Get('user/:userid/lastlogin') //e0811669-c7eb-4e5e-a699-e8334d5c5b01 -> aknuth
|
@Get('user/:userid/lastlogin') //e0811669-c7eb-4e5e-a699-e8334d5c5b01 -> aknuth
|
||||||
getLastLogin(@Param('userid') userId: string): any {
|
getLastLogin(@Param('userid') userId: string): any {
|
||||||
return this.authService.getLastLogin(userId);
|
return this.authService.getLastLogin(userId);
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
import { CanActivate, ExecutionContext, Injectable, UnauthorizedException } from '@nestjs/common';
|
||||||
|
import { AuthGuard } from '@nestjs/passport';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class AdminAuthGuard extends AuthGuard('jwt') implements CanActivate {
|
||||||
|
canActivate(context: ExecutionContext) {
|
||||||
|
// Add your custom authentication logic here
|
||||||
|
// for example, call super.logIn(request) to establish a session.
|
||||||
|
return super.canActivate(context);
|
||||||
|
}
|
||||||
|
handleRequest(err, user, info) {
|
||||||
|
// You can throw an exception based on either "info" or "err" arguments
|
||||||
|
if (err || !user || !user.roles.includes('ADMIN')) {
|
||||||
|
throw err || new UnauthorizedException(info);
|
||||||
|
}
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -10,7 +10,7 @@ import { FileService } from '../file/file.service.js';
|
||||||
import { GeoService } from '../geo/geo.service.js';
|
import { GeoService } from '../geo/geo.service.js';
|
||||||
import { BusinessListing, BusinessListingSchema } from '../models/db.model.js';
|
import { BusinessListing, BusinessListingSchema } from '../models/db.model.js';
|
||||||
import { BusinessListingCriteria, emailToDirName, JwtUser } from '../models/main.model.js';
|
import { BusinessListingCriteria, emailToDirName, JwtUser } from '../models/main.model.js';
|
||||||
import { convertBusinessToDrizzleBusiness, convertDrizzleBusinessToBusiness, getDistanceQuery } from '../utils.js';
|
import { convertBusinessToDrizzleBusiness, convertDrizzleBusinessToBusiness, getDistanceQuery, splitName } from '../utils.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class BusinessListingService {
|
export class BusinessListingService {
|
||||||
|
|
@ -94,10 +94,17 @@ export class BusinessListingService {
|
||||||
if (criteria.title) {
|
if (criteria.title) {
|
||||||
whereConditions.push(or(ilike(businesses.title, `%${criteria.title}%`), ilike(businesses.description, `%${criteria.title}%`)));
|
whereConditions.push(or(ilike(businesses.title, `%${criteria.title}%`), ilike(businesses.description, `%${criteria.title}%`)));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (criteria.brokerName) {
|
if (criteria.brokerName) {
|
||||||
whereConditions.push(or(ilike(schema.users.firstname, `%${criteria.brokerName}%`), ilike(schema.users.lastname, `%${criteria.brokerName}%`)));
|
const { firstname, lastname } = splitName(criteria.brokerName);
|
||||||
|
if (firstname === lastname) {
|
||||||
|
whereConditions.push(or(ilike(schema.users.firstname, `%${firstname}%`), ilike(schema.users.lastname, `%${lastname}%`)));
|
||||||
|
} else {
|
||||||
|
whereConditions.push(and(ilike(schema.users.firstname, `%${firstname}%`), ilike(schema.users.lastname, `%${lastname}%`)));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
// if (criteria.brokerName) {
|
||||||
|
// whereConditions.push(or(ilike(schema.users.firstname, `%${criteria.brokerName}%`), ilike(schema.users.lastname, `%${criteria.brokerName}%`)));
|
||||||
|
// }
|
||||||
if (!user?.roles?.includes('ADMIN') ?? false) {
|
if (!user?.roles?.includes('ADMIN') ?? false) {
|
||||||
whereConditions.push(or(eq(businesses.email, user?.username), ne(businesses.draft, true)));
|
whereConditions.push(or(eq(businesses.email, user?.username), ne(businesses.draft, true)));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ import { WINSTON_MODULE_PROVIDER } from 'nest-winston';
|
||||||
import { Logger } from 'winston';
|
import { Logger } from 'winston';
|
||||||
import { ZodError } from 'zod';
|
import { ZodError } from 'zod';
|
||||||
import { FileService } from '../file/file.service.js';
|
import { FileService } from '../file/file.service.js';
|
||||||
|
import { JwtAuthGuard } from '../jwt-auth/jwt-auth.guard.js';
|
||||||
import { OptionalJwtAuthGuard } from '../jwt-auth/optional-jwt-auth.guard.js';
|
import { OptionalJwtAuthGuard } from '../jwt-auth/optional-jwt-auth.guard.js';
|
||||||
import { User } from '../models/db.model';
|
import { User } from '../models/db.model';
|
||||||
import { JwtUser, Subscription, UserListingCriteria } from '../models/main.model.js';
|
import { JwtUser, Subscription, UserListingCriteria } from '../models/main.model.js';
|
||||||
|
|
@ -77,6 +78,7 @@ export class UserController {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@UseGuards(JwtAuthGuard)
|
||||||
@Get('subscriptions/:id')
|
@Get('subscriptions/:id')
|
||||||
async findSubscriptionsById(@Param('id') id: string): Promise<Subscription[]> {
|
async findSubscriptionsById(@Param('id') id: string): Promise<Subscription[]> {
|
||||||
const subscriptions = this.fileService.getSubscriptions();
|
const subscriptions = this.fileService.getSubscriptions();
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ import { environment } from '../environments/environment';
|
||||||
import { customKeycloakAdapter } from '../keycloak';
|
import { customKeycloakAdapter } from '../keycloak';
|
||||||
import { routes } from './app.routes';
|
import { routes } from './app.routes';
|
||||||
import { LoadingInterceptor } from './interceptors/loading.interceptor';
|
import { LoadingInterceptor } from './interceptors/loading.interceptor';
|
||||||
|
import { TimeoutInterceptor } from './interceptors/timeout.interceptor';
|
||||||
import { KeycloakInitializerService } from './services/keycloak-initializer.service';
|
import { KeycloakInitializerService } from './services/keycloak-initializer.service';
|
||||||
import { SelectOptionsService } from './services/select-options.service';
|
import { SelectOptionsService } from './services/select-options.service';
|
||||||
import { createLogger } from './utils/utils';
|
import { createLogger } from './utils/utils';
|
||||||
|
|
@ -44,6 +45,15 @@ export const appConfig: ApplicationConfig = {
|
||||||
useClass: KeycloakBearerInterceptor,
|
useClass: KeycloakBearerInterceptor,
|
||||||
multi: true,
|
multi: true,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
provide: HTTP_INTERCEPTORS,
|
||||||
|
useClass: TimeoutInterceptor,
|
||||||
|
multi: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
provide: 'TIMEOUT_DURATION',
|
||||||
|
useValue: 5000, // Standard-Timeout von 5 Sekunden
|
||||||
|
},
|
||||||
provideRouter(
|
provideRouter(
|
||||||
routes,
|
routes,
|
||||||
withEnabledBlockingInitialNavigation(),
|
withEnabledBlockingInitialNavigation(),
|
||||||
|
|
|
||||||
|
|
@ -124,7 +124,7 @@ export const routes: Routes = [
|
||||||
{
|
{
|
||||||
path: 'emailUs',
|
path: 'emailUs',
|
||||||
component: EmailUsComponent,
|
component: EmailUsComponent,
|
||||||
canActivate: [AuthGuard],
|
// canActivate: [AuthGuard],
|
||||||
},
|
},
|
||||||
// #########
|
// #########
|
||||||
// Logout
|
// Logout
|
||||||
|
|
|
||||||
|
|
@ -73,7 +73,7 @@
|
||||||
<a (click)="login()" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 dark:hover:bg-gray-600 dark:text-gray-200 dark:hover:text-white">Log In</a>
|
<a (click)="login()" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 dark:hover:bg-gray-600 dark:text-gray-200 dark:hover:text-white">Log In</a>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a (click)="register()" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 dark:hover:bg-gray-600 dark:text-gray-200 dark:hover:text-white">Register</a>
|
<a routerLink="/pricing" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 dark:hover:bg-gray-600 dark:text-gray-200 dark:hover:text-white">Register</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -109,9 +109,7 @@ export class HeaderComponent {
|
||||||
redirectUri: `${window.location.origin}/login${this.router.routerState.snapshot.url}`,
|
redirectUri: `${window.location.origin}/login${this.router.routerState.snapshot.url}`,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
register() {
|
|
||||||
this.keycloakService.register({ redirectUri: `${window.location.origin}/account` });
|
|
||||||
}
|
|
||||||
isActive(route: string): boolean {
|
isActive(route: string): boolean {
|
||||||
return this.router.url === route;
|
return this.router.url === route;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -330,21 +330,23 @@
|
||||||
<div>
|
<div>
|
||||||
<label for="price" class="block mb-2 text-sm font-medium text-gray-900">Price</label>
|
<label for="price" class="block mb-2 text-sm font-medium text-gray-900">Price</label>
|
||||||
<div class="flex items-center space-x-2">
|
<div class="flex items-center space-x-2">
|
||||||
<input
|
<!-- <input
|
||||||
type="number"
|
type="number"
|
||||||
id="price-from"
|
id="price-from"
|
||||||
[(ngModel)]="criteria.minPrice"
|
[(ngModel)]="criteria.minPrice"
|
||||||
class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-1/2 p-2.5"
|
class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-1/2 p-2.5"
|
||||||
placeholder="From"
|
placeholder="From"
|
||||||
/>
|
/> -->
|
||||||
|
<app-validated-price name="price-from" [(ngModel)]="criteria.minPrice" placeholder="From" inputClasses="bg-gray-50 text-sm !mt-0 p-2.5"></app-validated-price>
|
||||||
<span>-</span>
|
<span>-</span>
|
||||||
<input
|
<app-validated-price name="price-to" [(ngModel)]="criteria.maxPrice" placeholder="To" inputClasses="bg-gray-50 text-sm !mt-0 p-2.5"></app-validated-price>
|
||||||
|
<!-- <input
|
||||||
type="number"
|
type="number"
|
||||||
id="price-to"
|
id="price-to"
|
||||||
[(ngModel)]="criteria.maxPrice"
|
[(ngModel)]="criteria.maxPrice"
|
||||||
class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-1/2 p-2.5"
|
class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-1/2 p-2.5"
|
||||||
placeholder="To"
|
placeholder="To"
|
||||||
/>
|
/> -->
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
import { HttpErrorResponse, HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http';
|
||||||
|
import { Inject, Injectable, Optional } from '@angular/core';
|
||||||
|
import { Observable, throwError, TimeoutError } from 'rxjs';
|
||||||
|
import { catchError, timeout } from 'rxjs/operators';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class TimeoutInterceptor implements HttpInterceptor {
|
||||||
|
constructor(@Optional() @Inject('TIMEOUT_DURATION') private timeoutDuration: number = 5000) {}
|
||||||
|
|
||||||
|
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
|
||||||
|
return next.handle(req).pipe(
|
||||||
|
timeout(this.timeoutDuration),
|
||||||
|
catchError((error: any) => {
|
||||||
|
if (error instanceof TimeoutError) {
|
||||||
|
// Timeout error handling
|
||||||
|
return throwError(
|
||||||
|
() =>
|
||||||
|
new HttpErrorResponse({
|
||||||
|
error: 'Request timed out',
|
||||||
|
status: 408, // HTTP status code for Request Timeout
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return throwError(() => error);
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -110,7 +110,7 @@ export class DetailsBusinessListingComponent {
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.messageService.addMessage({
|
this.messageService.addMessage({
|
||||||
severity: 'danger',
|
severity: 'danger',
|
||||||
text: 'An error occurred while sending the request',
|
text: 'An error occurred while sending the request - Please check your inputs',
|
||||||
duration: 5000,
|
duration: 5000,
|
||||||
});
|
});
|
||||||
if (error.error && Array.isArray(error.error?.message)) {
|
if (error.error && Array.isArray(error.error?.message)) {
|
||||||
|
|
|
||||||
|
|
@ -138,7 +138,7 @@ export class DetailsCommercialPropertyListingComponent {
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.messageService.addMessage({
|
this.messageService.addMessage({
|
||||||
severity: 'danger',
|
severity: 'danger',
|
||||||
text: 'An error occurred while sending the request',
|
text: 'An error occurred while sending the request - Please check your inputs',
|
||||||
duration: 5000,
|
duration: 5000,
|
||||||
});
|
});
|
||||||
if (error.error && Array.isArray(error.error?.message)) {
|
if (error.error && Array.isArray(error.error?.message)) {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
:host ::ng-deep p {
|
:host ::ng-deep p {
|
||||||
display: block;
|
display: block;
|
||||||
margin-top: 1em;
|
// margin-top: 1em;
|
||||||
margin-bottom: 1em;
|
// margin-bottom: 1em;
|
||||||
margin-left: 0;
|
margin-left: 0;
|
||||||
margin-right: 0;
|
margin-right: 0;
|
||||||
font-size: 1rem; /* oder 1rem, abhängig vom Browser und den Standardeinstellungen */
|
font-size: 1rem; /* oder 1rem, abhängig vom Browser und den Standardeinstellungen */
|
||||||
|
|
|
||||||
|
|
@ -110,7 +110,9 @@
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
} @if(criteria && !aiSearch){
|
@if(aiSearchFailed){
|
||||||
|
<div id="error-message" class="w-full max-w-3xl mx-auto mt-2 text-red-600 text-center">Search timed out. Please try again or use classic Search</div>
|
||||||
|
} } @if(criteria && !aiSearch){
|
||||||
<div class="w-full max-w-3xl mx-auto bg-white rounded-lg flex flex-col md:flex-row md:border md:border-gray-300">
|
<div class="w-full max-w-3xl mx-auto bg-white rounded-lg flex flex-col md:flex-row md:border md:border-gray-300">
|
||||||
<div class="md:flex-none md:w-48 flex-1 md:border-r border-gray-300 overflow-hidden mb-2 md:mb-0">
|
<div class="md:flex-none md:w-48 flex-1 md:border-r border-gray-300 overflow-hidden mb-2 md:mb-0">
|
||||||
<div class="relative max-sm:border border-gray-300 rounded-md">
|
<div class="relative max-sm:border border-gray-300 rounded-md">
|
||||||
|
|
@ -184,7 +186,8 @@
|
||||||
}
|
}
|
||||||
<div class="mt-4 flex items-center justify-center text-gray-700">
|
<div class="mt-4 flex items-center justify-center text-gray-700">
|
||||||
<span class="mr-2">AI-Search</span>
|
<span class="mr-2">AI-Search</span>
|
||||||
<span class="bg-sky-300 text-teal-800 text-xs font-semibold px-2 py-1 rounded">BETA</span>
|
<span [attr.data-tooltip-target]="tooltipTargetBeta" class="bg-sky-300 text-teal-800 text-xs font-semibold px-2 py-1 rounded">BETA</span>
|
||||||
|
<app-tooltip [id]="tooltipTargetBeta" text="The AI will convert your input into filter criteria. Please check them in the filter menu after the search"></app-tooltip>
|
||||||
<span class="ml-2">- Try now</span>
|
<span class="ml-2">- Try now</span>
|
||||||
<div class="ml-4 relative inline-block w-10 mr-2 align-middle select-none transition duration-200 ease-in">
|
<div class="ml-4 relative inline-block w-10 mr-2 align-middle select-none transition duration-200 ease-in">
|
||||||
<input (click)="toggleAiSearch()" type="checkbox" name="toggle" id="toggle" class="toggle-checkbox absolute block w-6 h-6 rounded-full bg-white border-4 border-gray-300 appearance-none cursor-pointer" />
|
<input (click)="toggleAiSearch()" type="checkbox" name="toggle" id="toggle" class="toggle-checkbox absolute block w-6 h-6 rounded-full bg-white border-4 border-gray-300 appearance-none cursor-pointer" />
|
||||||
|
|
|
||||||
|
|
@ -4,10 +4,12 @@ import { FormsModule } from '@angular/forms';
|
||||||
import { ActivatedRoute, Router, RouterModule } from '@angular/router';
|
import { ActivatedRoute, Router, RouterModule } from '@angular/router';
|
||||||
import { NgSelectModule } from '@ng-select/ng-select';
|
import { NgSelectModule } from '@ng-select/ng-select';
|
||||||
import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy';
|
import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy';
|
||||||
|
import { initFlowbite } from 'flowbite';
|
||||||
import { KeycloakService } from 'keycloak-angular';
|
import { KeycloakService } from 'keycloak-angular';
|
||||||
import { catchError, concat, debounceTime, distinctUntilChanged, lastValueFrom, Observable, of, Subject, Subscription, switchMap, tap } from 'rxjs';
|
import { catchError, concat, debounceTime, distinctUntilChanged, lastValueFrom, Observable, of, Subject, Subscription, switchMap, tap } from 'rxjs';
|
||||||
import { BusinessListingCriteria, CityAndStateResult, CommercialPropertyListingCriteria, GeoResult, KeycloakUser, UserListingCriteria } from '../../../../../bizmatch-server/src/models/main.model';
|
import { BusinessListingCriteria, CityAndStateResult, CommercialPropertyListingCriteria, GeoResult, KeycloakUser, UserListingCriteria } from '../../../../../bizmatch-server/src/models/main.model';
|
||||||
import { ModalService } from '../../components/search-modal/modal.service';
|
import { ModalService } from '../../components/search-modal/modal.service';
|
||||||
|
import { TooltipComponent } from '../../components/tooltip/tooltip.component';
|
||||||
import { AiService } from '../../services/ai.service';
|
import { AiService } from '../../services/ai.service';
|
||||||
import { CriteriaChangeService } from '../../services/criteria-change.service';
|
import { CriteriaChangeService } from '../../services/criteria-change.service';
|
||||||
import { GeoService } from '../../services/geo.service';
|
import { GeoService } from '../../services/geo.service';
|
||||||
|
|
@ -29,12 +31,12 @@ import {
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-home',
|
selector: 'app-home',
|
||||||
standalone: true,
|
standalone: true,
|
||||||
imports: [CommonModule, FormsModule, RouterModule, NgSelectModule],
|
imports: [CommonModule, FormsModule, RouterModule, NgSelectModule, TooltipComponent],
|
||||||
templateUrl: './home.component.html',
|
templateUrl: './home.component.html',
|
||||||
styleUrl: './home.component.scss',
|
styleUrl: './home.component.scss',
|
||||||
})
|
})
|
||||||
export class HomeComponent {
|
export class HomeComponent {
|
||||||
placeholders: string[] = ['waterfront property close to Houston less than 1M', 'construction area with beach access close to San Diego'];
|
placeholders: string[] = ['Property close to Houston less than 10M', 'Franchise business in Austin price less than 500K'];
|
||||||
activeTabAction: 'business' | 'commercialProperty' | 'broker' = 'business';
|
activeTabAction: 'business' | 'commercialProperty' | 'broker' = 'business';
|
||||||
type: string;
|
type: string;
|
||||||
maxPrice: string;
|
maxPrice: string;
|
||||||
|
|
@ -53,6 +55,7 @@ export class HomeComponent {
|
||||||
|
|
||||||
aiSearch = false;
|
aiSearch = false;
|
||||||
aiSearchText = '';
|
aiSearchText = '';
|
||||||
|
aiSearchFailed = false;
|
||||||
loadingAi = false;
|
loadingAi = false;
|
||||||
@ViewChild('aiSearchInput', { static: false }) searchInput!: ElementRef;
|
@ViewChild('aiSearchInput', { static: false }) searchInput!: ElementRef;
|
||||||
typingSpeed: number = 100; // Geschwindigkeit des Tippens (ms)
|
typingSpeed: number = 100; // Geschwindigkeit des Tippens (ms)
|
||||||
|
|
@ -61,7 +64,7 @@ export class HomeComponent {
|
||||||
charIndex: number = 0;
|
charIndex: number = 0;
|
||||||
typingInterval: any;
|
typingInterval: any;
|
||||||
showInput: boolean = true; // Steuerung der Anzeige des Eingabefelds
|
showInput: boolean = true; // Steuerung der Anzeige des Eingabefelds
|
||||||
|
tooltipTargetBeta = 'tooltipTargetBeta';
|
||||||
public constructor(
|
public constructor(
|
||||||
private router: Router,
|
private router: Router,
|
||||||
private modalService: ModalService,
|
private modalService: ModalService,
|
||||||
|
|
@ -77,6 +80,9 @@ export class HomeComponent {
|
||||||
private aiService: AiService,
|
private aiService: AiService,
|
||||||
) {}
|
) {}
|
||||||
async ngOnInit() {
|
async ngOnInit() {
|
||||||
|
setTimeout(() => {
|
||||||
|
initFlowbite();
|
||||||
|
}, 0);
|
||||||
const token = await this.keycloakService.getToken();
|
const token = await this.keycloakService.getToken();
|
||||||
sessionStorage.removeItem('businessListings');
|
sessionStorage.removeItem('businessListings');
|
||||||
sessionStorage.removeItem('commercialPropertyListings');
|
sessionStorage.removeItem('commercialPropertyListings');
|
||||||
|
|
@ -219,6 +225,7 @@ export class HomeComponent {
|
||||||
}
|
}
|
||||||
toggleAiSearch() {
|
toggleAiSearch() {
|
||||||
this.aiSearch = !this.aiSearch;
|
this.aiSearch = !this.aiSearch;
|
||||||
|
this.aiSearchFailed = false;
|
||||||
if (!this.aiSearch) {
|
if (!this.aiSearch) {
|
||||||
this.aiSearchText = '';
|
this.aiSearchText = '';
|
||||||
this.stopTypingEffect();
|
this.stopTypingEffect();
|
||||||
|
|
@ -271,8 +278,9 @@ export class HomeComponent {
|
||||||
}
|
}
|
||||||
async generateAiResponse() {
|
async generateAiResponse() {
|
||||||
this.loadingAi = true;
|
this.loadingAi = true;
|
||||||
|
this.aiSearchFailed = false;
|
||||||
|
try {
|
||||||
const result = await this.aiService.generateAiReponse(this.aiSearchText);
|
const result = await this.aiService.generateAiReponse(this.aiSearchText);
|
||||||
console.log(result);
|
|
||||||
let criteria: BusinessListingCriteria | CommercialPropertyListingCriteria | UserListingCriteria | any;
|
let criteria: BusinessListingCriteria | CommercialPropertyListingCriteria | UserListingCriteria | any;
|
||||||
if (result.criteriaType === 'businessListings') {
|
if (result.criteriaType === 'businessListings') {
|
||||||
this.changeTab('business');
|
this.changeTab('business');
|
||||||
|
|
@ -299,5 +307,10 @@ export class HomeComponent {
|
||||||
this.loadingAi = false;
|
this.loadingAi = false;
|
||||||
this.criteria = assignProperties(this.criteria, criteria);
|
this.criteria = assignProperties(this.criteria, criteria);
|
||||||
this.search();
|
this.search();
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
this.aiSearchFailed = true;
|
||||||
|
this.loadingAi = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -137,6 +137,6 @@
|
||||||
<div class="mt-16 text-center">
|
<div class="mt-16 text-center">
|
||||||
<h2 class="text-2xl font-semibold mb-4">Not sure which plan is right for you?</h2>
|
<h2 class="text-2xl font-semibold mb-4">Not sure which plan is right for you?</h2>
|
||||||
<p class="text-gray-600 mb-8">Contact our sales team for a personalized recommendation.</p>
|
<p class="text-gray-600 mb-8">Contact our sales team for a personalized recommendation.</p>
|
||||||
<a href="#" class="bg-blue-500 text-white rounded-full px-6 py-3 font-semibold hover:bg-blue-600 transition duration-300">Contact Sales</a>
|
<a routerLink="/emailUs" class="bg-blue-500 text-white rounded-full px-6 py-3 font-semibold hover:bg-blue-600 transition duration-300">Contact Sales</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -173,7 +173,7 @@ export class AccountComponent {
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.messageService.addMessage({
|
this.messageService.addMessage({
|
||||||
severity: 'danger',
|
severity: 'danger',
|
||||||
text: 'An error occurred while saving the profile',
|
text: 'An error occurred while saving the profile - Please check your inputs',
|
||||||
duration: 5000,
|
duration: 5000,
|
||||||
});
|
});
|
||||||
if (error.error && Array.isArray(error.error?.message)) {
|
if (error.error && Array.isArray(error.error?.message)) {
|
||||||
|
|
|
||||||
|
|
@ -128,7 +128,7 @@ export class EditBusinessListingComponent {
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.messageService.addMessage({
|
this.messageService.addMessage({
|
||||||
severity: 'danger',
|
severity: 'danger',
|
||||||
text: 'An error occurred while saving the profile',
|
text: 'An error occurred while saving the profile - Please check your inputs',
|
||||||
duration: 5000,
|
duration: 5000,
|
||||||
});
|
});
|
||||||
if (error.error && Array.isArray(error.error?.message)) {
|
if (error.error && Array.isArray(error.error?.message)) {
|
||||||
|
|
|
||||||
|
|
@ -57,8 +57,8 @@ export class EmailUsComponent {
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.messageService.addMessage({
|
this.messageService.addMessage({
|
||||||
severity: 'danger',
|
severity: 'danger',
|
||||||
text: 'An error occurred',
|
text: 'Please check your inputs',
|
||||||
duration: 50000,
|
duration: 5000,
|
||||||
});
|
});
|
||||||
if (error.error && Array.isArray(error.error?.message)) {
|
if (error.error && Array.isArray(error.error?.message)) {
|
||||||
this.validationMessagesService.updateMessages(error.error.message);
|
this.validationMessagesService.updateMessages(error.error.message);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue