Update with new components

This commit is contained in:
2025-09-23 19:41:25 +05:30
parent cfe68a276f
commit bd2f5b95ce
129 changed files with 5849 additions and 1169 deletions

View File

@ -0,0 +1,481 @@
<div class="container mt-4">
<!-- Header -->
<div class="row mb-3">
<div class="col">
<h2 class="text-primary">Education & Training Management</h2>
<p class="text-muted">Manage courses, programs, upcoming events and applications</p>
</div>
</div>
<!-- Header Actions -->
<div class="d-flex justify-content-between mb-3">
<div>
<button *ngIf="!showCourseForm && !showApplications && !showUpcomingEvents && !showUpcomingEventForm"
class="btn btn-primary mr-2" (click)="showCourseFormModal()">
<i class="fa fa-plus"></i> New Course
</button>
<button *ngIf="!showCourseForm && !showApplications && !showUpcomingEvents && !showUpcomingEventForm"
class="btn btn-info" (click)="showUpcomingEventsModal()">
<i class="fa fa-calendar"></i> Manage Upcoming Events
</button>
<button *ngIf="showCourseForm" class="btn btn-secondary" (click)="hideCourseForm()">
<i class="fa fa-arrow-left"></i> Back to Courses
</button>
<button *ngIf="showApplications" class="btn btn-secondary" (click)="hideApplications()">
<i class="fa fa-arrow-left"></i> Back to Courses
</button>
<button *ngIf="showUpcomingEvents && !showUpcomingEventForm" class="btn btn-secondary mr-2"
(click)="hideUpcomingEventsModal()">
<i class="fa fa-arrow-left"></i> Back to Courses
</button>
<button *ngIf="showUpcomingEvents && !showUpcomingEventForm" class="btn btn-primary"
(click)="showUpcomingEventFormModal()">
<i class="fa fa-plus"></i> New Event
</button>
<button *ngIf="showUpcomingEventForm" class="btn btn-secondary" (click)="hideUpcomingEventForm()">
<i class="fa fa-arrow-left"></i> Back to Events
</button>
</div>
<div *ngIf="!showCourseForm && !showApplications && !showUpcomingEvents && !showUpcomingEventForm">
<span class="badge badge-info">Total Courses: {{ courses.length }}</span>
<span class="badge badge-warning ml-2">Total Applications: {{ applications.length }}</span>
<span class="badge badge-success ml-2">Upcoming Events: {{ upcomingEvents.length }}</span>
</div>
</div>
<!-- Upcoming Event Form -->
<div *ngIf="showUpcomingEventForm" class="card">
<div class="card-header">
<h5 class="mb-0">{{ editingUpcomingEvent ? 'Edit Upcoming Event' : 'Create New Upcoming Event' }}</h5>
</div>
<div class="card-body">
<form [formGroup]="upcomingEventForm" (ngSubmit)="saveUpcomingEvent()">
<div class="form-group">
<label for="eventTitle" class="text-primary">Event Title *</label>
<input type="text" id="eventTitle" class="form-control" formControlName="title"
placeholder="Enter event title">
<div *ngIf="upcomingEventForm.get('title')?.invalid && upcomingEventForm.get('title')?.touched"
class="text-danger">
Event title is required.
</div>
</div>
<div class="form-group">
<label for="eventDescription" class="text-primary">Event Description *</label>
<textarea id="eventDescription" class="form-control" formControlName="description" rows="4"
placeholder="Enter event description"></textarea>
<div *ngIf="upcomingEventForm.get('description')?.invalid && upcomingEventForm.get('description')?.touched"
class="text-danger">
Event description is required.
</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label for="eventSchedule" class="text-primary">Schedule *</label>
<input type="text" id="eventSchedule" class="form-control" formControlName="schedule"
placeholder="e.g., Q3 2025, Monthly Sessions, Ongoing">
<div *ngIf="upcomingEventForm.get('schedule')?.invalid && upcomingEventForm.get('schedule')?.touched"
class="text-danger">
Schedule is required.
</div>
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label for="eventDate" class="text-primary">Event Date (Optional)</label>
<input type="date" id="eventDate" class="form-control" formControlName="eventDate">
</div>
</div>
</div>
<div class="form-check mb-3">
<input type="checkbox" class="form-check-input" id="eventIsActive" formControlName="isActive">
<label class="form-check-label text-primary" for="eventIsActive">Active (visible on website)</label>
</div>
<div class="form-group">
<button type="submit" class="btn btn-primary" [disabled]="upcomingEventForm.invalid">
<i class="fa fa-save"></i> {{ editingUpcomingEvent ? 'Update Event' : 'Create Event' }}
</button>
<button type="button" class="btn btn-secondary ml-2" (click)="resetUpcomingEventForm()">
<i class="fa fa-times"></i> Cancel
</button>
</div>
</form>
</div>
</div>
<!-- Upcoming Events List -->
<div *ngIf="showUpcomingEvents && !showUpcomingEventForm">
<div class="card">
<div class="card-header">
<h5 class="mb-0">Upcoming Events Management</h5>
</div>
<div class="card-body">
<div *ngIf="upcomingEvents.length > 0">
<table class="table table-striped">
<thead>
<tr>
<th>Title</th>
<th>Description</th>
<th>Schedule</th>
<th>Event Date</th>
<th>Status</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let event of upcomingEvents">
<td>
<strong>{{ event.title }}</strong>
</td>
<td>
<span [title]="event.description">
{{ event.description.length > 100 ? (event.description | slice:0:100) + '...' :
event.description }}
</span>
</td>
<td>{{ event.schedule }}</td>
<td>{{ event.eventDate ? (event.eventDate | date:'short') : 'N/A' }}</td>
<td>
<span *ngIf="event.isActive" class="badge badge-success">Active</span>
<span *ngIf="!event.isActive" class="badge badge-danger">Inactive</span>
</td>
<td>
<button class="btn btn-info btn-sm mr-2" (click)="editUpcomingEvent(event)">
<i class="fa fa-edit"></i> Edit
</button>
<button class="btn btn-danger btn-sm" (click)="deleteUpcomingEvent(event)">
<i class="fa fa-trash"></i> Delete
</button>
</td>
</tr>
</tbody>
</table>
</div>
<div *ngIf="upcomingEvents.length === 0" class="alert alert-info">
No upcoming events available. Please create a new event.
</div>
</div>
</div>
</div>
<!-- Course Form (existing content) -->
<div *ngIf="showCourseForm" class="card">
<div class="card-header">
<h5 class="mb-0">{{ editing ? 'Edit Course' : 'Create New Course' }}</h5>
</div>
<div class="card-body">
<form [formGroup]="courseForm" (ngSubmit)="saveCourse()">
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label for="title" class="text-primary">Course Title *</label>
<input type="text" id="title" class="form-control" formControlName="title"
placeholder="Enter course title">
<div *ngIf="courseForm.get('title')?.invalid && courseForm.get('title')?.touched"
class="text-danger">
Course title is required.
</div>
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label for="instructor" class="text-primary">Instructor *</label>
<input type="text" id="instructor" class="form-control" formControlName="instructor"
placeholder="Enter instructor name">
<div *ngIf="courseForm.get('instructor')?.invalid && courseForm.get('instructor')?.touched"
class="text-danger">
Instructor is required.
</div>
</div>
</div>
</div>
<div class="form-group">
<label for="description" class="text-primary">Course Description *</label>
<textarea id="description" class="form-control" formControlName="description" rows="4"
placeholder="Enter course description"></textarea>
<div *ngIf="courseForm.get('description')?.invalid && courseForm.get('description')?.touched"
class="text-danger">
Course description is required.
</div>
</div>
<div class="row">
<div class="col-md-4">
<div class="form-group">
<label for="duration" class="text-primary">Duration *</label>
<input type="text" id="duration" class="form-control" formControlName="duration"
placeholder="e.g., 3 Days, 2 Years">
<div *ngIf="courseForm.get('duration')?.invalid && courseForm.get('duration')?.touched"
class="text-danger">
Duration is required.
</div>
</div>
</div>
<div class="col-md-4">
<div class="form-group">
<label for="seats" class="text-primary">Number of Seats *</label>
<input type="number" id="seats" class="form-control" formControlName="seats"
placeholder="Enter number of seats" min="1">
<div *ngIf="courseForm.get('seats')?.invalid && courseForm.get('seats')?.touched"
class="text-danger">
Number of seats is required and must be at least 1.
</div>
</div>
</div>
<div class="col-md-4">
<div class="form-group">
<label for="price" class="text-primary">Price</label>
<input type="text" id="price" class="form-control" formControlName="price"
placeholder="e.g., $15,000 or N/A">
</div>
</div>
</div>
<div class="row">
<div class="col-md-4">
<div class="form-group">
<label for="category" class="text-primary">Category *</label>
<select id="category" class="form-control" formControlName="category">
<option value="">Select category</option>
<option value="Certification">Certification</option>
<option value="Training">Training</option>
<option value="Workshop">Workshop</option>
<option value="Fellowship">Fellowship</option>
<option value="Course">Course</option>
</select>
<div *ngIf="courseForm.get('category')?.invalid && courseForm.get('category')?.touched"
class="text-danger">
Category is required.
</div>
</div>
</div>
<div class="col-md-4">
<div class="form-group">
<label for="level" class="text-primary">Level *</label>
<select id="level" class="form-control" formControlName="level">
<option value="">Select level</option>
<option value="Beginner">Beginner</option>
<option value="Intermediate">Intermediate</option>
<option value="Advanced">Advanced</option>
<option value="Professional">Professional</option>
<option value="Post-Doctoral">Post-Doctoral</option>
</select>
<div *ngIf="courseForm.get('level')?.invalid && courseForm.get('level')?.touched"
class="text-danger">
Level is required.
</div>
</div>
</div>
<div class="col-md-4">
<div class="form-group">
<label for="startDate" class="text-primary">Start Date</label>
<input type="date" id="startDate" class="form-control" formControlName="startDate">
</div>
</div>
</div>
<!-- Image Upload Section -->
<div class="form-group">
<label class="text-primary">Course Image</label>
<!-- Image Preview -->
<div *ngIf="imagePreview" class="mb-3">
<div class="position-relative d-inline-block">
<img [src]="getFullImageUrl(imagePreview)" alt="Preview" class="img-thumbnail"
style="max-width: 300px; max-height: 200px;">
<button type="button" class="btn btn-danger btn-sm position-absolute"
style="top: -5px; right: -5px;" (click)="removeImage()">
×
</button>
</div>
</div>
<!-- File Input -->
<div class="mb-2">
<input type="file" id="imageInput" class="form-control" accept="image/*"
(change)="onImageSelected($event)">
<small class="form-text text-muted">Supported formats: JPG, PNG, GIF. Max size: 5MB</small>
</div>
<!-- Upload Error -->
<div *ngIf="uploadError" class="alert alert-danger alert-sm">
{{ uploadError }}
</div>
<!-- Upload Progress -->
<div *ngIf="isImageUploading" class="mb-2">
<div class="d-flex align-items-center">
<div class="spinner-border spinner-border-sm me-2" role="status"></div>
<small class="text-muted">Uploading image...</small>
</div>
</div>
</div>
<div class="form-group">
<label for="eligibility" class="text-primary">Eligibility Criteria</label>
<textarea id="eligibility" class="form-control" formControlName="eligibility" rows="3"
placeholder="Enter eligibility criteria separated by commas"></textarea>
<small class="form-text text-muted">Separate multiple criteria with commas</small>
</div>
<div class="form-group">
<label for="objectives" class="text-primary">Learning Objectives</label>
<textarea id="objectives" class="form-control" formControlName="objectives" rows="3"
placeholder="Enter learning objectives separated by commas"></textarea>
<small class="form-text text-muted">Separate multiple objectives with commas</small>
</div>
<div class="form-check mb-3">
<input type="checkbox" class="form-check-input" id="isActive" formControlName="isActive">
<label class="form-check-label text-primary" for="isActive">Active (visible to students)</label>
</div>
<div class="form-group">
<button type="submit" class="btn btn-primary" [disabled]="courseForm.invalid || isImageUploading">
<i class="fa fa-save"></i> {{ editing ? 'Update Course' : 'Create Course' }}
</button>
<button type="button" class="btn btn-secondary ml-2" (click)="resetCourseForm()">
<i class="fa fa-times"></i> Cancel
</button>
</div>
</form>
</div>
</div>
<!-- Applications View (existing content) -->
<div *ngIf="showApplications && selectedCourseForApplications" class="card">
<div class="card-header">
<h5 class="mb-0">Applications for: {{ selectedCourseForApplications.title }}</h5>
</div>
<div class="card-body">
<div *ngIf="applications.length > 0">
<table class="table table-striped">
<thead>
<tr>
<th>Applicant</th>
<th>Email</th>
<th>Phone</th>
<th>Qualification</th>
<th>Experience</th>
<th>Status</th>
<th>Applied Date</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let application of applications">
<td>{{ application.fullName }}</td>
<td>{{ application.email }}</td>
<td>{{ application.phone }}</td>
<td>{{ application.qualification }}</td>
<td>{{ application.experience || 'N/A' }}</td>
<td>
<span class="badge" [ngClass]="getStatusBadgeClass(application.status || 'pending')">
{{ application.status || 'PENDING' }}
</span>
</td>
<td>{{ application.createdDate | date:'short' }}</td>
<td>
<div class="btn-group dropdown">
<button type="button" class="btn btn-sm btn-outline-primary dropdown-toggle"
data-toggle="dropdown">
Status
</button>
<div class="dropdown-menu">
<a class="dropdown-item"
(click)="updateApplicationStatus(application, 'PENDING')">Pending</a>
<a class="dropdown-item"
(click)="updateApplicationStatus(application, 'REVIEWED')">Reviewed</a>
<a class="dropdown-item"
(click)="updateApplicationStatus(application, 'SHORTLISTED')">Shortlisted</a>
<a class="dropdown-item"
(click)="updateApplicationStatus(application, 'ACCEPTED')">Accepted</a>
<a class="dropdown-item"
(click)="updateApplicationStatus(application, 'ENROLLED')">Enrolled</a>
<a class="dropdown-item"
(click)="updateApplicationStatus(application, 'REJECTED')">Rejected</a>
</div>
</div>
<button class="btn btn-sm btn-danger ml-1" (click)="deleteApplication(application)">
<i class="fa fa-trash"></i>
</button>
</td>
</tr>
</tbody>
</table>
</div>
<div *ngIf="applications.length === 0" class="alert alert-info">
No applications found for this course.
</div>
</div>
</div>
<!-- Courses List (existing content) -->
<div *ngIf="!showCourseForm && !showApplications && !showUpcomingEvents && !showUpcomingEventForm">
<div *ngIf="courses.length > 0">
<table class="table table-striped">
<thead>
<tr>
<th>Image</th>
<th>Course</th>
<th>Category</th>
<th>Duration</th>
<th>Seats</th>
<th>Status</th>
<th>Applications</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let course of courses">
<td>
<img *ngIf="course.imageUrl" [src]="getFullImageUrl(course.imageUrl)"
alt="{{ course.title }}" class="img-thumbnail"
style="width: 60px; height: 60px; object-fit: cover;">
<span *ngIf="!course.imageUrl" class="text-muted">No image</span>
</td>
<td>
<strong>{{ course.title }}</strong>
<br>
<small class="text-muted">{{ course.instructor }}</small>
<br>
<small class="text-muted">{{ course.level }}</small>
</td>
<td>
<span class="badge badge-secondary">{{ course.category }}</span>
</td>
<td>{{ course.duration }}</td>
<td>{{ course.seats }}</td>
<td>
<span *ngIf="course.isActive" class="badge badge-success">Active</span>
<span *ngIf="!course.isActive" class="badge badge-danger">Inactive</span>
</td>
<td>
<button class="btn btn-sm btn-info" (click)="viewApplications(course)">
View Applications
<span class="badge badge-light ml-1">{{ getApplicationCount(course.id) }}</span>
</button>
</td>
<td>
<button class="btn btn-info btn-sm mr-2" (click)="editCourse(course)">
<i class="fa fa-edit"></i> Edit
</button>
<button class="btn btn-danger btn-sm" (click)="deleteCourse(course)">
<i class="fa fa-trash"></i> Delete
</button>
</td>
</tr>
</tbody>
</table>
</div>
<div *ngIf="courses.length === 0" class="alert alert-info">
No courses available. Please create a new course.
</div>
</div>
</div>

View File

@ -0,0 +1,25 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { EducationComponent } from './education.component';
describe('EducationComponent', () => {
let component: EducationComponent;
let fixture: ComponentFixture<EducationComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ EducationComponent ]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(EducationComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,385 @@
// education.component.ts
import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { EducationService, Course, CourseApplication } from '../../service/education.service';
import { UpcomingEventsService, UpcomingEvent } from '../../service/upcoming-events.service';
import { FileUploadService } from '../../service/file-upload.service';
import { environment } from 'src/environments/environment';
@Component({
selector: 'app-education',
templateUrl: './education.component.html',
styleUrls: ['./education.component.css'],
})
export class EducationComponent implements OnInit {
courses: Course[] = [];
applications: CourseApplication[] = [];
upcomingEvents: UpcomingEvent[] = [];
selectedCourse: Course | null = null;
selectedUpcomingEvent: UpcomingEvent | null = null;
courseForm: FormGroup;
upcomingEventForm: FormGroup;
showCourseForm = false;
showUpcomingEventForm = false;
editing = false;
editingUpcomingEvent = false;
showApplications = false;
showUpcomingEvents = false;
// Filter for applications
selectedCourseForApplications: Course | null = null;
// Image upload properties
selectedImage: File | null = null;
imagePreview: string | null = null;
isImageUploading = false;
uploadError: string | null = null;
constructor(
private educationService: EducationService,
private upcomingEventsService: UpcomingEventsService,
private fileUploadService: FileUploadService,
private fb: FormBuilder
) {
this.courseForm = this.fb.group({
title: ['', Validators.required],
description: ['', Validators.required],
duration: ['', Validators.required],
seats: ['', [Validators.required, Validators.min(1)]],
category: ['', Validators.required],
level: ['', Validators.required],
instructor: ['', Validators.required],
price: [''],
startDate: [''],
eligibility: [''],
objectives: [''],
imageUrl: [''],
isActive: [true]
});
this.upcomingEventForm = this.fb.group({
title: ['', Validators.required],
description: ['', Validators.required],
schedule: ['', Validators.required],
eventDate: [''],
isActive: [true]
});
}
ngOnInit(): void {
this.loadCourses();
this.loadApplications();
this.loadUpcomingEvents();
}
loadCourses() {
this.educationService.getAllCourses().subscribe(data => {
this.courses = data;
});
}
loadApplications() {
this.educationService.getAllApplications().subscribe(data => {
this.applications = data;
});
}
getFullImageUrl(imageUrl: string): string {
if (!imageUrl) return '';
// If it's already a full URL, return as-is
if (imageUrl.startsWith('http://') || imageUrl.startsWith('https://')) {
return imageUrl;
}
// Otherwise, prepend your API base URL
return environment.apiUrl + imageUrl;
}
loadUpcomingEvents() {
this.upcomingEventsService.getAllUpcomingEvents().subscribe(data => {
this.upcomingEvents = data;
});
}
// Upcoming Events Management
showUpcomingEventsModal() {
this.showUpcomingEvents = true;
}
hideUpcomingEventsModal() {
this.showUpcomingEvents = false;
this.hideUpcomingEventForm();
}
showUpcomingEventFormModal() {
this.showUpcomingEventForm = true;
this.resetUpcomingEventForm();
setTimeout(() => {
this.upcomingEventForm.patchValue({
isActive: true
});
}, 0);
}
hideUpcomingEventForm() {
this.showUpcomingEventForm = false;
this.resetUpcomingEventForm();
}
editUpcomingEvent(event: UpcomingEvent) {
this.selectedUpcomingEvent = event;
this.upcomingEventForm.patchValue({
title: event.title,
description: event.description,
schedule: event.schedule,
eventDate: event.eventDate || '',
isActive: event.isActive
});
this.editingUpcomingEvent = true;
this.showUpcomingEventForm = true;
}
saveUpcomingEvent() {
if (this.upcomingEventForm.valid) {
const eventData = this.upcomingEventForm.value;
eventData.isActive = this.upcomingEventForm.get('isActive')?.value === true;
if (this.editingUpcomingEvent && this.selectedUpcomingEvent) {
this.upcomingEventsService.updateUpcomingEvent(this.selectedUpcomingEvent.id!, eventData).subscribe(() => {
this.loadUpcomingEvents();
this.hideUpcomingEventForm();
});
} else {
this.upcomingEventsService.createUpcomingEvent(eventData).subscribe(() => {
this.loadUpcomingEvents();
this.hideUpcomingEventForm();
});
}
}
}
deleteUpcomingEvent(event: UpcomingEvent) {
if (confirm('Are you sure you want to delete this upcoming event?')) {
this.upcomingEventsService.deleteUpcomingEvent(event.id!).subscribe(() => {
this.loadUpcomingEvents();
});
}
}
resetUpcomingEventForm() {
this.upcomingEventForm.reset();
this.selectedUpcomingEvent = null;
this.editingUpcomingEvent = false;
this.upcomingEventForm.patchValue({
isActive: true
});
}
showCourseFormModal() {
this.showCourseForm = true;
this.resetCourseForm();
setTimeout(() => {
this.courseForm.patchValue({
isActive: true
});
}, 0);
}
hideCourseForm() {
this.showCourseForm = false;
this.resetCourseForm();
}
editCourse(course: Course) {
this.selectedCourse = course;
this.courseForm.patchValue({
title: course.title,
description: course.description,
duration: course.duration,
seats: course.seats,
category: course.category,
level: course.level,
instructor: course.instructor,
price: course.price || '',
startDate: course.startDate || '',
eligibility: course.eligibility ? course.eligibility.join(', ') : '',
objectives: course.objectives ? course.objectives.join(', ') : '',
imageUrl: course.imageUrl || '',
isActive: course.isActive
});
if (course.imageUrl) {
this.imagePreview = course.imageUrl;
}
this.editing = true;
this.showCourseForm = true;
}
// Image handling methods
onImageSelected(event: any) {
const file = event.target.files[0];
if (file) {
this.selectedImage = file;
this.uploadError = null;
const reader = new FileReader();
reader.onload = (e: any) => {
this.imagePreview = e.target.result;
};
reader.readAsDataURL(file);
}
}
uploadImage(): Promise<string> {
return new Promise((resolve, reject) => {
if (!this.selectedImage) {
resolve('');
return;
}
this.isImageUploading = true;
this.uploadError = null;
this.fileUploadService.uploadFile(this.selectedImage).subscribe({
next: (response) => {
this.isImageUploading = false;
this.courseForm.patchValue({ imageUrl: response.url });
resolve(response.url);
},
error: (error) => {
this.isImageUploading = false;
this.uploadError = error.error?.error || 'Failed to upload image';
reject(error);
}
});
});
}
removeImage() {
this.selectedImage = null;
this.imagePreview = null;
this.courseForm.patchValue({ imageUrl: '' });
this.uploadError = null;
const fileInput = document.getElementById('imageInput') as HTMLInputElement;
if (fileInput) {
fileInput.value = '';
}
}
async saveCourse() {
if (this.courseForm.valid) {
try {
if (this.selectedImage) {
await this.uploadImage();
}
const courseData = this.courseForm.value;
courseData.isActive = this.courseForm.get('isActive')?.value === true;
courseData.eligibility = courseData.eligibility
? courseData.eligibility.split(',').map((item: string) => item.trim()).filter((item: string) => item.length > 0)
: [];
courseData.objectives = courseData.objectives
? courseData.objectives.split(',').map((item: string) => item.trim()).filter((item: string) => item.length > 0)
: [];
if (this.editing && this.selectedCourse) {
this.educationService.updateCourse(this.selectedCourse.id!, courseData).subscribe(() => {
this.loadCourses();
this.hideCourseForm();
});
} else {
this.educationService.createCourse(courseData).subscribe(() => {
this.loadCourses();
this.hideCourseForm();
});
}
} catch (error) {
console.error('Error saving course:', error);
}
}
}
deleteCourse(course: Course) {
if (confirm('Are you sure you want to delete this course?')) {
this.educationService.deleteCourse(course.id!).subscribe(() => {
this.loadCourses();
});
}
}
resetCourseForm() {
this.courseForm.reset();
this.selectedCourse = null;
this.editing = false;
this.selectedImage = null;
this.imagePreview = null;
this.uploadError = null;
this.courseForm.patchValue({
isActive: true
});
const fileInput = document.getElementById('imageInput') as HTMLInputElement;
if (fileInput) {
fileInput.value = '';
}
}
// Application management
viewApplications(course: Course) {
this.selectedCourseForApplications = course;
this.showApplications = true;
this.educationService.getApplicationsByCourseId(course.id!).subscribe(data => {
this.applications = data;
});
}
hideApplications() {
this.showApplications = false;
this.selectedCourseForApplications = null;
this.loadApplications();
}
updateApplicationStatus(application: CourseApplication, status: string) {
this.educationService.updateApplicationStatus(application.id!, status).subscribe(() => {
if (this.selectedCourseForApplications) {
this.viewApplications(this.selectedCourseForApplications);
} else {
this.loadApplications();
}
});
}
deleteApplication(application: CourseApplication) {
if (confirm('Are you sure you want to delete this application?')) {
this.educationService.deleteApplication(application.id!).subscribe(() => {
if (this.selectedCourseForApplications) {
this.viewApplications(this.selectedCourseForApplications);
} else {
this.loadApplications();
}
});
}
}
getStatusBadgeClass(status: string): string {
switch (status?.toLowerCase()) {
case 'pending': return 'badge-warning';
case 'reviewed': return 'badge-info';
case 'shortlisted': return 'badge-primary';
case 'accepted': return 'badge-success';
case 'enrolled': return 'badge-success';
case 'rejected': return 'badge-danger';
default: return 'badge-light';
}
}
getApplicationCount(courseId?: number): number {
if (!courseId) return 0;
return this.applications.filter(app => app.course?.id === courseId).length;
}}