Skip to content

Commit

Permalink
#2816 user promotion
Browse files Browse the repository at this point in the history
  • Loading branch information
superhvarn committed Dec 25, 2024
1 parent 0d8ad13 commit 6220d82
Show file tree
Hide file tree
Showing 8 changed files with 101 additions and 45 deletions.
2 changes: 1 addition & 1 deletion src/backend/src/prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ model User {
googleAuthId String @unique
email String @unique
emailId String? @unique
completedOnboarding Boolean @default(true)
completedOnboarding Boolean @default(false)
roles Role[]
userSettings User_Settings?
userSecureSettings User_Secure_Settings?
Expand Down
18 changes: 17 additions & 1 deletion src/backend/src/services/users.services.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
*/
Expand All @@ -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
Expand Down
4 changes: 4 additions & 0 deletions src/frontend/src/apis/users.api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 = (id: string) => {
return axios.post<{ message: string }>(apiUrls.toggleCompletedOnboarding(id));
};
25 changes: 23 additions & 2 deletions src/frontend/src/hooks/users.hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ import {
getCurrentUserSecureSettings,
getUserSecureSettings,
getUserScheduleSettings,
updateUserScheduleSettings
updateUserScheduleSettings,
toggleCompletedOnboarding
} from '../apis/users.api';
import {
User,
Expand All @@ -28,7 +29,8 @@ import {
UserSecureSettings,
UserScheduleSettings,
UserWithScheduleSettings,
SetUserScheduleSettingsPayload
SetUserScheduleSettingsPayload,
ToggleCompletedOnboardingPayload
} from 'shared';
import { useAuth } from './auth.hooks';
import { useContext } from 'react';
Expand Down Expand Up @@ -233,3 +235,22 @@ export const useUpdateUserRole = () => {
}
);
};

/**
* Custom React Hook to update a user's role.
*/
export const useToggleCompletedOnboarding = () => {
const queryClient = useQueryClient();
return useMutation<{ message: string }, Error, ToggleCompletedOnboardingPayload>(
['users', 'toggle-onboarding'],
async (toggleCompletedOnboardingPayload: ToggleCompletedOnboardingPayload) => {
const { data } = await toggleCompletedOnboarding(toggleCompletedOnboardingPayload.userId);
return data;
},
{
onSuccess: () => {
queryClient.invalidateQueries(['users']);
}
}
);
};
73 changes: 45 additions & 28 deletions src/frontend/src/pages/HomePage/OnboardingHomePage.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,29 @@
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 { useCurrentUser, 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 user = useCurrentUser();

console.log(user);

const toast = useToast();

const toggleCompletedOnboarding = useToggleCompletedOnboarding();

useEffect(() => {
setCurrentHomePage('onboarding');
Expand All @@ -22,13 +32,31 @@ const OnboardingHomePage = () => {
if (!organization || isLoading) return <LoadingIndicator />;
if (isError) return <ErrorPage message={error?.message} />;

const handleOpenModal = () => {
setModalOpen(true);
};

const handleCloseModal = () => {
setModalOpen(false);
};

const handleConfirmModal = async () => {
await toggleCompletedOnboarding.mutateAsync({ userId: user.userId });
toast.success('Role updated successfully!');
setModalOpen(false);
};

return (
<PageLayout title="Home" hidePageTitle>
<Grid container display="flex" alignItems="center" justifyContent={'space-between'} padding={1} marginTop={4}>
<Grid container display={'flex'} alignItems={'center'} marginLeft={2} marginTop={4}>
<Grid item xs={12} md={7}>
<Typography sx={{ fontSize: '2.5em' }}>Welcome to the {organization.name} Team</Typography>
</Grid>
<NERButton variant="contained">Finished?</NERButton>
<Grid item xs={12} md={5} sx={{ display: 'flex', justifyContent: 'flex-end' }}>
<NERButton variant="contained" onClick={handleOpenModal}>
Finished?
</NERButton>
</Grid>
</Grid>
<Grid
container
Expand All @@ -38,29 +66,10 @@ 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={50}
text={'Complete'}
typographySx={{ fontSize: '1.2em' }}
progressBarSx={{ height: '3vh' }}
/>
</Box>
<Box display={'flex'} justifyContent={'center'}>
<Typography sx={{ fontSize: '2em', mt: 4, ml: 2 }}>Progress Bar</Typography>
</Box>
<Grid container display="flex">
<Grid container display={'flex'}>
<Grid
item
xs={12}
Expand All @@ -82,6 +91,14 @@ const OnboardingHomePage = () => {
</Grid>
</Grid>
</Grid>
{isModalOpen && (
<ConfirmOnboardingChecklistModal
open={isModalOpen}
onHide={handleCloseModal}
onConfirm={handleConfirmModal}
title="Confirm Onboarding Checklist"
/>
)}
</PageLayout>
);
};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,34 +1,26 @@
import React from 'react';
import { Typography, Box } from '@mui/material';
import NERModal from '../../../components/NERModal';
import { useCurrentUser } from '../../../hooks/users.hooks';

interface ConfirmOnboardingChecklistModalProps {
open: boolean;
onHide: () => void;
onConfirm: () => void;
title?: string;
message?: string;
}

const ConfirmOnboardingChecklistModal: React.FC<ConfirmOnboardingChecklistModalProps> = ({
open,
onHide,
onConfirm,
title = 'Confirm Action'
}) => {
const user = useCurrentUser();

const handleConfirm = () => {
if (user) {
user.role = 'MEMBER';
}
onHide();
};

return (
<NERModal open={open} onHide={onHide} title={title} onSubmit={handleConfirm}>
<NERModal open={open} onHide={onHide} title={title} onSubmit={onConfirm}>
<Box
sx={{
textAlign: 'center',
padding: '1.5rem',
display: 'flex',
flexDirection: 'column',
alignItems: 'center'
Expand Down
4 changes: 3 additions & 1 deletion src/frontend/src/utils/urls.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,10 @@ const currentUserSecureSettings = () => `${users()}/secure-settings/current-user
const userSecureSettingsSet = () => `${users()}/secure-settings/set`;
const userRoleByUserId = (id: string) => `${usersById(id)}/change-role`;
const userFavoriteProjects = (id: string) => `${usersById(id)}/favorite-projects`;
const userSecureSettings = (id: string) => `${usersById(id)}/secure-settings`;
const userSecureSettings = (id: string) => `${usersById(id)}/secure-psettings`;
const userScheduleSettings = (id: string) => `${usersById(id)}/schedule-settings`;
const userScheduleSettingsSet = () => `${users()}/schedule-settings/set`;
const toggleCompletedOnboarding = (id: string) => `${usersById(id)}/toggle-completed-onboarding`;

/**************** Projects Endpoints ****************/
const projects = () => `${API_URL}/projects`;
Expand Down Expand Up @@ -217,6 +218,7 @@ export const apiUrls = {
userSecureSettings,
userScheduleSettings,
userScheduleSettingsSet,
toggleCompletedOnboarding,

projects,
allProjects,
Expand Down
4 changes: 4 additions & 0 deletions src/shared/src/types/user-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,10 @@ export interface UpdateUserRolePayload {
role: string;
}

export interface ToggleCompletedOnboardingPayload {
userId: string;
}

export interface UserScheduleSettings {
drScheduleSettingsId: string;
personalGmail: string;
Expand Down

0 comments on commit 6220d82

Please sign in to comment.