Version 1.0 upload
This commit is contained in:
@@ -0,0 +1,191 @@
|
||||
// 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.`);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user