From c79c2afb0fb949b9c54577b1b3b6d0a1b4254e85 Mon Sep 17 00:00:00 2001 From: Justin Lau Date: Tue, 22 Oct 2024 21:12:53 -0400 Subject: [PATCH 1/2] Refactor UserManagementPage component and UserAPIClient - Add useEffect and useState to UserManagementPage component to fetch and display users - Update UserManagementPage component UI to display a table of users - Add fetchUsers function to UserManagementPage component to fetch users from the backend - Create UserAPIClient module to handle API requests for user data - Implement get function in UserAPIClient to fetch users from the backend - Define User type in UserTypes module to represent user data --- frontend/src/APIClients/UserAPIClient.ts | 27 +++++++++ .../components/pages/UserManagementPage.tsx | 59 +++++++++++++++++-- frontend/src/types/UserTypes.ts | 8 +++ 3 files changed, 90 insertions(+), 4 deletions(-) create mode 100644 frontend/src/APIClients/UserAPIClient.ts create mode 100644 frontend/src/types/UserTypes.ts diff --git a/frontend/src/APIClients/UserAPIClient.ts b/frontend/src/APIClients/UserAPIClient.ts new file mode 100644 index 0000000..6871163 --- /dev/null +++ b/frontend/src/APIClients/UserAPIClient.ts @@ -0,0 +1,27 @@ +import axios from "axios"; +import { User } from "../types/UserTypes"; +import { getLocalStorageObj } from "../utils/LocalStorageUtils"; +import AUTHENTICATED_USER_KEY from "../constants/AuthConstants"; + +const baseURL = process.env.REACT_APP_BACKEND_URL; + +const get = async (): Promise => { + try { + const currentUser: { accessToken?: string } = + getLocalStorageObj(AUTHENTICATED_USER_KEY) || {}; + const accessToken = currentUser?.accessToken; + + const { data } = await axios.get(`${baseURL}/users`, { + headers: { + Authorization: `Bearer ${accessToken}`, + }, + withCredentials: true, + }); + + return data; + } catch (error) { + throw new Error(`Failed to get users: ${error}`); + } +}; + +export default { get }; diff --git a/frontend/src/components/pages/UserManagementPage.tsx b/frontend/src/components/pages/UserManagementPage.tsx index 21431ca..b219396 100644 --- a/frontend/src/components/pages/UserManagementPage.tsx +++ b/frontend/src/components/pages/UserManagementPage.tsx @@ -1,11 +1,62 @@ -import React from "react"; +import React, { useEffect, useState } from "react"; +import { + Table, + Thead, + Tbody, + Tr, + Th, + Td, + TableContainer, + VStack, + Button, +} from "@chakra-ui/react"; +import UserAPIClient from "../../APIClients/UserAPIClient"; +import { User } from "../../types/UserTypes"; import MainPageButton from "../common/MainPageButton"; const UserManagementPage = (): React.ReactElement => { + const [users, setUsers] = useState([]); + + const fetchUsers = async () => { + try { + const fetchedUsers = await UserAPIClient.get(); + setUsers(fetchedUsers); + } catch (error) { + /* empty */ + } + }; + + useEffect(() => { + fetchUsers(); + }, []); + return ( -
-

User Management

- +
+

Team Members Page

+ + + + + + + + + + + + {users.map((user) => ( + + + + + + ))} + +
First NameLast NameRole
{user.firstName}{user.lastName}{user.role}
+
+ + +
); }; diff --git a/frontend/src/types/UserTypes.ts b/frontend/src/types/UserTypes.ts new file mode 100644 index 0000000..ec548db --- /dev/null +++ b/frontend/src/types/UserTypes.ts @@ -0,0 +1,8 @@ +export type User = { + id: number; + firstName: string; + lastName: string; + email: string; + role: string; + status: string; +}; From 604584579dd7571cd994b7c2e2d77a7bf27d8b8f Mon Sep 17 00:00:00 2001 From: Justin Lau Date: Thu, 24 Oct 2024 20:31:01 -0400 Subject: [PATCH 2/2] Refactor AuthService to remove email verification check --- .../services/implementations/authService.ts | 10 ++++---- frontend/src/APIClients/UserAPIClient.ts | 24 +++++++------------ .../components/pages/UserManagementPage.tsx | 10 ++++---- 3 files changed, 21 insertions(+), 23 deletions(-) diff --git a/backend/typescript/services/implementations/authService.ts b/backend/typescript/services/implementations/authService.ts index 0f1c543..a9f045b 100644 --- a/backend/typescript/services/implementations/authService.ts +++ b/backend/typescript/services/implementations/authService.ts @@ -176,11 +176,13 @@ class AuthService implements IAuthService { decodedIdToken.uid, ); - const firebaseUser = await firebaseAdmin - .auth() - .getUser(decodedIdToken.uid); + // TODO: Uncomment when the email verification is working + // const firebaseUser = await firebaseAdmin + // .auth() + // .getUser(decodedIdToken.uid); - return firebaseUser.emailVerified && roles.has(userRole); + // return firebaseUser.emailVerified && roles.has(userRole); + return roles.has(userRole); } catch (error) { return false; } diff --git a/frontend/src/APIClients/UserAPIClient.ts b/frontend/src/APIClients/UserAPIClient.ts index 6871163..20ddc2e 100644 --- a/frontend/src/APIClients/UserAPIClient.ts +++ b/frontend/src/APIClients/UserAPIClient.ts @@ -1,26 +1,20 @@ -import axios from "axios"; import { User } from "../types/UserTypes"; -import { getLocalStorageObj } from "../utils/LocalStorageUtils"; import AUTHENTICATED_USER_KEY from "../constants/AuthConstants"; - -const baseURL = process.env.REACT_APP_BACKEND_URL; +import baseAPIClient from "./BaseAPIClient"; +import { getLocalStorageObjProperty } from "../utils/LocalStorageUtils"; const get = async (): Promise => { + const bearerToken = `Bearer ${getLocalStorageObjProperty( + AUTHENTICATED_USER_KEY, + "accessToken", + )}`; try { - const currentUser: { accessToken?: string } = - getLocalStorageObj(AUTHENTICATED_USER_KEY) || {}; - const accessToken = currentUser?.accessToken; - - const { data } = await axios.get(`${baseURL}/users`, { - headers: { - Authorization: `Bearer ${accessToken}`, - }, - withCredentials: true, + const { data } = await baseAPIClient.get("/users", { + headers: { Authorization: bearerToken }, }); - return data; } catch (error) { - throw new Error(`Failed to get users: ${error}`); + throw new Error(`Failed to get entity: ${error}`); } }; diff --git a/frontend/src/components/pages/UserManagementPage.tsx b/frontend/src/components/pages/UserManagementPage.tsx index b219396..e1db017 100644 --- a/frontend/src/components/pages/UserManagementPage.tsx +++ b/frontend/src/components/pages/UserManagementPage.tsx @@ -17,17 +17,19 @@ import MainPageButton from "../common/MainPageButton"; const UserManagementPage = (): React.ReactElement => { const [users, setUsers] = useState([]); - const fetchUsers = async () => { + const getUsers = async () => { try { const fetchedUsers = await UserAPIClient.get(); - setUsers(fetchedUsers); + if (fetchedUsers != null) { + setUsers(fetchedUsers); + } } catch (error) { /* empty */ } }; useEffect(() => { - fetchUsers(); + getUsers(); }, []); return ( @@ -54,7 +56,7 @@ const UserManagementPage = (): React.ReactElement => { - +