fix local bootstrap startup and catalog widget UX
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
.product-card {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
min-width: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
@@ -19,12 +19,13 @@ export class ApiConfigService {
|
||||
|
||||
if (this.tenantResolver.isLocalhost() && localhostUrl) {
|
||||
url = localhostUrl;
|
||||
} else if (bootstrapUrl) {
|
||||
url = bootstrapUrl;
|
||||
} else if (tenantMap?.[tenantKey]) {
|
||||
url = tenantMap[tenantKey];
|
||||
} else if (apiTemplate) {
|
||||
url = apiTemplate.replace('{tenant}', tenantKey);
|
||||
} else if (bootstrapUrl) {
|
||||
// Bootstrap API override is opt-in and only for absolute URLs.
|
||||
url = bootstrapUrl;
|
||||
}
|
||||
|
||||
return this.normalizeBaseUrl(url);
|
||||
@@ -58,24 +59,33 @@ export class ApiConfigService {
|
||||
}
|
||||
|
||||
private resolveBootstrapApiBaseUrl(): string | null {
|
||||
const allowBootstrapApiOverride = (environment as any).allowBootstrapApiOverride === true;
|
||||
if (!allowBootstrapApiOverride) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const bootstrap = this.configService.getBootstrapSnapshot() as any;
|
||||
if (!bootstrap) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const endpointBase = bootstrap?.apiEndpoints?.website?.baseUrl;
|
||||
if (typeof endpointBase === 'string' && endpointBase.trim().length > 0) {
|
||||
if (typeof endpointBase === 'string' && this.isAbsoluteHttpUrl(endpointBase)) {
|
||||
return endpointBase;
|
||||
}
|
||||
|
||||
const tenantBase = bootstrap?.tenant?.apiBaseUrl;
|
||||
if (typeof tenantBase === 'string' && tenantBase.trim().length > 0) {
|
||||
if (typeof tenantBase === 'string' && this.isAbsoluteHttpUrl(tenantBase)) {
|
||||
return tenantBase;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private isAbsoluteHttpUrl(url: string): boolean {
|
||||
return /^https?:\/\//i.test(url.trim());
|
||||
}
|
||||
|
||||
private normalizeBaseUrl(url: string): string {
|
||||
if (!url || url === '/') {
|
||||
return '/';
|
||||
|
||||
@@ -5,11 +5,25 @@ export type RuntimeProviderMode = 'mock' | 'api' | 'remote-config';
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class RuntimeProviderStrategyService {
|
||||
private isLocalhost(): boolean {
|
||||
if (typeof window === 'undefined') {
|
||||
return false;
|
||||
}
|
||||
|
||||
const host = window.location.hostname.toLowerCase();
|
||||
return host === 'localhost' || host === '127.0.0.1' || host === '::1';
|
||||
}
|
||||
|
||||
getBootstrapProviderMode(): RuntimeProviderMode {
|
||||
if (environment.useMockData) {
|
||||
return 'mock';
|
||||
}
|
||||
|
||||
// Local dev must use mocked bootstrap while API data can stay production-based.
|
||||
if ((environment as any).useMockBootstrapOnLocal === true && this.isLocalhost()) {
|
||||
return 'mock';
|
||||
}
|
||||
|
||||
return 'api';
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,14 @@
|
||||
|
||||
.catalog-product-shell {
|
||||
min-width: 0;
|
||||
display: flex;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.catalog-product-shell app-product-card {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
|
||||
import { ChangeDetectionStrategy, Component, Input, inject } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
import { SectionConfig } from '../../shared/models/config';
|
||||
import { CatalogCategoryGridComponent } from '../../features/website/catalog/components/category-grid/category-grid.component';
|
||||
import { CategoriesWidgetData } from '../contracts/widget-data.contract';
|
||||
import { Category } from '../../core/categories/models/category-domain.model';
|
||||
import { LanguageService } from '../../services/language.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-categories-widget',
|
||||
@@ -16,7 +19,10 @@ import { CategoriesWidgetData } from '../contracts/widget-data.contract';
|
||||
}
|
||||
|
||||
@if (widgetData.categories.length) {
|
||||
<app-catalog-category-grid [categories]="widgetData.categories" />
|
||||
<app-catalog-category-grid
|
||||
[categories]="widgetData.categories"
|
||||
(categorySelected)="onCategorySelected($event)"
|
||||
/>
|
||||
} @else if (widgetData.emptyMessage) {
|
||||
<p class="categories-widget__empty">{{ widgetData.emptyMessage }}</p>
|
||||
}
|
||||
@@ -32,6 +38,13 @@ import { CategoriesWidgetData } from '../contracts/widget-data.contract';
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
})
|
||||
export class CategoriesWidgetComponent {
|
||||
private readonly router = inject(Router);
|
||||
private readonly languageService = inject(LanguageService);
|
||||
|
||||
@Input() section: SectionConfig | null = null;
|
||||
@Input() data: CategoriesWidgetData | null = null;
|
||||
|
||||
onCategorySelected(category: Category): void {
|
||||
this.router.navigate([`/${this.languageService.currentLanguage()}/catalog`, category.id]);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user