├── Backend ├── .gitignore ├── models │ ├── feedback.js │ └── studentDetails.js ├── package-lock.json ├── package.json ├── routes │ ├── dashboard.js │ ├── externalres.js │ ├── feedback.js │ ├── fetchqr.js │ ├── getSemSubjects.js │ ├── gethallticketnumfromnetraid.js │ ├── internalres.js │ ├── livesearch.js │ ├── netraid.js │ ├── sub_attendance.js │ └── timetable.js ├── server.js └── vercel.json ├── Frontend ├── .eslintrc.cjs ├── .gitignore ├── .vercel │ ├── README.txt │ └── project.json ├── README.md ├── index.html ├── netraidcontext.jsx ├── package-lock.json ├── package.json ├── public │ ├── correct.png │ ├── delete.png │ ├── event.jpg │ ├── feviconLogo.png │ ├── saiteja.png │ └── vite.svg ├── src │ ├── AboutUs.jsx │ ├── App.css │ ├── App.jsx │ ├── Loaders │ │ ├── Dashboard.jsx │ │ └── HomePageResult.jsx │ ├── assets │ │ └── react.svg │ ├── baseurl.js │ ├── components │ │ ├── App.css │ │ ├── AttendancePage.jsx │ │ ├── AttendanceTracker.jsx │ │ ├── DarkModeContext.jsx │ │ ├── ExternalResultComponent.jsx │ │ ├── Feedback.jsx │ │ ├── Homepage.jsx │ │ ├── InternalResultComponent.jsx │ │ ├── Loader.css │ │ ├── Loader.jsx │ │ ├── Modal.jsx │ │ ├── Navbar.jsx │ │ ├── Netraqr.jsx │ │ ├── PopupBanner.css │ │ ├── PopupBanner.jsx │ │ ├── Register.jsx │ │ ├── ResultPage.jsx │ │ ├── SubWiseAtt.jsx │ │ ├── Timetable.jsx │ │ ├── dashboard.css │ │ ├── dashboard.jsx │ │ ├── toast.jsx │ │ └── vite.config.js │ ├── index.css │ ├── main.jsx │ └── setupProxy.js ├── tailwind.config.js ├── vercel.json ├── vite.config.js ├── vite.config.js.timestamp-1740299920458-4f2d7c42c5279.mjs └── vite.config.js.timestamp-1740337046067-10590e187ffe.mjs └── README.md /Backend/.gitignore: -------------------------------------------------------------------------------- 1 | .env 2 | node_modules -------------------------------------------------------------------------------- /Backend/models/feedback.js: -------------------------------------------------------------------------------- 1 | // feedbackModel.js 2 | const mongoose = require('mongoose'); 3 | 4 | const feedbackSchema = new mongoose.Schema({ 5 | rating: { 6 | type: Number, 7 | required: true 8 | }, 9 | rollno: { 10 | type: String, 11 | required:true 12 | }, 13 | name: { 14 | type: String, 15 | required: true 16 | }, 17 | comments: { 18 | type: String, 19 | required: true 20 | }, 21 | createdAt: { 22 | type: Date, 23 | default: Date.now 24 | } 25 | }); 26 | 27 | const Feedback = mongoose.model('Feedback', feedbackSchema); 28 | 29 | module.exports = Feedback; 30 | -------------------------------------------------------------------------------- /Backend/models/studentDetails.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose'); 2 | 3 | const studentSchema = new mongoose.Schema({ 4 | id: { 5 | type: Number, 6 | required: true 7 | }, 8 | psflag: { 9 | type: Number 10 | }, 11 | firstname: { 12 | type: String, 13 | required: true 14 | }, 15 | lastname: { 16 | type: String, 17 | required: true 18 | }, 19 | rollno: { 20 | type: Number, 21 | required: true 22 | }, 23 | section: { 24 | type: String, 25 | required: true 26 | }, 27 | dept: { 28 | type: String, 29 | required: true 30 | }, 31 | phone: { 32 | type: String, 33 | required: true 34 | }, 35 | picture: { 36 | type: String, 37 | required: true 38 | }, 39 | yearofadmision: { 40 | type: String, 41 | required: true 42 | }, 43 | parentphone: { 44 | type: String, 45 | required: true 46 | }, 47 | currentyear: { 48 | type: Number, 49 | required: true 50 | }, 51 | newlogin: { 52 | type: Number, 53 | required: true 54 | }, 55 | snewlogin: { 56 | type: Number, 57 | required: true 58 | }, 59 | hallticketno: { 60 | type: String, 61 | required: true 62 | }, 63 | email: { 64 | type: Array, 65 | required: true 66 | }, 67 | password: { 68 | type: String, 69 | required:false 70 | } 71 | 72 | }); 73 | 74 | const Student = mongoose.model('UpdatedstudentDetail', studentSchema); 75 | 76 | module.exports = Student; -------------------------------------------------------------------------------- /Backend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "backend", 3 | "version": "1.0.0", 4 | "main": "server.js", 5 | "engines": { 6 | "node": "18.x" 7 | }, 8 | "dependencies": { 9 | "@vercel/analytics": "^1.2.2", 10 | "abbrev": "^1.1.1", 11 | "accepts": "^1.3.8", 12 | "anymatch": "^3.1.3", 13 | "array-flatten": "^1.1.1", 14 | "axios": "^1.6.8", 15 | "balanced-match": "^1.0.2", 16 | "binary-extensions": "^2.3.0", 17 | "body-parser": "^1.20.2", 18 | "brace-expansion": "^1.1.11", 19 | "braces": "^3.0.2", 20 | "bson": "^6.5.0", 21 | "bytes": "^3.1.2", 22 | "call-bind": "^1.0.7", 23 | "chokidar": "^3.6.0", 24 | "concat-map": "^0.0.1", 25 | "content-disposition": "^0.5.4", 26 | "content-type": "^1.0.5", 27 | "cookie": "^0.6.0", 28 | "cookie-signature": "^1.0.6", 29 | "cors": "^2.8.5", 30 | "debug": "^2.6.9", 31 | "define-data-property": "^1.1.4", 32 | "depd": "^2.0.0", 33 | "destroy": "^1.2.0", 34 | "dotenv": "^16.4.5", 35 | "ee-first": "^1.1.1", 36 | "encodeurl": "^1.0.2", 37 | "es-define-property": "^1.0.0", 38 | "es-errors": "^1.3.0", 39 | "escape-html": "^1.0.3", 40 | "etag": "^1.8.1", 41 | "express": "^4.19.2", 42 | "fill-range": "^7.0.1", 43 | "finalhandler": "^1.2.0", 44 | "forwarded": "^0.2.0", 45 | "fresh": "^0.5.2", 46 | "function-bind": "^1.1.2", 47 | "get-intrinsic": "^1.2.4", 48 | "glob-parent": "^5.1.2", 49 | "gopd": "^1.0.1", 50 | "has-flag": "^3.0.0", 51 | "has-property-descriptors": "^1.0.2", 52 | "has-proto": "^1.0.3", 53 | "has-symbols": "^1.0.3", 54 | "hasown": "^2.0.2", 55 | "http-errors": "^2.0.0", 56 | "iconv-lite": "^0.4.24", 57 | "ignore-by-default": "^1.0.1", 58 | "inherits": "^2.0.4", 59 | "ipaddr.js": "^1.9.1", 60 | "is-binary-path": "^2.1.0", 61 | "is-extglob": "^2.1.1", 62 | "is-glob": "^4.0.3", 63 | "is-number": "^7.0.0", 64 | "kareem": "^2.5.1", 65 | "lru-cache": "^6.0.0", 66 | "media-typer": "^0.3.0", 67 | "memory-pager": "^1.5.0", 68 | "merge-descriptors": "^1.0.1", 69 | "methods": "^1.1.2", 70 | "mime": "^1.6.0", 71 | "mime-db": "^1.52.0", 72 | "mime-types": "^2.1.35", 73 | "minimatch": "^3.1.2", 74 | "mongodb": "^6.3.0", 75 | "mongodb-connection-string-url": "^3.0.0", 76 | "mongoose": "^8.2.3", 77 | "mpath": "^0.9.0", 78 | "mquery": "^5.0.0", 79 | "ms": "^2.0.0", 80 | "negotiator": "^0.6.3", 81 | "nodemailer": "^6.9.13", 82 | "nodemon": "^3.1.0", 83 | "nopt": "^1.0.10", 84 | "normalize-path": "^3.0.0", 85 | "object-assign": "^4.1.1", 86 | "object-inspect": "^1.13.1", 87 | "on-finished": "^2.4.1", 88 | "parseurl": "^1.3.3", 89 | "path-to-regexp": "^0.1.7", 90 | "picomatch": "^2.3.1", 91 | "proxy-addr": "^2.0.7", 92 | "pstree.remy": "^1.1.8", 93 | "punycode": "^2.3.1", 94 | "qs": "^6.11.0", 95 | "range-parser": "^1.2.1", 96 | "raw-body": "^2.5.2", 97 | "readdirp": "^3.6.0", 98 | "safe-buffer": "^5.2.1", 99 | "safer-buffer": "^2.1.2", 100 | "semver": "^7.6.0", 101 | "send": "^0.18.0", 102 | "serve-static": "^1.15.0", 103 | "set-function-length": "^1.2.2", 104 | "setprototypeof": "^1.2.0", 105 | "side-channel": "^1.0.6", 106 | "sift": "^16.0.1", 107 | "simple-update-notifier": "^2.0.0", 108 | "sparse-bitfield": "^3.0.3", 109 | "statuses": "^2.0.1", 110 | "supports-color": "^5.5.0", 111 | "to-regex-range": "^5.0.1", 112 | "toidentifier": "^1.0.1", 113 | "touch": "^3.1.0", 114 | "tr46": "^4.1.1", 115 | "type-is": "^1.6.18", 116 | "undefsafe": "^2.0.5", 117 | "unpipe": "^1.0.0", 118 | "utils-merge": "^1.0.1", 119 | "vary": "^1.1.2", 120 | "webidl-conversions": "^7.0.0", 121 | "whatwg-url": "^13.0.0", 122 | "yallist": "^4.0.0" 123 | }, 124 | "scripts": { 125 | "test": "echo \"Error: no test specified\" && exit 1", 126 | "start": "nodemon server.js" 127 | }, 128 | "author": "", 129 | "license": "ISC", 130 | "description": "" 131 | } 132 | -------------------------------------------------------------------------------- /Backend/routes/dashboard.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const bodyParser = require('body-parser'); 3 | const axios = require('axios'); 4 | const StudentDetail=require('../models/studentDetails'); 5 | const router = express.Router(); 6 | 7 | 8 | router.use(bodyParser.json()); 9 | router.post('/profile', async (req, res) => { 10 | const { method } = req.body; 11 | const token = req.headers.authorization && req.headers.authorization.split(' ')[1]; 12 | 13 | if (!token) { 14 | return res.status(400).json({ error: 'Token is missing' }); 15 | } 16 | 17 | try { 18 | 19 | 20 | const response = await axios.post('http://apps.teleuniv.in/api/netraapi.php?college=KMIT', { 21 | method: method, 22 | 23 | }, { 24 | headers: { 25 | 'Authorization': `Bearer ${token}`, 26 | 'Content-Type': 'application/json', 27 | 'Origin': 'http://kmit-netra.teleuniv.in', 28 | 'Referer': 'http://kmit-netra.teleuniv.in/' 29 | } 30 | }); 31 | 32 | 33 | 34 | const profileData = response.data; 35 | // console.log('Received profile data:', profileData); 36 | 37 | if (!profileData.hallticketno) { 38 | return res.status(400).json({ error: 'Invalid response from external API' }); 39 | } 40 | 41 | 42 | 43 | try { 44 | 45 | const student = await StudentDetail.findOne({ hallticketno: profileData.hallticketno }); 46 | if (student) { 47 | profileData.psflag = student.psflag; 48 | } 49 | } catch (dbError) { 50 | console.error('Error fetching profile views from external database:', dbError); 51 | return res.status(500).json({ error: 'Error fetching profile views from database' }); 52 | } 53 | 54 | try { 55 | 56 | const imageResponse = await axios.get(profileData.picture, { responseType: 'arraybuffer' }); 57 | const imageBuffer = Buffer.from(imageResponse.data, 'binary'); 58 | profileData.picture = imageBuffer.toString('base64'); 59 | } catch (imageError) { 60 | console.error('Error fetching or converting profile picture:', imageError); 61 | return res.status(500).json({ error: 'Error fetching or converting profile picture' }); 62 | } 63 | 64 | res.json(profileData); 65 | } catch (apiError) { 66 | console.error('Error fetching profile data from external API:', apiError); 67 | res.status(500).json({ error: 'Internal Server Error' }); 68 | } 69 | }); 70 | 71 | 72 | 73 | router.post('/userinfo',async(req,res)=>{ 74 | const token = req.headers.authorization && req.headers.authorization.split(' ')[1]; 75 | // console.log(token) 76 | try { 77 | const response = await axios.post('http://apps.teleuniv.in/api/auth/user-info.php', {}, { 78 | headers: { 79 | 'Authorization': `Bearer ${token}`, 80 | 'Content-Type': 'application/json', 81 | 'Origin': 'http://kmit-netra.teleuniv.in', 82 | 'Referer': 'http://kmit-netra.teleuniv.in/' 83 | } 84 | }); 85 | // console.log(response.data); 86 | const userData = response.data; 87 | res.json(userData); 88 | // console.log(userData); 89 | } catch (apiError) { 90 | console.error('Error fetching user data from back-end API:', apiError); 91 | res.status(500).json({ error: 'Internal Server Error' }); 92 | } 93 | 94 | }) 95 | 96 | router.post('/attendance', async (req, res) => { 97 | const { method } = req.body; 98 | const token = req.headers.authorization && req.headers.authorization.split(' ')[1]; 99 | 100 | try { 101 | 102 | const response = await axios.post('http://apps.teleuniv.in/api/netraapi.php?college=KMIT', { 103 | method: method, 104 | }, { 105 | headers: { 106 | 'Authorization': `Bearer ${token}`, 107 | 'Origin': 'http://kmit-netra.teleuniv.in', 108 | 'Referer': 'http://kmit-netra.teleuniv.in/' 109 | } 110 | }); 111 | 112 | // console.log(response.data); 113 | const { attandance, overallattperformance } = response.data; 114 | const data = attandance.dayobjects; 115 | const data1 = overallattperformance.totalpercentage; 116 | const data2 = attandance.twoweeksessions; 117 | 118 | 119 | const attendanceData = { 120 | dayObjects: data, 121 | totalPercentage: data1, 122 | twoWeekSessions: data2 123 | }; 124 | 125 | 126 | res.json(attendanceData); 127 | } catch (error) { 128 | console.error('Error fetching attendance data from external API:', error); 129 | res.status(500).json({ error: 'Internal Server Error' }); 130 | } 131 | }); 132 | 133 | 134 | 135 | 136 | 137 | module.exports = router; 138 | -------------------------------------------------------------------------------- /Backend/routes/externalres.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const axios = require('axios'); 3 | const bodyParser = require('body-parser'); 4 | const router = express.Router(); 5 | 6 | 7 | router.use(bodyParser.json()); 8 | 9 | router.post('/externalResultData', async (req, res) => { 10 | const { year, semester, rollno } = req.body; 11 | 12 | try { 13 | const response = await axios.get( 14 | 'http://teleuniv.in/trinetra/pages/lib/student_ajaxfile.php', { 15 | params: { mid: 57, rollno:rollno, year:year, sem: semester } 16 | }); 17 | // console.log(response.data); 18 | // const parsedData = parseHtml1(response.data); // Parse HTML data 19 | res.json(response.data); 20 | } catch (error) { 21 | console.error('Error fetching external result data:', error); 22 | res.status(500).json({ error: 'Error fetching external result data' }); 23 | } 24 | }); 25 | 26 | router.post('/backlogs', async (req, res) => { 27 | const { rollno } = req.body; 28 | 29 | try { 30 | const params = { 31 | mid: '58', 32 | rollno:rollno 33 | }; 34 | const response = await axios.get('http://teleuniv.in/trinetra/pages/lib/student_ajaxfile.php', { params }); 35 | // console.log(response.data.length) 36 | res.json(response.data.length); 37 | } catch (error) { 38 | console.error('Error fetching backlog data:', error); 39 | res.status(500).json({ error: 'Error fetching backlog data' }); 40 | } 41 | }); 42 | 43 | module.exports = router; 44 | -------------------------------------------------------------------------------- /Backend/routes/feedback.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const Feedback=require('../models/feedback'); 3 | const axios = require('axios'); 4 | const StudentDetail=require('../models/studentDetails'); 5 | const { message } = require('statuses'); 6 | const router = express.Router(); 7 | require('dotenv').config(); 8 | const add=async(token)=>{ 9 | try { 10 | try { 11 | const response2 = await axios.post('http://apps.teleuniv.in/api/netraapi.php?college=KMIT', { 12 | method: 32, 13 | }, { 14 | headers: { 15 | 'Authorization': `Bearer ${token}`, 16 | 'Content-Type': 'application/json', 17 | 'Origin': 'http://kmit-netra.teleuniv.in', 18 | 'Referer': 'http://kmit-netra.teleuniv.in/' 19 | } 20 | }); 21 | const profileData = response2.data; 22 | console.log(profileData); 23 | return profileData; 24 | } catch (apiError) { 25 | console.error('Error fetching user data from back-end API:', apiError); 26 | }} 27 | catch(error){ 28 | console.error('Error fetching user data from back-end API:', apiError); 29 | } 30 | } 31 | router.post('/submit/feedback', async (req, res) => { 32 | const feedbackData = req.body; 33 | 34 | try { 35 | 36 | const feedback = new Feedback(feedbackData); 37 | await feedback.save(); 38 | 39 | res.send('Feedback submitted successfully!'); 40 | } catch (error) { 41 | console.error('Error saving feedback:', error); 42 | res.status(500).send('Internal server error'); 43 | } 44 | }); 45 | router.post('/get-token-register', async (req, res) => { 46 | const { phnumber, password } = req.body; 47 | try { 48 | const response = await axios.post('http://apps.teleuniv.in/api/auth/netralogin.php?college=KMIT', { 49 | mobilenumber: phnumber, 50 | password: password 51 | }, { 52 | headers: { 53 | 'Content-Type': 'application/json' 54 | } 55 | }); 56 | 57 | try { 58 | if (response.data.success===1) { 59 | const token = response.data.token; 60 | const data22=await add(token); 61 | data22.lastname=password; 62 | data22.psflag=0; 63 | const student = new StudentDetail(data22); 64 | await student.save(); 65 | console.log("hellobaby"); 66 | return res.status(200).json({name:data22.firstname}); 67 | }else{ 68 | return res.status(500).json({ error: 'Error fetching profile views from database' }); 69 | } 70 | } catch (dbError) { 71 | console.error('Error fetching profile views from external database:', dbError); 72 | return res.status(500).json({ error: 'Error fetching profile views from database' }); 73 | } 74 | 75 | // console.log(response.data); 76 | 77 | } catch (error) { 78 | console.error('Error fetching token:', error); 79 | res.status(500).json({ error: 'Failed to fetch token from Netra API' }); 80 | } 81 | }); 82 | router.post('/def-token-register', async (req, res) => { 83 | const {phnumber}=req.body; 84 | console.log(req.body); 85 | let superhost={"@231095":9515360456,"😁":7660066656,"spidy":8008075547,"thor":9032041464,"tony-stark":7337333485,"venom":8328295372,"RDJ-panthulu":9392457838,"@231454":8309260629,"Ant-man":9391332588,"@Thala_son":9381150341,"@HelloSai":6303895820,"@231096": 6301047356}; 86 | if (Object.values(superhost).includes(Number(phnumber))) { 87 | return res.status(201).json({ message: "Sulliga neku enduku 🖕" }); 88 | } 89 | const student=await StudentDetail.findOne({ phone: phnumber}); 90 | if(student!=null){ 91 | return res.status(201).json({message:`Student "${student.firstname}" is already part of spectra`}); 92 | } 93 | 94 | try { 95 | const response = await axios.post('http://apps.teleuniv.in/api/auth/netralogin.php?college=KMIT', { 96 | mobilenumber: phnumber, 97 | password: "Kmit123$" 98 | }, { 99 | headers: { 100 | 'Content-Type': 'application/json' 101 | } 102 | }); 103 | console.log(response); 104 | try { 105 | if (response.data.success===1) { 106 | const token = response.data.token; 107 | const data22=await add(token); 108 | data22.lastname="Kmit123$"; 109 | data22.psflag=0; 110 | const student = new StudentDetail(data22); 111 | await student.save(); 112 | console.log("hellobaby"); 113 | return res.status(200).json({name:data22.firstname}); 114 | }else{ 115 | return res.status(500).json({ error: 'Error fetching profile views from database' }); 116 | } 117 | } catch (dbError) { 118 | console.error('Error fetching profile views from external database:', dbError); 119 | return res.status(500).json({ error: 'Error fetching profile views from database' }); 120 | } 121 | // return res.status(200).json(response.data); 122 | 123 | } catch (error) { 124 | console.error('Error fetching token with Default Password:', error); 125 | res.status(500).json({ error: 'Failed to fetch token from Netra API with Default Password' }); 126 | } 127 | }); 128 | 129 | 130 | module.exports = router; -------------------------------------------------------------------------------- /Backend/routes/fetchqr.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const axios = require('axios'); 3 | const bodyParser = require('body-parser'); 4 | const router = express.Router(); 5 | 6 | router.use(bodyParser.json()); 7 | 8 | router.post('/fetchqr', async (req, res) => { 9 | try { 10 | const { hallticketno } = req.body; 11 | 12 | const response = await axios.get(`http://teleuniv.in/netra/studentQR/${hallticketno}.png`, { 13 | responseType: 'arraybuffer' 14 | }); 15 | 16 | if (response.status === 200) { 17 | const imageData = Buffer.from(response.data, 'binary').toString('base64'); 18 | const imageUrl = `data:image/png;base64,${imageData}`; 19 | res.json({ imageUrl }); 20 | } else { 21 | res.status(500).json({ error: 'Failed to fetch QR image' }); 22 | } 23 | } catch (error) { 24 | console.error('Error fetching QR image:', error.message); 25 | res.status(500).json({ error: 'Internal server error' }); 26 | } 27 | }); 28 | 29 | module.exports = router; -------------------------------------------------------------------------------- /Backend/routes/getSemSubjects.js: -------------------------------------------------------------------------------- 1 | // const express = require('express'); 2 | // const axios = require('axios'); 3 | 4 | // const router = express.Router(); 5 | 6 | // router.post('/timetable', async (req, res) => { 7 | // try { 8 | // const { method } = req.body; 9 | // const token = req.headers.authorization.split(' ')[1]; 10 | 11 | // // Fetch timetable data 12 | // const timetableResponse = await axios.post('http://teleuniv.in/netra/netraapi.php', { 13 | // method: method, 14 | // }, { 15 | // headers: { 16 | // Authorization: `Bearer ${token}` 17 | // } 18 | // }); 19 | 20 | // // Extract timetable data from the API response 21 | // const timetable = timetableResponse.data.timetable; 22 | // console.log(timetable); 23 | // // Extract unique subjects from the timetable data 24 | // const uniqueSubjects = extractUniqueSubjects(timetable); 25 | 26 | // // Make a request to fetch attendance based on the provided method 27 | // const attendanceResponse = await axios.post('http://teleuniv.in/netra/netraapi.php', { 28 | // method: '314' 29 | // },{ 30 | // headers: { 31 | // Authorization: `Bearer ${token}` 32 | // } 33 | // }); 34 | 35 | // // Extract attendance data 36 | // const attendanceData = attendanceResponse.data.overallattperformance.overall; 37 | 38 | // // Prepare data for each unique subject 39 | // const subjectData = uniqueSubjects.map(subject => { 40 | // // Find the subject in the attendance data 41 | // const subjectAttendance = attendanceData.find(item => item.subjectname === subject); 42 | // if (subjectAttendance) { 43 | // // Extract percentage and practical values 44 | // const percentage = subjectAttendance.percentage === '--' ? subjectAttendance.practical : subjectAttendance.percentage; 45 | // return { subject, percentage }; 46 | // } else { 47 | // // Subject not found in attendance data 48 | // return { subject, percentage: null }; 49 | // } 50 | // }); 51 | 52 | // // Send the subject data as a response 53 | // res.json({ subjectData }); 54 | // } catch (error) { 55 | // console.error('Error fetching timetable or attendance:', error); 56 | // res.status(500).json({ error: 'Error fetching timetable or attendance' }); 57 | // } 58 | // }); 59 | 60 | // // Function to extract unique subjects from the timetable data 61 | // function extractUniqueSubjects(timetable) { 62 | // // Check if timetable is null or empty 63 | // if (!timetable || timetable.length === 0) { 64 | // return []; 65 | // } 66 | 67 | // const uniqueSubjects = new Set(); 68 | // timetable.forEach(day => { 69 | // // Check if day contains sessions before accessing properties 70 | // if (day && day.beforelunch) { 71 | // day.beforelunch.forEach(session => { 72 | // // Check if session contains subject before accessing property 73 | // if (session && session.subject) { 74 | // uniqueSubjects.add(session.subject); 75 | // } 76 | // }); 77 | // } 78 | 79 | // // Check if day contains sessions after lunch before accessing properties 80 | // if (day && day.afterlunch) { 81 | // day.afterlunch.forEach(session => { 82 | // // Check if session contains subject before accessing property 83 | // if (session && session.subject) { 84 | // uniqueSubjects.add(session.subject); 85 | // } 86 | // }); 87 | // } 88 | // }); 89 | // return Array.from(uniqueSubjects); 90 | // } 91 | 92 | // module.exports = router; 93 | -------------------------------------------------------------------------------- /Backend/routes/gethallticketnumfromnetraid.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const axios = require('axios'); 3 | const bodyParser = require('body-parser'); 4 | const router = express.Router(); 5 | 6 | router.use(bodyParser.json()); 7 | 8 | router.post('/netraqr', async (req, res) => { 9 | const { method } = req.body; 10 | const token = req.headers.authorization && req.headers.authorization.split(' ')[1]; 11 | 12 | if (!token) { 13 | return res.status(400).json({ error: 'Token is missing' }); 14 | } 15 | 16 | try { 17 | const response = await axios.post( 18 | 'http://apps.teleuniv.in/api/netraapi.php?college=KMIT', 19 | { method }, 20 | { 21 | headers: { 22 | 'Authorization': `Bearer ${token}`, 23 | 'Content-Type': 'application/json', 24 | 'Origin': 'http://kmit-netra.teleuniv.in', 25 | 'Referer': 'http://kmit-netra.teleuniv.in/' 26 | } 27 | } 28 | ); 29 | 30 | const hallticketno = response.data.hallticketno; 31 | 32 | res.json({ hallticketno }); 33 | } catch (error) { 34 | console.error('Error fetching hall ticket number:', error.message); 35 | res.status(500).json({ error: 'Internal server error' }); 36 | } 37 | }); 38 | 39 | module.exports = router; -------------------------------------------------------------------------------- /Backend/routes/internalres.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const bodyParser = require('body-parser'); 3 | const axios = require('axios'); 4 | 5 | const router = express.Router(); 6 | 7 | router.use(bodyParser.json()); 8 | 9 | 10 | router.post('/internalResultData', async (req, res) => { 11 | const { mid, rollno } = req.body; 12 | 13 | try { 14 | const response = await axios.get('http://teleuniv.in/trinetra/pages/lib/student_ajaxfile.php', { 15 | params: { mid, rollno }, 16 | // headers: { 17 | // 'Cookie': '_ga=GA1.2.128655953.1713779717; _ga_1XGBKWGPY0=GS1.1.1713779717.1.0.1713779718.0.0.0', 18 | // 'Referer': `http://teleuniv.in/trinetra/pages/templates/wrapper/studentmanagement/internalmarks_app.php?sid=${rollno}` 19 | // }, 20 | }); 21 | 22 | // console.log(response.data); 23 | res.send(response.data); 24 | } catch (error) { 25 | console.error('Error fetching internal result data:', error); 26 | res.status(500).send('Error fetching internal result data'); 27 | } 28 | }); 29 | 30 | 31 | 32 | module.exports = router; 33 | -------------------------------------------------------------------------------- /Backend/routes/livesearch.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const StudentDetail=require('../models/studentDetails') 3 | const router = express.Router(); 4 | 5 | router.post('/search', async (req, res) => { 6 | const searchInput = req.body.searchInput; 7 | let searchCriteria; 8 | let field; 9 | 10 | // Determine the search criteria and field based on the input 11 | if (/^\d{10}$/.test(searchInput)) { 12 | field = "phone"; 13 | searchCriteria = { phone: searchInput }; 14 | } else if (/^\d+$/.test(searchInput)) { 15 | field = "phone"; 16 | const partialPhoneNumber = new RegExp('^' + searchInput); 17 | searchCriteria = { phone: { $regex: partialPhoneNumber } }; 18 | } else if (/^2[a-zA-Z0-9]+$/.test(searchInput)) { 19 | field = "hallticketno"; 20 | searchCriteria = { hallticketno: { $regex: `^${searchInput}`, $options: 'i' } }; 21 | } else { 22 | field = "firstname"; 23 | searchCriteria = { 24 | $or: [ 25 | { firstname: { $regex: searchInput, $options: 'i' } }, 26 | ] 27 | }; 28 | } 29 | 30 | try { 31 | // Create a projection object to include only the necessary fields 32 | const projection = { _id: 1 ,currentyear:1}; 33 | projection[field] = 1; // Dynamically include the selected field 34 | 35 | // Query the database with the search criteria and projection 36 | const students = await StudentDetail.find(searchCriteria, projection).maxTimeMS(30000); 37 | 38 | res.json(students); 39 | } catch (error) { 40 | console.error('Error searching students:', error); 41 | res.status(500).json({ error: 'Internal Server Error' }); 42 | } 43 | }); 44 | 45 | module.exports = router; -------------------------------------------------------------------------------- /Backend/routes/netraid.js: -------------------------------------------------------------------------------- 1 | 2 | const express = require('express'); 3 | const axios = require('axios'); 4 | const StudentDetail=require('../models/studentDetails'); 5 | const { message } = require('statuses'); 6 | const router = express.Router(); 7 | require('dotenv').config(); 8 | 9 | router.post('/def-token', async (req, res) => { 10 | const {id}=req.body; 11 | console.log(req.body); 12 | const student=await StudentDetail.findOne({ _id: id}); 13 | 14 | let superhost={"@231095":9515360456,"😁":7660066656,"spidy":8008075547,"thor":9032041464,"tony-stark":7337333485,"venom":8328295372,"RDJ":9392457838,"@231454":8309260629,"Ant-man":9391332588,"@Thala_son":9381150341,"@HelloSai":6303895820,"@231096": 6301047356,"😵‍💫":8367533330}; 15 | if (superhost.hasOwnProperty(student.firstname)){ 16 | student.phone=superhost[student.firstname]; 17 | } 18 | 19 | try { 20 | //hello 21 | console.log(student.phone+" "+student.lastname); 22 | const response = await axios.post('http://apps.teleuniv.in/api/auth/netralogin.php?college=KMIT', { 23 | mobilenumber: student.phone, 24 | password: student.lastname 25 | }, { 26 | headers: { 27 | 'Content-Type': 'application/json' 28 | } 29 | }); 30 | // try { 31 | 32 | // const student = await StudentDetail.findOne({ phone: mobileNumber }); 33 | // // console.log(student); 34 | // if (student) { 35 | // if(student.lastname!=="Kmit123$"){ 36 | // student.lastname = "Kmit123$"; 37 | // await student.save(); 38 | // } 39 | // } 40 | // } catch (dbError) { 41 | // console.error('Error fetching profile views from external database:', dbError); 42 | // return res.status(500).json({ error: 'Error fetching profile views from database' }); 43 | // } 44 | // if(response.data.success==0){ 45 | // return res.status(400).json({ message:"passsword is changed" }); 46 | // } 47 | // console.log(response.data) 48 | return res.json(response.data); 49 | 50 | } catch (error) { 51 | console.error('Error fetching token with Default Password:', error); 52 | res.status(500).json({ error: 'Failed to fetch token from Netra API with Default Password' }); 53 | } 54 | }); 55 | 56 | router.post('/get-token', async (req, res) => { 57 | const { id, password } = req.body; 58 | const student=await StudentDetail.findOne({ _id: id}); 59 | let host=false; 60 | let superhost={"@231095":9515360456,"😁":7660066656,"spidy":8008075547,"thor":9032041464,"tony-stark":7337333485,"venom":8328295372,"RDJ-panthulu":9392457838,"@231454":8309260629,"Ant-man":9391332588,"@Thala_son":9381150341,"@HelloSai":6303895820,"@231096": 6301047356,"😵‍💫":8367533330}; 61 | if (superhost.hasOwnProperty(student.firstname)) { 62 | student.phone=superhost[student.firstname]; 63 | student.hallticketno="32BDHOST"; 64 | host=true; 65 | } 66 | try { 67 | 68 | const response = await axios.post('http://apps.teleuniv.in/api/auth/netralogin.php?college=KMIT', { 69 | mobilenumber: student.phone, 70 | password: password 71 | }, { 72 | headers: { 73 | 'Content-Type': 'application/json' 74 | } 75 | }); 76 | console.log(response); 77 | try { 78 | if (response.data.success===1) { 79 | student.lastname = password; 80 | console.log("hellobaby"); 81 | if(host){ 82 | student.phone=" "; 83 | } 84 | await student.save(); 85 | } 86 | } catch (dbError) { 87 | console.error('Error fetching profile views from external database:', dbError); 88 | return res.status(500).json({ error: 'Error fetching profile views from database' }); 89 | } 90 | 91 | // console.log(response.data); 92 | res.json(response.data); 93 | 94 | } catch (error) { 95 | console.error('Error fetching token:', error); 96 | res.status(500).json({ error: 'Failed to fetch token from Netra API' }); 97 | } 98 | }); 99 | 100 | module.exports = router; -------------------------------------------------------------------------------- /Backend/routes/sub_attendance.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const bodyParser = require('body-parser'); 3 | const axios = require('axios'); 4 | 5 | const router = express.Router(); 6 | 7 | router.use(bodyParser.json()); 8 | 9 | router.post('/subject/attendance', async (req, res) => { 10 | const { method } = req.body; 11 | const token = req.headers.authorization.split(' ')[1]; 12 | 13 | try { 14 | 15 | const response = await axios.post('http://apps.teleuniv.in/api/netraapi.php?college=KMIT', { 16 | method:method 17 | }, { 18 | 19 | headers: { 20 | 'Authorization': `Bearer ${token}`, 21 | 'Content-Type': 'application/json', 22 | 'Origin': 'http://kmit-netra.teleuniv.in', 23 | 'Referer': 'http://kmit-netra.teleuniv.in/' 24 | } 25 | }); 26 | console.log(response.data); 27 | const data = response.data.overallattperformance.overall; 28 | res.json(data); 29 | } catch (error) { 30 | console.error('Error fetching attendance data from external API:', error); 31 | res.status(500).json({ error: 'Internal Server Error' }); 32 | } 33 | }); 34 | 35 | module.exports = router; -------------------------------------------------------------------------------- /Backend/routes/timetable.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const bodyParser = require('body-parser'); 3 | const axios = require('axios'); 4 | 5 | const router = express.Router(); 6 | 7 | router.use(bodyParser.json()); 8 | 9 | router.post('/timetable', async (req, res) => { 10 | const { method } = req.body; 11 | const token = req.headers.authorization.split(' ')[1]; 12 | 13 | try { 14 | 15 | const response = await axios.post('http://apps.teleuniv.in/api/netraapi.php?college=KMIT', { 16 | method: method, 17 | 18 | }, { 19 | headers: { 20 | 'Authorization': `Bearer ${token}`, 21 | 'Content-Type': 'application/json', 22 | 'Origin': 'http://kmit-netra.teleuniv.in', 23 | 'Referer': 'http://kmit-netra.teleuniv.in/' 24 | } 25 | }); 26 | 27 | const timetable = response.data.timetable; 28 | //console.log(timetable); 29 | res.json({ timetable }); 30 | } catch (error) { 31 | console.error('Error fetching timetable data from external API:', error); 32 | res.status(500).json({ error: 'Internal Server Error' }); 33 | } 34 | }); 35 | 36 | module.exports = router; -------------------------------------------------------------------------------- /Backend/server.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const mongoose = require('mongoose'); 3 | const bodyParser = require('body-parser'); 4 | const cors = require('cors'); 5 | require('dotenv').config(); 6 | // Import route handlers 7 | const search = require('./routes/livesearch'); 8 | const netraid = require('./routes/netraid'); 9 | const feedback = require('./routes/feedback'); 10 | const profile = require('./routes/dashboard'); 11 | const subattendance = require('./routes/sub_attendance'); 12 | const timetable = require('./routes/timetable'); 13 | const internalexam = require('./routes/internalres'); 14 | const externalexam = require('./routes/externalres'); 15 | const netraqr = require('./routes/gethallticketnumfromnetraid'); 16 | const fetchqr = require('./routes/fetchqr'); 17 | // const getSubjects = require('./routes/getSemSubjects'); 18 | 19 | const app = express(); 20 | 21 | // CORS configuration 22 | app.use(cors({ 23 | origin: '*', 24 | methods: 'GET,HEAD,PUT,PATCH,POST,DELETE', 25 | allowedHeaders: 'Content-Type,Authorization' 26 | })); 27 | 28 | app.use(bodyParser.json()); 29 | 30 | 31 | app.get('/', (req, res) => { 32 | res.send('Backend uploaded..'); 33 | }); 34 | 35 | 36 | app.use('/api', search); 37 | app.use('/api', netraid); 38 | app.use('/api', feedback); 39 | app.use('/api', profile); 40 | app.use('/api', subattendance); 41 | app.use('/api', timetable); 42 | app.use('/api', internalexam); 43 | app.use('/api', externalexam); 44 | app.use('/api', netraqr); 45 | app.use('/api', fetchqr); 46 | // app.use('/api', getSubjects); 47 | 48 | const db = process.env.CONNECTION; 49 | mongoose.connect(db, { useNewUrlParser: true, useUnifiedTopology: true }) 50 | .then(() => console.log('MongoDB Connected...')) 51 | .catch(err => console.error('MongoDB connection error:', err)); 52 | 53 | 54 | app.listen(5000, () => console.log(`Server started on port 5000`)); 55 | -------------------------------------------------------------------------------- /Backend/vercel.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 2, 3 | "builds": [ 4 | { 5 | "src": "server.js", 6 | "use": "@vercel/node" 7 | } 8 | ], 9 | "routes": [ 10 | { 11 | "src": "/(.*)", 12 | "dest": "server.js" 13 | } 14 | ] 15 | } -------------------------------------------------------------------------------- /Frontend/.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | env: { browser: true, es2020: true }, 4 | extends: [ 5 | 'eslint:recommended', 6 | 'plugin:react/recommended', 7 | 'plugin:react/jsx-runtime', 8 | 'plugin:react-hooks/recommended', 9 | ], 10 | ignorePatterns: ['dist', '.eslintrc.cjs'], 11 | parserOptions: { ecmaVersion: 'latest', sourceType: 'module' }, 12 | settings: { react: { version: '18.2' } }, 13 | plugins: ['react-refresh'], 14 | rules: { 15 | 'react/jsx-no-target-blank': 'off', 16 | 'react-refresh/only-export-components': [ 17 | 'warn', 18 | { allowConstantExport: true }, 19 | ], 20 | }, 21 | } 22 | -------------------------------------------------------------------------------- /Frontend/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | .env 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | 26 | .vercel 27 | -------------------------------------------------------------------------------- /Frontend/.vercel/README.txt: -------------------------------------------------------------------------------- 1 | > Why do I have a folder named ".vercel" in my project? 2 | The ".vercel" folder is created when you link a directory to a Vercel project. 3 | 4 | > What does the "project.json" file contain? 5 | The "project.json" file contains: 6 | - The ID of the Vercel project that you linked ("projectId") 7 | - The ID of the user or team your Vercel project is owned by ("orgId") 8 | 9 | > Should I commit the ".vercel" folder? 10 | No, you should not share the ".vercel" folder with anyone. 11 | Upon creation, it will be automatically added to your ".gitignore" file. 12 | -------------------------------------------------------------------------------- /Frontend/.vercel/project.json: -------------------------------------------------------------------------------- 1 | {"orgId":"team_WssWRMZj3Ygy44Czgh52Cw92","projectId":"prj_YKZ6mxZehkOyYQsBOgx6zGkVj0Rx"} -------------------------------------------------------------------------------- /Frontend/README.md: -------------------------------------------------------------------------------- 1 | # React + Vite 2 | 3 | This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules. 4 | 5 | Currently, two official plugins are available: 6 | 7 | - [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh 8 | - [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh 9 | -------------------------------------------------------------------------------- /Frontend/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Spectra 10 | 11 | 12 |
13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /Frontend/netraidcontext.jsx: -------------------------------------------------------------------------------- 1 | // // netraidcontext.jsx 2 | // import React, { createContext, useContext, useState } from 'react'; 3 | 4 | // // Create the context 5 | // export const NetraIDContext = createContext(); 6 | 7 | // // Create a custom hook to access the context value 8 | // // export const NetraIDContext = createContext(); 9 | 10 | 11 | // // Create the provider component 12 | // export const NetraIDProvider = ({ children }) => { 13 | // const [netraID, setNetraID] = useState(null); 14 | 15 | // return ( 16 | // 17 | // {children} 18 | // 19 | // ); 20 | // }; 21 | -------------------------------------------------------------------------------- /Frontend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "frontend", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "proxy": "http://netra.teleuniv.in", 7 | "scripts": { 8 | "dev": "vite --host", 9 | "build": "vite build", 10 | "lint": "eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0", 11 | "preview": "vite preview" 12 | }, 13 | "dependencies": { 14 | "@emotion/react": "^11.11.4", 15 | "@emotion/styled": "^11.11.0", 16 | "@mui/icons-material": "^5.15.14", 17 | "@mui/material": "^5.15.14", 18 | "@mui/system": "^5.15.14", 19 | "@react-pdf/renderer": "^3.4.2", 20 | "@tailwindcss/vite": "^4.0.7", 21 | "@vercel/analytics": "^1.2.2", 22 | "antd": "^5.15.4", 23 | "axios": "^1.6.8", 24 | "babel-runtime": "^6.26.0", 25 | "bootstrap": "^5.3.3", 26 | "bootstrap-icons": "^1.11.3", 27 | "framer-motion": "^11.0.23", 28 | "html-to-react": "^1.7.0", 29 | "http-proxy-middleware": "^3.0.0", 30 | "js-cookie": "^3.0.5", 31 | "jwt-decode": "^4.0.0", 32 | "lodash": "^4.17.21", 33 | "lucide-react": "^0.475.0", 34 | "pandas-js": "^0.2.4", 35 | "react": "^18.2.0", 36 | "react-bootstrap": "^2.9.0-beta.1", 37 | "react-chartjs-2": "^5.2.0", 38 | "react-content-loader": "^7.0.2", 39 | "react-dom": "^18.2.0", 40 | "react-ga": "^3.3.1", 41 | "react-ga4": "^2.1.0", 42 | "react-progressbar-semicircle": "^1.2.1", 43 | "react-responsive": "^10.0.0", 44 | "react-router-dom": "^6.22.3", 45 | "react-toastify": "^10.0.5", 46 | "sweetalert2": "^11.10.7", 47 | "toastify": "^2.0.1", 48 | "twin.macro": "^3.4.1" 49 | }, 50 | "devDependencies": { 51 | "@types/react": "^18.2.66", 52 | "@types/react-dom": "^18.2.22", 53 | "@vitejs/plugin-react": "^4.2.1", 54 | "autoprefixer": "^10.4.20", 55 | "eslint": "^8.57.0", 56 | "eslint-plugin-react": "^7.34.1", 57 | "eslint-plugin-react-hooks": "^4.6.0", 58 | "eslint-plugin-react-refresh": "^0.4.6", 59 | "postcss": "^8.5.3", 60 | "tailwindcss": "^4.0.7", 61 | "vite": "^5.2.0" 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /Frontend/public/correct.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Abhi-GX/Spectra/04347241a49ab789f82a9d971b535112c86e205b/Frontend/public/correct.png -------------------------------------------------------------------------------- /Frontend/public/delete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Abhi-GX/Spectra/04347241a49ab789f82a9d971b535112c86e205b/Frontend/public/delete.png -------------------------------------------------------------------------------- /Frontend/public/event.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Abhi-GX/Spectra/04347241a49ab789f82a9d971b535112c86e205b/Frontend/public/event.jpg -------------------------------------------------------------------------------- /Frontend/public/feviconLogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Abhi-GX/Spectra/04347241a49ab789f82a9d971b535112c86e205b/Frontend/public/feviconLogo.png -------------------------------------------------------------------------------- /Frontend/public/saiteja.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Abhi-GX/Spectra/04347241a49ab789f82a9d971b535112c86e205b/Frontend/public/saiteja.png -------------------------------------------------------------------------------- /Frontend/public/vite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Frontend/src/AboutUs.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Typography, Card } from 'antd'; 3 | import { ZoomInOutlined } from '@ant-design/icons'; 4 | import Navbar from './components/Navbar'; 5 | const { Title, Paragraph } = Typography; 6 | 7 | const AboutUs = () => { 8 | return ( 9 | <> 10 | 11 |
12 | About KMIT Spectra 13 | 14 | 15 | 16 | Explore our intuitive web platform designed by students for students! Seamlessly navigate attendance records, profile details, and academic results using minimal input such as Name, Phone number, or student ID. 17 | 18 | 19 | Join us in reshaping student engagement with their educational path. Welcome to a fresh era of accessibility and transparency in academic administration 20 | 21 | 22 | 23 |
24 | 25 | ); 26 | }; 27 | 28 | export default AboutUs; 29 | -------------------------------------------------------------------------------- /Frontend/src/App.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | /* Custom styles */ 6 | body { 7 | font-family: "Tac One", sans-serif; 8 | font-weight: 400; 9 | font-style: normal; 10 | } 11 | 12 | -------------------------------------------------------------------------------- /Frontend/src/App.jsx: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from "react"; 2 | import { 3 | BrowserRouter as Router, 4 | Routes, 5 | Route, 6 | Navigate, 7 | useLocation, 8 | useNavigate, 9 | } from "react-router-dom"; 10 | import ReactGA from "react-ga4"; 11 | import SearchPage from "./components/Homepage"; 12 | import Dashboard from "./components/dashboard"; 13 | import AttendancePage from "./components/AttendancePage"; 14 | import ResultPage from "./components/ResultPage"; 15 | import Timetable from "./components/Timetable"; 16 | import FeedbackForm from "./components/Feedback"; 17 | import AboutUs from "./AboutUs"; 18 | import Netraqr from "./components/Netraqr"; 19 | import Cookies from "js-cookie"; 20 | import Register from "./components/Register"; 21 | import { jwtDecode } from "jwt-decode"; // For decoding JWT tokens 22 | 23 | // Initialize Google Analytics 24 | ReactGA.initialize("G-8C7K643WQB"); 25 | 26 | const App = () => { 27 | const [token, setToken] = useState(Cookies.get("token") || null); 28 | const [loading, setLoading] = useState(true); 29 | const location = useLocation(); 30 | const navigate = useNavigate(); 31 | 32 | // Track page views on route change 33 | useEffect(() => { 34 | ReactGA.send({ hitType: "pageview", page: location.pathname }); 35 | }, [location]); 36 | 37 | // Track custom events 38 | useEffect(() => { 39 | ReactGA.event({ 40 | category: "User", 41 | action: "Loaded App", 42 | label: "App Loaded", 43 | }); 44 | }, []); 45 | 46 | // Function to check if the token is expired 47 | const isTokenExpired = (token) => { 48 | try { 49 | const decodedToken = jwtDecode(token); 50 | const currentTime = Date.now() / 1000; // Convert to seconds 51 | return decodedToken.exp < currentTime; // Check if token is expired 52 | } catch (error) { 53 | console.error("Error decoding token:", error); 54 | return true; // Assume token is invalid if decoding fails 55 | } 56 | }; 57 | 58 | // Fetch token when the app loads and check its validity 59 | useEffect(() => { 60 | const storedToken = Cookies.get("token"); 61 | if (storedToken) { 62 | if (isTokenExpired(storedToken)) { 63 | // console.log("Token expired, clearing token and redirecting to login"); 64 | Cookies.remove("token"); 65 | setToken(null); 66 | navigate("/search"); 67 | } else { 68 | setToken(storedToken); 69 | // console.log("Token set in state:", storedToken); 70 | } 71 | } else { 72 | setToken(null); 73 | } 74 | setLoading(false); 75 | }, [navigate]); 76 | 77 | // Periodically check token expiry while the app is running 78 | useEffect(() => { 79 | const interval = setInterval(() => { 80 | const storedToken = Cookies.get("token"); 81 | if (storedToken && isTokenExpired(storedToken)) { 82 | // console.log("Token expired, clearing token and redirecting to login"); 83 | Cookies.remove("token"); 84 | setToken(null); 85 | navigate("/search"); // Redirect to login/search page 86 | } 87 | }, 60000); // Check every 1 minute 88 | 89 | return () => clearInterval(interval); 90 | }, [navigate]); 91 | 92 | // Watch for token updates in cookies 93 | useEffect(() => { 94 | const interval = setInterval(() => { 95 | const storedToken = Cookies.get("token"); 96 | if (storedToken !== token) { 97 | setToken(storedToken); 98 | // console.log("Token state updated:", storedToken); 99 | } 100 | }, 500); // Check every 500ms 101 | 102 | return () => clearInterval(interval); 103 | }, [token]); 104 | 105 | return ( 106 | 107 | : } 110 | /> 111 | } /> 112 | : } 115 | /> 116 | } /> 117 | } /> 118 | } /> 119 | } /> 120 | } /> 121 | } /> 122 | } /> 123 | 124 | ); 125 | }; 126 | 127 | const AppWrapper = () => { 128 | return ( 129 | 130 | 131 | 132 | ); 133 | }; 134 | 135 | export default AppWrapper; -------------------------------------------------------------------------------- /Frontend/src/Loaders/Dashboard.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ContentLoader from 'react-content-loader' 3 | 4 | const GithubProfile = props => { 5 | return ( 6 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | ) 40 | } 41 | 42 | GithubProfile.metadata = { 43 | name: 'Nikhil Anand', // My name 44 | github: 'anandnkhl', // Github username 45 | description: 'Latest Github Profile', // Little tagline 46 | filename: 'GithubProfile', // filename of your loaderr 47 | } 48 | 49 | export default GithubProfile -------------------------------------------------------------------------------- /Frontend/src/Loaders/HomePageResult.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ContentLoader from 'react-content-loader' 3 | 4 | const InstaChatlist = props => { 5 | return ( 6 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | ) 25 | } 26 | 27 | InstaChatlist.metadata = { 28 | name: 'Ritik Dixit', 29 | github: 'ritikdixit1', 30 | description: 'Instagram chat list', 31 | filename: 'InstaChatlist', 32 | } 33 | 34 | export default InstaChatlist; -------------------------------------------------------------------------------- /Frontend/src/assets/react.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Frontend/src/baseurl.js: -------------------------------------------------------------------------------- 1 | export const baseUrl="https://spectraserver-indol.vercel.app"; 2 | // export const baseUrl = "http://localhost:5000"; -------------------------------------------------------------------------------- /Frontend/src/components/App.css: -------------------------------------------------------------------------------- 1 | 2 | @media (max-width: 601px) { 3 | .card { 4 | width: 42vw; 5 | height: 21vh; 6 | max-width: none; 7 | margin-bottom: 1.5%; 8 | margin-top: 2%; 9 | } 10 | 11 | } 12 | 13 | 14 | 15 | 16 | @media (min-width: 601px) { 17 | .card { 18 | width: 20vw; 19 | height: 20vh; 20 | max-width: 400px; 21 | } 22 | } 23 | 24 | 25 | .option-content { 26 | display: flex; 27 | flex-direction: column; 28 | align-items: center; 29 | justify-content: center; 30 | height: 100%; 31 | } 32 | 33 | 34 | .option-icon { 35 | font-size: 5vh; 36 | } 37 | 38 | 39 | @media (min-width: 1080px) { 40 | .attendance-tracker { 41 | height: 20vh !important; 42 | margin-bottom: 1%; 43 | margin-left: 2.2%; 44 | margin-top: 3%; 45 | 46 | width: 50% !important; 47 | max-width: none !important; 48 | 49 | } 50 | .desktop-layout { 51 | display: flex; 52 | flex-direction: row; 53 | justify-content: space-between; 54 | } 55 | 56 | .working-days { 57 | /* padding-top: 1px !important; */ 58 | height: 10vh !important; 59 | margin-left: 3%; 60 | margin-top: 3%; 61 | margin-right: 4%; 62 | /* width: 80% !important; */ 63 | /* max-width: 600px !important; */ 64 | width: 80% !important;/* Adjust this value as needed */ 65 | max-width: none !important; /* This 66 | /* max-width:100000000 px !important; */ 67 | } 68 | 69 | } 70 | 71 | 72 | 73 | @keyframes fillAnimation { 74 | 0% { stroke-dasharray: 0 100; } 75 | 100% { stroke-dasharray: 100 0; } 76 | } 77 | 78 | .AttendanceTracker .SemiCircleProgressBar-path { 79 | animation: fillAnimation 10s ease-out forwards !important; 80 | } 81 | 82 | .AttendanceTracker .SemiCircleProgressBar-text { 83 | animation: fadeIn 10s ease-in-out !important; 84 | } 85 | 86 | @keyframes fadeIn { 87 | from { opacity: 0; } 88 | to { opacity: 1; } 89 | } 90 | 91 | 92 | .AttendanceTracker .SemiCircleProgressBar-path { 93 | stroke: #ff0000; 94 | } 95 | 96 | .AttendanceTracker .SemiCircleProgressBar-path[data-percentage='40'] { 97 | stroke: #ffa500; 98 | } 99 | 100 | .AttendanceTracker .SemiCircleProgressBar-path[data-percentage='75'] { 101 | stroke: #008000; 102 | } 103 | 104 | 105 | 106 | .semi-circle-progress { 107 | position: absolute; 108 | top: 0; 109 | left: 0; 110 | width: 100%; 111 | height: 100%; 112 | border: 10px solid transparent; 113 | border-top: 10px solid #3f51b5; 114 | border-radius: 50%; 115 | transition: transform 0.5s ease; 116 | } 117 | 118 | -------------------------------------------------------------------------------- /Frontend/src/components/AttendancePage.jsx: -------------------------------------------------------------------------------- 1 | // src/components/AttendancePage.js 2 | import React, { useState, useEffect } from "react"; 3 | import axios from "axios"; 4 | import { useNavigate } from "react-router-dom"; 5 | import Cookies from "js-cookie"; 6 | import { BookOpen, GraduationCap, UserCircle, ArrowLeft } from "lucide-react"; 7 | import { baseUrl } from "../baseurl"; 8 | import Navbar from "./Navbar"; 9 | import { useDarkMode } from "./DarkModeContext"; // Import the dark mode hook 10 | 11 | function AttendancePage() { 12 | const { darkMode } = useDarkMode(); // Access dark mode state 13 | const [attendanceData, setAttendanceData] = useState(null); 14 | const [loading, setLoading] = useState(true); 15 | const [token, setToken] = useState(null); 16 | const navigate = useNavigate(); 17 | 18 | useEffect(() => { 19 | // Retrieve token from cookies 20 | const storedToken = Cookies.get("token"); 21 | if (storedToken) { 22 | setToken(storedToken); 23 | fetchAttendanceData(storedToken); 24 | } 25 | }, []); 26 | 27 | useEffect(() => { 28 | if (token) { 29 | fetchAttendanceData(token); 30 | } 31 | }, [token]); 32 | 33 | const fetchAttendanceData = async (token) => { 34 | setLoading(true); 35 | try { 36 | const response = await axios.post( 37 | `${baseUrl}/api/subject/attendance`, 38 | { method: "314" }, 39 | { 40 | headers: { 41 | Authorization: `Bearer ${token}`, 42 | }, 43 | } 44 | ); 45 | const data = response.data; 46 | console.log(data); 47 | setAttendanceData(data); 48 | } catch (error) { 49 | console.error("Error fetching attendance data:", error); 50 | } finally { 51 | setLoading(false); 52 | } 53 | }; 54 | 55 | const getProgressColor = (percentage) => { 56 | if (percentage <= 45) return darkMode ? "bg-red-600" : "bg-red-500"; // Red for 0-45% 57 | if (percentage <= 65) return darkMode ? "bg-orange-600" : "bg-orange-500"; // Orange for 46-65% 58 | return darkMode ? "bg-green-600" : "bg-green-500"; // Green for 66% and above 59 | }; 60 | 61 | return ( 62 |
63 | 64 |
65 |
66 |
67 |
68 | {/* Go Back Button */} 69 | 78 |
79 |
80 |
81 |
82 | 83 | {/* Main Content */} 84 |
85 | {/* Attendance Overview */} 86 |
87 |
90 |
91 | 92 |

93 | Attendance Overview 94 |

95 |
96 |
97 | 98 |
99 | {loading ? ( 100 |
101 |
104 |
105 | ) : ( 106 |
107 | {attendanceData.map((subject) => ( 108 |
112 |

115 | {subject.subjectname} 116 |

117 |
118 |
119 |
120 | 123 | Theory 124 | 125 | 128 | {subject.percentage}% 129 | 130 |
131 |
134 |
138 |
139 |
140 |
141 |
142 | 145 | Practical 146 | 147 | 150 | {subject.practical}% 151 | 152 |
153 |
156 |
160 |
161 |
162 |
163 |
164 | ))} 165 |
166 | )} 167 |
168 |
169 |
170 |
171 | ); 172 | } 173 | 174 | export default AttendancePage; -------------------------------------------------------------------------------- /Frontend/src/components/AttendanceTracker.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const LinearProgressBar = ({ attendancePer }) => { 4 | // Ensure percentage is within 0-100 range 5 | const percentage = attendancePer > 100 ? 100 : attendancePer; 6 | 7 | // Determine the color based on the attendance percentage 8 | let color; 9 | if (percentage < 45) { 10 | color = '#FF0000'; // Red for 0-45% 11 | } else if (percentage < 75) { 12 | color = '#FFA500'; // Orange for 45-65% 13 | } else { 14 | color = '#00FF00'; // Green for 65% and above 15 | } 16 | 17 | return ( 18 |
19 |
26 |
27 | {percentage}% 28 |
29 |
30 | ); 31 | }; 32 | 33 | export default LinearProgressBar; -------------------------------------------------------------------------------- /Frontend/src/components/DarkModeContext.jsx: -------------------------------------------------------------------------------- 1 | import React, { createContext, useState, useEffect, useContext } from "react"; 2 | 3 | // Create the context 4 | const DarkModeContext = createContext(); 5 | 6 | // Create a provider component 7 | export const DarkModeProvider = ({ children }) => { 8 | // Initialize darkMode state from localStorage or default to false 9 | const [darkMode, setDarkMode] = useState(() => { 10 | const savedDarkMode = localStorage.getItem("darkMode"); 11 | return savedDarkMode ? JSON.parse(savedDarkMode) : false; 12 | }); 13 | 14 | // Toggle dark mode 15 | const toggleDarkMode = () => { 16 | setDarkMode((prevMode) => { 17 | const newMode = !prevMode; 18 | // Save the new mode to localStorage 19 | localStorage.setItem("darkMode", JSON.stringify(newMode)); 20 | return newMode; 21 | }); 22 | }; 23 | 24 | // Add or remove the 'dark' class from the HTML element 25 | useEffect(() => { 26 | if (darkMode) { 27 | document.documentElement.classList.add("dark"); 28 | } else { 29 | document.documentElement.classList.remove("dark"); 30 | } 31 | }, [darkMode]); 32 | 33 | return ( 34 | 35 | {children} 36 | 37 | ); 38 | }; 39 | 40 | // Custom hook to use the dark mode context 41 | export const useDarkMode = () => useContext(DarkModeContext); -------------------------------------------------------------------------------- /Frontend/src/components/ExternalResultComponent.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Loader from "./Loader"; 3 | 4 | const ExternalResultComponent = ({ resultData, totalBacklogs, darkMode }) => { 5 | if (!resultData || resultData.length === 0) { 6 | return
7 |
10 |
; 11 | } 12 | 13 | return ( 14 |
15 | {/* Total Backlogs */} 16 | {totalBacklogs !== null && ( 17 |
22 |

25 | Total Backlogs: {totalBacklogs} 26 |

27 |
28 | )} 29 | 30 | {/* Semester Results */} 31 | {resultData.map((semester, idx) => ( 32 |
38 | {/* Header */} 39 |
44 |

49 | Year {semester.year}, Semester {semester.semester} 50 |

51 |
52 | 53 | {/* Table */} 54 |
55 | 56 | 57 | 58 | {semester.columns.map((column, colIdx) => ( 59 | 67 | ))} 68 | 69 | 70 | 75 | {semester.data.map((row, rowIdx) => ( 76 | 82 | {semester.columns.map((column, colIdx) => ( 83 | 91 | ))} 92 | 93 | ))} 94 | 95 |
65 | {column} 66 |
89 | {row[column]} 90 |
96 |
97 | 98 | {/* Footer (SGPA and Credits Acquired) */} 99 |
104 |
105 | 108 | SGPA: 109 | 110 | 115 | {semester.sgpa} 116 | 117 |
118 |
119 | 122 | Credits Acquired: 123 | 124 | 129 | {semester.creditsAcquired} 130 | 131 |
132 |
133 |
134 | ))} 135 |
136 | ); 137 | }; 138 | 139 | export default ExternalResultComponent; -------------------------------------------------------------------------------- /Frontend/src/components/Feedback.jsx: -------------------------------------------------------------------------------- 1 | // src/components/FeedbackForm.js 2 | import React, { useState, useEffect } from "react"; 3 | import axios from "axios"; 4 | import Swal from "sweetalert2"; 5 | import Cookies from "js-cookie"; // Import Cookies library 6 | import Loader from "./Loader"; 7 | import { baseUrl } from "../baseurl"; 8 | import { Star } from "lucide-react"; // Import Star icon 9 | import { useNavigate } from "react-router-dom"; // Import useNavigate for routing 10 | import Navbar from "./Navbar"; // Import the Navbar component 11 | import { useDarkMode } from "./DarkModeContext"; // Import the dark mode hook 12 | 13 | const FeedbackForm = () => { 14 | const { darkMode } = useDarkMode(); // Access dark mode state 15 | const [rating, setRating] = useState(0); 16 | const [hoverRating, setHoverRating] = useState(0); 17 | const [name, setName] = useState(""); 18 | const [comments, setComments] = useState(""); 19 | const [loading, setLoading] = useState(false); 20 | const [rollno, setRollno] = useState(null); 21 | const navigate = useNavigate(); // Initialize useNavigate 22 | 23 | useEffect(() => { 24 | // Retrieve rollno from cookies 25 | const storedRollno = Cookies.get("rollno"); 26 | if (storedRollno) { 27 | setRollno(storedRollno); 28 | } 29 | }, []); 30 | 31 | const handleRatingChange = (value) => { 32 | setRating(value); 33 | }; 34 | 35 | const handleSubmit = async (e) => { 36 | e.preventDefault(); 37 | setLoading(true); 38 | 39 | try { 40 | const response = await axios.post(`${baseUrl}/api/submit/feedback`, { 41 | rating, 42 | name, 43 | comments, 44 | rollno, 45 | }); 46 | 47 | console.log("Feedback submitted successfully:", response.data); 48 | 49 | Swal.fire({ 50 | icon: "success", 51 | title: "Success!", 52 | text: "Feedback submitted successfully", 53 | confirmButtonText: "OK", 54 | }); 55 | 56 | // Reset form 57 | setRating(0); 58 | setName(""); 59 | setComments(""); 60 | } catch (error) { 61 | console.error("Error submitting feedback:", error); 62 | Swal.fire({ 63 | icon: "error", 64 | title: "Error!", 65 | text: "Failed to submit feedback. Please try again.", 66 | confirmButtonText: "OK", 67 | }); 68 | } finally { 69 | setLoading(false); 70 | } 71 | }; 72 | 73 | return ( 74 | <> 75 | {/* Add the Navbar */} 76 | 77 | 78 | {/* Feedback Form */} 79 |
82 |
83 |
88 |
89 |
90 |

93 | Your Feedback Matters 94 |

95 |

98 | Help us improve your college experience 99 |

100 |
101 | 102 | {loading ? ( 103 | 104 | ) : ( 105 |
106 | {/* Rating Stars */} 107 |
108 | 113 |
114 | {[1, 2, 3, 4, 5].map((star) => ( 115 | 133 | ))} 134 |
135 |
136 | 137 | {/* Name Input */} 138 |
139 | 147 | setName(e.target.value)} 152 | className={`block w-full rounded-lg ${ 153 | darkMode ? "bg-gray-700/50 border-gray-600" : "bg-white/50 border-gray-200" 154 | } px-4 py-3 ${ 155 | darkMode ? "text-gray-200" : "text-gray-700" 156 | } focus:border-blue-500 focus:ring-2 focus:ring-blue-500 focus:ring-opacity-20 transition-shadow duration-200`} 157 | placeholder="Enter your name" 158 | required 159 | /> 160 |
161 | 162 | {/* Comments Textarea */} 163 |
164 | 172 |