bizmatch-project/bizmatch/src/app/pages/home/home.component.ts

346 lines
22 KiB
TypeScript

import { CommonModule } from '@angular/common';
import { ChangeDetectorRef, Component, ElementRef, ViewChild } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { ActivatedRoute, Router, RouterModule } from '@angular/router';
import { NgSelectModule } from '@ng-select/ng-select';
import { UntilDestroy } from '@ngneat/until-destroy';
import { catchError, concat, distinctUntilChanged, Observable, of, Subject, switchMap, tap } from 'rxjs';
import { BusinessListingCriteria, CityAndStateResult, CommercialPropertyListingCriteria, GeoResult, KeycloakUser, UserListingCriteria } from '../../../../../bizmatch-server/src/models/main.model';
import { FaqComponent, FAQItem } from '../../components/faq/faq.component';
import { ModalService } from '../../components/search-modal/modal.service';
import { TooltipComponent } from '../../components/tooltip/tooltip.component';
import { AiService } from '../../services/ai.service';
import { AuthService } from '../../services/auth.service';
import { FilterStateService } from '../../services/filter-state.service';
import { GeoService } from '../../services/geo.service';
import { ListingsService } from '../../services/listings.service';
import { SearchService } from '../../services/search.service';
import { SelectOptionsService } from '../../services/select-options.service';
import { SeoService } from '../../services/seo.service';
import { UserService } from '../../services/user.service';
import { map2User } from '../../utils/utils';
@UntilDestroy()
@Component({
selector: 'app-home',
standalone: true,
imports: [CommonModule, FormsModule, RouterModule, NgSelectModule, TooltipComponent, FaqComponent],
templateUrl: './home.component.html',
styleUrl: './home.component.scss',
})
export class HomeComponent {
placeholders: string[] = ['Property close to Houston less than 10M', 'Franchise business in Austin price less than 500K'];
activeTabAction: 'business' | 'commercialProperty' | 'broker' = 'business';
type: string;
maxPrice: string;
minPrice: string;
criteria: BusinessListingCriteria | CommercialPropertyListingCriteria | UserListingCriteria;
states = [];
isMenuOpen = false;
user: KeycloakUser;
prompt: string;
cities$: Observable<CityAndStateResult[]>;
cityLoading = false;
cityInput$ = new Subject<string>();
cityOrState = undefined;
numberOfResults$: Observable<number>;
numberOfBroker$: Observable<number>;
numberOfCommercial$: Observable<number>;
aiSearch = false;
aiSearchText = '';
aiSearchFailed = false;
loadingAi = false;
@ViewChild('aiSearchInput', { static: false }) searchInput!: ElementRef;
typingSpeed: number = 100;
pauseTime: number = 2000;
index: number = 0;
charIndex: number = 0;
typingInterval: any;
showInput: boolean = true;
tooltipTargetBeta = 'tooltipTargetBeta';
// FAQ data optimized for AEO (Answer Engine Optimization) and Featured Snippets
faqItems: FAQItem[] = [
{
question: 'How do I buy a business on BizMatch?',
answer: '<p><strong>Buying a business on BizMatch involves 6 simple steps:</strong></p><ol><li><strong>Browse Listings:</strong> Search our marketplace using filters for industry, location, and price range</li><li><strong>Review Details:</strong> Examine financial information, business operations, and growth potential</li><li><strong>Contact Seller:</strong> Reach out directly through our secure messaging platform</li><li><strong>Due Diligence:</strong> Review financial statements, contracts, and legal documents</li><li><strong>Negotiate Terms:</strong> Work with the seller to agree on price and transition details</li><li><strong>Close Deal:</strong> Complete the purchase with legal and financial advisors</li></ol><p>We recommend working with experienced business brokers and conducting thorough due diligence before making any purchase.</p>'
},
{
question: 'How much does it cost to list a business for sale?',
answer: '<p><strong>BizMatch offers flexible pricing options:</strong></p><ul><li><strong>Free Basic Listing:</strong> Post your business with essential details at no cost</li><li><strong>Premium Listing:</strong> Enhanced visibility with featured placement and priority support</li><li><strong>Broker Packages:</strong> Professional tools for business brokers and agencies</li></ul><p>Contact our team for detailed pricing information tailored to your specific needs.</p>'
},
{
question: 'What types of businesses can I find on BizMatch?',
answer: '<p><strong>BizMatch features businesses across all major industries:</strong></p><ul><li><strong>Food & Hospitality:</strong> Restaurants, cafes, bars, hotels, catering services</li><li><strong>Retail:</strong> Stores, boutiques, online shops, franchises</li><li><strong>Service Businesses:</strong> Consulting firms, cleaning services, healthcare practices</li><li><strong>Manufacturing:</strong> Production facilities, distribution centers, warehouses</li><li><strong>E-commerce:</strong> Online businesses, digital products, subscription services</li><li><strong>Commercial Real Estate:</strong> Office buildings, retail spaces, industrial properties</li></ul><p>Our marketplace serves all business sizes from small local operations to large enterprises across the United States.</p>'
},
{
question: 'How do I know if a business listing is legitimate?',
answer: '<p><strong>Yes, BizMatch verifies all listings.</strong> Here\'s how we ensure legitimacy:</p><ol><li><strong>Seller Verification:</strong> All users must verify their identity and contact information</li><li><strong>Listing Review:</strong> Our team reviews each listing for completeness and accuracy</li><li><strong>Documentation Check:</strong> We verify business registration and ownership documents</li><li><strong>Transparent Communication:</strong> All conversations are logged through our secure platform</li></ol><p><strong>Additional steps you should take:</strong></p><ul><li>Review financial statements and tax returns</li><li>Visit the business location in person</li><li>Consult with legal and financial advisors</li><li>Work with licensed business brokers when appropriate</li><li>Conduct background checks on sellers</li></ul>'
},
{
question: 'Can I sell commercial property on BizMatch?',
answer: '<p><strong>Yes!</strong> BizMatch is a full-service marketplace for both businesses and commercial real estate.</p><p><strong>Property types you can list:</strong></p><ul><li>Office buildings and professional spaces</li><li>Retail locations and shopping centers</li><li>Warehouses and distribution facilities</li><li>Industrial properties and manufacturing plants</li><li>Mixed-use developments</li><li>Land for commercial development</li></ul><p>Our platform connects you with qualified buyers, investors, and commercial real estate professionals actively searching for investment opportunities.</p>'
},
{
question: 'What information should I include when listing my business?',
answer: '<p><strong>A complete listing should include these essential details:</strong></p><ol><li><strong>Financial Information:</strong> Asking price, annual revenue, cash flow, profit margins</li><li><strong>Business Operations:</strong> Years established, number of employees, hours of operation</li><li><strong>Description:</strong> Detailed overview of products/services, customer base, competitive advantages</li><li><strong>Industry Category:</strong> Specific business type and market segment</li><li><strong>Location Details:</strong> City, state, demographic information</li><li><strong>Assets Included:</strong> Equipment, inventory, real estate, intellectual property</li><li><strong>Visual Content:</strong> High-quality photos of business premises and operations</li><li><strong>Growth Potential:</strong> Expansion opportunities and market trends</li></ol><p><strong>Pro tip:</strong> The more detailed and transparent your listing, the more interest it will generate from serious, qualified buyers.</p>'
},
{
question: 'How long does it take to sell a business?',
answer: '<p><strong>Most businesses sell within 6 to 12 months.</strong> The timeline varies based on several factors:</p><p><strong>Factors that speed up sales:</strong></p><ul><li>Realistic pricing based on professional valuation</li><li>Complete and organized financial documentation</li><li>Strong business performance and growth trends</li><li>Attractive location and market conditions</li><li>Experienced business broker representation</li><li>Flexible seller terms and financing options</li></ul><p><strong>Timeline breakdown:</strong></p><ol><li><strong>Months 1-2:</strong> Preparation and listing creation</li><li><strong>Months 3-6:</strong> Marketing and buyer qualification</li><li><strong>Months 7-10:</strong> Negotiations and due diligence</li><li><strong>Months 11-12:</strong> Closing and transition</li></ol>'
},
{
question: 'What is business valuation and why is it important?',
answer: '<p><strong>Business valuation is the process of determining the economic worth of a company.</strong> It calculates the fair market value based on financial performance, assets, and market conditions.</p><p><strong>Why valuation matters:</strong></p><ul><li><strong>Realistic Pricing:</strong> Attracts serious buyers and prevents extended time on market</li><li><strong>Negotiation Power:</strong> Provides data-driven justification for asking price</li><li><strong>Buyer Confidence:</strong> Professional valuations increase trust and credibility</li><li><strong>Financing Approval:</strong> Banks require valuations for business acquisition loans</li></ul><p><strong>Valuation methods include:</strong></p><ol><li><strong>Asset-Based:</strong> Total value of business assets minus liabilities</li><li><strong>Income-Based:</strong> Projected future earnings and cash flow</li><li><strong>Market-Based:</strong> Comparison to similar business sales</li><li><strong>Multiple of Earnings:</strong> Revenue or profit multiplied by industry-standard factor</li></ol>'
},
{
question: 'Do I need a business broker to buy or sell a business?',
answer: '<p><strong>No, but brokers are highly recommended.</strong> You can conduct transactions directly through BizMatch, but professional brokers provide significant advantages:</p><p><strong>Benefits of using a business broker:</strong></p><ul><li><strong>Expert Valuation:</strong> Accurate pricing based on market data and analysis</li><li><strong>Marketing Expertise:</strong> Professional listing creation and buyer outreach</li><li><strong>Qualified Buyers:</strong> Pre-screening to ensure financial capability and serious interest</li><li><strong>Negotiation Skills:</strong> Experience handling complex deal structures and terms</li><li><strong>Confidentiality:</strong> Protect sensitive information during the sales process</li><li><strong>Legal Compliance:</strong> Navigate regulations, contracts, and disclosures</li><li><strong>Time Savings:</strong> Handle paperwork, communications, and coordination</li></ul><p>BizMatch connects you with licensed brokers in your area, or you can manage the transaction yourself using our secure platform and resources.</p>'
},
{
question: 'What financing options are available for buying a business?',
answer: '<p><strong>Business buyers have multiple financing options:</strong></p><ol><li><strong>SBA 7(a) Loans:</strong> Government-backed loans with favorable terms<ul><li>Down payment as low as 10%</li><li>Loan amounts up to $5 million</li><li>Competitive interest rates</li><li>Terms up to 10-25 years</li></ul></li><li><strong>Conventional Bank Financing:</strong> Traditional business acquisition loans<ul><li>Typically require 20-30% down payment</li><li>Based on creditworthiness and business performance</li></ul></li><li><strong>Seller Financing:</strong> Owner provides loan to buyer<ul><li>More flexible terms and requirements</li><li>Often combined with other financing</li><li>Typically 10-30% of purchase price</li></ul></li><li><strong>Investor Partnerships:</strong> Equity financing from partners<ul><li>Shared ownership and profits</li><li>No personal debt obligation</li></ul></li><li><strong>Personal Savings:</strong> Self-funded purchase<ul><li>No interest or loan payments</li><li>Full ownership from day one</li></ul></li></ol><p><strong>Most buyers use a combination of these options</strong> to structure the optimal deal for their situation.</p>'
}
];
constructor(
private router: Router,
private modalService: ModalService,
private searchService: SearchService,
private activatedRoute: ActivatedRoute,
public selectOptions: SelectOptionsService,
private geoService: GeoService,
public cdRef: ChangeDetectorRef,
private listingService: ListingsService,
private userService: UserService,
private aiService: AiService,
private authService: AuthService,
private filterStateService: FilterStateService,
private seoService: SeoService,
) {}
async ngOnInit() {
// Flowbite is now initialized once in AppComponent
// Set SEO meta tags for home page
this.seoService.updateMetaTags({
title: 'BizMatch - Buy & Sell Businesses and Commercial Properties',
description: 'Find profitable businesses for sale, commercial real estate, and franchise opportunities across the United States. Browse thousands of listings from verified sellers and brokers.',
keywords: 'business for sale, businesses for sale, buy business, sell business, commercial property, commercial real estate, franchise opportunities, business broker, business marketplace',
type: 'website'
});
// Add Organization schema for brand identity and FAQ schema for AEO
const organizationSchema = this.seoService.generateOrganizationSchema();
const faqSchema = this.seoService.generateFAQPageSchema(
this.faqItems.map(item => ({
question: item.question,
answer: item.answer
}))
);
// 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();
this.seoService.injectMultipleSchemas([organizationSchema, faqSchema, howToSchema, searchBoxSchema]);
// Clear all filters and sort options on initial load
this.filterStateService.resetCriteria('businessListings');
this.filterStateService.resetCriteria('commercialPropertyListings');
this.filterStateService.resetCriteria('brokerListings');
this.filterStateService.updateSortBy('businessListings', null);
this.filterStateService.updateSortBy('commercialPropertyListings', null);
this.filterStateService.updateSortBy('brokerListings', null);
// Initialize criteria for the default tab
this.criteria = this.filterStateService.getCriteria('businessListings');
this.numberOfBroker$ = this.userService.getNumberOfBroker(this.filterStateService.getCriteria('brokerListings') as UserListingCriteria);
this.numberOfCommercial$ = this.listingService.getNumberOfListings('commercialProperty');
const token = await this.authService.getToken();
this.user = map2User(token);
this.loadCities();
this.setTotalNumberOfResults();
}
changeTab(tabname: 'business' | 'commercialProperty' | 'broker') {
this.activeTabAction = tabname;
this.cityOrState = null;
const tabToListingType = {
business: 'businessListings',
commercialProperty: 'commercialPropertyListings',
broker: 'brokerListings',
};
this.criteria = this.filterStateService.getCriteria(tabToListingType[tabname] as 'businessListings' | 'commercialPropertyListings' | 'brokerListings');
this.setTotalNumberOfResults();
}
search() {
this.router.navigate([`${this.activeTabAction}Listings`]);
}
toggleMenu() {
this.isMenuOpen = !this.isMenuOpen;
}
onTypesChange(value) {
const tabToListingType = {
business: 'businessListings',
commercialProperty: 'commercialPropertyListings',
broker: 'brokerListings',
};
const listingType = tabToListingType[this.activeTabAction] as 'businessListings' | 'commercialPropertyListings' | 'brokerListings';
this.filterStateService.updateCriteria(listingType, { types: value === '' ? [] : [value] });
this.criteria = this.filterStateService.getCriteria(listingType);
this.setTotalNumberOfResults();
}
onRadiusChange(value) {
const tabToListingType = {
business: 'businessListings',
commercialProperty: 'commercialPropertyListings',
broker: 'brokerListings',
};
const listingType = tabToListingType[this.activeTabAction] as 'businessListings' | 'commercialPropertyListings' | 'brokerListings';
this.filterStateService.updateCriteria(listingType, { radius: value === 'null' ? null : parseInt(value) });
this.criteria = this.filterStateService.getCriteria(listingType);
this.setTotalNumberOfResults();
}
async openModal() {
const tabToListingType = {
business: 'businessListings',
commercialProperty: 'commercialPropertyListings',
broker: 'brokerListings',
};
const listingType = tabToListingType[this.activeTabAction] as 'businessListings' | 'commercialPropertyListings' | 'brokerListings';
const accepted = await this.modalService.showModal(this.criteria);
if (accepted) {
this.router.navigate([`${this.activeTabAction}Listings`]);
}
}
private loadCities() {
this.cities$ = concat(
of([]),
this.cityInput$.pipe(
distinctUntilChanged(),
tap(() => (this.cityLoading = true)),
switchMap(term =>
this.geoService.findCitiesAndStatesStartingWith(term).pipe(
catchError(() => of([])),
tap(() => (this.cityLoading = false)),
),
),
),
);
}
trackByFn(item: GeoResult) {
return item.id;
}
setCityOrState(cityOrState: CityAndStateResult) {
const tabToListingType = {
business: 'businessListings',
commercialProperty: 'commercialPropertyListings',
broker: 'brokerListings',
};
const listingType = tabToListingType[this.activeTabAction] as 'businessListings' | 'commercialPropertyListings' | 'brokerListings';
if (cityOrState) {
if (cityOrState.type === 'state') {
this.filterStateService.updateCriteria(listingType, { state: cityOrState.content.state_code, city: null, radius: null, searchType: 'exact' });
} else {
this.filterStateService.updateCriteria(listingType, {
city: cityOrState.content as GeoResult,
state: cityOrState.content.state,
searchType: 'radius',
radius: 20,
});
}
} else {
this.filterStateService.updateCriteria(listingType, { state: null, city: null, radius: null, searchType: 'exact' });
}
this.criteria = this.filterStateService.getCriteria(listingType);
this.setTotalNumberOfResults();
}
getTypes() {
if (this.criteria.criteriaType === 'businessListings') {
return this.selectOptions.typesOfBusiness;
} else if (this.criteria.criteriaType === 'commercialPropertyListings') {
return this.selectOptions.typesOfCommercialProperty;
} else {
return this.selectOptions.customerSubTypes;
}
}
getPlaceholderLabel() {
if (this.criteria.criteriaType === 'businessListings') {
return 'Business Type';
} else if (this.criteria.criteriaType === 'commercialPropertyListings') {
return 'Property Type';
} else {
return 'Professional Type';
}
}
setTotalNumberOfResults() {
if (this.criteria) {
console.log(`Getting total number of results for ${this.criteria.criteriaType}`);
const tabToListingType = {
business: 'businessListings',
commercialProperty: 'commercialPropertyListings',
broker: 'brokerListings',
};
const listingType = tabToListingType[this.activeTabAction] as 'businessListings' | 'commercialPropertyListings' | 'brokerListings';
if (this.criteria.criteriaType === 'businessListings' || this.criteria.criteriaType === 'commercialPropertyListings') {
this.numberOfResults$ = this.listingService.getNumberOfListings(this.criteria.criteriaType === 'businessListings' ? 'business' : 'commercialProperty');
} else if (this.criteria.criteriaType === 'brokerListings') {
this.numberOfResults$ = this.userService.getNumberOfBroker(this.filterStateService.getCriteria('brokerListings') as UserListingCriteria);
} else {
this.numberOfResults$ = of();
}
}
}
ngOnDestroy(): void {
clearTimeout(this.typingInterval);
}
}