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"
|
"email": "adminuser@example.com"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"employee": [
|
"employees": [
|
||||||
{
|
{
|
||||||
"id": "1",
|
"id": "1",
|
||||||
"name": "Employee User",
|
"name": "Employee User",
|
||||||
@ -112,6 +112,16 @@
|
|||||||
"email": "tejas001@gmail.com",
|
"email": "tejas001@gmail.com",
|
||||||
"address": " Baner, Pune",
|
"address": " Baner, Pune",
|
||||||
"mobile": "8675493099"
|
"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 { AuthProvider, AuthContext } from './contexts/AuthContext';
|
||||||
import EmployeeList from './components/admin/EmployeeList';
|
import EmployeeList from './components/admin/EmployeeList';
|
||||||
import AddEmployee from './components/admin/AddEmployee';
|
import AddEmployee from './components/admin/AddEmployee';
|
||||||
|
import EmployeeProfile from './components/admin/EmployeeProfile';
|
||||||
|
|
||||||
const { Content } = Layout;
|
const { Content } = Layout;
|
||||||
|
|
||||||
@ -33,6 +34,7 @@ const App = () => {
|
|||||||
<Route path="/measurements" element={<CustomerMeasurements />} />
|
<Route path="/measurements" element={<CustomerMeasurements />} />
|
||||||
<Route path="employees" element={<PrivateRoute><EmployeeList /></PrivateRoute>} />
|
<Route path="employees" element={<PrivateRoute><EmployeeList /></PrivateRoute>} />
|
||||||
<Route path="/add-employee" element={<PrivateRoute><AddEmployee /></PrivateRoute>} />
|
<Route path="/add-employee" element={<PrivateRoute><AddEmployee /></PrivateRoute>} />
|
||||||
|
<Route path="/employee-profile" element={<PrivateRoute><EmployeeProfile /></PrivateRoute>} />
|
||||||
</Routes>
|
</Routes>
|
||||||
</Router>
|
</Router>
|
||||||
</AuthProvider>
|
</AuthProvider>
|
||||||
|
@ -15,16 +15,16 @@ const LoginPage = () => {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await axiosInstance.get('http://localhost:5000/authlogin');
|
const response = await axiosInstance.get('http://localhost:5000/authlogin');
|
||||||
|
|
||||||
const user = response.data.find(user => user.email === email && user.password === password);
|
const user = response.data.find(user => user.email === email && user.password === password);
|
||||||
|
|
||||||
if (user) {
|
if (user) {
|
||||||
|
localStorage.setItem("loggedInUser", JSON.stringify(user))
|
||||||
if (user.role === 'admin') {
|
if (user.role === 'admin') {
|
||||||
navigate('/admin');
|
navigate('/admin');
|
||||||
} else if (user.role === 'employee') {
|
} else if (user.role === 'employee') {
|
||||||
navigate('/employee');
|
navigate('/employee');
|
||||||
} else {
|
} else {
|
||||||
setError('Invalid credentials');
|
setError('Invalid role.');
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
setError('Invalid credentials');
|
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="w-full flex flex-col min-h-screen text-black">
|
||||||
<div className="min-h-screen text-gray-800 p-6">
|
<div className="min-h-screen text-gray-800 p-6">
|
||||||
<div className="flex justify-between items-center mb-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>
|
<Link to="/" className="text-blue-900">Skip for now</Link>
|
||||||
</div>
|
</div>
|
||||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
|
<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="inline-block relative">
|
||||||
<div className="bg-gray-300 w-24 h-24 rounded-full mx-auto"></div>
|
<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">
|
<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>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -56,7 +56,7 @@ const AddEmployee = () => {
|
|||||||
<div className="md:col-span-2 space-y-4">
|
<div className="md:col-span-2 space-y-4">
|
||||||
<form onSubmit={handleAddEmployeeSubmit}>
|
<form onSubmit={handleAddEmployeeSubmit}>
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-gray-800 font-medium">Employee Firstname:</label>
|
<label className="block text-gray-800 font-medium">employee firstname:</label>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
name="firstname"
|
name="firstname"
|
||||||
@ -66,7 +66,7 @@ const AddEmployee = () => {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<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
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
name="lastname"
|
name="lastname"
|
||||||
@ -76,7 +76,7 @@ const AddEmployee = () => {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-gray-800 font-medium">Age:</label>
|
<label className="block text-gray-800 font-medium">age:</label>
|
||||||
<input
|
<input
|
||||||
type="number"
|
type="number"
|
||||||
name="age"
|
name="age"
|
||||||
@ -86,7 +86,7 @@ const AddEmployee = () => {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-gray-800 font-medium">Gender:</label>
|
<label className="block text-gray-800 font-medium">gender:</label>
|
||||||
<select
|
<select
|
||||||
name="gender"
|
name="gender"
|
||||||
value={employeeData.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"
|
className="input-underline w-full p-2 border-b border-gray-400 focus:border-#4b5563"
|
||||||
>
|
>
|
||||||
<option value="" disabled>Select Gender</option>
|
<option value="" disabled>Select Gender</option>
|
||||||
<option value="male">Male</option>
|
<option value="male">male</option>
|
||||||
<option value="female">Female</option>
|
<option value="female">female</option>
|
||||||
<option value="other">Other</option>
|
<option value="other">other</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-gray-800 font-medium">Email:</label>
|
<label className="block text-gray-800 font-medium">email:</label>
|
||||||
<input
|
<input
|
||||||
type="email"
|
type="email"
|
||||||
name="email"
|
name="email"
|
||||||
@ -110,7 +110,7 @@ const AddEmployee = () => {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-gray-800 font-medium">Address:</label>
|
<label className="block text-gray-800 font-medium">address:</label>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
name="address"
|
name="address"
|
||||||
@ -120,7 +120,7 @@ const AddEmployee = () => {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<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
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
name="mobile"
|
name="mobile"
|
||||||
@ -132,7 +132,7 @@ const AddEmployee = () => {
|
|||||||
<br />
|
<br />
|
||||||
<div className="text-center">
|
<div className="text-center">
|
||||||
<button type="submit" className="bg-#0e355b text-#d1d5db px-4 py-2 rounded-md font-semibold">
|
<button type="submit" className="bg-#0e355b text-#d1d5db px-4 py-2 rounded-md font-semibold">
|
||||||
Create Account
|
create account
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
@ -28,9 +28,9 @@ const EmployeeList = ({ className = '' }) => {
|
|||||||
navigate('/add-employee');
|
navigate('/add-employee');
|
||||||
};
|
};
|
||||||
|
|
||||||
// const onEmployeeCardsClick = useCallback(() => {
|
const onEmployeeCardsClick = useCallback(() => {
|
||||||
// navigate('/employee-profile');
|
navigate('/employee-profile');
|
||||||
// }, [navigate]);
|
}, [navigate]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-row min-h-screen">
|
<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="flex-grow p-6 bg-gray-100">
|
||||||
<div className="bg-white p-6 rounded-lg shadow">
|
<div className="bg-white p-6 rounded-lg shadow">
|
||||||
<div className="flex justify-between items-center mb-6">
|
<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
|
<button
|
||||||
className="bg-#0e355b text-d1d5db px-4 py-2 rounded-md text-sm"
|
className="bg-#0e355b text-d1d5db px-4 py-2 rounded-md text-sm"
|
||||||
onClick={handleAddEmployee}
|
onClick={handleAddEmployee}
|
||||||
>
|
>
|
||||||
Add New Employee
|
add new employee
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center mb-4">
|
<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"
|
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>
|
</svg>
|
||||||
<span className="text-sm text-gray-600">Filter</span>
|
<span className="text-sm text-gray-600">filter</span>
|
||||||
</div>
|
</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">
|
<table className="w-full bg-white">
|
||||||
<thead>
|
<thead>
|
||||||
<tr className="text-left text-xs uppercase text-gray-600 border-b">
|
<tr className="text-left text-xs uppercase text-gray-600 border-b">
|
||||||
<th className="py-2">#</th>
|
<th className="py-2">#</th>
|
||||||
<th className="py-2">Employee Name</th>
|
<th className="py-2">employee name</th>
|
||||||
<th className="py-2">Email Address</th>
|
<th className="py-2">email address</th>
|
||||||
<th className="py-2">Details</th>
|
<th className="py-2">details</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
@ -82,9 +82,9 @@ const EmployeeList = ({ className = '' }) => {
|
|||||||
<td className="py-2 text-gray-800">
|
<td className="py-2 text-gray-800">
|
||||||
<button
|
<button
|
||||||
className="text-#4b5563 underline"
|
className="text-#4b5563 underline"
|
||||||
// onClick={onEmployeeCardsClick}
|
onClick={onEmployeeCardsClick}
|
||||||
>
|
>
|
||||||
View Details
|
view details
|
||||||
</button>
|
</button>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</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;
|
@ -42,7 +42,7 @@ const AddCustomer = () => {
|
|||||||
<div className="min-h-screen text-gray-300 p-6">
|
<div className="min-h-screen text-gray-300 p-6">
|
||||||
<div className="flex justify-between items-center mb-6">
|
<div className="flex justify-between items-center mb-6">
|
||||||
<h1 className="text-2xl font-semibold text-#0e355b" > add customer</h1>
|
<h1 className="text-2xl font-semibold text-#0e355b" > add customer</h1>
|
||||||
<Link to="/" className="text-#0e355b">skip for now</Link>
|
<Link to="/CategoryList" className="text-#0e355b">skip for now</Link>
|
||||||
</div>
|
</div>
|
||||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
|
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
|
||||||
<div className="space-y-6">
|
<div className="space-y-6">
|
||||||
@ -55,7 +55,7 @@ const AddCustomer = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<Link to="/">
|
<Link to="/add-customer">
|
||||||
<h2 className="text-lg font-semibold text-">customer information</h2>
|
<h2 className="text-lg font-semibold text-">customer information</h2>
|
||||||
</Link>
|
</Link>
|
||||||
<Link to="/measurements">
|
<Link to="/measurements">
|
||||||
|
@ -68,9 +68,11 @@ const CustomerMeasurements = () => {
|
|||||||
<Input className="block text-sm font-medium text-#4b5563" />
|
<Input className="block text-sm font-medium text-#4b5563" />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<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">
|
<div className="text-center">
|
||||||
Save Measurements
|
<button type="submit" className="bg-#0e355b text-#d1d5db px-4 py-2 rounded-md font-semibold text-sm">
|
||||||
</Button>
|
save measurements
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</Form>
|
</Form>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,12 +1,19 @@
|
|||||||
import React, { useContext } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import AdminSidebar from './AdminSidebar';
|
import AdminSidebar from './AdminSidebar';
|
||||||
import EmployeeSidebar from './EmployeeSidebar';
|
import EmployeeSidebar from './EmployeeSidebar';
|
||||||
import { AuthContext } from '../../contexts/AuthContext';
|
|
||||||
|
|
||||||
const Sidebar = () => {
|
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 />;
|
return user.role === 'admin' ? <AdminSidebar /> : <EmployeeSidebar />;
|
||||||
};
|
};
|
||||||
|
@ -1,17 +1,36 @@
|
|||||||
const authService = {
|
const authService = {
|
||||||
login: async (username, password) => {
|
login: async (username, password) => {
|
||||||
// Simulate login process
|
try {
|
||||||
const userData = { username, role: username === 'admin' ? 'admin' : 'employee' };
|
// 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('user', JSON.stringify(userData));
|
||||||
|
localStorage.setItem('token', userData.token);
|
||||||
|
|
||||||
return userData;
|
return userData;
|
||||||
|
} catch (error) {
|
||||||
|
throw new Error('Login failed. Please check your credentials.');
|
||||||
|
}
|
||||||
},
|
},
|
||||||
logout: () => {
|
logout: () => {
|
||||||
localStorage.removeItem('user');
|
localStorage.removeItem('user');
|
||||||
|
localStorage.removeItem('token');
|
||||||
},
|
},
|
||||||
getCurrentUser: () => {
|
getCurrentUser: () => {
|
||||||
return JSON.parse(localStorage.getItem('user'));
|
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;
|
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