227 lines
8.1 KiB
HTML
227 lines
8.1 KiB
HTML
<div class="admin-questions-container">
|
|
<!-- Header -->
|
|
<div class="page-header">
|
|
<div class="header-content">
|
|
<div class="title-section">
|
|
<mat-icon class="header-icon">quiz</mat-icon>
|
|
<div>
|
|
<h1>Question Management</h1>
|
|
<p class="subtitle">Create, edit, and manage quiz questions</p>
|
|
</div>
|
|
</div>
|
|
<button mat-raised-button color="primary" (click)="createQuestion()">
|
|
<mat-icon>add</mat-icon>
|
|
Create Question
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Filters Card -->
|
|
<mat-card class="filters-card">
|
|
<mat-card-content>
|
|
<form [formGroup]="filterForm" class="filters-form">
|
|
<!-- Search -->
|
|
<mat-form-field appearance="outline" class="search-field">
|
|
<mat-label>Search Questions</mat-label>
|
|
<input matInput formControlName="search" placeholder="Search by question text...">
|
|
<mat-icon matPrefix>search</mat-icon>
|
|
</mat-form-field>
|
|
|
|
<!-- Category Filter -->
|
|
<mat-form-field appearance="outline">
|
|
<mat-label>Category</mat-label>
|
|
<mat-select formControlName="category">
|
|
<mat-option value="all">All Categories</mat-option>
|
|
@for (category of categories(); track category.id) {
|
|
<mat-option [value]="category.id">{{ category.name }}</mat-option>
|
|
}
|
|
</mat-select>
|
|
</mat-form-field>
|
|
|
|
<!-- Difficulty Filter -->
|
|
<mat-form-field appearance="outline">
|
|
<mat-label>Difficulty</mat-label>
|
|
<mat-select formControlName="difficulty">
|
|
<mat-option value="all">All Difficulties</mat-option>
|
|
<mat-option value="easy">Easy</mat-option>
|
|
<mat-option value="medium">Medium</mat-option>
|
|
<mat-option value="hard">Hard</mat-option>
|
|
</mat-select>
|
|
</mat-form-field>
|
|
|
|
<!-- Type Filter -->
|
|
<mat-form-field appearance="outline">
|
|
<mat-label>Type</mat-label>
|
|
<mat-select formControlName="type">
|
|
<mat-option value="all">All Types</mat-option>
|
|
<mat-option value="multiple_choice">Multiple Choice</mat-option>
|
|
<mat-option value="true_false">True/False</mat-option>
|
|
<mat-option value="written">Written</mat-option>
|
|
</mat-select>
|
|
</mat-form-field>
|
|
|
|
<!-- Sort By -->
|
|
<mat-form-field appearance="outline">
|
|
<mat-label>Sort By</mat-label>
|
|
<mat-select formControlName="sortBy">
|
|
<mat-option value="createdAt">Date Created</mat-option>
|
|
<mat-option value="questionText">Question Text</mat-option>
|
|
<mat-option value="difficulty">Difficulty</mat-option>
|
|
<mat-option value="points">Points</mat-option>
|
|
</mat-select>
|
|
</mat-form-field>
|
|
|
|
<!-- Sort Order -->
|
|
<mat-form-field appearance="outline">
|
|
<mat-label>Order</mat-label>
|
|
<mat-select formControlName="sortOrder">
|
|
<mat-option value="asc">Ascending</mat-option>
|
|
<mat-option value="desc">Descending</mat-option>
|
|
</mat-select>
|
|
</mat-form-field>
|
|
</form>
|
|
</mat-card-content>
|
|
</mat-card>
|
|
|
|
<!-- Results Card -->
|
|
<mat-card class="results-card">
|
|
<!-- Loading State -->
|
|
@if (isLoading()) {
|
|
<div class="loading-container">
|
|
<mat-spinner diameter="50"></mat-spinner>
|
|
<p>Loading questions...</p>
|
|
</div>
|
|
}
|
|
|
|
<!-- Error State -->
|
|
@else if (error()) {
|
|
<div class="error-container">
|
|
<mat-icon color="warn">error</mat-icon>
|
|
<p>{{ error() }}</p>
|
|
<button mat-raised-button color="primary" (click)="loadQuestions()">
|
|
<mat-icon>refresh</mat-icon>
|
|
Retry
|
|
</button>
|
|
</div>
|
|
}
|
|
|
|
<!-- Empty State -->
|
|
@else if (questions().length === 0) {
|
|
<div class="empty-container">
|
|
<mat-icon>quiz</mat-icon>
|
|
<h3>No Questions Found</h3>
|
|
<p>No questions match your current filters. Try adjusting your search criteria.</p>
|
|
<button mat-raised-button color="primary" (click)="createQuestion()">
|
|
<mat-icon>add</mat-icon>
|
|
Create First Question
|
|
</button>
|
|
</div>
|
|
}
|
|
|
|
<!-- Questions Table (Desktop) -->
|
|
@else {
|
|
<div class="table-container">
|
|
<table mat-table [dataSource]="questions()" class="questions-table">
|
|
<!-- Question Text Column -->
|
|
<ng-container matColumnDef="questionText">
|
|
<th mat-header-cell *matHeaderCellDef>Question</th>
|
|
<td mat-cell *matCellDef="let question">
|
|
<div class="question-text-cell">
|
|
{{ question.questionText.substring(0, 100) }}{{ question.questionText.length > 100 ? '...' : '' }}
|
|
</div>
|
|
</td>
|
|
</ng-container>
|
|
|
|
<!-- Type Column -->
|
|
<ng-container matColumnDef="type">
|
|
<th mat-header-cell *matHeaderCellDef>Type</th>
|
|
<td mat-cell *matCellDef="let question">
|
|
<mat-chip>
|
|
@if (question.questionType === 'multiple_choice') {
|
|
<mat-icon>radio_button_checked</mat-icon>
|
|
<span>MCQ</span>
|
|
} @else if (question.questionType === 'true_false') {
|
|
<mat-icon>check_circle</mat-icon>
|
|
<span>T/F</span>
|
|
} @else {
|
|
<mat-icon>edit_note</mat-icon>
|
|
<span>Written</span>
|
|
}
|
|
</mat-chip>
|
|
</td>
|
|
</ng-container>
|
|
|
|
<!-- Category Column -->
|
|
<ng-container matColumnDef="category">
|
|
<th mat-header-cell *matHeaderCellDef>Category</th>
|
|
<td mat-cell *matCellDef="let question">
|
|
{{ getCategoryName(question) }}
|
|
</td>
|
|
</ng-container>
|
|
|
|
<!-- Difficulty Column -->
|
|
<ng-container matColumnDef="difficulty">
|
|
<th mat-header-cell *matHeaderCellDef>Difficulty</th>
|
|
<td mat-cell *matCellDef="let question">
|
|
<mat-chip [color]="getDifficultyColor(question.difficulty)">
|
|
{{ question.difficulty }}
|
|
</mat-chip>
|
|
</td>
|
|
</ng-container>
|
|
|
|
<!-- Points Column -->
|
|
<ng-container matColumnDef="points">
|
|
<th mat-header-cell *matHeaderCellDef>Points</th>
|
|
<td mat-cell *matCellDef="let question">
|
|
<span class="points-badge">{{ question.points }}</span>
|
|
</td>
|
|
</ng-container>
|
|
|
|
<!-- Status Column -->
|
|
<ng-container matColumnDef="status">
|
|
<th mat-header-cell *matHeaderCellDef>Status</th>
|
|
<td mat-cell *matCellDef="let question">
|
|
<mat-chip [color]="getStatusColor(question.isActive)">
|
|
{{ question.isActive ? 'Active' : 'Inactive' }}
|
|
</mat-chip>
|
|
</td>
|
|
</ng-container>
|
|
|
|
<!-- Actions Column -->
|
|
<ng-container matColumnDef="actions">
|
|
<th mat-header-cell *matHeaderCellDef>Actions</th>
|
|
<td mat-cell *matCellDef="let question">
|
|
<div class="action-buttons">
|
|
<button mat-icon-button color="primary"
|
|
(click)="editQuestion(question)"
|
|
matTooltip="Edit Question">
|
|
<mat-icon>edit</mat-icon>
|
|
</button>
|
|
<button mat-icon-button color="warn"
|
|
(click)="deleteQuestion(question)"
|
|
matTooltip="Delete Question">
|
|
<mat-icon>delete</mat-icon>
|
|
</button>
|
|
</div>
|
|
</td>
|
|
</ng-container>
|
|
|
|
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
|
|
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
|
|
</table>
|
|
</div>
|
|
|
|
<!-- Pagination -->
|
|
<app-pagination
|
|
[state]="paginationState()"
|
|
[pageNumbers]="pageNumbers()"
|
|
[pageSizeOptions]="[10, 25, 50, 100]"
|
|
[showFirstLast]="true"
|
|
[itemLabel]="'questions'"
|
|
(pageChange)="goToPage($event)"
|
|
(pageSizeChange)="onPageSizeChange($event)">
|
|
</app-pagination>
|
|
}
|
|
</mat-card>
|
|
</div>
|