lms-frontend/src/widgets/StudentTableWidget.ts
2025-04-08 00:05:15 +08:00

191 lines
7.7 KiB
TypeScript

// widgets/StudentTableWidget.ts
import { Widget } from '../components/Widget';
import { createElement, navigateTo } from '../utils/utils';
import { globalAPI, ApiResponse, StudentListData } from '../api/api';
export class StudentTableWidget extends Widget {
private students: StudentListData[] = [];
private yearFilter: string = 'all';
private courseFilter: string = 'all';
private availableYears: string[] = ['all', '1', '2', '3', '4'];
private availableCourses: string[] = ['all', 'Math', 'Science', 'History', 'English'];
constructor() {
super();
this.fetchStudentData();
}
async fetchStudentData() {
try {
const response: ApiResponse<StudentListData[]> = await globalAPI.getStudentList();
if (response.success && response.data) {
this.students = response.data;
this.render();
} else {
console.error("Failed to fetch student list");
}
} catch (error) {
console.error("Error fetching student list:", error);
}
}
render(): HTMLElement {
this.container.innerHTML = '';
const header = createElement('div');
header.classList.add('widget-header');
header.textContent = 'Manage Students';
this.container.appendChild(header);
const widgetBody = createElement('div');
widgetBody.classList.add('widget-body');
// Filters
const filtersRow = createElement('div');
filtersRow.classList.add('row', 'mb-3', 'g-3', 'align-items-center');
// Year Level Filter
const yearFilterCol = createElement('div');
yearFilterCol.classList.add('col-auto');
const yearFilterLabel = createElement('label') as HTMLLabelElement; // Cast first
yearFilterLabel.classList.add('col-form-label', 'me-2');
yearFilterLabel.htmlFor = 'yearLevelFilter'; // Set htmlFor as property
yearFilterLabel.textContent = 'Year Level:';
const yearFilterSelect = createElement('select') as HTMLSelectElement;
yearFilterSelect.classList.add('form-select');
yearFilterSelect.id = 'yearLevelFilter';
this.availableYears.forEach(year => {
const option = createElement('option');
option.value = year;
option.textContent = year === 'all' ? 'All Years' : `Year ${year}`;
yearFilterSelect.appendChild(option);
});
yearFilterSelect.value = this.yearFilter;
yearFilterSelect.addEventListener('change', (e) => {
this.yearFilter = (e.target as HTMLSelectElement).value;
this.renderTable(widgetBody);
});
yearFilterCol.appendChild(yearFilterLabel);
yearFilterCol.appendChild(yearFilterSelect);
filtersRow.appendChild(yearFilterCol);
// Course Filter
const courseFilterCol = createElement('div');
courseFilterCol.classList.add('col-auto');
const courseFilterLabel = createElement('label') as HTMLLabelElement; // Cast first
courseFilterLabel.classList.add('col-form-label', 'me-2');
courseFilterLabel.htmlFor = 'courseFilter'; // Set htmlFor as property
courseFilterLabel.textContent = 'Course:';
const courseFilterSelect = createElement('select') as HTMLSelectElement;
courseFilterSelect.classList.add('form-select');
courseFilterSelect.id = 'courseFilter';
this.availableCourses.forEach(course => {
const option = createElement('option');
option.value = course;
option.textContent = course === 'all' ? 'All Courses' : course;
courseFilterSelect.appendChild(option);
});
courseFilterSelect.value = this.courseFilter;
courseFilterSelect.addEventListener('change', (e) => {
this.courseFilter = (e.target as HTMLSelectElement).value;
this.renderTable(widgetBody);
});
courseFilterCol.appendChild(courseFilterLabel);
courseFilterCol.appendChild(courseFilterSelect);
filtersRow.appendChild(courseFilterCol);
widgetBody.appendChild(filtersRow);
// Table Container
const tableContainer = createElement('div');
widgetBody.appendChild(tableContainer);
this.renderTable(tableContainer);
// "Add" button and Batch Add
const addButtonRow = createElement('div');
addButtonRow.classList.add('row', 'mt-3', 'justify-content-between', 'align-items-center');
const addButtonCol = createElement('div');
addButtonCol.classList.add('col-auto');
const addButton = createElement('button');
addButton.classList.add('btn', 'btn-success', 'btn-sm', 'me-2');
addButton.textContent = 'Add Student';
addButtonCol.appendChild(addButton);
addButtonRow.appendChild(addButtonCol);
const batchAddCol = createElement('div');
batchAddCol.classList.add('col-auto');
const batchAddLink = createElement('a');
batchAddLink.href = '#/batch-add-students';
batchAddLink.textContent = 'Batch Add Students';
batchAddCol.appendChild(batchAddLink);
addButtonRow.appendChild(batchAddCol);
widgetBody.appendChild(addButtonRow);
this.container.appendChild(widgetBody);
return this.container;
}
private renderTable(container: HTMLElement) {
container.innerHTML = '';
const table = createElement('table');
table.classList.add('table', 'table-striped', 'table-bordered');
const thead = createElement('thead');
thead.innerHTML = `
<tr>
<th>ID</th>
<th>Name</th>
<th>Year Level</th>
<th>Courses</th>
<th>Actions</th>
</tr>
`;
table.appendChild(thead);
const tbody = createElement('tbody');
const filteredStudents = this.students.filter(student => {
const yearMatch = this.yearFilter === 'all' || student.yearLevel === this.yearFilter;
const courseMatch = this.courseFilter === 'all' || student.courses.includes(this.courseFilter);
return yearMatch && courseMatch;
});
filteredStudents.forEach(student => {
const row = createElement('tr');
row.innerHTML = `
<td>${student.id}</td>
<td>${student.name}</td>
<td>${student.yearLevel}</td>
<td>${student.courses.join(', ')}</td>
<td>
<button class="btn btn-info btn-sm view-profile-btn" data-student-id="${student.id}">View Profile</button>
<button class="btn btn-secondary btn-sm enroll-btn" data-student-id="${student.id}">Enroll</button>
</td>
`;
tbody.appendChild(row);
});
table.appendChild(tbody);
container.appendChild(table);
this.attachTableEventListeners(table);
}
private attachTableEventListeners(table: HTMLTableElement) {
table.querySelectorAll('.view-profile-btn').forEach(button => {
button.addEventListener('click', (event) => {
const studentId = (event.target as HTMLElement).dataset.studentId;
if (studentId) {
navigateTo(`/profile?studentId=${studentId}`);
}
});
});
table.querySelectorAll('.enroll-btn').forEach(button => {
button.addEventListener('click', (event) => {
const studentId = (event.target as HTMLElement).dataset.studentId;
if (studentId) {
alert(`Enroll functionality for student ID ${studentId} - Not fully implemented in prototype.`);
}
});
});
}
}