Skip to content

Commit a6fdd1b

Browse files
authored
Merge pull request #24 from acm-uiuc/dsingh14/ui-up2
functional profile designer
2 parents 703e7a7 + f96a9b3 commit a6fdd1b

File tree

17 files changed

+899
-161
lines changed

17 files changed

+899
-161
lines changed

clientv2/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
"@kinde-oss/kinde-auth-react": "^4.0.1",
2323
"@mantine/core": "7.11.1",
2424
"@mantine/hooks": "7.11.1",
25+
"@mantine/notifications": "^7.11.1",
2526
"@tabler/icons-react": "^3.10.0",
2627
"axios": "^1.7.2",
2728
"dotenv": "^16.4.5",

clientv2/src/App.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
import '@mantine/core/styles.css';
2+
import '@mantine/notifications/styles.css';
23
import { MantineProvider } from '@mantine/core';
4+
import { Notifications } from '@mantine/notifications';
35
import { Router } from './Router';
46
import { theme } from './theme';
57

68
export default function App() {
79
return (
810
<MantineProvider theme={theme}>
11+
<Notifications position="top-right" />
912
<Router />
1013
</MantineProvider>
1114
);

clientv2/src/Router.tsx

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { createBrowserRouter, Navigate, RouterProvider } from 'react-router-dom';
22
import { AuthRoleEnum, useAuth } from './components/AuthContext';
33
import { LoginPage } from './pages/Login.page';
4-
import { StudentHomePage } from './pages/student/StudentHome.page';
4+
import { StudentHomePage } from './pages/student/StudentProfile.page';
55
import { RecruiterHomePage } from './pages/recruiter/RecruiterHome.page';
66

77
const unauthenticatedRouter = createBrowserRouter([
@@ -13,6 +13,10 @@ const unauthenticatedRouter = createBrowserRouter([
1313
path: '/login',
1414
element: <LoginPage />,
1515
},
16+
{
17+
path: '/profile',
18+
element: <Navigate to="/login" replace />,
19+
},
1620
]);
1721

1822
const recruiterRouter = createBrowserRouter([
@@ -29,12 +33,16 @@ const recruiterRouter = createBrowserRouter([
2933
const studentRouter = createBrowserRouter([
3034
{
3135
path: '/',
32-
element: <StudentHomePage />,
36+
element: <Navigate to="/profile" replace />,
3337
},
3438
{
3539
path: '/login',
3640
element: <Navigate to="/" replace />,
3741
},
42+
{
43+
path: '/profile',
44+
element: <StudentHomePage />,
45+
},
3846
]);
3947

4048
export function Router() {

clientv2/src/components/AuthContext/index.tsx

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
import React, { createContext, ReactNode, useContext, useState, useEffect } from 'react';
22
import { useMsal } from '@azure/msal-react';
33
import { useKindeAuth } from '@kinde-oss/kinde-auth-react';
4-
import { AuthenticationResult, InteractionRequiredAuthError, InteractionStatus } from '@azure/msal-browser';
4+
import {
5+
AuthenticationResult,
6+
InteractionRequiredAuthError,
7+
InteractionStatus,
8+
} from '@azure/msal-browser';
59
import { MantineProvider } from '@mantine/core';
610
import FullScreenLoader from './LoadingScreen';
711

@@ -57,19 +61,19 @@ export const AuthProvider: React.FC<AuthProviderProps> = ({ children }) => {
5761
user,
5862
logout: kindeLogout,
5963
getToken: getKindeToken,
60-
getPermission: getKindePermission
64+
getPermission: getKindePermission,
6165
} = useKindeAuth();
6266

6367
const [userData, setUserData] = useState<AuthContextData | null>(null);
6468
const [isLoggedIn, setIsLoggedIn] = useState<boolean>(
6569
(isAuthenticated || accounts.length > 0) && !isLoading
6670
);
6771
if (isAuthenticated && !isLoading && !userData) {
68-
const isRecruiter = getKindePermission("recruiter:resume-book").isGranted;
72+
const isRecruiter = getKindePermission('recruiter:resume-book').isGranted;
6973
if (!isRecruiter) {
7074
setUserData(null);
7175
setIsLoggedIn(false);
72-
window.location.href = "/";
76+
window.location.href = '/';
7377
} else {
7478
setUserData({
7579
email: user?.email!,
@@ -79,7 +83,6 @@ export const AuthProvider: React.FC<AuthProviderProps> = ({ children }) => {
7983
});
8084
setIsLoggedIn(true);
8185
}
82-
8386
}
8487

8588
useEffect(() => {
@@ -89,9 +92,10 @@ export const AuthProvider: React.FC<AuthProviderProps> = ({ children }) => {
8992
handleMsalResponse(response);
9093
} else if (accounts.length > 0) {
9194
// User is already logged in, set the state
95+
const [lastName, firstName] = accounts[0].name?.split(",")!
9296
setUserData({
9397
email: accounts[0].username,
94-
name: accounts[0].name,
98+
name: `${firstName} ${lastName}`,
9599
authenticationMethod: AuthSourceEnum.MSAL,
96100
role: AuthRoleEnum.STUDENT,
97101
});
@@ -125,25 +129,25 @@ export const AuthProvider: React.FC<AuthProviderProps> = ({ children }) => {
125129
}
126130
if (userData?.authenticationMethod === AuthSourceEnum.MSAL) {
127131
try {
128-
const accounts = instance.getAllAccounts();
129-
if (accounts.length > 0) {
132+
const msalAccounts = instance.getAllAccounts();
133+
if (msalAccounts.length > 0) {
130134
const silentRequest = {
131-
account: accounts[0],
132-
scopes: [".default"], // Adjust scopes as needed
135+
account: msalAccounts[0],
136+
scopes: ['.default'], // Adjust scopes as needed
133137
};
134138
const tokenResponse = await instance.acquireTokenSilent(silentRequest);
135139
return tokenResponse.accessToken;
136140
} else {
137-
throw new Error('No accounts found.');
141+
throw new Error("More than one account found, cannot proceed.")
138142
}
139143
} catch (error) {
140144
console.error('Silent token acquisition failed.', error);
141145
if (error instanceof InteractionRequiredAuthError) {
142146
// Fallback to interaction when silent token acquisition fails
143147
try {
144148
const interactiveRequest = {
145-
scopes: [".default"], // Adjust scopes as needed
146-
redirectUri: "/login", // Redirect URI after login
149+
scopes: ['.default'], // Adjust scopes as needed
150+
redirectUri: '/login', // Redirect URI after login
147151
};
148152
const tokenResponse: any = await instance.acquireTokenRedirect(interactiveRequest);
149153
return tokenResponse.accessToken;
@@ -161,7 +165,7 @@ export const AuthProvider: React.FC<AuthProviderProps> = ({ children }) => {
161165
}
162166
throw new Error('Unknown authentication method.');
163167
};
164-
168+
165169
const loginMsal = () => {
166170
instance.loginRedirect();
167171
};
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import React, { MouseEventHandler } from 'react';
2+
import { Container, Paper, Title, Text, Button } from '@mantine/core';
3+
4+
interface FullPageErrorProps {
5+
errorCode?: number;
6+
errorMessage?: string;
7+
onRetry?: MouseEventHandler<HTMLButtonElement>;
8+
}
9+
10+
const FullPageError: React.FC<FullPageErrorProps> = ({ errorCode, errorMessage, onRetry }) => (
11+
<Container>
12+
<Paper shadow="md" radius="md">
13+
<Title>{errorCode || 'An error occurred'}</Title>
14+
<Text color="dimmed">
15+
{errorMessage || 'Something went wrong. Please try again later.'}
16+
</Text>
17+
{onRetry && (
18+
<Button variant="outline" onClick={onRetry}>
19+
Retry
20+
</Button>
21+
)}
22+
</Paper>
23+
</Container>
24+
);
25+
26+
export default FullPageError;

clientv2/src/components/Navbar/index.tsx

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,23 +4,25 @@ import { Group, Divider, Box, Burger, Drawer, ScrollArea, rem, Badge } from '@ma
44
import { useDisclosure } from '@mantine/hooks';
55
import classes from './index.module.css';
66
import LogoBadge from './Logo';
7-
import { AuthContextData, AuthSourceEnum } from '../AuthContext';
7+
import { AuthContextData, AuthRoleEnum, AuthSourceEnum } from '../AuthContext';
88
import { AuthenticatedProfileDropdown } from '../ProfileDropdown';
99

1010
interface HeaderNavbarProps {
1111
userData?: AuthContextData | null;
1212
}
1313

14+
const isActiveLink = (path: string) => location.pathname === path;
15+
1416
const HeaderNavbar: React.FC<HeaderNavbarProps> = ({ userData }) => {
1517
const [drawerOpened, { toggle: toggleDrawer, close: closeDrawer }] = useDisclosure(false);
1618
let badge = null;
17-
if (userData?.authenticationMethod === AuthSourceEnum.LOCAL) {
19+
if (userData?.role === AuthRoleEnum.RECRUITER) {
1820
badge = (
1921
<Badge color="blue" style={{ marginLeft: 10 }}>
2022
Recruiter
2123
</Badge>
2224
);
23-
} else if (userData?.authenticationMethod === AuthSourceEnum.MSAL) {
25+
} else if (userData?.role === AuthRoleEnum.STUDENT) {
2426
badge = (
2527
<Badge color="#FF5F05" style={{ marginLeft: 10 }}>
2628
Student
@@ -34,9 +36,16 @@ const HeaderNavbar: React.FC<HeaderNavbarProps> = ({ userData }) => {
3436
<Group justify="start" h="100%" gap={10}>
3537
<LogoBadge />
3638
{badge}
37-
<a href="/" className={classes.link}>
38-
Home
39-
</a>
39+
{userData?.role !== AuthRoleEnum.STUDENT ? (
40+
<a href="/" className={classes.link}>
41+
Home
42+
</a>
43+
) : null}
44+
{userData?.role === AuthRoleEnum.STUDENT ? (
45+
<a href="/profile" className={classes.link}>
46+
My Profile
47+
</a>
48+
) : null}
4049
</Group>
4150
<Group h="100%" justify="end" gap={10} visibleFrom="sm">
4251
{userData ? <AuthenticatedProfileDropdown userData={userData} /> : null}

clientv2/src/components/ProfileDropdown/index.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ const AuthenticatedProfileDropdown: React.FC<ProfileDropdownProps> = ({ userData
4747
>
4848
<Center inline>
4949
<Box component="span" mr={5}>
50-
Profile
50+
My Account
5151
</Box>
5252
<IconChevronDown
5353
style={{ width: rem(16), height: rem(16) }}
@@ -57,7 +57,7 @@ const AuthenticatedProfileDropdown: React.FC<ProfileDropdownProps> = ({ userData
5757
</a>
5858
</Popover.Target>
5959

60-
<Popover.Dropdown style={{ overflow: 'hidden' }} aria-label="Authenticated Profile Dropdown">
60+
<Popover.Dropdown style={{ overflow: 'hidden' }} aria-label="Authenticated My Account Dropdown">
6161
<SimpleGrid cols={1} spacing={0}>
6262
<UnstyledButton className={classes.subLink} key="name">
6363
<Group wrap="nowrap" align="flex-start">

0 commit comments

Comments
 (0)