Skip to content

Commit e0478e6

Browse files
initial survey outline + backend compatability
1 parent 174a822 commit e0478e6

32 files changed

+3075
-1410
lines changed

client/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
"type": "module",
44
"dependencies": {
55
"@casl/ability": "^6.7.3",
6+
"@casl/react": "^5.0.0",
67
"@emotion/react": "^11.14.0",
78
"@emotion/styled": "^11.14.1",
89
"@mui/icons-material": "^7.3.4",
@@ -14,6 +15,7 @@
1415
"cra-template": "1.2.0",
1516
"html5-qrcode": "^2.3.8",
1617
"jwt-decode": "^4.0.0",
18+
"mui": "^0.0.1",
1719
"qrcode.react": "^4.2.0",
1820
"react": "^18.2.0",
1921
"react-dom": "^18.2.0",

client/src/App.tsx

Lines changed: 135 additions & 163 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
import { useState } from 'react';
2-
31
import NewUser from '@/pages/AdminDashboard/NewUser';
42
import AdminDashboard from '@/pages/AdminDashboard/StaffDashboard';
53
import QrPage from '@/pages/CompletedSurvey/QrPage';
@@ -15,6 +13,7 @@ import Signup from '@/pages/Signup/Signup';
1513
import SurveyComponent from '@/pages/Survey/SurveyComponent';
1614
import SurveyEntryDashboard from '@/pages/SurveyEntryDashboard/SurveyEntryDashboard';
1715
import CssBaseline from '@mui/material/CssBaseline';
16+
import { ProtectedRoute } from './components/ProtectedRoute';
1817
import { ThemeProvider } from '@mui/material/styles';
1918
import {
2019
Navigate,
@@ -23,172 +22,145 @@ import {
2322
Routes
2423
} from 'react-router-dom';
2524

26-
import { useAuthStore } from './stores/useAuthStore';
27-
import { useSurveyStore } from './stores/useSurveyStore';
2825
import { muiTheme } from './theme/muiTheme';
29-
import { hasAuthToken } from './utils/authTokenHandler';
26+
import { AbilityContext, AuthProvider } from '@/contexts';
27+
import { useAbility, useAuth } from '@/hooks';
3028

3129
function App() {
32-
const [isLoggedIn, setIsLoggedIn] = useState<boolean>(hasAuthToken());
33-
34-
const handleLogin = () => {
35-
setIsLoggedIn(true);
36-
};
37-
38-
const handleLogout = () => {
39-
setIsLoggedIn(false);
40-
// Clear auth and survey storage upon logout
41-
useAuthStore.getState().clearSession();
42-
useSurveyStore.getState().clearSession();
43-
};
30+
const { isLoggedIn, handleLogin, handleLogout } = useAuth();
31+
const ability = useAbility();
4432

4533
return (
46-
<ThemeProvider theme={muiTheme}>
47-
<CssBaseline />
48-
<Router>
49-
<Routes>
50-
<Route
51-
path="/"
52-
element={<Navigate replace to="/login" />}
53-
/>
54-
<Route
55-
path="/login"
56-
element={<Login onLogin={handleLogin} />}
57-
/>
58-
<Route
59-
path="/survey/:id/survey"
60-
element={
61-
isLoggedIn ? (
62-
<SurveyComponent onLogout={handleLogout} />
63-
) : (
64-
<Navigate replace to="/login" />
65-
)
66-
}
67-
/>
68-
<Route path="/signup" element={<Signup />} />
69-
<Route
70-
path="/dashboard"
71-
element={
72-
isLoggedIn ? (
73-
<LandingPage onLogout={handleLogout} />
74-
) : (
75-
<Navigate replace to="/login" />
76-
)
77-
}
78-
/>
79-
<Route
80-
path="/survey"
81-
element={
82-
isLoggedIn ? (
83-
<SurveyComponent onLogout={handleLogout} />
84-
) : (
85-
<Navigate replace to="/login" />
86-
)
87-
}
88-
/>
89-
<Route
90-
path="/admin-dashboard"
91-
element={
92-
isLoggedIn ? (
93-
<AdminDashboard onLogout={handleLogout} />
94-
) : (
95-
<Navigate replace to="/login" />
96-
)
97-
}
98-
/>
99-
<Route
100-
path="/admin-edit-profile/:id"
101-
element={
102-
isLoggedIn ? (
103-
<AdminEditProfile onLogout={handleLogout} />
104-
) : (
105-
<Navigate replace to="/login" />
106-
)
107-
}
108-
/>
109-
<Route
110-
path="/add-new-user"
111-
element={
112-
isLoggedIn ? (
113-
<NewUser onLogout={handleLogout} />
114-
) : (
115-
<Navigate replace to="/login" />
116-
)
117-
}
118-
/>
119-
<Route
120-
path="/survey-entries"
121-
element={
122-
isLoggedIn ? (
123-
<SurveyEntryDashboard onLogout={handleLogout} />
124-
) : (
125-
<Navigate replace to="/login" />
126-
)
127-
}
128-
/>
129-
<Route
130-
path="/qrcode"
131-
element={
132-
isLoggedIn ? (
133-
<QrPage onLogout={handleLogout} />
134-
) : (
135-
<Navigate replace to="/login" />
136-
)
137-
}
138-
/>
139-
<Route
140-
path="/past-entries"
141-
element={
142-
isLoggedIn ? (
143-
<PastEntries onLogout={handleLogout} />
144-
) : (
145-
<Navigate replace to="/login" />
146-
)
147-
}
148-
/>
149-
<Route
150-
path="/survey/:id"
151-
element={
152-
isLoggedIn ? (
153-
<SurveyDetails onLogout={handleLogout} />
154-
) : (
155-
<Navigate replace to="/login" />
156-
)
157-
}
158-
/>
159-
<Route
160-
path="/survey/:id/edit"
161-
element={
162-
isLoggedIn ? (
163-
<SurveyEdit />
164-
) : (
165-
<Navigate replace to="/login" />
166-
)
167-
}
168-
/>
169-
<Route
170-
path="/apply-referral"
171-
element={
172-
isLoggedIn ? (
173-
<ApplyReferral onLogout={handleLogout} />
174-
) : (
175-
<Navigate replace to="/login" />
176-
)
177-
}
178-
/>
179-
<Route
180-
path="/view-profile"
181-
element={
182-
isLoggedIn ? (
183-
<ViewProfile onLogout={handleLogout} />
184-
) : (
185-
<Navigate replace to="/login" />
186-
)
187-
}
188-
/>
189-
</Routes>
190-
</Router>
191-
</ThemeProvider>
34+
<AuthProvider value={{ onLogout: handleLogout, isLoggedIn }}>
35+
<AbilityContext.Provider value={ability}>
36+
<ThemeProvider theme={muiTheme}>
37+
<CssBaseline />
38+
<Router>
39+
<Routes>
40+
<Route
41+
path="/"
42+
element={<Navigate replace to="/login" />}
43+
/>
44+
<Route
45+
path="/login"
46+
element={<Login onLogin={handleLogin} />}
47+
/>
48+
<Route
49+
path="/survey/:id/survey"
50+
element={
51+
<ProtectedRoute
52+
isLoggedIn={isLoggedIn}
53+
children={<SurveyComponent />}
54+
/>
55+
}
56+
/>
57+
<Route path="/signup" element={<Signup />} />
58+
<Route
59+
path="/dashboard"
60+
element={
61+
<ProtectedRoute
62+
isLoggedIn={isLoggedIn}
63+
children={<LandingPage />}
64+
/>
65+
}
66+
/>
67+
<Route
68+
path="/survey"
69+
element={
70+
<ProtectedRoute
71+
isLoggedIn={isLoggedIn}
72+
children={<SurveyComponent />}
73+
/>
74+
}
75+
/>
76+
<Route
77+
path="/admin-dashboard"
78+
element={
79+
<ProtectedRoute
80+
isLoggedIn={isLoggedIn}
81+
children={<AdminDashboard />}
82+
/>
83+
}
84+
/>
85+
<Route
86+
path="/admin-edit-profile/:id"
87+
element={
88+
<ProtectedRoute
89+
isLoggedIn={isLoggedIn}
90+
children={<AdminEditProfile />}
91+
/>
92+
}
93+
/>
94+
<Route
95+
path="/add-new-user"
96+
element={
97+
<ProtectedRoute
98+
isLoggedIn={isLoggedIn}
99+
children={<NewUser />}
100+
/>
101+
}
102+
/>
103+
<Route
104+
path="/survey-entries"
105+
element={
106+
<ProtectedRoute isLoggedIn={isLoggedIn}
107+
children={<SurveyEntryDashboard />}
108+
/>
109+
}
110+
/>
111+
<Route
112+
path="/qrcode"
113+
element={
114+
<ProtectedRoute isLoggedIn={isLoggedIn}
115+
children={<QrPage />}
116+
/>
117+
}
118+
/>
119+
<Route
120+
path="/past-entries"
121+
element={
122+
<ProtectedRoute isLoggedIn={isLoggedIn}
123+
children={<PastEntries />}
124+
/>
125+
}
126+
/>
127+
<Route
128+
path="/survey/:id"
129+
element={
130+
<ProtectedRoute isLoggedIn={isLoggedIn}
131+
children={<SurveyDetails />}
132+
/>
133+
}
134+
/>
135+
<Route
136+
path="/survey/:id/edit"
137+
element={
138+
<ProtectedRoute isLoggedIn={isLoggedIn}
139+
children={<SurveyEdit />}
140+
/>
141+
}
142+
/>
143+
<Route
144+
path="/apply-referral"
145+
element={
146+
<ProtectedRoute isLoggedIn={isLoggedIn}
147+
children={<ApplyReferral />}
148+
/>
149+
}
150+
/>
151+
<Route
152+
path="/view-profile"
153+
element={
154+
<ProtectedRoute isLoggedIn={isLoggedIn}
155+
children={<ViewProfile onLogout={handleLogout} />} // TODO: rm onLogout when updating API fetching to useApi hook
156+
/>
157+
}
158+
/>
159+
</Routes>
160+
</Router>
161+
</ThemeProvider>
162+
</AbilityContext.Provider>
163+
</AuthProvider>
192164
);
193165
}
194166

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,10 @@ import { useEffect, useRef, useState } from 'react';
44

55
import { useNavigate } from 'react-router-dom';
66

7-
import { LogoutProps } from '@/types/AuthProps';
7+
import { useAuthContext } from '@/contexts';
88

9-
function Header({ onLogout }: LogoutProps) {
9+
export function Header() {
10+
const { onLogout } = useAuthContext();
1011
const [isProfileMenuOpen, setIsProfileMenuOpen] = useState(false);
1112
const navigate = useNavigate();
1213
const menuRef = useRef<HTMLDivElement | null>(null); // Ref to track the menu
@@ -159,5 +160,3 @@ function Header({ onLogout }: LogoutProps) {
159160
</div>
160161
);
161162
}
162-
163-
export default Header;
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { Navigate } from 'react-router-dom';
2+
import { ReactNode } from 'react';
3+
import { Header } from '@/components';
4+
5+
interface ProtectedRouteProps {
6+
isLoggedIn: boolean;
7+
children: ReactNode;
8+
redirectTo?: string;
9+
}
10+
11+
export const ProtectedRoute = ({
12+
isLoggedIn,
13+
children,
14+
redirectTo = '/login'
15+
}: ProtectedRouteProps) => {
16+
return isLoggedIn ? <><Header />{children}</> : <Navigate replace to={redirectTo} />;
17+
};

client/src/components/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export { ProtectedRoute } from './ProtectedRoute';
2+
export { Header } from './Header';
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { createContext } from 'react';
2+
import { createContextualCan } from '@casl/react';
3+
import { Ability } from '@/permissions/constants';
4+
import defineAbilitiesForUser from '@/permissions/abilityBuilder';
5+
6+
// Default ability will be nonexistent user (i.e. no permissions)
7+
export const AbilityContext = createContext<Ability>(defineAbilitiesForUser('', '', '', []));
8+
export const Can = createContextualCan<Ability>(AbilityContext.Consumer);

0 commit comments

Comments
 (0)