ChandimaPrabath commited on
Commit
b780a2e
·
1 Parent(s): c3cdf77

get all users

Browse files
frontend/app/assets/logo6.png ADDED

Git LFS Details

  • SHA256: 3d380fb74d957e29449ba011541bc7dfd3f3a42283b3bfb5b9af4e7ac0fce823
  • Pointer size: 130 Bytes
  • Size of remote file: 69 kB
frontend/app/components/NexusAuth.js CHANGED
@@ -3,7 +3,7 @@ import './NexusAuth.css';
3
  import { useState, useEffect } from 'react';
4
  import NexusAuthApi from '@/app/lib/Nexus_Auth_API';
5
  import SplashScreen from '@/app/components/SplashScreen';
6
- import { CheckCircleIcon} from '@heroicons/react/20/solid';
7
 
8
  const SignupForm = ({ onSignup }) => {
9
  const [username, setUsername] = useState('');
@@ -183,7 +183,6 @@ export const NexusAuthWrapper = ({ children, toast }) => {
183
  const [isLoggedIn, setIsLoggedIn] = useState(false);
184
  const [isSignup, setIsSignup] = useState(false);
185
  const [isLoading, setIsLoading] = useState(true);
186
- const [isSignupSuccessfull, setIsSignupSuccessfull] = useState(false);
187
 
188
  useEffect(() => {
189
  const validateUserSession = async () => {
@@ -194,28 +193,44 @@ export const NexusAuthWrapper = ({ children, toast }) => {
194
  if (storedUsername && storedToken && storedUserID) {
195
  try {
196
  // Validate the token with the NexusAuthApi
197
- const isValid = await NexusAuthApi.validateToken(storedUserID, storedToken);
198
- if (isValid) {
 
 
199
  console.log("User is already logged in.");
200
- toast.info("Welcome back!");
201
  setIsLoggedIn(true);
202
- } else {
203
- // Token invalid, clear localStorage
 
 
 
 
 
 
 
204
  clearLocalStorage();
 
 
 
 
205
  }
206
  } catch (error) {
207
- console.error("Token validation failed:", error);
208
- toast.error("Token validation failed. Please login again.");
209
- clearLocalStorage();
 
210
  }
211
  }
212
- setIsLoading(false); // Stop showing splash screen after validation
 
213
  };
214
 
215
  const clearLocalStorage = () => {
216
  localStorage.removeItem("me");
217
  localStorage.removeItem("s_tkn");
218
  localStorage.removeItem("u_id");
 
219
  setIsLoggedIn(false);
220
  toast.error("Session expired. Please login again.");
221
  };
@@ -224,24 +239,23 @@ export const NexusAuthWrapper = ({ children, toast }) => {
224
  }, []);
225
 
226
  const handleSignup = async (data) => {
 
227
  try {
228
  const response = await NexusAuthApi.signup(data.username, data.password, data.email);
229
  console.log("Signup successful:", response);
230
  setIsSignupSuccessfull(true);
 
231
  toast.success('Signup successful. Please login to continue');
232
-
233
- // Save username and token to localStorage
234
- localStorage.setItem("me", response.username);
235
- localStorage.setItem("s_tkn", response.access_token);
236
- localStorage.setItem("u_id", response.user_id);
237
  setIsSignup(false);
238
  } catch (error) {
 
239
  console.error("Signup failed:", error);
240
  toast.error("Signup failed");
241
  }
242
  };
243
 
244
  const handleLogin = async (data) => {
 
245
  try {
246
  const response = await NexusAuthApi.login(data.username, data.password);
247
  console.log("Login successful:", response);
@@ -250,9 +264,12 @@ export const NexusAuthWrapper = ({ children, toast }) => {
250
  localStorage.setItem("me", response.username);
251
  localStorage.setItem("s_tkn", response.access_token);
252
  localStorage.setItem("u_id", response.user_id);
 
253
 
254
  setIsLoggedIn(true);
 
255
  } catch (error) {
 
256
  console.error("Login failed:", error);
257
  toast.error("Login failed");
258
  }
 
3
  import { useState, useEffect } from 'react';
4
  import NexusAuthApi from '@/app/lib/Nexus_Auth_API';
5
  import SplashScreen from '@/app/components/SplashScreen';
6
+ import { CheckCircleIcon } from '@heroicons/react/20/solid';
7
 
8
  const SignupForm = ({ onSignup }) => {
9
  const [username, setUsername] = useState('');
 
183
  const [isLoggedIn, setIsLoggedIn] = useState(false);
184
  const [isSignup, setIsSignup] = useState(false);
185
  const [isLoading, setIsLoading] = useState(true);
 
186
 
187
  useEffect(() => {
188
  const validateUserSession = async () => {
 
193
  if (storedUsername && storedToken && storedUserID) {
194
  try {
195
  // Validate the token with the NexusAuthApi
196
+ const response = await NexusAuthApi.validateToken(storedUserID, storedToken);
197
+
198
+ if (response.data && response.data.user_id) {
199
+ // Token is valid; response contains user details
200
  console.log("User is already logged in.");
201
+ toast.info("Welcome back, " + response.data.username + "!");
202
  setIsLoggedIn(true);
203
+
204
+ // Optionally, update localStorage with new details if needed
205
+ localStorage.setItem("me", response.data.username);
206
+ localStorage.setItem("s_tkn", response.data.access_token);
207
+ localStorage.setItem("u_id", response.data.user_id);
208
+ localStorage.setItem("a_l", response.data.access_level);
209
+ } else if (response.status === 401) {
210
+ // Token is invalid; clear local storage
211
+ console.error("Token validation failed with status 401:", response.data);
212
  clearLocalStorage();
213
+ } else {
214
+ // Handle other errors (e.g., network issues)
215
+ console.error("Token validation failed due to an unexpected error:", response.data);
216
+ toast.error("Unable to validate token. Please check your connection.");
217
  }
218
  } catch (error) {
219
+ // Handle other errors (e.g., network issues)
220
+ console.error("Token validation failed due to an unexpected error:", error);
221
+ toast.error("Unable to validate token. Please check your connection.");
222
+
223
  }
224
  }
225
+ setIsLoading(false);
226
+
227
  };
228
 
229
  const clearLocalStorage = () => {
230
  localStorage.removeItem("me");
231
  localStorage.removeItem("s_tkn");
232
  localStorage.removeItem("u_id");
233
+ localStorage.removeItem("a_l");
234
  setIsLoggedIn(false);
235
  toast.error("Session expired. Please login again.");
236
  };
 
239
  }, []);
240
 
241
  const handleSignup = async (data) => {
242
+ setIsLoading(true);
243
  try {
244
  const response = await NexusAuthApi.signup(data.username, data.password, data.email);
245
  console.log("Signup successful:", response);
246
  setIsSignupSuccessfull(true);
247
+ setIsLoading(false);
248
  toast.success('Signup successful. Please login to continue');
 
 
 
 
 
249
  setIsSignup(false);
250
  } catch (error) {
251
+ setIsLoading(false);
252
  console.error("Signup failed:", error);
253
  toast.error("Signup failed");
254
  }
255
  };
256
 
257
  const handleLogin = async (data) => {
258
+ setIsLoading(true);
259
  try {
260
  const response = await NexusAuthApi.login(data.username, data.password);
261
  console.log("Login successful:", response);
 
264
  localStorage.setItem("me", response.username);
265
  localStorage.setItem("s_tkn", response.access_token);
266
  localStorage.setItem("u_id", response.user_id);
267
+ localStorage.setItem("a_l", response.access_level);
268
 
269
  setIsLoggedIn(true);
270
+ setIsLoading(false);
271
  } catch (error) {
272
+ setIsLoading(false);
273
  console.error("Login failed:", error);
274
  toast.error("Login failed");
275
  }
frontend/app/components/Sidebar.js CHANGED
@@ -1,9 +1,10 @@
1
  'use client';
2
  import { VERSION } from "@/app/lib/config";
3
- import { Bars3Icon, UserCircleIcon, Cog6ToothIcon, QuestionMarkCircleIcon } from "@heroicons/react/20/solid";
4
  import Link from "next/link";
 
5
  import Image from "next/image";
6
- import logo from "@/app/assets/logo6-cropped.jpg";
7
 
8
  export default function Sidebar({ isCollapsed, toggleSidebar }) {
9
  const logoStyle = {
@@ -11,6 +12,8 @@ export default function Sidebar({ isCollapsed, toggleSidebar }) {
11
  height: isCollapsed ? "60px" : "100px",
12
  borderRadius: "50px",
13
  transition: "width 0.3s ease, height 0.3s ease",
 
 
14
  };
15
 
16
  const sidebarStyle = {
@@ -18,7 +21,7 @@ export default function Sidebar({ isCollapsed, toggleSidebar }) {
18
  left: isCollapsed ? "-180px" : "0",
19
  backgroundColor: "var(--sidebar-background)",
20
  color: "var(--foreground)",
21
- padding: isCollapsed ? "15px" : "30px",
22
  position: "fixed",
23
  height: "100vh",
24
  display: "flex",
@@ -42,7 +45,7 @@ export default function Sidebar({ isCollapsed, toggleSidebar }) {
42
  padding: "10px 5px",
43
  transition: "all 0.3s ease",
44
  color: "var(--foreground)",
45
- fontSize: "1.2em",
46
  };
47
 
48
  const textStyle = {
@@ -75,6 +78,12 @@ export default function Sidebar({ isCollapsed, toggleSidebar }) {
75
  transition: "background-color 0.3s ease, right 0.3s ease",
76
  };
77
 
 
 
 
 
 
 
78
  return (
79
  <div style={sidebarStyle}>
80
  <div className="logo-container" style={{ display: "flex", flexDirection: "column", alignItems: "center" }}>
@@ -94,6 +103,12 @@ export default function Sidebar({ isCollapsed, toggleSidebar }) {
94
  <span style={textStyle}>Profile</span>
95
  </Link>
96
  </li>
 
 
 
 
 
 
97
  <li>
98
  <Link href="/settings" style={navLinkStyle}>
99
  <Cog6ToothIcon style={iconStyle} />
 
1
  'use client';
2
  import { VERSION } from "@/app/lib/config";
3
+ import { Bars3Icon, UserCircleIcon, Cog6ToothIcon, QuestionMarkCircleIcon, BoltIcon } from "@heroicons/react/20/solid";
4
  import Link from "next/link";
5
+ import { useEffect, useState } from "react";
6
  import Image from "next/image";
7
+ import logo from "@/app/assets/logo6.png";
8
 
9
  export default function Sidebar({ isCollapsed, toggleSidebar }) {
10
  const logoStyle = {
 
12
  height: isCollapsed ? "60px" : "100px",
13
  borderRadius: "50px",
14
  transition: "width 0.3s ease, height 0.3s ease",
15
+ marginBottom: "20px",
16
+ marginTop: "20px",
17
  };
18
 
19
  const sidebarStyle = {
 
21
  left: isCollapsed ? "-180px" : "0",
22
  backgroundColor: "var(--sidebar-background)",
23
  color: "var(--foreground)",
24
+ padding: isCollapsed ? "15px" : "20px",
25
  position: "fixed",
26
  height: "100vh",
27
  display: "flex",
 
45
  padding: "10px 5px",
46
  transition: "all 0.3s ease",
47
  color: "var(--foreground)",
48
+ fontSize: "1em",
49
  };
50
 
51
  const textStyle = {
 
78
  transition: "background-color 0.3s ease, right 0.3s ease",
79
  };
80
 
81
+ const [acessLevel, setAcessLevel] = useState(null);
82
+
83
+ useEffect(() => {
84
+ setAcessLevel(localStorage.getItem('a_l'));
85
+ }, []);
86
+
87
  return (
88
  <div style={sidebarStyle}>
89
  <div className="logo-container" style={{ display: "flex", flexDirection: "column", alignItems: "center" }}>
 
103
  <span style={textStyle}>Profile</span>
104
  </Link>
105
  </li>
106
+ <li>
107
+ <Link href={`/su/${acessLevel}`} style={navLinkStyle}>
108
+ <BoltIcon style={iconStyle} />
109
+ <span style={textStyle}>{acessLevel}</span>
110
+ </Link>
111
+ </li>
112
  <li>
113
  <Link href="/settings" style={navLinkStyle}>
114
  <Cog6ToothIcon style={iconStyle} />
frontend/app/components/SplashScreen.js CHANGED
@@ -1,5 +1,5 @@
1
  'use client';
2
- import logo from "@/app/assets/logo6-cropped.jpg";
3
  import Image from "next/image";
4
  import { useEffect, useState } from "react";
5
 
 
1
  'use client';
2
+ import logo from "@/app/assets/logo6.png";
3
  import Image from "next/image";
4
  import { useEffect, useState } from "react";
5
 
frontend/app/globals.css CHANGED
@@ -3,14 +3,14 @@
3
  @tailwind utilities;
4
 
5
  :root {
6
- --background: #100b1a; /* Deeper dark background */
7
  --foreground: #E0E0E0; /* Light gray text */
8
  --sidebar-background: #14141b; /* Darker sidebar background */
9
- --primary: #1F1F2A; /* Darker primary for sidebar */
10
- --secondary: #2A2A3B; /* Soft secondary background for content */
11
- --accent: #4a4a7f;
12
- --hover-accent: #5c5c8a; /* Slightly lighter accent color for hover */
13
- --button-background: #3A3A4C; /* Button background */
14
  --button-hover: #2D2D38; /* Darker button hover */
15
  --shadow-dark: rgba(0, 0, 0, 0.15); /* Shadow for depth */
16
  }
 
3
  @tailwind utilities;
4
 
5
  :root {
6
+ --background: #15171f; /* Deeper dark background */
7
  --foreground: #E0E0E0; /* Light gray text */
8
  --sidebar-background: #14141b; /* Darker sidebar background */
9
+ --primary: #1f202a;
10
+ --secondary: #2a2b3b; /* Soft secondary background for content */
11
+ --accent: #4a557f;
12
+ --hover-accent: #5c608a; /* Slightly lighter accent color for hover */
13
+ --button-background: #3a3b4c; /* Button background */
14
  --button-hover: #2D2D38; /* Darker button hover */
15
  --shadow-dark: rgba(0, 0, 0, 0.15); /* Shadow for depth */
16
  }
frontend/app/layout.js CHANGED
@@ -65,7 +65,7 @@ export default function RootLayout({ children }) {
65
  <Sidebar isCollapsed={isCollapsed} toggleSidebar={toggleSidebar} />
66
  <div style={contentStyle}>
67
  <header style={headerStyle}>
68
- <h1>Welcome to Your Dashboard</h1>
69
  </header>
70
  <div className="main-content">
71
  {children}
 
65
  <Sidebar isCollapsed={isCollapsed} toggleSidebar={toggleSidebar} />
66
  <div style={contentStyle}>
67
  <header style={headerStyle}>
68
+ <h1>Welcome to Nexus Dashboard</h1>
69
  </header>
70
  <div className="main-content">
71
  {children}
frontend/app/lib/Nexus_Auth_API.js CHANGED
@@ -58,7 +58,7 @@ const NexusAuthApi = {
58
  throw error.response?.data || error.message;
59
  }
60
  },
61
-
62
 
63
  async validateToken(userId, token) {
64
  debugLog("Validating token", { userId, token });
@@ -66,14 +66,14 @@ const NexusAuthApi = {
66
  const response = await axios.get(
67
  `${API_BASE_URL}/auth/validate?user_id=${encodeURIComponent(userId)}&token=${encodeURIComponent(token)}`
68
  );
69
- debugLog("Token validation successful", response.data);
70
- return response.data;
71
  } catch (error) {
72
- debugLog("Token validation failed", error.response?.data || error.message);
73
- throw error.response?.data || error.message;
74
  }
75
  },
76
-
77
 
78
  async searchUsers(query) {
79
  debugLog("Searching users", { query });
@@ -117,6 +117,21 @@ const NexusAuthApi = {
117
  }
118
  },
119
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
120
  async getAllUsers(adminId, token) {
121
  debugLog("Fetching all users", { adminId });
122
  try {
@@ -176,20 +191,6 @@ const NexusAuthApi = {
176
  throw error.response?.data || error.message;
177
  }
178
  },
179
-
180
- async updateOwnData(userId, updateData, token) {
181
- debugLog("Updating own data", { userId, updateData });
182
- try {
183
- const response = await axios.put(`${API_BASE_URL}/auth/user/update`, updateData, {
184
- params: { user_id: userId, token },
185
- });
186
- debugLog("Update own data successful", response.data);
187
- return response.data;
188
- } catch (error) {
189
- debugLog("Update own data failed", error.response?.data || error.message);
190
- throw error.response?.data || error.message;
191
- }
192
- },
193
  };
194
 
195
- export default NexusAuthApi;
 
58
  throw error.response?.data || error.message;
59
  }
60
  },
61
+
62
 
63
  async validateToken(userId, token) {
64
  debugLog("Validating token", { userId, token });
 
66
  const response = await axios.get(
67
  `${API_BASE_URL}/auth/validate?user_id=${encodeURIComponent(userId)}&token=${encodeURIComponent(token)}`
68
  );
69
+ debugLog("Token validation successful", response);
70
+ return response;
71
  } catch (error) {
72
+ debugLog("Token validation failed", error.response?.data || error);
73
+ return error;
74
  }
75
  },
76
+
77
 
78
  async searchUsers(query) {
79
  debugLog("Searching users", { query });
 
117
  }
118
  },
119
 
120
+ async updateOwnData(userId, updateData, token) {
121
+ debugLog("Updating own data", { userId, updateData });
122
+ try {
123
+ const response = await axios.put(`${API_BASE_URL}/auth/user/update`, updateData, {
124
+ params: { user_id: userId, token },
125
+ });
126
+ debugLog("Update own data successful", response.data);
127
+ return response.data;
128
+ } catch (error) {
129
+ debugLog("Update own data failed", error.response?.data || error.message);
130
+ throw error.response?.data || error.message;
131
+ }
132
+ },
133
+
134
+ // Admin API
135
  async getAllUsers(adminId, token) {
136
  debugLog("Fetching all users", { adminId });
137
  try {
 
191
  throw error.response?.data || error.message;
192
  }
193
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
194
  };
195
 
196
+ export default NexusAuthApi;
frontend/app/page.js CHANGED
@@ -7,17 +7,20 @@ export default function Home() {
7
  const [username, setUsername] = useState(null);
8
  const [userID, setUserID] = useState(null);
9
  const [token, setToken] = useState(null);
 
10
 
11
  useEffect(() => {
12
  setUsername(localStorage.getItem('me'));
13
  setUserID(localStorage.getItem('u_id'));
14
  setToken(localStorage.getItem('s_tkn'));
 
15
  }, []);
16
 
17
  const clearLocalStorage = () => {
18
  localStorage.removeItem('me');
19
  localStorage.removeItem('s_tkn');
20
  localStorage.removeItem('u_id');
 
21
  setUsername(null);
22
  };
23
 
@@ -35,10 +38,29 @@ export default function Home() {
35
  return (
36
  <>
37
  {username && (
38
- <div className="user-info-card">
39
- <h3>Hello, <strong>{username}</strong></h3>
40
- <p>User ID: <strong>{userID}</strong></p>
41
- <button onClick={handleLogout} className="logout-button">Logout</button>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
42
  </div>
43
  )}
44
  </>
 
7
  const [username, setUsername] = useState(null);
8
  const [userID, setUserID] = useState(null);
9
  const [token, setToken] = useState(null);
10
+ const [accessLevel, setAccessLevel] = useState(null);
11
 
12
  useEffect(() => {
13
  setUsername(localStorage.getItem('me'));
14
  setUserID(localStorage.getItem('u_id'));
15
  setToken(localStorage.getItem('s_tkn'));
16
+ setAccessLevel(localStorage.getItem('a_l'));
17
  }, []);
18
 
19
  const clearLocalStorage = () => {
20
  localStorage.removeItem('me');
21
  localStorage.removeItem('s_tkn');
22
  localStorage.removeItem('u_id');
23
+ localStorage.removeItem('a_l');
24
  setUsername(null);
25
  };
26
 
 
38
  return (
39
  <>
40
  {username && (
41
+ <div className="max-w-sm mx-auto shadow-lg rounded-lg overflow-hidden bg-gray-800 text-white">
42
+ <table className="min-w-full divide-y divide-gray-700">
43
+ <tbody className="divide-y divide-gray-700">
44
+ <tr>
45
+ <td className="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-300">User ID:</td>
46
+ <td className="px-6 py-4 whitespace-nowrap text-sm text-gray-100"><strong>{userID}</strong></td>
47
+ </tr>
48
+ <tr>
49
+ <td className="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-300">Username:</td>
50
+ <td className="px-6 py-4 whitespace-nowrap text-sm text-gray-100"><strong>{username}</strong></td>
51
+ </tr>
52
+
53
+ <tr>
54
+ <td className="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-300">Access Level:</td>
55
+ <td className="px-6 py-4 whitespace-nowrap text-sm text-gray-100"><strong>{accessLevel}</strong></td>
56
+ </tr>
57
+ <tr>
58
+ <td colSpan="2" className="px-6 py-4 whitespace-nowrap text-sm text-center">
59
+ <button onClick={handleLogout} className="bg-red-600 text-white px-4 py-2 rounded-md hover:bg-red-700 transition duration-300">Logout</button>
60
+ </td>
61
+ </tr>
62
+ </tbody>
63
+ </table>
64
  </div>
65
  )}
66
  </>
frontend/app/su/[access_level]/page.js ADDED
@@ -0,0 +1,155 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ 'use client';
2
+
3
+ import { useState, useEffect } from 'react';
4
+ import { useParams, useRouter } from 'next/navigation';
5
+ import NexusAuthApi from '@/app/lib/Nexus_Auth_API';
6
+
7
+ export default function SuperUser() {
8
+ const router = useRouter();
9
+ const { access_level } = useParams();
10
+
11
+ const [userDetails, setUserDetails] = useState({
12
+ username: null,
13
+ userID: null,
14
+ token: null,
15
+ accessLevel: null,
16
+ });
17
+ const [users, setUsers] = useState([]);
18
+
19
+ // Fetch user details from local storage on mount
20
+ useEffect(() => {
21
+ setUserDetails({
22
+ username: localStorage.getItem('me'),
23
+ userID: localStorage.getItem('u_id'),
24
+ token: localStorage.getItem('s_tkn'),
25
+ accessLevel: localStorage.getItem('a_l'),
26
+ });
27
+ }, []);
28
+
29
+ const clearLocalStorage = () => {
30
+ localStorage.removeItem('me');
31
+ localStorage.removeItem('s_tkn');
32
+ localStorage.removeItem('u_id');
33
+ localStorage.removeItem('a_l');
34
+ setUserDetails({
35
+ username: null,
36
+ userID: null,
37
+ token: null,
38
+ accessLevel: null,
39
+ });
40
+ };
41
+
42
+ const handleLogout = () => {
43
+ const { userID, token } = userDetails;
44
+ NexusAuthApi.logout(userID, token)
45
+ .then(() => {
46
+ clearLocalStorage();
47
+ window.location.reload();
48
+ })
49
+ .catch((error) => {
50
+ console.error('Logout failed', error);
51
+ });
52
+ };
53
+
54
+ const getAllUsers = () => {
55
+ const { userID, token } = userDetails;
56
+ NexusAuthApi.getAllUsers(userID, token)
57
+ .then((fetchedUsers) => {
58
+ setUsers(fetchedUsers);
59
+ })
60
+ .catch((error) => {
61
+ console.error('Get all users failed', error);
62
+ });
63
+ };
64
+
65
+ // Redirect if the access level doesn't match
66
+ useEffect(() => {
67
+ if (access_level && userDetails.accessLevel) {
68
+ if (access_level !== userDetails.accessLevel) {
69
+ router.push(`/su/${userDetails.accessLevel}`);
70
+ }
71
+ }
72
+ }, [access_level, userDetails.accessLevel]);
73
+
74
+ const { username, userID, accessLevel } = userDetails;
75
+
76
+ return (
77
+ <div className="max-w-xl mx-auto shadow-lg rounded-lg overflow-hidden bg-gray-800 text-white">
78
+ {username ? (
79
+ <>
80
+ <table className="min-w-full divide-y divide-gray-700">
81
+ <tbody className="divide-y divide-gray-700">
82
+ <tr>
83
+ <td className="px-6 py-4 text-sm font-medium text-gray-300">Username:</td>
84
+ <td className="px-6 py-4 text-sm text-gray-100"><strong>{username}</strong></td>
85
+ </tr>
86
+ <tr>
87
+ <td className="px-6 py-4 text-sm font-medium text-gray-300">User ID:</td>
88
+ <td className="px-6 py-4 text-sm text-gray-100"><strong>{userID}</strong></td>
89
+ </tr>
90
+ <tr>
91
+ <td className="px-6 py-4 text-sm font-medium text-gray-300">Access Level:</td>
92
+ <td className="px-6 py-4 text-sm text-gray-100"><strong>{accessLevel}</strong></td>
93
+ </tr>
94
+ <tr>
95
+ <td colSpan="2" className="px-6 py-4 text-center">
96
+ <button
97
+ onClick={handleLogout}
98
+ className="bg-red-600 text-white px-4 py-2 rounded-md hover:bg-red-700 transition duration-300"
99
+ >
100
+ Logout
101
+ </button>
102
+ </td>
103
+ </tr>
104
+ </tbody>
105
+ </table>
106
+
107
+ {(accessLevel === 'admin' || accessLevel === 'hush') && (
108
+ <div>
109
+ <button
110
+ onClick={getAllUsers}
111
+ className="bg-blue-600 text-white px-4 py-2 rounded-md hover:bg-blue-700 transition duration-300 mt-4"
112
+ >
113
+ Get All Users
114
+ </button>
115
+ {users.length > 0 && (
116
+ <div className="mt-4 max-h-64 overflow-y-auto">
117
+ <table className="min-w-full divide-y divide-gray-700">
118
+ <thead>
119
+ <tr>
120
+ <th className="px-6 py-3 bg-gray-700 text-left text-xs font-medium text-gray-300 uppercase tracking-wider">
121
+ Username
122
+ </th>
123
+ <th className="px-6 py-3 bg-gray-700 text-left text-xs font-medium text-gray-300 uppercase tracking-wider">
124
+ Email
125
+ </th>
126
+ <th className="px-6 py-3 bg-gray-700 text-left text-xs font-medium text-gray-300 uppercase tracking-wider">
127
+ Access Level
128
+ </th>
129
+ <th className="px-6 py-3 bg-gray-700 text-left text-xs font-medium text-gray-300 uppercase tracking-wider">
130
+ Date Joined
131
+ </th>
132
+ </tr>
133
+ </thead>
134
+ <tbody className="divide-y divide-gray-700">
135
+ {users.map((user, index) => (
136
+ <tr key={index}>
137
+ <td className="px-6 py-4 text-sm text-gray-100">{user.username}</td>
138
+ <td className="px-6 py-4 text-sm text-gray-100">{user.email || 'N/A'}</td>
139
+ <td className="px-6 py-4 text-sm text-gray-100">{user.access_level}</td>
140
+ <td className="px-6 py-4 text-sm text-gray-100">{new Date(user.date_joined).toLocaleDateString()}</td>
141
+ </tr>
142
+ ))}
143
+ </tbody>
144
+ </table>
145
+ </div>
146
+ )}
147
+ </div>
148
+ )}
149
+ </>
150
+ ) : (
151
+ <div className="p-4 text-center">No user details available. Please log in.</div>
152
+ )}
153
+ </div>
154
+ );
155
+ }