add new changes

This commit is contained in:
AD2025
2025-11-20 00:39:00 +02:00
parent 37b4d565b1
commit b2c564225e
12 changed files with 2734 additions and 34 deletions

View File

@@ -11,6 +11,14 @@ export interface Question {
difficulty: Difficulty;
categoryId: string;
categoryName?: string;
category?: {
id: string;
name: string;
slug?: string;
icon?: string;
color?: string;
guestAccessible?: boolean;
};
options?: string[]; // For multiple choice
correctAnswer: string | string[];
explanation: string;

View File

@@ -747,6 +747,46 @@ export class AdminService {
);
}
/**
* Get all questions with pagination, search, and filtering
* Endpoint: GET /api/admin/questions
*/
getAllQuestions(params: {
page?: number;
limit?: number;
search?: string;
category?: string;
difficulty?: string;
sortBy?: string;
order?: string;
}): Observable<{
success: boolean;
count: number;
total: number;
page: number;
totalPages: number;
limit: number;
filters: any;
data: Question[];
message: string;
}> {
let queryParams: any = {};
if (params.page) queryParams.page = params.page;
if (params.limit) queryParams.limit = params.limit;
if (params.search) queryParams.search = params.search;
if (params.category && params.category !== 'all') queryParams.category = params.category;
if (params.difficulty && params.difficulty !== 'all') queryParams.difficulty = params.difficulty;
if (params.sortBy) queryParams.sortBy = params.sortBy;
if (params.order) queryParams.order = params.order.toUpperCase();
return this.http.get<any>(`${this.apiUrl}/questions`, { params: queryParams }).pipe(
catchError((error: HttpErrorResponse) => this.handleQuestionError(error, 'Failed to load questions'))
);
}
/**
* Delete question (soft delete)
*/

View File

@@ -14,7 +14,6 @@ import { MatRadioModule } from '@angular/material/radio';
import { MatDividerModule } from '@angular/material/divider';
import { MatTooltipModule } from '@angular/material/tooltip';
import { COMMA, ENTER } from '@angular/cdk/keycodes';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { AdminService } from '../../../core/services/admin.service';
import { CategoryService } from '../../../core/services/category.service';
import { Question, QuestionFormData } from '../../../core/models/question.model';
@@ -123,23 +122,22 @@ export class AdminQuestionFormComponent implements OnInit {
this.categoryService.getCategories().subscribe();
// Check if we're in edit mode
this.route.params
.pipe(takeUntilDestroyed())
.subscribe(params => {
const id = params['id'];
if (id) {
this.route.params.subscribe(params => {
const id = params['id'];
if (id) {
// Defer signal updates to avoid ExpressionChangedAfterItHasBeenCheckedError
setTimeout(() => {
this.isEditMode.set(true);
this.questionId.set(id);
this.loadQuestion(id);
}
});
});
}
});
// Watch for question type changes
this.questionForm.get('questionType')?.valueChanges
.pipe(takeUntilDestroyed())
.subscribe((type: QuestionType) => {
this.onQuestionTypeChange(type);
});
this.questionForm.get('questionType')?.valueChanges.subscribe((type: QuestionType) => {
this.onQuestionTypeChange(type);
});
}
/**
@@ -148,9 +146,7 @@ export class AdminQuestionFormComponent implements OnInit {
private loadQuestion(id: string): void {
this.isLoadingQuestion.set(true);
this.adminService.getQuestion(id)
.pipe(takeUntilDestroyed())
.subscribe({
this.adminService.getQuestion(id).subscribe({
next: (response) => {
this.isLoadingQuestion.set(false);
this.populateForm(response.data);
@@ -391,9 +387,7 @@ export class AdminQuestionFormComponent implements OnInit {
? this.adminService.updateQuestion(this.questionId()!, questionData)
: this.adminService.createQuestion(questionData);
serviceCall
.pipe(takeUntilDestroyed())
.subscribe({
serviceCall.subscribe({
next: (response) => {
this.isSubmitting.set(false);
this.router.navigate(['/admin/questions']);

View File

@@ -155,7 +155,7 @@
<ng-container matColumnDef="category">
<th mat-header-cell *matHeaderCellDef>Category</th>
<td mat-cell *matCellDef="let question">
{{ getCategoryName(question.categoryId) }}
{{ getCategoryName(question) }}
</td>
</ng-container>

View File

@@ -177,23 +177,30 @@ export class AdminQuestionsComponent implements OnInit {
page: this.currentPage(),
limit: this.pageSize(),
search: filters.search || undefined,
categoryId: filters.category !== 'all' ? filters.category : undefined,
category: filters.category !== 'all' ? filters.category : undefined,
difficulty: filters.difficulty !== 'all' ? filters.difficulty : undefined,
questionType: filters.type !== 'all' ? filters.type : undefined,
sortBy: filters.sortBy,
sortOrder: filters.sortOrder
order: filters.sortOrder
};
// Remove undefined values
Object.keys(params).forEach(key => params[key] === undefined && delete params[key]);
// TODO: Replace with actual API call when available
// For now, using mock data
setTimeout(() => {
this.questions.set([]);
this.totalQuestions.set(0);
this.isLoading.set(false);
}, 500);
this.adminService.getAllQuestions(params)
.pipe(finalize(() => this.isLoading.set(false)))
.subscribe({
next: (response) => {
this.questions.set(response.data);
this.totalQuestions.set(response.total);
this.currentPage.set(response.page);
},
error: (error) => {
this.error.set(error.message || 'Failed to load questions');
this.questions.set([]);
this.totalQuestions.set(0);
console.error('Load questions error:', error);
}
});
}
/**
@@ -253,11 +260,27 @@ export class AdminQuestionsComponent implements OnInit {
}
/**
* Get category name by ID
* Get category name from question
* The API returns a nested category object with the question
*/
getCategoryName(categoryId: string | number): string {
const category = this.categories().find(c => c.id === categoryId || c.id === categoryId.toString());
return category?.name || 'Unknown';
getCategoryName(question: Question): string {
// First try to get from nested category object (API response)
if (question.category?.name) {
return question.category.name;
}
// Fallback: try to find by categoryId in loaded categories
if (question.categoryId) {
const category = this.categories().find(
c => c.id === question.categoryId || c.id === question.categoryId.toString()
);
if (category) {
return category.name;
}
}
// Last fallback: use categoryName property if available
return question.categoryName || 'Unknown';
}
/**