From ec0576e7b8e8f687391d9aae257d186e4177ca4c Mon Sep 17 00:00:00 2001 From: Andreas Knuth Date: Mon, 12 Aug 2024 17:18:32 +0200 Subject: [PATCH] diverse BugFixes --- bizmatch-server/src/models/db.model.ts | 2 +- bizmatch-server/src/models/main.model.ts | 3 +- bizmatch-server/src/user/user.service.ts | 11 ++---- bizmatch-server/src/utils.ts | 13 +++++++ .../customer-sub-type.component.ts | 29 +++++++++++++++ .../components/header/header.component.html | 2 + .../app/components/header/header.component.ts | 37 ++----------------- .../search-modal/search-modal.component.html | 18 ++++++++- .../details-user/details-user.component.html | 4 ++ .../broker-listings.component.html | 3 +- .../broker-listings.component.ts | 3 +- .../subscription/account/account.component.ts | 18 ++++++--- ...commercial-property-listing.component.html | 30 ++++++--------- ...t-commercial-property-listing.component.ts | 35 +++++------------- .../email-us/email-us.component.html | 2 +- .../app/services/select-options.service.ts | 3 ++ bizmatch/src/app/utils/utils.ts | 5 +-- 17 files changed, 118 insertions(+), 100 deletions(-) create mode 100644 bizmatch/src/app/components/customer-sub-type/customer-sub-type.component.ts 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,