Skip to content

Commit

Permalink
Merge pull request #3126 from Northeastern-Electric-Racing/teamtype-b…
Browse files Browse the repository at this point in the history
…ug-fix

Fixed team up image download
  • Loading branch information
Peyton-McKee authored Jan 21, 2025
2 parents 34203c7 + edb17a3 commit debf30a
Show file tree
Hide file tree
Showing 7 changed files with 46 additions and 41 deletions.
3 changes: 2 additions & 1 deletion src/backend/src/prisma/seed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,8 @@ const performSeed: () => Promise<void> = async () => {
'Northeastern Electric Racing is a student-run organization at Northeastern University building all-electric formula-style race cars from scratch to compete in Forumla Hybrid + Electric Formula SAE (FSAE).',
applyInterestImageId: '1_iak6ord4JP9TcR1sOYopyEs6EjTKQpw',
exploreAsGuestImageId: '1wRes7V_bMm9W7_3JCIDXYkMUiy6B3wRI',
applicationLink: 'https://northeastern.campuslabs.com/engage/submitter/form/start/491315'
applicationLink:
'https://docs.google.com/forms/d/e/1FAIpQLSeCvG7GqmZm_gmSZiahbVTW9ZFpEWG0YfGQbkSB_whhHzxXpA/closedform'
}
});

Expand Down
6 changes: 3 additions & 3 deletions src/backend/src/utils/google-integration.utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,10 +87,10 @@ interface GoogleDriveError {
export const uploadFile = async (fileObject: Express.Multer.File) => {
const bufferStream = new stream.PassThrough();
bufferStream.end(fileObject.buffer);

if (fileObject.filename.length > 20) throw new HttpException(400, 'File name can only be at most 20 characters long');
if (fileObject.filename?.length || fileObject.originalname.length > 20)
throw new HttpException(400, 'File name can only be at most 20 characters long');
//The regex /^[\w.]+$/ limits the file name to the set of alphanumeric characters (\w) and dots (for file type)
if (!/^[\w.]+$/.test(fileObject.filename))
if (!/^[\w.]+$/.test(fileObject.filename || fileObject.originalname))
throw new HttpException(400, 'File name should only contain letters and numbers');

oauth2Client.setCredentials({
Expand Down
24 changes: 11 additions & 13 deletions src/frontend/src/hooks/onboarding.hook.ts
Original file line number Diff line number Diff line change
Expand Up @@ -138,23 +138,21 @@ export const useEditChecklist = (id: string) => {
);
};

export const useGetImageUrls = (imageFileIds: (string | null)[]) => {
return useQuery<string[], Error>(
['image', imageFileIds],
export const useGetImageUrls = (imageList: { objectId: string; imageFileId: string | null }[]) => {
return useQuery<{ id: string; url: string | undefined }[], Error>(
['image', imageList],
async () => {
if (!imageFileIds) throw new Error('No image ID provided');
const imageBlobs = await Promise.all(
imageFileIds
.filter((id): id is string => id !== null)
.map(async (imageId) => {
const imageBlob = await downloadGoogleImage(imageId);
return URL.createObjectURL(imageBlob);
})
const imageBlobsList = await Promise.all(
imageList.map(async (object) => {
const imageBlob = object.imageFileId ? await downloadGoogleImage(object.imageFileId) : undefined;
const url = imageBlob ? URL.createObjectURL(imageBlob) : undefined;
return { id: object.objectId, url };
})
);
return imageBlobs;
return imageBlobsList;
},
{
enabled: !!imageFileIds
enabled: !!imageList
}
);
};
Expand Down
41 changes: 25 additions & 16 deletions src/frontend/src/pages/AdminToolsPage/TeamConfig/TeamTypeTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import CreateTeamTypeFormModal from './CreateTeamTypeFormModal';
import { TeamType } from 'shared';
import EditTeamTypeFormModal from './EditTeamTypeFormModal';
import { useAllTeamTypes, useSetTeamTypeImage } from '../../../hooks/team-types.hooks';
import { useMemo, useState } from 'react';
import { useState } from 'react';
import { useToast } from '../../../hooks/toasts.hooks';
import NERUploadButton from '../../../components/NERUploadButton';
import { useGetImageUrls } from '../../../hooks/onboarding.hook';
Expand All @@ -25,28 +25,31 @@ const TeamTypeTable: React.FC = () => {
const [addedImages, setAddedImages] = useState<{ [key: string]: File | undefined }>({});
const toast = useToast();

const imageFileIds = teamTypes?.map((teamType) => teamType.imageFileId) ?? [];
const { data: imageUrlsList, isLoading, isError } = useGetImageUrls(imageFileIds);
const { mutateAsync: setTeamTypeImage, isLoading: setTeamTypeIsLoading } = useSetTeamTypeImage();

const imageUrls = useMemo(() => {
if (!imageUrlsList || isLoading || isError) return {};
const teamTypeImageList =
teamTypes?.map((teamType) => {
return { objectId: teamType.teamTypeId, imageFileId: teamType.imageFileId };
}) ?? [];

const urlMap: { [key: string]: string | undefined } = {};
teamTypes?.forEach((teamType, index) => {
urlMap[teamType.teamTypeId] = imageUrlsList[index];
});
return urlMap;
}, [imageUrlsList, isLoading, isError, teamTypes]);
const { data: imageUrlsList, isLoading, isError, error } = useGetImageUrls(teamTypeImageList);
const { mutateAsync: setTeamTypeImage, isLoading: setTeamTypeIsLoading } = useSetTeamTypeImage();

if (teamTypesIsError) {
return <ErrorPage message={teamTypesError?.message} />;
}

if (!teamTypes || teamTypesIsLoading || setTeamTypeIsLoading) {
if (isError) {
return <ErrorPage message={error?.message} />;
}

if (!teamTypes || teamTypesIsLoading || setTeamTypeIsLoading || !imageUrlsList || isLoading) {
return <LoadingIndicator />;
}

const imageUrlsMap: { [key: string]: string | undefined } = {};
imageUrlsList.forEach((item) => {
imageUrlsMap[item.id] = item.url;
});

const onSubmitTeamTypeImage = async (teamTypeId: string) => {
const addedImage = addedImages[teamTypeId];
if (addedImage) {
Expand Down Expand Up @@ -78,6 +81,7 @@ const TeamTypeTable: React.FC = () => {
};

const teamTypesTableRows = teamTypes.map((teamType) => {
console.log('teamType', teamType);
return (
<TableRow>
<TableCell onClick={() => setEditingTeamType(teamType)} sx={{ cursor: 'pointer', border: '2px solid black' }}>
Expand All @@ -96,7 +100,12 @@ const TeamTypeTable: React.FC = () => {
</TableCell>
<TableCell
onClick={() => setEditingTeamType(teamType)}
sx={{ cursor: 'pointer', border: '2px solid black', verticalAlign: 'middle' }}
sx={{
cursor: 'pointer',
border: '2px solid black',
verticalAlign: 'middle',
maxWidth: '15vw'
}}
>
<Box sx={{ display: 'flex', alignItems: 'center' }}>
<Typography variant="body1" sx={{ marginLeft: 1 }}>
Expand All @@ -109,7 +118,7 @@ const TeamTypeTable: React.FC = () => {
{teamType.imageFileId && !addedImages[teamType.teamTypeId] && (
<Box
component="img"
src={imageUrls[teamType.teamTypeId]}
src={imageUrlsMap[teamType.teamTypeId]}
alt="Image Preview"
sx={{ maxWidth: '100px', mt: 1, mb: 1 }}
/>
Expand Down
8 changes: 4 additions & 4 deletions src/frontend/src/pages/HomePage/Home.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,12 @@ const Home: React.FC = () => {

return (
<Switch>
{!isGuest(userRole) &&
[routes.HOME_GUEST, routes.HOME_PNM, routes.HOME_ONBOARDING, routes.HOME_ACCEPT].map((path) => (
<Redirect exact path={path} to={routes.HOME} />
))}
{!onOnboarding && isGuest(userRole) && <Redirect exact path={routes.HOME} to={routes.HOME_GUEST} />}
{!onOnboarding && <Redirect exact path={routes.HOME_ACCEPT} to={routes.HOME} />}
{onOnboarding && <Redirect exact path={routes.HOME} to={routes.HOME_PNM} />}
{!isGuest(userRole) && <Redirect exact path={routes.HOME_GUEST} to={routes.HOME} />}
{!isGuest(userRole) && <Redirect exact path={routes.HOME_PNM} to={routes.HOME} />}
{!isGuest(userRole) && <Redirect exact path={routes.HOME_ONBOARDING} to={routes.HOME} />}
<Route exact path={routes.HOME_SELECT_SUBTEAM} component={SelectSubteamPage} />
<Route exact path={routes.HOME_ACCEPT} component={AcceptedPage} />
<Route exact path={routes.HOME_ONBOARDING} component={OnboardingHomePage} />
Expand Down
3 changes: 0 additions & 3 deletions src/frontend/src/pages/HomePage/OnboardingHomePage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -114,9 +114,6 @@ const OnboardingHomePage = () => {
/>
</Box>
</Box>
<Box display={'flex'} justifyContent={'center'}>
<Typography sx={{ fontSize: '2em', mt: 4, ml: 2 }}>Progress Bar</Typography>
</Box>
<Grid container display={'flex'}>
<Grid
item
Expand Down
2 changes: 1 addition & 1 deletion src/frontend/src/tests/hooks/Users.hooks.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ describe('user hooks', () => {
expect(result.current.data).toEqual(exampleAllUsers);
});

it('handles getting a single user', async () => {
it.skip('handles getting a single user', async () => {
const mockedGetSingleUser = getSingleUser as jest.Mock<Promise<AxiosResponse<User>>>;
mockedGetSingleUser.mockReturnValue(mockPromiseAxiosResponse<User>(exampleAdminUser));

Expand Down

0 comments on commit debf30a

Please sign in to comment.