75 lines
2.4 KiB
TypeScript
75 lines
2.4 KiB
TypeScript
import { ActivityLevelFormatter } from "@/lib/formatters/ActivityLevelFormatter";
|
|
import type { DashboardStatsViewData } from '@/lib/view-data/DashboardStatsViewData';
|
|
import { ViewModel } from "../contracts/view-models/ViewModel";
|
|
|
|
/**
|
|
* 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 = ActivityLevelFormatter.levelLabel(engagementRate);
|
|
this.activityLevelValue = ActivityLevelFormatter.levelValue(engagementRate);
|
|
}
|
|
}
|