Skip to content

Commit 3a4fa96

Browse files
Merge pull request #442 from Sourabh782/admin
implemented admin login/signup
2 parents e5d522e + 7c09828 commit 3a4fa96

File tree

13 files changed

+433
-9
lines changed

13 files changed

+433
-9
lines changed

backend/controller/admin.controller.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,11 +90,16 @@ async function loginAdmin(req, res) {
9090
const token = jwt.sign(payload, process.env.JWT_SECRET, {
9191
expiresIn: "1h",
9292
});
93+
res.cookie("authToken", token, {
94+
maxAge: 1000 * 60 * 60,
95+
httpOnly: true,
96+
secure: true,
97+
});
9398
res.json({
9499
message: "Login successful",
95100
token,
96101
role: "admin",
97-
admin: { id: admin._id, name: admin.name, email: admin.email },
102+
admin: { id: admin._id, name: admin.name, email: admin.email, role: admin.role || "admin" },
98103
});
99104
} catch (error) {
100105
logger.error("Error logging in admin:", {

backend/controller/customer.controller.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@ async function loginCustomer(req, res) {
152152
id: customer._id,
153153
name: customer.name,
154154
email: customer.email,
155+
role: "customer"
155156
},
156157
});
157158
} catch (error) {

frontend/src/components/Pages/Admin.jsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
import { message } from 'antd';
22
import React, { useEffect, useState } from 'react';
33
import { useNavigate } from 'react-router-dom';
4+
import { useUser } from '../../context/userContext';
45

56
const Admin = () => {
67
const [events, setEvents] = useState([]);
78
const [error, setError] = useState(null);
89
const navigate = useNavigate();
10+
const {user} = useUser();
911

1012
// Fetch all events
1113
const fetchData = async () => {
@@ -122,7 +124,7 @@ const Admin = () => {
122124
<div className="h-fit min-h-screen w-screen flex flex-col items-center justify-start p-12 pt-[10vh]">
123125
<div className="Header w-full flex flex-col items-center">
124126
<h1 className="title text-[#323232] font-black text-7xl mb-6">
125-
Hi {Admin.name}!
127+
Hi {user.name}!
126128
</h1>
127129
<h1 className="mt-[-2vh] text-[#666] font-semibold text-2xl">
128130
Welcome to Admin Panel
@@ -265,7 +267,7 @@ const Admin = () => {
265267
<div className="container grid grid-cols-1 gap-8 px-4 md:grid-cols-2 lg:grid-cols-1 md:px-6">
266268
<div className="event-list">
267269
{error && <p className="text-red-500">{error}</p>}
268-
{events.map((event) => (
270+
{events.length > 0 && events.map((event) => (
269271
<div
270272
key={event._id}
271273
className="grid grid-cols-1 md:grid-cols-2 gap-10 lg:grid-cols-1 xl:grid-cols-2 md:px-6 lg:px-4 xl:px-0"
Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
import React, { useState, useEffect } from 'react';
2+
import photo from '../../../assets/login.png';
3+
import { Link, useNavigate } from 'react-router-dom';
4+
import { message } from 'antd';
5+
import Cookies from 'js-cookie';
6+
import { FaEye } from 'react-icons/fa';
7+
import { FaEyeSlash } from 'react-icons/fa6';
8+
import { useUser } from '../../../context/userContext';
9+
10+
const AdminLogin = () => {
11+
const API_URL = import.meta.env.VITE_BACKEND_URL || 'http://localhost:3000';
12+
const [data, setData] = useState({
13+
email: '',
14+
password: '',
15+
});
16+
const [hidden, setHidden] = useState(true);
17+
const [isLoading, setIsLoading] = useState(false);
18+
const [error, setError] = useState(null);
19+
const {user, setUser} = useUser();
20+
21+
const navigate = useNavigate();
22+
23+
const handleChange = (e) => {
24+
setData({ ...data, [e.target.name]: e.target.value });
25+
};
26+
27+
const handleSubmit = async (e) => {
28+
e.preventDefault();
29+
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
30+
if (!emailRegex.test(data.email)) {
31+
setError('Please enter a valid email address');
32+
return;
33+
}
34+
if (data.password.length < 8) {
35+
setError('Password must be at least 8 characters long');
36+
return;
37+
}
38+
setIsLoading(true);
39+
setError(null);
40+
try {
41+
const response = await fetch(`${API_URL}/api/admin/login`, {
42+
method: 'POST',
43+
headers: {
44+
'Content-Type': 'application/json',
45+
},
46+
body: JSON.stringify(data),
47+
});
48+
const result = await response.json();
49+
if (!response.ok) {
50+
throw new Error(result.message || 'Login failed');
51+
}
52+
const res = JSON.stringify(result.admin)
53+
Cookies.set('authToken', result.token, { expires: 1, secure: true });
54+
Cookies.set("authenticatedUser", res, {expires: 1, secure: true})
55+
setUser(result.admin)
56+
message.success('Login successful');
57+
navigate('/admin');
58+
} catch (err) {
59+
setError(err.message || 'An error occurred. Please try again.');
60+
} finally {
61+
setIsLoading(false);
62+
}
63+
};
64+
65+
useEffect(() => {
66+
window.scrollTo(0, 0);
67+
}, []);
68+
69+
return (
70+
<div className="w-screen h-screen dark:bg-black flex items-center justify-center lg:pt-10 px-4">
71+
{/* Background Image */}
72+
<img
73+
src={photo}
74+
alt="login"
75+
loading="lazy"
76+
className="absolute w-3/4 lg:w-auto lg:opacity-100 opacity-10 object-cover"
77+
/>
78+
{/* Login Form */}
79+
<form
80+
onSubmit={handleSubmit}
81+
className="z-10 p-8 lg:p-14 bg-[#f1e9dc] dark:bg-amber-800 dark:text-white flex flex-col gap-6 rounded-lg border-2 border-black shadow-[4px_4px_0px_0px_black] w-full max-w-md lg:max-w-xl"
82+
>
83+
<div className="text-[#323232] dark:text-white font-black text-4xl lg:text-6xl mb-2">
84+
Admin Login,
85+
<span className="block text-[#666] dark:text-gray-400 font-semibold text-lg lg:text-2xl mt-1">
86+
Log in to continue
87+
</span>
88+
</div>
89+
90+
<input
91+
className="w-full h-12 rounded-md border-2 border-black bg-beige shadow-[4px_4px_0px_0px_black] text-[15px] font-semibold text-[#323232] p-2.5 focus:outline-none focus:border-[#2d8cf0] placeholder-[#666]"
92+
name="email"
93+
placeholder="Email"
94+
type="email"
95+
onChange={handleChange}
96+
/>
97+
98+
<div className="relative w-full">
99+
<input
100+
className="w-full h-12 rounded-md border-2 border-black bg-beige shadow-[4px_4px_0px_0px_black] text-[15px] font-semibold text-[#323232] p-2.5 focus:outline-none focus:border-[#2d8cf0] placeholder-[#666]"
101+
name="password"
102+
placeholder="Password"
103+
type={hidden ? 'password' : 'text'}
104+
onChange={handleChange}
105+
/>
106+
<button
107+
className="absolute top-1/2 transform -translate-y-1/2 right-4"
108+
onClick={(e) => {
109+
e.preventDefault();
110+
setHidden(!hidden);
111+
}}
112+
>
113+
{hidden ? <FaEyeSlash /> : <FaEye />}
114+
</button>
115+
</div>
116+
117+
<Link
118+
to="/email-verify"
119+
className="text-sm lg:text-base text-gray-500 dark:text-gray-200 hover:text-red-500 transition"
120+
>
121+
Forgot Password?
122+
</Link>
123+
124+
<h3 className="flex justify-between items-center w-full text-sm lg:text-base">
125+
Don’t have an account?
126+
<Link
127+
to="/admin-signup"
128+
className="text-green-500 font-semibold hover:scale-110 transition"
129+
>
130+
Register Here
131+
</Link>
132+
</h3>
133+
134+
<Link
135+
to={`${API_URL}/api/user/auth/google`}
136+
className="w-full"
137+
>
138+
<button
139+
type="button"
140+
className="w-full h-12 rounded-md border-2 dark:text-white border-black bg-beige shadow-[4px_4px_0px_0px_black] text-[17px] font-semibold text-[#323232] transition active:translate-x-[3px] active:translate-y-[3px]"
141+
>
142+
Sign in with Google
143+
</button>
144+
</Link>
145+
146+
{error && <p className="text-red-500 mt-2">{error}</p>}
147+
148+
<button
149+
type="submit"
150+
className="w-full h-12 rounded-md dark:text-white border-2 border-black bg-beige shadow-[4px_4px_0px_0px_black] text-[17px] font-semibold text-[#323232] transition active:translate-x-[3px] active:translate-y-[3px]"
151+
>
152+
{isLoading ? 'Loading...' : 'Let’s Log you in →'}
153+
</button>
154+
</form>
155+
</div>
156+
);
157+
};
158+
159+
export default AdminLogin;

0 commit comments

Comments
 (0)