diff --git a/src/backend/src/controllers/users.controllers.ts b/src/backend/src/controllers/users.controllers.ts
index 458c19b8e4..4e6c9a9b8c 100644
--- a/src/backend/src/controllers/users.controllers.ts
+++ b/src/backend/src/controllers/users.controllers.ts
@@ -117,7 +117,7 @@ export default class UsersController {
static async toggleCompletedOnboarding(req: Request, res: Response, next: NextFunction) {
try {
- const { userId } = req.params;
+ const { userId } = req.currentUser;
await UsersService.toggleCompletedOnboarding(userId, req.organization);
diff --git a/src/backend/src/routes/users.routes.ts b/src/backend/src/routes/users.routes.ts
index 3a580231e5..c80e2d5ed3 100644
--- a/src/backend/src/routes/users.routes.ts
+++ b/src/backend/src/routes/users.routes.ts
@@ -19,7 +19,7 @@ userRouter.post(
UsersController.updateUserSettings
);
userRouter.post('/:userId/change-role', isRole(body('role')), validateInputs, UsersController.updateUserRole);
-userRouter.post('/:userId/toggle-completed-onboarding', UsersController.toggleCompletedOnboarding);
+userRouter.post('/toggle-completed-onboarding', UsersController.toggleCompletedOnboarding);
userRouter.post('/auth/login', UsersController.logUserIn);
userRouter.post('/auth/login/dev', UsersController.logUserInDev);
userRouter.post(
diff --git a/src/backend/src/services/users.services.ts b/src/backend/src/services/users.services.ts
index a03c231000..e69e88d10a 100644
--- a/src/backend/src/services/users.services.ts
+++ b/src/backend/src/services/users.services.ts
@@ -395,7 +395,7 @@ export default class UsersService {
}
/**
- * Toggles the completed onboarding status of a user
+ * Toggles the completed onboarding status of a user and elevates role to member if user completed onboarding
* @param user the user who's onboarding status is being toggled
* @returns the updated user
*/
@@ -409,8 +409,24 @@ export default class UsersService {
...getUserQueryArgs(organization.organizationId)
});
+ if (updatedUser.completedOnboarding) {
+ const currentRole = updatedUser.roles.find((role) => role.organizationId === organization.organizationId);
+
+ if (currentRole && currentRole.roleType !== RoleEnum.MEMBER) {
+ await prisma.role.update({
+ where: {
+ uniqueRole: { userId, organizationId: organization.organizationId }
+ },
+ data: {
+ roleType: RoleEnum.MEMBER
+ }
+ });
+ }
+ }
+
return userTransformer(updatedUser);
}
+
/**
* Gets a user's secure settings
* @param userId the id of user who's secure settings are being returned
diff --git a/src/frontend/src/apis/users.api.ts b/src/frontend/src/apis/users.api.ts
index 44d7a40d70..1ae1171efb 100644
--- a/src/frontend/src/apis/users.api.ts
+++ b/src/frontend/src/apis/users.api.ts
@@ -141,3 +141,7 @@ export const updateUserScheduleSettings = (settings: SetUserScheduleSettingsPayl
export const updateUserRole = (id: string, role: string) => {
return axios.post<{ message: string }>(apiUrls.userRoleByUserId(id), { role });
};
+
+export const toggleCompletedOnboarding = () => {
+ return axios.post<{ message: string }>(apiUrls.toggleCompletedOnboarding());
+};
diff --git a/src/frontend/src/hooks/users.hooks.ts b/src/frontend/src/hooks/users.hooks.ts
index b0c76b09b9..d8f2a20137 100644
--- a/src/frontend/src/hooks/users.hooks.ts
+++ b/src/frontend/src/hooks/users.hooks.ts
@@ -17,7 +17,8 @@ import {
getCurrentUserSecureSettings,
getUserSecureSettings,
getUserScheduleSettings,
- updateUserScheduleSettings
+ updateUserScheduleSettings,
+ toggleCompletedOnboarding
} from '../apis/users.api';
import {
User,
@@ -233,3 +234,22 @@ export const useUpdateUserRole = () => {
}
);
};
+
+/**
+ * Custom React Hook to toggle the current user's completed onboarding status.
+ */
+export const useToggleCompletedOnboarding = () => {
+ const queryClient = useQueryClient();
+ return useMutation<{ message: string }, Error>(
+ ['users', 'toggle-onboarding'],
+ async () => {
+ const { data } = await toggleCompletedOnboarding();
+ return data;
+ },
+ {
+ onSuccess: () => {
+ queryClient.invalidateQueries(['users']);
+ }
+ }
+ );
+};
diff --git a/src/frontend/src/pages/HomePage/OnboardingHomePage.tsx b/src/frontend/src/pages/HomePage/OnboardingHomePage.tsx
index a9e8dd006d..a410a91fb8 100644
--- a/src/frontend/src/pages/HomePage/OnboardingHomePage.tsx
+++ b/src/frontend/src/pages/HomePage/OnboardingHomePage.tsx
@@ -1,19 +1,25 @@
-import React, { useEffect } from 'react';
-import { Box, Grid, Typography, useTheme } from '@mui/material';
+import { Box, Grid, Typography } from '@mui/material';
import PageLayout from '../../components/PageLayout';
import { useCurrentOrganization } from '../../hooks/organizations.hooks';
+import React, { useEffect, useState } from 'react';
import LoadingIndicator from '../../components/LoadingIndicator';
import ErrorPage from '../ErrorPage';
import { useHomePageContext } from '../../app/HomePageContext';
import ChecklistSection from './components/ChecklistSection';
import OnboardingInfoSection from './components/OnboardingInfoSection';
-import OnboardingProgressBar from '../../components/OnboardingProgressBar';
+import ConfirmOnboardingChecklistModal from './components/ConfirmOnboardingChecklistModal';
import { NERButton } from '../../components/NERButton';
+import { useToggleCompletedOnboarding } from '../../hooks/users.hooks';
+import { useToast } from '../../hooks/toasts.hooks';
const OnboardingHomePage = () => {
const { data: organization, isError, error, isLoading } = useCurrentOrganization();
const { setCurrentHomePage } = useHomePageContext();
- const theme = useTheme();
+ const [isModalOpen, setModalOpen] = useState(false);
+
+ const toast = useToast();
+
+ const toggleCompletedOnboarding = useToggleCompletedOnboarding();
useEffect(() => {
setCurrentHomePage('onboarding');
@@ -22,13 +28,31 @@ const OnboardingHomePage = () => {
if (!organization || isLoading) return ;
if (isError) return ;
+ const handleOpenModal = () => {
+ setModalOpen(true);
+ };
+
+ const handleCloseModal = () => {
+ setModalOpen(false);
+ };
+
+ const handleConfirmModal = async () => {
+ await toggleCompletedOnboarding.mutateAsync();
+ toast.success('Role updated successfully!');
+ setModalOpen(false);
+ };
+
return (
-
+
Welcome to the {organization.name} Team
- Finished?
+
+
+ Finished?
+
+
{
flexDirection: 'column'
}}
>
-
-
-
-
+
+ Progress Bar
-
+
{
+ {isModalOpen && (
+
+ )}
);
};
diff --git a/src/frontend/src/pages/HomePage/components/ConfirmOnboardingChecklistModal.tsx b/src/frontend/src/pages/HomePage/components/ConfirmOnboardingChecklistModal.tsx
new file mode 100644
index 0000000000..9394797ee3
--- /dev/null
+++ b/src/frontend/src/pages/HomePage/components/ConfirmOnboardingChecklistModal.tsx
@@ -0,0 +1,45 @@
+import React from 'react';
+import { Typography, Box } from '@mui/material';
+import NERModal from '../../../components/NERModal';
+
+interface ConfirmOnboardingChecklistModalProps {
+ open: boolean;
+ onHide: () => void;
+ onConfirm: () => void;
+ title?: string;
+ message?: string;
+}
+
+const ConfirmOnboardingChecklistModal: React.FC = ({
+ open,
+ onHide,
+ onConfirm,
+ title = 'Confirm Action'
+}) => {
+ return (
+
+
+
+ Looks like you completed everything on the onboarding checklist!
+
+
+
+ You sure you want to submit?
+
+
+
+ (After you submit, you will be officially onboarded into NER!)
+
+
+
+ );
+};
+
+export default ConfirmOnboardingChecklistModal;
diff --git a/src/frontend/src/utils/urls.ts b/src/frontend/src/utils/urls.ts
index 1d9f59b128..9b4dc933f1 100644
--- a/src/frontend/src/utils/urls.ts
+++ b/src/frontend/src/utils/urls.ts
@@ -24,6 +24,7 @@ const userFavoriteProjects = (id: string) => `${usersById(id)}/favorite-projects
const userSecureSettings = (id: string) => `${usersById(id)}/secure-settings`;
const userScheduleSettings = (id: string) => `${usersById(id)}/schedule-settings`;
const userScheduleSettingsSet = () => `${users()}/schedule-settings/set`;
+const toggleCompletedOnboarding = () => `${users()}/toggle-completed-onboarding`;
/**************** Projects Endpoints ****************/
const projects = () => `${API_URL}/projects`;
@@ -221,6 +222,7 @@ export const apiUrls = {
userSecureSettings,
userScheduleSettings,
userScheduleSettingsSet,
+ toggleCompletedOnboarding,
projects,
allProjects,