diff --git a/bizmatch-server/src/models/db.model.ts b/bizmatch-server/src/models/db.model.ts index fdc0bec..def6d21 100644 --- a/bizmatch-server/src/models/db.model.ts +++ b/bizmatch-server/src/models/db.model.ts @@ -98,55 +98,142 @@ export const LicensedInSchema = z.object({ state: z.string().nonempty('State is required'), }); +// export const UserSchema = z +// .object({ +// id: z.string().uuid('Invalid ID format. Must be a valid UUID').optional(), +// firstname: z.string().min(2, 'First name must be at least 2 characters long'), +// lastname: z.string().min(2, 'Last name must be at least 2 characters long'), +// email: z.string().email('Invalid email address'), +// phoneNumber: z.string().optional().nullable(), +// description: z.string().min(10, 'Description must be at least 10 characters long').optional().nullable(), +// companyName: z.string().optional().nullable(), +// companyOverview: z.string().min(10, 'Company overview must be at least 10 characters long').optional().nullable(), +// companyWebsite: z.string().url('Invalid company website URL').optional().nullable(), +// companyLocation: z.string().optional().nullable(), // Additional validation for US locations could be implemented here +// offeredServices: z.string().min(10, 'Offered services must be at least 10 characters long').optional().nullable(), +// areasServed: z.array(AreasServedSchema).optional().nullable(), +// hasProfile: z.boolean().optional().nullable(), +// hasCompanyLogo: z.boolean().optional().nullable(), +// licensedIn: z.array(LicensedInSchema).optional().nullable(), +// gender: GenderEnum.optional().nullable(), +// customerType: CustomerTypeEnum.optional().nullable(), +// customerSubType: CustomerSubTypeEnum.optional().nullable(), +// created: z.date().optional().nullable(), +// updated: z.date().optional().nullable(), +// latitude: z.number().optional().nullable(), +// longitude: z.number().optional().nullable(), +// }) +// .refine( +// data => { +// if (data.customerType === 'professional') { +// return !!data.customerSubType && !!data.phoneNumber && !!data.companyOverview && !!data.description && !!data.offeredServices && !!data.companyLocation && data.areasServed && data.areasServed.length > 0; +// } +// return true; +// }, +// { +// message: 'For professional customers, additional fields are required: customer subtype, phone number, company overview, description, offered services, company location, and at least one area served', +// path: ['customerType'], +// }, +// ) +// .refine( +// data => { +// if (data.customerType === 'professional') { +// return /\(\d{3}\) \d{3}-\d{4}$/.test(data.phoneNumber || ''); +// } +// return true; +// }, +// { +// message: 'Phone number must be in US format: +1 (XXX) XXX-XXXX', +// path: ['phoneNumber'], +// }, +// ); + +const phoneRegex = /^\+1 \(\d{3}\) \d{3}-\d{4}$/; + export const UserSchema = z .object({ - id: z.string().uuid('Invalid ID format. Must be a valid UUID').optional(), - firstname: z.string().min(2, 'First name must be at least 2 characters long'), - lastname: z.string().min(2, 'Last name must be at least 2 characters long'), - email: z.string().email('Invalid email address'), + id: z.string().uuid(), + firstname: z.string().min(2, { message: 'First name must contain at least 2 characters' }), + lastname: z.string().min(2, { message: 'Last name must contain at least 2 characters' }), + email: z.string().email({ message: 'Invalid email address' }), phoneNumber: z.string().optional().nullable(), - description: z.string().min(10, 'Description must be at least 10 characters long').optional().nullable(), + description: z.string().optional().nullable(), companyName: z.string().optional().nullable(), - companyOverview: z.string().min(10, 'Company overview must be at least 10 characters long').optional().nullable(), - companyWebsite: z.string().url('Invalid company website URL').optional().nullable(), - companyLocation: z.string().optional().nullable(), // Additional validation for US locations could be implemented here - offeredServices: z.string().min(10, 'Offered services must be at least 10 characters long').optional().nullable(), + companyOverview: z.string().optional().nullable(), + companyWebsite: z.string().url({ message: 'Invalid URL format' }).optional().nullable(), + companyLocation: z.string().optional().nullable(), + offeredServices: z.string().optional().nullable(), areasServed: z.array(AreasServedSchema).optional().nullable(), hasProfile: z.boolean().optional().nullable(), hasCompanyLogo: z.boolean().optional().nullable(), licensedIn: z.array(LicensedInSchema).optional().nullable(), gender: GenderEnum.optional().nullable(), - customerType: CustomerTypeEnum.optional().nullable(), + customerType: CustomerTypeEnum, customerSubType: CustomerSubTypeEnum.optional().nullable(), created: z.date().optional().nullable(), updated: z.date().optional().nullable(), latitude: z.number().optional().nullable(), longitude: z.number().optional().nullable(), }) - .refine( - data => { - if (data.customerType === 'professional') { - return !!data.customerSubType && !!data.phoneNumber && !!data.companyOverview && !!data.description && !!data.offeredServices && !!data.companyLocation && data.areasServed && data.areasServed.length > 0; + .superRefine((data, ctx) => { + if (data.customerType === 'professional') { + if (!data.customerSubType) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: 'Customer subtype is required for professional customers', + path: ['customerSubType'], + }); } - return true; - }, - { - message: 'For professional customers, additional fields are required: customer subtype, phone number, company overview, description, offered services, company location, and at least one area served', - path: ['customerType'], - }, - ) - .refine( - data => { - if (data.customerType === 'professional') { - return /\(\d{3}\) \d{3}-\d{4}$/.test(data.phoneNumber || ''); + + if (!data.phoneNumber || !phoneRegex.test(data.phoneNumber)) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: 'Phone number is required and must be in US format (+1 (XXX) XXX-XXXX) for professional customers', + path: ['phoneNumber'], + }); } - return true; - }, - { - message: 'Phone number must be in US format: +1 (XXX) XXX-XXXX', - path: ['phoneNumber'], - }, - ); + + if (!data.companyOverview || data.companyOverview.length < 10) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: 'Company overview must contain at least 10 characters for professional customers', + path: ['companyOverview'], + }); + } + + if (!data.description || data.description.length < 10) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: 'Description must contain at least 10 characters for professional customers', + path: ['description'], + }); + } + + if (!data.offeredServices || data.offeredServices.length < 10) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: 'Offered services must contain at least 10 characters for professional customers', + path: ['offeredServices'], + }); + } + + if (!data.companyLocation) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: 'Company location is required for professional customers', + path: ['companyLocation'], + }); + } + + if (!data.areasServed || data.areasServed.length < 1) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: 'At least one area served is required for professional customers', + path: ['areasServed'], + }); + } + } + }); export type AreasServed = z.infer; export type LicensedIn = z.infer; diff --git a/bizmatch/src/app/components/base-input/base-input.component.ts b/bizmatch/src/app/components/base-input/base-input.component.ts index ffe73c7..9cc1b09 100644 --- a/bizmatch/src/app/components/base-input/base-input.component.ts +++ b/bizmatch/src/app/components/base-input/base-input.component.ts @@ -1,5 +1,6 @@ import { Component, Input } from '@angular/core'; import { ControlValueAccessor } from '@angular/forms'; +import { initFlowbite } from 'flowbite'; import { Subscription } from 'rxjs'; import { ValidationMessagesService } from '../validation-messages.service'; @@ -23,6 +24,9 @@ export abstract class BaseInputComponent implements ControlValueAccessor { this.subscription = this.validationMessagesService.messages$.subscribe(() => { this.updateValidationMessage(); }); + setTimeout(() => { + initFlowbite(); + }, 10); } ngOnDestroy() { diff --git a/bizmatch/src/app/components/tooltip/tooltip.component.html b/bizmatch/src/app/components/tooltip/tooltip.component.html new file mode 100644 index 0000000..d72cebb --- /dev/null +++ b/bizmatch/src/app/components/tooltip/tooltip.component.html @@ -0,0 +1,8 @@ + diff --git a/bizmatch/src/app/components/validated-input/validated-input.component.scss b/bizmatch/src/app/components/tooltip/tooltip.component.scss similarity index 100% rename from bizmatch/src/app/components/validated-input/validated-input.component.scss rename to bizmatch/src/app/components/tooltip/tooltip.component.scss diff --git a/bizmatch/src/app/components/tooltip/tooltip.component.ts b/bizmatch/src/app/components/tooltip/tooltip.component.ts new file mode 100644 index 0000000..d83d1db --- /dev/null +++ b/bizmatch/src/app/components/tooltip/tooltip.component.ts @@ -0,0 +1,19 @@ +import { CommonModule } from '@angular/common'; +import { Component, Input } from '@angular/core'; +import { initFlowbite } from 'flowbite'; + +@Component({ + selector: 'app-tooltip', + standalone: true, + imports: [CommonModule], + templateUrl: './tooltip.component.html', +}) +export class TooltipComponent { + @Input() id; + @Input() text; + ngOnInit() { + setTimeout(() => { + initFlowbite(); + }, 10); + } +} diff --git a/bizmatch/src/app/components/validated-input/validated-input.component.html b/bizmatch/src/app/components/validated-input/validated-input.component.html index 437d665..417116c 100644 --- a/bizmatch/src/app/components/validated-input/validated-input.component.html +++ b/bizmatch/src/app/components/validated-input/validated-input.component.html @@ -1 +1,23 @@ -

validated-input works!

+
+ + +
diff --git a/bizmatch/src/app/components/validated-input/validated-input.component.ts b/bizmatch/src/app/components/validated-input/validated-input.component.ts index a2a9788..6b06946 100644 --- a/bizmatch/src/app/components/validated-input/validated-input.component.ts +++ b/bizmatch/src/app/components/validated-input/validated-input.component.ts @@ -1,30 +1,15 @@ import { CommonModule } from '@angular/common'; -import { Component, EventEmitter, forwardRef, Output } from '@angular/core'; +import { Component, EventEmitter, forwardRef, Input, Output } from '@angular/core'; import { FormsModule, NG_VALUE_ACCESSOR } from '@angular/forms'; import { BaseInputComponent } from '../base-input/base-input.component'; +import { TooltipComponent } from '../tooltip/tooltip.component'; import { ValidationMessagesService } from '../validation-messages.service'; @Component({ selector: 'app-validated-input', - template: ` -
- - -
- `, + templateUrl: './validated-input.component.html', standalone: true, - imports: [CommonModule, FormsModule], + imports: [CommonModule, FormsModule, TooltipComponent], providers: [ { provide: NG_VALUE_ACCESSOR, @@ -35,15 +20,13 @@ import { ValidationMessagesService } from '../validation-messages.service'; }) export class ValidatedInputComponent extends BaseInputComponent { @Output() valueChange = new EventEmitter(); - + @Input() kind: 'text' | 'number' | 'email' | 'tel' = 'text'; constructor(validationMessagesService: ValidationMessagesService) { super(validationMessagesService); } onInputChange(event: Event): void { - const value = (event.target as HTMLInputElement).value; - this.value = value; - this.onChange(value); - this.valueChange.emit(value); + this.value = event; + this.onChange(event); } } diff --git a/bizmatch/src/app/components/validated-ng-select/validated-ng-select.component.html b/bizmatch/src/app/components/validated-ng-select/validated-ng-select.component.html new file mode 100644 index 0000000..c90a92d --- /dev/null +++ b/bizmatch/src/app/components/validated-ng-select/validated-ng-select.component.html @@ -0,0 +1,14 @@ +
+ + +
diff --git a/bizmatch/src/app/components/validated-ng-select/validated-ng-select.component.ts b/bizmatch/src/app/components/validated-ng-select/validated-ng-select.component.ts new file mode 100644 index 0000000..c603c98 --- /dev/null +++ b/bizmatch/src/app/components/validated-ng-select/validated-ng-select.component.ts @@ -0,0 +1,31 @@ +import { CommonModule } from '@angular/common'; +import { Component, forwardRef, Input } from '@angular/core'; +import { FormsModule, NG_VALUE_ACCESSOR } from '@angular/forms'; +import { NgSelectModule } from '@ng-select/ng-select'; +import { BaseInputComponent } from '../base-input/base-input.component'; +import { TooltipComponent } from '../tooltip/tooltip.component'; +import { ValidationMessagesService } from '../validation-messages.service'; + +@Component({ + selector: 'app-validated-ng-select', + standalone: true, + imports: [CommonModule, FormsModule, NgSelectModule, TooltipComponent], + templateUrl: './validated-ng-select.component.html', + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => ValidatedNgSelectComponent), + multi: true, + }, + ], +}) +export class ValidatedNgSelectComponent extends BaseInputComponent { + @Input() items; + constructor(validationMessagesService: ValidationMessagesService) { + super(validationMessagesService); + } + onInputChange(event: Event): void { + this.value = event; + this.onChange(this.value); + } +} diff --git a/bizmatch/src/app/components/validated-price/validated-price.component.html b/bizmatch/src/app/components/validated-price/validated-price.component.html new file mode 100644 index 0000000..5e98825 --- /dev/null +++ b/bizmatch/src/app/components/validated-price/validated-price.component.html @@ -0,0 +1,25 @@ +
+ + +
diff --git a/bizmatch/src/app/components/validated-price/validated-price.component.ts b/bizmatch/src/app/components/validated-price/validated-price.component.ts new file mode 100644 index 0000000..9c3ddca --- /dev/null +++ b/bizmatch/src/app/components/validated-price/validated-price.component.ts @@ -0,0 +1,31 @@ +import { CommonModule } from '@angular/common'; +import { Component, forwardRef } from '@angular/core'; +import { FormsModule, NG_VALUE_ACCESSOR } from '@angular/forms'; +import { NgxCurrencyDirective } from 'ngx-currency'; +import { BaseInputComponent } from '../base-input/base-input.component'; +import { TooltipComponent } from '../tooltip/tooltip.component'; +import { ValidationMessagesService } from '../validation-messages.service'; + +@Component({ + selector: 'app-validated-price', + standalone: true, + imports: [CommonModule, FormsModule, TooltipComponent, NgxCurrencyDirective], + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => ValidatedPriceComponent), + multi: true, + }, + ], + templateUrl: './validated-price.component.html', +}) +export class ValidatedPriceComponent extends BaseInputComponent { + constructor(validationMessagesService: ValidationMessagesService) { + super(validationMessagesService); + } + + onInputChange(event: Event): void { + this.value = event; + this.onChange(event); + } +} diff --git a/bizmatch/src/app/components/validated-quill/validated-quill.component.html b/bizmatch/src/app/components/validated-quill/validated-quill.component.html new file mode 100644 index 0000000..da21cd2 --- /dev/null +++ b/bizmatch/src/app/components/validated-quill/validated-quill.component.html @@ -0,0 +1,13 @@ + + diff --git a/bizmatch/src/app/components/validated-quill/validated-quill.component.ts b/bizmatch/src/app/components/validated-quill/validated-quill.component.ts index 80b8067..20cdb09 100644 --- a/bizmatch/src/app/components/validated-quill/validated-quill.component.ts +++ b/bizmatch/src/app/components/validated-quill/validated-quill.component.ts @@ -3,21 +3,17 @@ import { Component, forwardRef } from '@angular/core'; import { FormsModule, NG_VALUE_ACCESSOR } from '@angular/forms'; import { QuillModule } from 'ngx-quill'; import { BaseInputComponent } from '../base-input/base-input.component'; +import { TooltipComponent } from '../tooltip/tooltip.component'; import { ValidationMessagesService } from '../validation-messages.service'; @Component({ selector: 'app-validated-quill', - template: ` -
- - -
- `, + templateUrl: './validated-quill.component.html', + styles: `quill-editor { + width: 100%; + }`, standalone: true, - imports: [CommonModule, FormsModule, QuillModule], + imports: [CommonModule, FormsModule, QuillModule, TooltipComponent], providers: [ { provide: NG_VALUE_ACCESSOR, diff --git a/bizmatch/src/app/components/validated-select/validated-select.component.html b/bizmatch/src/app/components/validated-select/validated-select.component.html index 6f8bd7a..9431866 100644 --- a/bizmatch/src/app/components/validated-select/validated-select.component.html +++ b/bizmatch/src/app/components/validated-select/validated-select.component.html @@ -1 +1,20 @@ -

validated-select works!

+
+ + +
diff --git a/bizmatch/src/app/components/validated-select/validated-select.component.scss b/bizmatch/src/app/components/validated-select/validated-select.component.scss deleted file mode 100644 index e69de29..0000000 diff --git a/bizmatch/src/app/components/validated-select/validated-select.component.ts b/bizmatch/src/app/components/validated-select/validated-select.component.ts index c822627..a4a0f0c 100644 --- a/bizmatch/src/app/components/validated-select/validated-select.component.ts +++ b/bizmatch/src/app/components/validated-select/validated-select.component.ts @@ -2,33 +2,14 @@ import { CommonModule } from '@angular/common'; import { Component, EventEmitter, forwardRef, Input, Output } from '@angular/core'; import { FormsModule, NG_VALUE_ACCESSOR } from '@angular/forms'; import { BaseInputComponent } from '../base-input/base-input.component'; +import { TooltipComponent } from '../tooltip/tooltip.component'; import { ValidationMessagesService } from '../validation-messages.service'; @Component({ selector: 'app-validated-select', - template: ` -
- - -
- `, + templateUrl: './validated-select.component.html', standalone: true, - imports: [CommonModule, FormsModule], + imports: [CommonModule, FormsModule, TooltipComponent], providers: [ { provide: NG_VALUE_ACCESSOR, @@ -38,8 +19,6 @@ import { ValidationMessagesService } from '../validation-messages.service'; ], }) export class ValidatedSelectComponent extends BaseInputComponent { - // @Input() required: boolean = false; - // @Input() validationMessage: string = ''; @Input() options: Array<{ value: any; label: string }> = []; @Output() valueChange = new EventEmitter(); diff --git a/bizmatch/src/app/components/validated-textarea/validated-textarea.component.html b/bizmatch/src/app/components/validated-textarea/validated-textarea.component.html new file mode 100644 index 0000000..f5bb159 --- /dev/null +++ b/bizmatch/src/app/components/validated-textarea/validated-textarea.component.html @@ -0,0 +1,16 @@ +
+ + +
diff --git a/bizmatch/src/app/components/validated-textarea/validated-textarea.component.ts b/bizmatch/src/app/components/validated-textarea/validated-textarea.component.ts index 3746b1b..649e7c0 100644 --- a/bizmatch/src/app/components/validated-textarea/validated-textarea.component.ts +++ b/bizmatch/src/app/components/validated-textarea/validated-textarea.component.ts @@ -1,22 +1,15 @@ import { CommonModule } from '@angular/common'; -import { Component, EventEmitter, forwardRef, Output } from '@angular/core'; +import { Component, forwardRef } from '@angular/core'; import { FormsModule, NG_VALUE_ACCESSOR } from '@angular/forms'; import { BaseInputComponent } from '../base-input/base-input.component'; +import { TooltipComponent } from '../tooltip/tooltip.component'; import { ValidationMessagesService } from '../validation-messages.service'; @Component({ selector: 'app-validated-textarea', - template: ` -
- - -
- `, + templateUrl: './validated-textarea.component.html', standalone: true, - imports: [CommonModule, FormsModule], + imports: [CommonModule, FormsModule, TooltipComponent], providers: [ { provide: NG_VALUE_ACCESSOR, @@ -26,8 +19,6 @@ import { ValidationMessagesService } from '../validation-messages.service'; ], }) export class ValidatedTextareaComponent extends BaseInputComponent { - @Output() valueChange = new EventEmitter(); - constructor(validationMessagesService: ValidationMessagesService) { super(validationMessagesService); } diff --git a/bizmatch/src/app/pages/details/details-business-listing/details-business-listing.component.html b/bizmatch/src/app/pages/details/details-business-listing/details-business-listing.component.html index 932e4ad..589949e 100644 --- a/bizmatch/src/app/pages/details/details-business-listing/details-business-listing.component.html +++ b/bizmatch/src/app/pages/details/details-business-listing/details-business-listing.component.html @@ -38,7 +38,7 @@

Contact the Author of this Listing

Please include your contact info below

-
+ +
+ +
-
+ +
+ +
-
+ +
+
@if(listingUser){
diff --git a/bizmatch/src/app/pages/details/details-business-listing/details-business-listing.component.ts b/bizmatch/src/app/pages/details/details-business-listing/details-business-listing.component.ts index b1d9be6..270ec24 100644 --- a/bizmatch/src/app/pages/details/details-business-listing/details-business-listing.component.ts +++ b/bizmatch/src/app/pages/details/details-business-listing/details-business-listing.component.ts @@ -7,6 +7,8 @@ import { lastValueFrom } from 'rxjs'; import { BusinessListing, User } from '../../../../../../bizmatch-server/src/models/db.model'; import { BusinessListingCriteria, KeycloakUser, MailInfo } from '../../../../../../bizmatch-server/src/models/main.model'; import { environment } from '../../../../environments/environment'; +import { ValidatedInputComponent } from '../../../components/validated-input/validated-input.component'; +import { ValidatedTextareaComponent } from '../../../components/validated-textarea/validated-textarea.component'; import { HistoryService } from '../../../services/history.service'; import { ListingsService } from '../../../services/listings.service'; import { MailService } from '../../../services/mail.service'; @@ -17,7 +19,7 @@ import { getCriteriaStateObject, getSessionStorageHandler, map2User } from '../. @Component({ selector: 'app-details-business-listing', standalone: true, - imports: [SharedModule], + imports: [SharedModule, ValidatedInputComponent, ValidatedTextareaComponent], providers: [], templateUrl: './details-business-listing.component.html', styleUrl: '../details.scss', diff --git a/bizmatch/src/app/pages/details/details-commercial-property-listing/details-commercial-property-listing.component.html b/bizmatch/src/app/pages/details/details-commercial-property-listing/details-commercial-property-listing.component.html index 262a7e7..c42cae6 100644 --- a/bizmatch/src/app/pages/details/details-commercial-property-listing/details-commercial-property-listing.component.html +++ b/bizmatch/src/app/pages/details/details-commercial-property-listing/details-commercial-property-listing.component.html @@ -176,8 +176,8 @@

Contact the Author of this Listing

Please include your contact info below

- -
+ + +
+ +
+
+ + +
+
+ +
+
@if(listingUser){
diff --git a/bizmatch/src/app/pages/details/details-commercial-property-listing/details-commercial-property-listing.component.ts b/bizmatch/src/app/pages/details/details-commercial-property-listing/details-commercial-property-listing.component.ts index c0391d9..29f8ece 100644 --- a/bizmatch/src/app/pages/details/details-commercial-property-listing/details-commercial-property-listing.component.ts +++ b/bizmatch/src/app/pages/details/details-commercial-property-listing/details-commercial-property-listing.component.ts @@ -7,6 +7,8 @@ import { lastValueFrom } from 'rxjs'; import { CommercialPropertyListing, User } from '../../../../../../bizmatch-server/src/models/db.model'; import { CommercialPropertyListingCriteria, ErrorResponse, KeycloakUser, MailInfo } from '../../../../../../bizmatch-server/src/models/main.model'; import { environment } from '../../../../environments/environment'; +import { ValidatedInputComponent } from '../../../components/validated-input/validated-input.component'; +import { ValidatedTextareaComponent } from '../../../components/validated-textarea/validated-textarea.component'; import { HistoryService } from '../../../services/history.service'; import { ImageService } from '../../../services/image.service'; import { ListingsService } from '../../../services/listings.service'; @@ -19,7 +21,7 @@ import { map2User } from '../../../utils/utils'; @Component({ selector: 'app-details-commercial-property-listing', standalone: true, - imports: [SharedModule], + imports: [SharedModule, ValidatedInputComponent, ValidatedTextareaComponent], providers: [], templateUrl: './details-commercial-property-listing.component.html', styleUrl: '../details.scss', diff --git a/bizmatch/src/app/pages/subscription/account/account.component.html b/bizmatch/src/app/pages/subscription/account/account.component.html index 4b679b9..d7b9c0b 100644 --- a/bizmatch/src/app/pages/subscription/account/account.component.html +++ b/bizmatch/src/app/pages/subscription/account/account.component.html @@ -84,18 +84,20 @@
@if (isProfessional){
-
+ + + +
-
+ + + +
-
- - + +
+
+ +
-

Areas We Serve

+

+ Areas We Serve @if(getValidationMessage('areasServed')){ +
+ ! +
+ + } +

diff --git a/bizmatch/src/app/pages/subscription/account/account.component.ts b/bizmatch/src/app/pages/subscription/account/account.component.ts index 5ca30cf..d6ffc09 100644 --- a/bizmatch/src/app/pages/subscription/account/account.component.ts +++ b/bizmatch/src/app/pages/subscription/account/account.component.ts @@ -3,6 +3,7 @@ import { ChangeDetectorRef, Component } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { faTrash } from '@fortawesome/free-solid-svg-icons'; import { NgSelectModule } from '@ng-select/ng-select'; +import { initFlowbite } from 'flowbite'; import { KeycloakService } from 'keycloak-angular'; import { NgxCurrencyDirective } from 'ngx-currency'; import { ImageCropperComponent } from 'ngx-image-cropper'; @@ -16,6 +17,7 @@ import { ConfirmationService } from '../../../components/confirmation/confirmati import { ImageCropAndUploadComponent, UploadReponse } from '../../../components/image-crop-and-upload/image-crop-and-upload.component'; import { MessageComponent } from '../../../components/message/message.component'; import { MessageService } from '../../../components/message/message.service'; +import { TooltipComponent } from '../../../components/tooltip/tooltip.component'; import { ValidatedInputComponent } from '../../../components/validated-input/validated-input.component'; import { ValidatedQuillComponent } from '../../../components/validated-quill/validated-quill.component'; import { ValidatedSelectComponent } from '../../../components/validated-select/validated-select.component'; @@ -45,6 +47,7 @@ import { TOOLBAR_OPTIONS } from '../../utils/defaults'; ValidatedInputComponent, ValidatedSelectComponent, ValidatedQuillComponent, + TooltipComponent, ], providers: [TitleCasePipe], templateUrl: './account.component.html', @@ -71,6 +74,7 @@ export class AccountComponent { validationMessages: ValidationMessage[] = []; customerTypeOptions: Array<{ value: string; label: string }> = []; customerSubTypeOptions: Array<{ value: string; label: string }> = []; + tooltipTarget = 'tooltip-areasServed'; constructor( public userService: UserService, private subscriptionService: SubscriptionsService, @@ -89,6 +93,9 @@ export class AccountComponent { private validationMessagesService: ValidationMessagesService, ) {} async ngOnInit() { + setTimeout(() => { + initFlowbite(); + }, 10); if (this.id) { this.user = await this.userService.getById(this.id); } else { @@ -127,6 +134,7 @@ export class AccountComponent { await this.userService.save(this.user); this.messageService.addMessage({ severity: 'success', text: 'Account changes have been persisted', duration: 3000 }); this.validationMessagesService.clearMessages(); // Löschen Sie alle bestehenden Validierungsnachrichten + this.validationMessages = []; } catch (error) { this.messageService.addMessage({ severity: 'danger', @@ -135,6 +143,7 @@ export class AccountComponent { }); if (error.error && Array.isArray(error.error?.message)) { this.validationMessagesService.updateMessages(error.error.message); + this.validationMessages = error.error.message; } } } diff --git a/bizmatch/src/app/pages/subscription/edit-business-listing/edit-business-listing.component.html b/bizmatch/src/app/pages/subscription/edit-business-listing/edit-business-listing.component.html index e2eebbf..5f8800b 100644 --- a/bizmatch/src/app/pages/subscription/edit-business-listing/edit-business-listing.component.html +++ b/bizmatch/src/app/pages/subscription/edit-business-listing/edit-business-listing.component.html @@ -2,28 +2,37 @@

Edit Listing

@if(listing){ - +
-
+ +
+
-
+ +
+
-
+ +
+
-
+ +
+ +
-
+ +
+ +
-
+ +
+
-
+ +
+ +
@@ -100,17 +124,20 @@
-
+ +
+ +
-
+ +
+ +
-
+ +
+
diff --git a/bizmatch/src/app/pages/subscription/edit-business-listing/edit-business-listing.component.ts b/bizmatch/src/app/pages/subscription/edit-business-listing/edit-business-listing.component.ts index 483aa1d..2475b5e 100644 --- a/bizmatch/src/app/pages/subscription/edit-business-listing/edit-business-listing.component.ts +++ b/bizmatch/src/app/pages/subscription/edit-business-listing/edit-business-listing.component.ts @@ -17,6 +17,11 @@ import { AutoCompleteCompleteEvent, ImageProperty, createDefaultBusinessListing, import { environment } from '../../../../environments/environment'; import { MessageService } from '../../../components/message/message.service'; +import { ValidatedInputComponent } from '../../../components/validated-input/validated-input.component'; +import { ValidatedNgSelectComponent } from '../../../components/validated-ng-select/validated-ng-select.component'; +import { ValidatedPriceComponent } from '../../../components/validated-price/validated-price.component'; +import { ValidatedQuillComponent } from '../../../components/validated-quill/validated-quill.component'; +import { ValidatedTextareaComponent } from '../../../components/validated-textarea/validated-textarea.component'; import { ArrayToStringPipe } from '../../../pipes/array-to-string.pipe'; import { GeoService } from '../../../services/geo.service'; import { ImageService } from '../../../services/image.service'; @@ -27,7 +32,19 @@ import { TOOLBAR_OPTIONS } from '../../utils/defaults'; @Component({ selector: 'business-listing', standalone: true, - imports: [SharedModule, ArrayToStringPipe, DragDropModule, QuillModule, NgxCurrencyDirective, NgSelectModule], + imports: [ + SharedModule, + ArrayToStringPipe, + DragDropModule, + QuillModule, + NgxCurrencyDirective, + NgSelectModule, + ValidatedInputComponent, + ValidatedQuillComponent, + ValidatedNgSelectComponent, + ValidatedPriceComponent, + ValidatedTextareaComponent, + ], providers: [], templateUrl: './edit-business-listing.component.html', styleUrl: './edit-business-listing.component.scss', 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 c80eed3..42cf100 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 @@ -1,177 +1,34 @@ - -

Edit Listing

@if (listing){ - -
+ +
- +
-
+ +
+
-
- - +
+ +
-
+ + -
+ +
+ +
-
+ +
+ +
-
-
+ +
+ + +