Skip to content

Commit bdf0d34

Browse files
committed
Merge branch 'feature/global-car-filtering' of github.com:Northeastern-Electric-Racing/FinishLine into feature/global-car-filtering
Merge remote-tracking branch 'feature/global-car-filtering'
2 parents 67ecd1c + 020bf87 commit bdf0d34

File tree

6 files changed

+70
-83
lines changed

6 files changed

+70
-83
lines changed

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,11 @@ export default class UsersController {
7474

7575
static async getUsersFavoriteProjects(req: Request, res: Response, next: NextFunction) {
7676
try {
77-
const projects = await UsersService.getUsersFavoriteProjects(req.currentUser.userId, req.organization);
77+
const projects = await UsersService.getUsersFavoriteProjects(
78+
req.currentUser.userId,
79+
req.organization,
80+
req.currentCar?.carId
81+
);
7882

7983
res.status(200).json(projects);
8084
} catch (error: unknown) {

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

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,11 @@ export default class UsersService {
161161
* @param organizationId the id of the organization the user is in
162162
* @returns the user's favorite projects
163163
*/
164-
static async getUsersFavoriteProjects(userId: string, organization: Organization): Promise<ProjectOverview[]> {
164+
static async getUsersFavoriteProjects(
165+
userId: string,
166+
organization: Organization,
167+
carId?: string
168+
): Promise<ProjectOverview[]> {
165169
const requestedUser = await prisma.user.findUnique({ where: { userId } });
166170
if (!requestedUser) throw new NotFoundException('User', userId);
167171

@@ -175,7 +179,8 @@ export default class UsersService {
175179
wbsElement: {
176180
organizationId: organization.organizationId,
177181
dateDeleted: null
178-
}
182+
},
183+
...(carId && { carId })
179184
},
180185
...getProjectOverviewQueryArgs(organization.organizationId)
181186
});

src/frontend/src/components/GlobalCarFilterDropdown.tsx

Lines changed: 50 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,8 @@
33
* See the LICENSE file in the repository root folder for details.
44
*/
55

6-
import React, { useState } from 'react';
7-
import { Box, Typography, Chip, Collapse, IconButton } from '@mui/material';
8-
import { ExpandMore as ExpandMoreIcon, DirectionsCar as CarIcon } from '@mui/icons-material';
6+
import { Box, Typography, Chip } from '@mui/material';
7+
import { DirectionsCar as CarIcon } from '@mui/icons-material';
98
import { Car } from 'shared';
109
import { useGlobalCarFilter } from '../app/AppGlobalCarFilterContext';
1110
import LoadingIndicator from './LoadingIndicator';
@@ -17,15 +16,9 @@ interface GlobalCarFilterDropdownProps {
1716

1817
const GlobalCarFilterDropdown: React.FC<GlobalCarFilterDropdownProps> = ({ compact = false, sx = {} }) => {
1918
const { selectedCar, allCars, setSelectedCar, isLoading, error } = useGlobalCarFilter();
20-
const [expanded, setExpanded] = useState(false);
21-
22-
const handleToggle = () => {
23-
setExpanded(!expanded);
24-
};
2519

2620
const handleCarSelect = (car: Car | null) => {
2721
setSelectedCar(car);
28-
setExpanded(false);
2922
};
3023

3124
if (isLoading) {
@@ -60,7 +53,6 @@ const GlobalCarFilterDropdown: React.FC<GlobalCarFilterDropdownProps> = ({ compa
6053
return (
6154
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 1, ...sx }}>
6255
<Box
63-
onClick={handleToggle}
6456
sx={{
6557
display: 'flex',
6658
alignItems: 'center',
@@ -78,67 +70,57 @@ const GlobalCarFilterDropdown: React.FC<GlobalCarFilterDropdownProps> = ({ compa
7870
{currentCarLabel}
7971
</Typography>
8072
</Box>
81-
<IconButton size="small" sx={{ color: 'white' }}>
82-
<ExpandMoreIcon
83-
sx={{
84-
transform: expanded ? 'rotate(180deg)' : 'rotate(0deg)',
85-
transition: 'transform 0.3s'
86-
}}
87-
/>
88-
</IconButton>
8973
</Box>
90-
<Collapse in={expanded}>
91-
<Box
74+
<Box
75+
sx={{
76+
display: 'flex',
77+
gap: 1,
78+
overflowX: 'auto',
79+
py: 1,
80+
'&::-webkit-scrollbar': {
81+
height: 6
82+
},
83+
'&::-webkit-scrollbar-thumb': {
84+
backgroundColor: 'rgba(255,255,255,0.3)',
85+
borderRadius: 3
86+
}
87+
}}
88+
>
89+
<Chip
90+
label="All Cars"
91+
onClick={() => handleCarSelect(null)}
92+
variant="outlined"
9293
sx={{
93-
display: 'flex',
94-
gap: 1,
95-
overflowX: 'auto',
96-
py: 1,
97-
'&::-webkit-scrollbar': {
98-
height: 6
99-
},
100-
'&::-webkit-scrollbar-thumb': {
101-
backgroundColor: 'rgba(255,255,255,0.3)',
102-
borderRadius: 3
103-
}
94+
borderColor: 'white',
95+
color: 'white',
96+
backgroundColor: 'transparent',
97+
fontWeight: !selectedCar ? 'bold' : 'normal',
98+
borderWidth: !selectedCar ? 2 : 1,
99+
'&:hover': { backgroundColor: 'rgba(255,255,255,0.1)' },
100+
whiteSpace: 'nowrap'
104101
}}
105-
>
106-
<Chip
107-
label="All Cars"
108-
onClick={() => handleCarSelect(null)}
109-
variant="outlined"
110-
sx={{
111-
borderColor: 'white',
112-
color: 'white',
113-
backgroundColor: 'transparent',
114-
fontWeight: !selectedCar ? 'bold' : 'normal',
115-
borderWidth: !selectedCar ? 2 : 1,
116-
'&:hover': { backgroundColor: 'rgba(255,255,255,0.1)' },
117-
whiteSpace: 'nowrap'
118-
}}
119-
/>
120-
{sortedCars.map((car) => {
121-
const isSelected = selectedCar ? car.id === selectedCar.id : false;
122-
return (
123-
<Chip
124-
key={car.id}
125-
label={car.name}
126-
onClick={() => handleCarSelect(car)}
127-
variant="outlined"
128-
sx={{
129-
borderColor: 'white',
130-
color: 'white',
131-
backgroundColor: 'transparent',
132-
fontWeight: isSelected ? 'bold' : 'normal',
133-
borderWidth: isSelected ? 2 : 1,
134-
'&:hover': { backgroundColor: 'rgba(255,255,255,0.1)' },
135-
whiteSpace: 'nowrap'
136-
}}
137-
/>
138-
);
139-
})}
140-
</Box>
141-
</Collapse>
102+
/>
103+
{sortedCars.map((car) => {
104+
const isSelected = selectedCar ? car.id === selectedCar.id : false;
105+
return (
106+
<Chip
107+
key={car.id}
108+
label={car.name}
109+
onClick={() => handleCarSelect(car)}
110+
variant="outlined"
111+
sx={{
112+
borderColor: 'white',
113+
color: 'white',
114+
backgroundColor: 'transparent',
115+
fontWeight: isSelected ? 'bold' : 'normal',
116+
borderWidth: isSelected ? 2 : 1,
117+
'&:hover': { backgroundColor: 'rgba(255,255,255,0.1)' },
118+
whiteSpace: 'nowrap'
119+
}}
120+
/>
121+
);
122+
})}
123+
</Box>
142124
</Box>
143125
);
144126
}

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ import {
4242
import { useAuth } from './auth.hooks';
4343
import { useContext } from 'react';
4444
import { UserContext } from '../app/AppContextUser';
45+
import { useGlobalCarFilter } from '../app/AppGlobalCarFilterContext';
4546

4647
/**
4748
* Custom React Hook to supply the current user
@@ -188,7 +189,8 @@ export const useUserScheduleSettings = (id: string) => {
188189
* @param id User ID of the requested user's settings.
189190
*/
190191
export const useUsersFavoriteProjects = (id: string) => {
191-
return useQuery<ProjectOverview[], Error>(['users', id, 'favorite projects'], async () => {
192+
const { selectedCar } = useGlobalCarFilter();
193+
return useQuery<ProjectOverview[], Error>(['users', id, 'favorite projects', selectedCar?.id], async () => {
192194
const { data } = await getUsersFavoriteProjects(id);
193195
return data;
194196
});

src/frontend/src/layouts/Sidebar/Sidebar.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -224,12 +224,12 @@ const Sidebar = ({ drawerOpen, setDrawerOpen, moveContent, setMoveContent }: Sid
224224
}}
225225
>
226226
<DrawerHeader>
227+
<Box sx={{ maxWidth: 150, minWidth: 0, maxHeight: 70, minHeight: 70 }}>
228+
<GlobalCarFilterDropdown compact />
229+
</Box>
227230
<IconButton onClick={() => handleMoveContent()}>{moveContent ? <ChevronLeft /> : <ChevronRight />}</IconButton>
228231
</DrawerHeader>
229-
<Divider />
230-
<Box sx={{ px: 2, py: 2 }}>
231-
<GlobalCarFilterDropdown compact />
232-
</Box>
232+
<Box sx={{ py: 2.5 }}></Box>
233233
<Divider />
234234
<Box
235235
overflow={'auto'}

src/frontend/src/pages/ProjectsPage/ProjectsOverview.tsx

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,12 @@ import { useCurrentUser, useUsersFavoriteProjects } from '../../hooks/users.hook
1010
import ProjectsOverviewCards from './ProjectsOverviewCards';
1111
import { useGetUsersLeadingProjects, useGetUsersTeamsProjects } from '../../hooks/projects.hooks';
1212
import { WbsElementStatus } from 'shared';
13-
import { useGlobalCarFilter } from '../../app/AppGlobalCarFilterContext';
1413

1514
/**
1615
* Cards of all projects this user has favorited
1716
*/
1817
const ProjectsOverview: React.FC = () => {
1918
const user = useCurrentUser();
20-
const { selectedCar } = useGlobalCarFilter();
2119

2220
const { isLoading, data: favoriteProjects, isError, error } = useUsersFavoriteProjects(user.userId);
2321
const {
@@ -50,10 +48,6 @@ const ProjectsOverview: React.FC = () => {
5048

5149
const favoriteProjectsSet: Set<string> = new Set(favoriteProjects.map((project) => project.id));
5250

53-
const carFilteredFavorites = selectedCar
54-
? favoriteProjects.filter((project) => project.wbsNum.carNumber === selectedCar.wbsNum.carNumber)
55-
: favoriteProjects;
56-
5751
// Keeps only favorite team/leading projects (even when completed) or incomplete projects
5852
const filteredTeamsProjects = teamsProjects.filter(
5953
(project) => project.status !== WbsElementStatus.Complete || favoriteProjectsSet.has(project.id)
@@ -65,7 +59,7 @@ const ProjectsOverview: React.FC = () => {
6559
return (
6660
<Box>
6761
<ProjectsOverviewCards
68-
projects={carFilteredFavorites}
62+
projects={favoriteProjects}
6963
title="My Favorites"
7064
favoriteProjectsSet={favoriteProjectsSet}
7165
emptyMessage="You have no favorite projects. Click the star on a project's page to add one!"

0 commit comments

Comments
 (0)