Fehlerbehebung & Start Vector Search
This commit is contained in:
parent
7bd5e1aaf8
commit
b4644ea295
|
|
@ -36,7 +36,7 @@
|
|||
"@nestjs/serve-static": "^4.0.1",
|
||||
"cors": "^2.8.5",
|
||||
"dotenv": "^16.4.5",
|
||||
"drizzle-orm": "^0.30.8",
|
||||
"drizzle-orm": "^0.32.0",
|
||||
"fs-extra": "^11.2.0",
|
||||
"handlebars": "^4.7.8",
|
||||
"jwks-rsa": "^3.1.0",
|
||||
|
|
@ -44,13 +44,13 @@
|
|||
"nest-winston": "^1.9.4",
|
||||
"nodemailer": "^6.9.10",
|
||||
"nodemailer-smtp-transport": "^2.7.4",
|
||||
"openai": "^4.52.6",
|
||||
"passport": "^0.7.0",
|
||||
"passport-google-oauth20": "^2.0.0",
|
||||
"passport-jwt": "^4.0.1",
|
||||
"passport-local": "^1.0.0",
|
||||
"pg": "^8.11.5",
|
||||
"redis": "^4.6.13",
|
||||
"redis-om": "^0.4.3",
|
||||
"pgvector": "^0.2.0",
|
||||
"reflect-metadata": "^0.2.0",
|
||||
"rxjs": "^7.8.1",
|
||||
"sharp": "^0.33.2",
|
||||
|
|
@ -77,7 +77,7 @@
|
|||
"@typescript-eslint/eslint-plugin": "^6.0.0",
|
||||
"@typescript-eslint/parser": "^6.0.0",
|
||||
"commander": "^12.0.0",
|
||||
"drizzle-kit": "^0.20.16",
|
||||
"drizzle-kit": "^0.23.0",
|
||||
"eslint": "^8.42.0",
|
||||
"eslint-config-prettier": "^9.0.0",
|
||||
"eslint-plugin-prettier": "^5.0.0",
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import 'dotenv/config';
|
|||
import { drizzle } from 'drizzle-orm/node-postgres';
|
||||
import { existsSync, readFileSync, readdirSync, statSync, unlinkSync } from 'fs';
|
||||
import fs from 'fs-extra';
|
||||
import OpenAI from 'openai';
|
||||
import { join } from 'path';
|
||||
import pkg from 'pg';
|
||||
import { rimraf } from 'rimraf';
|
||||
|
|
@ -11,6 +12,10 @@ import { emailToDirName } from 'src/models/main.model.js';
|
|||
import * as schema from './schema.js';
|
||||
const { Pool } = pkg;
|
||||
|
||||
const openai = new OpenAI({
|
||||
apiKey: process.env.OPENAI_API_KEY, // Stellen Sie sicher, dass Sie Ihren API-Key als Umgebungsvariable setzen
|
||||
});
|
||||
|
||||
const connectionString = process.env.DATABASE_URL;
|
||||
// const pool = new Pool({connectionString})
|
||||
const client = new Pool({ connectionString });
|
||||
|
|
@ -124,6 +129,14 @@ for (const commercial of commercialJsonData) {
|
|||
//End
|
||||
await client.end();
|
||||
|
||||
async function createEmbedding(text: string): Promise<number[]> {
|
||||
const response = await openai.embeddings.create({
|
||||
model: 'text-embedding-ada-002',
|
||||
input: text,
|
||||
});
|
||||
return response.data[0].embedding;
|
||||
}
|
||||
|
||||
function getRandomItem<T>(arr: T[]): T {
|
||||
if (arr.length === 0) {
|
||||
throw new Error('The array is empty.');
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
import { boolean, char, doublePrecision, integer, jsonb, pgEnum, pgTable, serial, text, timestamp, uuid, varchar } from 'drizzle-orm/pg-core';
|
||||
import { boolean, char, doublePrecision, integer, jsonb, pgEnum, pgTable, serial, text, timestamp, uuid, varchar, vector } from 'drizzle-orm/pg-core';
|
||||
import { AreasServed, LicensedIn } from 'src/models/db.model';
|
||||
|
||||
export const PG_CONNECTION = 'PG_CONNECTION';
|
||||
export const genderEnum = pgEnum('gender', ['male', 'female']);
|
||||
export const customerTypeEnum = pgEnum('customerType', ['buyer', 'professional']);
|
||||
|
|
@ -58,6 +57,9 @@ export const businesses = pgTable('businesses', {
|
|||
updated: timestamp('updated'),
|
||||
visits: integer('visits'),
|
||||
lastVisit: timestamp('lastVisit'),
|
||||
// Neue Spalte für das OpenAI Embedding
|
||||
embedding: vector('embedding', { dimensions: 1536 }),
|
||||
// embedding: sql`vector(1536)`,
|
||||
});
|
||||
|
||||
export const commercials = pgTable('commercials', {
|
||||
|
|
|
|||
|
|
@ -30,3 +30,4 @@
|
|||
</div>
|
||||
</div>
|
||||
}
|
||||
<app-message-container></app-message-container>
|
||||
|
|
|
|||
|
|
@ -10,13 +10,14 @@ import { ListingCriteria } from '../../../bizmatch-server/src/models/main.model'
|
|||
import build from '../build';
|
||||
import { FooterComponent } from './components/footer/footer.component';
|
||||
import { HeaderComponent } from './components/header/header.component';
|
||||
import { MessageContainerComponent } from './components/message/message-container.component';
|
||||
import { LoadingService } from './services/loading.service';
|
||||
import { UserService } from './services/user.service';
|
||||
import { createDefaultListingCriteria } from './utils/utils';
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
standalone: true,
|
||||
imports: [CommonModule, RouterOutlet, HeaderComponent, FooterComponent],
|
||||
imports: [CommonModule, RouterOutlet, HeaderComponent, FooterComponent, MessageContainerComponent],
|
||||
providers: [],
|
||||
templateUrl: './app.component.html',
|
||||
styleUrl: './app.component.scss',
|
||||
|
|
|
|||
|
|
@ -41,19 +41,21 @@
|
|||
</div>
|
||||
<ul class="py-2" aria-labelledby="user-menu-button">
|
||||
<li>
|
||||
<a routerLink="/account" 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">Account</a>
|
||||
<a routerLink="/account" (click)="closeDropdown()" 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">Account</a>
|
||||
</li>
|
||||
<li>
|
||||
<a routerLink="/createBusinessListing" 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">Create Listing</a>
|
||||
<a routerLink="/createBusinessListing" (click)="closeDropdown()" 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"
|
||||
>Create Listing</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a routerLink="/myListings" 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">My Listings</a>
|
||||
<a routerLink="/myListings" (click)="closeDropdown()" 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">My Listings</a>
|
||||
</li>
|
||||
<li>
|
||||
<a routerLink="/emailUs" 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">EMail Us</a>
|
||||
<a routerLink="/emailUs" (click)="closeDropdown()" 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">EMail Us</a>
|
||||
</li>
|
||||
<li>
|
||||
<a routerLink="/logout" 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">Logout</a>
|
||||
<a routerLink="/logout" (click)="closeDropdown()" 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">Logout</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
|
@ -93,6 +95,7 @@
|
|||
[ngClass]="{ 'bg-blue-700 text-white md:text-blue-700 md:bg-transparent md:dark:text-blue-500': isActive('/businessListings') }"
|
||||
class="block py-2 px-3 rounded hover:bg-gray-100 md:hover:bg-transparent md:hover:text-blue-700 md:p-0 dark:text-white md:dark:hover:text-blue-500 dark:hover:bg-gray-700 dark:hover:text-white md:dark:hover:bg-transparent dark:border-gray-700"
|
||||
aria-current="page"
|
||||
(click)="closeMenus()"
|
||||
>Businesses</a
|
||||
>
|
||||
</li>
|
||||
|
|
@ -102,6 +105,7 @@
|
|||
routerLink="/commercialPropertyListings"
|
||||
[ngClass]="{ 'bg-blue-700 text-white md:text-blue-700 md:bg-transparent md:dark:text-blue-500': isActive('/commercialPropertyListings') }"
|
||||
class="block py-2 px-3 rounded hover:bg-gray-100 md:hover:bg-transparent md:hover:text-blue-700 md:p-0 dark:text-white md:dark:hover:text-blue-500 dark:hover:bg-gray-700 dark:hover:text-white md:dark:hover:bg-transparent dark:border-gray-700"
|
||||
(click)="closeMenus()"
|
||||
>Properties</a
|
||||
>
|
||||
</li>
|
||||
|
|
@ -111,6 +115,7 @@
|
|||
routerLink="/brokerListings"
|
||||
[ngClass]="{ 'bg-blue-700 text-white md:text-blue-700 md:bg-transparent md:dark:text-blue-500': isActive('/brokerListings') }"
|
||||
class="block py-2 px-3 rounded hover:bg-gray-100 md:hover:bg-transparent md:hover:text-blue-700 md:p-0 dark:text-white md:dark:hover:text-blue-500 dark:hover:bg-gray-700 dark:hover:text-white md:dark:hover:bg-transparent dark:border-gray-700"
|
||||
(click)="closeMenus()"
|
||||
>Professionals</a
|
||||
>
|
||||
</li>
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { CommonModule } from '@angular/common';
|
|||
import { Component } from '@angular/core';
|
||||
import { Router, RouterModule } from '@angular/router';
|
||||
import { faUserGear } from '@fortawesome/free-solid-svg-icons';
|
||||
import { initFlowbite } from 'flowbite';
|
||||
import { Collapse, Dropdown, initFlowbite } from 'flowbite';
|
||||
import { KeycloakService } from 'keycloak-angular';
|
||||
import { Observable } from 'rxjs';
|
||||
import { User } from '../../../../../bizmatch-server/src/models/db.model';
|
||||
|
|
@ -60,4 +60,26 @@ export class HeaderComponent {
|
|||
isActive(route: string): boolean {
|
||||
return this.router.url === route;
|
||||
}
|
||||
closeDropdown() {
|
||||
const dropdownButton = document.getElementById('user-menu-button');
|
||||
const dropdownMenu = this.user ? document.getElementById('user-login') : document.getElementById('user-unknown');
|
||||
|
||||
if (dropdownButton && dropdownMenu) {
|
||||
const dropdown = new Dropdown(dropdownMenu, dropdownButton);
|
||||
dropdown.hide();
|
||||
}
|
||||
}
|
||||
closeMobileMenu() {
|
||||
const targetElement = document.getElementById('navbar-user');
|
||||
const triggerElement = document.querySelector('[data-collapse-toggle="navbar-user"]');
|
||||
|
||||
if (targetElement instanceof HTMLElement && triggerElement instanceof HTMLElement) {
|
||||
const collapse = new Collapse(targetElement, triggerElement);
|
||||
collapse.collapse();
|
||||
}
|
||||
}
|
||||
closeMenus() {
|
||||
this.closeDropdown();
|
||||
this.closeMobileMenu();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,30 @@
|
|||
import { CommonModule } from '@angular/common';
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { MessageComponent } from './message.component';
|
||||
import { Message, MessageService } from './message.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-message-container',
|
||||
standalone: true,
|
||||
imports: [CommonModule, MessageComponent],
|
||||
template: `
|
||||
<div class="fixed top-5 right-5 z-50 flex flex-col items-end">
|
||||
<app-message *ngFor="let message of messages" [message]="message" (close)="removeMessage(message)"> </app-message>
|
||||
</div>
|
||||
`,
|
||||
})
|
||||
export class MessageContainerComponent implements OnInit {
|
||||
messages: Message[] = [];
|
||||
|
||||
constructor(private messageService: MessageService) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.messageService.messages$.subscribe(messages => {
|
||||
this.messages = messages;
|
||||
});
|
||||
}
|
||||
|
||||
removeMessage(message: Message): void {
|
||||
this.messageService.removeMessage(message);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,32 +1,25 @@
|
|||
import { Component } from '@angular/core';
|
||||
|
||||
import { AsyncPipe, NgIf } from '@angular/common';
|
||||
import { MessageService } from './message.service';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { Component, EventEmitter, Input, Output } from '@angular/core';
|
||||
import { Message } from './message.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-message',
|
||||
standalone: true,
|
||||
imports: [AsyncPipe, NgIf],
|
||||
imports: [CommonModule],
|
||||
template: `
|
||||
<div
|
||||
*ngIf="messageService.modalVisible$ | async"
|
||||
id="toast-success"
|
||||
class="fixed top-[0.5rem] right-[1rem] flex items-center w-full max-w-xs p-4 mb-4 text-gray-500 bg-slate-200 rounded-lg shadow dark:text-gray-400 dark:bg-gray-800"
|
||||
role="alert"
|
||||
>
|
||||
<div class="inline-flex items-center justify-center flex-shrink-0 w-8 h-8 text-green-500 bg-green-100 rounded-lg dark:bg-green-800 dark:text-green-200">
|
||||
<div [ngClass]="getClasses()" role="alert">
|
||||
<div [ngClass]="getIconClasses()">
|
||||
<svg class="w-5 h-5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path d="M10 .5a9.5 9.5 0 1 0 9.5 9.5A9.51 9.51 0 0 0 10 .5Zm3.707 8.207-4 4a1 1 0 0 1-1.414 0l-2-2a1 1 0 0 1 1.414-1.414L9 10.586l3.293-3.293a1 1 0 0 1 1.414 1.414Z" />
|
||||
<path [attr.d]="getIconPath()" />
|
||||
</svg>
|
||||
<span class="sr-only">Check icon</span>
|
||||
<span class="sr-only">{{ getSrText() }}</span>
|
||||
</div>
|
||||
<div class="ms-3 text-sm font-normal">{{ messageService.message$ | async }}</div>
|
||||
<div class="ms-3 text-sm font-normal">{{ message.text }}</div>
|
||||
<button
|
||||
type="button"
|
||||
(click)="onClose()"
|
||||
class="ms-auto -mx-1.5 -my-1.5 bg-white text-gray-400 hover:text-gray-900 rounded-lg focus:ring-2 focus:ring-gray-300 p-1.5 hover:bg-gray-100 inline-flex items-center justify-center h-8 w-8 dark:text-gray-500 dark:hover:text-white dark:bg-gray-800 dark:hover:bg-gray-700"
|
||||
data-dismiss-target="#toast-success"
|
||||
aria-label="Close"
|
||||
(click)="messageService.reject()"
|
||||
>
|
||||
<span class="sr-only">Close</span>
|
||||
<svg class="w-3 h-3" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 14 14">
|
||||
|
|
@ -37,5 +30,59 @@ import { MessageService } from './message.service';
|
|||
`,
|
||||
})
|
||||
export class MessageComponent {
|
||||
constructor(public messageService: MessageService) {}
|
||||
@Input() message!: Message;
|
||||
@Output() close = new EventEmitter<void>();
|
||||
|
||||
onClose(): void {
|
||||
this.close.emit();
|
||||
}
|
||||
|
||||
getClasses(): string {
|
||||
return `flex items-center w-full max-w-xs p-4 mb-4 text-gray-500 bg-white rounded-lg shadow dark:text-gray-400 dark:bg-gray-800 ${this.getSeverityClasses()}`;
|
||||
}
|
||||
|
||||
getIconClasses(): string {
|
||||
const baseClasses = 'inline-flex items-center justify-center flex-shrink-0 w-8 h-8 rounded-lg';
|
||||
switch (this.message.severity) {
|
||||
case 'success':
|
||||
return `${baseClasses} text-green-500 bg-green-100 dark:bg-green-800 dark:text-green-200`;
|
||||
case 'danger':
|
||||
return `${baseClasses} text-red-500 bg-red-100 dark:bg-red-800 dark:text-red-200`;
|
||||
case 'warning':
|
||||
return `${baseClasses} text-orange-500 bg-orange-100 dark:bg-orange-700 dark:text-orange-200`;
|
||||
}
|
||||
}
|
||||
|
||||
getIconPath(): string {
|
||||
switch (this.message.severity) {
|
||||
case 'success':
|
||||
return 'M10 .5a9.5 9.5 0 1 0 9.5 9.5A9.51 9.51 0 0 0 10 .5Zm3.707 8.207-4 4a1 1 0 0 1-1.414 0l-2-2a1 1 0 0 1 1.414-1.414L9 10.586l3.293-3.293a1 1 0 0 1 1.414 1.414Z';
|
||||
case 'danger':
|
||||
return 'M10 .5a9.5 9.5 0 1 0 9.5 9.5A9.51 9.51 0 0 0 10 .5Zm3.707 11.793a1 1 0 1 1-1.414 1.414L10 11.414l-2.293 2.293a1 1 0 0 1-1.414-1.414L8.586 10 6.293 7.707a1 1 0 0 1 1.414-1.414L10 8.586l2.293-2.293a1 1 0 0 1 1.414 1.414L11.414 10l2.293 2.293Z';
|
||||
case 'warning':
|
||||
return 'M10 .5a9.5 9.5 0 1 0 9.5 9.5A9.51 9.51 0 0 0 10 .5ZM10 15a1 1 0 1 1 0-2 1 1 0 0 1 0 2Zm1-4a1 1 0 0 1-2 0V6a1 1 0 0 1 2 0v5Z';
|
||||
}
|
||||
}
|
||||
|
||||
getSrText(): string {
|
||||
switch (this.message.severity) {
|
||||
case 'success':
|
||||
return 'Check icon';
|
||||
case 'danger':
|
||||
return 'Error icon';
|
||||
case 'warning':
|
||||
return 'Warning icon';
|
||||
}
|
||||
}
|
||||
|
||||
private getSeverityClasses(): string {
|
||||
switch (this.message.severity) {
|
||||
case 'success':
|
||||
return 'border-green-500';
|
||||
case 'danger':
|
||||
return 'border-red-500';
|
||||
case 'warning':
|
||||
return 'border-orange-500';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,32 +1,30 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
import { BehaviorSubject, Observable } from 'rxjs';
|
||||
|
||||
export interface Message {
|
||||
severity: 'success' | 'danger' | 'warning';
|
||||
text: string;
|
||||
duration: number;
|
||||
}
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class MessageService {
|
||||
private modalVisibleSubject = new BehaviorSubject<boolean>(false);
|
||||
private messageSubject = new BehaviorSubject<string>('');
|
||||
private resolvePromise!: (value: boolean) => void;
|
||||
private messagesSubject = new BehaviorSubject<Message[]>([]);
|
||||
messages$: Observable<Message[]> = this.messagesSubject.asObservable();
|
||||
|
||||
modalVisible$: Observable<boolean> = this.modalVisibleSubject.asObservable();
|
||||
message$: Observable<string> = this.messageSubject.asObservable();
|
||||
addMessage(message: Message): void {
|
||||
const currentMessages = this.messagesSubject.value;
|
||||
this.messagesSubject.next([...currentMessages, message]);
|
||||
|
||||
showMessage(message: string): Promise<boolean> {
|
||||
this.messageSubject.next(message);
|
||||
this.modalVisibleSubject.next(true);
|
||||
return new Promise<boolean>(resolve => {
|
||||
this.resolvePromise = resolve;
|
||||
});
|
||||
}
|
||||
|
||||
accept(): void {
|
||||
this.modalVisibleSubject.next(false);
|
||||
this.resolvePromise(true);
|
||||
}
|
||||
|
||||
reject(): void {
|
||||
this.modalVisibleSubject.next(false);
|
||||
this.resolvePromise(false);
|
||||
if (message.duration > 0) {
|
||||
setTimeout(() => this.removeMessage(message), message.duration);
|
||||
}
|
||||
}
|
||||
|
||||
removeMessage(messageToRemove: Message): void {
|
||||
const currentMessages = this.messagesSubject.value;
|
||||
this.messagesSubject.next(currentMessages.filter(msg => msg !== messageToRemove));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -200,10 +200,15 @@
|
|||
<textarea id="message" name="message" [(ngModel)]="mailinfo.sender.comments" rows="4" class="w-full px-3 py-2 border border-gray-300 rounded-md"></textarea>
|
||||
</div>
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="text-sm">
|
||||
Listing by <span class="font-semibold">Mia Hernandez</span>
|
||||
<img src="https://placehold.co/30x30" alt="Realtor logo" class="inline-block ml-1 w-6 h-6" />
|
||||
@if(listingUser){
|
||||
<div class="flex items-center space-x-2">
|
||||
<p>Listing by</p>
|
||||
<a routerLink="/details-user/{{ listingUser.id }}" class="text-blue-600 dark:text-blue-500 hover:underline">{{ listingUser.firstname }} {{ listingUser.lastname }}</a>
|
||||
@if(listingUser.hasCompanyLogo){
|
||||
<img src="{{ env.imageBaseUrl }}/pictures/logo/{{ listing.imagePath }}.avif?_ts={{ ts }}" class="mr-5 lg:mb-0" style="max-height: 30px; max-width: 100px" />
|
||||
}
|
||||
</div>
|
||||
}
|
||||
<button (click)="mail()" class="bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-600">Submit</button>
|
||||
</div>
|
||||
</form>
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
<input type="email" id="email" name="email" [(ngModel)]="user.email" required class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500" />
|
||||
<p class="text-xs text-gray-500 mt-1">You can only modify your email by contacting us at support@bizwatch.net</p>
|
||||
</div>
|
||||
@if (isProfessional){
|
||||
<div class="flex flex-row items-center justify-around md:space-x-4">
|
||||
<div class="flex h-full justify-between flex-col">
|
||||
<p class="text-sm font-medium text-gray-700 mb-1">Company Logo</p>
|
||||
|
|
@ -55,6 +56,7 @@
|
|||
</button>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
|
|
@ -75,14 +77,16 @@
|
|||
<option *ngFor="let type of customerTypes" [value]="type">{{ type | titlecase }}</option>
|
||||
</select>
|
||||
</div>
|
||||
@if (isProfessional){
|
||||
<div>
|
||||
<label for="customerSubType" class="block text-sm font-medium text-gray-700">Professional Type</label>
|
||||
<select id="customerSubType" name="customerSubType" [(ngModel)]="user.customerSubType" required class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500">
|
||||
<option *ngFor="let subType of customerSubTypes" [value]="subType">{{ subType | titlecase }}</option>
|
||||
</select>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
@if (isProfessional){
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label for="companyName" class="block text-sm font-medium text-gray-700">Company Name</label>
|
||||
|
|
@ -178,7 +182,7 @@
|
|||
<span class="text-sm text-gray-500 ml-2">[Add more licenses or remove existing ones.]</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
}
|
||||
<div class="flex justify-start">
|
||||
<button type="submit" class="px-4 py-2 bg-blue-500 text-white rounded-md hover:bg-blue-600 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500" (click)="updateProfile(user)">
|
||||
Update Profile
|
||||
|
|
@ -263,7 +267,6 @@
|
|||
<!-- @if(showModal){ -->
|
||||
<app-image-crop-and-upload [uploadParams]="uploadParams" (uploadFinished)="uploadFinished($event)"></app-image-crop-and-upload>
|
||||
<app-confirmation></app-confirmation>
|
||||
<app-message></app-message>
|
||||
<!-- } -->
|
||||
<!-- <div class="surface-ground px-4 py-8 md:px-6 lg:px-8">
|
||||
<div class="p-fluid flex flex-column lg:flex-row">
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ import { SharedService } from '../../../services/shared.service';
|
|||
import { SubscriptionsService } from '../../../services/subscriptions.service';
|
||||
import { UserService } from '../../../services/user.service';
|
||||
import { SharedModule } from '../../../shared/shared/shared.module';
|
||||
import { map2User } from '../../../utils/utils';
|
||||
import { createDefaultUser, map2User } from '../../../utils/utils';
|
||||
import { TOOLBAR_OPTIONS } from '../../utils/defaults';
|
||||
@Component({
|
||||
selector: 'app-account',
|
||||
|
|
@ -34,13 +34,10 @@ import { TOOLBAR_OPTIONS } from '../../utils/defaults';
|
|||
styleUrl: './account.component.scss',
|
||||
})
|
||||
export class AccountComponent {
|
||||
// @ViewChild('companyUpload') public companyUpload: FileUpload;
|
||||
// @ViewChild('profileUpload') public profileUpload: FileUpload;
|
||||
private id: string | undefined = this.activatedRoute.snapshot.params['id'] as string | undefined;
|
||||
user: User;
|
||||
subscriptions: Array<Subscription>;
|
||||
userSubscriptions: Array<Subscription> = [];
|
||||
maxFileSize = 15000000;
|
||||
companyLogoUrl: string;
|
||||
profileUrl: string;
|
||||
type: 'company' | 'profile';
|
||||
|
|
@ -101,8 +98,16 @@ export class AccountComponent {
|
|||
printInvoice(invoice: Invoice) {}
|
||||
|
||||
async updateProfile(user: User) {
|
||||
if (this.user.customerType === 'buyer') {
|
||||
const id = this.user.id;
|
||||
this.user = createDefaultUser(this.user.email, this.user.firstname, this.user.lastname);
|
||||
this.user.customerType = 'buyer';
|
||||
this.user.id = id;
|
||||
this.imageService.deleteLogoImagesByMail(this.user.email);
|
||||
this.imageService.deleteProfileImagesByMail(this.user.email);
|
||||
}
|
||||
await this.userService.save(this.user);
|
||||
// this.messageService.add({ severity: 'info', summary: 'Confirmed', detail: 'Account changes have been persisted', life: 3000 });
|
||||
this.messageService.addMessage({ severity: 'success', text: 'Account changes have been persisted', duration: 3000 });
|
||||
}
|
||||
|
||||
onUploadCompanyLogo(event: any) {
|
||||
|
|
@ -162,13 +167,18 @@ export class AccountComponent {
|
|||
if (confirmed) {
|
||||
if (type === 'profile') {
|
||||
this.user.hasProfile = false;
|
||||
await Promise.all([this.imageService.deleteProfileImagesById(this.user.email), this.userService.save(this.user)]);
|
||||
await Promise.all([this.imageService.deleteProfileImagesByMail(this.user.email), this.userService.save(this.user)]);
|
||||
} else {
|
||||
this.user.hasCompanyLogo = false;
|
||||
await Promise.all([this.imageService.deleteLogoImagesById(this.user.email), this.userService.save(this.user)]);
|
||||
await Promise.all([this.imageService.deleteLogoImagesByMail(this.user.email), this.userService.save(this.user)]);
|
||||
}
|
||||
this.user = await this.userService.getById(this.user.id);
|
||||
this.messageService.showMessage('Image deleted');
|
||||
// this.messageService.showMessage('Image deleted');
|
||||
this.messageService.addMessage({
|
||||
severity: 'success',
|
||||
text: 'Image deleted.',
|
||||
duration: 3000, // 3 seconds
|
||||
});
|
||||
}
|
||||
}
|
||||
// select(event: any, type: 'company' | 'profile') {
|
||||
|
|
|
|||
|
|
@ -1,3 +1,150 @@
|
|||
<div class="container mx-auto p-4">
|
||||
<div class="bg-white rounded-lg shadow-md p-6">
|
||||
<h1 class="text-2xl font-semibold mb-6">Edit Listing</h1>
|
||||
@if(listing){
|
||||
<form #listingForm="ngForm">
|
||||
<div class="mb-4">
|
||||
<label for="listingsCategory" class="block text-sm font-bold text-gray-700 mb-1">Listing category</label>
|
||||
<ng-select [readonly]="mode === 'edit'" [items]="selectOptions?.listingCategories" bindLabel="name" bindValue="value" [(ngModel)]="listing.listingsCategory" name="listingsCategory"> </ng-select>
|
||||
</div>
|
||||
|
||||
<div class="mb-4">
|
||||
<label for="title" class="block text-sm font-bold text-gray-700 mb-1">Title of Listing</label>
|
||||
<input type="text" id="title" [(ngModel)]="listing.title" name="title" class="w-full p-2 border border-gray-300 rounded-md" />
|
||||
</div>
|
||||
|
||||
<div class="mb-4">
|
||||
<label for="description" class="block text-sm font-bold text-gray-700 mb-1">Description</label>
|
||||
<quill-editor [(ngModel)]="listing.description" name="description" [modules]="quillModules"></quill-editor>
|
||||
</div>
|
||||
|
||||
<div class="mb-4">
|
||||
<label for="type" class="block text-sm font-bold text-gray-700 mb-1">Type of business</label>
|
||||
<ng-select [items]="typesOfBusiness" bindLabel="name" bindValue="value" [(ngModel)]="listing.type" name="type"> </ng-select>
|
||||
</div>
|
||||
|
||||
<div class="flex mb-4 space-x-4">
|
||||
<div class="w-1/2">
|
||||
<label for="state" class="block text-sm font-bold text-gray-700 mb-1">State</label>
|
||||
<ng-select [items]="selectOptions?.states" bindLabel="name" bindValue="value" [(ngModel)]="listing.state" name="state"> </ng-select>
|
||||
</div>
|
||||
<div class="w-1/2">
|
||||
<label for="city" class="block text-sm font-bold text-gray-700 mb-1">City</label>
|
||||
<input type="text" id="city" [(ngModel)]="listing.city" name="city" class="w-full p-2 border border-gray-300 rounded-md" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex mb-4 space-x-4">
|
||||
<div class="w-1/2">
|
||||
<label for="price" class="block text-sm font-bold text-gray-700 mb-1">Price</label>
|
||||
<input
|
||||
type="text"
|
||||
id="price"
|
||||
[(ngModel)]="listing.price"
|
||||
name="price"
|
||||
class="w-full p-2 border border-gray-300 rounded-md"
|
||||
[options]="{ prefix: '$', thousands: ',', decimal: '.', precision: 0, align: 'left' }"
|
||||
currencyMask
|
||||
/>
|
||||
</div>
|
||||
<div class="w-1/2">
|
||||
<label for="salesRevenue" class="block text-sm font-bold text-gray-700 mb-1">Sales Revenue</label>
|
||||
<input
|
||||
type="text"
|
||||
id="salesRevenue"
|
||||
[(ngModel)]="listing.salesRevenue"
|
||||
name="salesRevenue"
|
||||
class="w-full p-2 border border-gray-300 rounded-md"
|
||||
[options]="{ prefix: '$', thousands: ',', decimal: '.', precision: 0, align: 'left' }"
|
||||
currencyMask
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-4">
|
||||
<label for="cashFlow" class="block text-sm font-bold text-gray-700 mb-1">Cash Flow</label>
|
||||
<input
|
||||
type="text"
|
||||
id="cashFlow"
|
||||
[(ngModel)]="listing.cashFlow"
|
||||
name="cashFlow"
|
||||
class="w-full p-2 border border-gray-300 rounded-md"
|
||||
[options]="{ prefix: '$', thousands: ',', decimal: '.', precision: 0, align: 'left' }"
|
||||
currencyMask
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="flex mb-4 space-x-4">
|
||||
<div class="w-1/2">
|
||||
<label for="established" class="block text-sm font-bold text-gray-700 mb-1">Years Established Since</label>
|
||||
<input type="number" id="established" [(ngModel)]="listing.established" name="established" class="w-full p-2 border border-gray-300 rounded-md" />
|
||||
</div>
|
||||
<div class="w-1/2">
|
||||
<label for="employees" class="block text-sm font-bold text-gray-700 mb-1">Employees</label>
|
||||
<input type="number" id="employees" [(ngModel)]="listing.employees" name="employees" class="w-full p-2 border border-gray-300 rounded-md" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex mb-4 space-x-4">
|
||||
<div class="flex items-center">
|
||||
<input type="checkbox" id="realEstateIncluded" [(ngModel)]="listing.realEstateIncluded" name="realEstateIncluded" class="mr-2" />
|
||||
<label for="realEstateIncluded" class="text-sm font-bold text-gray-700">Real Estate Included</label>
|
||||
</div>
|
||||
<div class="flex items-center">
|
||||
<input type="checkbox" id="leasedLocation" [(ngModel)]="listing.leasedLocation" name="leasedLocation" class="mr-2" />
|
||||
<label for="leasedLocation" class="text-sm font-bold text-gray-700">Leased Location</label>
|
||||
</div>
|
||||
<div class="flex items-center">
|
||||
<input type="checkbox" id="franchiseResale" [(ngModel)]="listing.franchiseResale" name="franchiseResale" class="mr-2" />
|
||||
<label for="franchiseResale" class="text-sm font-bold text-gray-700">Franchise Re-Sale</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-4">
|
||||
<label for="supportAndTraining" class="block text-sm font-bold text-gray-700 mb-1">Support & Training</label>
|
||||
<input type="text" id="supportAndTraining" [(ngModel)]="listing.supportAndTraining" name="supportAndTraining" class="w-full p-2 border border-gray-300 rounded-md" />
|
||||
</div>
|
||||
|
||||
<div class="mb-4">
|
||||
<label for="reasonForSale" class="block text-sm font-bold text-gray-700 mb-1">Reason for Sale</label>
|
||||
<input type="text" id="reasonForSale" [(ngModel)]="listing.reasonForSale" name="reasonForSale" class="w-full p-2 border border-gray-300 rounded-md" />
|
||||
</div>
|
||||
|
||||
<div class="flex mb-4 space-x-4">
|
||||
<div class="w-1/2">
|
||||
<label for="brokerLicencing" class="block text-sm font-bold text-gray-700 mb-1">Broker Licensing</label>
|
||||
<input type="text" id="brokerLicencing" [(ngModel)]="listing.brokerLicencing" name="brokerLicencing" class="w-full p-2 border border-gray-300 rounded-md" />
|
||||
</div>
|
||||
<div class="w-1/2">
|
||||
<label for="internalListingNumber" class="block text-sm font-bold text-gray-700 mb-1">Internal Listing Number</label>
|
||||
<input type="number" id="internalListingNumber" [(ngModel)]="listing.internalListingNumber" name="internalListingNumber" class="w-full p-2 border border-gray-300 rounded-md" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-4">
|
||||
<label for="internals" class="block text-sm font-bold text-gray-700 mb-1">Internal Notes (Will not be shown on the listing, for your records only.)</label>
|
||||
<textarea id="internals" [(ngModel)]="listing.internals" name="internals" class="w-full p-2 border border-gray-300 rounded-md" rows="3"></textarea>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center mb-4">
|
||||
<label class="flex items-center cursor-pointer">
|
||||
<div class="relative">
|
||||
<input type="checkbox" [(ngModel)]="listing.draft" name="draft" class="hidden" />
|
||||
<div class="toggle-bg block w-12 h-6 rounded-full bg-gray-600 transition"></div>
|
||||
</div>
|
||||
<div class="ml-3 text-gray-700 font-medium">Draft Mode (Will not be shown as public listing)</div>
|
||||
</label>
|
||||
</div>
|
||||
@if (mode==='create'){
|
||||
<button (click)="save()" class="bg-blue-500 text-white px-4 py-2 rounded-md hover:bg-blue-600">Post Listing</button>
|
||||
} @else {
|
||||
<button (click)="save()" class="bg-blue-500 text-white px-4 py-2 rounded-md hover:bg-blue-600">Update Listing</button>
|
||||
}
|
||||
</form>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- <div class="surface-ground px-4 py-8 md:px-6 lg:px-8">
|
||||
<div class="p-fluid flex flex-column lg:flex-row">
|
||||
<menu-account></menu-account>
|
||||
|
|
@ -156,153 +303,3 @@
|
|||
</div>
|
||||
<p-toast></p-toast>
|
||||
<p-confirmDialog></p-confirmDialog> -->
|
||||
|
||||
<div class="container mx-auto p-4">
|
||||
<div class="bg-white rounded-lg shadow-md p-6">
|
||||
<h1 class="text-2xl font-semibold mb-6">Edit Listing</h1>
|
||||
@if(listing){
|
||||
<form #listingForm="ngForm">
|
||||
<div class="mb-4">
|
||||
<label for="listingsCategory" class="block text-sm font-bold text-gray-700 mb-1">Listing category</label>
|
||||
<select id="listingsCategory" [(ngModel)]="listing.listingsCategory" name="listingsCategory" class="w-full p-2 border border-gray-300 rounded-md">
|
||||
<option value="business">Business</option>
|
||||
<option value="commercialProperty">Commercial Property</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="mb-4">
|
||||
<label for="title" class="block text-sm font-bold text-gray-700 mb-1">Title of Listing</label>
|
||||
<input type="text" id="title" [(ngModel)]="listing.title" name="title" class="w-full p-2 border border-gray-300 rounded-md" />
|
||||
</div>
|
||||
|
||||
<div class="mb-4">
|
||||
<label for="description" class="block text-sm font-bold text-gray-700 mb-1">Description</label>
|
||||
<quill-editor [(ngModel)]="listing.description" name="description" [modules]="quillModules"></quill-editor>
|
||||
</div>
|
||||
|
||||
<div class="mb-4">
|
||||
<label for="type" class="block text-sm font-bold text-gray-700 mb-1">Type of business</label>
|
||||
<ng-select [items]="typesOfBusiness" bindLabel="name" bindValue="value" [(ngModel)]="listing.type" name="type"> </ng-select>
|
||||
</div>
|
||||
|
||||
<div class="flex mb-4 space-x-4">
|
||||
<div class="w-1/2">
|
||||
<label for="state" class="block text-sm font-bold text-gray-700 mb-1">State</label>
|
||||
<ng-select [items]="selectOptions?.states" bindLabel="name" bindValue="value" [(ngModel)]="listing.state" name="state"> </ng-select>
|
||||
</div>
|
||||
<div class="w-1/2">
|
||||
<label for="city" class="block text-sm font-bold text-gray-700 mb-1">City</label>
|
||||
<input type="text" id="city" [(ngModel)]="listing.city" name="city" class="w-full p-2 border border-gray-300 rounded-md" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex mb-4 space-x-4">
|
||||
<div class="w-1/2">
|
||||
<label for="price" class="block text-sm font-bold text-gray-700 mb-1">Price</label>
|
||||
<input
|
||||
type="text"
|
||||
id="price"
|
||||
[(ngModel)]="listing.price"
|
||||
name="price"
|
||||
class="w-full p-2 border border-gray-300 rounded-md"
|
||||
[options]="{ prefix: '$', thousands: ',', decimal: '.', precision: 0, align: 'left' }"
|
||||
currencyMask
|
||||
/>
|
||||
</div>
|
||||
<div class="w-1/2">
|
||||
<label for="salesRevenue" class="block text-sm font-bold text-gray-700 mb-1">Sales Revenue</label>
|
||||
<input
|
||||
type="text"
|
||||
id="salesRevenue"
|
||||
[(ngModel)]="listing.salesRevenue"
|
||||
name="salesRevenue"
|
||||
class="w-full p-2 border border-gray-300 rounded-md"
|
||||
[options]="{ prefix: '$', thousands: ',', decimal: '.', precision: 0, align: 'left' }"
|
||||
currencyMask
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-4">
|
||||
<label for="cashFlow" class="block text-sm font-bold text-gray-700 mb-1">Cash Flow</label>
|
||||
<input
|
||||
type="text"
|
||||
id="cashFlow"
|
||||
[(ngModel)]="listing.cashFlow"
|
||||
name="cashFlow"
|
||||
class="w-full p-2 border border-gray-300 rounded-md"
|
||||
[options]="{ prefix: '$', thousands: ',', decimal: '.', precision: 0, align: 'left' }"
|
||||
currencyMask
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="flex mb-4 space-x-4">
|
||||
<div class="w-1/2">
|
||||
<label for="established" class="block text-sm font-bold text-gray-700 mb-1">Years Established Since</label>
|
||||
<input type="number" id="established" [(ngModel)]="listing.established" name="established" class="w-full p-2 border border-gray-300 rounded-md" />
|
||||
</div>
|
||||
<div class="w-1/2">
|
||||
<label for="employees" class="block text-sm font-bold text-gray-700 mb-1">Employees</label>
|
||||
<input type="number" id="employees" [(ngModel)]="listing.employees" name="employees" class="w-full p-2 border border-gray-300 rounded-md" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex mb-4 space-x-4">
|
||||
<div class="flex items-center">
|
||||
<input type="checkbox" id="realEstateIncluded" [(ngModel)]="listing.realEstateIncluded" name="realEstateIncluded" class="mr-2" />
|
||||
<label for="realEstateIncluded" class="text-sm font-bold text-gray-700">Real Estate Included</label>
|
||||
</div>
|
||||
<div class="flex items-center">
|
||||
<input type="checkbox" id="leasedLocation" [(ngModel)]="listing.leasedLocation" name="leasedLocation" class="mr-2" />
|
||||
<label for="leasedLocation" class="text-sm font-bold text-gray-700">Leased Location</label>
|
||||
</div>
|
||||
<div class="flex items-center">
|
||||
<input type="checkbox" id="franchiseResale" [(ngModel)]="listing.franchiseResale" name="franchiseResale" class="mr-2" />
|
||||
<label for="franchiseResale" class="text-sm font-bold text-gray-700">Franchise Re-Sale</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-4">
|
||||
<label for="supportAndTraining" class="block text-sm font-bold text-gray-700 mb-1">Support & Training</label>
|
||||
<input type="text" id="supportAndTraining" [(ngModel)]="listing.supportAndTraining" name="supportAndTraining" class="w-full p-2 border border-gray-300 rounded-md" />
|
||||
</div>
|
||||
|
||||
<div class="mb-4">
|
||||
<label for="reasonForSale" class="block text-sm font-bold text-gray-700 mb-1">Reason for Sale</label>
|
||||
<input type="text" id="reasonForSale" [(ngModel)]="listing.reasonForSale" name="reasonForSale" class="w-full p-2 border border-gray-300 rounded-md" />
|
||||
</div>
|
||||
|
||||
<div class="flex mb-4 space-x-4">
|
||||
<div class="w-1/2">
|
||||
<label for="brokerLicencing" class="block text-sm font-bold text-gray-700 mb-1">Broker Licensing</label>
|
||||
<input type="text" id="brokerLicencing" [(ngModel)]="listing.brokerLicencing" name="brokerLicencing" class="w-full p-2 border border-gray-300 rounded-md" />
|
||||
</div>
|
||||
<div class="w-1/2">
|
||||
<label for="internalListingNumber" class="block text-sm font-bold text-gray-700 mb-1">Internal Listing Number</label>
|
||||
<input type="number" id="internalListingNumber" [(ngModel)]="listing.internalListingNumber" name="internalListingNumber" class="w-full p-2 border border-gray-300 rounded-md" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-4">
|
||||
<label for="internals" class="block text-sm font-bold text-gray-700 mb-1">Internal Notes (Will not be shown on the listing, for your records only.)</label>
|
||||
<textarea id="internals" [(ngModel)]="listing.internals" name="internals" class="w-full p-2 border border-gray-300 rounded-md" rows="3"></textarea>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center mb-4">
|
||||
<label class="flex items-center cursor-pointer">
|
||||
<div class="relative">
|
||||
<input type="checkbox" [(ngModel)]="listing.draft" name="draft" class="hidden" />
|
||||
<div class="toggle-bg block w-12 h-6 rounded-full bg-gray-600 transition"></div>
|
||||
</div>
|
||||
<div class="ml-3 text-gray-700 font-medium">Draft Mode (Will not be shown as public listing)</div>
|
||||
</label>
|
||||
</div>
|
||||
@if (mode==='create'){
|
||||
<button (click)="save()" class="bg-blue-500 text-white px-4 py-2 rounded-md hover:bg-blue-600">Post Listing</button>
|
||||
} @else {
|
||||
<button (click)="save()" class="bg-blue-500 text-white px-4 py-2 rounded-md hover:bg-blue-600">Update Listing</button>
|
||||
}
|
||||
</form>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ import { NgxCurrencyDirective } from 'ngx-currency';
|
|||
import { BusinessListing, CommercialPropertyListing, User } from '../../../../../../bizmatch-server/src/models/db.model';
|
||||
import { AutoCompleteCompleteEvent, ImageProperty, emailToDirName } from '../../../../../../bizmatch-server/src/models/main.model';
|
||||
import { environment } from '../../../../environments/environment';
|
||||
import { MessageService } from '../../../components/message/message.service';
|
||||
import { ArrayToStringPipe } from '../../../pipes/array-to-string.pipe';
|
||||
import { GeoService } from '../../../services/geo.service';
|
||||
import { ImageService } from '../../../services/image.service';
|
||||
|
|
@ -39,25 +40,7 @@ export class EditBusinessListingComponent {
|
|||
listing: BusinessListing;
|
||||
private id: string | undefined = this.activatedRoute.snapshot.params['id'] as string | undefined;
|
||||
user: User;
|
||||
maxFileSize = 3000000;
|
||||
environment = environment;
|
||||
responsiveOptions = [
|
||||
{
|
||||
breakpoint: '1199px',
|
||||
numVisible: 1,
|
||||
numScroll: 1,
|
||||
},
|
||||
{
|
||||
breakpoint: '991px',
|
||||
numVisible: 2,
|
||||
numScroll: 1,
|
||||
},
|
||||
{
|
||||
breakpoint: '767px',
|
||||
numVisible: 1,
|
||||
numScroll: 1,
|
||||
},
|
||||
];
|
||||
config = { aspectRatio: 16 / 9 };
|
||||
editorModules = TOOLBAR_OPTIONS;
|
||||
draggedImage: ImageProperty;
|
||||
|
|
@ -76,7 +59,7 @@ export class EditBusinessListingComponent {
|
|||
private geoService: GeoService,
|
||||
private imageService: ImageService,
|
||||
private loadingService: LoadingService,
|
||||
|
||||
private messageService: MessageService,
|
||||
private route: ActivatedRoute,
|
||||
private keycloakService: KeycloakService,
|
||||
) {
|
||||
|
|
@ -114,7 +97,7 @@ export class EditBusinessListingComponent {
|
|||
async save() {
|
||||
this.listing = await this.listingsService.save(this.listing, this.listing.listingsCategory);
|
||||
this.router.navigate(['editBusinessListing', this.listing.id]);
|
||||
// this.messageService.add({ severity: 'info', summary: 'Confirmed', detail: 'Listing changes have been persisted', life: 3000 });
|
||||
this.messageService.addMessage({ severity: 'success', text: 'Listing changes have been persisted', duration: 3000 });
|
||||
}
|
||||
|
||||
suggestions: string[] | undefined;
|
||||
|
|
|
|||
|
|
@ -137,7 +137,7 @@ export class EditCommercialPropertyListingComponent {
|
|||
async save() {
|
||||
this.listing = await this.listingsService.save(this.listing, this.listing.listingsCategory);
|
||||
this.router.navigate(['editCommercialPropertyListing', this.listing.id]);
|
||||
// this.messageService.add({ severity: 'info', summary: 'Confirmed', detail: 'Listing changes have been persisted', life: 3000 });
|
||||
this.messageService.addMessage({ severity: 'success', text: 'Listing changes have been persisted', duration: 3000 });
|
||||
}
|
||||
|
||||
async search(event: AutoCompleteCompleteEvent) {
|
||||
|
|
@ -167,10 +167,7 @@ export class EditCommercialPropertyListingComponent {
|
|||
if (this.croppedImage) {
|
||||
this.imageService.uploadImage(this.croppedImage, 'uploadPropertyPicture', this.listing.imagePath, this.listing.serialId).subscribe(
|
||||
async () => {
|
||||
//console.log('Upload successful', response);
|
||||
//setTimeout(async () => {
|
||||
this.listing = await lastValueFrom(this.listingsService.getListingById(this.id, 'commercialProperty'));
|
||||
//}, 10);
|
||||
this.closeModal();
|
||||
},
|
||||
error => {
|
||||
|
|
@ -184,11 +181,10 @@ export class EditCommercialPropertyListingComponent {
|
|||
const confirmed = await this.confirmationService.showConfirmation('Are you sure you want to delete this image?');
|
||||
if (confirmed) {
|
||||
this.listing.imageOrder = this.listing.imageOrder.filter(item => item !== imageName);
|
||||
// await Promise.all([, ]);
|
||||
await this.imageService.deleteListingImage(this.listing.imagePath, this.listing.serialId, imageName);
|
||||
await this.listingsService.save(this.listing, 'commercialProperty');
|
||||
this.listing = await lastValueFrom(this.listingsService.getListingById(this.id, 'commercialProperty'));
|
||||
this.messageService.showMessage('Image deleted');
|
||||
this.messageService.addMessage({ severity: 'success', text: 'Image has been deleted', duration: 3000 });
|
||||
} else {
|
||||
console.log('deny');
|
||||
}
|
||||
|
|
|
|||
|
|
@ -88,7 +88,6 @@
|
|||
</div>
|
||||
</div>
|
||||
<app-confirmation></app-confirmation>
|
||||
<app-message></app-message>
|
||||
<!-- <div class="surface-ground px-4 py-8 md:px-6 lg:px-8 h-full">
|
||||
<div class="p-fluid flex flex-column lg:flex-row">
|
||||
<menu-account></menu-account>
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ export class MyListingComponent {
|
|||
async confirm(listing: ListingType) {
|
||||
const confirmed = await this.confirmationService.showConfirmation(`Are you sure you want to delete this listing?`);
|
||||
if (confirmed) {
|
||||
this.messageService.showMessage('Listing has been deleted');
|
||||
// this.messageService.showMessage('Listing has been deleted');
|
||||
this.deleteListing(listing);
|
||||
}
|
||||
// this.confirmationService.confirm({
|
||||
|
|
|
|||
|
|
@ -29,11 +29,11 @@ export class ImageService {
|
|||
return await lastValueFrom(this.http.delete<[]>(`${this.apiBaseUrl}/bizmatch/image/propertyPicture/${imagePath}/${serial}/${name}`));
|
||||
}
|
||||
|
||||
async deleteLogoImagesById(email: string) {
|
||||
async deleteLogoImagesByMail(email: string) {
|
||||
const adjustedEmail = emailToDirName(email);
|
||||
await lastValueFrom(this.http.delete<[]>(`${this.apiBaseUrl}/bizmatch/image/logo/${adjustedEmail}`));
|
||||
}
|
||||
async deleteProfileImagesById(email: string) {
|
||||
async deleteProfileImagesByMail(email: string) {
|
||||
const adjustedEmail = emailToDirName(email);
|
||||
await lastValueFrom(this.http.delete<[]>(`${this.apiBaseUrl}/bizmatch/image/profile/${adjustedEmail}`));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,33 @@
|
|||
import { Router } from '@angular/router';
|
||||
import { ConsoleFormattedStream, INFO, createLogger as _createLogger, stdSerializers } from 'browser-bunyan';
|
||||
import { jwtDecode } from 'jwt-decode';
|
||||
import { BusinessListing, CommercialPropertyListing } from '../../../../bizmatch-server/src/models/db.model';
|
||||
import { BusinessListing, CommercialPropertyListing, User } from '../../../../bizmatch-server/src/models/db.model';
|
||||
import { JwtToken, KeycloakUser, ListingCriteria } from '../../../../bizmatch-server/src/models/main.model';
|
||||
|
||||
export function createDefaultUser(email: string, firstname: string, lastname: string): User {
|
||||
return {
|
||||
email,
|
||||
firstname,
|
||||
lastname,
|
||||
phoneNumber: '',
|
||||
description: '',
|
||||
companyName: '',
|
||||
companyOverview: '',
|
||||
companyWebsite: '',
|
||||
companyLocation: '',
|
||||
offeredServices: '',
|
||||
areasServed: [],
|
||||
hasProfile: false,
|
||||
hasCompanyLogo: false,
|
||||
licensedIn: [],
|
||||
gender: undefined,
|
||||
customerType: undefined,
|
||||
customerSubType: undefined,
|
||||
created: new Date(),
|
||||
updated: new Date(),
|
||||
};
|
||||
}
|
||||
|
||||
export function createDefaultCommercialPropertyListing(): CommercialPropertyListing {
|
||||
return {
|
||||
id: undefined,
|
||||
|
|
|
|||
Loading…
Reference in New Issue