Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/backend/src/controllers/teams.controllers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ export default class TeamsController {

static async completeOnboarding(req: Request, res: Response, next: NextFunction) {
try {
await TeamsService.completeOnboarding(req.currentUser, req.organization);
await TeamsService.completeOnboarding(req.currentUser);

res.status(200).json({ message: 'Successfully completed onboarding' });
} catch (error: unknown) {
Expand Down
5 changes: 5 additions & 0 deletions src/backend/src/prisma-query-args/auth-user.query-args.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,11 @@ export const getAuthUserQueryArgs = (organizationId: string) =>
where: {
organizationId
}
},
onboardedTeamTypes: {
where: {
organizationId
}
}
}
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
-- CreateTable
CREATE TABLE "_onboardedTeamTypes" (
"A" TEXT NOT NULL,
"B" TEXT NOT NULL
);

-- CreateIndex
CREATE UNIQUE INDEX "_onboardedTeamTypes_AB_unique" ON "_onboardedTeamTypes"("A", "B");

-- CreateIndex
CREATE INDEX "_onboardedTeamTypes_B_index" ON "_onboardedTeamTypes"("B");

-- AddForeignKey
ALTER TABLE "_onboardedTeamTypes" ADD CONSTRAINT "_onboardedTeamTypes_A_fkey" FOREIGN KEY ("A") REFERENCES "Team_Type"("teamTypeId") ON DELETE CASCADE ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE "_onboardedTeamTypes" ADD CONSTRAINT "_onboardedTeamTypes_B_fkey" FOREIGN KEY ("B") REFERENCES "User"("userId") ON DELETE CASCADE ON UPDATE CASCADE;
2 changes: 2 additions & 0 deletions src/backend/src/prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,7 @@ model User {
checkedChecklists Checklist[] @relation(name: "checkedChecklists")
contacts Contact[]
onboardingTeamTypes Team_Type[] @relation(name: "onboardingTeamTypes")
onboardedTeamTypes Team_Type[] @relation(name: "onboardedTeamTypes")
}

model Role {
Expand Down Expand Up @@ -774,6 +775,7 @@ model Team_Type {
calendarId String?
checklists Checklist[]
usersOnboarding User[] @relation(name: "onboardingTeamTypes")
usersOnboarded User[] @relation(name: "onboardedTeamTypes")

dateDeleted DateTime?
deletedById String?
Expand Down
31 changes: 13 additions & 18 deletions src/backend/src/services/teams.services.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { isAdmin, isHead, RoleEnum, Team, TeamType } from 'shared';
import { isAdmin, isHead, Team, TeamType } from 'shared';
import { Organization, User, WBS_Element_Status } from '@prisma/client';
import prisma from '../prisma/prisma';
import teamTransformer from '../transformers/teams.transformer';
Expand Down Expand Up @@ -609,30 +609,25 @@ export default class TeamsService {
return teamTypeTransformer(updatedTeamType);
}

static async completeOnboarding(submitter: User, organization: Organization) {
// remove the user from any onboardingTeamTypes they are a part of
const user = await prisma.user.update({
static async completeOnboarding(submitter: User) {
const onboardingTeamTypes = await prisma.team_Type.findMany({
where: { usersOnboarding: { some: { userId: submitter.userId } } }
});

const teamTypeIds = onboardingTeamTypes.map((teamType) => ({ teamTypeId: teamType.teamTypeId }));

// remove the user from any onboardingTeamTypes they are a part of and add them to the onboardedTeamTypes
await prisma.user.update({
where: { userId: submitter.userId },
include: { roles: true },
data: {
onboardedTeamTypes: {
set: teamTypeIds
},
onboardingTeamTypes: {
set: []
}
}
});

// update the users role to member after they complete their onboarding
const currentRole = user.roles.find((role) => role.organizationId === organization.organizationId);
if (currentRole && currentRole.roleType !== RoleEnum.MEMBER) {
await prisma.role.update({
where: {
uniqueRole: { userId: user.userId, organizationId: organization.organizationId }
},
data: {
roleType: RoleEnum.MEMBER
}
});
}
}

static async setTeamTypeImage(
Expand Down
6 changes: 4 additions & 2 deletions src/backend/src/services/users.services.ts
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,8 @@ export default class UsersService {
teamsAsLead: [],
teamsAsMember: [],
roles: [],
onboardingTeamTypes: []
onboardingTeamTypes: [],
onboardedTeamTypes: []
}),
token
};
Expand Down Expand Up @@ -333,7 +334,8 @@ export default class UsersService {
teamsAsLead: [],
teamsAsMember: [],
roles: [],
onboardingTeamTypes: []
onboardingTeamTypes: [],
onboardedTeamTypes: []
});
}

Expand Down
1 change: 1 addition & 0 deletions src/backend/src/transformers/auth-user.transformer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ const authenticatedUserTransformer = (
organizations: user.organizations.map((organization) => organization.organizationId),
currentOrganization: currentOrganization ? organizationTransformer(currentOrganization) : undefined,
onboardingTeamTypeIds: user.onboardingTeamTypes.map((teamType) => teamType.teamTypeId),
onboardedTeamTypeIds: user.onboardedTeamTypes.map((teamType) => teamType.teamTypeId),
teamsAsHead: user.teamsAsHead.map(teamTransformer),
teamsAsLead: user.teamsAsLead.map(teamTransformer),
permissions: user.roles
Expand Down
2 changes: 1 addition & 1 deletion src/frontend/src/app/AppMain.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ const AppMain: React.FC = () => {
<ToastProvider>
<BrowserRouter>
<AppOAuthProvider>
<AppPublic />
<AppPublic />
</AppOAuthProvider>
</BrowserRouter>
</ToastProvider>
Expand Down
7 changes: 6 additions & 1 deletion src/frontend/src/hooks/onboarding.hook.ts
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,12 @@ export const useGetImageUrls = (imageList: { objectId: string; imageFileId: stri
export const useChecklistProgress = (parentChecklists: Checklist[], checkedChecklists: Checklist[]) => {
const [progress, setProgress] = useState(0);
useEffect(() => {
if (!checkedChecklists || parentChecklists.length === 0) return;
if (parentChecklists.length === 0) {
setProgress(100);
return;
}

if (!checkedChecklists) return;

const totalChecklistsLength = parentChecklists.length;

Expand Down
21 changes: 21 additions & 0 deletions src/frontend/src/pages/HomePage/GuestHomePage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,25 @@ import MemberEncouragement from './components/MemberEncouragement';
import GuestOrganizationInfo from './components/GuestOrganizationInfo';
import FeaturedProjects from './components/FeaturedProjects';
import OrganizationLogo from './components/OrganizationLogo';
import NERModal from '../../components/NERModal';
import { useEffect, useState } from 'react';

interface GuestHomePageProps {
user: AuthenticatedUser;
}

const GuestHomePage = ({ user }: GuestHomePageProps) => {
const { isLoading, isError, error, data: userSettingsData } = useSingleUserSettings(user.userId);
const [showModal, setShowModal] = useState(false);

// shows modal only once per session
useEffect(() => {
const hasSeenModal = sessionStorage.getItem('hasSeenModal');
if (!hasSeenModal) {
setShowModal(true);
sessionStorage.setItem('hasSeenModal', 'true');
}
}, []);

if (isLoading || !userSettingsData) return <LoadingIndicator />;
if (isError) return <ErrorPage error={error} message={error.message} />;
Expand Down Expand Up @@ -57,6 +69,15 @@ const GuestHomePage = ({ user }: GuestHomePageProps) => {
<FeaturedProjects />
</Box>
</Box>
<NERModal
open={showModal}
title={'Want to become a member?'}
onHide={() => setShowModal(false)}
showCloseButton
hideFormButtons
>
Ask your head to upgrade you to a member to gain full access
</NERModal>
</PageLayout>
);
};
Expand Down
10 changes: 6 additions & 4 deletions src/frontend/src/pages/HomePage/Home.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,25 @@ import OnboardingHomePage from './OnboardingHomePage';
import SelectSubteamPage from './SelectSubteamPage';
import AcceptedPage from '../AcceptedPage/AcceptedPage';
import HomePage from './HomePage';
import { isGuest } from 'shared';
import { useCurrentUser } from '../../hooks/users.hooks';
import IntroGuestHomePage from './IntroGuestHomePage';
import { isGuest } from 'shared';

const Home: React.FC = () => {
const user = useCurrentUser();

const onOnboarding = user.onboardingTeamTypeIds.length > 0;
const userRole = user.role;
const completedOnboarding = user.onboardedTeamTypeIds.length > 0;

return (
<Switch>
{!isGuest(userRole) &&
{completedOnboarding &&
[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 && !completedOnboarding && isGuest(user.role) && (
<Redirect exact path={routes.HOME} to={routes.HOME_GUEST} />
)}
{onOnboarding && <Redirect exact path={routes.HOME} to={routes.HOME_PNM} />}
<Route exact path={routes.HOME_SELECT_SUBTEAM} component={SelectSubteamPage} />
<Route exact path={routes.HOME_ACCEPT} component={AcceptedPage} />
Expand Down
15 changes: 14 additions & 1 deletion src/frontend/src/pages/HomePage/components/ChecklistSection.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Box, Grid } from '@mui/material';
import { Box, Grid, Typography } from '@mui/material';
import { groupChecklists } from '../../../utils/onboarding.utils';
import Checklist from './Checklist';
import { Checklist as ChecklistType } from 'shared';
Expand All @@ -20,6 +20,19 @@ const ChecklistSection: React.FC<ChecklistSectionProps> = ({ usersChecklists, ch
</Grid>
))}
</Grid>
{!usersChecklists.length && (
<Box
sx={{
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
height: '100px',
marginTop: 6
}}
>
<Typography variant="h2">No checklists found</Typography>
</Box>
)}
</Box>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,6 @@ export const exampleAuthenticatedAdminUser: AuthenticatedUser = {
changeRequestsToReviewId: [],
organizations: [],
onboardingTeamTypeIds: [],
onboardedTeamTypeIds: [],
permissions: []
};
4 changes: 4 additions & 0 deletions src/frontend/src/tests/test-support/test-data/users.stub.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export const exampleAdminUser: AuthenticatedUser = {
changeRequestsToReviewId: [],
organizations: ['yello'],
onboardingTeamTypeIds: [],
onboardedTeamTypeIds: [],
permissions: []
};

Expand All @@ -40,6 +41,7 @@ export const exampleAdminUser2: AuthenticatedUser = {
changeRequestsToReviewId: [],
organizations: [],
onboardingTeamTypeIds: [],
onboardedTeamTypeIds: [],
permissions: []
};

Expand Down Expand Up @@ -84,6 +86,7 @@ export const exampleMemberUser: AuthenticatedUser = {
changeRequestsToReviewId: [],
organizations: [],
onboardingTeamTypeIds: [],
onboardedTeamTypeIds: [],
permissions: []
};

Expand All @@ -98,6 +101,7 @@ export const exampleGuestUser: AuthenticatedUser = {
changeRequestsToReviewId: [],
organizations: [],
onboardingTeamTypeIds: [],
onboardedTeamTypeIds: [],
permissions: []
};

Expand Down
1 change: 1 addition & 0 deletions src/shared/src/types/user-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ export interface AuthenticatedUser {
organizations: string[];
currentOrganization?: OrganizationPreview;
onboardingTeamTypeIds: string[];
onboardedTeamTypeIds: string[];
teamsAsHead?: Team[];
teamsAsLead?: Team[];
permissions: Permission[];
Expand Down