Skip to content

Commit c174796

Browse files
authored
Merge pull request Ketanop321#51 from Gamerking177/backend-and-froontend-seperate-folder
Backend and froontend seperate folder
2 parents 452aa15 + 6bfd18f commit c174796

File tree

10 files changed

+1412
-1076
lines changed

10 files changed

+1412
-1076
lines changed

package-lock.json

Lines changed: 1166 additions & 847 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
"firebase": "^11.0.1",
1515
"framer-motion": "^11.11.10",
1616
"react": "^18.3.1",
17+
"react-avatar": "^5.0.3",
1718
"react-calendar": "^5.1.0",
1819
"react-chartjs-2": "^5.2.0",
1920
"react-dom": "^18.3.1",

src/Newslettermodal.js

Lines changed: 13 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,22 @@
11
import { useEffect, useState } from 'react';
2-
import { getAuth, onAuthStateChanged } from 'firebase/auth';
32

43
function NewsletterModal() {
54
const [isOpen, setIsOpen] = useState(false);
65

76
useEffect(() => {
8-
const auth = getAuth();
9-
10-
const unsubscribe = onAuthStateChanged(auth, (user) => {
11-
if (user) {
12-
// Delay opening the modal by 3 seconds after a successful login
13-
const timer = setTimeout(() => {
14-
setIsOpen(true);
15-
}, 3000);
16-
17-
// Clear timeout if the user logs out before 3 seconds pass
18-
return () => clearTimeout(timer);
19-
} else {
20-
setIsOpen(false);
21-
}
22-
});
23-
24-
// Cleanup the listener on component unmount
25-
return () => unsubscribe();
7+
const storedUser = localStorage.getItem("user");
8+
9+
if (storedUser) {
10+
// Delay opening the modal by 3 seconds after detecting login
11+
const timer = setTimeout(() => {
12+
setIsOpen(true);
13+
}, 3000);
14+
15+
// Cleanup timeout
16+
return () => clearTimeout(timer);
17+
} else {
18+
setIsOpen(false);
19+
}
2620
}, []);
2721

2822
const closeModal = () => {

src/auth/login/login.js

Lines changed: 104 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -1,104 +1,128 @@
1-
import React, { useState } from 'react';
2-
import { Navigate, Link } from 'react-router-dom';
3-
import { doSignInWithEmailAndPassword } from '../../firebase/auth';
4-
import { useAuth } from '../../context/authContext/authContext';
5-
6-
const InputField = ({ label, type, value, onChange, required }) => (
7-
<div>
8-
<label className="text-sm text-gray-600 font-bold">{label}</label>
9-
<input
10-
type={type}
11-
autoComplete={type === 'email' ? 'email' : 'current-password'}
12-
required={required}
13-
value={value}
14-
onChange={onChange}
15-
className="w-full mt-2 px-3 py-2 text-gray-500 bg-transparent outline-none border focus:border-indigo-600 shadow-sm rounded-lg transition duration-300"
16-
/>
17-
</div>
18-
);
1+
import { useState, useEffect } from "react";
2+
import { useNavigate, Link } from "react-router-dom";
3+
import { useAuth } from "../../context/authContext/authContext"; // 🔹 Import authentication context
4+
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
5+
import { faEye, faEyeSlash } from "@fortawesome/free-solid-svg-icons";
6+
import { motion } from "framer-motion"; // 🔹 Import Framer Motion for animations
197

208
const Login = () => {
21-
const { userLoggedIn } = useAuth(); // Check if user is already logged in
22-
const [email, setEmail] = useState('');
23-
const [password, setPassword] = useState('');
9+
const { userLoggedIn, login } = useAuth(); // 🔹 Getting authentication functions
10+
const navigate = useNavigate();
11+
const [email, setEmail] = useState("");
12+
const [password, setPassword] = useState("");
2413
const [isSigningIn, setIsSigningIn] = useState(false);
25-
const [error, setError] = useState(null); // Error state for login errors
14+
const [error, setError] = useState(null);
15+
const [showPassword, setShowPassword] = useState(false); // 🔹 State for password visibility
16+
17+
useEffect(() => {
18+
if (userLoggedIn) {
19+
navigate("/"); // 🔹 Redirect user if already logged in
20+
}
21+
}, [userLoggedIn, navigate]);
22+
23+
const validateForm = () => {
24+
if (!email || !password) {
25+
setError("Email and Password are required.");
26+
return false;
27+
}
28+
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
29+
if (!emailRegex.test(email)) {
30+
setError("Invalid email format.");
31+
return false;
32+
}
33+
if (password.length < 6) {
34+
setError("Password must be at least 6 characters.");
35+
return false;
36+
}
37+
return true;
38+
};
2639

2740
const onSubmit = async (e) => {
2841
e.preventDefault();
29-
30-
if (!isSigningIn) {
42+
if (!isSigningIn && validateForm()) {
3143
setIsSigningIn(true);
32-
setError(null); // Reset error state
44+
setError(null);
3345

3446
try {
35-
await doSignInWithEmailAndPassword(email, password);
47+
await login(email, password); // 🔹 Calling login function from auth context
3648
} catch (error) {
37-
setError('Invalid email or password.'); // Show custom error message
49+
setError(error.message || "Invalid email or password.");
3850
console.error("Login error:", error.message);
3951
} finally {
40-
setIsSigningIn(false); // Reset loading state
52+
setIsSigningIn(false);
4153
}
4254
}
4355
};
4456

45-
if (userLoggedIn) {
46-
return <Navigate to="/" replace />; // Redirect to home if logged in
47-
}
48-
4957
return (
50-
<div>
51-
<main className="w-full h-screen flex items-center justify-center">
52-
<div className="w-96 text-gray-600 space-y-5 p-4 shadow-xl border rounded-xl">
53-
<div className="text-center">
54-
<h3 className="mt-2 text-gray-800 text-xl font-semibold sm:text-2xl">Welcome Back</h3>
55-
</div>
56-
<form onSubmit={onSubmit} className="space-y-5">
57-
<InputField
58-
label="Email"
59-
type="email"
60-
value={email}
61-
onChange={(e) => setEmail(e.target.value)}
62-
required
58+
<main className="w-full h-screen flex items-center justify-center">
59+
{/* 🔹 Animated Login Form */}
60+
<motion.div
61+
initial={{ opacity: 0, y: -50 }}
62+
animate={{ opacity: 1, y: 0 }}
63+
transition={{ duration: 0.6, ease: "easeOut" }}
64+
className="w-96 text-gray-600 space-y-5 p-4 shadow-xl border rounded-xl"
65+
>
66+
<div className="text-center">
67+
<h3 className="mt-2 text-gray-800 text-xl font-semibold sm:text-2xl">Welcome Back</h3>
68+
</div>
69+
<form onSubmit={onSubmit} className="space-y-5">
70+
<div>
71+
<label className="text-sm text-gray-600 font-bold">Email</label>
72+
<input
73+
type="email"
74+
autoComplete="email"
75+
required
76+
value={email}
77+
onChange={(e) => setEmail(e.target.value)}
78+
className="w-full mt-2 px-3 py-2 text-gray-500 bg-transparent outline-none border focus:border-indigo-600 shadow-sm rounded-lg transition duration-300"
6379
/>
64-
<InputField
65-
label="Password"
66-
type="password"
67-
value={password}
68-
onChange={(e) => setPassword(e.target.value)}
69-
required
80+
</div>
81+
82+
{/* 🔹 Password Field with Show/Hide Toggle */}
83+
<div className="relative">
84+
<label className="text-sm text-gray-600 font-bold">Password</label>
85+
<input
86+
type={showPassword ? "text" : "password"}
87+
autoComplete="current-password"
88+
required
89+
value={password}
90+
onChange={(e) => setPassword(e.target.value)}
91+
className="w-full mt-2 px-3 py-2 text-gray-500 bg-transparent outline-none border focus:border-indigo-600 shadow-sm rounded-lg transition duration-300 pr-10"
7092
/>
93+
{/* 👁 Password Visibility Toggle */}
94+
<motion.span
95+
className="absolute top-10 right-3 cursor-pointer text-gray-500 hover:text-indigo-600 transition"
96+
onClick={() => setShowPassword(!showPassword)}
97+
transition={{ duration: 0.3, ease: "easeInOut" }}
98+
>
99+
<FontAwesomeIcon icon={showPassword ? faEyeSlash : faEye} size="lg" />
100+
</motion.span>
101+
</div>
71102

72-
{error && (
73-
<p className="text-red-500 text-sm text-center" aria-live="assertive">{error}</p>
74-
)}
103+
{error && <p className="text-red-500 text-sm text-center" aria-live="assertive">{error}</p>}
75104

76-
<button
77-
type="submit"
78-
disabled={isSigningIn}
79-
className={`w-full py-2 text-white font-bold rounded-lg transition duration-300
80-
${isSigningIn ? 'bg-gray-400' : 'bg-indigo-600 hover:bg-indigo-700'}`}
81-
>
82-
{isSigningIn ? (
83-
<span className="flex items-center justify-center">
84-
<svg className="animate-spin h-5 w-5 mr-3" viewBox="0 0 24 24">
85-
<circle className="text-indigo-200" cx="12" cy="12" r="10" strokeWidth="4" />
86-
<path className="text-indigo-600" fill="currentColor" d="M4 12c0 1.1.9 2 2 2h1c0-2.21-1.79-4-4-4v2zm16-2c-1.1 0-2 .9-2 2h2c0-1.1-.9-2-2-2zm-2 0c0 2.21 1.79 4 4 4v-2h-1c-1.1 0-2-.9-2-2h-2zm-4 6c2.21 0 4-1.79 4-4h-2c0 1.1-.9 2-2 2v2z" />
87-
</svg>
88-
Signing In...
89-
</span>
90-
) : 'Sign In'}
91-
</button>
92-
</form>
93-
<p className="text-center text-sm">
94-
Don't have an account? <Link to="/register" className="hover:underline font-bold">Sign up</Link>
95-
</p>
96-
<p className="text-center text-sm">
97-
<Link to="/forgot-password" className="hover:underline">Forgot Password?</Link>
98-
</p>
99-
</div>
100-
</main>
101-
</div>
105+
{/* 🔹 Submit Button with Animation */}
106+
<motion.button
107+
type="submit"
108+
disabled={isSigningIn}
109+
whileHover={{ scale: 1.05 }}
110+
whileTap={{ scale: 0.95 }}
111+
className={`w-full py-2 text-white font-bold rounded-lg transition duration-300
112+
${isSigningIn ? "bg-gray-400" : "bg-indigo-600 hover:bg-indigo-700"}`}
113+
>
114+
{isSigningIn ? "Signing In..." : "Sign In"}
115+
</motion.button>
116+
</form>
117+
118+
<p className="text-center text-sm">
119+
Don't have an account? <Link to="/register" className="hover:underline font-bold">Sign up</Link>
120+
</p>
121+
<p className="text-center text-sm">
122+
<Link to="/forgot-password" className="hover:underline">Forgot Password?</Link>
123+
</p>
124+
</motion.div>
125+
</main>
102126
);
103127
};
104128

src/components/ExamAssignmentSchedule.js

Lines changed: 58 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,30 +2,36 @@ import React, { useState } from 'react';
22
import Navbar from './ScheduleDashboard';
33

44
function ExamAssignmentSchedule() {
5-
// Define selectedTab state to keep track of the active tab
65
const [selectedTab, setSelectedTab] = useState('exams');
6+
const [showSchedule, setShowSchedule] = useState(false);
77

88
const upcomingExams = [
9-
{ subject: 'Mathematics', date: '2024-11-20' },
10-
{ subject: 'Physics', date: '2024-11-25' },
9+
{ subject: 'Mathematics', date: '2024-11-20', startTime: '9:00 AM', endTime: '11:00 AM', room: 'Room 101' },
10+
{ subject: 'Physics', date: '2024-11-25', startTime: '1:00 PM', endTime: '3:00 PM', room: 'Room 102' },
11+
{ subject: 'Chemistry', date: '2024-11-28', startTime: '10:00 AM', endTime: '12:00 PM', room: 'Room 103' },
1112
];
1213

1314
const assignments = [
1415
{ title: 'Math Assignment', dueDate: '2024-11-15', detailsLink: '#' },
1516
{ title: 'Physics Lab Report', dueDate: '2024-11-18', detailsLink: '#' },
1617
];
1718

19+
const toggleScheduleView = () => {
20+
setShowSchedule(!showSchedule);
21+
};
22+
1823
return (
1924
<div>
20-
{/* Pass selectedTab and setSelectedTab to Navbar if needed */}
2125
<Navbar selectedTab={selectedTab} setSelectedTab={setSelectedTab} />
2226

2327
<h2 className="text-2xl font-semibold mb-4">Exam & Assignment Schedule</h2>
2428

25-
{/* Tabs */}
2629
<div className="flex space-x-4 mb-8">
2730
<button
28-
onClick={() => setSelectedTab('exams')}
31+
onClick={() => {
32+
setSelectedTab('exams');
33+
toggleScheduleView();
34+
}}
2935
className={`py-2 px-4 ${selectedTab === 'exams' ? 'bg-blue-500 text-white' : 'bg-gray-200'}`}
3036
>
3137
Upcoming Exams
@@ -38,8 +44,8 @@ function ExamAssignmentSchedule() {
3844
</button>
3945
</div>
4046

41-
{/* Conditionally Render Content Based on selectedTab */}
42-
{selectedTab === 'exams' && (
47+
{/* Conditionally Render Content Based on selectedTab and showSchedule */}
48+
{selectedTab === 'exams' && !showSchedule && (
4349
<div className="mb-8">
4450
<h3 className="text-xl font-medium mb-2">Upcoming Exams</h3>
4551
<ul className="bg-white p-4 shadow rounded">
@@ -67,6 +73,50 @@ function ExamAssignmentSchedule() {
6773
</ul>
6874
</div>
6975
)}
76+
77+
{showSchedule && <ExamSchedule />} {/* Display exam schedule when showSchedule is true */}
78+
</div>
79+
);
80+
}
81+
82+
// Exam schedule component in table format
83+
function ExamSchedule() {
84+
const upcomingExams = [
85+
{ day: 'Wednesday', date: '2024-11-20', startTime: '9:00 AM', endTime: '10:30 AM', subject: 'Mathematics', room: 'Room 101' },
86+
{ day: 'Friday', date: '2024-11-25', startTime: '11:00 AM', endTime: '12:30 PM', subject: 'Physics', room: 'Room 102' },
87+
{ day: 'Monday', date: '2024-11-28', startTime: '1:00 PM', endTime: '2:30 PM', subject: 'Chemistry', room: 'Room 103' },
88+
];
89+
90+
return (
91+
<div>
92+
<h3 className="text-xl font-medium mb-2">Exam Schedule - Fall 2023</h3>
93+
<div className="bg-white p-4 shadow rounded">
94+
<h4 className="text-lg font-semibold mb-2">Weekly Exam Schedule</h4>
95+
<table className="w-full text-left border-collapse">
96+
<thead>
97+
<tr>
98+
<th className="border-b p-2">Day</th>
99+
<th className="border-b p-2">Date</th>
100+
<th className="border-b p-2">Start Time</th>
101+
<th className="border-b p-2">End Time</th>
102+
<th className="border-b p-2">Subject</th>
103+
<th className="border-b p-2">Room No.</th>
104+
</tr>
105+
</thead>
106+
<tbody>
107+
{upcomingExams.map((exam, index) => (
108+
<tr key={index}>
109+
<td className="border-b p-2">{exam.day}</td>
110+
<td className="border-b p-2">{exam.date}</td>
111+
<td className="border-b p-2">{exam.startTime}</td>
112+
<td className="border-b p-2">{exam.endTime}</td>
113+
<td className="border-b p-2">{exam.subject}</td>
114+
<td className="border-b p-2">{exam.room}</td>
115+
</tr>
116+
))}
117+
</tbody>
118+
</table>
119+
</div>
70120
</div>
71121
);
72122
}

0 commit comments

Comments
 (0)