diff --git a/bizmatch-server/src/models/db.model.ts b/bizmatch-server/src/models/db.model.ts
index 0b716b5..4ef9ecd 100644
--- a/bizmatch-server/src/models/db.model.ts
+++ b/bizmatch-server/src/models/db.model.ts
@@ -102,7 +102,7 @@ const USStates = z.enum([
'WY',
]);
export const AreasServedSchema = z.object({
- county: z.string().nonempty('County is required'),
+ county: z.string().optional().nullable(),
state: z.string().nonempty('State is required'),
});
diff --git a/bizmatch-server/src/models/main.model.ts b/bizmatch-server/src/models/main.model.ts
index 0d91bf2..3f68a9f 100644
--- a/bizmatch-server/src/models/main.model.ts
+++ b/bizmatch-server/src/models/main.model.ts
@@ -92,8 +92,7 @@ export interface CommercialPropertyListingCriteria extends ListCriteria {
criteriaType: 'commercialPropertyListings';
}
export interface UserListingCriteria extends ListCriteria {
- firstname: string;
- lastname: string;
+ brokerName: string;
companyName: string;
counties: string[];
criteriaType: 'brokerListings';
diff --git a/bizmatch-server/src/user/user.service.ts b/bizmatch-server/src/user/user.service.ts
index cc876f0..fdb9f23 100644
--- a/bizmatch-server/src/user/user.service.ts
+++ b/bizmatch-server/src/user/user.service.ts
@@ -10,7 +10,7 @@ import { FileService } from '../file/file.service.js';
import { GeoService } from '../geo/geo.service.js';
import { User, UserSchema } from '../models/db.model.js';
import { createDefaultUser, emailToDirName, JwtUser, UserListingCriteria } from '../models/main.model.js';
-import { convertDrizzleUserToUser, convertUserToDrizzleUser, getDistanceQuery } from '../utils.js';
+import { convertDrizzleUserToUser, convertUserToDrizzleUser, getDistanceQuery, splitName } from '../utils.js';
type CustomerSubType = (typeof customerSubTypeEnum.enumValues)[number];
@Injectable()
@@ -37,12 +37,9 @@ export class UserService {
whereConditions.push(inArray(schema.users.customerSubType, criteria.types as CustomerSubType[]));
}
- if (criteria.firstname) {
- whereConditions.push(ilike(schema.users.firstname, `%${criteria.firstname}%`));
- }
-
- if (criteria.lastname) {
- whereConditions.push(ilike(schema.users.lastname, `%${criteria.lastname}%`));
+ if (criteria.brokerName) {
+ const { firstname, lastname } = splitName(criteria.brokerName);
+ whereConditions.push(or(ilike(schema.users.firstname, `%${firstname}%`), ilike(schema.users.lastname, `%${lastname}%`)));
}
if (criteria.companyName) {
diff --git a/bizmatch-server/src/utils.ts b/bizmatch-server/src/utils.ts
index 156f11f..69fb98c 100644
--- a/bizmatch-server/src/utils.ts
+++ b/bizmatch-server/src/utils.ts
@@ -139,3 +139,16 @@ function unflattenObject(obj: any, separator: string = '_'): any {
return result;
}
+export function splitName(fullName: string): { firstname: string; lastname: string } {
+ const parts = fullName.trim().split(/\s+/); // Teile den Namen am Leerzeichen auf
+
+ if (parts.length === 1) {
+ // Falls es nur ein Teil gibt, ist firstname und lastname gleich
+ return { firstname: parts[0], lastname: parts[0] };
+ } else {
+ // Ansonsten ist der letzte Teil der lastname, der Rest der firstname
+ const lastname = parts.pop()!;
+ const firstname = parts.join(' ');
+ return { firstname, lastname };
+ }
+}
diff --git a/bizmatch/src/app/components/customer-sub-type/customer-sub-type.component.ts b/bizmatch/src/app/components/customer-sub-type/customer-sub-type.component.ts
new file mode 100644
index 0000000..ee2d61c
--- /dev/null
+++ b/bizmatch/src/app/components/customer-sub-type/customer-sub-type.component.ts
@@ -0,0 +1,29 @@
+import { CommonModule } from '@angular/common';
+import { Component, Input } from '@angular/core';
+import { FormsModule } from '@angular/forms';
+
+interface KeyValue {
+ name: string;
+ value: string;
+}
+
+@Component({
+ selector: 'app-customer-sub-type',
+ standalone: true,
+ imports: [CommonModule, FormsModule],
+ template: `
+
+ Broker
+ CPA
+ Attorney
+ Title Company
+ Surveyor
+ Appraiser
+ Unknown
+
+ `,
+ styles: [],
+})
+export class CustomerSubTypeComponent {
+ @Input() customerSubType: 'broker' | 'cpa' | 'attorney' | 'surveyor' | 'appraiser' | 'titleCompany';
+}
diff --git a/bizmatch/src/app/components/header/header.component.html b/bizmatch/src/app/components/header/header.component.html
index 26c6be3..ecb0372 100644
--- a/bizmatch/src/app/components/header/header.component.html
+++ b/bizmatch/src/app/components/header/header.component.html
@@ -154,6 +154,7 @@
Account
+ @if(user.customerType==='professional' || isAdmin()){
Create Listing
My Listings
+ }
EMail Us
diff --git a/bizmatch/src/app/components/header/header.component.ts b/bizmatch/src/app/components/header/header.component.ts
index e498aac..0b03bcf 100644
--- a/bizmatch/src/app/components/header/header.component.ts
+++ b/bizmatch/src/app/components/header/header.component.ts
@@ -82,40 +82,6 @@ export class HeaderComponent {
this.criteria = getCriteriaProxy(this.baseRoute, this);
this.searchService.search(this.criteria);
}
- // getCriteriaProxy(path:string):BusinessListingCriteria | CommercialPropertyListingCriteria | UserListingCriteria{
- // if ('businessListings' === path) {
- // return this.createEnhancedProxy(getCriteriaStateObject('business'));
- // } else if ('commercialPropertyListings' === path) {
- // return this.createEnhancedProxy(getCriteriaStateObject('commercialProperty'));
- // } else if ('brokerListings' === path) {
- // return this.createEnhancedProxy(getCriteriaStateObject('broker'));
- // } else {
- // return undefined;
- // }
- // }
- // private createEnhancedProxy(obj: any) {
- // const component = this;
-
- // const sessionStorageHandler = function (path, value, previous, applyData) {
- // let criteriaType = '';
- // if ('/businessListings' === window.location.pathname) {
- // criteriaType = 'business';
- // } else if ('/commercialPropertyListings' === window.location.pathname) {
- // criteriaType = 'commercialProperty';
- // } else if ('/brokerListings' === window.location.pathname) {
- // criteriaType = 'broker';
- // }
- // 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();
- // });
- // }
ngAfterViewInit() {}
@@ -183,4 +149,7 @@ export class HeaderComponent {
return 0;
}
}
+ isAdmin() {
+ return this.keycloakService.getUserRoles(true).includes('ADMIN');
+ }
}
diff --git a/bizmatch/src/app/components/search-modal/search-modal.component.html b/bizmatch/src/app/components/search-modal/search-modal.component.html
index d92f328..cade652 100644
--- a/bizmatch/src/app/components/search-modal/search-modal.component.html
+++ b/bizmatch/src/app/components/search-modal/search-modal.component.html
@@ -392,7 +392,14 @@
{{ city.name }} - {{ selectOptions.getStateInitials(city.state) }}
}
-->
-
+
@@ -408,6 +415,15 @@
+
+
+
+
diff --git a/bizmatch/src/app/pages/details/details-user/details-user.component.html b/bizmatch/src/app/pages/details/details-user/details-user.component.html
index cfd73df..1b93daf 100644
--- a/bizmatch/src/app/pages/details/details-user/details-user.component.html
+++ b/bizmatch/src/app/pages/details/details-user/details-user.component.html
@@ -201,6 +201,10 @@
Company Location
{{ user.companyLocation.name }} - {{ user.companyLocation.state }}
+
+ Professional Type
+ {{ selectOptions.getCustomerSubType(user.customerSubType) }}
+
diff --git a/bizmatch/src/app/pages/listings/broker-listings/broker-listings.component.html b/bizmatch/src/app/pages/listings/broker-listings/broker-listings.component.html
index 6cfc281..9bfa0ff 100644
--- a/bizmatch/src/app/pages/listings/broker-listings/broker-listings.component.html
+++ b/bizmatch/src/app/pages/listings/broker-listings/broker-listings.component.html
@@ -76,7 +76,8 @@
{{ user.description }}
{{ user.firstname }} {{ user.lastname }}
-
{{ user.companyName }}
+
+
{{ user.companyName }}
diff --git a/bizmatch/src/app/pages/listings/broker-listings/broker-listings.component.ts b/bizmatch/src/app/pages/listings/broker-listings/broker-listings.component.ts
index 111d4a9..bcbe0a7 100644
--- a/bizmatch/src/app/pages/listings/broker-listings/broker-listings.component.ts
+++ b/bizmatch/src/app/pages/listings/broker-listings/broker-listings.component.ts
@@ -5,6 +5,7 @@ import { ActivatedRoute, Router, RouterModule } from '@angular/router';
import { BusinessListing, User } from '../../../../../../bizmatch-server/src/models/db.model';
import { LISTINGS_PER_PAGE, ListingType, UserListingCriteria, emailToDirName } from '../../../../../../bizmatch-server/src/models/main.model';
import { environment } from '../../../../environments/environment';
+import { CustomerSubTypeComponent } from '../../../components/customer-sub-type/customer-sub-type.component';
import { PaginatorComponent } from '../../../components/paginator/paginator.component';
import { ImageService } from '../../../services/image.service';
import { ListingsService } from '../../../services/listings.service';
@@ -16,7 +17,7 @@ import { getCriteriaStateObject } from '../../../utils/utils';
@Component({
selector: 'app-broker-listings',
standalone: true,
- imports: [CommonModule, FormsModule, RouterModule, NgOptimizedImage, PaginatorComponent],
+ imports: [CommonModule, FormsModule, RouterModule, NgOptimizedImage, PaginatorComponent, CustomerSubTypeComponent],
templateUrl: './broker-listings.component.html',
styleUrls: ['./broker-listings.component.scss', '../../pages.scss'],
})
diff --git a/bizmatch/src/app/pages/subscription/account/account.component.ts b/bizmatch/src/app/pages/subscription/account/account.component.ts
index 6b1f0d6..5c7dec9 100644
--- a/bizmatch/src/app/pages/subscription/account/account.component.ts
+++ b/bizmatch/src/app/pages/subscription/account/account.component.ts
@@ -128,12 +128,18 @@ export class AccountComponent {
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);
+ const confirmed = await this.confirmationService.showConfirmation({ message: 'Are you sure you want to switch to Buyer ? All your listings as well as all your professionals informations will be deleted' });
+ if (confirmed) {
+ 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);
+ } else {
+ this.user.customerType = 'professional';
+ return;
+ }
}
try {
await this.userService.save(this.user);
diff --git a/bizmatch/src/app/pages/subscription/edit-commercial-property-listing/edit-commercial-property-listing.component.html b/bizmatch/src/app/pages/subscription/edit-commercial-property-listing/edit-commercial-property-listing.component.html
index 14d741b..7024ff8 100644
--- a/bizmatch/src/app/pages/subscription/edit-commercial-property-listing/edit-commercial-property-listing.component.html
+++ b/bizmatch/src/app/pages/subscription/edit-commercial-property-listing/edit-commercial-property-listing.component.html
@@ -115,7 +115,7 @@
}
-->
-
+
- @if (mode!=='create'){
-
+
+
Property Pictures
+ @if(mode === 'create'){
(Pictures can be uploaded once the listing is posted initially)
+ } @if(mode !== 'create'){
-
+ }
+
- } @if (mode==='create'){
+ @if (mode==='create'){
} @else {
@@ -156,15 +159,6 @@
}
-
-
-
-
Crop Image
-
-
-
-
-
-
-
+
+
diff --git a/bizmatch/src/app/pages/subscription/edit-commercial-property-listing/edit-commercial-property-listing.component.ts b/bizmatch/src/app/pages/subscription/edit-commercial-property-listing/edit-commercial-property-listing.component.ts
index 812da23..2f8ef1f 100644
--- a/bizmatch/src/app/pages/subscription/edit-commercial-property-listing/edit-commercial-property-listing.component.ts
+++ b/bizmatch/src/app/pages/subscription/edit-commercial-property-listing/edit-commercial-property-listing.component.ts
@@ -11,15 +11,16 @@ import { faTrash } from '@fortawesome/free-solid-svg-icons';
import { NgSelectModule } from '@ng-select/ng-select';
import { KeycloakService } from 'keycloak-angular';
import { NgxCurrencyDirective } from 'ngx-currency';
-import { ImageCroppedEvent, ImageCropperComponent } from 'ngx-image-cropper';
+import { ImageCropperComponent } from 'ngx-image-cropper';
import { QuillModule } from 'ngx-quill';
import { BusinessListing, CommercialPropertyListing, User } from '../../../../../../bizmatch-server/src/models/db.model';
-import { AutoCompleteCompleteEvent, ImageProperty, createDefaultCommercialPropertyListing, emailToDirName } from '../../../../../../bizmatch-server/src/models/main.model';
+import { AutoCompleteCompleteEvent, ImageProperty, UploadParams, createDefaultCommercialPropertyListing, emailToDirName } from '../../../../../../bizmatch-server/src/models/main.model';
import { environment } from '../../../../environments/environment';
import { ConfirmationComponent } from '../../../components/confirmation/confirmation.component';
import { ConfirmationService } from '../../../components/confirmation/confirmation.service';
import { DragDropMixedComponent } from '../../../components/drag-drop-mixed/drag-drop-mixed.component';
+import { ImageCropAndUploadComponent, UploadReponse } from '../../../components/image-crop-and-upload/image-crop-and-upload.component';
import { MessageService } from '../../../components/message/message.service';
import { ValidatedCityComponent } from '../../../components/validated-city/validated-city.component';
import { ValidatedInputComponent } from '../../../components/validated-input/validated-input.component';
@@ -52,6 +53,7 @@ import { TOOLBAR_OPTIONS } from '../../utils/defaults';
ValidatedNgSelectComponent,
ValidatedPriceComponent,
ValidatedCityComponent,
+ ImageCropAndUploadComponent,
],
providers: [],
templateUrl: './edit-commercial-property-listing.component.html',
@@ -101,9 +103,10 @@ export class EditCommercialPropertyListingComponent {
quillModules = {
toolbar: [['bold', 'italic', 'underline', 'strike'], [{ list: 'ordered' }, { list: 'bullet' }], [{ header: [1, 2, 3, 4, 5, 6, false] }], [{ color: [] }, { background: [] }], ['clean']],
};
- showModal = false;
+ //showModal = false;
imageChangedEvent: any = '';
croppedImage: Blob | null = null;
+ uploadParams: UploadParams;
constructor(
public selectOptions: SelectOptionsService,
private router: Router,
@@ -179,30 +182,12 @@ export class EditCommercialPropertyListingComponent {
const result = await lastValueFrom(this.geoService.findCitiesStartingWith(event.query));
this.suggestions = result.map(r => r.name).slice(0, 5);
}
- openFileDialog() {
- this.fileInput.nativeElement.click();
- }
- fileChangeEvent(event: any): void {
- this.imageChangedEvent = event;
- this.showModal = true;
+ uploadPropertyPicture() {
+ this.uploadParams = { type: 'uploadPropertyPicture', imagePath: this.listing.imagePath, serialId: this.listing.serialId };
}
-
- imageCropped(event: ImageCroppedEvent) {
- this.croppedImage = event.blob;
- }
-
- closeModal() {
- this.imageChangedEvent = null;
- this.croppedImage = null;
- this.showModal = false;
- }
-
- async uploadImage() {
- if (this.croppedImage) {
- await this.imageService.uploadImage(this.croppedImage, 'uploadPropertyPicture', this.listing.imagePath, this.listing.serialId);
- this.ts = new Date().getTime();
- this.closeModal();
+ async uploadFinished(response: UploadReponse) {
+ if (response.success) {
this.listing = (await lastValueFrom(this.listingsService.getListingById(this.id, 'commercialProperty'))) as CommercialPropertyListing;
}
}
diff --git a/bizmatch/src/app/pages/subscription/email-us/email-us.component.html b/bizmatch/src/app/pages/subscription/email-us/email-us.component.html
index 807908f..f4a195e 100644
--- a/bizmatch/src/app/pages/subscription/email-us/email-us.component.html
+++ b/bizmatch/src/app/pages/subscription/email-us/email-us.component.html
@@ -53,7 +53,7 @@
diff --git a/bizmatch/src/app/services/select-options.service.ts b/bizmatch/src/app/services/select-options.service.ts
index 18cf5a2..d2ef402 100644
--- a/bizmatch/src/app/services/select-options.service.ts
+++ b/bizmatch/src/app/services/select-options.service.ts
@@ -56,6 +56,9 @@ export class SelectOptionsService {
getCustomerType(value: string): string {
return this.customerTypes.find(c => c.value === value)?.name;
}
+ getCustomerSubType(value: string): string {
+ return this.customerSubTypes.find(c => c.value === value)?.name;
+ }
getGender(value: string): string {
return this.gender.find(c => c.value === value)?.name;
}
diff --git a/bizmatch/src/app/utils/utils.ts b/bizmatch/src/app/utils/utils.ts
index 6ff1a22..ec6a5d9 100644
--- a/bizmatch/src/app/utils/utils.ts
+++ b/bizmatch/src/app/utils/utils.ts
@@ -145,8 +145,7 @@ export function createEmptyUserListingCriteria(): UserListingCriteria {
types: [],
prompt: '',
criteriaType: 'brokerListings',
- firstname: '',
- lastname: '',
+ brokerName: '',
companyName: '',
counties: [],
state: '',
@@ -156,7 +155,7 @@ export function createEmptyUserListingCriteria(): UserListingCriteria {
}
export function createMailInfo(user: User): MailInfo {
return {
- sender: { name: `${user.firstname} ${user.lastname}`, email: user.email, phoneNumber: user.phoneNumber, state: user.companyLocation.state, comments: null },
+ sender: { name: `${user.firstname} ${user.lastname}`, email: user.email, phoneNumber: user.phoneNumber, state: user.companyLocation?.state, comments: null },
email: null,
url: environment.mailinfoUrl,
listing: null,