Skip to content

Commit 01f68cc

Browse files
authored
Merge pull request #3812 from Northeastern-Electric-Racing/#3801-person-search
only search for members and fix autocomplete bug
2 parents e754720 + 6981230 commit 01f68cc

29 files changed

Lines changed: 136 additions & 78 deletions

File tree

src/backend/src/controllers/users.controllers.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,15 @@ export default class UsersController {
2121
}
2222
}
2323

24+
static async getAllMembers(req: Request, res: Response, next: NextFunction) {
25+
try {
26+
const users = await UsersService.getAllOrgMembers(req.organization.organizationId);
27+
res.status(200).json(users);
28+
} catch (error: unknown) {
29+
next(error);
30+
}
31+
}
32+
2433
static async getCurrentUser(req: Request, res: Response, next: NextFunction) {
2534
try {
2635
const user = await UsersService.getCurrentUser(req.currentUser);

src/backend/src/routes/users.routes.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ const userRouter = express.Router();
88

99
userRouter.get('/', UsersController.getAllUsers);
1010
userRouter.get('/organization', UsersController.getAllOrgUsers);
11+
userRouter.get('/members', UsersController.getAllMembers);
1112
userRouter.post(
1213
'/scheduleSettings',
1314
body('userIds').isArray(),

src/backend/src/services/users.services.ts

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { User_Settings, Organization } from '@prisma/client';
1+
import { User_Settings, Organization, Role_Type } from '@prisma/client';
22
import { OAuth2Client } from 'google-auth-library/build/src/auth/oauth2client';
33
import {
44
Role,
@@ -59,6 +59,28 @@ export default class UsersService {
5959
return users.map(userTransformer);
6060
}
6161

62+
static async getAllOrgMembers(organizationId: string): Promise<User[]> {
63+
const users = await prisma.user.findMany({
64+
where: {
65+
organizations: {
66+
some: {
67+
organizationId,
68+
roles: {}
69+
}
70+
},
71+
roles: {
72+
some: {
73+
AND: [{ NOT: { roleType: Role_Type.GUEST } }, { organizationId }]
74+
}
75+
}
76+
},
77+
...getUserQueryArgs(organizationId),
78+
orderBy: { lastName: 'asc' }
79+
});
80+
81+
return users.map(userTransformer);
82+
}
83+
6284
static async getCurrentUser(user: User): Promise<AuthenticatedUser> {
6385
const userWithOrgs = await prisma.user.findUnique({ where: { userId: user.userId }, include: { organizations: true } });
6486

src/frontend/src/apis/users.api.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,16 @@ export const getAllOrgUsers = () => {
4444
});
4545
};
4646

47+
/**
48+
* All users in the current organization that are member or higher in role
49+
* @returns the members in the current organization with their roles
50+
*/
51+
export const getAllOrgMembers = () => {
52+
return axios.get<UserWithRole[]>(apiUrls.orgMembers(), {
53+
transformResponse: (data) => JSON.parse(data).map(userTransformer)
54+
});
55+
};
56+
4757
/**
4858
* Fetch a single user.
4959
*

src/frontend/src/components/NERAutocomplete.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,8 @@ const NERAutocomplete: React.FC<NERAutocompleteProps> = ({
7373
<>
7474
<Autocomplete
7575
isOptionEqualToValue={(option, value) => option.id === value.id}
76+
getOptionLabel={(option) => option.label}
77+
getOptionKey={(option) => option.id}
7678
disablePortal
7779
id={id}
7880
onChange={onChange}

src/frontend/src/hooks/users.hooks.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ import {
2323
getCurrentUser,
2424
logUserOut,
2525
getManyUsersWithScheduleSettings,
26-
getAllOrgUsers
26+
getAllOrgUsers,
27+
getAllOrgMembers
2728
} from '../apis/users.api';
2829
import {
2930
User,
@@ -61,6 +62,16 @@ export const useAllUsers = () => {
6162
});
6263
};
6364

65+
/**
66+
* Custom React Hook to supply all members (members and up in the current org)
67+
*/
68+
export const useAllMembers = () => {
69+
return useQuery<UserWithRole[], Error>(['users', 'members'], async () => {
70+
const { data } = await getAllOrgMembers();
71+
return data;
72+
});
73+
};
74+
6475
/**
6576
* Custom React Hook to supply all users for login (no org filtering).
6677
* @returns all users regardless of org

src/frontend/src/pages/AdminToolsPage/AdminToolsAttendeeDesignReviewInfo.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,29 +5,29 @@ import { useAllTeams } from '../../hooks/teams.hooks';
55
import LoadingIndicator from '../../components/LoadingIndicator';
66
import ErrorPage from '../ErrorPage';
77
import { fullNamePipe } from '../../utils/pipes';
8-
import { useAllUsers } from '../../hooks/users.hooks';
8+
import { useAllMembers } from '../../hooks/users.hooks';
99
import { useAllDesignReviews } from '../../hooks/design-reviews.hooks';
1010
import { DesignReviewStatus } from 'shared';
1111

1212
const AdminToolsAttendeeDesignReviewInfo: React.FC = () => {
1313
const [searchQuery, setSearchQuery] = useState('');
1414

1515
const { data: allTeams, isLoading: teamsIsLoading, isError: teamsIsError, error: teamsError } = useAllTeams();
16-
const { data: allUsers, isLoading: usersIsLoading, isError: usersIsError, error: usersError } = useAllUsers();
16+
const { data: allMembers, isLoading: usersIsLoading, isError: usersIsError, error: usersError } = useAllMembers();
1717
const {
1818
data: allDesignReviews,
1919
isLoading: designReviewsIsLoading,
2020
isError: designReviewsIsError,
2121
error: designReviewsError
2222
} = useAllDesignReviews();
2323

24-
if (!allTeams || teamsIsLoading || !allUsers || usersIsLoading || !allDesignReviews || designReviewsIsLoading)
24+
if (!allTeams || teamsIsLoading || !allMembers || usersIsLoading || !allDesignReviews || designReviewsIsLoading)
2525
return <LoadingIndicator />;
2626
if (teamsIsError) return <ErrorPage message={teamsError.message} />;
2727
if (usersIsError) return <ErrorPage message={usersError.message} />;
2828
if (designReviewsIsError) return <ErrorPage message={designReviewsError.message} />;
2929

30-
const filteredMembers = allUsers.filter((member) =>
30+
const filteredMembers = allMembers.filter((member) =>
3131
fullNamePipe(member).toLowerCase().includes(searchQuery.toLowerCase())
3232
);
3333

src/frontend/src/pages/AdminToolsPage/FinanceConfig/FinanceDelegatesTable.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import React, { useState } from 'react';
1616
import { NERButton } from '../../../components/NERButton';
1717
import DeleteIcon from '@mui/icons-material/Delete';
1818
import { useGetFinanceDelegates, useSetFinanceDelegates } from '../../../hooks/organizations.hooks';
19-
import { useAllUsers } from '../../../hooks/users.hooks';
19+
import { useAllMembers } from '../../../hooks/users.hooks';
2020
import { useToast } from '../../../hooks/toasts.hooks';
2121
import { fullNamePipe } from '../../../utils/pipes';
2222

@@ -28,14 +28,14 @@ const FinanceDelegatesTable = () => {
2828
error: delegatesError
2929
} = useGetFinanceDelegates();
3030

31-
const { data: allUsers, isLoading: usersIsLoading, isError: usersIsError, error: usersError } = useAllUsers();
31+
const { data: allMembers, isLoading: usersIsLoading, isError: usersIsError, error: usersError } = useAllMembers();
3232

3333
const { mutateAsync: setFinanceDelegates, isLoading: isUpdating } = useSetFinanceDelegates();
3434
const toast = useToast();
3535

3636
const [selectedUserId, setSelectedUserId] = useState<string>();
3737

38-
if (!financeDelegates || delegatesIsLoading || !allUsers || usersIsLoading) {
38+
if (!financeDelegates || delegatesIsLoading || !allMembers || usersIsLoading) {
3939
return <LoadingIndicator />;
4040
}
4141

@@ -71,7 +71,7 @@ const FinanceDelegatesTable = () => {
7171
};
7272

7373
const availableUsers =
74-
allUsers?.filter((user) => !financeDelegates.some((delegate) => delegate.userId === user.userId)) || [];
74+
allMembers?.filter((user) => !financeDelegates.some((delegate) => delegate.userId === user.userId)) || [];
7575

7676
const userAutocompleteOptions = availableUsers.map((user) => ({
7777
label: `${fullNamePipe(user)} (${user.email})`,

src/frontend/src/pages/AdminToolsPage/OnboardingConfig/UpdateContactsModal.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import LoadingIndicator from '../../../components/LoadingIndicator';
1010
import * as yup from 'yup';
1111
import { useUpdateOrganizationContacts } from '../../../hooks/organizations.hooks'; // Assume hook exists
1212
import { Contact } from 'shared';
13-
import { useAllUsers } from '../../../hooks/users.hooks';
13+
import { useAllMembers } from '../../../hooks/users.hooks';
1414
import { fullNamePipe } from '../../../utils/pipes';
1515

1616
const schema = yup.object().shape({
@@ -48,7 +48,7 @@ const UpdateOnboardingContactsModal: React.FC<UpdateOnboardingContactsModalProps
4848
mutateAsync
4949
} = useUpdateOrganizationContacts();
5050

51-
const { isLoading: allUsersIsLoading, isError: allUsersIsError, error: allUsersError, data: users } = useAllUsers();
51+
const { isLoading: allUsersIsLoading, isError: allUsersIsError, error: allUsersError, data: users } = useAllMembers();
5252

5353
const contactsAsObjects = useMemo(
5454
() =>

src/frontend/src/pages/AdminToolsPage/TeamConfig/CreateTeamForm.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { useState } from 'react';
33
import { Controller, useForm } from 'react-hook-form';
44
import { useCreateTeam } from '../../../hooks/teams.hooks';
55
import { useToast } from '../../../hooks/toasts.hooks';
6-
import { useAllUsers } from '../../../hooks/users.hooks';
6+
import { useAllMembers } from '../../../hooks/users.hooks';
77
import * as yup from 'yup';
88
import ErrorPage from '../../ErrorPage';
99
import LoadingIndicator from '../../../components/LoadingIndicator';
@@ -44,7 +44,7 @@ const CreateTeamForm = () => {
4444
const theme = useTheme();
4545
const [showPreview, setShowPreview] = useState(false);
4646
const { isLoading, mutateAsync } = useCreateTeam();
47-
const { isLoading: allUsersIsLoading, isError: allUsersIsError, error: allUsersError, data: users } = useAllUsers();
47+
const { isLoading: allUsersIsLoading, isError: allUsersIsError, error: allUsersError, data: users } = useAllMembers();
4848
const toast = useToast();
4949
const {
5050
handleSubmit,

0 commit comments

Comments
 (0)