diff --git a/client/src/App.jsx b/client/src/App.jsx
index 3bd00d106..4c7d590f3 100644
--- a/client/src/App.jsx
+++ b/client/src/App.jsx
@@ -26,6 +26,7 @@ import addProject from './components/manageProjects/addProject';
import HealthCheck from './pages/HealthCheck';
import SecretPassword from './pages/SecretPassword';
import UserWelcome from './pages/UserWelcome';
+import UserPermission from './pages/UserPermission';
import { ThemeProvider } from '@mui/material';
import theme from './theme';
@@ -50,6 +51,11 @@ const routes = [
{ path: '/users', name: 'users', Component: Users },
{ path: '/users/user-search', name: 'useradmin', Component: UserAdmin },
+ {
+ path: '/users/permission-search',
+ name: 'useradmin',
+ Component: UserPermission,
+ },
{ path: '/projects', name: 'projects', Component: ProjectList },
{ path: '/projects/create', name: 'projectform', Component: addProject },
{
diff --git a/client/src/components/user-admin/UserPermissionSearch.jsx b/client/src/components/user-admin/UserPermissionSearch.jsx
new file mode 100644
index 000000000..53c773822
--- /dev/null
+++ b/client/src/components/user-admin/UserPermissionSearch.jsx
@@ -0,0 +1,354 @@
+import React, { useState, useEffect } from 'react';
+import {
+ Box,
+ Button,
+ ButtonGroup,
+ Grid,
+ TextField,
+ Typography,
+ List,
+ ListItem,
+ ListItemButton,
+} from '@mui/material';
+import { useLocation } from 'react-router-dom';
+
+import '../../sass/UserAdmin.scss';
+
+const Buttonsx = {
+ px: 2,
+ py: 0.5,
+};
+
+const dummyData = [
+ {
+ _id: 1,
+ name: {
+ firstName: 'John',
+ lastName: 'Doe',
+ },
+ accessLevel: 'admin',
+ email: 'johndoe@hackforla.org',
+ projects: [],
+ },
+ {
+ _id: 2,
+ name: {
+ firstName: 'Vinny',
+ lastName: 'Harris',
+ },
+ accessLevel: 'admin',
+ email: 'vinnyharris@hackforla.org',
+ projects: [],
+ },
+ {
+ _id: 3,
+ name: {
+ firstName: 'Gary',
+ lastName: 'Jones',
+ },
+ accessLevel: 'admin',
+ email: 'garyjones@hackforla.org',
+ projects: [],
+ },
+ {
+ _id: 4,
+ name: {
+ firstName: 'Jane',
+ lastName: 'Smith',
+ },
+ accessLevel: 'projectLead',
+ email: 'janesmith@hackforla.org',
+ projects: ['VRMS', 'Mobile'],
+ },
+ {
+ _id: 5,
+ name: {
+ firstName: 'Bonnie',
+ lastName: 'Wolfe',
+ },
+ accessLevel: 'projectLead',
+ email: 'bonnie@hackforla.org',
+ projects: ['Home Unite Us'],
+ },
+ {
+ _id: 6,
+ name: {
+ firstName: 'Diana',
+ lastName: 'Loeb',
+ },
+ accessLevel: 'projectLead',
+ email: 'dianaloeb@hackforla.org',
+ projects: ['HackforLA Mobile', 'LA TDM Calculator'],
+ },
+ {
+ _id: 7,
+ name: {
+ firstName: 'Zack',
+ lastName: 'Cruz',
+ },
+ accessLevel: 'projectLead',
+ email: 'dianaloeb@hackforla.org',
+ projects: ['LA TDM Calculator', 'VRMS backend'],
+ },
+ {
+ _id: 8,
+ name: {
+ firstName: 'Iris',
+ lastName: 'Sosa',
+ },
+ accessLevel: 'projectLead',
+ email: 'irissosa@hackforla.org',
+ projects: ['Home Unite Us', 'VRMS Support'],
+ },
+];
+
+const DummyComponent = ({ data, type, setUserToEdit }) => {
+ return (
+
+ {data.map((u, idx) => {
+ // Destructure user object
+ const { _id, name, email } = u;
+ // return projects.length === 0 ?
+ return type === 'admin' ? (
+
+ setUserToEdit(u)}
+ >
+
+
+
+ {`${name.firstName.toUpperCase()} ${name.lastName.toUpperCase()} ( ${email.toUpperCase()} )`}
+
+
+
+
+
+ ) : (
+
+ setUserToEdit(u)}
+ >
+
+
+
+ {name.firstName.toUpperCase() +
+ ' ' +
+ name.lastName.toUpperCase()}
+
+
+
+
+ {u.project}
+
+
+
+
+
+ );
+ })}
+
+ );
+};
+
+const UserPermissionSearch = ({ users, setUserToEdit }) => {
+ const [userType, setUserType] = useState('admin'); // Which results will display
+ const [searchText, setSearchText] = useState(''); // Search term for the admin/PM search
+
+ const location = useLocation();
+
+ useEffect(() => {
+ // Edit url by adding '/admin' upon loading
+ let editURL = '';
+ if (userType === 'admin') {
+ editURL = location.pathname + '/admin';
+ } else {
+ editURL = location.pathname + '/projects';
+ }
+ window.history.replaceState({}, '', editURL);
+ }, [userType]);
+
+ // Swaps the buttons and displayed panels for the search results, by email or by name
+ const buttonSwap = () =>
+ userType === 'projectLead'
+ ? setUserType('admin')
+ : setUserType('projectLead');
+
+ // Handle change on input in search form
+ const handleChange = (event) => {
+ setSearchText(event.target.value);
+ };
+
+ const getFilteredData = (dummyData, searchText, userType) => {
+ const searchTextLowerCase = searchText.trim().toLowerCase();
+
+ let filteredData = dummyData
+ .filter((user) => user.accessLevel === userType)
+ .flatMap((user) =>
+ userType === 'projectLead' && user.projects.length > 0
+ ? user.projects.map((project) => ({ ...user, project }))
+ : [{ ...user }]
+ )
+ .filter((user) => {
+ const fullName =
+ `${user.name.firstName} ${user.name.lastName}`.toLowerCase();
+ const projectName = user.project ? user.project.toLowerCase() : '';
+ return (
+ fullName.includes(searchTextLowerCase) ||
+ (userType === 'projectLead' &&
+ projectName.includes(searchTextLowerCase))
+ );
+ });
+
+ return filteredData.sort((a, b) => {
+ if (userType === 'projectLead') {
+ return (
+ a.project.localeCompare(b.project) ||
+ a.name.firstName.localeCompare(b.name.firstName)
+ );
+ }
+ return a.name.firstName.localeCompare(b.name.firstName);
+ });
+ };
+
+ // Filtering logic
+ let filteredData;
+ if (!searchText) {
+ filteredData = dummyData.filter((user) => user.accessLevel === userType);
+ if (userType === 'admin') {
+ // Default display for admins, sorted ASC based on first name
+ filteredData.sort((u1, u2) =>
+ u1.name?.firstName.localeCompare(u2.name?.firstName)
+ );
+ } else {
+ // Default display of all PMs, sorted ASC based on project name, then first name
+ let tempFilter = [];
+ filteredData.forEach((user) => {
+ user.projects.forEach((project) => {
+ tempFilter.push({ ...user, project });
+ });
+ });
+ tempFilter.sort(
+ (u1, u2) =>
+ u1.project.localeCompare(u2.project) ||
+ u1.name?.firstName.localeCompare(u2.name?.firstName)
+ );
+ filteredData = [...tempFilter];
+ }
+ } else {
+ // NOTE: Using "users" instead of "dummyData" to check the link to user profile
+ filteredData = getFilteredData(users, searchText, userType);
+ }
+
+ return (
+
+
+
+ User Permission Search
+
+
+
+
+
+
+
+
+ 0 ? '#F5F5F5' : 'transparent',
+ my: 1.2,
+ borderRadius: 1,
+ flexGrow: 1,
+ width: 1 / 1,
+ }}
+ >
+
+ {/*Component to render admins and PMs*/}
+
+
+
+
+
+ );
+};
+
+export default UserPermissionSearch;
diff --git a/client/src/pages/UserPermission.jsx b/client/src/pages/UserPermission.jsx
new file mode 100644
index 000000000..0fc07f2bc
--- /dev/null
+++ b/client/src/pages/UserPermission.jsx
@@ -0,0 +1,87 @@
+import React, { useState, useEffect, useCallback } from 'react';
+import { Redirect } from 'react-router-dom';
+import '../sass/UserAdmin.scss';
+import useAuth from '../hooks/useAuth';
+import EditUsers from '../components/user-admin/EditUsers';
+import UserPermissionSearch from '../components/user-admin/UserPermissionSearch';
+import UserApiService from '../api/UserApiService';
+import ProjectApiService from '../api/ProjectApiService';
+
+//NOTE: This page is based off of "UserAdmin.jsx" for now. It should be update as part of #1801.
+
+const UserPermission = () => {
+ // Initialize state hooks
+ const { auth } = useAuth();
+ const [users, setUsers] = useState([]); // All users pulled from database
+ const [projects, setProjects] = useState([]); // All projects pulled from db
+ const [userToEdit, setUserToEdit] = useState({}); // The selected user that is being edited
+
+ const [userApiService] = useState(new UserApiService());
+ const [projectApiService] = useState(new ProjectApiService());
+
+ // NOTE: will have to be updated as part of #1801
+ const fetchUsers = useCallback(async () => {
+ const userRes = await userApiService.fetchUsers();
+ setUsers(userRes);
+ }, [userApiService]);
+
+ const updateUserDb = useCallback(
+ async (user, managedProjects) => {
+ await userApiService.updateUserDbProjects(user, managedProjects);
+ fetchUsers();
+ },
+ [userApiService, fetchUsers]
+ );
+
+ const updateUserActiveStatus = useCallback(
+ async (user, isActive) => {
+ await userApiService.updateUserDbIsActive(user, isActive);
+ fetchUsers();
+ },
+ [userApiService, fetchUsers]
+ );
+
+ // Update user's access level (admin/user)
+ const updateUserAccessLevel = useCallback(
+ async (user, newAccessLevel) => {
+ await userApiService.updateUserAccessLevel(user, newAccessLevel);
+ fetchUsers();
+ },
+ [userApiService, fetchUsers]
+ );
+
+ const fetchProjects = useCallback(async () => {
+ const projectRes = await projectApiService.fetchProjects();
+ setProjects(projectRes);
+ }, [projectApiService]);
+
+ useEffect(() => {
+ fetchUsers();
+ fetchProjects();
+ }, [fetchUsers, fetchProjects]);
+
+ const backToSearch = () => {
+ setUserToEdit({});
+ };
+
+ if (!auth && !auth?.user) {
+ return ;
+ }
+
+ if (Object.keys(userToEdit).length === 0) {
+ return ;
+ } else {
+ return (
+
+ );
+ }
+};
+
+export default UserPermission;