Files
marketplaces/src/app/app.ts

138 lines
5.3 KiB
TypeScript
Raw Normal View History

2026-01-18 18:57:06 +04:00
import { Component, OnInit, signal, ApplicationRef, inject, DestroyRef, ChangeDetectionStrategy } from '@angular/core';
2026-02-14 01:28:08 +04:00
import { Router, RouterOutlet, NavigationEnd } from '@angular/router';
2026-01-18 18:57:06 +04:00
import { Title } from '@angular/platform-browser';
import { HeaderComponent } from './components/header/header.component';
import { FooterComponent } from './components/footer/footer.component';
2026-02-14 01:28:08 +04:00
import { BackButtonComponent } from './components/back-button/back-button.component';
2026-02-19 01:23:25 +04:00
import { interval, concat } from 'rxjs';
2026-02-14 01:28:08 +04:00
import { filter, first } from 'rxjs/operators';
2026-02-19 01:23:25 +04:00
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
2026-01-18 18:57:06 +04:00
import { SwUpdate } from '@angular/service-worker';
2026-02-26 23:09:20 +04:00
import { TranslatePipe } from './i18n/translate.pipe';
import { TranslateService } from './i18n/translate.service';
import { PlatformRuntimeService } from './core/runtime/platform-runtime.service';
2026-07-05 00:38:21 +04:00
import { UiRuntimeFacade } from './facades/runtime/ui-runtime.facade';
import { ApiHealthService } from './services/api-health.service';
chore(cleanup): Phase 1 - remove dead code, fix orphaned SeoService wiring Ran knip to find unused exports/dependencies (deps already clean, no unused packages/files found). Removed genuinely dead code (verified zero references anywhere, including templates): - 4 unused constants in config/constants.ts (scroll/pagination/search thresholds never consumed) - isAdminRole(), toSearchResult(), createInitialSearchState(), getTranslatedCategoryName() - unused utility functions - DEFAULT_EDITOR_HEADER_CONFIG - unused constant - TelegramService - entire file deleted; cart.component.ts/ cart.service.ts already implement the same window.Telegram.WebApp access directly, this was an unused duplicate Real bug fix found during the sweep: SeoService has providedIn:'root' with a live effect() meant to sync <title>/OG/canonical tags to tenant bootstrap config, but nothing in the app ever injected it, so Angular never instantiated it and the effect never ran - the SEO sync a prior sprint reported as "done and verified" was actually dead on arrival. Fixed by injecting SeoService in the root App component. Left alone: ~125 knip-flagged "unused exported types" - overwhelmingly config/schema interfaces for the widget/theme/admin domain models, high false-positive rate for this kind of interface-heavy Angular app, deleting blind risks breaking structural type contracts. Also left locally-used-but-over-exported helpers (toCssColor/toBackendColor, HTML_EDITOR_TOOLBAR*, HISTORY_LIMIT, DEFAULT_CATALOG_PAGE_SIZE) - real code, not dead, just exported wider than needed. tsc --noEmit and ng build --configuration=production both clean (only pre-existing bundle-budget warning, unrelated). Files changed: src/app/app.ts, src/app/config/constants.ts, src/app/core/auth/models/permission.model.ts, src/app/core/products/models/catalog-experience.model.ts, src/app/core/search/models/search-state.model.ts, src/app/features/project-editor/models/project-editor.model.ts, src/app/services/index.ts, src/app/utils/item.utils.ts, src/app/services/telegram.service.ts (deleted)
2026-07-26 15:39:54 +04:00
import { SeoService } from './services/seo.service';
import { FloatingNotificationsComponent } from './features/website/user-experience/components/floating-notifications/floating-notifications.component';
import { AdminAuthService, AuthService } from '@marketplaces/auth';
import { TelegramLoginComponent } from './components/telegram-login/telegram-login.component';
2026-01-18 18:57:06 +04:00
@Component({
selector: 'app-root',
imports: [RouterOutlet, HeaderComponent, FooterComponent, BackButtonComponent, TranslatePipe, FloatingNotificationsComponent, TelegramLoginComponent],
2026-01-18 18:57:06 +04:00
templateUrl: './app.html',
styleUrl: './app.scss',
changeDetection: ChangeDetectionStrategy.OnPush
2026-01-18 18:57:06 +04:00
})
2026-02-19 01:23:25 +04:00
export class App implements OnInit {
2026-07-05 00:38:21 +04:00
protected title = '';
2026-02-14 01:28:08 +04:00
isHomePage = signal(true);
isAdminRoute = signal(false);
2026-02-19 01:23:25 +04:00
checkingServer = signal(true);
serverAvailable = signal(false);
2026-01-18 18:57:06 +04:00
2026-02-19 01:23:25 +04:00
private destroyRef = inject(DestroyRef);
private titleService = inject(Title);
private swUpdate = inject(SwUpdate);
private appRef = inject(ApplicationRef);
private router = inject(Router);
2026-02-26 23:09:20 +04:00
private i18n = inject(TranslateService);
private platformRuntime = inject(PlatformRuntimeService);
2026-07-05 00:38:21 +04:00
private uiRuntime = inject(UiRuntimeFacade);
private apiHealth = inject(ApiHealthService);
chore(cleanup): Phase 1 - remove dead code, fix orphaned SeoService wiring Ran knip to find unused exports/dependencies (deps already clean, no unused packages/files found). Removed genuinely dead code (verified zero references anywhere, including templates): - 4 unused constants in config/constants.ts (scroll/pagination/search thresholds never consumed) - isAdminRole(), toSearchResult(), createInitialSearchState(), getTranslatedCategoryName() - unused utility functions - DEFAULT_EDITOR_HEADER_CONFIG - unused constant - TelegramService - entire file deleted; cart.component.ts/ cart.service.ts already implement the same window.Telegram.WebApp access directly, this was an unused duplicate Real bug fix found during the sweep: SeoService has providedIn:'root' with a live effect() meant to sync <title>/OG/canonical tags to tenant bootstrap config, but nothing in the app ever injected it, so Angular never instantiated it and the effect never ran - the SEO sync a prior sprint reported as "done and verified" was actually dead on arrival. Fixed by injecting SeoService in the root App component. Left alone: ~125 knip-flagged "unused exported types" - overwhelmingly config/schema interfaces for the widget/theme/admin domain models, high false-positive rate for this kind of interface-heavy Angular app, deleting blind risks breaking structural type contracts. Also left locally-used-but-over-exported helpers (toCssColor/toBackendColor, HTML_EDITOR_TOOLBAR*, HISTORY_LIMIT, DEFAULT_CATALOG_PAGE_SIZE) - real code, not dead, just exported wider than needed. tsc --noEmit and ng build --configuration=production both clean (only pre-existing bundle-budget warning, unrelated). Files changed: src/app/app.ts, src/app/config/constants.ts, src/app/core/auth/models/permission.model.ts, src/app/core/products/models/catalog-experience.model.ts, src/app/core/search/models/search-state.model.ts, src/app/features/project-editor/models/project-editor.model.ts, src/app/services/index.ts, src/app/utils/item.utils.ts, src/app/services/telegram.service.ts (deleted)
2026-07-26 15:39:54 +04:00
private seoService = inject(SeoService);
private authService = inject(AuthService);
private adminAuthService = inject(AdminAuthService);
2026-01-18 18:57:06 +04:00
ngOnInit(): void {
this.platformRuntime.initialize();
2026-07-05 00:38:21 +04:00
this.title = this.uiRuntime.marketplaceName();
this.titleService.setTitle(`${this.uiRuntime.marketplaceDisplayName()} - ${this.i18n.t('app.pageTitle')}`);
2026-01-18 18:57:06 +04:00
this.checkServerHealth();
this.setupAutoUpdates();
this.openLoginDialogsFromTestModeQueryParams();
2026-02-14 01:28:08 +04:00
// Track route changes to show/hide back button
2026-02-19 01:23:25 +04:00
this.router.events
.pipe(
filter(event => event instanceof NavigationEnd),
takeUntilDestroyed(this.destroyRef)
)
2026-02-14 01:28:08 +04:00
.subscribe((event) => {
2026-02-26 21:54:21 +04:00
const navEnd = event as NavigationEnd;
const url = navEnd.urlAfterRedirects || navEnd.url;
2026-02-26 22:23:08 +04:00
// Home pages: /ru, /en, /hy (with or without trailing slash)
this.isHomePage.set(/^\/[a-z]{2}\/?$/.test(url) || url === '/' || url === '');
// Admin backoffice and the Marketplace Builder (/edit) own their own
// shells (AdminLayoutComponent / ProjectEditorPageComponent's sidebar) -
// the storefront header/back-button/footer never render on either.
this.isAdminRoute.set(/^\/[a-z]{2}\/(backoffice|edit)(\/|$|\?)/.test(url));
2026-02-14 01:28:08 +04:00
});
2026-01-18 18:57:06 +04:00
}
2026-02-19 01:23:25 +04:00
private checkServerHealth(): void {
this.checkingServer.set(true);
this.apiHealth.ping()
2026-02-19 01:23:25 +04:00
.pipe(takeUntilDestroyed(this.destroyRef))
.subscribe({
next: () => {
this.serverAvailable.set(true);
this.checkingServer.set(false);
},
error: () => {
this.serverAvailable.set(false);
this.checkingServer.set(false);
}
});
}
retryConnection(): void {
this.checkServerHealth();
2026-01-18 18:57:06 +04:00
}
/**
* ?login=true / ?adminLogin=true open the respective login dialog for
* manual testing. ?devBypassAdmin=true skips the QR flow entirely and
* activates a fake local admin session - dev builds only, no effect (and
* no-ops server-side too, see AdminAuthService.devBypassLogin) in
* production. No effect when the params are absent.
*/
private openLoginDialogsFromTestModeQueryParams(): void {
if (typeof window === 'undefined') {
return;
}
const params = new URLSearchParams(window.location.search);
if (params.get('login') === 'true') {
this.authService.requestLogin();
}
if (params.get('adminLogin') === 'true') {
this.adminAuthService.requestLogin();
}
if (params.get('devBypassAdmin') === 'true') {
this.adminAuthService.devBypassLogin();
}
}
2026-02-19 01:23:25 +04:00
private setupAutoUpdates(): void {
2026-01-18 18:57:06 +04:00
if (!this.swUpdate.isEnabled) {
return;
}
const appIsStable$ = this.appRef.isStable.pipe(first(isStable => isStable === true));
const every6Hours$ = interval(6 * 60 * 60 * 1000);
const checkInterval$ = concat(appIsStable$, every6Hours$);
2026-02-19 01:23:25 +04:00
checkInterval$
.pipe(takeUntilDestroyed(this.destroyRef))
.subscribe(async () => {
try {
await this.swUpdate.checkForUpdate();
} catch (err) {
console.error('Update check failed:', err);
}
});
2026-01-18 18:57:06 +04:00
}
}