- Add admin dashboard feature (models/gateway/facade/components/page) - Wire admin/products routes and backoffice coming-soon placeholders - Add lastPublishedAt to ProjectEditorFacade/state - Add dashboard i18n keys (en/ru/hy) and docs/ADMIN.md Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
172 lines
5.9 KiB
TypeScript
172 lines
5.9 KiB
TypeScript
import { ChangeDetectionStrategy, Component, computed, inject } from '@angular/core';
|
|
import { CommonModule } from '@angular/common';
|
|
import { TranslateService } from '../../../../i18n/translate.service';
|
|
import { TranslatePipe } from '../../../../i18n/translate.pipe';
|
|
import { LanguageService } from '../../../../services/language.service';
|
|
import { AdminDashboardFacade } from '../facade/admin-dashboard.facade';
|
|
import { AdminDashboardCardComponent } from '../components/admin-dashboard-card.component';
|
|
import { AdminDashboardQuickActionsComponent } from '../components/admin-dashboard-quick-actions.component';
|
|
import { AdminDashboardActivityComponent, AdminDashboardActivityViewEntry } from '../components/admin-dashboard-activity.component';
|
|
import { AdminDashboardHealthComponent } from '../components/admin-dashboard-health.component';
|
|
import { AdminDashboardCardStatus, AdminDashboardQuickAction } from '../models/admin-dashboard.model';
|
|
|
|
interface DashboardCardViewModel {
|
|
id: string;
|
|
titleKey: string;
|
|
status: AdminDashboardCardStatus;
|
|
value: string | null;
|
|
subtitle: string | null;
|
|
}
|
|
|
|
@Component({
|
|
selector: 'app-admin-dashboard-page',
|
|
standalone: true,
|
|
imports: [
|
|
CommonModule,
|
|
TranslatePipe,
|
|
AdminDashboardCardComponent,
|
|
AdminDashboardQuickActionsComponent,
|
|
AdminDashboardActivityComponent,
|
|
AdminDashboardHealthComponent,
|
|
],
|
|
templateUrl: './admin-dashboard-page.component.html',
|
|
styleUrls: ['./admin-dashboard-page.component.scss'],
|
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
})
|
|
export class AdminDashboardPageComponent {
|
|
readonly facade = inject(AdminDashboardFacade);
|
|
private readonly translate = inject(TranslateService);
|
|
private readonly languageService = inject(LanguageService);
|
|
|
|
readonly quickActions = computed<AdminDashboardQuickAction[]>(() => {
|
|
const lang = this.languageService.currentLanguage();
|
|
return this.facade.quickActions.map(action => ({
|
|
...action,
|
|
route: ['/', lang, ...action.route.filter(segment => segment !== '')],
|
|
}));
|
|
});
|
|
|
|
readonly activityEntries = computed<AdminDashboardActivityViewEntry[]>(() =>
|
|
this.facade.activityEntries().map(entry => ({
|
|
id: entry.id,
|
|
labelKey: entry.type === 'published' ? 'dashboard.activityPublished' : 'dashboard.activityDraftSaved',
|
|
timeText: new Date(entry.timestamp).toLocaleString(),
|
|
})),
|
|
);
|
|
|
|
readonly healthChecks = this.facade.healthChecks;
|
|
|
|
readonly cards = computed<DashboardCardViewModel[]>(() => {
|
|
const bootstrap = this.facade.bootstrap();
|
|
const bootstrapLoading: AdminDashboardCardStatus = bootstrap ? 'ready' : 'loading';
|
|
const metrics = this.facade.metrics();
|
|
const locales = bootstrap?.localization.supportedLocales ?? [];
|
|
|
|
return [
|
|
{
|
|
id: 'marketplace-status',
|
|
titleKey: 'dashboard.cardMarketplaceStatus',
|
|
status: bootstrapLoading,
|
|
value: bootstrap ? this.translate.t(this.facade.status() === 'published' ? 'builder.statusPublished' : 'builder.statusDraft') : null,
|
|
subtitle: null,
|
|
},
|
|
{
|
|
id: 'project-name',
|
|
titleKey: 'dashboard.cardProjectName',
|
|
status: bootstrapLoading,
|
|
value: bootstrap?.tenant.name ?? null,
|
|
subtitle: null,
|
|
},
|
|
{
|
|
id: 'current-theme',
|
|
titleKey: 'dashboard.cardCurrentTheme',
|
|
status: bootstrapLoading,
|
|
value: bootstrap?.theme.themeId ?? null,
|
|
subtitle: null,
|
|
},
|
|
{
|
|
id: 'languages',
|
|
titleKey: 'dashboard.cardLanguages',
|
|
status: bootstrapLoading === 'loading' ? 'loading' : (locales.length === 0 ? 'empty' : 'ready'),
|
|
value: locales.length ? locales.join(', ').toUpperCase() : null,
|
|
subtitle: null,
|
|
},
|
|
{
|
|
id: 'categories-count',
|
|
titleKey: 'dashboard.cardCategoriesCount',
|
|
status: metrics.status,
|
|
value: metrics.value ? String(metrics.value.categoriesCount) : null,
|
|
subtitle: null,
|
|
},
|
|
{
|
|
id: 'products-count',
|
|
titleKey: 'dashboard.cardProductsCount',
|
|
status: metrics.status,
|
|
value: metrics.value ? String(metrics.value.productsCount) : null,
|
|
subtitle: null,
|
|
},
|
|
{
|
|
id: 'orders',
|
|
titleKey: 'dashboard.cardOrders',
|
|
status: 'pending-backend',
|
|
value: null,
|
|
subtitle: null,
|
|
},
|
|
{
|
|
id: 'revenue',
|
|
titleKey: 'dashboard.cardRevenue',
|
|
status: 'pending-backend',
|
|
value: null,
|
|
subtitle: null,
|
|
},
|
|
{
|
|
id: 'last-publish',
|
|
titleKey: 'dashboard.cardLastPublish',
|
|
status: bootstrapLoading,
|
|
value: bootstrap ? this.formatTimestamp(this.facade.lastPublishedAt()) : null,
|
|
subtitle: null,
|
|
},
|
|
{
|
|
id: 'last-draft-save',
|
|
titleKey: 'dashboard.cardLastDraftSave',
|
|
status: bootstrapLoading,
|
|
value: bootstrap ? this.formatTimestamp(this.facade.lastSavedAt()) : null,
|
|
subtitle: null,
|
|
},
|
|
{
|
|
id: 'bootstrap-version',
|
|
titleKey: 'dashboard.cardBootstrapVersion',
|
|
status: bootstrapLoading,
|
|
value: bootstrap?.schemaVersion ?? null,
|
|
subtitle: null,
|
|
},
|
|
{
|
|
id: 'active-layout',
|
|
titleKey: 'dashboard.cardActiveLayout',
|
|
status: bootstrapLoading,
|
|
value: bootstrap ? (bootstrap.layout?.type ?? 'default') : null,
|
|
subtitle: null,
|
|
},
|
|
{
|
|
id: 'enabled-widgets',
|
|
titleKey: 'dashboard.cardEnabledWidgets',
|
|
status: bootstrapLoading,
|
|
value: bootstrap ? String(this.facade.enabledWidgetsCount()) : null,
|
|
subtitle: null,
|
|
},
|
|
];
|
|
});
|
|
|
|
constructor() {
|
|
this.facade.ensureLoaded();
|
|
}
|
|
|
|
cardTitle(titleKey: string): string {
|
|
return this.translate.t(titleKey);
|
|
}
|
|
|
|
private formatTimestamp(timestamp: number | null): string {
|
|
return timestamp ? new Date(timestamp).toLocaleString() : this.translate.t('dashboard.never');
|
|
}
|
|
}
|