fix logout

This commit is contained in:
chark1es 2025-04-02 20:11:32 -07:00
parent a935417a31
commit 9e2345c0f7
5 changed files with 12351 additions and 846 deletions

11376
package-lock.json generated Normal file

File diff suppressed because it is too large Load diff

View file

@ -10,10 +10,10 @@
"astro": "astro"
},
"dependencies": {
"@astrojs/mdx": "4.0.3",
"@astrojs/node": "^9.0.0",
"@astrojs/react": "^4.2.0",
"@astrojs/tailwind": "5.1.4",
"@astrojs/mdx": "^4.2.3",
"@astrojs/node": "^9.1.3",
"@astrojs/react": "^4.2.3",
"@astrojs/tailwind": "^6.0.2",
"@heroui/react": "^2.7.5",
"@iconify-json/heroicons": "^1.2.2",
"@iconify-json/mdi": "^1.2.3",
@ -21,9 +21,9 @@
"@types/highlight.js": "^10.1.0",
"@types/js-yaml": "^4.0.9",
"@types/lodash": "^4.17.15",
"@types/react": "^19.0.8",
"@types/react-dom": "^19.0.3",
"astro": "5.1.1",
"@types/react": "^19.1.0",
"@types/react-dom": "^19.1.1",
"astro": "^5.5.6",
"astro-expressive-code": "^0.40.2",
"astro-icon": "^1.1.5",
"chart.js": "^4.4.7",
@ -37,9 +37,9 @@
"next": "^15.1.2",
"pocketbase": "^0.25.1",
"prismjs": "^1.29.0",
"react": "^19.0.0",
"react": "^19.1.0",
"react-chartjs-2": "^5.3.0",
"react-dom": "^19.0.0",
"react-dom": "^19.1.0",
"react-hot-toast": "^2.5.2",
"react-icons": "^5.4.0",
"rehype-expressive-code": "^0.40.2",

View file

@ -59,16 +59,7 @@ export default function AccountSecuritySettings({
checkAuth();
}, []);
const handleLogout = async () => {
try {
await logger.send('logout', 'auth', 'User manually logged out from settings page');
await auth.logout();
window.location.href = '/';
} catch (error) {
console.error('Error during logout:', error);
toast.error('Failed to log out. Please try again.');
}
};
// No logout functions needed here as logout is handled in the dashboard menu
const detectBrowser = (userAgent: string): string => {
if (userAgent.indexOf('Chrome') > -1) return 'Chrome';
@ -179,17 +170,13 @@ export default function AccountSecuritySettings({
<h4 className="font-semibold text-lg mb-2">Account Actions</h4>
<div className="space-y-4">
<button
onClick={handleLogout}
className="btn btn-error btn-outline w-full md:w-auto"
>
Sign Out
</button>
<p className="text-sm text-warning p-3 bg-warning bg-opacity-10 rounded-lg">
If you need to delete your account or have other account-related issues,
please contact an IEEE UCSD administrator.
</p>
<p className="text-sm text-info p-3 bg-info bg-opacity-10 rounded-lg">
To log out of your account, use the Logout option in the dashboard menu.
</p>
</div>
</div>
</div>

79
src/pages/api/logout.ts Normal file
View file

@ -0,0 +1,79 @@
import type { APIRoute } from "astro";
// Mark this endpoint as server-rendered, not static
export const prerender = false;
export const GET: APIRoute = async ({ request, redirect }) => {
try {
// Get the Logto endpoint and client ID from environment variables
const logtoEndpoint = import.meta.env.LOGTO_ENDPOINT;
const clientId = import.meta.env.LOGTO_POCKETBASE_APP_ID;
if (!logtoEndpoint) {
throw new Error("LOGTO_ENDPOINT environment variable is not set");
}
if (!clientId) {
throw new Error(
"LOGTO_POCKETBASE_APP_ID environment variable is not set",
);
}
// Get the current origin to use as the redirect URL
const url = new URL(request.url);
const origin = url.origin;
// Construct the redirect URL (back to dashboard)
const redirectUrl = `${origin}/dashboard`;
// Log the redirect URL for debugging
console.log(`Setting post-logout redirect to: ${redirectUrl}`);
console.log(`Using client ID: ${clientId}`);
// Make a POST request to the Logto session end endpoint with the redirect in the body
const logoutUrl = `${logtoEndpoint}/oidc/session/end`;
try {
// Try to make a POST request with the redirect in the body and client ID
const response = await fetch(logoutUrl, {
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
body: new URLSearchParams({
post_logout_redirect_uri: redirectUrl,
client_id: clientId,
}),
redirect: "manual", // Don't automatically follow redirects
});
// If we get a redirect response, follow it
if (response.status >= 300 && response.status < 400) {
const location = response.headers.get("Location");
if (location) {
console.log(`Received redirect to: ${location}`);
return redirect(location);
}
}
// If POST doesn't work, fall back to the query parameter approach
console.log(
"POST request didn't result in expected redirect, falling back to GET",
);
return redirect(
`${logoutUrl}?post_logout_redirect_uri=${encodeURIComponent(redirectUrl)}&client_id=${encodeURIComponent(clientId)}`,
);
} catch (fetchError) {
console.error("Error making POST request to Logto:", fetchError);
// Fall back to the query parameter approach
return redirect(
`${logoutUrl}?post_logout_redirect_uri=${encodeURIComponent(redirectUrl)}&client_id=${encodeURIComponent(clientId)}`,
);
}
} catch (error) {
console.error("Error in logout API:", error);
// If there's an error, redirect to dashboard anyway
return redirect("/dashboard");
}
};

View file

@ -32,8 +32,8 @@ const components = Object.fromEntries(
);
// console.log(`Loaded component: ${section.component}`); // Debug log
return [section.component, component.default];
})
)
}),
),
);
// console.log("Available components:", Object.keys(components)); // Debug log
@ -52,10 +52,7 @@ const components = Object.fromEntries(
</head>
<body class="bg-base-200">
<!-- First Time Login Manager - This handles the onboarding popup for new users -->
<FirstTimeLoginManager
client:load
logtoApiEndpoint={logtoApiEndpoint}
/>
<FirstTimeLoginManager client:load logtoApiEndpoint={logtoApiEndpoint} />
<div class="flex h-screen">
<!-- Sidebar -->
@ -75,33 +72,19 @@ const components = Object.fromEntries(
<!-- User Profile -->
<div class="p-6 border-b border-base-200">
<!-- Loading State -->
<div
id="userProfileSkeleton"
class="flex items-center gap-4"
>
<div id="userProfileSkeleton" class="flex items-center gap-4">
<div class="avatar flex items-center justify-center">
<div
class="w-12 h-12 rounded-xl bg-base-300 animate-pulse"
>
</div>
<div class="w-12 h-12 rounded-xl bg-base-300 animate-pulse"></div>
</div>
<div class="flex-1">
<div
class="h-6 w-32 bg-base-300 animate-pulse rounded mb-2"
>
</div>
<div
class="h-5 w-20 bg-base-300 animate-pulse rounded"
>
<div class="h-6 w-32 bg-base-300 animate-pulse rounded mb-2">
</div>
<div class="h-5 w-20 bg-base-300 animate-pulse rounded"></div>
</div>
</div>
<!-- Signed Out State -->
<div
id="userProfileSignedOut"
class="flex items-center gap-4 hidden"
>
<div id="userProfileSignedOut" class="flex items-center gap-4 hidden">
<div class="avatar flex items-center justify-center">
<div
class="w-12 h-12 rounded-xl bg-base-300 text-base-content/30 flex items-center justify-center"
@ -110,22 +93,15 @@ const components = Object.fromEntries(
</div>
</div>
<div>
<h3
class="font-medium text-lg text-base-content/70"
>
<h3 class="font-medium text-lg text-base-content/70">
Signed Out
</h3>
<div class="badge badge-outline mt-1 opacity-50">
Guest
</div>
<div class="badge badge-outline mt-1 opacity-50">Guest</div>
</div>
</div>
<!-- Actual Profile -->
<div
id="userProfileSummary"
class="flex items-center gap-4 hidden"
>
<div id="userProfileSummary" class="flex items-center gap-4 hidden">
<div class="avatar flex items-center justify-center">
<div
class="w-12 h-12 rounded-xl bg-[#06659d] text-white ring ring-base-200 ring-offset-base-100 ring-offset-2 inline-flex items-center justify-center"
@ -137,9 +113,7 @@ const components = Object.fromEntries(
</div>
</div>
<div>
<h3 class="font-medium text-lg" id="userName">
Loading...
</h3>
<h3 class="font-medium text-lg" id="userName">Loading...</h3>
<div
class="badge badge-outline mt-1 border-[#06659d] text-[#06659d]"
id="userRole"
@ -178,64 +152,41 @@ const components = Object.fromEntries(
<div id="actualMenu" class="hidden">
{
Object.entries(dashboardConfig.categories).map(
([categoryKey, category]: [
string,
any,
]) => (
([categoryKey, category]: [string, any]) => (
<>
<li
class={`menu-title font-medium opacity-70 ${
category.role &&
category.role !== "none"
category.role && category.role !== "none"
? "hidden"
: ""
}`}
data-role-required={
category.role || "none"
}
data-role-required={category.role || "none"}
>
<span>{category.title}</span>
</li>
{category.sections.map(
(sectionKey: string) => {
const section =
dashboardConfig
.sections[
sectionKey
];
{category.sections.map((sectionKey: string) => {
const section = dashboardConfig.sections[sectionKey];
return (
<li
class={
section.role &&
section.role !==
"none"
section.role && section.role !== "none"
? "hidden"
: ""
}
data-role-required={
section.role
}
data-role-required={section.role}
>
<button
class={`dashboard-nav-btn gap-4 transition-all duration-200 outline-none focus:outline-none hover:bg-opacity-5 ${section.class || ""}`}
data-section={
sectionKey
}
data-section={sectionKey}
>
<Icon
name={
section.icon
}
class="h-5 w-5"
/>
<Icon name={section.icon} class="h-5 w-5" />
{section.title}
</button>
</li>
);
}
)}
})}
</>
)
),
)
}
</div>
@ -248,15 +199,10 @@ const components = Object.fromEntries(
class="flex-1 overflow-x-hidden overflow-y-auto bg-base-200 w-full xl:w-[calc(100%-20rem)]"
>
<!-- Mobile Header -->
<header
class="bg-base-100 p-4 shadow-md xl:hidden sticky top-0 z-40"
>
<header class="bg-base-100 p-4 shadow-md xl:hidden sticky top-0 z-40">
<div class="flex items-center justify-between">
<div class="flex items-center gap-2">
<button
id="mobileSidebarToggle"
class="btn btn-square btn-ghost"
>
<button id="mobileSidebarToggle" class="btn btn-square btn-ghost">
<Icon name="heroicons:bars-3" class="h-6 w-6" />
</button>
<h1 class="text-xl font-bold">IEEE UCSD</h1>
@ -268,11 +214,8 @@ const components = Object.fromEntries(
<div class="p-4 md:p-6 max-w-[1600px] mx-auto">
<!-- Loading State -->
<div id="pageLoadingState" class="w-full">
<div
class="flex flex-col items-center justify-center p-4 sm:p-8"
>
<div class="loading loading-spinner loading-lg">
</div>
<div class="flex flex-col items-center justify-center p-4 sm:p-8">
<div class="loading loading-spinner loading-lg"></div>
<p class="mt-4 opacity-70">Loading dashboard...</p>
</div>
</div>
@ -298,9 +241,7 @@ const components = Object.fromEntries(
<!-- Not Authenticated State -->
<div id="notAuthenticatedState" class="hidden w-full">
<div class="card bg-base-100 shadow-xl mx-2 sm:mx-0">
<div
class="card-body items-center text-center p-4 sm:p-8"
>
<div class="card-body items-center text-center p-4 sm:p-8">
<div class="mb-4 sm:mb-6">
<svg
xmlns="http://www.w3.org/2000/svg"
@ -317,11 +258,9 @@ const components = Object.fromEntries(
<h2 class="card-title text-xl sm:text-2xl mb-2">
Sign in to Access Dashboard
</h2>
<p
class="opacity-70 mb-4 sm:mb-6 text-sm sm:text-base"
>
Please sign in with your IEEE UCSD account
to access the dashboard.
<p class="opacity-70 mb-4 sm:mb-6 text-sm sm:text-base">
Please sign in with your IEEE UCSD account to access the
dashboard.
</p>
<button
class="login-button btn btn-primary btn-lg gap-2 w-full sm:w-auto"
@ -353,14 +292,12 @@ const components = Object.fromEntries(
// Skip if no component is defined
if (!section.component) return null;
const Component =
components[section.component];
const Component = components[section.component];
return (
<div
id={`${sectionKey}Section`}
class={`dashboard-section hidden ${
section.role &&
section.role !== "none"
section.role && section.role !== "none"
? "role-restricted"
: ""
}`}
@ -369,7 +306,7 @@ const components = Object.fromEntries(
<Component />
</div>
);
}
},
)
}
</div>
@ -398,11 +335,10 @@ const components = Object.fromEntries(
}
// Initialize page state
const pageLoadingState =
document.getElementById("pageLoadingState");
const pageLoadingState = document.getElementById("pageLoadingState");
const pageErrorState = document.getElementById("pageErrorState");
const notAuthenticatedState = document.getElementById(
"notAuthenticatedState"
"notAuthenticatedState",
);
const mainContent = document.getElementById("mainContent");
const sidebar = document.querySelector("aside");
@ -433,11 +369,9 @@ const components = Object.fromEntries(
}
// For non-sponsor roles, handle normally
document
.querySelectorAll("[data-role-required]")
.forEach((element) => {
document.querySelectorAll("[data-role-required]").forEach((element) => {
const requiredRole = element.getAttribute(
"data-role-required"
"data-role-required",
) as OfficerStatus;
// Skip elements that don't have a role requirement
@ -447,22 +381,185 @@ const components = Object.fromEntries(
}
// Check if user has permission for this role
const hasPermission = hasAccess(
officerStatus,
requiredRole
);
const hasPermission = hasAccess(officerStatus, requiredRole);
// Only show elements if user has permission
element.classList.toggle("hidden", !hasPermission);
});
};
// Function to delete all cookies (to handle Logto logout)
const deleteAllCookies = () => {
// Get all cookies
const cookies = document.cookie.split(";");
// Common paths that might have cookies
const paths = ["/", "/dashboard", "/auth", "/api"];
// Domains to target
const domains = [
"", // current domain
"auth.ieeeucsd.org",
".auth.ieeeucsd.org",
"ieeeucsd.org",
".ieeeucsd.org",
"dev.ieeeucsd.org",
".dev.ieeeucsd.org",
];
// Delete each cookie with all combinations of paths and domains
for (let i = 0; i < cookies.length; i++) {
const cookie = cookies[i];
const eqPos = cookie.indexOf("=");
const name =
eqPos > -1 ? cookie.substring(0, eqPos).trim() : cookie.trim();
if (!name) continue; // Skip empty cookie names
// Try all combinations of paths and domains
for (const path of paths) {
// Delete from current domain (no domain specified)
document.cookie = `${name}=;expires=Thu, 01 Jan 1970 00:00:00 GMT;path=${path}`;
// Try with specific domains
for (const domain of domains) {
if (domain) {
document.cookie = `${name}=;expires=Thu, 01 Jan 1970 00:00:00 GMT;path=${path};domain=${domain}`;
}
}
}
}
// Specifically target known Logto cookies
const logtoSpecificCookies = [
"logto",
"logto.signin",
"logto.session",
"logto.callback",
];
for (const cookieName of logtoSpecificCookies) {
for (const path of paths) {
document.cookie = `${cookieName}=;expires=Thu, 01 Jan 1970 00:00:00 GMT;path=${path}`;
for (const domain of domains) {
if (domain) {
document.cookie = `${cookieName}=;expires=Thu, 01 Jan 1970 00:00:00 GMT;path=${path};domain=${domain}`;
}
}
}
}
};
// Function to create and show a logout confirmation modal
const showLogoutConfirmation = () => {
// Create modal if it doesn't exist
let modal = document.getElementById("logoutConfirmModal");
if (!modal) {
modal = document.createElement("dialog");
modal.id = "logoutConfirmModal";
modal.className = "modal modal-bottom sm:modal-middle";
modal.innerHTML = `
<div class="modal-box">
<h3 class="font-bold text-lg">Confirm Logout</h3>
<p class="py-4">Are you sure you want to log out of your account?</p>
<div class="modal-action">
<button id="cancelLogout" class="btn btn-outline">Cancel</button>
<button id="confirmLogout" class="btn btn-error">
<span id="logoutSpinner" class="loading loading-spinner loading-sm hidden"></span>
<span id="logoutText">Log Out</span>
</button>
</div>
</div>
<form method="dialog" class="modal-backdrop">
<button>Close</button>
</form>
`;
document.body.appendChild(modal);
// Add event listeners
document
.getElementById("cancelLogout")
?.addEventListener("click", () => {
(modal as HTMLDialogElement).close();
});
document
.getElementById("confirmLogout")
?.addEventListener("click", async () => {
// Show loading state
const spinner = document.getElementById("logoutSpinner");
const text = document.getElementById("logoutText");
const confirmBtn = document.getElementById("confirmLogout");
const cancelBtn = document.getElementById("cancelLogout");
if (spinner) spinner.classList.remove("hidden");
if (text) text.textContent = "Logging out...";
if (confirmBtn) confirmBtn.setAttribute("disabled", "true");
if (cancelBtn) cancelBtn.setAttribute("disabled", "true");
try {
// Log the logout action
await logger.send(
"logout",
"auth",
"User logged out from dashboard menu",
);
// Log out from PocketBase using the Authentication class
await auth.logout();
// For extra safety, also directly clear the PocketBase auth store
const pb = auth.getPocketBase();
pb.authStore.clear();
// Delete all cookies to ensure Logto is logged out
deleteAllCookies();
// Specifically target auth.ieeeucsd.org cookies with different approaches
document.cookie =
"logto=;expires=Thu, 01 Jan 1970 00:00:00 GMT;path=/;domain=auth.ieeeucsd.org";
document.cookie =
"logto=;expires=Thu, 01 Jan 1970 00:00:00 GMT;path=/;domain=.ieeeucsd.org";
document.cookie =
"logto=;expires=Thu, 01 Jan 1970 00:00:00 GMT;path=/";
// Direct logout from Logto by redirecting to our API endpoint
// This will handle the Logto session end with proper redirect back to dashboard
window.location.href = "/api/logout";
return; // Stop execution here as we're redirecting
} catch (error) {
console.error("Error during logout:", error);
// Show error message if toast is available
if (window.toast && typeof window.toast === "function") {
window.toast("Failed to log out. Please try again.", {
type: "error",
});
}
// Reset button state
if (spinner) spinner.classList.add("hidden");
if (text) text.textContent = "Log Out";
if (confirmBtn) confirmBtn.removeAttribute("disabled");
if (cancelBtn) cancelBtn.removeAttribute("disabled");
// Close the modal
if (modal) (modal as HTMLDialogElement).close();
}
});
}
// Show the modal
if (modal) (modal as HTMLDialogElement).showModal();
};
// Handle navigation
const handleNavigation = () => {
const navButtons =
document.querySelectorAll(".dashboard-nav-btn");
const sections =
document.querySelectorAll(".dashboard-section");
const navButtons = document.querySelectorAll(".dashboard-nav-btn");
const sections = document.querySelectorAll(".dashboard-section");
const mainContentDiv = document.getElementById("mainContent");
// Ensure mainContent is visible
@ -476,8 +573,7 @@ const components = Object.fromEntries(
// Handle logout button
if (sectionKey === "logout") {
auth.logout();
window.location.reload();
showLogoutConfirmation();
return;
}
@ -496,8 +592,7 @@ const components = Object.fromEntries(
// Show selected section
const sectionId = `${sectionKey}Section`;
const targetSection =
document.getElementById(sectionId);
const targetSection = document.getElementById(sectionId);
if (targetSection) {
targetSection.classList.remove("hidden");
// console.log(`Showing section: ${sectionId}`); // Debug log
@ -507,8 +602,7 @@ const components = Object.fromEntries(
if (window.innerWidth < 1024 && sidebar) {
sidebar.classList.add("-translate-x-full");
document.body.classList.remove("overflow-hidden");
const overlay =
document.getElementById("sidebarOverlay");
const overlay = document.getElementById("sidebarOverlay");
overlay?.remove();
}
});
@ -553,7 +647,7 @@ const components = Object.fromEntries(
"",
{
fields: ["id", "type", "role"],
}
},
);
if (officerRecords && officerRecords.items.length > 0) {
@ -595,7 +689,7 @@ const components = Object.fromEntries(
"",
{
fields: ["id", "company"],
}
},
);
if (sponsorRecords && sponsorRecords.items.length > 0) {
@ -629,8 +723,7 @@ const components = Object.fromEntries(
if (userName) userName.textContent = fallbackValues.name;
if (userRole) userRole.textContent = fallbackValues.role;
if (userInitials)
userInitials.textContent = fallbackValues.initials;
if (userInitials) userInitials.textContent = fallbackValues.initials;
updateSectionVisibility("" as OfficerStatus);
}
@ -638,18 +731,16 @@ const components = Object.fromEntries(
// Mobile sidebar toggle
const mobileSidebarToggle = document.getElementById(
"mobileSidebarToggle"
"mobileSidebarToggle",
);
if (mobileSidebarToggle && sidebar) {
const toggleSidebar = () => {
const isOpen =
!sidebar.classList.contains("-translate-x-full");
const isOpen = !sidebar.classList.contains("-translate-x-full");
if (isOpen) {
sidebar.classList.add("-translate-x-full");
document.body.classList.remove("overflow-hidden");
const overlay =
document.getElementById("sidebarOverlay");
const overlay = document.getElementById("sidebarOverlay");
overlay?.remove();
} else {
sidebar.classList.remove("-translate-x-full");
@ -684,8 +775,7 @@ const components = Object.fromEntries(
window.toast = originalToast;
// console.log("User not authenticated");
if (pageLoadingState)
pageLoadingState.classList.add("hidden");
if (pageLoadingState) pageLoadingState.classList.add("hidden");
if (notAuthenticatedState)
notAuthenticatedState.classList.remove("hidden");
return;
@ -694,30 +784,28 @@ const components = Object.fromEntries(
// Initialize auth sync for IndexedDB (for authenticated users)
await initAuthSync();
if (pageLoadingState)
pageLoadingState.classList.remove("hidden");
if (pageLoadingState) pageLoadingState.classList.remove("hidden");
if (pageErrorState) pageErrorState.classList.add("hidden");
if (notAuthenticatedState)
notAuthenticatedState.classList.add("hidden");
// Show loading states
const userProfileSkeleton = document.getElementById(
"userProfileSkeleton"
"userProfileSkeleton",
);
const userProfileSignedOut = document.getElementById(
"userProfileSignedOut"
"userProfileSignedOut",
);
const userProfileSummary =
document.getElementById("userProfileSummary");
const menuLoadingSkeleton = document.getElementById(
"menuLoadingSkeleton"
"menuLoadingSkeleton",
);
const actualMenu = document.getElementById("actualMenu");
if (userProfileSkeleton)
userProfileSkeleton.classList.remove("hidden");
if (userProfileSummary)
userProfileSummary.classList.add("hidden");
if (userProfileSummary) userProfileSummary.classList.add("hidden");
if (userProfileSignedOut)
userProfileSignedOut.classList.add("hidden");
if (menuLoadingSkeleton)
@ -728,15 +816,11 @@ const components = Object.fromEntries(
await updateUserProfile(user);
// Show actual profile and hide skeleton
if (userProfileSkeleton)
userProfileSkeleton.classList.add("hidden");
if (userProfileSummary)
userProfileSummary.classList.remove("hidden");
if (userProfileSkeleton) userProfileSkeleton.classList.add("hidden");
if (userProfileSummary) userProfileSummary.classList.remove("hidden");
// Hide all sections first
document
.querySelectorAll(".dashboard-section")
.forEach((section) => {
document.querySelectorAll(".dashboard-section").forEach((section) => {
section.classList.add("hidden");
});
@ -753,7 +837,7 @@ const components = Object.fromEntries(
"",
{
fields: ["id", "type", "role"],
}
},
);
if (officerRecords && officerRecords.items.length > 0) {
@ -791,23 +875,17 @@ const components = Object.fromEntries(
"",
{
fields: ["id", "company"],
}
},
);
if (
sponsorRecords &&
sponsorRecords.items.length > 0
) {
if (sponsorRecords && sponsorRecords.items.length > 0) {
officerStatus = "sponsor";
} else {
officerStatus = "none";
}
}
} catch (error) {
console.error(
"Error determining officer status:",
error
);
console.error("Error determining officer status:", error);
officerStatus = "none";
}
@ -818,19 +896,14 @@ const components = Object.fromEntries(
// Only sponsors get a different default view
if (officerStatus === "sponsor") {
// For sponsors, show the sponsor dashboard
defaultSection = document.getElementById(
"sponsorDashboardSection"
);
defaultSection = document.getElementById("sponsorDashboardSection");
defaultButton = document.querySelector(
'[data-section="sponsorDashboard"]'
'[data-section="sponsorDashboard"]',
);
} else {
// For all other users (including administrators), show the profile section
defaultSection =
document.getElementById("profileSection");
defaultButton = document.querySelector(
'[data-section="profile"]'
);
defaultSection = document.getElementById("profileSection");
defaultButton = document.querySelector('[data-section="profile"]');
// Log the default section for debugging
// console.log(`Setting default section to profile for user with role: ${officerStatus}`);
@ -847,20 +920,16 @@ const components = Object.fromEntries(
handleNavigation();
// Show actual menu and hide skeleton
if (menuLoadingSkeleton)
menuLoadingSkeleton.classList.add("hidden");
if (menuLoadingSkeleton) menuLoadingSkeleton.classList.add("hidden");
if (actualMenu) actualMenu.classList.remove("hidden");
// Show main content and hide loading
if (mainContent) mainContent.classList.remove("hidden");
if (pageLoadingState)
pageLoadingState.classList.add("hidden");
if (pageLoadingState) pageLoadingState.classList.add("hidden");
} catch (error) {
console.error("Error initializing dashboard:", error);
if (pageLoadingState)
pageLoadingState.classList.add("hidden");
if (pageErrorState)
pageErrorState.classList.remove("hidden");
if (pageLoadingState) pageLoadingState.classList.add("hidden");
if (pageErrorState) pageErrorState.classList.remove("hidden");
}
};
@ -872,24 +941,19 @@ const components = Object.fromEntries(
.querySelector(".login-button")
?.addEventListener("click", async () => {
try {
if (pageLoadingState)
pageLoadingState.classList.remove("hidden");
if (pageLoadingState) pageLoadingState.classList.remove("hidden");
if (notAuthenticatedState)
notAuthenticatedState.classList.add("hidden");
await auth.login();
} catch (error) {
console.error("Login error:", error);
if (pageLoadingState)
pageLoadingState.classList.add("hidden");
if (pageErrorState)
pageErrorState.classList.remove("hidden");
if (pageLoadingState) pageLoadingState.classList.add("hidden");
if (pageErrorState) pageErrorState.classList.remove("hidden");
}
});
// Handle logout button click
document
.getElementById("logoutButton")
?.addEventListener("click", () => {
document.getElementById("logoutButton")?.addEventListener("click", () => {
auth.logout();
window.location.reload();
});
@ -902,8 +966,7 @@ const components = Object.fromEntries(
window.addEventListener("resize", () => {
if (window.innerWidth >= 1024) {
const overlay =
document.getElementById("sidebarOverlay");
const overlay = document.getElementById("sidebarOverlay");
if (overlay) {
overlay.remove();
document.body.classList.remove("overflow-hidden");