feat: Goa GEL Blockchain e-Licensing Platform - Full Stack Implementation
Complete implementation of the Goa Government e-Licensing platform with: Backend: - NestJS API with JWT authentication - PostgreSQL database with Knex ORM - Redis caching and session management - MinIO document storage - Hyperledger Besu blockchain integration - Multi-department workflow system - Comprehensive API tests (266/282 passing) Frontend: - Angular 21 with standalone components - Angular Material + TailwindCSS UI - Visual workflow builder - Document upload with progress tracking - Blockchain explorer integration - Role-based dashboards (Admin, Department, Citizen) - E2E tests with Playwright (37 tests) Infrastructure: - Docker Compose orchestration - Blockscout blockchain explorer - Development and production configurations
This commit is contained in:
290
frontend/src/app/features/admin/admin.component.ts
Normal file
290
frontend/src/app/features/admin/admin.component.ts
Normal file
@@ -0,0 +1,290 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { MatTabsModule } from '@angular/material/tabs';
|
||||
import { MatCardModule } from '@angular/material/card';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatDividerModule } from '@angular/material/divider';
|
||||
import { DepartmentOnboardingComponent } from './department-onboarding/department-onboarding.component';
|
||||
import { DepartmentListComponent } from './department-list/department-list.component';
|
||||
import { UserListComponent } from './user-list/user-list.component';
|
||||
import { TransactionDashboardComponent } from './transaction-dashboard/transaction-dashboard.component';
|
||||
import { EventDashboardComponent } from './event-dashboard/event-dashboard.component';
|
||||
import { LogsViewerComponent } from './logs-viewer/logs-viewer.component';
|
||||
import { AdminStatsComponent } from './admin-stats/admin-stats.component';
|
||||
import { BlockchainExplorerMiniComponent } from '../../shared/components';
|
||||
|
||||
@Component({
|
||||
selector: 'app-admin',
|
||||
standalone: true,
|
||||
imports: [
|
||||
CommonModule,
|
||||
RouterModule,
|
||||
MatTabsModule,
|
||||
MatCardModule,
|
||||
MatIconModule,
|
||||
MatButtonModule,
|
||||
MatDividerModule,
|
||||
DepartmentOnboardingComponent,
|
||||
DepartmentListComponent,
|
||||
UserListComponent,
|
||||
TransactionDashboardComponent,
|
||||
EventDashboardComponent,
|
||||
LogsViewerComponent,
|
||||
AdminStatsComponent,
|
||||
BlockchainExplorerMiniComponent,
|
||||
],
|
||||
template: `
|
||||
<div class="admin-container">
|
||||
<header class="admin-header">
|
||||
<div class="header-content">
|
||||
<div class="header-icon-container">
|
||||
<mat-icon class="header-icon">admin_panel_settings</mat-icon>
|
||||
</div>
|
||||
<div class="header-text">
|
||||
<h1>Admin Portal</h1>
|
||||
<p class="subtitle">Manage the Goa GEL Blockchain Platform</p>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="admin-content">
|
||||
<!-- Platform Statistics -->
|
||||
<app-admin-stats></app-admin-stats>
|
||||
|
||||
<!-- Main Tabs -->
|
||||
<mat-card class="tabs-card">
|
||||
<mat-tab-group animationDuration="300ms">
|
||||
<!-- Dashboard Tab -->
|
||||
<mat-tab>
|
||||
<ng-template mat-tab-label>
|
||||
<mat-icon class="tab-icon">dashboard</mat-icon>
|
||||
Dashboard
|
||||
</ng-template>
|
||||
<div class="tab-content">
|
||||
<div class="dashboard-grid">
|
||||
<div class="dashboard-main">
|
||||
<app-transaction-dashboard></app-transaction-dashboard>
|
||||
</div>
|
||||
<div class="dashboard-sidebar">
|
||||
<app-blockchain-explorer-mini [showViewAll]="false"></app-blockchain-explorer-mini>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</mat-tab>
|
||||
|
||||
<!-- Departments Tab -->
|
||||
<mat-tab>
|
||||
<ng-template mat-tab-label>
|
||||
<mat-icon class="tab-icon">business</mat-icon>
|
||||
Departments
|
||||
</ng-template>
|
||||
<div class="tab-content">
|
||||
<app-department-onboarding></app-department-onboarding>
|
||||
<mat-divider class="section-divider"></mat-divider>
|
||||
<app-department-list></app-department-list>
|
||||
</div>
|
||||
</mat-tab>
|
||||
|
||||
<!-- Users Tab -->
|
||||
<mat-tab>
|
||||
<ng-template mat-tab-label>
|
||||
<mat-icon class="tab-icon">people</mat-icon>
|
||||
Users
|
||||
</ng-template>
|
||||
<div class="tab-content">
|
||||
<app-user-list></app-user-list>
|
||||
</div>
|
||||
</mat-tab>
|
||||
|
||||
<!-- Transactions Tab -->
|
||||
<mat-tab>
|
||||
<ng-template mat-tab-label>
|
||||
<mat-icon class="tab-icon">receipt_long</mat-icon>
|
||||
Transactions
|
||||
</ng-template>
|
||||
<div class="tab-content">
|
||||
<app-transaction-dashboard></app-transaction-dashboard>
|
||||
</div>
|
||||
</mat-tab>
|
||||
|
||||
<!-- Events Tab -->
|
||||
<mat-tab>
|
||||
<ng-template mat-tab-label>
|
||||
<mat-icon class="tab-icon">event_note</mat-icon>
|
||||
Events
|
||||
</ng-template>
|
||||
<div class="tab-content">
|
||||
<app-event-dashboard></app-event-dashboard>
|
||||
</div>
|
||||
</mat-tab>
|
||||
|
||||
<!-- Logs Tab -->
|
||||
<mat-tab>
|
||||
<ng-template mat-tab-label>
|
||||
<mat-icon class="tab-icon">description</mat-icon>
|
||||
Logs
|
||||
</ng-template>
|
||||
<div class="tab-content">
|
||||
<app-logs-viewer></app-logs-viewer>
|
||||
</div>
|
||||
</mat-tab>
|
||||
</mat-tab-group>
|
||||
</mat-card>
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
styles: [
|
||||
`
|
||||
.admin-container {
|
||||
min-height: 100vh;
|
||||
background-color: var(--dbim-linen);
|
||||
}
|
||||
|
||||
.admin-header {
|
||||
background: linear-gradient(135deg, var(--dbim-blue-dark) 0%, var(--dbim-blue-mid) 100%);
|
||||
color: white;
|
||||
padding: 32px;
|
||||
box-shadow: var(--shadow-elevated);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: -50%;
|
||||
right: -20%;
|
||||
width: 60%;
|
||||
height: 200%;
|
||||
background: radial-gradient(circle, rgba(255, 255, 255, 0.1) 0%, transparent 50%);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
&::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
bottom: -50%;
|
||||
left: -10%;
|
||||
width: 40%;
|
||||
height: 150%;
|
||||
background: radial-gradient(circle, rgba(99, 102, 241, 0.2) 0%, transparent 50%);
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
|
||||
.header-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 20px;
|
||||
max-width: 1400px;
|
||||
margin: 0 auto;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.header-icon-container {
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
border-radius: 16px;
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
backdrop-filter: blur(10px);
|
||||
|
||||
.header-icon {
|
||||
font-size: 32px;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
}
|
||||
}
|
||||
|
||||
.header-text {
|
||||
h1 {
|
||||
margin: 0;
|
||||
font-size: 28px;
|
||||
font-weight: 700;
|
||||
letter-spacing: -0.02em;
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
margin: 4px 0 0;
|
||||
opacity: 0.9;
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
}
|
||||
}
|
||||
|
||||
.admin-content {
|
||||
max-width: 1400px;
|
||||
margin: 0 auto;
|
||||
padding: 24px;
|
||||
}
|
||||
|
||||
.tabs-card {
|
||||
margin-top: 24px;
|
||||
border-radius: 16px !important;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.tab-icon {
|
||||
margin-right: 8px;
|
||||
font-size: 20px;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
.tab-content {
|
||||
padding: 24px;
|
||||
background: var(--dbim-white);
|
||||
}
|
||||
|
||||
.section-divider {
|
||||
margin: 32px 0;
|
||||
}
|
||||
|
||||
.dashboard-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 400px;
|
||||
gap: 24px;
|
||||
|
||||
@media (max-width: 1200px) {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
.dashboard-main {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.dashboard-sidebar {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
:host ::ng-deep {
|
||||
.mat-mdc-tab-label {
|
||||
min-width: 120px;
|
||||
}
|
||||
|
||||
.mat-mdc-tab-header {
|
||||
background: var(--dbim-linen);
|
||||
border-bottom: 1px solid rgba(29, 10, 105, 0.08);
|
||||
}
|
||||
|
||||
.mat-mdc-tab:not(.mat-mdc-tab-disabled).mdc-tab--active .mdc-tab__text-label {
|
||||
color: var(--dbim-blue-dark);
|
||||
}
|
||||
|
||||
.mat-mdc-tab-body-wrapper {
|
||||
background: var(--dbim-white);
|
||||
}
|
||||
}
|
||||
`,
|
||||
],
|
||||
})
|
||||
export class AdminComponent implements OnInit {
|
||||
ngOnInit(): void {
|
||||
// Initialize admin dashboard
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user