import type { AdminUserViewData } from '@/lib/view-data/AdminUserViewData'; import type { DashboardStatsViewData } from '@/lib/view-data/DashboardStatsViewData'; import { ViewModel } from "../contracts/view-models/ViewModel"; import { UserStatusDisplay } from "../display-objects/UserStatusDisplay"; import { UserRoleDisplay } from "../display-objects/UserRoleDisplay"; import { DateDisplay } from "../display-objects/DateDisplay"; import { ActivityLevelDisplay } from "../display-objects/ActivityLevelDisplay"; /** * AdminUserViewModel * * View Model for admin user management. * Transforms API DTO into UI-ready state with formatting and derived fields. */ export class AdminUserViewModel extends ViewModel { id: string; email: string; displayName: string; roles: string[]; status: string; isSystemAdmin: boolean; createdAt: Date; updatedAt: Date; lastLoginAt?: Date; primaryDriverId?: string; // UI-specific derived fields (primitive outputs only) readonly roleBadges: string[]; readonly statusBadgeLabel: string; readonly statusBadgeVariant: string; readonly lastLoginFormatted: string; readonly createdAtFormatted: string; constructor(viewData: AdminUserViewData) { super(); this.id = viewData.id; this.email = viewData.email; this.displayName = viewData.displayName; this.roles = viewData.roles; this.status = viewData.status; this.isSystemAdmin = viewData.isSystemAdmin; this.createdAt = new Date(viewData.createdAt); this.updatedAt = new Date(viewData.updatedAt); this.lastLoginAt = viewData.lastLoginAt ? new Date(viewData.lastLoginAt) : undefined; this.primaryDriverId = viewData.primaryDriverId; // Derive role badges using Display Object this.roleBadges = this.roles.map(role => UserRoleDisplay.roleLabel(role)); // Derive status badge using Display Object this.statusBadgeLabel = UserStatusDisplay.statusLabel(this.status); this.statusBadgeVariant = UserStatusDisplay.statusVariant(this.status); // Format dates using Display Object this.lastLoginFormatted = this.lastLoginAt ? DateDisplay.formatShort(this.lastLoginAt) : 'Never'; this.createdAtFormatted = DateDisplay.formatShort(this.createdAt); } } /** * 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); } } /** * UserListViewModel * * View Model for user list with pagination and filtering state. */ export class UserListViewModel extends ViewModel { users: AdminUserViewModel[]; total: number; page: number; limit: number; totalPages: number; // UI-specific derived fields (primitive outputs only) readonly hasUsers: boolean; readonly showPagination: boolean; readonly startIndex: number; readonly endIndex: number; constructor(data: { users: AdminUserViewData[]; total: number; page: number; limit: number; totalPages: number; }) { super(); this.users = data.users.map(viewData => new AdminUserViewModel(viewData)); this.total = data.total; this.page = data.page; this.limit = data.limit; this.totalPages = data.totalPages; // Derive UI state this.hasUsers = this.users.length > 0; this.showPagination = this.totalPages > 1; this.startIndex = this.users.length > 0 ? (this.page - 1) * this.limit + 1 : 0; this.endIndex = this.users.length > 0 ? (this.page - 1) * this.limit + this.users.length : 0; } }