Files
gridpilot.gg/apps/website/lib/view-models/DashboardStatsViewModel.ts
2026-01-23 15:30:23 +01:00

75 lines
2.4 KiB
TypeScript

import { ViewModel } from "../contracts/view-models/ViewModel";
import { ActivityLevelDisplay } from "@/lib/display-objects/ActivityLevelDisplay";
import type { DashboardStatsViewData } from '@/lib/view-data/DashboardStatsViewData';
/**
* DashboardStatsViewModel
*
* View Model for admin dashboard statistics.
* Provides formatted statistics and derived metrics for UI.
*/
export class DashboardStatsViewModel extends ViewModel {
totalUsers: number;
activeUsers: number;
suspendedUsers: number;
deletedUsers: number;
systemAdmins: number;
recentLogins: number;
newUsersToday: number;
userGrowth: {
label: string;
value: number;
color: string;
}[];
roleDistribution: {
label: string;
value: number;
color: string;
}[];
statusDistribution: {
active: number;
suspended: number;
deleted: number;
};
activityTimeline: {
date: string;
newUsers: number;
logins: number;
}[];
// UI-specific derived fields (primitive outputs only)
readonly activeRate: number;
readonly activeRateFormatted: string;
readonly adminRatio: string;
readonly activityLevelLabel: string;
readonly activityLevelValue: 'low' | 'medium' | 'high';
constructor(viewData: DashboardStatsViewData) {
super();
this.totalUsers = viewData.totalUsers;
this.activeUsers = viewData.activeUsers;
this.suspendedUsers = viewData.suspendedUsers;
this.deletedUsers = viewData.deletedUsers;
this.systemAdmins = viewData.systemAdmins;
this.recentLogins = viewData.recentLogins;
this.newUsersToday = viewData.newUsersToday;
this.userGrowth = viewData.userGrowth;
this.roleDistribution = viewData.roleDistribution;
this.statusDistribution = viewData.statusDistribution;
this.activityTimeline = viewData.activityTimeline;
// Derive active rate
this.activeRate = this.totalUsers > 0 ? (this.activeUsers / this.totalUsers) * 100 : 0;
this.activeRateFormatted = `${Math.round(this.activeRate)}%`;
// Derive admin ratio
const nonAdmins = Math.max(1, this.totalUsers - this.systemAdmins);
this.adminRatio = `1:${Math.floor(nonAdmins / Math.max(1, this.systemAdmins))}`;
// Derive activity level using Display Object
const engagementRate = this.totalUsers > 0 ? (this.recentLogins / this.totalUsers) * 100 : 0;
this.activityLevelLabel = ActivityLevelDisplay.levelLabel(engagementRate);
this.activityLevelValue = ActivityLevelDisplay.levelValue(engagementRate);
}
}