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)
This commit is contained in:
@@ -14,6 +14,7 @@ import { TranslateService } from './i18n/translate.service';
|
|||||||
import { PlatformRuntimeService } from './core/runtime/platform-runtime.service';
|
import { PlatformRuntimeService } from './core/runtime/platform-runtime.service';
|
||||||
import { UiRuntimeFacade } from './facades/runtime/ui-runtime.facade';
|
import { UiRuntimeFacade } from './facades/runtime/ui-runtime.facade';
|
||||||
import { ApiHealthService } from './services/api-health.service';
|
import { ApiHealthService } from './services/api-health.service';
|
||||||
|
import { SeoService } from './services/seo.service';
|
||||||
import { FloatingNotificationsComponent } from './features/website/user-experience/components/floating-notifications/floating-notifications.component';
|
import { FloatingNotificationsComponent } from './features/website/user-experience/components/floating-notifications/floating-notifications.component';
|
||||||
import { AdminAuthService } from './core/admin-auth/admin-auth.service';
|
import { AdminAuthService } from './core/admin-auth/admin-auth.service';
|
||||||
import { AuthService } from './services/auth.service';
|
import { AuthService } from './services/auth.service';
|
||||||
@@ -42,6 +43,7 @@ export class App implements OnInit {
|
|||||||
private platformRuntime = inject(PlatformRuntimeService);
|
private platformRuntime = inject(PlatformRuntimeService);
|
||||||
private uiRuntime = inject(UiRuntimeFacade);
|
private uiRuntime = inject(UiRuntimeFacade);
|
||||||
private apiHealth = inject(ApiHealthService);
|
private apiHealth = inject(ApiHealthService);
|
||||||
|
private seoService = inject(SeoService);
|
||||||
private authService = inject(AuthService);
|
private authService = inject(AuthService);
|
||||||
private adminAuthService = inject(AdminAuthService);
|
private adminAuthService = inject(AdminAuthService);
|
||||||
|
|
||||||
|
|||||||
@@ -4,14 +4,6 @@ export const PAYMENT_MIN_POLL_SECONDS = 60;
|
|||||||
export const PAYMENT_TIMEOUT_CLOSE_MS = 3000;
|
export const PAYMENT_TIMEOUT_CLOSE_MS = 3000;
|
||||||
export const LINK_COPIED_DURATION_MS = 2000;
|
export const LINK_COPIED_DURATION_MS = 2000;
|
||||||
|
|
||||||
// Infinite scroll
|
|
||||||
export const SCROLL_THRESHOLD_PX = 1200;
|
|
||||||
export const SCROLL_DEBOUNCE_MS = 100;
|
|
||||||
export const ITEMS_PER_PAGE = 50;
|
|
||||||
|
|
||||||
// Search
|
|
||||||
export const SEARCH_DEBOUNCE_MS = 300;
|
|
||||||
|
|
||||||
// Cache
|
// Cache
|
||||||
export const CACHE_DURATION_MS = 5 * 60 * 1000;
|
export const CACHE_DURATION_MS = 5 * 60 * 1000;
|
||||||
export const CATEGORY_CACHE_DURATION_MS = 2 * 60 * 1000;
|
export const CATEGORY_CACHE_DURATION_MS = 2 * 60 * 1000;
|
||||||
|
|||||||
@@ -28,7 +28,3 @@ export const ROLE_PERMISSIONS: Readonly<Record<AdminRole, readonly Permission[]>
|
|||||||
Support: ['backoffice.read'],
|
Support: ['backoffice.read'],
|
||||||
ReadOnly: ['backoffice.read', 'builder.read']
|
ReadOnly: ['backoffice.read', 'builder.read']
|
||||||
};
|
};
|
||||||
|
|
||||||
export function isAdminRole(value: unknown): value is AdminRole {
|
|
||||||
return typeof value === 'string' && value in ROLE_PERMISSIONS;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -67,20 +67,3 @@ export interface SearchResult {
|
|||||||
pageSize: number;
|
pageSize: number;
|
||||||
summary: string;
|
summary: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function toSearchResult(result: ProductListResult, criteria: SearchCriteria): SearchResult {
|
|
||||||
const pageSize = Math.max(1, criteria.pageSize ?? result.count ?? 24);
|
|
||||||
const page = Math.max(1, criteria.page ?? Math.floor((result.skip ?? 0) / pageSize) + 1);
|
|
||||||
const keyword = (criteria.keyword ?? '').trim();
|
|
||||||
|
|
||||||
return {
|
|
||||||
criteria,
|
|
||||||
items: result.items,
|
|
||||||
total: result.total,
|
|
||||||
page,
|
|
||||||
pageSize,
|
|
||||||
summary: keyword.length > 0
|
|
||||||
? `Results for "${keyword}" (${result.total})`
|
|
||||||
: `Products found: ${result.total}`
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -10,18 +10,3 @@ export interface SearchState {
|
|||||||
pageSize: number;
|
pageSize: number;
|
||||||
filters: SearchFilterState;
|
filters: SearchFilterState;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createInitialSearchState(pageSize = 24): SearchState {
|
|
||||||
return {
|
|
||||||
text: '',
|
|
||||||
sort: 'relevance',
|
|
||||||
layout: 'grid',
|
|
||||||
page: 1,
|
|
||||||
pageSize,
|
|
||||||
filters: {
|
|
||||||
values: {},
|
|
||||||
ranges: {},
|
|
||||||
toggles: {},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -53,17 +53,3 @@ export interface ProjectEditorWidgetPreset {
|
|||||||
type: string;
|
type: string;
|
||||||
label: string;
|
label: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const DEFAULT_EDITOR_HEADER_CONFIG: Required<HeaderConfig> = {
|
|
||||||
showLogo: true,
|
|
||||||
showSearch: true,
|
|
||||||
showCategories: true,
|
|
||||||
showLanguages: true,
|
|
||||||
showCart: true,
|
|
||||||
showProfile: false,
|
|
||||||
showWishlist: true,
|
|
||||||
showCompare: true,
|
|
||||||
showRegion: true,
|
|
||||||
sticky: true,
|
|
||||||
layout: 'default',
|
|
||||||
};
|
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
export * from './api.service';
|
export * from './api.service';
|
||||||
export * from './cart.service';
|
export * from './cart.service';
|
||||||
export * from './telegram.service';
|
|
||||||
export * from './language.service';
|
export * from './language.service';
|
||||||
export * from './seo.service';
|
export * from './seo.service';
|
||||||
export * from './location.service';
|
export * from './location.service';
|
||||||
|
|||||||
@@ -1,39 +0,0 @@
|
|||||||
import { Injectable } from '@angular/core';
|
|
||||||
import type { } from '../types/telegram.types';
|
|
||||||
|
|
||||||
@Injectable({
|
|
||||||
providedIn: 'root'
|
|
||||||
})
|
|
||||||
export class TelegramService {
|
|
||||||
private tg = typeof window !== 'undefined' ? window.Telegram?.WebApp : null;
|
|
||||||
|
|
||||||
isTelegramApp(): boolean {
|
|
||||||
return !!this.tg;
|
|
||||||
}
|
|
||||||
|
|
||||||
getUser() {
|
|
||||||
return this.tg?.initDataUnsafe?.user || null;
|
|
||||||
}
|
|
||||||
|
|
||||||
getUserId(): number | null {
|
|
||||||
return this.tg?.initDataUnsafe?.user?.id || null;
|
|
||||||
}
|
|
||||||
|
|
||||||
getUsername(): string | null {
|
|
||||||
return this.tg?.initDataUnsafe?.user?.username || null;
|
|
||||||
}
|
|
||||||
|
|
||||||
getFirstName(): string | null {
|
|
||||||
return this.tg?.initDataUnsafe?.user?.first_name || null;
|
|
||||||
}
|
|
||||||
|
|
||||||
getFullName(): string | null {
|
|
||||||
const user = this.getUser();
|
|
||||||
if (!user) return null;
|
|
||||||
return `${user.first_name}${user.last_name ? ' ' + user.last_name : ''}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
getDisplayName(): string {
|
|
||||||
return this.getUsername() || this.getFullName() || 'User';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -106,19 +106,3 @@ export function getTranslatedField(
|
|||||||
if (field === 'simpleDescription') return item.simpleDescription || item.description || '';
|
if (field === 'simpleDescription') return item.simpleDescription || item.description || '';
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get translated category name for the current language.
|
|
||||||
*/
|
|
||||||
export function getTranslatedCategoryName(cat: Category, lang: string): string {
|
|
||||||
const translation = cat.translations?.[lang];
|
|
||||||
if (translation?.name) return translation.name;
|
|
||||||
|
|
||||||
if (cat.names?.length) {
|
|
||||||
const entry = cat.names.find(n => n.language === lang || n.language === lang.toUpperCase() || (lang === 'hy' && n.language === 'AM'));
|
|
||||||
const val = entry?.value || (entry as any)?.valuue || '';
|
|
||||||
if (val) return val;
|
|
||||||
}
|
|
||||||
|
|
||||||
return cat.name || '';
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user