Files
Tasks/frontend/src/app/features/admin/admin-user-detail/admin-user-detail.component.html
2025-11-14 21:48:47 +02:00

330 lines
13 KiB
HTML

<div class="admin-user-detail-container">
<!-- Header -->
<div class="page-header">
<div class="header-left">
<button mat-icon-button (click)="goBack()" class="back-button" aria-label="Go back to users list">
<mat-icon>arrow_back</mat-icon>
</button>
<h1 class="page-title">User Details</h1>
</div>
<div class="header-actions">
<button mat-icon-button (click)="refreshUser()" [disabled]="isLoading()"
matTooltip="Refresh user details" aria-label="Refresh">
<mat-icon>refresh</mat-icon>
</button>
</div>
</div>
<!-- Breadcrumb -->
<nav class="breadcrumb" aria-label="Breadcrumb navigation">
<a routerLink="/admin" class="breadcrumb-link">Admin</a>
<mat-icon class="breadcrumb-separator">chevron_right</mat-icon>
<a routerLink="/admin/users" class="breadcrumb-link">Users</a>
<mat-icon class="breadcrumb-separator">chevron_right</mat-icon>
<span class="breadcrumb-current">{{ user()?.username || 'User Detail' }}</span>
</nav>
<!-- Loading State -->
@if (isLoading()) {
<div class="loading-container">
<mat-spinner diameter="48"></mat-spinner>
<p class="loading-text">Loading user details...</p>
</div>
}
<!-- Error State -->
@if (error() && !isLoading()) {
<mat-card class="error-card">
<mat-card-content>
<div class="error-content">
<mat-icon class="error-icon">error</mat-icon>
<h2>Error Loading User</h2>
<p>{{ error() }}</p>
<button mat-raised-button color="primary" (click)="goBack()">
<mat-icon>arrow_back</mat-icon>
Back to Users
</button>
</div>
</mat-card-content>
</mat-card>
}
<!-- User Detail Content -->
@if (user() && !isLoading()) {
<div class="detail-content">
<!-- User Profile Card -->
<mat-card class="profile-card">
<mat-card-header>
<div class="profile-header">
<div class="user-avatar">
<mat-icon>account_circle</mat-icon>
</div>
<div class="user-info">
<h2 class="user-name">{{ user()!.username }}</h2>
<p class="user-email">{{ user()!.email }}</p>
<div class="user-badges">
<mat-chip [class]="'chip-' + getRoleColor(user()!.role)">
<mat-icon>{{ user()!.role === 'admin' ? 'admin_panel_settings' : 'person' }}</mat-icon>
{{ user()!.role | titlecase }}
</mat-chip>
<mat-chip [class]="'chip-' + getStatusColor(user()!.isActive)">
<mat-icon>{{ user()!.isActive ? 'check_circle' : 'cancel' }}</mat-icon>
{{ user()!.isActive ? 'Active' : 'Inactive' }}
</mat-chip>
</div>
</div>
</div>
</mat-card-header>
<mat-card-content>
<div class="profile-details">
<div class="detail-row">
<mat-icon>event</mat-icon>
<div class="detail-info">
<span class="detail-label">Member Since</span>
<span class="detail-value">{{ memberSince() }}</span>
</div>
</div>
<div class="detail-row">
<mat-icon>schedule</mat-icon>
<div class="detail-info">
<span class="detail-label">Last Active</span>
<span class="detail-value">{{ lastActive() }}</span>
</div>
</div>
@if (user()!.metadata?.registrationMethod) {
<div class="detail-row">
<mat-icon>how_to_reg</mat-icon>
<div class="detail-info">
<span class="detail-label">Registration Method</span>
<span class="detail-value">{{ user()!.metadata!.registrationMethod === 'guest_conversion' ? 'Guest Conversion' : 'Direct' }}</span>
</div>
</div>
}
</div>
</mat-card-content>
<mat-card-actions class="profile-actions">
<button mat-raised-button color="primary" (click)="editUserRole()">
<mat-icon>edit</mat-icon>
Edit Role
</button>
<button mat-raised-button [color]="user()!.isActive ? 'warn' : 'accent'" (click)="toggleUserStatus()">
<mat-icon>{{ user()!.isActive ? 'block' : 'check_circle' }}</mat-icon>
{{ user()!.isActive ? 'Deactivate' : 'Activate' }}
</button>
</mat-card-actions>
</mat-card>
<!-- Statistics Cards -->
<div class="stats-grid">
<mat-card class="stat-card">
<mat-card-content>
<div class="stat-icon primary">
<mat-icon>quiz</mat-icon>
</div>
<div class="stat-info">
<h3 class="stat-value">{{ formatNumber(user()!.statistics.totalQuizzes) }}</h3>
<p class="stat-label">Total Quizzes</p>
</div>
</mat-card-content>
</mat-card>
<mat-card class="stat-card">
<mat-card-content>
<div class="stat-icon success">
<mat-icon>grade</mat-icon>
</div>
<div class="stat-info">
<h3 class="stat-value">{{ user()!.statistics.averageScore.toFixed(1) }}%</h3>
<p class="stat-label">Average Score</p>
</div>
</mat-card-content>
</mat-card>
<mat-card class="stat-card">
<mat-card-content>
<div class="stat-icon accent">
<mat-icon>check_circle</mat-icon>
</div>
<div class="stat-info">
<h3 class="stat-value">{{ user()!.statistics.accuracy.toFixed(1) }}%</h3>
<p class="stat-label">Accuracy</p>
</div>
</mat-card-content>
</mat-card>
<mat-card class="stat-card">
<mat-card-content>
<div class="stat-icon warn">
<mat-icon>local_fire_department</mat-icon>
</div>
<div class="stat-info">
<h3 class="stat-value">{{ user()!.statistics.currentStreak }}</h3>
<p class="stat-label">Current Streak</p>
</div>
</mat-card-content>
</mat-card>
<mat-card class="stat-card">
<mat-card-content>
<div class="stat-icon primary">
<mat-icon>help_outline</mat-icon>
</div>
<div class="stat-info">
<h3 class="stat-value">{{ formatNumber(user()!.statistics.totalQuestionsAnswered) }}</h3>
<p class="stat-label">Questions Answered</p>
</div>
</mat-card-content>
</mat-card>
<mat-card class="stat-card">
<mat-card-content>
<div class="stat-icon success">
<mat-icon>timer</mat-icon>
</div>
<div class="stat-info">
<h3 class="stat-value">{{ formatDuration(user()!.statistics.totalTimeSpent) }}</h3>
<p class="stat-label">Time Spent</p>
</div>
</mat-card-content>
</mat-card>
</div>
<!-- Additional Stats Card -->
<mat-card class="additional-stats-card">
<mat-card-header>
<mat-card-title>
<mat-icon>analytics</mat-icon>
Additional Statistics
</mat-card-title>
</mat-card-header>
<mat-card-content>
<div class="stats-details">
<div class="stat-detail-row">
<span class="stat-detail-label">Correct Answers:</span>
<span class="stat-detail-value">{{ formatNumber(user()!.statistics.correctAnswers) }}</span>
</div>
<div class="stat-detail-row">
<span class="stat-detail-label">Longest Streak:</span>
<span class="stat-detail-value">{{ user()!.statistics.longestStreak }} days</span>
</div>
@if (user()!.statistics.favoriteCategory) {
<div class="stat-detail-row">
<span class="stat-detail-label">Favorite Category:</span>
<span class="stat-detail-value">
{{ user()!.statistics.favoriteCategory!.name }}
({{ user()!.statistics.favoriteCategory!.quizCount }} quizzes)
</span>
</div>
}
<div class="stat-detail-row">
<span class="stat-detail-label">Quizzes This Week:</span>
<span class="stat-detail-value">{{ user()!.statistics.recentActivity.quizzesThisWeek }}</span>
</div>
<div class="stat-detail-row">
<span class="stat-detail-label">Quizzes This Month:</span>
<span class="stat-detail-value">{{ user()!.statistics.recentActivity.quizzesThisMonth }}</span>
</div>
</div>
</mat-card-content>
</mat-card>
<!-- Quiz History -->
<mat-card class="quiz-history-card">
<mat-card-header>
<mat-card-title>
<mat-icon>history</mat-icon>
Quiz History
</mat-card-title>
</mat-card-header>
<mat-card-content>
@if (hasQuizHistory()) {
<div class="quiz-history-list">
@for (quiz of user()!.quizHistory; track quiz.id) {
<div class="quiz-history-item">
<div class="quiz-history-header">
<div class="quiz-category">
<mat-icon>category</mat-icon>
<span>{{ quiz.categoryName }}</span>
</div>
<div class="quiz-date">{{ formatDateTime(quiz.completedAt) }}</div>
</div>
<div class="quiz-history-stats">
<div class="quiz-stat">
<mat-icon [class]="'score-icon-' + getScoreColor(quiz.percentage)">grade</mat-icon>
<span class="quiz-stat-label">Score:</span>
<span [class]="'quiz-stat-value-' + getScoreColor(quiz.percentage)">
{{ quiz.score }}/{{ quiz.totalQuestions }} ({{ quiz.percentage.toFixed(1) }}%)
</span>
</div>
<div class="quiz-stat">
<mat-icon>timer</mat-icon>
<span class="quiz-stat-label">Time:</span>
<span class="quiz-stat-value">{{ formatDuration(quiz.timeTaken) }}</span>
</div>
<button mat-icon-button (click)="viewQuizDetails(quiz.id)"
matTooltip="View quiz details" class="quiz-action-btn">
<mat-icon>visibility</mat-icon>
</button>
</div>
</div>
}
</div>
} @else {
<div class="empty-state">
<mat-icon>quiz</mat-icon>
<p>No quiz history available</p>
</div>
}
</mat-card-content>
</mat-card>
<!-- Activity Timeline -->
<mat-card class="activity-timeline-card">
<mat-card-header>
<mat-card-title>
<mat-icon>timeline</mat-icon>
Activity Timeline
</mat-card-title>
</mat-card-header>
<mat-card-content>
@if (hasActivity()) {
<mat-list class="activity-list">
@for (activity of user()!.activityTimeline; track activity.id) {
<mat-list-item class="activity-item">
<mat-icon [class]="'activity-icon-' + getActivityColor(activity.type)" matListItemIcon>
{{ getActivityIcon(activity.type) }}
</mat-icon>
<div matListItemTitle class="activity-description">{{ activity.description }}</div>
<div matListItemLine class="activity-time">{{ formatRelativeTime(activity.timestamp) }}</div>
@if (activity.metadata) {
<div matListItemLine class="activity-metadata">
@if (activity.metadata.categoryName) {
<span class="metadata-item">
<mat-icon>category</mat-icon>
{{ activity.metadata.categoryName }}
</span>
}
@if (activity.metadata.score !== undefined) {
<span class="metadata-item">
<mat-icon>grade</mat-icon>
{{ activity.metadata.score }}%
</span>
}
</div>
}
</mat-list-item>
<mat-divider></mat-divider>
}
</mat-list>
} @else {
<div class="empty-state">
<mat-icon>timeline</mat-icon>
<p>No activity recorded</p>
</div>
}
</mat-card-content>
</mat-card>
</div>
}
</div>