👨🏫 Nexora Teacher Panel
Secure School OS teacher dashboard for assigned classes, attendance, online tests, notes, messages, class links, results and support.
🔐 Teacher Login
Login with Gmail first, then enter the Secret Teacher ID generated by School Manager. No demo login and no localStorage is used.
Gmail login required.
Only School Manager approved teachers can open this dashboard.
Teacher session loading...
👤
My Teacher Profile
View your school, assigned class, section, subject and contact information.
School
Class
Subject
👨🎓
Assigned Students
View students assigned to your class and section.
Students
Class List
📅
Daily Attendance
Mark present, absent or leave for assigned class students and submit daily report.
Present
Absent
Leave
📝
Tests / Class Tasks
Create class test, assignment or paper task for assigned students.
Tests
Assignments
Papers
📚
Notes / Assignments
Send notes, homework, assignments and study instructions to assigned class.
Notes
Homework
💻
Online Class Link
Create Google Meet, Zoom, WhatsApp or other class link notice for students.
Google Meet
Zoom
WhatsApp
📢
Messages
Read school messages and send class messages to students.
School Notice
Class Message
🛠
Support
Send support ticket to School Manager / CEO and review replies.
Support
Reply
👤 My Teacher Profile
👨🎓 Assigned Students
These students are loaded from Firestore based on your assigned school, class and section.
📅 Daily Attendance
Select attendance status for each assigned student and submit daily attendance report.
function renderProfile(){
if(!requireTeacher()) return;
el("profileBox").innerHTML = `
${esc(currentTeacher.teacherName)}
School: ${esc(currentTeacher.schoolName)}
Teacher Gmail: ${esc(currentTeacher.teacherEmail)}
Contact: ${esc(currentTeacher.teacherContact || "-")}
Assigned Class: ${esc(currentTeacher.className)}
Section: ${esc(currentTeacher.section || "-")}
Subject: ${esc(currentTeacher.subject)}
Status: ${esc(currentTeacher.status)}
Teacher ID: ${esc(currentTeacher.teacherId)}
`;
}
window.loadAssignedStudents = async function(){
if(!requireTeacher()) return;
const q = query(
collection(db,"schoolStudentAccess"),
where("schoolId","==",currentTeacher.schoolId),
where("className","==",currentTeacher.className),
where("status","==","Active")
);
const snap = await getDocs(q);
assignedStudents = [];
snap.forEach((item)=>{
const data = item.data();
if(!currentTeacher.section || !data.section || data.section === currentTeacher.section){
assignedStudents.push({
id:item.id,
...data
});
}
});
assignedStudents.sort((a,b)=>String(a.studentName || "").localeCompare(String(b.studentName || "")));
const box = el("studentsListBox");
if(assignedStudents.length === 0){
box.innerHTML = `No assigned students found for your class.
`;
return;
}
let html = ``;
box.innerHTML = html;
};
window.loadAttendanceStudents = async function(){
if(!requireTeacher()) return;
await loadAssignedStudents();
const box = el("attendanceStudentsBox");
if(assignedStudents.length === 0){
box.innerHTML = `No students found for attendance.
`;
return;
}
let html = "";
assignedStudents.forEach((s)=>{
html += `
`;
});
box.innerHTML = html;
};
window.submitDailyAttendance = async function(){
if(!requireTeacher()) return;
const dateValue = el("attendanceDate").value;
if(!dateValue){
alert("Attendance date is required.");
return;
}
if(assignedStudents.length === 0){
await loadAssignedStudents();
}
if(assignedStudents.length === 0){
alert("No students found.");
return;
}
const attendanceItems = [];
let presentCount = 0;
let absentCount = 0;
let leaveCount = 0;
let boysPresent = 0;
let girlsPresent = 0;
assignedStudents.forEach((s)=>{
const status = el("att_" + s.id)?.value || "Present";
const note = el("attNote_" + s.id)?.value || "";
if(status === "Present"){
presentCount++;
if(s.gender === "Boy") boysPresent++;
if(s.gender === "Girl") girlsPresent++;
}
if(status === "Absent") absentCount++;
if(status === "Leave") leaveCount++;
attendanceItems.push({
studentDocId:s.id,
studentId:s.studentId || "",
studentName:s.studentName || "",
regNo:s.regNo || "",
gender:s.gender || "",
status,
note
});
});
await addDoc(collection(db,"schoolDailyAttendance"),{
attendanceId:makeId("ATT"),
schoolId:currentTeacher.schoolId,
schoolName:currentTeacher.schoolName,
teacherId:currentTeacher.teacherId,
teacherName:currentTeacher.teacherName,
teacherEmail:currentTeacher.teacherEmail,
className:currentTeacher.className,
section:currentTeacher.section || "",
subject:currentTeacher.subject,
attendanceDate:dateValue,
students:attendanceItems,
presentCount,
absentCount,
leaveCount,
boysPresent,
girlsPresent,
totalStudents:assignedStudents.length,
createdAt:Date.now(),
updatedAt:serverTimestamp()
});
alert("Daily attendance submitted ✅");
await loadAttendanceHistory();
await refreshAll();
};
async function loadAttendanceHistory(){
if(!requireTeacher()) return;
const rows = await getTeacherRows("schoolDailyAttendance","createdAt");
const box = el("attendanceHistoryBox");
if(rows.length === 0){
box.innerHTML = `No attendance history found.
`;
return;
}
let html = `Attendance History
`;
rows.slice(0,20).forEach((a)=>{
html += `
${esc(a.attendanceDate || formatDate(a.createdAt))}
Class: ${esc(a.className)} ${esc(a.section || "")}
Total: ${esc(a.totalStudents || 0)}
Present: ${esc(a.presentCount || 0)}
Absent: ${esc(a.absentCount || 0)}
Leave: ${esc(a.leaveCount || 0)}
Boys Present: ${esc(a.boysPresent || 0)}
Girls Present: ${esc(a.girlsPresent || 0)}
`;
});
box.innerHTML = html;
}
async function countTeacherRows(collectionName){
try{
const rows = await getTeacherRows(collectionName);
return rows.length;
}catch(error){
return 0;
}
}
window.refreshAll = async function(){
if(!requireTeacher()) return;
await loadAssignedStudents();
const attendance = await countTeacherRows("schoolDailyAttendance");
const tests = await countTeacherRows("schoolClassTasks");
const schoolMessages = await getClassRows("schoolMessages","createdAt");
const teacherMessages = await getTeacherRows("schoolTeacherMessages","createdAt");
el("assignedStudentCount").textContent = assignedStudents.length;
el("teacherAttendanceCount").textContent = attendance;
el("teacherTestCount").textContent = tests;
el("teacherMessageCount").textContent = schoolMessages.length + teacherMessages.length;
};
window.createTeacherTest = async function(){
if(!requireTeacher()) return;
const test = {
testId:makeId("TTEST"),
schoolId:currentTeacher.schoolId,
schoolName:currentTeacher.schoolName,
teacherId:currentTeacher.teacherId,
teacherName:currentTeacher.teacherName,
teacherEmail:currentTeacher.teacherEmail,
className:currentTeacher.className,
section:currentTeacher.section || "",
subject:currentTeacher.subject,
title:el("testTitle").value.trim(),
chapter:el("testChapter").value.trim(),
testCode:el("testCode").value.trim(),
questions:el("testQuestions").value.trim(),
status:"Active",
createdBy:currentUser.email,
createdAt:Date.now(),
updatedAt:serverTimestamp()
};
if(!test.title || !test.testCode || !test.questions){
alert("Test title, test code and questions are required.");
return;
}
await addDoc(collection(db,"schoolClassTasks"),test);
el("testTitle").value = "";
el("testChapter").value = "";
el("testCode").value = "";
el("testQuestions").value = "";
alert("Test / task created successfully ✅");
await loadTeacherTests();
await refreshAll();
};
window.loadTeacherTests = async function(){
if(!requireTeacher()) return;
const tests = await getTeacherRows("schoolClassTasks","createdAt");
const box = el("testsListBox");
if(tests.length === 0){
box.innerHTML = `No tests or class tasks found.
`;
return;
}
let html = "";
tests.forEach((t)=>{
html += `
${esc(t.title)}
Class: ${esc(t.className)} ${esc(t.section || "")}
Subject: ${esc(t.subject)}
Chapter: ${esc(t.chapter || "-")}
Test Code: ${esc(t.testCode)}
Status: ${esc(t.status)}
Questions / Instructions:
${esc(t.questions)}
Date: ${formatDate(t.createdAt)}
`;
});
box.innerHTML = html;
};
window.toggleTeacherTestStatus = async function(id,status){
if(!requireTeacher()) return;
const newStatus = status === "Active" ? "Disabled" : "Active";
await updateDoc(doc(db,"schoolClassTasks",id),{
status:newStatus,
updatedBy:currentUser.email,
updatedAt:serverTimestamp()
});
alert("Test status updated ✅");
await loadTeacherTests();
};
window.deleteTeacherTest = async function(id){
if(!requireTeacher()) return;
if(!confirm("Delete this test / task?")){
return;
}
await deleteDoc(doc(db,"schoolClassTasks",id));
alert("Test deleted ✅");
await loadTeacherTests();
await refreshAll();
};
window.sendClassNote = async function(){
if(!requireTeacher()) return;
const note = {
noteId:makeId("NOTE"),
schoolId:currentTeacher.schoolId,
schoolName:currentTeacher.schoolName,
teacherId:currentTeacher.teacherId,
teacherName:currentTeacher.teacherName,
teacherEmail:currentTeacher.teacherEmail,
className:currentTeacher.className,
section:currentTeacher.section || "",
subject:currentTeacher.subject,
title:el("noteTitle").value.trim(),
type:el("noteType").value,
details:el("noteDetails").value.trim(),
status:"Active",
createdBy:currentUser.email,
createdAt:Date.now(),
updatedAt:serverTimestamp()
};
if(!note.title || !note.details){
alert("Note title and details are required.");
return;
}
await addDoc(collection(db,"schoolClassNotes"),note);
el("noteTitle").value = "";
el("noteDetails").value = "";
el("noteType").value = "Homework";
alert("Class note sent ✅");
await loadClassNotes();
};
window.loadClassNotes = async function(){
if(!requireTeacher()) return;
const notes = await getTeacherRows("schoolClassNotes","createdAt");
const box = el("notesListBox");
if(notes.length === 0){
box.innerHTML = `No class notes found.
`;
return;
}
let html = "";
notes.forEach((n)=>{
html += `
${esc(n.title)}
Type: ${esc(n.type)}
Class: ${esc(n.className)} ${esc(n.section || "")}
Subject: ${esc(n.subject)}
${esc(n.details)}
Status: ${esc(n.status)}
Date: ${formatDate(n.createdAt)}
`;
});
box.innerHTML = html;
};
window.toggleClassNoteStatus = async function(id,status){
if(!requireTeacher()) return;
const newStatus = status === "Active" ? "Disabled" : "Active";
await updateDoc(doc(db,"schoolClassNotes",id),{
status:newStatus,
updatedBy:currentUser.email,
updatedAt:serverTimestamp()
});
alert("Note status updated ✅");
await loadClassNotes();
};
window.deleteClassNote = async function(id){
if(!requireTeacher()) return;
if(!confirm("Delete this note?")){
return;
}
await deleteDoc(doc(db,"schoolClassNotes",id));
alert("Note deleted ✅");
await loadClassNotes();
};
window.createOnlineClassLink = async function(){
if(!requireTeacher()) return;
const onlineClass = {
classLinkId:makeId("ONLINE"),
schoolId:currentTeacher.schoolId,
schoolName:currentTeacher.schoolName,
teacherId:currentTeacher.teacherId,
teacherName:currentTeacher.teacherName,
teacherEmail:currentTeacher.teacherEmail,
className:currentTeacher.className,
section:currentTeacher.section || "",
subject:currentTeacher.subject,
title:el("onlineTitle").value.trim(),
platform:el("onlinePlatform").value,
dateTime:el("onlineDateTime").value.trim(),
classLink:el("onlineLink").value.trim(),
instructions:el("onlineInstructions").value.trim(),
status:"Active",
createdBy:currentUser.email,
createdAt:Date.now(),
updatedAt:serverTimestamp()
};
if(!onlineClass.title || !onlineClass.dateTime || !onlineClass.classLink){
alert("Class title, date/time and class link are required.");
return;
}
await addDoc(collection(db,"schoolOnlineClasses"),onlineClass);
el("onlineTitle").value = "";
el("onlineDateTime").value = "";
el("onlineLink").value = "";
el("onlineInstructions").value = "";
el("onlinePlatform").value = "Google Meet";
alert("Online class notice created ✅");
await loadOnlineClassLinks();
};
window.loadOnlineClassLinks = async function(){
if(!requireTeacher()) return;
const classes = await getTeacherRows("schoolOnlineClasses","createdAt");
const box = el("onlineClassListBox");
if(classes.length === 0){
box.innerHTML = `No online class links found.
`;
return;
}
let html = "";
classes.forEach((c)=>{
html += `
${esc(c.title)}
Platform: ${esc(c.platform)}
Class: ${esc(c.className)} ${esc(c.section || "")}
Subject: ${esc(c.subject)}
Date/Time: ${esc(c.dateTime)}
Link: ${esc(c.classLink)}
Instructions:
${esc(c.instructions || "-")}
Status: ${esc(c.status)}
`;
});
box.innerHTML = html;
};
window.toggleOnlineClassStatus = async function(id,status){
if(!requireTeacher()) return;
const newStatus = status === "Active" ? "Disabled" : "Active";
await updateDoc(doc(db,"schoolOnlineClasses",id),{
status:newStatus,
updatedBy:currentUser.email,
updatedAt:serverTimestamp()
});
alert("Online class status updated ✅");
await loadOnlineClassLinks();
};
window.deleteOnlineClass = async function(id){
if(!requireTeacher()) return;
if(!confirm("Delete this online class link?")){
return;
}
await deleteDoc(doc(db,"schoolOnlineClasses",id));
alert("Online class link deleted ✅");
await loadOnlineClassLinks();
};
window.sendTeacherMessage = async function(){
if(!requireTeacher()) return;
const message = {
messageId:makeId("TMSG"),
schoolId:currentTeacher.schoolId,
schoolName:currentTeacher.schoolName,
teacherId:currentTeacher.teacherId,
teacherName:currentTeacher.teacherName,
teacherEmail:currentTeacher.teacherEmail,
className:currentTeacher.className,
section:currentTeacher.section || "",
subject:currentTeacher.subject,
title:el("messageTitle").value.trim(),
body:el("messageBody").value.trim(),
target:"students",
status:"Active",
createdBy:currentUser.email,
createdAt:Date.now(),
updatedAt:serverTimestamp()
};
if(!message.title || !message.body){
alert("Message title and body are required.");
return;
}
await addDoc(collection(db,"schoolTeacherMessages"),message);
el("messageTitle").value = "";
el("messageBody").value = "";
alert("Class message sent ✅");
await loadMessages();
await refreshAll();
};
window.loadMessages = async function(){
if(!requireTeacher()) return;
const schoolMessages = await getClassRows("schoolMessages","createdAt");
const teacherMessages = await getTeacherRows("schoolTeacherMessages","createdAt");
let allMessages = [];
schoolMessages.forEach((m)=>allMessages.push({...m,source:"School Manager"}));
teacherMessages.forEach((m)=>allMessages.push({...m,source:"Teacher"}));
allMessages.sort((a,b)=>Number(b.createdAt || 0) - Number(a.createdAt || 0));
const box = el("messagesListBox");
if(allMessages.length === 0){
box.innerHTML = `No messages found.
`;
return;
}
let html = "";
allMessages.forEach((m)=>{
html += `
${esc(m.title)}
Source: ${esc(m.source)}
Target: ${esc(m.target || "-")}
${esc(m.body)}
Status: ${esc(m.status || "Active")}
Date: ${formatDate(m.createdAt)}
`;
});
box.innerHTML = html;
};
window.submitTeacherSupport = async function(){
if(!requireTeacher()) return;
const title = el("supportTitle").value.trim();
const details = el("supportDetails").value.trim();
if(!title || !details){
alert("Support title and details are required.");
return;
}
await addDoc(collection(db,"schoolSupportTickets"),{
ticketId:makeId("TSUP"),
schoolId:currentTeacher.schoolId,
schoolName:currentTeacher.schoolName,
teacherId:currentTeacher.teacherId,
teacherName:currentTeacher.teacherName,
teacherEmail:currentTeacher.teacherEmail,
title,
details,
source:"Teacher Panel",
status:"Open",
createdBy:currentUser.email,
createdAt:Date.now(),
updatedAt:serverTimestamp()
});
el("supportTitle").value = "";
el("supportDetails").value = "";
alert("Support ticket submitted ✅");
await loadTeacherSupport();
};
window.loadTeacherSupport = async function(){
if(!requireTeacher()) return;
const q = query(
collection(db,"schoolSupportTickets"),
where("schoolId","==",currentTeacher.schoolId),
where("teacherId","==",currentTeacher.teacherId)
);
const snap = await getDocs(q);
let tickets = [];
snap.forEach((item)=>{
tickets.push({
id:item.id,
...item.data()
});
});
tickets.sort((a,b)=>Number(b.createdAt || 0) - Number(a.createdAt || 0));
const box = el("supportListBox");
if(tickets.length === 0){
box.innerHTML = `No support ticket found.
`;
return;
}
let html = "";
tickets.forEach((s)=>{
html += `
${esc(s.title)}
${esc(s.details)}
Status: ${esc(s.status || "Open")}
Reply: ${esc(s.reply || "No reply yet")}
Date: ${formatDate(s.createdAt)}
`;
});
box.innerHTML = html;
};
window.downloadTeacherBackup = async function(){
if(!requireTeacher()) return;
const backup = {
teacher:currentTeacher,
students:assignedStudents,
data:{},
exportedAt:new Date().toLocaleString()
};
const teacherCollections = [
"schoolDailyAttendance",
"schoolClassTasks",
"schoolClassNotes",
"schoolOnlineClasses",
"schoolTeacherMessages",
"schoolSupportTickets"
];
for(const colName of teacherCollections){
let rows = [];
try{
const q = query(
collection(db,colName),
where("schoolId","==",currentTeacher.schoolId),
where("teacherId","==",currentTeacher.teacherId)
);
const snap = await getDocs(q);
snap.forEach((item)=>{
rows.push({
id:item.id,
...item.data()
});
});
}catch(error){
console.warn("Backup collection failed:",colName,error);
}
backup.data[colName] = rows;
}
downloadTextFile(
"teacher-panel-backup.json",
JSON.stringify(backup,null,2)
);
};