Skip to content

Commit 431198e

Browse files
Merge pull request #416 from RUKAYAT-CODER/feat-dashboard-analytics
Feat dashboard analytics
2 parents 94606ab + 752aa11 commit 431198e

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+2780
-71
lines changed

backend/package-lock.json

Lines changed: 347 additions & 41 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

backend/package.json

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,34 +21,41 @@
2121
},
2222
"dependencies": {
2323
"@nestjs/common": "^10.0.0",
24-
"@nestjs/config": "^3.0.0",
24+
"@nestjs/config": "^3.3.0",
2525
"@nestjs/core": "^10.0.0",
2626
"@nestjs/event-emitter": "^3.0.1",
27-
"@nestjs/jwt": "^11.0.0",
27+
"@nestjs/jwt": "^11.0.2",
2828
"@nestjs/mapped-types": "*",
2929
"@nestjs/passport": "^11.0.5",
3030
"@nestjs/platform-express": "^10.0.0",
3131
"@nestjs/schedule": "^6.0.1",
3232
"@nestjs/swagger": "^7.3.0",
33+
"@nestjs/throttler": "^6.5.0",
3334
"@nestjs/typeorm": "^10.0.2",
3435
"@types/multer": "^2.0.0",
36+
"@types/speakeasy": "^2.0.10",
3537
"@types/uuid": "^10.0.0",
36-
"bcryptjs": "^3.0.2",
38+
"axios": "^1.6.0",
39+
"bcryptjs": "^3.0.3",
3740
"bwip-js": "^4.7.0",
3841
"class-transformer": "^0.5.1",
39-
"class-validator": "^0.14.0",
42+
"class-validator": "^0.14.3",
4043
"date-fns": "^4.1.0",
4144
"json2csv": "^6.0.0-alpha.2",
4245
"multer": "^2.0.2",
4346
"nestjs-i18n": "^10.5.1",
47+
"otplib": "^13.1.1",
4448
"papaparse": "^5.5.3",
4549
"passport": "^0.7.0",
4650
"passport-jwt": "^4.0.1",
51+
"passport-local": "^1.0.0",
4752
"pdfkit": "^0.17.2",
4853
"pg": "^8.11.3",
4954
"qrcode": "^1.5.4",
55+
"redis": "^5.10.0",
5056
"reflect-metadata": "^0.2.0",
5157
"rxjs": "^7.8.1",
58+
"speakeasy": "^2.0.0",
5259
"swagger-ui-express": "^5.0.1",
5360
"typeorm": "^0.3.27"
5461
},
@@ -60,9 +67,12 @@
6067
"@types/express": "^5.0.0",
6168
"@types/jest": "^29.5.2",
6269
"@types/json2csv": "^5.0.7",
70+
"@types/jsonwebtoken": "^9.0.10",
6371
"@types/node": "^20.3.1",
72+
"@types/otplib": "^7.0.0",
6473
"@types/papaparse": "^5.3.16",
6574
"@types/passport-jwt": "^4.0.1",
75+
"@types/passport-local": "^1.0.38",
6676
"@types/pdfkit": "^0.17.3",
6777
"@types/pg": "^8.10.0",
6878
"@types/supertest": "^6.0.0",
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
import { Controller, Get, Query, Param, UseGuards, Req } from '@nestjs/common';
2+
import { ApiTags, ApiOperation, ApiBearerAuth, ApiResponse } from '@nestjs/swagger';
3+
import { AnalyticsService } from './analytics.service';
4+
import { AnalyticsQueryDto, DashboardStatsResponse, TrendsResponse, DistributionResponse } from './dto/analytics-query.dto';
5+
import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard';
6+
import { RbacGuard } from '../auth/guards/rbac.guard';
7+
import { CustomThrottlerGuard } from '../security/throttler.guard';
8+
import { RequirePermission } from '../common/decorators/require-permission.decorator';
9+
10+
@ApiTags('Analytics')
11+
@ApiBearerAuth('JWT-auth')
12+
@UseGuards(JwtAuthGuard, RbacGuard, CustomThrottlerGuard)
13+
@Controller('api/v1/analytics')
14+
export class AnalyticsController {
15+
constructor(private readonly analyticsService: AnalyticsService) {}
16+
17+
@Get('dashboard')
18+
@ApiOperation({ summary: 'Get main dashboard statistics' })
19+
@RequirePermission('analytics', 'read')
20+
async getDashboardStats(@Query() query: AnalyticsQueryDto, @Req() req: any): Promise<DashboardStatsResponse> {
21+
return this.analyticsService.getDashboardStats(query, req.user);
22+
}
23+
24+
@Get('asset-stats')
25+
@ApiOperation({ summary: 'Get asset-specific statistics' })
26+
@RequirePermission('analytics', 'read')
27+
async getAssetStats() {
28+
return this.analyticsService.getAssetStats();
29+
}
30+
31+
@Get('trends')
32+
@ApiOperation({ summary: 'Get trend data for charts' })
33+
@RequirePermission('analytics', 'read')
34+
async getTrends(@Query() query: AnalyticsQueryDto, @Req() req: any): Promise<TrendsResponse> {
35+
return this.analyticsService.getTrends(query, req.user);
36+
}
37+
38+
@Get('distribution')
39+
@ApiOperation({ summary: 'Get asset distribution data' })
40+
@RequirePermission('analytics', 'read')
41+
async getDistribution(@Query() query: AnalyticsQueryDto, @Req() req: any): Promise<DistributionResponse> {
42+
return this.analyticsService.getDistribution(query, req.user);
43+
}
44+
45+
@Get('top-assets')
46+
@ApiOperation({ summary: 'Get most expensive/valuable assets' })
47+
@RequirePermission('analytics', 'read')
48+
async getTopAssets() {
49+
return this.analyticsService.getTopAssets();
50+
}
51+
52+
@Get('alerts')
53+
@ApiOperation({ summary: 'Get assets requiring attention' })
54+
@RequirePermission('analytics', 'read')
55+
async getAlerts() {
56+
return this.analyticsService.getAlerts();
57+
}
58+
59+
@Get('departments/comparison')
60+
@ApiOperation({ summary: 'Compare departments' })
61+
@RequirePermission('analytics', 'read')
62+
async compareDepartments() {
63+
// Basic implementation using existing logic
64+
return this.analyticsService.getDistribution({}, { role: 'ADMIN' });
65+
}
66+
67+
@Get('departments/:id')
68+
@ApiOperation({ summary: 'Get department-specific analytics' })
69+
@RequirePermission('analytics', 'read')
70+
async getDepartmentAnalytics(@Param('id') id: string) {
71+
return this.analyticsService.getDepartmentAnalytics(id);
72+
}
73+
74+
@Get('locations/utilization')
75+
@ApiOperation({ summary: 'Get location utilization rates' })
76+
@RequirePermission('analytics', 'read')
77+
async getLocationUtilization() {
78+
return this.analyticsService.getDistribution({}, { role: 'ADMIN' });
79+
}
80+
81+
@Get('locations/:id')
82+
@ApiOperation({ summary: 'Get location-specific analytics' })
83+
@RequirePermission('analytics', 'read')
84+
async getLocationAnalytics(@Param('id') id: string) {
85+
return this.analyticsService.getLocationAnalytics(id);
86+
}
87+
88+
@Get('users/activity')
89+
@ApiOperation({ summary: 'Get user activity statistics' })
90+
@RequirePermission('analytics', 'read')
91+
async getUserActivity() {
92+
// Placeholder
93+
return { activity: [] };
94+
}
95+
96+
@Get('users/:id')
97+
@ApiOperation({ summary: "Get user's asset assignment history" })
98+
@RequirePermission('analytics', 'read')
99+
async getUserAnalytics(@Param('id') id: string) {
100+
return this.analyticsService.getUserAnalytics(id);
101+
}
102+
103+
@Get('timeline')
104+
@ApiOperation({ summary: 'Asset registrations over time' })
105+
@RequirePermission('analytics', 'read')
106+
async getTimeline(@Query() query: AnalyticsQueryDto, @Req() req: any) {
107+
return this.analyticsService.getTrends(query, req.user);
108+
}
109+
110+
@Get('forecast')
111+
@ApiOperation({ summary: 'Predictive analytics (asset needs)' })
112+
@RequirePermission('analytics', 'read')
113+
async getForecast() {
114+
// Mock forecast implementation
115+
return {
116+
forecast: [
117+
{ month: '2025-02', predictedNeed: 15, confidence: 0.85 },
118+
{ month: '2025-03', predictedNeed: 22, confidence: 0.78 },
119+
]
120+
};
121+
}
122+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { Module } from '@nestjs/common';
2+
import { TypeOrmModule } from '@nestjs/typeorm';
3+
import { AnalyticsService } from './analytics.service';
4+
import { AnalyticsController } from './analytics.controller';
5+
import { Asset } from '../assets/entities/asset.entity';
6+
import { AssetCategory } from '../asset-categories/asset-category.entity';
7+
import { Department } from '../departments/entities/department.entity';
8+
import { User } from '../users/entities/user.entity';
9+
import { RedisService } from '../common/redis.service';
10+
11+
@Module({
12+
imports: [
13+
TypeOrmModule.forFeature([Asset, AssetCategory, Department, User]),
14+
],
15+
controllers: [AnalyticsController],
16+
providers: [AnalyticsService, RedisService],
17+
exports: [AnalyticsService],
18+
})
19+
export class AnalyticsModule {}

0 commit comments

Comments
 (0)