feat: Initialize BizMatch application with core UI components, routing, listing pages, backend services, migration scripts, and vulnerability management.
This commit is contained in:
@@ -6,8 +6,10 @@
|
||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
|
||||
<div class="md:col-span-2">
|
||||
<label for="email" class="block text-sm font-medium text-gray-700">E-mail (required)</label>
|
||||
<input type="email" id="email" name="email" [(ngModel)]="user.email" disabled 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@bizmatch.net</p>
|
||||
<input type="email" id="email" name="email" [(ngModel)]="user.email" disabled
|
||||
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@bizmatch.net</p>
|
||||
</div>
|
||||
@if (isProfessional || (authService.isAdmin() | async)){
|
||||
<div class="flex flex-row items-center justify-around md:space-x-4">
|
||||
@@ -16,20 +18,21 @@
|
||||
<div class="w-20 h-20 w-full rounded-md flex items-center justify-center relative">
|
||||
@if(user?.hasCompanyLogo){
|
||||
<img src="{{ companyLogoUrl }}" alt="Company logo" class="max-w-full max-h-full" />
|
||||
<div class="absolute top-[-0.5rem] right-[0rem] bg-white rounded-full p-1 drop-shadow-custom-bg hover:cursor-pointer" (click)="deleteConfirm('logo')">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" class="w-4 h-4 text-gray-600">
|
||||
<div
|
||||
class="absolute top-[-0.5rem] right-[0rem] bg-white rounded-full p-1 drop-shadow-custom-bg hover:cursor-pointer"
|
||||
(click)="deleteConfirm('logo')">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor"
|
||||
class="w-4 h-4 text-gray-600">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
|
||||
</svg>
|
||||
</div>
|
||||
} @else {
|
||||
<img src="assets/images/placeholder.png" class="max-w-full max-h-full" />
|
||||
<img src="/assets/images/placeholder.png" class="max-w-full max-h-full" />
|
||||
}
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
<button type="button"
|
||||
class="mt-2 w-full px-4 py-2 border border-gray-300 rounded-md shadow-sm text-sm font-medium text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"
|
||||
(click)="uploadCompanyLogo()"
|
||||
>
|
||||
(click)="uploadCompanyLogo()">
|
||||
Upload
|
||||
</button>
|
||||
</div>
|
||||
@@ -38,20 +41,21 @@
|
||||
<div class="w-20 h-20 w-full rounded-md flex items-center justify-center relative">
|
||||
@if(user?.hasProfile){
|
||||
<img src="{{ profileUrl }}" alt="Profile picture" class="max-w-full max-h-full" />
|
||||
<div class="absolute top-[-0.5rem] right-[0rem] bg-white rounded-full p-1 drop-shadow-custom-bg hover:cursor-pointer" (click)="deleteConfirm('profile')">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" class="w-4 h-4 text-gray-600">
|
||||
<div
|
||||
class="absolute top-[-0.5rem] right-[0rem] bg-white rounded-full p-1 drop-shadow-custom-bg hover:cursor-pointer"
|
||||
(click)="deleteConfirm('profile')">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor"
|
||||
class="w-4 h-4 text-gray-600">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
|
||||
</svg>
|
||||
</div>
|
||||
} @else {
|
||||
<img src="assets/images/placeholder.png" class="max-w-full max-h-full" />
|
||||
<img src="/assets/images/placeholder.png" class="max-w-full max-h-full" />
|
||||
}
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
<button type="button"
|
||||
class="mt-2 w-full px-4 py-2 border border-gray-300 rounded-md shadow-sm text-sm font-medium text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"
|
||||
(click)="uploadProfile()"
|
||||
>
|
||||
(click)="uploadProfile()">
|
||||
Upload
|
||||
</button>
|
||||
</div>
|
||||
@@ -74,11 +78,13 @@
|
||||
@if ((authService.isAdmin() | async) && !id){
|
||||
<div>
|
||||
<label for="customerType" class="block text-sm font-medium text-gray-700">User Type</label>
|
||||
<span class="bg-blue-100 text-blue-800 text-sm font-medium me-2 px-2.5 py-0.5 rounded dark:bg-blue-900 dark:text-blue-300">ADMIN</span>
|
||||
<span
|
||||
class="bg-blue-100 text-blue-800 text-sm font-medium me-2 px-2.5 py-0.5 rounded dark:bg-blue-900 dark:text-blue-300">ADMIN</span>
|
||||
</div>
|
||||
|
||||
}@else{
|
||||
<app-validated-select label="Customer Type" name="customerType" [(ngModel)]="user.customerType" [options]="customerTypeOptions"></app-validated-select>
|
||||
<app-validated-select label="Customer Type" name="customerType" [(ngModel)]="user.customerType"
|
||||
[options]="customerTypeOptions"></app-validated-select>
|
||||
} @if (isProfessional){
|
||||
<!-- <div>
|
||||
<label for="customerSubType" class="block text-sm font-medium text-gray-700">Professional Type</label>
|
||||
@@ -86,7 +92,8 @@
|
||||
<option *ngFor="let subType of customerSubTypes" [value]="subType">{{ subType | titlecase }}</option>
|
||||
</select>
|
||||
</div> -->
|
||||
<app-validated-select label="Professional Type" name="customerSubType" [(ngModel)]="user.customerSubType" [options]="customerSubTypeOptions"></app-validated-select>
|
||||
<app-validated-select label="Professional Type" name="customerSubType" [(ngModel)]="user.customerSubType"
|
||||
[options]="customerSubTypeOptions"></app-validated-select>
|
||||
}
|
||||
</div>
|
||||
@if (isProfessional){
|
||||
@@ -99,8 +106,10 @@
|
||||
<label for="description" class="block text-sm font-medium text-gray-700">Describe yourself</label>
|
||||
<input type="text" id="description" name="description" [(ngModel)]="user.description" class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500" />
|
||||
</div> -->
|
||||
<app-validated-input label="Company Name" name="companyName" [(ngModel)]="user.companyName"></app-validated-input>
|
||||
<app-validated-input label="Describe Yourself" name="description" [(ngModel)]="user.description"></app-validated-input>
|
||||
<app-validated-input label="Company Name" name="companyName"
|
||||
[(ngModel)]="user.companyName"></app-validated-input>
|
||||
<app-validated-input label="Describe Yourself" name="description"
|
||||
[(ngModel)]="user.description"></app-validated-input>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
|
||||
@@ -116,11 +125,14 @@
|
||||
<label for="companyLocation" class="block text-sm font-medium text-gray-700">Company Location</label>
|
||||
<input type="text" id="companyLocation" name="companyLocation" [(ngModel)]="user.companyLocation" class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500" />
|
||||
</div> -->
|
||||
<app-validated-input label="Your Phone Number" name="phoneNumber" [(ngModel)]="user.phoneNumber" mask="(000) 000-0000"></app-validated-input>
|
||||
<app-validated-input label="Company Website" name="companyWebsite" [(ngModel)]="user.companyWebsite"></app-validated-input>
|
||||
<app-validated-input label="Your Phone Number" name="phoneNumber" [(ngModel)]="user.phoneNumber"
|
||||
mask="(000) 000-0000"></app-validated-input>
|
||||
<app-validated-input label="Company Website" name="companyWebsite"
|
||||
[(ngModel)]="user.companyWebsite"></app-validated-input>
|
||||
<!-- <app-validated-input label="Company Location" name="companyLocation" [(ngModel)]="user.companyLocation"></app-validated-input> -->
|
||||
<!-- <app-validated-city label="Company Location" name="location" [(ngModel)]="user.location"></app-validated-city> -->
|
||||
<app-validated-location label="Company Location" name="location" [(ngModel)]="user.location"></app-validated-location>
|
||||
<app-validated-location label="Company Location" name="location"
|
||||
[(ngModel)]="user.location"></app-validated-location>
|
||||
</div>
|
||||
|
||||
<!-- <div>
|
||||
@@ -128,21 +140,21 @@
|
||||
<quill-editor [(ngModel)]="user.companyOverview" name="companyOverview" [modules]="quillModules"></quill-editor>
|
||||
</div> -->
|
||||
<div>
|
||||
<app-validated-quill label="Company Overview" name="companyOverview" [(ngModel)]="user.companyOverview"></app-validated-quill>
|
||||
<app-validated-quill label="Company Overview" name="companyOverview"
|
||||
[(ngModel)]="user.companyOverview"></app-validated-quill>
|
||||
</div>
|
||||
<div>
|
||||
<!-- <label for="offeredServices" class="block text-sm font-medium text-gray-700">Services We Offer</label>
|
||||
<quill-editor [(ngModel)]="user.offeredServices" name="offeredServices" [modules]="quillModules"></quill-editor> -->
|
||||
<app-validated-quill label="Services We Offer" name="offeredServices" [(ngModel)]="user.offeredServices"></app-validated-quill>
|
||||
<app-validated-quill label="Services We Offer" name="offeredServices"
|
||||
[(ngModel)]="user.offeredServices"></app-validated-quill>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h3 class="text-lg font-medium text-gray-700 mb-2 relative w-fit">
|
||||
Areas We Serve @if(getValidationMessage('areasServed')){
|
||||
<div
|
||||
[attr.data-tooltip-target]="tooltipTargetAreasServed"
|
||||
class="absolute inline-flex items-center justify-center w-6 h-6 text-xs font-bold text-white bg-red-500 border-2 border-white rounded-full -top-2 dark:border-gray-900 hover:cursor-pointer"
|
||||
>
|
||||
<div [attr.data-tooltip-target]="tooltipTargetAreasServed"
|
||||
class="absolute inline-flex items-center justify-center w-6 h-6 text-xs font-bold text-white bg-red-500 border-2 border-white rounded-full -top-2 dark:border-gray-900 hover:cursor-pointer">
|
||||
!
|
||||
</div>
|
||||
<app-tooltip [id]="tooltipTargetAreasServed" [text]="getValidationMessage('areasServed')"></app-tooltip>
|
||||
@@ -159,19 +171,25 @@
|
||||
@for (areasServed of user.areasServed; track areasServed; let i=$index){
|
||||
<div class="grid grid-cols-12 md:gap-4 gap-1 mb-3 md:mb-1">
|
||||
<div class="col-span-6">
|
||||
<ng-select [items]="selectOptions?.states" bindLabel="name" bindValue="value" [(ngModel)]="areasServed.state" (ngModelChange)="setState(i, $event)" name="areasServed_state{{ i }}"> </ng-select>
|
||||
<ng-select [items]="selectOptions?.states" bindLabel="name" bindValue="value"
|
||||
[(ngModel)]="areasServed.state" (ngModelChange)="setState(i, $event)" name="areasServed_state{{ i }}">
|
||||
</ng-select>
|
||||
</div>
|
||||
<div class="col-span-5">
|
||||
<!-- <input type="text" id="county{{ i }}" name="county{{ i }}" [(ngModel)]="areasServed.county" class="block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500" /> -->
|
||||
<app-validated-county name="county{{ i }}" [(ngModel)]="areasServed.county" labelClasses="text-gray-900 font-medium" [state]="areasServed.state" [readonly]="!areasServed.state"></app-validated-county>
|
||||
<app-validated-county name="county{{ i }}" [(ngModel)]="areasServed.county"
|
||||
labelClasses="text-gray-900 font-medium" [state]="areasServed.state"
|
||||
[readonly]="!areasServed.state"></app-validated-county>
|
||||
</div>
|
||||
<div class="col-span-1">
|
||||
<button type="button" class="px-2 py-1 bg-red-500 text-white rounded-md h-[42px] w-8" (click)="removeArea(i)">-</button>
|
||||
<button type="button" class="px-2 py-1 bg-red-500 text-white rounded-md h-[42px] w-8"
|
||||
(click)="removeArea(i)">-</button>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
<div class="mt-2">
|
||||
<button type="button" class="px-2 py-1 bg-green-500 text-white rounded-md mr-2 h-[42px] w-8" (click)="addArea()">+</button>
|
||||
<button type="button" class="px-2 py-1 bg-green-500 text-white rounded-md mr-2 h-[42px] w-8"
|
||||
(click)="addArea()">+</button>
|
||||
|
||||
<span class="text-sm text-gray-500 ml-2">[Add more Areas or remove existing ones.]</span>
|
||||
</div>
|
||||
@@ -180,10 +198,8 @@
|
||||
<div>
|
||||
<h3 class="text-lg font-medium text-gray-700 mb-2 relative">
|
||||
Licensed In@if(getValidationMessage('licensedIn')){
|
||||
<div
|
||||
[attr.data-tooltip-target]="tooltipTargetLicensed"
|
||||
class="absolute inline-flex items-center justify-center w-6 h-6 text-xs font-bold text-white bg-red-500 border-2 border-white rounded-full -top-2 dark:border-gray-900 hover:cursor-pointer"
|
||||
>
|
||||
<div [attr.data-tooltip-target]="tooltipTargetLicensed"
|
||||
class="absolute inline-flex items-center justify-center w-6 h-6 text-xs font-bold text-white bg-red-500 border-2 border-white rounded-full -top-2 dark:border-gray-900 hover:cursor-pointer">
|
||||
!
|
||||
</div>
|
||||
<app-tooltip [id]="tooltipTargetLicensed" [text]="getValidationMessage('licensedIn')"></app-tooltip>
|
||||
@@ -200,22 +216,20 @@
|
||||
@for (licensedIn of user.licensedIn; track licensedIn; let i=$index){
|
||||
<div class="grid grid-cols-12 md:gap-4 gap-1 mb-3 md:mb-1">
|
||||
<div class="col-span-6">
|
||||
<ng-select [items]="selectOptions?.states" bindLabel="name" bindValue="value" [(ngModel)]="licensedIn.state" name="licensedIn_state{{ i }}"> </ng-select>
|
||||
<ng-select [items]="selectOptions?.states" bindLabel="name" bindValue="value" [(ngModel)]="licensedIn.state"
|
||||
name="licensedIn_state{{ i }}"> </ng-select>
|
||||
</div>
|
||||
<div class="col-span-5">
|
||||
<input
|
||||
type="text"
|
||||
id="licenseNumber{{ i }}"
|
||||
name="licenseNumber{{ i }}"
|
||||
[(ngModel)]="licensedIn.registerNo"
|
||||
class="block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500"
|
||||
/>
|
||||
<input type="text" id="licenseNumber{{ i }}" name="licenseNumber{{ i }}" [(ngModel)]="licensedIn.registerNo"
|
||||
class="block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500" />
|
||||
</div>
|
||||
<button type="button" class="px-2 py-1 bg-red-500 text-white rounded-md h-[42px] w-8" (click)="removeLicence(i)">-</button>
|
||||
<button type="button" class="px-2 py-1 bg-red-500 text-white rounded-md h-[42px] w-8"
|
||||
(click)="removeLicence(i)">-</button>
|
||||
</div>
|
||||
}
|
||||
<div class="mt-2">
|
||||
<button type="button" class="px-2 py-1 bg-green-500 text-white rounded-md mr-2 h-[42px] w-8" (click)="addLicence()">+</button>
|
||||
<button type="button" class="px-2 py-1 bg-green-500 text-white rounded-md mr-2 h-[42px] w-8"
|
||||
(click)="addLicence()">+</button>
|
||||
<span class="text-sm text-gray-500 ml-2">[Add more licenses or remove existing ones.]</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -231,7 +245,9 @@
|
||||
</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)">
|
||||
<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
|
||||
</button>
|
||||
</div>
|
||||
@@ -314,5 +330,6 @@
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
<app-image-crop-and-upload [uploadParams]="uploadParams" (uploadFinished)="uploadFinished($event)"></app-image-crop-and-upload>
|
||||
<app-confirmation></app-confirmation>
|
||||
<app-image-crop-and-upload [uploadParams]="uploadParams"
|
||||
(uploadFinished)="uploadFinished($event)"></app-image-crop-and-upload>
|
||||
<app-confirmation></app-confirmation>
|
||||
@@ -39,16 +39,12 @@ import { TOOLBAR_OPTIONS } from '../../utils/defaults';
|
||||
imports: [
|
||||
SharedModule,
|
||||
QuillModule,
|
||||
NgxCurrencyDirective,
|
||||
NgSelectModule,
|
||||
ImageCropperComponent,
|
||||
ConfirmationComponent,
|
||||
ImageCropAndUploadComponent,
|
||||
MessageComponent,
|
||||
ValidatedInputComponent,
|
||||
ValidatedSelectComponent,
|
||||
ValidatedQuillComponent,
|
||||
ValidatedCityComponent,
|
||||
TooltipComponent,
|
||||
ValidatedCountyComponent,
|
||||
ValidatedLocationComponent,
|
||||
@@ -95,7 +91,7 @@ export class AccountComponent {
|
||||
private datePipe: DatePipe,
|
||||
private router: Router,
|
||||
public authService: AuthService,
|
||||
) {}
|
||||
) { }
|
||||
async ngOnInit() {
|
||||
// Flowbite is now initialized once in AppComponent
|
||||
if (this.id) {
|
||||
@@ -162,7 +158,7 @@ export class AccountComponent {
|
||||
ngOnDestroy() {
|
||||
this.validationMessagesService.clearMessages(); // Löschen Sie alle bestehenden Validierungsnachrichten
|
||||
}
|
||||
printInvoice(invoice: Invoice) {}
|
||||
printInvoice(invoice: Invoice) { }
|
||||
|
||||
async updateProfile(user: User) {
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user