5 Commits

Author SHA1 Message Date
097f911889 pos and size change 2026-05-28 11:05:32 -05:00
621e5222fa pos and size change 2026-05-28 11:05:23 -05:00
3ed7519afd Disclaimer 2026-05-28 10:41:03 -05:00
3cfe86e1a0 remove Listed since 2026-05-12 10:52:28 -05:00
e62263622f move + fix 2026-04-11 15:15:59 -05:00
7 changed files with 109 additions and 43 deletions

View File

@@ -106,7 +106,14 @@
[leafletCenter]="mapCenter" [leafletZoom]="mapZoom" (leafletMapReady)="onMapReady($event)"></div>
</div>
</div>
<!-- Disclaimer: immer sichtbar, unabhängig von der Map -->
<p class="mt-4 text-sm text-neutral-500 leading-relaxed w-full">
The information on this listing has been provided by either the seller or a business broker
representing the seller. BizMatch, Inc. has no interest or stake in the sale of this business
and has not verified any of the information and assumes no responsibility for its accuracy,
veracity, or completeness. See our full
<a class="text-primary-600 hover:underline hover:cursor-pointer" routerLink="/terms-of-use">Terms of Use</a>.
</p>
<!-- Right column -->
<div class="w-full lg:w-1/2 mt-6 lg:mt-0 print:hidden">
<h2 class="md:mt-8 mb-4 text-xl font-bold">Contact the Author of this Listing</h2>

View File

@@ -1,5 +1,5 @@
import { ChangeDetectorRef, Component } from '@angular/core';
import { NgOptimizedImage } from '@angular/common';
import { ChangeDetectorRef, Component } from '@angular/core';
import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
import { ActivatedRoute, NavigationEnd, Router } from '@angular/router';
import { LeafletModule } from '@bluehalo/ngx-leaflet';
@@ -7,13 +7,13 @@ import { lastValueFrom } from 'rxjs';
import { BusinessListing, EventTypeEnum, ShareByEMail, User } from '../../../../../../bizmatch-server/src/models/db.model';
import { KeycloakUser, MailInfo } from '../../../../../../bizmatch-server/src/models/main.model';
import { environment } from '../../../../environments/environment';
import { BreadcrumbItem, BreadcrumbsComponent } from '../../../components/breadcrumbs/breadcrumbs.component';
import { EMailService } from '../../../components/email/email.service';
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 { ValidatedTextareaComponent } from '../../../components/validated-textarea/validated-textarea.component';
import { ValidationMessagesService } from '../../../components/validation-messages.service';
import { BreadcrumbItem, BreadcrumbsComponent } from '../../../components/breadcrumbs/breadcrumbs.component';
import { AuditService } from '../../../services/audit.service';
import { GeoService } from '../../../services/geo.service';
import { HistoryService } from '../../../services/history.service';
@@ -26,13 +26,13 @@ import { SharedModule } from '../../../shared/shared/shared.module';
import { createMailInfo, map2User } from '../../../utils/utils';
// Import für Leaflet
// Note: Leaflet requires browser environment - protected by isBrowser checks in base class
import { circle, Circle, Control, DomEvent, DomUtil, icon, Icon, latLng, LatLngBounds, Marker, polygon, Polygon, tileLayer } from 'leaflet';
import dayjs from 'dayjs';
import { circle, Control, DomEvent, DomUtil, icon, Icon, latLng, LatLngBounds, Marker, polygon, Polygon, tileLayer } from 'leaflet';
import { provideShareButtonsOptions, SharerMethods, withConfig } from 'ngx-sharebuttons';
import { ShareButton } from 'ngx-sharebuttons/button';
import { shareIcons } from 'ngx-sharebuttons/icons';
import { AuthService } from '../../../services/auth.service';
import { BaseDetailsComponent } from '../base-details.component';
import { ShareButton } from 'ngx-sharebuttons/button';
import { provideShareButtonsOptions, SharerMethods, withConfig } from 'ngx-sharebuttons';
import { shareIcons } from 'ngx-sharebuttons/icons';
@Component({
selector: 'app-details-business-listing',
standalone: true,
@@ -376,7 +376,6 @@ export class DetailsBusinessListingComponent extends BaseDetailsComponent {
{ label: 'Support & Training', value: this.listing.supportAndTraining },
{ label: 'Reason for Sale', value: this.listing.reasonForSale },
{ label: 'Broker licensing', value: this.listing.brokerLicencing },
{ label: 'Listed since', value: `${this.dateInserted()} - ${this.getDaysListed()} days` },
{
label: 'Listing by',
value: null, // Wird nicht verwendet

View File

@@ -107,7 +107,14 @@
[leafletCenter]="mapCenter" [leafletZoom]="mapZoom" (leafletMapReady)="onMapReady($event)"></div>
</div>
</div>
<!-- Disclaimer: immer sichtbar, unabhängig von der Map -->
<p class="mt-4 text-sm text-neutral-500 leading-relaxed w-full">
The information on this listing has been provided by either the seller or a business broker
representing the seller. BizMatch, Inc. has no interest or stake in the sale of this business
and has not verified any of the information and assumes no responsibility for its accuracy,
veracity, or completeness. See our full
<a class="text-primary-600 hover:underline hover:cursor-pointer" routerLink="/terms-of-use">Terms of Use</a>.
</p>
<div class="w-full lg:w-1/2 mt-6 lg:mt-0">
@if(this.images.length>0){
<div class="block print:hidden">

View File

@@ -1,15 +1,18 @@
import { ChangeDetectorRef, Component, NgZone } from '@angular/core';
import { NgOptimizedImage } from '@angular/common';
import { ChangeDetectorRef, Component, NgZone } from '@angular/core';
import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
import { ActivatedRoute, Router } from '@angular/router';
import { LeafletModule } from '@bluehalo/ngx-leaflet';
import { APP_ICONS } from '../../../utils/fontawesome-icons';
import dayjs from 'dayjs';
import { GALLERY_CONFIG, GalleryConfig, GalleryModule, ImageItem } from 'ng-gallery';
import { provideShareButtonsOptions, SharerMethods, withConfig } from 'ngx-sharebuttons';
import { ShareButton } from 'ngx-sharebuttons/button';
import { shareIcons } from 'ngx-sharebuttons/icons';
import { lastValueFrom } from 'rxjs';
import { CommercialPropertyListing, EventTypeEnum, ShareByEMail, 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 { BreadcrumbItem, BreadcrumbsComponent } from '../../../components/breadcrumbs/breadcrumbs.component';
import { EMailService } from '../../../components/email/email.service';
import { MessageService } from '../../../components/message/message.service';
import { ValidatedInputComponent } from '../../../components/validated-input/validated-input.component';
@@ -26,12 +29,9 @@ import { SelectOptionsService } from '../../../services/select-options.service';
import { SeoService } from '../../../services/seo.service';
import { UserService } from '../../../services/user.service';
import { SharedModule } from '../../../shared/shared/shared.module';
import { APP_ICONS } from '../../../utils/fontawesome-icons';
import { createMailInfo, map2User } from '../../../utils/utils';
import { BaseDetailsComponent } from '../base-details.component';
import { BreadcrumbItem, BreadcrumbsComponent } from '../../../components/breadcrumbs/breadcrumbs.component';
import { ShareButton } from 'ngx-sharebuttons/button';
import { provideShareButtonsOptions, SharerMethods, withConfig } from 'ngx-sharebuttons';
import { shareIcons } from 'ngx-sharebuttons/icons';
@Component({
selector: 'app-details-commercial-property-listing',
@@ -145,7 +145,6 @@ export class DetailsCommercialPropertyListingComponent extends BaseDetailsCompon
{ label: 'Located in', value: this.selectOptions.getState(this.listing.location.state) },
{ label: this.listing.location.name ? 'City' : 'County', value: this.listing.location.name ? this.listing.location.name : this.listing.location.county },
{ label: 'Asking Price:', value: `$${this.listing.price?.toLocaleString()}` },
{ label: 'Listed since', value: `${this.dateInserted()} - ${this.getDaysListed()} days` },
{
label: 'Listing by',
value: null, // Wird nicht verwendet

View File

@@ -136,13 +136,44 @@ export class HomeComponent {
// FAQ content is preserved in component for future use when FAQ section is made visible
const organizationSchema = this.seoService.generateOrganizationSchema();
// Add HowTo schema for buying a business
const howToSchema = this.seoService.generateHowToSchema({
name: 'How to Buy a Business on BizMatch',
description: 'Step-by-step guide to finding and purchasing your ideal business through BizMatch marketplace',
totalTime: 'PT45M',
steps: [
{
name: 'Browse Business Listings',
text: 'Search through thousands of verified business listings using our advanced filters. Filter by industry, location, price range, revenue, and more to find businesses that match your criteria.'
},
{
name: 'Review Business Details',
text: 'Examine the business financials, including annual revenue, cash flow, asking price, and years established. Read the detailed business description and view photos of the operation.'
},
{
name: 'Contact the Seller',
text: 'Use our secure messaging system to contact the seller or business broker directly. Request additional information, financial documents, or schedule a site visit to see the business in person.'
},
{
name: 'Conduct Due Diligence',
text: 'Review all financial statements, tax returns, lease agreements, and legal documents. Verify the business information, inspect the physical location, and consult with legal and financial advisors.'
},
{
name: 'Make an Offer',
text: 'Submit a formal offer based on your valuation and due diligence findings. Negotiate terms including purchase price, payment structure, transition period, and any contingencies.'
},
{
name: 'Close the Transaction',
text: 'Work with attorneys and escrow services to finalize all legal documents, transfer ownership, and complete the purchase. The seller will transfer assets, train you on operations, and help with the transition.'
}
]
});
// Add SearchBox schema for Sitelinks Search
const searchBoxSchema = this.seoService.generateSearchBoxSchema();
// Inject schemas (FAQ schema excluded - content not visible to users)
this.seoService.injectMultipleSchemas([organizationSchema, searchBoxSchema]);
this.seoService.injectMultipleSchemas([organizationSchema, howToSchema, searchBoxSchema]);
// Clear all filters and sort options on initial load
this.filterStateService.resetCriteria('businessListings');

View File

@@ -66,7 +66,39 @@
<!-- Note: Organization and WebSite schemas are now injected dynamically by SeoService -->
<!-- with more complete data (telephone, foundingDate, knowsAbout, dual search actions) -->
<!-- LocalBusiness Schema for local visibility -->
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "LocalBusiness",
"@id": "https://www.bizmatch.net/#localbusiness",
"name": "BizMatch",
"description": "Business brokerage and commercial real estate marketplace connecting buyers and sellers across the United States.",
"url": "https://www.bizmatch.net",
"logo": "https://www.bizmatch.net/assets/images/bizmatch-logo.png",
"image": "https://www.bizmatch.net/assets/images/bizmatch-logo.png",
"priceRange": "$$",
"address": {
"@type": "PostalAddress",
"streetAddress": "1001 Blucher Street",
"addressLocality": "Corpus Christi",
"addressRegion": "TX",
"postalCode": "78401",
"addressCountry": "US"
},
"geo": {
"@type": "GeoCoordinates",
"latitude": "27.7876",
"longitude": "-97.3940"
},
"areaServed": {
"@type": "Country",
"name": "United States"
},
"serviceType": ["Business Brokerage", "Commercial Real Estate", "Business For Sale Listings"],
"knowsAbout": ["Business Sales", "Commercial Properties", "Franchise Opportunities", "Business Valuation"]
}
</script>
</head>
<body class="flex flex-col min-h-screen">

View File

@@ -1,39 +1,37 @@
services:
# --- FRONTEND ---
# --- FRONTEND (SSR) ---
bizmatch-ssr:
build:
context: . # Pfad zum Angular Ordner
context: .
dockerfile: bizmatch/Dockerfile
image: bizmatch-ssr
container_name: bizmatch-ssr
extra_hosts:
- "localhost:host-gateway"
restart: unless-stopped
ports:
- '4200:4000' # Extern 4200 -> Intern 4000 (SSR)
environment:
NODE_ENV: production
# In der Produktion brauchen wir keine Ports nach außen (Caddy regelt das intern)
networks:
- bizmatch
volumes:
- ./bizmatch-server/pictures:/app/pictures
environment:
NODE_ENV: production
# WICHTIG: Die URL, unter der das SSR-Frontend die API intern erreicht
API_INTERNAL_URL: http://bizmatch-app:3001
# --- BACKEND ---
app:
build:
context: ./bizmatch-server # Pfad zum NestJS Ordner
context: ./bizmatch-server
dockerfile: Dockerfile
image: bizmatch-server:latest
container_name: bizmatch-app
restart: unless-stopped
ports:
- '3001:3001'
env_file:
- ./bizmatch-server/.env # Pfad zur .env Datei
- ./bizmatch-server/.env
depends_on:
- postgres
networks:
- bizmatch
# WICHTIG: Kein Volume Mapping für node_modules im Prod-Modus!
# Das Image bringt alles fertig mit.
volumes:
# Das Backend braucht ebenfalls Zugriff auf den Bilder-Ordner zum Speichern!
- ./bizmatch-server/pictures:/app/dist/pictures
# --- DATABASE ---
postgres:
@@ -44,19 +42,12 @@ services:
- bizmatch-db-data:/var/lib/postgresql/data
env_file:
- ./bizmatch-server/.env
environment:
POSTGRES_DB: ${POSTGRES_DB}
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
ports:
- '5434:5432'
networks:
- bizmatch
volumes:
bizmatch-db-data:
driver: local
networks:
bizmatch:
external: false # Oder true, falls du es manuell erstellt hast
external: true # Wir nutzen das gleiche Netzwerk wie für Caddy