191 lines
7.7 KiB
TypeScript
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.`);
|
|
}
|
|
});
|
|
});
|
|
}
|
|
} |