feat: Initialize BizMatch application with core UI components, routing, listing pages, backend services, migration scripts, and vulnerability management.

This commit is contained in:
Timo
2026-01-03 23:05:38 +01:00
parent e32e43d17f
commit e3e726d8ca
42 changed files with 1478 additions and 1579 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,7 @@
<nav class="bg-white border-neutral-200 dark:bg-neutral-900 print:hidden">
<div class="max-w-screen-xl flex flex-wrap items-center justify-between mx-auto p-4">
<a routerLink="/home" class="flex items-center space-x-3 rtl:space-x-reverse">
<img src="assets/images/header-logo.png" class="h-10 w-auto"
<img src="/assets/images/header-logo.png" class="h-10 w-auto"
alt="BizMatch - Business Marketplace for Buying and Selling Businesses" />
</a>
<div class="flex items-center md:order-2 space-x-3 rtl:space-x-reverse">
@@ -170,7 +170,7 @@
[ngClass]="{ 'bg-primary-600 text-white md:text-primary-600 md:bg-transparent md:dark:text-primary-500': isActive('/businessListings') }"
class="block py-2 px-3 rounded hover:bg-neutral-100 md:hover:bg-transparent md:hover:text-primary-600 md:p-0 dark:text-white md:dark:hover:text-primary-500 dark:hover:bg-neutral-700 dark:hover:text-white md:dark:hover:bg-transparent dark:border-neutral-700 inline-flex items-center"
aria-current="page" (click)="closeMenusAndSetCriteria('businessListings')">
<img src="assets/images/business_logo.png" alt="Business" class="w-5 h-5 mr-2 object-contain" width="20"
<img src="/assets/images/business_logo.png" alt="Business" class="w-5 h-5 mr-2 object-contain" width="20"
height="20" />
<span>Businesses</span>
</a>
@@ -181,8 +181,8 @@
[ngClass]="{ 'bg-primary-600 text-white md:text-primary-600 md:bg-transparent md:dark:text-primary-500': isActive('/commercialPropertyListings') }"
class="block py-2 px-3 rounded hover:bg-neutral-100 md:hover:bg-transparent md:hover:text-primary-600 md:p-0 dark:text-white md:dark:hover:text-primary-500 dark:hover:bg-neutral-700 dark:hover:text-white md:dark:hover:bg-transparent dark:border-neutral-700 inline-flex items-center"
(click)="closeMenusAndSetCriteria('commercialPropertyListings')">
<img src="assets/images/properties_logo.png" alt="Properties" class="w-5 h-5 mr-2 object-contain" width="20"
height="20" />
<img src="/assets/images/properties_logo.png" alt="Properties" class="w-5 h-5 mr-2 object-contain"
width="20" height="20" />
<span>Properties</span>
</a>
</li>
@@ -192,7 +192,7 @@
[ngClass]="{ 'bg-primary-600 text-white md:text-primary-600 md:bg-transparent md:dark:text-primary-500': isActive('/brokerListings') }"
class="inline-flex items-center py-2 px-3 rounded hover:bg-neutral-100 md:hover:bg-transparent md:hover:text-primary-600 md:p-0 dark:text-white md:dark:hover:text-primary-500 dark:hover:bg-neutral-700 dark:hover:text-white md:dark:hover:bg-transparent dark:border-neutral-700"
(click)="closeMenusAndSetCriteria('brokerListings')">
<img src="assets/images/icon_professionals.png" alt="Professionals"
<img src="/assets/images/icon_professionals.png" alt="Professionals"
class="w-5 h-5 mr-2 object-contain bg-transparent" style="mix-blend-mode: darken;" />
<span>Professionals</span>
</a>

View File

@@ -18,14 +18,14 @@ import { SelectOptionsService } from '../../services/select-options.service';
import { SharedService } from '../../services/shared.service';
import { UserService } from '../../services/user.service';
import { map2User } from '../../utils/utils';
import { DropdownComponent } from '../dropdown/dropdown.component';
import { ModalService } from '../search-modal/modal.service';
@UntilDestroy()
@Component({
selector: 'header',
standalone: true,
imports: [CommonModule, RouterModule, DropdownComponent, FormsModule],
imports: [CommonModule, RouterModule, FormsModule],
templateUrl: './header.component.html',
styleUrl: './header.component.scss',
})
@@ -65,12 +65,14 @@ export class HeaderComponent implements OnInit, OnDestroy, AfterViewInit {
public selectOptions: SelectOptionsService,
public authService: AuthService,
private listingService: ListingsService,
) {}
) { }
@HostListener('document:click', ['$event'])
handleGlobalClick(event: Event) {
const target = event.target as HTMLElement;
if (target.id !== 'sortDropdownButton' && target.id !== 'sortDropdownMobileButton') {
// Don't close sort dropdown when clicking on sort buttons or user menu button
const excludedIds = ['sortDropdownButton', 'sortDropdownMobileButton', 'user-menu-button'];
if (!excludedIds.includes(target.id) && !target.closest('#user-menu-button')) {
this.sortDropdownVisible = false;
}
}
@@ -95,9 +97,15 @@ export class HeaderComponent implements OnInit, OnDestroy, AfterViewInit {
this.profileUrl = photoUrl;
});
// User Updates
// User Updates - re-initialize Flowbite when user state changes
// This ensures the dropdown bindings are updated when the dropdown target changes
this.userService.currentUser.pipe(untilDestroyed(this)).subscribe(u => {
const previousUser = this.user;
this.user = u;
// Re-initialize Flowbite if user logged in/out state changed
if ((previousUser === null) !== (u === null)) {
setTimeout(() => initFlowbite(), 50);
}
});
// Router Events

View File

@@ -10,7 +10,7 @@ import { ValidationMessagesService } from '../validation-messages.service';
selector: 'app-validated-input',
templateUrl: './validated-input.component.html',
standalone: true,
imports: [CommonModule, FormsModule, TooltipComponent, NgxMaskDirective, NgxMaskPipe],
imports: [CommonModule, FormsModule, TooltipComponent, NgxMaskDirective],
providers: [
{
provide: NG_VALUE_ACCESSOR,