| 📦 Repository | Vishnumgit/feedback |
| 📝 Description | A multi-role feedback collection and analytics system for educational institutions with Student, Teacher, and Admin portals |
| 👤 Author | P Vishnuvardhan Reddy (Vishnumgit) |
| 🏫 Institution | MGIT — Mahatma Gandhi Institute of Technology |
| 📅 Created | 12 March 2026 |
| 🌐 Visibility | Public |
| 🗃 Total Size | 137 KB (15 files + 2 folders) |
| 💻 Language | HTML, CSS, JavaScript (Vanilla — No frameworks) |
| 🗄 Database | Firebase Firestore (Cloud) + localStorage (Offline) |
| 📊 Charts | Chart.js 4.4.0 (Radar, Bar, Doughnut, Trend) |
| Collection | localStorage Key | Purpose |
|---|---|---|
| users | sfft_users | All student, teacher, admin accounts |
| subjects | sfft_subjects | Academic subjects (Math, Physics, etc.) |
| questionnaires | sfft_questionnaires | Subject-specific feedback question sets |
| enrollments | sfft_enrollments | Student-teacher assignment mappings |
| responses | sfft_responses | Submitted feedback with scores & comments |
| attendance | sfft_attendance | Student attendance records per section |
| settings | sfft_settings | College name, domain, min threshold |
| File | Lines | Size | Purpose |
|---|---|---|---|
| admin-dashboard.html | 1,968 | 104 KB | Full admin panel (7 tabs, reports, user mgmt) |
| teacher-dashboard.html | 877 | 49 KB | Teacher portal (analytics, charts, report gen) |
| student-dashboard.html | 489 | 25 KB | Student portal (profile, feedback status) |
| feedback-form.html | 261 | 12 KB | Feedback submission form |
| style.css | 523 | 24 KB | Global dark theme styles |
| data.js | 309 | 17 KB | localStorage data layer (CRUD, analytics) |
| firebase-sync.js | 237 | 10 KB | Firestore background sync |
| charts.js | 125 | 4 KB | Chart.js rendering helpers |
| auth.js | 76 | 3 KB | Authentication & session management |
| firebase-config.js | 18 | 646 B | Firebase initialization |
| fix_emojis.js | 99 | 3 KB | Emoji compatibility fixes |
| index.html | 63 | 3 KB | Landing page / role selection |
| admin-login.html | 127 | 6 KB | Admin login page |
| teacher-login.html | 125 | 6 KB | Teacher login page |
| student-login.html | 137 | 6 KB | Student login page |
Create, edit, delete students/teachers. Bulk CSV import. Select All + Delete Selected with Firestore sync.
CRUDBulk ImportAdd/remove subjects. Build multi-section feedback questionnaires per subject.
Dynamic FormsMulti-SectionAssign students to teachers with visual checklist cards. Roll No display. Section grouping.
Visual CardsRoll NoView all submissions with filters. Select All checkbox. Delete Selected + Clear All with Firestore sync.
FiltersFirestore DeleteInstitution-wide charts. Per-teacher breakdown. Downloadable HTML report with SVG charts.
ChartsDownload ReportUpload CSV attendance. 75% threshold gate. College name, domain, min threshold config.
CSV UploadConfigScore cards, radar chart, bar chart, trend line. Status banner. Category breakdown.
Beautiful HTML report with SVG charts, summary cards, data table, comments. Print/PDF.
Multi-section questionnaire with 1-5 star ratings. Anonymous option. Attendance-gated.
Profile with Roll No. Assigned teachers list. Submission status per teacher.
DB object mapping 7 collection names (USERS, SUBJECTS, QUESTIONNAIRES, ENROLLMENTS, RESPONSES, ATTENDANCE, SETTINGS) to their sfft_* localStorage keys. Centralises all key strings to prevent typos across the codebase.get()/set() parse/stringify JSON arrays, getObj()/setObj() do the same for plain objects. Used by every higher-level function to read/write localStorage.hashPassword) — Async function. Tries crypto.subtle.digest('SHA-256') (available only on HTTPS). Falls back to a self-contained pure-JS SHA-256 implementation for HTTP environments. Returns a lowercase hex string. Both admin, teacher and student default demo passwords are pre-hashed with this function.initDB) — Runs once per device (guarded by sfft_initialized flag). Seeds: 1 admin + 3 sample teachers + 5 sample students with SHA-256 hashed passwords; 5 subjects; detailed 5-section questionnaires per subject (Math, Physics, English, CS, Chemistry); empty arrays for enrollments, attendance and responses; default settings object with college domain, name and minimum score threshold.getSettings() returns the settings object; saveSettings(s) persists it. Used by admin panel to store/read college name, email domain and min threshold.getUsers(), getUserByEmail() (case-insensitive), getUserById(). saveUser(u) upserts by id. deleteUser(id) removes a user and cascades deletion of their enrollments and responses. getTeachers()/getStudents() are role-filtered views.getEnrollments() returns all enrollment records. getTeachersForStudent(studentId) returns teacher objects augmented with _enrolledSubjectId — one entry per teacher-subject pair. getStudentsForTeacher(teacherId) returns matching student objects.hasSubmitted(studentId, teacherId, subjectId) checks if feedback already exists for the specific teacher+subject pair. saveResponse(r) inserts a response only if no duplicate exists. getResponsesForTeacher(teacherId) returns all responses for a teacher. getTeacherStats(teacherId) computes overall average, per-section averages, rating distribution histogram, trend data and comment list from the stored responses.SESSION_KEY constant for sessionStorage. generateSessionToken() creates a random token (timestamp base-36 + random suffix) to detect concurrent logins.fetchUserFromFirestore) — When a user logs in on a new device and their data isn't in localStorage yet, this async function queries the Firestore users collection by email and merges the result into localStorage. Handles case-sensitivity differences in stored emails.login) — Resolves the local user, then calls Firebase auth.signInWithEmailAndPassword. If the Firebase account doesn't exist yet (first login after admin setup), it auto-creates a Firebase Auth account using the supplied password (auto-migration). Falls back to anonymous sign-in if creation fails. Writes the user doc to Firestore as a non-blocking background operation (errors are caught and logged as console warnings), stores Firebase UID in localStorage, and saves a session object in sessionStorage.googleLogin, googleLoginWithPopup) — googleLogin decodes the Google JWT, looks up the user by email, signs in with Firebase signInWithCredential, and creates a session. googleLoginWithPopup wraps Google Identity Services (GIS) one-tap prompt with a rendered fallback button if the prompt is suppressed.startSessionListener) — Writes the session token to the Firestore user doc, then subscribes to real-time updates. If another device changes the token, the listener signs the current session out and redirects to the home page with an alert.logout() clears sessionStorage and Firebase Auth state. getSession() reads the current session. requireAuth(expectedRole) redirects to home if no session or role mismatch — called at the top of every dashboard.changePassword() verifies the current password (hashed), updates Firebase Auth password, rehashes and saves the new password in localStorage and Firestore. adminResetPassword() skips the current-password check (admin only). validateCollegeEmail() checks that the email domain matches the configured college domain.fsSetDoc(collection, docId, data) strips password and passwordHash fields before writing (security). For the users collection it prefers the Firebase UID as the document key. fsDeleteDoc(collection, docId) deletes a Firestore document; both functions catch errors and log console warnings without propagating them, so the UI is never blocked by sync failures.mergeById(arr, item) upserts an item into an array matching on id or email (fallback). mergeByField(arr, item, field) does the same for arbitrary fields (used for enrollments and attendance). Prevents duplicates when Firestore snapshots arrive out of order.syncFromFirestore(role, userId) fetches only the data relevant to the logged-in role. Students fetch their own enrollments and responses. Teachers fetch responses for their teacher ID. Admins fetch all collections. A 5-minute timestamp cache prevents redundant Firestore reads.pushToFirestore() reads every localStorage collection and writes each item to Firestore as a separate document. Called non-blocking (not awaited) after any write operation so the UI stays responsive.setupRealtimeSync(role, userId) attaches Firestore onSnapshot listeners so that changes made by an admin (new users, enrollments, settings) propagate to other open sessions without a page reload. Updates are merged into localStorage via the helper functions above.chartInstances object tracks live Chart.js instances by canvas ID. destroyChart(id) destroys an existing chart before re-rendering to prevent memory leaks and duplicate canvas contexts.renderRadar(canvasId, teacherId) — Calls getTeacherStats() from data.js, extracts section labels and averages, and renders a purple radar chart showing performance across teaching categories (e.g., Teaching Methodology, Communication Skills, etc.).renderBar(canvasId, teacherId) — Renders a stacked bar chart showing the distribution of 1–5 star ratings for a teacher. Each bar is colour-coded (red → green → purple) for quick visual interpretation of feedback quality.renderTrend(canvasId, teacherId) — Renders a filled line (area) chart of average score over time (each submission as a data point). Uses the trendData array from getTeacherStats() to show performance evolution.renderInstitutionBar(canvasId) — Admin-only chart. Calls getInstitutionStats() (returns per-teacher averages) and renders a bar chart comparing all teachers side-by-side. Cycles through 6 purple shades for visual variety.style.css, Firebase SDK, data.js, auth.js and firebase-sync.js. All scripts deferred so the form HTML is parsed first.requireAuth('student'), then reads the teacher and subject IDs from URL params. Fetches the student's attendance record and compares it against ATTENDANCE_THRESHOLD (75%). If below threshold, replaces the form with a locked message showing the student's actual percentage.hasSubmitted(studentId, teacherId, subjectId). If true, shows a "Feedback already submitted" banner and hides the form. Prevents duplicate responses for the same teacher-subject pair.data.js. For each section, generates a card with the section title and a 1–5 star rating input (radio buttons styled as stars) for each question. All sections are rendered dynamically — no hardcoded questions in HTML.{ studentId, teacherId, subjectId, scores, comment, anonymous, timestamp }), calls saveResponse() and fsSetDoc() to persist locally and to Firestore. Redirects back to the student dashboard on success.style.css, Firebase, data/auth/sync scripts, and renders a sidebar with the student's name and role badge.getTeachersForStudent(). For each pair, checks hasSubmitted() and renders a green "Submitted ✓" badge or a "Give Feedback" button. The button navigates to feedback-form.html with the teacher and subject IDs as URL query parameters.requireAuth('student') guard, Firestore sync, then calls render functions for each tab. Handles tab switching via sidebar nav items. Change-password modal and logout are in the header area.style.css, data.js, charts.js, auth.js, firebase-sync.js. Script load order matters: data.js must come before charts.js since charts call getTeacherStats().charts.js helpers. A status banner shows green/amber/red based on the score relative to the minimum threshold from settings.generateReport() function builds a self-contained HTML string with inline SVG bar/radar charts, a summary card grid, a full data table and a comments section. Opens in a new tab via window.open() (note: may be blocked by the browser's popup blocker — users should allow popups for the site). The report uses @media print so it can be saved as PDF from the browser print dialog.requireAuth('teacher') guard, then syncFromFirestore('teacher'). Renders all tabs. Change-password modal POSTs to changePassword() in auth.js. Logout clears the session and redirects to index.html.renderInstitutionBar()). Shows per-teacher summary cards with average score, response count and a colour-coded performance badge.fsSetDoc/fsDeleteDoc. Table sorted by roll number for students.sfft_questionnaires localStorage key and synced to Firestore.sfft_attendance. "Clear All Attendance" button with Firestore sync. Used by the feedback form's attendance gate.sfft_settings and Firestore. The init block at the bottom runs requireAuth('admin'), syncFromFirestore('admin'), seeds demo data via initDB(), and renders the default tab. Also registers the service worker for push notifications.firebase.initializeApp(firebaseConfig) and exports db = firebase.firestore() and auth = firebase.auth() as global variables used by all other scripts. Uses the Firebase Compat SDK (v8 API) to avoid ES module bundling requirements.