Fix: Prevent Sidebar component from crashing when user data is null
Added a check to ensure the user object is not null before accessing its properties. This prevents the application from crashing due to a TypeError when no user data is available in localStorage.
This commit is contained in:
parent
f900881dd7
commit
8bde35342c
12
db.json
12
db.json
@ -23,7 +23,7 @@
|
||||
"email": "adminuser@example.com"
|
||||
}
|
||||
],
|
||||
"employee": [
|
||||
"employees": [
|
||||
{
|
||||
"id": "1",
|
||||
"name": "Employee User",
|
||||
@ -112,6 +112,16 @@
|
||||
"email": "tejas001@gmail.com",
|
||||
"address": " Baner, Pune",
|
||||
"mobile": "8675493099"
|
||||
},
|
||||
{
|
||||
"id": "e539",
|
||||
"firstname": "aaaa",
|
||||
"lastname": "bbbb",
|
||||
"age": "25",
|
||||
"gender": "male",
|
||||
"email": "aaaa@gmail.com",
|
||||
"address": "pune",
|
||||
"mobile": "7559393995"
|
||||
}
|
||||
]
|
||||
}
|
@ -11,6 +11,7 @@ import CustomerMeasurements from './components/customer/CustomerMeasurements';
|
||||
import { AuthProvider, AuthContext } from './contexts/AuthContext';
|
||||
import EmployeeList from './components/admin/EmployeeList';
|
||||
import AddEmployee from './components/admin/AddEmployee';
|
||||
import EmployeeProfile from './components/admin/EmployeeProfile';
|
||||
|
||||
const { Content } = Layout;
|
||||
|
||||
@ -33,6 +34,7 @@ const App = () => {
|
||||
<Route path="/measurements" element={<CustomerMeasurements />} />
|
||||
<Route path="employees" element={<PrivateRoute><EmployeeList /></PrivateRoute>} />
|
||||
<Route path="/add-employee" element={<PrivateRoute><AddEmployee /></PrivateRoute>} />
|
||||
<Route path="/employee-profile" element={<PrivateRoute><EmployeeProfile /></PrivateRoute>} />
|
||||
</Routes>
|
||||
</Router>
|
||||
</AuthProvider>
|
||||
|
@ -15,16 +15,16 @@ const LoginPage = () => {
|
||||
|
||||
try {
|
||||
const response = await axiosInstance.get('http://localhost:5000/authlogin');
|
||||
|
||||
const user = response.data.find(user => user.email === email && user.password === password);
|
||||
|
||||
|
||||
if (user) {
|
||||
localStorage.setItem("loggedInUser", JSON.stringify(user))
|
||||
if (user.role === 'admin') {
|
||||
navigate('/admin');
|
||||
} else if (user.role === 'employee') {
|
||||
navigate('/employee');
|
||||
} else {
|
||||
setError('Invalid credentials');
|
||||
setError('Invalid role.');
|
||||
}
|
||||
} else {
|
||||
setError('Invalid credentials');
|
||||
|
48
src/components/Auth/ResetPasswordRequest.jsx
Normal file
48
src/components/Auth/ResetPasswordRequest.jsx
Normal file
@ -0,0 +1,48 @@
|
||||
// import React, { useState } from 'react';
|
||||
// import axiosInstance from '../../api/axiosConfig';
|
||||
// import './ResetPasswordRequest.css';
|
||||
|
||||
// const ResetPasswordRequest = () => {
|
||||
// const [email, setEmail] = useState('');
|
||||
// const [message, setMessage] = useState('');
|
||||
|
||||
// const handleResetRequest = async (e) => {
|
||||
// e.preventDefault();
|
||||
// try {
|
||||
// await axiosInstance.post('http://localhost:5000/auth/forgot-password', { email });
|
||||
// setMessage('Password reset email sent. Please check your inbox.');
|
||||
// } catch (error) {
|
||||
// setMessage('Error sending password reset email. Please try again.');
|
||||
// }
|
||||
// };
|
||||
|
||||
// return (
|
||||
// <div className="flex flex-row min-h-screen justify-center items-center">
|
||||
// <div className="reset-request-page flex items-center justify-center min-h-screen w-full md:w-1/2 lg:w-1/3 p-4">
|
||||
// <div className="w-full">
|
||||
// <h1>Reset Password</h1>
|
||||
// <p>Enter your email to receive password reset instructions.</p>
|
||||
// {message && <p className="message">{message}</p>}
|
||||
// <form onSubmit={handleResetRequest} className="space-y-4">
|
||||
// <label htmlFor="email" className="block"></label>
|
||||
// <input
|
||||
// type="email"
|
||||
// id="email"
|
||||
// name="email"
|
||||
// value={email}
|
||||
// onChange={(e) => setEmail(e.target.value)}
|
||||
// placeholder="Enter your email"
|
||||
// required
|
||||
// className="input-field"
|
||||
// />
|
||||
// <button type="submit" className="reset-button">
|
||||
// Send Reset Instructions
|
||||
// </button>
|
||||
// </form>
|
||||
// </div>
|
||||
// </div>
|
||||
// </div>
|
||||
// );
|
||||
// };
|
||||
|
||||
// export default ResetPasswordRequest;
|
@ -39,7 +39,7 @@ const AddEmployee = () => {
|
||||
<div className="w-full flex flex-col min-h-screen text-black">
|
||||
<div className="min-h-screen text-gray-800 p-6">
|
||||
<div className="flex justify-between items-center mb-6">
|
||||
<h1 className="text-2xl font-semibold text-blue-900">Creating Employee Account</h1>
|
||||
<h1 className="text-2xl font-semibold text-blue-900">creating employee account</h1>
|
||||
<Link to="/" className="text-blue-900">Skip for now</Link>
|
||||
</div>
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
|
||||
@ -48,7 +48,7 @@ const AddEmployee = () => {
|
||||
<div className="inline-block relative">
|
||||
<div className="bg-gray-300 w-24 h-24 rounded-full mx-auto"></div>
|
||||
<button className="absolute bottom-0 left-1/2 transform -translate-x-1/2 bg-#4b5563 text-white text-xs px-2 py-1 rounded-full">
|
||||
Add Employee Image
|
||||
add employee image
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@ -56,7 +56,7 @@ const AddEmployee = () => {
|
||||
<div className="md:col-span-2 space-y-4">
|
||||
<form onSubmit={handleAddEmployeeSubmit}>
|
||||
<div>
|
||||
<label className="block text-gray-800 font-medium">Employee Firstname:</label>
|
||||
<label className="block text-gray-800 font-medium">employee firstname:</label>
|
||||
<input
|
||||
type="text"
|
||||
name="firstname"
|
||||
@ -66,7 +66,7 @@ const AddEmployee = () => {
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-gray-800 font-medium">Employee Lastname:</label>
|
||||
<label className="block text-gray-800 font-medium">employee lastname:</label>
|
||||
<input
|
||||
type="text"
|
||||
name="lastname"
|
||||
@ -76,7 +76,7 @@ const AddEmployee = () => {
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-gray-800 font-medium">Age:</label>
|
||||
<label className="block text-gray-800 font-medium">age:</label>
|
||||
<input
|
||||
type="number"
|
||||
name="age"
|
||||
@ -86,7 +86,7 @@ const AddEmployee = () => {
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-gray-800 font-medium">Gender:</label>
|
||||
<label className="block text-gray-800 font-medium">gender:</label>
|
||||
<select
|
||||
name="gender"
|
||||
value={employeeData.gender}
|
||||
@ -94,13 +94,13 @@ const AddEmployee = () => {
|
||||
className="input-underline w-full p-2 border-b border-gray-400 focus:border-#4b5563"
|
||||
>
|
||||
<option value="" disabled>Select Gender</option>
|
||||
<option value="male">Male</option>
|
||||
<option value="female">Female</option>
|
||||
<option value="other">Other</option>
|
||||
<option value="male">male</option>
|
||||
<option value="female">female</option>
|
||||
<option value="other">other</option>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-gray-800 font-medium">Email:</label>
|
||||
<label className="block text-gray-800 font-medium">email:</label>
|
||||
<input
|
||||
type="email"
|
||||
name="email"
|
||||
@ -110,7 +110,7 @@ const AddEmployee = () => {
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-gray-800 font-medium">Address:</label>
|
||||
<label className="block text-gray-800 font-medium">address:</label>
|
||||
<input
|
||||
type="text"
|
||||
name="address"
|
||||
@ -120,7 +120,7 @@ const AddEmployee = () => {
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-gray-800 font-medium">Mobile No:</label>
|
||||
<label className="block text-gray-800 font-medium">mobile no:</label>
|
||||
<input
|
||||
type="text"
|
||||
name="mobile"
|
||||
@ -132,7 +132,7 @@ const AddEmployee = () => {
|
||||
<br />
|
||||
<div className="text-center">
|
||||
<button type="submit" className="bg-#0e355b text-#d1d5db px-4 py-2 rounded-md font-semibold">
|
||||
Create Account
|
||||
create account
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
@ -25,12 +25,12 @@ const EmployeeList = ({ className = '' }) => {
|
||||
};
|
||||
|
||||
const handleAddEmployee = () => {
|
||||
navigate('/add-employee');
|
||||
};
|
||||
navigate('/add-employee');
|
||||
};
|
||||
|
||||
// const onEmployeeCardsClick = useCallback(() => {
|
||||
// navigate('/employee-profile');
|
||||
// }, [navigate]);
|
||||
const onEmployeeCardsClick = useCallback(() => {
|
||||
navigate('/employee-profile');
|
||||
}, [navigate]);
|
||||
|
||||
return (
|
||||
<div className="flex flex-row min-h-screen">
|
||||
@ -38,12 +38,12 @@ const EmployeeList = ({ className = '' }) => {
|
||||
<div className="flex-grow p-6 bg-gray-100">
|
||||
<div className="bg-white p-6 rounded-lg shadow">
|
||||
<div className="flex justify-between items-center mb-6">
|
||||
<h1 className="text-2xl font-semibold text-gray-800">Employees List</h1>
|
||||
<h1 className="text-2xl font-semibold text-gray-800">employees list</h1>
|
||||
<button
|
||||
className="bg-#0e355b text-d1d5db px-4 py-2 rounded-md text-sm"
|
||||
onClick={handleAddEmployee}
|
||||
>
|
||||
Add New Employee
|
||||
add new employee
|
||||
</button>
|
||||
</div>
|
||||
<div className="flex items-center mb-4">
|
||||
@ -61,16 +61,16 @@ const EmployeeList = ({ className = '' }) => {
|
||||
d="M3 4a1 1 0 011-1h16a1 1 0 011 1v2.586a1 1 0 01-.293.707l-6.414 6.414a1 1 0 00-.293.707V17l-4 4v-6.586a1 1 0 00-.293-.707L3.293 7.293A1 1 0 013 6.586V4z"
|
||||
/>
|
||||
</svg>
|
||||
<span className="text-sm text-gray-600">Filter</span>
|
||||
<span className="text-sm text-gray-600">filter</span>
|
||||
</div>
|
||||
<p className="text-sm text-gray-600 mb-4">Total Employees ({employees.length})</p>
|
||||
<p className="text-sm text-gray-600 mb-4">total employees ({employees.length})</p>
|
||||
<table className="w-full bg-white">
|
||||
<thead>
|
||||
<tr className="text-left text-xs uppercase text-gray-600 border-b">
|
||||
<th className="py-2">#</th>
|
||||
<th className="py-2">Employee Name</th>
|
||||
<th className="py-2">Email Address</th>
|
||||
<th className="py-2">Details</th>
|
||||
<th className="py-2">employee name</th>
|
||||
<th className="py-2">email address</th>
|
||||
<th className="py-2">details</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@ -82,9 +82,9 @@ const EmployeeList = ({ className = '' }) => {
|
||||
<td className="py-2 text-gray-800">
|
||||
<button
|
||||
className="text-#4b5563 underline"
|
||||
// onClick={onEmployeeCardsClick}
|
||||
onClick={onEmployeeCardsClick}
|
||||
>
|
||||
View Details
|
||||
view details
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
|
157
src/components/admin/EmployeeProfile.jsx
Normal file
157
src/components/admin/EmployeeProfile.jsx
Normal file
@ -0,0 +1,157 @@
|
||||
import React, { useCallback } from "react";
|
||||
import { useNavigate, useLocation } from "react-router-dom";
|
||||
import Sidebar from '../sidebar/Sidebar';
|
||||
import axiosInstance from '../../api/axiosConfig';
|
||||
// import ActionButtons from "../components/ActionButtons";
|
||||
// import Profile from "../components/Profile";
|
||||
|
||||
const EmployeeProfile = () => {
|
||||
const navigate = useNavigate();
|
||||
const location = useLocation();
|
||||
const { employee } = location.state || {};
|
||||
|
||||
const onButtonLabelsContainerClick = useCallback(() => {
|
||||
navigate("/adminemployee-account-delete");
|
||||
}, [navigate]);
|
||||
|
||||
const onHomeIconClick = useCallback(() => {
|
||||
navigate("/adminhome");
|
||||
}, [navigate]);
|
||||
|
||||
const onHeadingContainerClick = useCallback(() => {
|
||||
navigate("/adminemployee-list");
|
||||
}, [navigate]);
|
||||
|
||||
if (!employee) {
|
||||
return <div>Employee data not found</div>;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="w-full relative bg-brooks-color-system-secondary-brand overflow-hidden flex flex-row items-start justify-start leading-[normal] tracking-[normal]">
|
||||
<div className="overflow-hidden flex flex-col items-start justify-start pt-4 px-5 pb-[42px] gap-[136px] z-[1] mq450:pb-5 mq450:box-border mq825:pt-5 mq825:pb-[27px] mq825:box-border">
|
||||
<div className="flex flex-row items-start justify-start pt-0 px-0 pb-2.5">
|
||||
<img
|
||||
className="h-10 w-10 relative"
|
||||
loading="lazy"
|
||||
alt=""
|
||||
src="/brooks-logo3.svg"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex flex-row items-start justify-start py-0 pr-2 pl-[7px]">
|
||||
<div className="flex flex-col items-start justify-start gap-[60px]">
|
||||
<img
|
||||
className="w-[25px] h-[25px] relative overflow-hidden shrink-0 cursor-pointer"
|
||||
loading="lazy"
|
||||
alt=""
|
||||
src="/home-icon3.svg"
|
||||
onClick={onHomeIconClick}
|
||||
/>
|
||||
<img
|
||||
className="w-[25px] h-[25px] relative overflow-hidden shrink-0"
|
||||
loading="lazy"
|
||||
alt=""
|
||||
src="/customer-list-icon3.svg"
|
||||
/>
|
||||
<img
|
||||
className="w-[25px] h-[25px] relative overflow-hidden shrink-0"
|
||||
loading="lazy"
|
||||
alt=""
|
||||
src="/orders-iocn3.svg"
|
||||
/>
|
||||
<img
|
||||
className="w-[25px] h-[25px] relative overflow-hidden shrink-0"
|
||||
loading="lazy"
|
||||
alt=""
|
||||
src="/category-icon3.svg"
|
||||
/>
|
||||
<img
|
||||
className="w-[25px] h-[25px] relative overflow-hidden shrink-0"
|
||||
loading="lazy"
|
||||
alt=""
|
||||
src="/catalog-icon3.svg"
|
||||
/>
|
||||
<img
|
||||
className="w-[25px] h-[25px] relative overflow-hidden shrink-0"
|
||||
loading="lazy"
|
||||
alt=""
|
||||
src="/employee-icon3.svg"
|
||||
/>
|
||||
<img
|
||||
className="w-[25px] h-[25px] relative overflow-hidden shrink-0"
|
||||
loading="lazy"
|
||||
alt=""
|
||||
src="/measurments-iocn3.svg"
|
||||
/>
|
||||
<img
|
||||
className="w-[25px] h-[25px] relative overflow-hidden shrink-0"
|
||||
loading="lazy"
|
||||
alt=""
|
||||
src="/account-icon3.svg"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="w-10 flex flex-row items-start justify-start py-0 pr-2 pl-[7px] box-border">
|
||||
<div className="flex flex-col items-start justify-start">
|
||||
<img
|
||||
className="w-6 h-6 relative overflow-hidden shrink-0"
|
||||
loading="lazy"
|
||||
alt=""
|
||||
src="/materialsymbolslogout3.svg"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<main className="flex-1 flex flex-col items-start justify-start pt-14 px-0 pb-0 box-border max-w-[calc(100%_-_80px)] mq450:pt-[23px] mq450:box-border mq825:pt-9 mq825:box-border">
|
||||
<section className="self-stretch flex flex-col items-start justify-start gap-[35.3px] max-w-full text-center text-5xl text-brooks-color-system-text-colors-secondary-text font-button mq675:gap-[18px]">
|
||||
<header className="self-stretch flex flex-col items-start justify-start gap-[26px] max-w-full text-center text-29xl text-brooks-color-system-text-colors-primary-text font-button">
|
||||
<div className="flex flex-row items-start justify-start py-0 pr-5 pl-0 box-border">
|
||||
<div className="flex flex-col items-start justify-start gap-7">
|
||||
<div
|
||||
className="relative tracking-[0.03em] leading-[normal] font-semibold flex items-center w-[250px] h-10 shrink-0 cursor-pointer"
|
||||
onClick={onHeadingContainerClick}
|
||||
>
|
||||
<span className="text-xs tracking-[0.03em] leading-[normal] uppercase font-semibold text-brooks-color-system-text-colors-primary-text inline-block w-[170px] h-6 shrink-0 text-left z-[0]">
|
||||
Employee List
|
||||
</span>
|
||||
<img
|
||||
className="w-[19px] h-[19px] relative z-[1] ml-[9px]"
|
||||
loading="lazy"
|
||||
alt=""
|
||||
src="/icon5.svg"
|
||||
/>
|
||||
</div>
|
||||
<div className="relative leading-[normal] font-semibold inline-block w-[270px] h-[30px] shrink-0">
|
||||
Employee Profile
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
<Profile
|
||||
employeeName={`${employee.firstname} ${employee.lastname}`}
|
||||
employeeID={employee.id}
|
||||
/>
|
||||
</section>
|
||||
<section className="self-stretch flex flex-col items-start justify-start gap-[150px] max-w-full mq675:gap-[85px]">
|
||||
<ActionButtons employeeId={employee.id} />
|
||||
<footer className="self-stretch flex flex-col items-start justify-start pt-0 px-5 pb-[42px] gap-[66px] max-w-full text-left text-8xl text-brooks-color-system-text-colors-tertiary-text font-button mq450:pb-5 mq450:box-border">
|
||||
<div className="flex flex-col items-start justify-start gap-[30px] mq450:gap-[18px]">
|
||||
<div className="self-stretch relative leading-[normal] inline-block w-[300px] h-0 shrink-0 [transform:_rotate(90deg)] text-left [transform-origin:0_0] mq450:h-[15px]">
|
||||
Employee Actions
|
||||
</div>
|
||||
<div
|
||||
className="relative tracking-[0.03em] leading-[normal] font-semibold text-29xl inline-block w-[150px] h-[60px] shrink-0 text-center z-[0] mq675:w-[170px]"
|
||||
onClick={onButtonLabelsContainerClick}
|
||||
>
|
||||
<span className="inline-block w-[170px] h-10 shrink-0 text-29xl font-semibold text-center text-brooks-color-system-text-colors-secondary-text leading-[normal] uppercase tracking-[0.03em]">
|
||||
Delete Account
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
</section>
|
||||
</main>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default EmployeeProfile;
|
@ -41,8 +41,8 @@ const AddCustomer = () => {
|
||||
<div className="w-full flex flex-col min-h-screen text-white">
|
||||
<div className="min-h-screen text-gray-300 p-6">
|
||||
<div className="flex justify-between items-center mb-6">
|
||||
<h1 className="text-2xl font-semibold text-#0e355b">add customer</h1>
|
||||
<Link to="/" className="text-#0e355b">skip for now</Link>
|
||||
<h1 className="text-2xl font-semibold text-#0e355b" > add customer</h1>
|
||||
<Link to="/CategoryList" className="text-#0e355b">skip for now</Link>
|
||||
</div>
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
|
||||
<div className="space-y-6">
|
||||
@ -55,7 +55,7 @@ const AddCustomer = () => {
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<Link to="/">
|
||||
<Link to="/add-customer">
|
||||
<h2 className="text-lg font-semibold text-">customer information</h2>
|
||||
</Link>
|
||||
<Link to="/measurements">
|
||||
|
@ -68,9 +68,11 @@ const CustomerMeasurements = () => {
|
||||
<Input className="block text-sm font-medium text-#4b5563" />
|
||||
</Form.Item>
|
||||
<Form.Item>
|
||||
<Button type="primary" htmlType="submit" className="w-full py-4 bg-#0e355b text-#d1d5db rounded-md font-semibold mb-4 hover:bg-#154676">
|
||||
Save Measurements
|
||||
</Button>
|
||||
<div className="text-center">
|
||||
<button type="submit" className="bg-#0e355b text-#d1d5db px-4 py-2 rounded-md font-semibold text-sm">
|
||||
save measurements
|
||||
</button>
|
||||
</div>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</div>
|
||||
|
@ -1,12 +1,19 @@
|
||||
import React, { useContext } from 'react';
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import AdminSidebar from './AdminSidebar';
|
||||
import EmployeeSidebar from './EmployeeSidebar';
|
||||
import { AuthContext } from '../../contexts/AuthContext';
|
||||
|
||||
const Sidebar = () => {
|
||||
const { user } = useContext(AuthContext);
|
||||
const [user, setUserData] = useState(null);
|
||||
|
||||
if (!user) return null;
|
||||
useEffect(() => {
|
||||
// Retrieve user data from localStorage
|
||||
const storedUserData = localStorage.getItem('loggedInUser');
|
||||
if (storedUserData) {
|
||||
setUserData(JSON.parse(storedUserData));
|
||||
}
|
||||
}, []);
|
||||
|
||||
if (!user) return null; // Ensure user is not null before accessing its properties
|
||||
|
||||
return user.role === 'admin' ? <AdminSidebar /> : <EmployeeSidebar />;
|
||||
};
|
||||
|
@ -1,17 +1,36 @@
|
||||
const authService = {
|
||||
login: async (username, password) => {
|
||||
// Simulate login process
|
||||
const userData = { username, role: username === 'admin' ? 'admin' : 'employee' };
|
||||
login: async (username, password) => {
|
||||
try {
|
||||
// Simulate login process with API call (replace with real API endpoint)
|
||||
const response = await axiosInstance.post('/auth/login', { username, password });
|
||||
const userData = response.data;
|
||||
|
||||
// Store user data and token in localStorage
|
||||
localStorage.setItem('user', JSON.stringify(userData));
|
||||
localStorage.setItem('token', userData.token);
|
||||
|
||||
return userData;
|
||||
},
|
||||
logout: () => {
|
||||
localStorage.removeItem('user');
|
||||
},
|
||||
getCurrentUser: () => {
|
||||
return JSON.parse(localStorage.getItem('user'));
|
||||
} catch (error) {
|
||||
throw new Error('Login failed. Please check your credentials.');
|
||||
}
|
||||
};
|
||||
|
||||
export default authService;
|
||||
|
||||
},
|
||||
logout: () => {
|
||||
localStorage.removeItem('user');
|
||||
localStorage.removeItem('token');
|
||||
},
|
||||
getCurrentUser: () => {
|
||||
return JSON.parse(localStorage.getItem('user'));
|
||||
},
|
||||
getToken: () => {
|
||||
return localStorage.getItem('token');
|
||||
},
|
||||
isAuthenticated: () => {
|
||||
return !!localStorage.getItem('token');
|
||||
},
|
||||
hasRole: (role) => {
|
||||
const user = JSON.parse(localStorage.getItem('user'));
|
||||
return user && user.role === role;
|
||||
}
|
||||
};
|
||||
|
||||
export default authService;
|
||||
|
61
src/services/server.js
Normal file
61
src/services/server.js
Normal file
@ -0,0 +1,61 @@
|
||||
// server.js
|
||||
const express = require('express');
|
||||
const bodyParser = require('body-parser');
|
||||
const nodemailer = require('nodemailer');
|
||||
const crypto = require('crypto');
|
||||
|
||||
const app = express();
|
||||
const port = 5000;
|
||||
|
||||
app.use(bodyParser.json());
|
||||
|
||||
let users = [
|
||||
// Example users
|
||||
{ email: 'admin@example.com', password: 'admin123', role: 'admin' },
|
||||
{ email: 'employee@example.com', password: 'employee123', role: 'employee' },
|
||||
];
|
||||
|
||||
// Endpoint to handle password reset requests
|
||||
app.post('/auth/forgot-password', (req, res) => {
|
||||
const { email } = req.body;
|
||||
const user = users.find(user => user.email === email);
|
||||
|
||||
if (!user) {
|
||||
return res.status(404).json({ message: 'User not found' });
|
||||
}
|
||||
|
||||
const token = crypto.randomBytes(20).toString('hex');
|
||||
// Store token in a way that it can be verified later
|
||||
user.resetPasswordToken = token;
|
||||
user.resetPasswordExpires = Date.now() + 3600000; // 1 hour
|
||||
|
||||
// Send email with reset link
|
||||
const transporter = nodemailer.createTransport({
|
||||
service: 'Gmail',
|
||||
auth: {
|
||||
user: 'your-email@gmail.com',
|
||||
pass: 'your-email-password',
|
||||
},
|
||||
});
|
||||
|
||||
const mailOptions = {
|
||||
to: user.email,
|
||||
from: 'passwordreset@example.com',
|
||||
subject: 'Password Reset',
|
||||
text: `You are receiving this because you (or someone else) have requested the reset of the password for your account.\n\n
|
||||
Please click on the following link, or paste this into your browser to complete the process:\n\n
|
||||
http://localhost:3000/reset-password/${token}\n\n
|
||||
If you did not request this, please ignore this email and your password will remain unchanged.\n`,
|
||||
};
|
||||
|
||||
transporter.sendMail(mailOptions, (err) => {
|
||||
if (err) {
|
||||
return res.status(500).json({ message: 'Error sending email' });
|
||||
}
|
||||
res.status(200).json({ message: 'Password reset email sent' });
|
||||
});
|
||||
});
|
||||
|
||||
app.listen(port, () => {
|
||||
console.log(`Server is running on http://localhost:${port}`);
|
||||
});
|
Loading…
x
Reference in New Issue
Block a user