Skip to content

Commit

Permalink
Merge pull request #308 from COS301-SE-2024/fix/web/protectedRoutes-fix
Browse files Browse the repository at this point in the history
Fix/web/protected routes fix
  • Loading branch information
Rethakgetse-Manaka authored Aug 14, 2024
2 parents 17a4f95 + e5e2f76 commit 294fe19
Show file tree
Hide file tree
Showing 4 changed files with 122 additions and 76 deletions.
Binary file modified frontend/occupi-web/bun.lockb
Binary file not shown.
128 changes: 94 additions & 34 deletions frontend/occupi-web/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,50 @@
import { LoginForm, OtpPage, Settings, Dashboard, Analysis, Visitation, Faq, AiDashboard, Rooms, AboutPage, SecurityPage } from "@pages/index";
import { Appearance, OverviewComponent, BookingComponent, PDFReport, ProfileView } from "@components/index";
import {
LoginForm,
OtpPage,
Settings,
Dashboard,
Analysis,
Visitation,
Faq,
AiDashboard,
Rooms,
AboutPage,
SecurityPage,
} from "@pages/index";
import {
Appearance,
OverviewComponent,
BookingComponent,
PDFReport,
ProfileView,
} from "@components/index";
import { Layout } from "@layouts/index";
import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
import { useEffect, useState } from "react";
import { NotificationsSettings } from "@pages/notificationsSettings/NotificationsSettings";
import { FaroRoutes } from '@grafana/faro-react';
import { FaroRoutes } from "@grafana/faro-react";
import ProtectedRoutes from "@components/protectedRoutes/ProtectedRoutes";
import { Navigate } from "react-router";

function App() {
// Initialize the theme state with system preference
const [theme] = useState(() => {
const savedTheme = localStorage.getItem("theme") || "system";
return savedTheme;
});
const [isAuthenticated] = useState(() => {
// Retrieve user storage from localStorage
const userStorage = localStorage.getItem("user-storage");

// Parse the userStorage if it exists
if (userStorage) {
const parsedUserStorage = JSON.parse(userStorage);
// Check if the email in userDetails is null or empty
return parsedUserStorage?.state?.userDetails?.email ? true : false;
}

return false;
});
useEffect(() => {
const applyTheme = (theme: string) => {
if (theme === "system") {
Expand All @@ -35,38 +66,67 @@ function App() {
}, [theme]);
return (
<Router>
<FaroRoutes>
<Route path="/" element={<LoginForm />} />
<Route path="/otp" element={<OtpPage />} />
<Route
path="/*"
element={
<ProtectedRoutes>
<Layout>
<Routes>
<Route path="dashboard/*" element={<Dashboard />}>
<Route path="overview" element={<OverviewComponent />} />
<Route path="bookings" element={<BookingComponent />} />
<Route path="visitations" element={<Visitation />} />
<Route path="analysis" element={<Analysis />} />
</Route>
<Route path="reports" element={<PDFReport />} />{/**attach appropriate component */}
<Route path="faq" element={ <Faq/> } />{/**attach appropriate component */}
<Route path="ai-dashboard" element={<AiDashboard />} />{/**consider making ths its own page */}
<Route path="rooms" element={<Rooms />} />{/**attach appropriate component */}
{/* <Route path="notifications" element={<Notifications />} />*attach appropriate component */}
<FaroRoutes>
<Route
path="/"
element={
isAuthenticated ? (
<Navigate to="/dashboard/overview" />
) : (
<LoginForm />
)
}
/>
<Route
path="/otp"
element={
isAuthenticated ? (
<Navigate to="/dashboard/overview" />
) : (
<OtpPage />
)
}
/>
<Route
path="/*"
element={
<ProtectedRoutes>
<Layout>
<Routes>
<Route path="dashboard/*" element={<Dashboard />}>
<Route path="overview" element={<OverviewComponent />} />
<Route path="bookings" element={<BookingComponent />} />
<Route path="visitations" element={<Visitation />} />
<Route path="analysis" element={<Analysis />} />
</Route>
<Route path="reports" element={<PDFReport />} />
{/**attach appropriate component */}
<Route path="faq" element={<Faq />} />
{/**attach appropriate component */}
<Route path="ai-dashboard" element={<AiDashboard />} />
{/**consider making ths its own page */}
<Route path="rooms" element={<Rooms />} />
{/**attach appropriate component */}
{/* <Route path="notifications" element={<Notifications />} />*attach appropriate component */}

<Route path="settings/*" element={<Settings />}>
<Route path="profile" element={<ProfileView />} />{/**attach appropriate component */}
<Route path="appearance" element={<Appearance />} />
<Route path="notifications" element={<NotificationsSettings />} />{/**attach appropriate component */}
<Route path="security" element={<SecurityPage />} />{/**attach appropriate component */}
<Route path="about" element={<AboutPage />} />{/**attach appropriate component */}
</Route>
</Routes>
</Layout>
</ProtectedRoutes>}>
</Route>
<Route path="settings/*" element={<Settings />}>
<Route path="profile" element={<ProfileView />} />
{/**attach appropriate component */}
<Route path="appearance" element={<Appearance />} />
<Route
path="notifications"
element={<NotificationsSettings />}
/>
{/**attach appropriate component */}
<Route path="security" element={<SecurityPage />} />
{/**attach appropriate component */}
<Route path="about" element={<AboutPage />} />
{/**attach appropriate component */}
</Route>
</Routes>
</Layout>
</ProtectedRoutes>
}></Route>
</FaroRoutes>
</Router>
);
Expand Down
45 changes: 17 additions & 28 deletions frontend/occupi-web/src/AuthService.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import axios from "axios";
import { wrapper } from 'axios-cookiejar-support';
import { CookieJar } from 'tough-cookie';

import { wrapper } from "axios-cookiejar-support";
import { CookieJar } from "tough-cookie";

const jar = new CookieJar();
const client = wrapper(axios.create({ jar }));
Expand Down Expand Up @@ -188,21 +187,11 @@ const AuthService = {

logout: async () => {
try {
// Attempt to clear all cookies from the specific domain
try {
const cookies = await jar.getCookies('https://dev.occupi.tech/');
console.log("All cookies:", cookies);
cookies.forEach(cookie => {
jar.setCookie(`${cookie.key}=; Expires=Thu, 01 Jan 1970 00:00:00 GMT`, 'https://dev.occupi.tech/');
});
} catch (cookieError) {
console.error("Error clearing cookies:", cookieError);
throw new Error("Failed to clear cookies after logging out.");
}

// Perform the logout request
const response = await client.post(`${API_URL}/logout`, {});

const response = await client.post(`${API_URL}/logout`, {
withCredentials: true,
});
console.log(response.data);
return response.data;
} catch (error) {
if (axios.isAxiosError(error) && error.response?.data) {
Expand All @@ -212,8 +201,6 @@ const AuthService = {
}
},



updateUserDetails: async (userDetails: {
email: string;
name: string;
Expand All @@ -225,23 +212,29 @@ const AuthService = {
pronouns: string;
}) => {
try {
const response = await axios.post(`${API_USER_URL}/update-user`, userDetails);
const response = await axios.post(
`${API_USER_URL}/update-user`,
userDetails
);
if (response.data.status === 200) {
return response.data;
} else {
throw new Error(response.data.message || 'Failed to update user details');
throw new Error(
response.data.message || "Failed to update user details"
);
}
} catch (error) {
console.error("Error in updateUserDetails:", error);
if (axios.isAxiosError(error) && error.response) {
throw error.response.data;
}
throw new Error('An unexpected error occurred while updating user details');
throw new Error(
"An unexpected error occurred while updating user details"
);
}
},


getUserDetails : async (email: string) => {
getUserDetails: async (email: string) => {
try {
console.log(API_USER_URL);
const response = await axios.get(
Expand Down Expand Up @@ -317,8 +310,4 @@ function bufferDecode(value: string | null): Uint8Array | null {
return Uint8Array.from(atob(value), (c) => c.charCodeAt(0));
}





export default AuthService;
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,18 @@ const ProfileDropdown: React.FC<ProfileDropdownProps> = ({ isMinimized }) => {
const [isModalOpen, setModalOpen] = useState(false);
const [isNotificationsModalOpen, setNotificationsModalOpen] = useState(false);
const [isLoading, setLoading] = useState(false);
const [notifications, setNotifications] = useState<import("NotificationsService").Notification[]>([]);
const [notifications, setNotifications] = useState<
import("NotificationsService").Notification[]
>([]);

useEffect(() => {
loadNotifications();
}, []);

const loadNotifications = async () => {
try {
const fetchedNotifications = await NotificationService.fetchNotifications();
const fetchedNotifications =
await NotificationService.fetchNotifications();
setNotifications(fetchedNotifications);
} catch (error) {
console.error("Error loading notifications:", error);
Expand Down Expand Up @@ -106,8 +109,7 @@ const ProfileDropdown: React.FC<ProfileDropdownProps> = ({ isMinimized }) => {
<DropdownMenu
aria-label="User Actions"
variant="flat"
className={isMinimized ? "ml-2" : ""}
>
className={isMinimized ? "ml-2" : ""}>
<DropdownItem key="profile" className="h-14 gap-2">
<p className="font-bold text-text_col">Signed in as</p>
<p className="font-bold text-text_col">{userDetails?.email}</p>
Expand All @@ -120,38 +122,33 @@ const ProfileDropdown: React.FC<ProfileDropdownProps> = ({ isMinimized }) => {
<Badge
content={unreadCount}
color="warning"
style={{ position: "absolute", top: 0, right: 0 }}
>
style={{ position: "absolute", top: 0, right: 0 }}>
<Bell />
</Badge>
</div>
}
onClick={handleOpenNotifications}
>
onClick={handleOpenNotifications}>
Notifications
</DropdownItem>
<DropdownItem
key="settings"
shortcut="⌘S"
startContent={<SettingsIcon />}
onClick={() => navigateTo("/settings")}
>
onClick={() => navigateTo("/settings")}>
Settings
</DropdownItem>
<DropdownItem
key="faq"
shortcut="⌘H"
startContent={<Faq />}
onClick={() => navigateTo("/faq")}
>
onClick={() => navigateTo("/faq")}>
Help/FAQ
</DropdownItem>
<DropdownItem
data-testid="logout"
key="logout"
color="danger"
onClick={handleLogout}
>
onClick={handleLogout}>
Logout
</DropdownItem>
</DropdownMenu>
Expand Down

0 comments on commit 294fe19

Please sign in to comment.