add changes
This commit is contained in:
214
frontend/src/app/features/history/quiz-history.component.html
Normal file
214
frontend/src/app/features/history/quiz-history.component.html
Normal file
@@ -0,0 +1,214 @@
|
||||
<!-- Loading State -->
|
||||
<div *ngIf="isLoading()" class="loading-container">
|
||||
<mat-spinner diameter="50"></mat-spinner>
|
||||
<p>Loading quiz history...</p>
|
||||
</div>
|
||||
|
||||
<!-- Error State -->
|
||||
<div *ngIf="error() && !isLoading()" class="error-container">
|
||||
<mat-icon class="error-icon">error_outline</mat-icon>
|
||||
<h2>Failed to Load History</h2>
|
||||
<p>{{ error() }}</p>
|
||||
<button mat-raised-button color="primary" (click)="loadHistory()">
|
||||
<mat-icon>refresh</mat-icon>
|
||||
Try Again
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- History Content -->
|
||||
<div *ngIf="!isLoading() && !error()" class="history-container">
|
||||
|
||||
<!-- Header -->
|
||||
<div class="history-header">
|
||||
<div class="header-title">
|
||||
<h1>
|
||||
<mat-icon>history</mat-icon>
|
||||
Quiz History
|
||||
</h1>
|
||||
<p class="subtitle">View all your completed quizzes</p>
|
||||
</div>
|
||||
<button mat-raised-button color="primary" (click)="exportToCSV()" [disabled]="isEmpty()">
|
||||
<mat-icon>download</mat-icon>
|
||||
Export CSV
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Filters and Sort -->
|
||||
<mat-card class="filters-card">
|
||||
<mat-card-content>
|
||||
<div class="filters-row">
|
||||
<mat-form-field appearance="outline" class="filter-field">
|
||||
<mat-label>Filter by Category</mat-label>
|
||||
<mat-select [value]="selectedCategory()" (selectionChange)="onCategoryChange($event.value)">
|
||||
<mat-option [value]="null">All Categories</mat-option>
|
||||
<mat-option *ngFor="let category of categories()" [value]="category.id">
|
||||
{{ category.name }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field appearance="outline" class="filter-field">
|
||||
<mat-label>Sort By</mat-label>
|
||||
<mat-select [value]="sortBy()" (selectionChange)="onSortChange($event.value)">
|
||||
<mat-option value="date">Date (Newest First)</mat-option>
|
||||
<mat-option value="score">Score (Highest First)</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
|
||||
<button mat-icon-button (click)="refresh()" matTooltip="Refresh">
|
||||
<mat-icon>refresh</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
|
||||
<!-- Empty State -->
|
||||
<div *ngIf="isEmpty()" class="empty-state">
|
||||
<mat-icon class="empty-icon">quiz</mat-icon>
|
||||
<h2>No Quiz History</h2>
|
||||
<p>You haven't completed any quizzes yet. Start your first quiz to see it here!</p>
|
||||
<button mat-raised-button color="primary" [routerLink]="['/quiz/setup']">
|
||||
<mat-icon>play_arrow</mat-icon>
|
||||
Start a Quiz
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Desktop Table View -->
|
||||
<mat-card class="table-card desktop-only" *ngIf="!isEmpty()">
|
||||
<table mat-table [dataSource]="history()" class="history-table">
|
||||
|
||||
<!-- Date Column -->
|
||||
<ng-container matColumnDef="date">
|
||||
<th mat-header-cell *matHeaderCellDef>Date</th>
|
||||
<td mat-cell *matCellDef="let session">
|
||||
{{ formatDate(session.completedAt || session.startedAt) }}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<!-- Category Column -->
|
||||
<ng-container matColumnDef="category">
|
||||
<th mat-header-cell *matHeaderCellDef>Category</th>
|
||||
<td mat-cell *matCellDef="let session">
|
||||
{{ session.categoryName || 'Unknown' }}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<!-- Score Column -->
|
||||
<ng-container matColumnDef="score">
|
||||
<th mat-header-cell *matHeaderCellDef>Score</th>
|
||||
<td mat-cell *matCellDef="let session">
|
||||
<span class="score-badge" [ngClass]="getScoreColor(session.score, session.totalQuestions)">
|
||||
{{ session.score }}/{{ session.totalQuestions }}
|
||||
<span class="percentage">({{ ((session.score / session.totalQuestions) * 100).toFixed(0) }}%)</span>
|
||||
</span>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<!-- Time Column -->
|
||||
<ng-container matColumnDef="time">
|
||||
<th mat-header-cell *matHeaderCellDef>Time Spent</th>
|
||||
<td mat-cell *matCellDef="let session">
|
||||
{{ formatDuration(session.timeSpent) }}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<!-- Status Column -->
|
||||
<ng-container matColumnDef="status">
|
||||
<th mat-header-cell *matHeaderCellDef>Status</th>
|
||||
<td mat-cell *matCellDef="let session">
|
||||
<mat-chip [ngClass]="getStatusClass(session.status)">
|
||||
{{ session.status === 'in_progress' ? 'In Progress' :
|
||||
session.status === 'completed' ? 'Completed' :
|
||||
'Abandoned' }}
|
||||
</mat-chip>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<!-- Actions Column -->
|
||||
<ng-container matColumnDef="actions">
|
||||
<th mat-header-cell *matHeaderCellDef>Actions</th>
|
||||
<td mat-cell *matCellDef="let session">
|
||||
<button
|
||||
mat-icon-button
|
||||
(click)="viewResults(session.id)"
|
||||
matTooltip="View Results"
|
||||
*ngIf="session.status === 'completed'"
|
||||
>
|
||||
<mat-icon>visibility</mat-icon>
|
||||
</button>
|
||||
<button
|
||||
mat-icon-button
|
||||
(click)="reviewQuiz(session.id)"
|
||||
matTooltip="Review Quiz"
|
||||
*ngIf="session.status === 'completed'"
|
||||
>
|
||||
<mat-icon>rate_review</mat-icon>
|
||||
</button>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
|
||||
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
|
||||
</table>
|
||||
</mat-card>
|
||||
|
||||
<!-- Mobile Card View -->
|
||||
<div class="mobile-cards mobile-only" *ngIf="!isEmpty()">
|
||||
<mat-card *ngFor="let session of history()" class="history-card">
|
||||
<mat-card-content>
|
||||
<div class="card-header">
|
||||
<div class="card-title">
|
||||
<mat-icon>quiz</mat-icon>
|
||||
<span>{{ session.categoryName || 'Unknown' }}</span>
|
||||
</div>
|
||||
<mat-chip [ngClass]="getStatusClass(session.status)">
|
||||
{{ session.status === 'in_progress' ? 'In Progress' :
|
||||
session.status === 'completed' ? 'Completed' :
|
||||
'Abandoned' }}
|
||||
</mat-chip>
|
||||
</div>
|
||||
|
||||
<div class="card-details">
|
||||
<div class="detail-row">
|
||||
<mat-icon>calendar_today</mat-icon>
|
||||
<span>{{ formatDate(session.completedAt || session.startedAt) }}</span>
|
||||
</div>
|
||||
<div class="detail-row">
|
||||
<mat-icon>timer</mat-icon>
|
||||
<span>{{ formatDuration(session.timeSpent) }}</span>
|
||||
</div>
|
||||
<div class="detail-row score-row">
|
||||
<span class="score-label">Score:</span>
|
||||
<span class="score-value" [ngClass]="getScoreColor(session.score, session.totalQuestions)">
|
||||
{{ session.score }}/{{ session.totalQuestions }}
|
||||
({{ ((session.score / session.totalQuestions) * 100).toFixed(0) }}%)
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card-actions" *ngIf="session.status === 'completed'">
|
||||
<button mat-button color="primary" (click)="viewResults(session.id)">
|
||||
<mat-icon>visibility</mat-icon>
|
||||
View Results
|
||||
</button>
|
||||
<button mat-button color="accent" (click)="reviewQuiz(session.id)">
|
||||
<mat-icon>rate_review</mat-icon>
|
||||
Review
|
||||
</button>
|
||||
</div>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
</div>
|
||||
|
||||
<!-- Pagination -->
|
||||
<mat-paginator
|
||||
*ngIf="!isEmpty()"
|
||||
[length]="totalItems()"
|
||||
[pageSize]="pageSize()"
|
||||
[pageIndex]="currentPage() - 1"
|
||||
[pageSizeOptions]="[5, 10, 20, 50]"
|
||||
(page)="onPageChange($event)"
|
||||
showFirstLastButtons
|
||||
>
|
||||
</mat-paginator>
|
||||
</div>
|
||||
Reference in New Issue
Block a user