arch(sprint1): move UI env reads behind runtime facade
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import { Component, ChangeDetectionStrategy, inject } from '@angular/core';
|
||||
import { Location } from '@angular/common';
|
||||
import { environment } from '../../../environments/environment';
|
||||
import { TranslateService } from '../../i18n/translate.service';
|
||||
import { UiRuntimeFacade } from '../../facades/runtime/ui-runtime.facade';
|
||||
|
||||
@Component({
|
||||
selector: 'app-back-button',
|
||||
@@ -62,9 +62,13 @@ import { TranslateService } from '../../i18n/translate.service';
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
})
|
||||
export class BackButtonComponent {
|
||||
isnovo = environment.theme === 'novo';
|
||||
private readonly uiRuntime = inject(UiRuntimeFacade);
|
||||
i18n = inject(TranslateService);
|
||||
|
||||
get isnovo(): boolean {
|
||||
return this.uiRuntime.isNovo();
|
||||
}
|
||||
|
||||
constructor(private location: Location) {}
|
||||
|
||||
goBack(): void {
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { Component, ChangeDetectionStrategy } from '@angular/core';
|
||||
import { RouterLink } from '@angular/router';
|
||||
import { environment } from '../../../environments/environment';
|
||||
import { LangRoutePipe } from '../../pipes/lang-route.pipe';
|
||||
import { TranslatePipe } from '../../i18n/translate.pipe';
|
||||
import { LogoComponent } from '../logo/logo.component';
|
||||
import { UiRuntimeFacade } from '../../facades/runtime/ui-runtime.facade';
|
||||
|
||||
@Component({
|
||||
selector: 'app-footer',
|
||||
@@ -13,9 +13,23 @@ import { LogoComponent } from '../logo/logo.component';
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
})
|
||||
export class FooterComponent {
|
||||
constructor(private readonly uiRuntime: UiRuntimeFacade) {}
|
||||
|
||||
currentYear = new Date().getFullYear();
|
||||
brandName = environment.brandName;
|
||||
contactEmail = environment.contactEmail;
|
||||
isnovo = environment.theme === 'novo';
|
||||
islavero = environment.theme === 'lavero';
|
||||
|
||||
get brandName(): string {
|
||||
return this.uiRuntime.brandName();
|
||||
}
|
||||
|
||||
get contactEmail(): string {
|
||||
return this.uiRuntime.contactEmail();
|
||||
}
|
||||
|
||||
get isnovo(): boolean {
|
||||
return this.uiRuntime.isNovo();
|
||||
}
|
||||
|
||||
get islavero(): boolean {
|
||||
return this.uiRuntime.isLavero();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,12 +2,12 @@ import { Component, ChangeDetectionStrategy, Renderer2, inject, DOCUMENT } from
|
||||
import { Router, RouterLink, RouterLinkActive } from '@angular/router';
|
||||
import { CartService } from '../../services/cart.service';
|
||||
import { LanguageService } from '../../services/language.service';
|
||||
import { environment } from '../../../environments/environment';
|
||||
import { LogoComponent } from '../logo/logo.component';
|
||||
import { LanguageSelectorComponent } from '../language-selector/language-selector.component';
|
||||
import { RegionSelectorComponent } from '../region-selector/region-selector.component';
|
||||
import { LangRoutePipe } from '../../pipes/lang-route.pipe';
|
||||
import { TranslatePipe } from '../../i18n/translate.pipe';
|
||||
import { UiRuntimeFacade } from '../../facades/runtime/ui-runtime.facade';
|
||||
|
||||
@Component({
|
||||
selector: 'app-header',
|
||||
@@ -20,19 +20,29 @@ export class HeaderComponent {
|
||||
cartItemCount;
|
||||
cartTotal;
|
||||
menuOpen = false;
|
||||
brandName = environment.brandFullName;
|
||||
logo = environment.logo;
|
||||
isnovo = environment.theme === 'novo';
|
||||
|
||||
private renderer = inject(Renderer2);
|
||||
private document = inject(DOCUMENT);
|
||||
private langService = inject(LanguageService);
|
||||
private uiRuntime = inject(UiRuntimeFacade);
|
||||
|
||||
constructor(private cartService: CartService, private router: Router) {
|
||||
this.cartItemCount = this.cartService.itemCount;
|
||||
this.cartTotal = this.cartService.totalPrice;
|
||||
}
|
||||
|
||||
get brandName(): string {
|
||||
return this.uiRuntime.brandFullName();
|
||||
}
|
||||
|
||||
get logo(): string {
|
||||
return this.uiRuntime.logoUrl();
|
||||
}
|
||||
|
||||
get isnovo(): boolean {
|
||||
return this.uiRuntime.isNovo();
|
||||
}
|
||||
|
||||
get homeUrl(): string {
|
||||
return `/${this.langService.currentLanguage()}`;
|
||||
}
|
||||
|
||||
@@ -6,11 +6,11 @@ import { ButtonModule } from 'primeng/button';
|
||||
import { TagModule } from 'primeng/tag';
|
||||
import { ApiService, CartService } from '../../services';
|
||||
import { Item } from '../../models';
|
||||
import { environment } from '../../../environments/environment';
|
||||
import { getDiscountedPrice, getMainImage, getBadgeClass, getTranslatedField } from '../../utils/item.utils';
|
||||
import { LanguageService } from '../../services/language.service';
|
||||
import { LangRoutePipe } from '../../pipes/lang-route.pipe';
|
||||
import { TranslatePipe } from '../../i18n/translate.pipe';
|
||||
import { UiRuntimeFacade } from '../../facades/runtime/ui-runtime.facade';
|
||||
|
||||
@Component({
|
||||
selector: 'app-items-carousel',
|
||||
@@ -22,7 +22,7 @@ import { TranslatePipe } from '../../i18n/translate.pipe';
|
||||
export class ItemsCarouselComponent implements OnInit {
|
||||
products = signal<Item[]>([]);
|
||||
loading = signal(true);
|
||||
isnovo = environment.theme === 'novo';
|
||||
private readonly uiRuntime = inject(UiRuntimeFacade);
|
||||
|
||||
responsiveOptions: { breakpoint: string; numVisible: number; numScroll: number }[] | undefined;
|
||||
|
||||
@@ -102,6 +102,7 @@ export class ItemsCarouselComponent implements OnInit {
|
||||
readonly getBadgeClass = getBadgeClass;
|
||||
|
||||
private langService = inject(LanguageService);
|
||||
get isnovo(): boolean { return this.uiRuntime.isNovo(); }
|
||||
itemName(product: Item): string { return getTranslatedField(product, 'name', this.langService.currentLanguage()); }
|
||||
|
||||
addToCart(event: Event, item: Item): void {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Component, ChangeDetectionStrategy } from '@angular/core';
|
||||
import { environment } from '../../../environments/environment';
|
||||
import { UiRuntimeFacade } from '../../facades/runtime/ui-runtime.facade';
|
||||
|
||||
@Component({
|
||||
selector: 'app-logo',
|
||||
@@ -17,6 +17,13 @@ import { environment } from '../../../environments/environment';
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
})
|
||||
export class LogoComponent {
|
||||
brandName = environment.brandName;
|
||||
logoPath = (environment as any).logo ?? `/assets/images/${environment.theme}-logo.svg`;
|
||||
constructor(private readonly uiRuntime: UiRuntimeFacade) {}
|
||||
|
||||
get brandName(): string {
|
||||
return this.uiRuntime.brandName();
|
||||
}
|
||||
|
||||
get logoPath(): string {
|
||||
return this.uiRuntime.logoUrl();
|
||||
}
|
||||
}
|
||||
|
||||
65
src/app/facades/runtime/ui-runtime.facade.ts
Normal file
65
src/app/facades/runtime/ui-runtime.facade.ts
Normal file
@@ -0,0 +1,65 @@
|
||||
import { Injectable, signal } from '@angular/core';
|
||||
import { take } from 'rxjs/operators';
|
||||
import { ConfigService } from '../../core/config/config.service';
|
||||
import { environment } from '../../../environments/environment';
|
||||
|
||||
interface UiRuntimeState {
|
||||
brandName: string;
|
||||
brandFullName: string;
|
||||
logoUrl: string;
|
||||
contactEmail: string;
|
||||
themeId: string;
|
||||
}
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class UiRuntimeFacade {
|
||||
private readonly state = signal<UiRuntimeState>({
|
||||
brandName: environment.brandName,
|
||||
brandFullName: environment.brandFullName,
|
||||
logoUrl: environment.logo,
|
||||
contactEmail: environment.contactEmail,
|
||||
themeId: environment.theme
|
||||
});
|
||||
|
||||
constructor(private readonly configService: ConfigService) {
|
||||
this.configService.loadBootstrap().pipe(take(1)).subscribe({
|
||||
next: (bootstrap) => {
|
||||
this.state.set({
|
||||
brandName: bootstrap.branding.brandName,
|
||||
brandFullName: bootstrap.branding.brandName,
|
||||
logoUrl: bootstrap.branding.logoUrl,
|
||||
contactEmail: bootstrap.branding.supportEmail ?? environment.contactEmail,
|
||||
themeId: bootstrap.theme.themeId
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
brandName(): string {
|
||||
return this.state().brandName;
|
||||
}
|
||||
|
||||
brandFullName(): string {
|
||||
return this.state().brandFullName;
|
||||
}
|
||||
|
||||
logoUrl(): string {
|
||||
return this.state().logoUrl;
|
||||
}
|
||||
|
||||
contactEmail(): string {
|
||||
return this.state().contactEmail;
|
||||
}
|
||||
|
||||
themeId(): string {
|
||||
return this.state().themeId;
|
||||
}
|
||||
|
||||
isNovo(): boolean {
|
||||
return this.themeId().includes('novo');
|
||||
}
|
||||
|
||||
isLavero(): boolean {
|
||||
return this.themeId().includes('lavero');
|
||||
}
|
||||
}
|
||||
@@ -10,12 +10,12 @@ import { catchError, exhaustMap, take, timeout } from 'rxjs/operators';
|
||||
import { DeliverySelectorComponent } from '../../components/delivery-selector/delivery-selector.component';
|
||||
import { EmptyCartIconComponent } from '../../components/empty-cart-icon/empty-cart-icon.component';
|
||||
import { TelegramLoginComponent } from '../../components/telegram-login/telegram-login.component';
|
||||
import { environment } from '../../../environments/environment';
|
||||
import { getDiscountedPrice, getMainImage, trackByItemId, getBadgeClass, getTranslatedField } from '../../utils/item.utils';
|
||||
import { LangRoutePipe } from '../../pipes/lang-route.pipe';
|
||||
import { TranslatePipe } from '../../i18n/translate.pipe';
|
||||
import { TranslateService } from '../../i18n/translate.service';
|
||||
import { PAYMENT_POLL_INTERVAL_MS, PAYMENT_MAX_CHECKS, PAYMENT_TIMEOUT_CLOSE_MS, LINK_COPIED_DURATION_MS } from '../../config/constants';
|
||||
import { UiRuntimeFacade } from '../../facades/runtime/ui-runtime.facade';
|
||||
|
||||
type PaymentMethod = 'qr' | 'card';
|
||||
|
||||
@@ -35,11 +35,15 @@ export class CartComponent implements OnDestroy {
|
||||
hasDeliveryPrice;
|
||||
allRequiredDeliveriesSelected;
|
||||
termsAccepted = false;
|
||||
isnovo = environment.theme === 'novo';
|
||||
private readonly uiRuntime = inject(UiRuntimeFacade);
|
||||
|
||||
private i18n = inject(TranslateService);
|
||||
private authService = inject(AuthService);
|
||||
|
||||
get isnovo(): boolean {
|
||||
return this.uiRuntime.isNovo();
|
||||
}
|
||||
|
||||
isAuthenticated = this.authService.isAuthenticated;
|
||||
|
||||
// Swipe state
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
import { Router, RouterLink } from '@angular/router';
|
||||
import { ApiService, LanguageService } from '../../services';
|
||||
import { Category } from '../../models';
|
||||
import { environment } from '../../../environments/environment';
|
||||
import { getTranslatedCategoryName } from '../../utils/item.utils';
|
||||
import { ItemsCarouselComponent } from '../../components/items-carousel/items-carousel.component';
|
||||
import { LangRoutePipe } from '../../pipes/lang-route.pipe';
|
||||
import { TranslatePipe } from '../../i18n/translate.pipe';
|
||||
import { UiRuntimeFacade } from '../../facades/runtime/ui-runtime.facade';
|
||||
|
||||
@Component({
|
||||
selector: 'app-home',
|
||||
@@ -16,8 +16,13 @@ import { TranslatePipe } from '../../i18n/translate.pipe';
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
})
|
||||
export class HomeComponent implements OnInit, OnDestroy {
|
||||
brandName = environment.brandFullName;
|
||||
isnovo = environment.theme === 'novo';
|
||||
constructor(
|
||||
private apiService: ApiService,
|
||||
private router: Router,
|
||||
private langService: LanguageService,
|
||||
private readonly uiRuntime: UiRuntimeFacade
|
||||
) {}
|
||||
|
||||
categories = signal<Category[]>([]);
|
||||
wideCategories = signal<Set<number>>(new Set());
|
||||
loading = signal(true);
|
||||
@@ -53,7 +58,13 @@ export class HomeComponent implements OnInit, OnDestroy {
|
||||
return cache;
|
||||
});
|
||||
|
||||
constructor(private apiService: ApiService, private router: Router, private langService: LanguageService) {}
|
||||
get brandName(): string {
|
||||
return this.uiRuntime.brandFullName();
|
||||
}
|
||||
|
||||
get isnovo(): boolean {
|
||||
return this.uiRuntime.isNovo();
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.loadCategories();
|
||||
|
||||
@@ -7,12 +7,12 @@ import { AuthService } from '../../services/auth.service';
|
||||
import { Item, ItemDetail, DescriptionField, DeliveryOption } from '../../models';
|
||||
import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { environment } from '../../../environments/environment';
|
||||
import { SecurityContext } from '@angular/core';
|
||||
import { getStockStatus, getBadgeClass, getTranslatedField } from '../../utils/item.utils';
|
||||
import { LangRoutePipe } from '../../pipes/lang-route.pipe';
|
||||
import { TranslatePipe } from '../../i18n/translate.pipe';
|
||||
import { TranslateService } from '../../i18n/translate.service';
|
||||
import { UiRuntimeFacade } from '../../facades/runtime/ui-runtime.facade';
|
||||
|
||||
@Component({
|
||||
selector: 'app-item-detail',
|
||||
@@ -26,7 +26,11 @@ export class ItemDetailComponent implements OnInit, OnDestroy {
|
||||
selectedPhotoIndex = signal(0);
|
||||
loading = signal(true);
|
||||
error = signal<string | null>(null);
|
||||
isnovo = environment.theme === 'novo';
|
||||
private readonly uiRuntime = inject(UiRuntimeFacade);
|
||||
|
||||
get isnovo(): boolean {
|
||||
return this.uiRuntime.isNovo();
|
||||
}
|
||||
|
||||
// Variant selection
|
||||
selectedColour = signal<string | null>(null);
|
||||
|
||||
Reference in New Issue
Block a user