import { Component, OnInit, inject, signal } from '@angular/core'; import { CommonModule } from '@angular/common'; import { RouterModule } from '@angular/router'; import { MatCardModule } from '@angular/material/card'; import { MatIconModule } from '@angular/material/icon'; import { MatButtonModule } from '@angular/material/button'; import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; import { StatusBadgeComponent } from '../../../shared/components/status-badge/status-badge.component'; import { BlockchainExplorerMiniComponent } from '../../../shared/components/blockchain-explorer-mini/blockchain-explorer-mini.component'; import { ApiService } from '../../../core/services/api.service'; import { AdminStatsDto } from '../../../api/models'; @Component({ selector: 'app-admin-dashboard', standalone: true, imports: [ CommonModule, RouterModule, MatCardModule, MatIconModule, MatButtonModule, MatProgressSpinnerModule, StatusBadgeComponent, BlockchainExplorerMiniComponent, ], template: `
Admin Dashboard

Platform Overview

Monitor and manage the Goa GEL Blockchain Platform

@if (loading()) {

Loading dashboard...

} @else if (stats()) {
description
{{ stats()!.totalRequests }}
Total Requests
check_circle
{{ stats()!.totalApprovals }}
Approvals
folder_open
{{ stats()!.totalDocuments }}
Documents
business
{{ stats()!.totalDepartments }}
Departments
people
{{ stats()!.totalApplicants }}
Applicants
link
{{ stats()!.totalBlockchainTransactions }}
Blockchain Tx
pie_chart

Requests by Status

@for (item of (stats()?.requestsByStatus || []); track item.status) {
{{ item.count }}
}
flash_on

Quick Actions

business
Manage Departments
account_tree
Manage Workflows
history
View Audit Logs
webhook
Webhooks
}
`, styles: [` .page-container { padding: 0; } /* Welcome Section */ .welcome-section { background: linear-gradient(135deg, #1D0A69 0%, #2563EB 100%) !important; color: white !important; padding: 32px; margin: 0 0 24px 0; border-radius: 16px; position: relative; overflow: hidden; } .welcome-content { max-width: 1400px; margin: 0 auto; display: flex; justify-content: space-between; align-items: center; gap: 24px; position: relative; z-index: 1; } .welcome-text .greeting { font-size: 0.9rem; opacity: 0.9; text-transform: uppercase; letter-spacing: 1px; color: rgba(255, 255, 255, 0.9) !important; display: block; } .welcome-text h1 { margin: 8px 0; font-size: 2rem; font-weight: 700; color: white !important; } .welcome-text .subtitle { margin: 0; opacity: 0.9; font-size: 0.95rem; color: rgba(255, 255, 255, 0.9) !important; } .quick-actions { display: flex; gap: 12px; } .action-btn.primary { background: white !important; color: #1D0A69 !important; } .action-btn:not(.primary) { color: white; border-color: rgba(255, 255, 255, 0.5); } .action-btn:not(.primary):hover { background: rgba(255, 255, 255, 0.1); } .action-btn mat-icon { margin-right: 8px; } .loading-container { display: flex; flex-direction: column; align-items: center; justify-content: center; padding: 64px; gap: 16px; } .loading-container p { color: #8E8E8E; } /* Stats Section */ .stats-section { margin-bottom: 24px; } .stats-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 20px; } .stat-card { display: flex; align-items: center; gap: 16px; padding: 24px; border-radius: 16px !important; cursor: pointer; transition: all 0.3s ease; position: relative; overflow: hidden; background: white !important; color: #150202; border: 1px solid #EBEAEA; } .stat-card:hover { transform: translateY(-2px); box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08); } .stat-icon-wrapper { width: 48px; height: 48px; border-radius: 12px; background: rgba(29, 10, 105, 0.08); display: flex; align-items: center; justify-content: center; flex-shrink: 0; color: #1D0A69; } .stat-icon-wrapper mat-icon { font-size: 24px; width: 24px; height: 24px; } .stat-card.approvals .stat-icon-wrapper { background: rgba(5, 150, 105, 0.1); color: #059669; } .stat-card.documents .stat-icon-wrapper { background: rgba(245, 158, 11, 0.1); color: #f59e0b; } .stat-card.departments .stat-icon-wrapper { background: rgba(124, 58, 237, 0.1); color: #7c3aed; } .stat-card.applicants .stat-icon-wrapper { background: rgba(8, 145, 178, 0.1); color: #0891b2; } .stat-card.blockchain .stat-icon-wrapper { background: rgba(71, 85, 105, 0.1); color: #475569; } .stat-content { flex: 1; z-index: 1; } .stat-value { font-size: 1.75rem; font-weight: 700; line-height: 1.2; color: #150202; } .stat-label { font-size: 0.8rem; color: #8E8E8E; margin-top: 4px; } .stat-decoration { display: none; } /* Content Grid */ .content-grid { display: grid; grid-template-columns: 1fr 400px; gap: 24px; } .content-main { display: flex; flex-direction: column; gap: 24px; } .section-card { border-radius: 16px !important; } .card-header { display: flex; justify-content: space-between; align-items: center; padding: 20px 24px; border-bottom: 1px solid #EBEAEA; } .card-header .header-left { display: flex; align-items: center; gap: 12px; } .card-header .header-left mat-icon { color: #2563EB; } .card-header .header-left h2 { margin: 0; font-size: 1.1rem; font-weight: 600; color: #150202; } .card-header button mat-icon { margin-left: 4px; font-size: 18px; width: 18px; height: 18px; } .card-content { padding: 20px 24px; } .status-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); gap: 12px; } .status-item { display: flex; justify-content: space-between; align-items: center; padding: 14px 16px; background: #F5F5F5; border-radius: 10px; cursor: pointer; transition: all 0.2s; } .status-item:hover { background: rgba(0, 0, 0, 0.08); } .status-item .count { font-size: 1.25rem; font-weight: 700; color: #150202; } /* Quick Actions */ .actions-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 16px; } .action-item { display: flex; flex-direction: column; align-items: center; gap: 12px; padding: 20px; border-radius: 12px; cursor: pointer; transition: all 0.2s; text-align: center; } .action-item:hover { background: #F5F5F5; } .action-item span { font-size: 0.85rem; color: #150202; font-weight: 500; } .action-icon { width: 56px; height: 56px; border-radius: 14px; display: flex; align-items: center; justify-content: center; } .action-icon mat-icon { font-size: 26px; width: 26px; height: 26px; } .action-icon.departments { background: linear-gradient(135deg, #7c3aed, #a78bfa); color: white; } .action-icon.workflows { background: linear-gradient(135deg, #1D0A69, #2563EB); color: white; } .action-icon.audit { background: linear-gradient(135deg, #f59e0b, #fbbf24); color: white; } .action-icon.webhooks { background: linear-gradient(135deg, #059669, #10b981); color: white; } .content-sidebar { min-width: 0; } /* Responsive adjustments */ @media (max-width: 1200px) { .content-grid { grid-template-columns: 1fr; } .content-sidebar { order: -1; } } @media (max-width: 768px) { .welcome-content { flex-direction: column; align-items: flex-start; } .actions-grid { grid-template-columns: repeat(2, 1fr); } } `], }) export class AdminDashboardComponent implements OnInit { private readonly api = inject(ApiService); readonly loading = signal(true); readonly stats = signal(null); ngOnInit(): void { this.loadStats(); } private loadStats(): void { this.api.get('/admin/stats').subscribe({ next: (data) => { this.stats.set(data); this.loading.set(false); }, error: () => { // Use mock data for demo when API is unavailable this.loadMockStats(); this.loading.set(false); }, }); } private loadMockStats(): void { const mockStats: AdminStatsDto = { totalRequests: 156, totalApprovals: 89, totalDocuments: 423, totalDepartments: 12, totalApplicants: 67, totalBlockchainTransactions: 234, averageProcessingTime: 4.5, requestsByStatus: [ { status: 'DRAFT', count: 12 }, { status: 'SUBMITTED', count: 23 }, { status: 'IN_REVIEW', count: 18 }, { status: 'APPROVED', count: 89 }, { status: 'REJECTED', count: 8 }, { status: 'COMPLETED', count: 6 }, ], requestsByType: [ { type: 'NEW_LICENSE', count: 98 }, { type: 'RENEWAL', count: 42 }, { type: 'AMENDMENT', count: 16 }, ], departmentStats: [], lastUpdated: new Date().toISOString(), }; this.stats.set(mockStats); } }