Skip to content

Commit

Permalink
Merge pull request #3103 from Northeastern-Electric-Racing/#2815-Make…
Browse files Browse the repository at this point in the history
…-Progress-bar-reactive

#2815 make progress bar reactive
  • Loading branch information
Peyton-McKee authored Jan 13, 2025
2 parents 6a83bbf + c3a682a commit 85acc57
Show file tree
Hide file tree
Showing 15 changed files with 309 additions and 155 deletions.
24 changes: 19 additions & 5 deletions src/backend/src/services/onboarding.services.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,14 @@ export default class OnboardingServices {
teamTypeId: { in: teamTypeIds },
parentChecklistId: null
},
include: { subtasks: { where: { dateDeleted: null } }, teamType: true }
include: {
subtasks: {
include: {
usersChecked: true
}
},
teamType: true
}
});

const teamChecklists = await prisma.checklist.findMany({
Expand All @@ -73,7 +80,14 @@ export default class OnboardingServices {
teamId: { in: teamIds },
parentChecklistId: null
},
include: { subtasks: { where: { dateDeleted: null } }, team: true }
include: {
subtasks: {
include: {
usersChecked: true
}
},
team: true
}
});

return [...teamTypeChecklists, ...teamChecklists];
Expand Down Expand Up @@ -378,9 +392,9 @@ export default class OnboardingServices {
});

if (parentChecklist) {
const allSubtasksChecked = parentChecklist.subtasks.every((subtask) =>
subtask.usersChecked.some((user) => user.userId === userId)
);
const allSubtasksChecked = parentChecklist.subtasks
.filter((subtask) => !subtask.isOptional)
.every((subtask) => subtask.usersChecked.some((user) => user.userId === userId));
if (allSubtasksChecked) {
await prisma.checklist.update({
where: { checklistId: parentChecklist.checklistId },
Expand Down
4 changes: 2 additions & 2 deletions src/backend/tests/unmocked/onboarding.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,8 @@ describe('Onboarding tests', () => {
const checklist3 = await createTestChecklist(batman, orgId, 'Checklist 3', undefined, team1.teamId);
const teamTypeChecklists = await OnboardingServices.getUsersChecklists(batman.userId, organization);
expect(teamTypeChecklists.length).toEqual(2);
expect(teamTypeChecklists[0].checklistId).toEqual(checklist1.checklistId);
expect(teamTypeChecklists[1].checklistId).toEqual(checklist3.checklistId);
expect(teamTypeChecklists.some((checklist) => checklist.checklistId === checklist1.checklistId)).toBeTruthy();
expect(teamTypeChecklists.some((checklist) => checklist.checklistId === checklist3.checklistId)).toBeTruthy();
});
});

Expand Down
2 changes: 1 addition & 1 deletion src/frontend/src/apis/onboarding.api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export const getCheckedChecklists = () => {
* API call to fetch all the users checklists
*/
export const getUsersChecklists = () => {
return axios.get<Checklist[]>(apiUrls.usersTeamTypeChecklists(), {
return axios.get<Checklist[]>(apiUrls.usersChecklists(), {
transformResponse: (data) => JSON.parse(data)
});
};
Expand Down
23 changes: 21 additions & 2 deletions src/frontend/src/hooks/onboarding.hook.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import {
editChecklist,
getCheckedChecklists
} from '../apis/onboarding.api';
import { useEffect, useState } from 'react';
import { isChecklistChecked } from '../utils/onboarding.utils';

export interface ToggleChecklistPayload {
checklistId: string;
Expand Down Expand Up @@ -51,8 +53,8 @@ export const useCheckedChecklists = () => {
});
};

export const useUsersTeamTypeChecklists = () => {
return useQuery<Checklist[], Error>(['checklists', 'teamTypeChecklists'], async () => {
export const useUsersChecklists = () => {
return useQuery<Checklist[], Error>(['checklists'], async () => {
const { data } = await getUsersChecklists();
return data;
});
Expand Down Expand Up @@ -156,3 +158,20 @@ export const useGetImageUrls = (imageFileIds: (string | null)[]) => {
}
);
};

export const useChecklistProgress = (parentChecklists: Checklist[], checkedChecklists: Checklist[]) => {
const [progress, setProgress] = useState(0);
useEffect(() => {
if (!checkedChecklists || parentChecklists.length === 0) return;

const totalChecklistsLength = parentChecklists.length;

const completedChecklistsLength = parentChecklists.reduce((count, checklist) => {
return isChecklistChecked(checkedChecklists, checklist) ? count + 1 : count;
}, 0);

setProgress((completedChecklistsLength / totalChecklistsLength) * 100);
}, [parentChecklists, checkedChecklists]);

return progress;
};
59 changes: 0 additions & 59 deletions src/frontend/src/hooks/onboarding.hooks.ts

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import NERUploadButton from '../../../components/NERUploadButton';
import React, { useState } from 'react';
import { useCurrentOrganization, useSetOrganizationImages } from '../../../hooks/organizations.hooks';
import LoadingIndicator from '../../../components/LoadingIndicator';
import { useGetImageUrl } from '../../../hooks/onboarding.hooks';
import { useGetImageUrl } from '../../../hooks/onboarding.hook';
import ErrorPage from '../../ErrorPage';
import ApplicationLinkTable from './ApplicationLinkTable';

Expand Down
2 changes: 1 addition & 1 deletion src/frontend/src/pages/HomePage/GuestHomePage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { useHomePageContext } from '../../app/HomePageContext';
import { useCurrentOrganization } from '../../hooks/organizations.hooks';
import LoadingIndicator from '../../components/LoadingIndicator';
import ErrorPage from '../ErrorPage';
import { useGetImageUrl } from '../../hooks/onboarding.hooks';
import { useGetImageUrl } from '../../hooks/onboarding.hook';

const GuestHomePage = () => {
const user = useCurrentUser();
Expand Down
94 changes: 87 additions & 7 deletions src/frontend/src/pages/HomePage/OnboardingHomePage.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Box, Grid, Typography } from '@mui/material';
import { Box, Grid, Typography, useTheme } from '@mui/material';
import PageLayout from '../../components/PageLayout';
import { useCurrentOrganization } from '../../hooks/organizations.hooks';
import React, { useEffect, useState } from 'react';
Expand All @@ -9,14 +9,24 @@ import ChecklistSection from './components/ChecklistSection';
import OnboardingInfoSection from './components/OnboardingInfoSection';
import ConfirmOnboardingChecklistModal from './components/ConfirmOnboardingChecklistModal';
import { NERButton } from '../../components/NERButton';
import {
useCheckedChecklists,
useUsersChecklists,
useAllChecklists,
useChecklistProgress
} from '../../hooks/onboarding.hook';
import { Checklist } from 'shared';
import { useToggleCompletedOnboarding } from '../../hooks/users.hooks';
import { useToast } from '../../hooks/toasts.hooks';
import OnboardingProgressBar from '../../components/OnboardingProgressBar';

const OnboardingHomePage = () => {
const { data: organization, isError, error, isLoading } = useCurrentOrganization();
const { setCurrentHomePage } = useHomePageContext();
const [isModalOpen, setModalOpen] = useState(false);

const theme = useTheme();

const toast = useToast();

const toggleCompletedOnboarding = useToggleCompletedOnboarding();
Expand All @@ -25,9 +35,59 @@ const OnboardingHomePage = () => {
setCurrentHomePage('onboarding');
}, [setCurrentHomePage]);

if (!organization || isLoading) return <LoadingIndicator />;
const {
data: allChecklists,
isError: allChecklistsIsError,
error: allChecklistsError,
isLoading: allChecklistsIsLoading
} = useAllChecklists();

const {
data: usersChecklists,
isError: usersChecklistsIsError,
error: usersChecklistsError,
isLoading: usersChecklistsIsLoading
} = useUsersChecklists();

const {
data: checkedChecklists,
isLoading: checkedChecklistsLoading,
isError: checkedChecklistsIsError,
error: checkedChecklistsError
} = useCheckedChecklists();

const generalChecklists =
allChecklists?.filter((checklist: Checklist) => checklist.team === null && checklist.teamType === null) || [];

const progress = useChecklistProgress([...generalChecklists, ...(usersChecklists || [])], checkedChecklists || []);

if (isError) return <ErrorPage message={error?.message} />;

if (usersChecklistsIsError) {
return <ErrorPage error={usersChecklistsError} />;
}

if (checkedChecklistsIsError) {
return <ErrorPage error={checkedChecklistsError} />;
}

if (allChecklistsIsError) {
return <ErrorPage error={allChecklistsError} />;
}

if (
!organization ||
isLoading ||
usersChecklistsIsLoading ||
!usersChecklists ||
checkedChecklistsLoading ||
!checkedChecklists ||
allChecklistsIsLoading ||
!allChecklists
) {
return <LoadingIndicator />;
}

const handleOpenModal = () => {
setModalOpen(true);
};
Expand All @@ -48,11 +108,9 @@ const OnboardingHomePage = () => {
<Grid item xs={12} md={7}>
<Typography sx={{ fontSize: '2.5em' }}>Welcome to the {organization.name} Team</Typography>
</Grid>
<Grid item xs={12} md={5} sx={{ display: 'flex', justifyContent: 'flex-end' }}>
<NERButton variant="contained" onClick={handleOpenModal}>
Finished?
</NERButton>
</Grid>
<NERButton variant="contained" disabled={progress < 100} onClick={handleOpenModal}>
Finished?
</NERButton>
</Grid>
<Grid
container
Expand All @@ -62,6 +120,28 @@ const OnboardingHomePage = () => {
flexDirection: 'column'
}}
>
<Box display="flex" justifyContent="center">
<Box
sx={{
backgroundColor: theme.palette.background.paper,
borderRadius: 5,
p: 3.5,
flexGrow: 1,
width: '100%',
mt: 5,
ml: 4,
display: 'flex',
alignItems: 'center'
}}
>
<OnboardingProgressBar
value={Math.round(progress)}
text={`Complete`}
typographySx={{ fontSize: '1.2em' }}
progressBarSx={{ height: '3vh' }}
/>
</Box>
</Box>
<Box display={'flex'} justifyContent={'center'}>
<Typography sx={{ fontSize: '2em', mt: 4, ml: 2 }}>Progress Bar</Typography>
</Box>
Expand Down
15 changes: 9 additions & 6 deletions src/frontend/src/pages/HomePage/components/Checklist.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,16 @@ import { Typography, Grid, Box, IconButton, useTheme } from '@mui/material';
import { KeyboardArrowRight, KeyboardArrowDown } from '@mui/icons-material';
import ParentTask from './ParentTask';
import OnboardingProgressBar from '../../../components/OnboardingProgressBar';
import { useChecklistProgress } from '../../../hooks/onboarding.hook';

const Checklist: React.FC<{ parentChecklists: ChecklistType[]; checklistName?: string }> = ({
parentChecklists,
checklistName
}) => {
const Checklist: React.FC<{
parentChecklists: ChecklistType[];
checkedChecklists: ChecklistType[];
checklistName?: string;
}> = ({ parentChecklists, checkedChecklists, checklistName }) => {
const theme = useTheme();
const [showTasks, setShowTasks] = useState(false);
const progress = useChecklistProgress(parentChecklists, checkedChecklists);

const toggleShowTasks = () => {
setShowTasks((prev) => !prev);
Expand All @@ -24,7 +27,7 @@ const Checklist: React.FC<{ parentChecklists: ChecklistType[]; checklistName?: s
{checklistName ?? 'General'} Checklist
</Typography>
<Box sx={{ flexGrow: 1, mx: 2 }}>
<OnboardingProgressBar value={51} />
<OnboardingProgressBar value={progress} />
</Box>
<IconButton onClick={toggleShowTasks}>{showTasks ? <KeyboardArrowDown /> : <KeyboardArrowRight />}</IconButton>
</Grid>
Expand All @@ -40,7 +43,7 @@ const Checklist: React.FC<{ parentChecklists: ChecklistType[]; checklistName?: s
}}
>
{parentChecklists.map((parentChecklist) => (
<ParentTask parentTask={parentChecklist} />
<ParentTask parentTask={parentChecklist} checkedChecklists={checkedChecklists} />
))}
</Box>
</Grid>
Expand Down
Loading

0 comments on commit 85acc57

Please sign in to comment.