dashboard init
This commit is contained in:
parent
6cbe277c8c
commit
e4f5358b7e
4 changed files with 931 additions and 320 deletions
3
bun.lock
3
bun.lock
|
@ -24,6 +24,7 @@
|
|||
"tailwindcss": "^3.4.16",
|
||||
},
|
||||
"devDependencies": {
|
||||
"@iconify/react": "^5.2.0",
|
||||
"daisyui": "^4.12.23",
|
||||
"prettier": "^3.4.2",
|
||||
"prettier-plugin-astro": "^0.14.1",
|
||||
|
@ -157,6 +158,8 @@
|
|||
|
||||
"@expressive-code/plugin-text-markers": ["@expressive-code/plugin-text-markers@0.38.3", "", { "dependencies": { "@expressive-code/core": "^0.38.3" } }, "sha512-dPK3+BVGTbTmGQGU3Fkj3jZ3OltWUAlxetMHI6limUGCWBCucZiwoZeFM/WmqQa71GyKRzhBT+iEov6kkz2xVA=="],
|
||||
|
||||
"@iconify/react": ["@iconify/react@5.2.0", "", { "dependencies": { "@iconify/types": "^2.0.0" }, "peerDependencies": { "react": ">=16" } }, "sha512-7Sdjrqq3fkkQNks9SY3adGC37NQTHsBJL2PRKlQd455PoDi9s+Es9AUTY+vGLFOYs5yO9w9yCE42pmxCwG26WA=="],
|
||||
|
||||
"@iconify/tools": ["@iconify/tools@4.0.7", "", { "dependencies": { "@iconify/types": "^2.0.0", "@iconify/utils": "^2.1.32", "@types/tar": "^6.1.13", "axios": "^1.7.7", "cheerio": "1.0.0", "domhandler": "^5.0.3", "extract-zip": "^2.0.1", "local-pkg": "^0.5.0", "pathe": "^1.1.2", "svgo": "^3.3.2", "tar": "^6.2.1" } }, "sha512-zOJxKIfZn96ZRGGvIWzDRLD9vb2CsxjcLuM+QIdvwWbv6SWhm49gECzUnd4d2P0sq9sfodT7yCNobWK8nvavxQ=="],
|
||||
|
||||
"@iconify/types": ["@iconify/types@2.0.0", "", {}, "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg=="],
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
"tailwindcss": "^3.4.16"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@iconify/react": "^5.2.0",
|
||||
"daisyui": "^4.12.23",
|
||||
"prettier": "^3.4.2",
|
||||
"prettier-plugin-astro": "^0.14.1",
|
||||
|
|
586
src/pages/dashboard.astro
Normal file
586
src/pages/dashboard.astro
Normal file
|
@ -0,0 +1,586 @@
|
|||
---
|
||||
import yaml from "js-yaml";
|
||||
import profileConfig from "../config/profileConfig.yaml?raw";
|
||||
import textConfig from "../config/text.yml?raw";
|
||||
|
||||
const title = "Dashboard";
|
||||
const config = yaml.load(profileConfig) as any;
|
||||
const text = yaml.load(textConfig) as any;
|
||||
---
|
||||
|
||||
<!doctype html>
|
||||
<html lang="en" data-theme="dark">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>{title} | IEEE UCSD</title>
|
||||
<link rel="icon" type="image/x-icon" href="/favicon.ico" />
|
||||
</head>
|
||||
<body class="bg-base-200">
|
||||
<div class="flex h-screen">
|
||||
<!-- Sidebar -->
|
||||
<aside class="bg-base-100 w-80 flex flex-col shadow-lg">
|
||||
<!-- Logo -->
|
||||
<div class="p-4 border-b border-base-200">
|
||||
<div class="flex items-center gap-2">
|
||||
<img
|
||||
src="/ieee-logo.png"
|
||||
alt="IEEE Logo"
|
||||
class="w-8 h-8"
|
||||
/>
|
||||
<span class="text-xl font-bold">IEEE UCSD</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- User Profile -->
|
||||
<div class="p-4 border-b border-base-200">
|
||||
<div
|
||||
class="flex items-center gap-3"
|
||||
id="userProfileSummary"
|
||||
>
|
||||
<div class="avatar placeholder">
|
||||
<div
|
||||
class="w-12 h-12 rounded-full bg-primary text-primary-content"
|
||||
>
|
||||
<span class="text-xl" id="userInitials">?</span>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="font-medium" id="userName">
|
||||
Loading...
|
||||
</h3>
|
||||
<p class="text-sm opacity-70" id="userRole">
|
||||
Member
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Navigation -->
|
||||
<nav class="flex-1 overflow-y-auto">
|
||||
<ul class="menu p-4 gap-2 text-base-content">
|
||||
<li class="menu-title"><span>Main Menu</span></li>
|
||||
<li>
|
||||
<button
|
||||
class="dashboard-nav-btn active"
|
||||
data-section="profile"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-5 w-5"
|
||||
viewBox="0 0 20 20"
|
||||
fill="currentColor"
|
||||
>
|
||||
<path
|
||||
d="M10.707 2.293a1 1 0 00-1.414 0l-7 7a1 1 0 001.414 1.414L4 10.414V17a1 1 0 001 1h2a1 1 0 001-1v-2a1 1 0 011-1h2a1 1 0 011 1v2a1 1 0 001 1h2a1 1 0 001-1v-6.586l.293.293a1 1 0 001.414-1.414l-7-7z"
|
||||
></path>
|
||||
</svg>
|
||||
Dashboard
|
||||
</button>
|
||||
</li>
|
||||
<li>
|
||||
<button
|
||||
class="dashboard-nav-btn"
|
||||
data-section="events"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-5 w-5"
|
||||
viewBox="0 0 20 20"
|
||||
fill="currentColor"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M6 2a1 1 0 00-1 1v1H4a2 2 0 00-2 2v10a2 2 0 002 2h12a2 2 0 002-2V6a2 2 0 00-2-2h-1V3a1 1 0 10-2 0v1H7V3a1 1 0 00-1-1zm0 5a1 1 0 000 2h8a1 1 0 100-2H6z"
|
||||
clip-rule="evenodd"></path>
|
||||
</svg>
|
||||
Events
|
||||
</button>
|
||||
</li>
|
||||
<li>
|
||||
<button
|
||||
class="dashboard-nav-btn"
|
||||
data-section="reimbursement"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-5 w-5"
|
||||
viewBox="0 0 20 20"
|
||||
fill="currentColor"
|
||||
>
|
||||
<path
|
||||
d="M4 4a2 2 0 00-2 2v4a2 2 0 002 2V6h10a2 2 0 00-2-2H4zm2 6a2 2 0 012-2h8a2 2 0 012 2v4a2 2 0 01-2 2H8a2 2 0 01-2-2v-4zm6 4a2 2 0 100-4 2 2 0 000 4z"
|
||||
></path>
|
||||
</svg>
|
||||
Reimbursement
|
||||
</button>
|
||||
</li>
|
||||
|
||||
<li class="menu-title mt-4"><span>Account</span></li>
|
||||
<li>
|
||||
<button
|
||||
class="dashboard-nav-btn"
|
||||
data-section="settings"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-5 w-5"
|
||||
viewBox="0 0 20 20"
|
||||
fill="currentColor"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M11.49 3.17c-.38-1.56-2.6-1.56-2.98 0a1.532 1.532 0 01-2.286.948c-1.372-.836-2.942.734-2.106 2.106.54.886.061 2.042-.947 2.287-1.561.379-1.561 2.6 0 2.978a1.532 1.532 0 01.947 2.287c-.836 1.372.734 2.942 2.106 2.106a1.532 1.532 0 012.287.947c.379 1.561 2.6 1.561 2.978 0a1.533 1.533 0 012.287-.947c1.372.836 2.942-.734 2.106-2.106a1.533 1.533 0 01.947-2.287c1.561-.379 1.561-2.6 0-2.978a1.532 1.532 0 01-.947-2.287c.836-1.372-.734-2.942-2.106-2.106a1.532 1.532 0 01-2.287-.947zM10 13a3 3 0 100-6 3 3 0 000 6z"
|
||||
clip-rule="evenodd"></path>
|
||||
</svg>
|
||||
Settings
|
||||
</button>
|
||||
</li>
|
||||
<li>
|
||||
<button id="logoutButton" class="text-error">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-5 w-5"
|
||||
viewBox="0 0 20 20"
|
||||
fill="currentColor"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M3 3a1 1 0 00-1 1v12a1 1 0 102 0V4a1 1 0 00-1-1zm10.293 9.293a1 1 0 001.414 1.414l3-3a1 1 0 000-1.414l-3-3a1 1 0 10-1.414 1.414L14.586 9H7a1 1 0 100 2h7.586l-1.293 1.293z"
|
||||
clip-rule="evenodd"></path>
|
||||
</svg>
|
||||
Logout
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</aside>
|
||||
|
||||
<!-- Main Content -->
|
||||
<main class="flex-1 overflow-x-hidden overflow-y-auto bg-base-200">
|
||||
<!-- Mobile Header -->
|
||||
<header class="bg-base-100 p-4 shadow-md lg:hidden">
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex items-center gap-2">
|
||||
<button
|
||||
id="mobileSidebarToggle"
|
||||
class="btn btn-square btn-ghost"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-6 w-6"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M4 6h16M4 12h16M4 18h16"></path>
|
||||
</svg>
|
||||
</button>
|
||||
<h1 class="text-xl font-bold">IEEE UCSD</h1>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<!-- Page Content -->
|
||||
<div class="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-8"
|
||||
>
|
||||
<div class="loading loading-spinner loading-lg">
|
||||
</div>
|
||||
<p class="mt-4 opacity-70">Loading dashboard...</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Error State -->
|
||||
<div id="pageErrorState" class="hidden w-full">
|
||||
<div class="alert alert-error">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-6 w-6"
|
||||
viewBox="0 0 20 20"
|
||||
fill="currentColor"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7 4a1 1 0 11-2 0 1 1 0 012 0zm-1-9a1 1 0 00-1 1v4a1 1 0 102 0V6a1 1 0 00-1-1z"
|
||||
clip-rule="evenodd"></path>
|
||||
</svg>
|
||||
<span>Failed to load dashboard content</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Not Authenticated State -->
|
||||
<div id="notAuthenticatedState" class="hidden w-full">
|
||||
<div class="card bg-base-100 shadow-xl">
|
||||
<div class="card-body items-center text-center">
|
||||
<div class="mb-6">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-16 w-16 opacity-30"
|
||||
viewBox="0 0 20 20"
|
||||
fill="currentColor"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M10 9a3 3 0 100-6 3 3 0 000 6zm-7 9a7 7 0 1114 0H3z"
|
||||
clip-rule="evenodd"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<h2 class="card-title text-2xl mb-2">
|
||||
Sign in to Access Dashboard
|
||||
</h2>
|
||||
<p class="opacity-70 mb-6">
|
||||
Please sign in with your IEEE UCSD account
|
||||
to access the dashboard.
|
||||
</p>
|
||||
<button
|
||||
class="login-button btn btn-primary btn-lg gap-2"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-5 w-5"
|
||||
viewBox="0 0 20 20"
|
||||
fill="currentColor"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M3 3a1 1 0 011 1v12a1 1 0 11-2 0V4a1 1 0 011-1zm7.707 3.293a1 1 0 010 1.414L9.414 9H17a1 1 0 110 2H9.414l1.293 1.293a1 1 0 01-1.414 1.414l-3-3a1 1 0 010-1.414l3-3a1 1 0 011.414 0z"
|
||||
clip-rule="evenodd"></path>
|
||||
</svg>
|
||||
Sign in with IEEEUCSD SSO
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Main Content -->
|
||||
<div id="mainContent" class="hidden">
|
||||
<!-- Dashboard Section -->
|
||||
<div id="profileSection" class="dashboard-section">
|
||||
<div class="mb-6">
|
||||
<h2 class="text-2xl font-bold">
|
||||
Dashboard Overview
|
||||
</h2>
|
||||
<p class="opacity-70">
|
||||
Welcome to your IEEE UCSD dashboard
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Stats Cards -->
|
||||
<div
|
||||
class="grid grid-cols-1 md:grid-cols-3 gap-6 mb-8"
|
||||
>
|
||||
<div class="stats shadow">
|
||||
<div class="stat">
|
||||
<div class="stat-title">
|
||||
Events Attended
|
||||
</div>
|
||||
<div
|
||||
class="stat-value"
|
||||
id="eventsAttendedValue"
|
||||
>
|
||||
0
|
||||
</div>
|
||||
<div class="stat-desc">
|
||||
Since joining
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="stats shadow">
|
||||
<div class="stat">
|
||||
<div class="stat-title">
|
||||
Loyalty Points
|
||||
</div>
|
||||
<div
|
||||
class="stat-value text-primary"
|
||||
id="loyaltyPointsValue"
|
||||
>
|
||||
0
|
||||
</div>
|
||||
<div
|
||||
class="stat-desc"
|
||||
id="loyaltyPointsChange"
|
||||
>
|
||||
No recent activity
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="stats shadow">
|
||||
<div class="stat">
|
||||
<div class="stat-title">
|
||||
Activity Level
|
||||
</div>
|
||||
<div
|
||||
class="stat-value text-secondary"
|
||||
id="activityLevelValue"
|
||||
>
|
||||
Low
|
||||
</div>
|
||||
<div
|
||||
class="stat-desc"
|
||||
id="activityLevelDesc"
|
||||
>
|
||||
New Member
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Dashboard Content -->
|
||||
<div class="card bg-base-100 shadow-xl">
|
||||
<div class="card-body">
|
||||
<h3 class="card-title">Recent Activity</h3>
|
||||
<div class="py-4">
|
||||
<p class="text-base-content/70">
|
||||
No recent activity to display.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Events Section -->
|
||||
<div
|
||||
id="eventsSection"
|
||||
class="dashboard-section hidden"
|
||||
>
|
||||
<div class="mb-6">
|
||||
<h2 class="text-2xl font-bold">Events</h2>
|
||||
<p class="opacity-70">
|
||||
View and manage your IEEE UCSD events
|
||||
</p>
|
||||
</div>
|
||||
<div class="card bg-base-100 shadow-xl">
|
||||
<div class="card-body">
|
||||
<h3 class="card-title">Upcoming Events</h3>
|
||||
<!-- Events content will go here -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Reimbursement Section -->
|
||||
<div
|
||||
id="reimbursementSection"
|
||||
class="dashboard-section hidden"
|
||||
>
|
||||
<div class="mb-6">
|
||||
<h2 class="text-2xl font-bold">
|
||||
Reimbursement
|
||||
</h2>
|
||||
<p class="opacity-70">
|
||||
Manage your reimbursement requests
|
||||
</p>
|
||||
</div>
|
||||
<div class="card bg-base-100 shadow-xl">
|
||||
<div class="card-body">
|
||||
<h3 class="card-title">
|
||||
Reimbursement Requests
|
||||
</h3>
|
||||
<!-- Reimbursement content will go here -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Settings Section -->
|
||||
<div
|
||||
id="settingsSection"
|
||||
class="dashboard-section hidden"
|
||||
>
|
||||
<div class="mb-6">
|
||||
<h2 class="text-2xl font-bold">Settings</h2>
|
||||
<p class="opacity-70">
|
||||
Manage your account settings
|
||||
</p>
|
||||
</div>
|
||||
<div class="card bg-base-100 shadow-xl">
|
||||
<div class="card-body">
|
||||
<h3 class="card-title">Account Settings</h3>
|
||||
<div class="py-4">
|
||||
<p class="text-base-content/70">
|
||||
Account settings will be available
|
||||
soon.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
<script>
|
||||
import { Authentication } from "../components/pocketbase/Authentication";
|
||||
const auth = Authentication.getInstance();
|
||||
|
||||
// Initialize page state
|
||||
const pageLoadingState = document.getElementById("pageLoadingState");
|
||||
const pageErrorState = document.getElementById("pageErrorState");
|
||||
const notAuthenticatedState = document.getElementById(
|
||||
"notAuthenticatedState"
|
||||
);
|
||||
const mainContent = document.getElementById("mainContent");
|
||||
const sidebar = document.querySelector("aside");
|
||||
|
||||
// User profile elements
|
||||
const userInitials = document.getElementById("userInitials");
|
||||
const userName = document.getElementById("userName");
|
||||
const userRole = document.getElementById("userRole");
|
||||
|
||||
// Mobile sidebar toggle
|
||||
const mobileSidebarToggle = document.getElementById("mobileSidebarToggle");
|
||||
if (mobileSidebarToggle && sidebar) {
|
||||
mobileSidebarToggle.addEventListener("click", () => {
|
||||
sidebar.classList.toggle("-translate-x-full");
|
||||
});
|
||||
}
|
||||
|
||||
// Handle navigation
|
||||
const handleNavigation = () => {
|
||||
const navButtons = document.querySelectorAll(".dashboard-nav-btn");
|
||||
const sections = document.querySelectorAll(".dashboard-section");
|
||||
|
||||
navButtons.forEach((button) => {
|
||||
button.addEventListener("click", () => {
|
||||
// Remove active class from all buttons
|
||||
navButtons.forEach((btn) =>
|
||||
btn.classList.remove("active", "bg-base-200")
|
||||
);
|
||||
// Add active class to clicked button
|
||||
button.classList.add("active", "bg-base-200");
|
||||
|
||||
// Hide all sections
|
||||
sections.forEach((section) => section.classList.add("hidden"));
|
||||
// Show selected section
|
||||
const sectionId = `${button.getAttribute("data-section")}Section`;
|
||||
document.getElementById(sectionId)?.classList.remove("hidden");
|
||||
|
||||
// Close sidebar on mobile after selection
|
||||
if (window.innerWidth < 1024 && sidebar) {
|
||||
sidebar.classList.add("-translate-x-full");
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
// Update user profile
|
||||
const updateUserProfile = (user: any) => {
|
||||
if (!user) return;
|
||||
|
||||
if (userName) userName.textContent = user.name || "Unknown User";
|
||||
if (userRole) userRole.textContent = user.role || "Member";
|
||||
if (userInitials) {
|
||||
const initials = (user.name || "U")
|
||||
.split(" ")
|
||||
.map((n: string) => n[0])
|
||||
.join("")
|
||||
.toUpperCase();
|
||||
userInitials.textContent = initials;
|
||||
}
|
||||
};
|
||||
|
||||
// Initialize page
|
||||
const initializePage = async () => {
|
||||
try {
|
||||
if (pageLoadingState) pageLoadingState.classList.remove("hidden");
|
||||
if (pageErrorState) pageErrorState.classList.add("hidden");
|
||||
if (notAuthenticatedState)
|
||||
notAuthenticatedState.classList.add("hidden");
|
||||
if (mainContent) mainContent.classList.add("hidden");
|
||||
|
||||
// Check authentication
|
||||
if (!auth.isAuthenticated()) {
|
||||
if (pageLoadingState) pageLoadingState.classList.add("hidden");
|
||||
if (notAuthenticatedState)
|
||||
notAuthenticatedState.classList.remove("hidden");
|
||||
return;
|
||||
}
|
||||
|
||||
const user = auth.getCurrentUser();
|
||||
updateUserProfile(user);
|
||||
|
||||
// Initialize navigation
|
||||
handleNavigation();
|
||||
|
||||
// Show main content
|
||||
if (mainContent) mainContent.classList.remove("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");
|
||||
}
|
||||
};
|
||||
|
||||
// Initialize when DOM is loaded
|
||||
document.addEventListener("DOMContentLoaded", initializePage);
|
||||
|
||||
// Handle login button click
|
||||
document
|
||||
.querySelector(".login-button")
|
||||
?.addEventListener("click", async () => {
|
||||
try {
|
||||
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");
|
||||
}
|
||||
});
|
||||
|
||||
// Handle logout button click
|
||||
document.getElementById("logoutButton")?.addEventListener("click", () => {
|
||||
auth.logout();
|
||||
window.location.reload();
|
||||
});
|
||||
|
||||
// Handle responsive sidebar
|
||||
if (sidebar) {
|
||||
// Hide sidebar by default on mobile
|
||||
if (window.innerWidth < 1024) {
|
||||
sidebar.classList.add("-translate-x-full");
|
||||
}
|
||||
|
||||
// Add transition class
|
||||
sidebar.classList.add(
|
||||
"transition-transform",
|
||||
"duration-300",
|
||||
"ease-in-out",
|
||||
"lg:translate-x-0",
|
||||
"fixed",
|
||||
"lg:relative",
|
||||
"h-full",
|
||||
"z-50"
|
||||
);
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.dashboard-nav-btn.active {
|
||||
@apply bg-base-200 font-medium;
|
||||
}
|
||||
|
||||
/* Hide scrollbar for Chrome, Safari and Opera */
|
||||
.overflow-y-auto::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Hide scrollbar for IE, Edge and Firefox */
|
||||
.overflow-y-auto {
|
||||
-ms-overflow-style: none; /* IE and Edge */
|
||||
scrollbar-width: none; /* Firefox */
|
||||
}
|
||||
</style>
|
|
@ -15,358 +15,379 @@ const text = yaml.load(textConfig) as any;
|
|||
---
|
||||
|
||||
<Layout {title}>
|
||||
<main class="min-h-screen bg-base-100/50 rounded-[1.5rem]">
|
||||
<div class="container mx-auto px-6 py-6 mt-10">
|
||||
<!-- Header Section with Breadcrumbs -->
|
||||
<div class="mb-8">
|
||||
<h1 class="text-4xl font-bold">Profile Dashboard</h1>
|
||||
<p class="text-base-content/70 mt-2">
|
||||
Manage your IEEE UCSD membership and activities
|
||||
</p>
|
||||
</div>
|
||||
<main class="min-h-screen bg-base-100/50 rounded-[1.5rem]">
|
||||
<div class="container mx-auto px-6 py-6 mt-10">
|
||||
<!-- Header Section with Breadcrumbs -->
|
||||
<div class="mb-8">
|
||||
<h1 class="text-4xl font-bold">Profile Dashboard</h1>
|
||||
<p class="text-base-content/70 mt-2">
|
||||
Manage your IEEE UCSD membership and activities
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Loading State -->
|
||||
<div id="pageLoadingState" class="w-full">
|
||||
<div class="flex flex-col items-center justify-center p-8">
|
||||
<div class="loading loading-spinner loading-lg"></div>
|
||||
<p class="mt-4 text-base-content/70">Loading your profile...</p>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Loading State -->
|
||||
<div id="pageLoadingState" class="w-full">
|
||||
<div class="flex flex-col items-center justify-center p-8">
|
||||
<div class="loading loading-spinner loading-lg"></div>
|
||||
<p class="mt-4 text-base-content/70">
|
||||
Loading your profile...
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Error State -->
|
||||
<div id="pageErrorState" class="hidden w-full">
|
||||
<div class="alert alert-error">
|
||||
<div class="flex items-center gap-2">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-6 w-6"
|
||||
viewBox="0 0 20 20"
|
||||
fill="currentColor"
|
||||
<!-- Error State -->
|
||||
<div id="pageErrorState" class="hidden w-full">
|
||||
<div class="alert alert-error">
|
||||
<div class="flex items-center gap-2">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-6 w-6"
|
||||
viewBox="0 0 20 20"
|
||||
fill="currentColor"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7 4a1 1 0 11-2 0 1 1 0 012 0zm-1-9a1 1 0 00-1 1v4a1 1 0 102 0V6a1 1 0 00-1-1z"
|
||||
clip-rule="evenodd"></path>
|
||||
</svg>
|
||||
<span>{text.ui.messages.auth.loginError}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Not Authenticated State -->
|
||||
<div id="notAuthenticatedState" class="hidden w-full">
|
||||
<div class="card bg-base-100 shadow-xl">
|
||||
<div class="card-body items-center text-center">
|
||||
<div class="mb-6">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-16 w-16 text-base-content/30"
|
||||
viewBox="0 0 20 20"
|
||||
fill="currentColor"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M10 9a3 3 0 100-6 3 3 0 000 6zm-7 9a7 7 0 1114 0H3z"
|
||||
clip-rule="evenodd"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<h2 class="card-title text-2xl mb-2">
|
||||
Sign in to Access Your Profile
|
||||
</h2>
|
||||
<p class="text-base-content/70 mb-6">
|
||||
Please sign in with your IEEE UCSD account to view
|
||||
and manage your profile.
|
||||
</p>
|
||||
<button
|
||||
class="login-button btn btn-primary btn-lg gap-2"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-5 w-5"
|
||||
viewBox="0 0 20 20"
|
||||
fill="currentColor"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M3 3a1 1 0 011 1v12a1 1 0 11-2 0V4a1 1 0 011-1zm7.707 3.293a1 1 0 010 1.414L9.414 9H17a1 1 0 110 2H9.414l1.293 1.293a1 1 0 01-1.414 1.414l-3-3a1 1 0 010-1.414l3-3a1 1 0 011.414 0z"
|
||||
clip-rule="evenodd"></path>
|
||||
</svg>
|
||||
Sign in with IEEEUCSD SSO
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Main Content Grid -->
|
||||
<div
|
||||
id="mainContent"
|
||||
class="hidden grid grid-cols-1 xl:grid-cols-12 gap-8"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7 4a1 1 0 11-2 0 1 1 0 012 0zm-1-9a1 1 0 00-1 1v4a1 1 0 102 0V6a1 1 0 00-1-1z"
|
||||
clip-rule="evenodd"></path>
|
||||
</svg>
|
||||
<span>{text.ui.messages.auth.loginError}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Left Column - User Info -->
|
||||
<div class="xl:col-span-4 2xl:col-span-3">
|
||||
<div class="sticky top-[100px]">
|
||||
<UserProfile />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Not Authenticated State -->
|
||||
<div id="notAuthenticatedState" class="hidden w-full">
|
||||
<div class="card bg-base-100 shadow-xl">
|
||||
<div class="card-body items-center text-center">
|
||||
<div class="mb-6">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-16 w-16 text-base-content/30"
|
||||
viewBox="0 0 20 20"
|
||||
fill="currentColor"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M10 9a3 3 0 100-6 3 3 0 000 6zm-7 9a7 7 0 1114 0H3z"
|
||||
clip-rule="evenodd"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<h2 class="card-title text-2xl mb-2">
|
||||
Sign in to Access Your Profile
|
||||
</h2>
|
||||
<p class="text-base-content/70 mb-6">
|
||||
Please sign in with your IEEE UCSD account to view and manage your
|
||||
profile.
|
||||
</p>
|
||||
<button class="login-button btn btn-primary btn-lg gap-2">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-5 w-5"
|
||||
viewBox="0 0 20 20"
|
||||
fill="currentColor"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M3 3a1 1 0 011 1v12a1 1 0 11-2 0V4a1 1 0 011-1zm7.707 3.293a1 1 0 010 1.414L9.414 9H17a1 1 0 110 2H9.414l1.293 1.293a1 1 0 01-1.414 1.414l-3-3a1 1 0 010-1.414l3-3a1 1 0 011.414 0z"
|
||||
clip-rule="evenodd"></path>
|
||||
</svg>
|
||||
Sign in with IEEEUCSD SSO
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Right Column - Content -->
|
||||
<div class="xl:col-span-8 2xl:col-span-9">
|
||||
<!-- Stats Overview -->
|
||||
<div class="stats shadow w-full mb-8 bg-base-100">
|
||||
<div class="stat">
|
||||
<div class="stat-figure text-primary">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-8 w-8"
|
||||
viewBox="0 0 20 20"
|
||||
fill="currentColor"
|
||||
>
|
||||
<path
|
||||
d="M13 6a3 3 0 11-6 0 3 3 0 016 0zM18 8a2 2 0 11-4 0 2 2 0 014 0zM14 15a4 4 0 00-8 0v3h8v-3zM6 8a2 2 0 11-4 0 2 2 0 014 0zM16 18v-3a5.972 5.972 0 00-.75-2.906A3.005 3.005 0 0119 15v3h-3zM4.75 12.094A5.973 5.973 0 004 15v3H1v-3a3 3 0 013.75-2.906z"
|
||||
></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="stat-title">Events Attended</div>
|
||||
<div
|
||||
class="stat-value text-primary"
|
||||
id="eventsAttendedValue"
|
||||
>
|
||||
-
|
||||
</div>
|
||||
<div class="stat-desc">Since joining</div>
|
||||
</div>
|
||||
|
||||
<!-- Main Content Grid -->
|
||||
<div
|
||||
id="mainContent"
|
||||
class="hidden grid grid-cols-1 xl:grid-cols-12 gap-8"
|
||||
>
|
||||
<!-- Left Column - User Info -->
|
||||
<div class="xl:col-span-4 2xl:col-span-3">
|
||||
<div class="sticky top-[100px]">
|
||||
<UserProfile />
|
||||
</div>
|
||||
</div>
|
||||
<div class="stat">
|
||||
<div class="stat-figure text-secondary">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-8 w-8"
|
||||
viewBox="0 0 20 20"
|
||||
fill="currentColor"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M6.267 3.455a3.066 3.066 0 001.745-.723 3.066 3.066 0 013.976 0 3.066 3.066 0 001.745.723 3.066 3.066 0 012.812 2.812c.051.643.304 1.254.723 1.745a3.066 3.066 0 010 3.976 3.066 3.066 0 00-.723 1.745 3.066 3.066 0 01-2.812 2.812 3.066 3.066 0 00-1.745.723 3.066 3.066 0 01-3.976 0 3.066 3.066 0 00-1.745-.723 3.066 3.066 0 01-2.812-2.812 3.066 3.066 0 00-.723-1.745 3.066 3.066 0 010-3.976 3.066 3.066 0 00.723-1.745 3.066 3.066 0 012.812-2.812zm7.44 5.252a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z"
|
||||
clip-rule="evenodd"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="stat-title">Loyalty Points</div>
|
||||
<div
|
||||
class="stat-value text-secondary"
|
||||
id="loyaltyPointsValue"
|
||||
>
|
||||
-
|
||||
</div>
|
||||
<div class="stat-desc" id="loyaltyPointsChange">
|
||||
Loading...
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Right Column - Content -->
|
||||
<div class="xl:col-span-8 2xl:col-span-9">
|
||||
<!-- Stats Overview -->
|
||||
<div class="stats shadow w-full mb-8 bg-base-100">
|
||||
<div class="stat">
|
||||
<div class="stat-figure text-primary">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-8 w-8"
|
||||
viewBox="0 0 20 20"
|
||||
fill="currentColor"
|
||||
>
|
||||
<path
|
||||
d="M13 6a3 3 0 11-6 0 3 3 0 016 0zM18 8a2 2 0 11-4 0 2 2 0 014 0zM14 15a4 4 0 00-8 0v3h8v-3zM6 8a2 2 0 11-4 0 2 2 0 014 0zM16 18v-3a5.972 5.972 0 00-.75-2.906A3.005 3.005 0 0119 15v3h-3zM4.75 12.094A5.973 5.973 0 004 15v3H1v-3a3 3 0 013.75-2.906z"
|
||||
></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="stat-title">Events Attended</div>
|
||||
<div class="stat-value text-primary" id="eventsAttendedValue">
|
||||
-
|
||||
</div>
|
||||
<div class="stat-desc">Since joining</div>
|
||||
</div>
|
||||
<div class="stat">
|
||||
<div class="stat-figure text-accent">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-8 w-8"
|
||||
viewBox="0 0 20 20"
|
||||
fill="currentColor"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M5 3a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2V5a2 2 0 00-2-2H5zm9 4a1 1 0 10-2 0v6a1 1 0 102 0V7zm-3 2a1 1 0 10-2 0v4a1 1 0 102 0V9zm-3 3a1 1 0 10-2 0v1a1 1 0 102 0v-1z"
|
||||
clip-rule="evenodd"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="stat-title">Activity Level</div>
|
||||
<div
|
||||
class="stat-value text-accent"
|
||||
id="activityLevelValue"
|
||||
>
|
||||
-
|
||||
</div>
|
||||
<div class="stat-desc" id="activityLevelDesc">
|
||||
Loading...
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="stat">
|
||||
<div class="stat-figure text-secondary">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-8 w-8"
|
||||
viewBox="0 0 20 20"
|
||||
fill="currentColor"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M6.267 3.455a3.066 3.066 0 001.745-.723 3.066 3.066 0 013.976 0 3.066 3.066 0 001.745.723 3.066 3.066 0 012.812 2.812c.051.643.304 1.254.723 1.745a3.066 3.066 0 010 3.976 3.066 3.066 0 00-.723 1.745 3.066 3.066 0 01-2.812 2.812 3.066 3.066 0 00-1.745.723 3.066 3.066 0 01-3.976 0 3.066 3.066 0 00-1.745-.723 3.066 3.066 0 01-2.812-2.812 3.066 3.066 0 00-.723-1.745 3.066 3.066 0 010-3.976 3.066 3.066 0 00.723-1.745 3.066 3.066 0 012.812-2.812zm7.44 5.252a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z"
|
||||
clip-rule="evenodd"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="stat-title">Loyalty Points</div>
|
||||
<div class="stat-value text-secondary" id="loyaltyPointsValue">
|
||||
-
|
||||
</div>
|
||||
<div class="stat-desc" id="loyaltyPointsChange">Loading...</div>
|
||||
</div>
|
||||
<!-- Main Content Tabs -->
|
||||
<div class="tabs tabs-boxed mb-6" id="defaultViewTabs">
|
||||
<button class="tab tab-active" data-default-tab="events"
|
||||
>Events & Activities</button
|
||||
>
|
||||
<button class="tab" data-default-tab="settings"
|
||||
>Settings</button
|
||||
>
|
||||
</div>
|
||||
|
||||
<div class="stat">
|
||||
<div class="stat-figure text-accent">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-8 w-8"
|
||||
viewBox="0 0 20 20"
|
||||
fill="currentColor"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M5 3a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2V5a2 2 0 00-2-2H5zm9 4a1 1 0 10-2 0v6a1 1 0 102 0V7zm-3 2a1 1 0 10-2 0v4a1 1 0 102 0V9zm-3 3a1 1 0 10-2 0v1a1 1 0 102 0v-1z"
|
||||
clip-rule="evenodd"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="stat-title">Activity Level</div>
|
||||
<div class="stat-value text-accent" id="activityLevelValue">
|
||||
-
|
||||
</div>
|
||||
<div class="stat-desc" id="activityLevelDesc">Loading...</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Main Content Tabs -->
|
||||
<div class="tabs tabs-boxed mb-6" id="defaultViewTabs">
|
||||
<button class="tab tab-active" data-default-tab="events"
|
||||
>Events & Activities</button
|
||||
>
|
||||
<button class="tab" data-default-tab="settings">Settings</button>
|
||||
</div>
|
||||
|
||||
<!-- Content Areas -->
|
||||
<div id="defaultView">
|
||||
<DefaultProfileView />
|
||||
</div>
|
||||
<div id="settingsView" class="hidden">
|
||||
<UserSettings />
|
||||
</div>
|
||||
<!--<div id="officerView" class="hidden">
|
||||
<!-- Content Areas -->
|
||||
<div id="defaultView">
|
||||
<DefaultProfileView />
|
||||
</div>
|
||||
<div id="settingsView" class="hidden">
|
||||
<UserSettings />
|
||||
</div>
|
||||
<!--<div id="officerView" class="hidden">
|
||||
<OfficerProfileView />
|
||||
</div> -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Add FileViewerModal here, outside of the tab content -->
|
||||
<FileViewerModal client:load />
|
||||
</main>
|
||||
<!-- Add FileViewerModal here, outside of the tab content -->
|
||||
<FileViewerModal client:load />
|
||||
</main>
|
||||
</Layout>
|
||||
|
||||
<script>
|
||||
import { Authentication } from "../../components/pocketbase/Authentication";
|
||||
import yaml from "js-yaml";
|
||||
import profileConfig from "../../config/profileConfig.yaml?raw";
|
||||
import textConfig from "../../config/text.yml?raw";
|
||||
import { Authentication } from "../../components/pocketbase/Authentication";
|
||||
import yaml from "js-yaml";
|
||||
import profileConfig from "../../config/profileConfig.yaml?raw";
|
||||
import textConfig from "../../config/text.yml?raw";
|
||||
|
||||
const config = yaml.load(profileConfig) as any;
|
||||
const text = yaml.load(textConfig) as any;
|
||||
const auth = Authentication.getInstance();
|
||||
const config = yaml.load(profileConfig) as any;
|
||||
const text = yaml.load(textConfig) as any;
|
||||
const auth = Authentication.getInstance();
|
||||
|
||||
// Initialize page state
|
||||
const pageLoadingState = document.getElementById("pageLoadingState");
|
||||
const pageErrorState = document.getElementById("pageErrorState");
|
||||
const notAuthenticatedState = document.getElementById(
|
||||
"notAuthenticatedState",
|
||||
);
|
||||
const mainContent = document.getElementById("mainContent");
|
||||
const defaultView = document.getElementById("defaultView");
|
||||
const officerView = document.getElementById("officerView");
|
||||
const settingsView = document.getElementById("settingsView");
|
||||
|
||||
// Stats elements
|
||||
const eventsAttendedValue = document.getElementById("eventsAttendedValue");
|
||||
const loyaltyPointsValue = document.getElementById("loyaltyPointsValue");
|
||||
const loyaltyPointsChange = document.getElementById("loyaltyPointsChange");
|
||||
const activityLevelValue = document.getElementById("activityLevelValue");
|
||||
const activityLevelDesc = document.getElementById("activityLevelDesc");
|
||||
|
||||
// Show officer view if user has appropriate role
|
||||
const showOfficerView = (user: any) => {
|
||||
if (!user) return false;
|
||||
const userRole = user.role || "member";
|
||||
const roleConfig = config.roles[userRole];
|
||||
return (
|
||||
roleConfig?.permissions?.includes("manage") ||
|
||||
roleConfig?.permissions?.includes("edit")
|
||||
// Initialize page state
|
||||
const pageLoadingState = document.getElementById("pageLoadingState");
|
||||
const pageErrorState = document.getElementById("pageErrorState");
|
||||
const notAuthenticatedState = document.getElementById(
|
||||
"notAuthenticatedState"
|
||||
);
|
||||
};
|
||||
const mainContent = document.getElementById("mainContent");
|
||||
const defaultView = document.getElementById("defaultView");
|
||||
const officerView = document.getElementById("officerView");
|
||||
const settingsView = document.getElementById("settingsView");
|
||||
|
||||
// Initialize page
|
||||
const initializePage = async () => {
|
||||
try {
|
||||
// Show loading state
|
||||
if (pageLoadingState) pageLoadingState.classList.remove("hidden");
|
||||
if (pageErrorState) pageErrorState.classList.add("hidden");
|
||||
if (notAuthenticatedState) notAuthenticatedState.classList.add("hidden");
|
||||
if (mainContent) mainContent.classList.add("hidden");
|
||||
// Stats elements
|
||||
const eventsAttendedValue = document.getElementById("eventsAttendedValue");
|
||||
const loyaltyPointsValue = document.getElementById("loyaltyPointsValue");
|
||||
const loyaltyPointsChange = document.getElementById("loyaltyPointsChange");
|
||||
const activityLevelValue = document.getElementById("activityLevelValue");
|
||||
const activityLevelDesc = document.getElementById("activityLevelDesc");
|
||||
|
||||
// Check auth state
|
||||
if (!auth.isAuthenticated()) {
|
||||
if (pageLoadingState) pageLoadingState.classList.add("hidden");
|
||||
if (notAuthenticatedState)
|
||||
notAuthenticatedState.classList.remove("hidden");
|
||||
return;
|
||||
}
|
||||
// Show officer view if user has appropriate role
|
||||
const showOfficerView = (user: any) => {
|
||||
if (!user) return false;
|
||||
const userRole = user.role || "member";
|
||||
const roleConfig = config.roles[userRole];
|
||||
return (
|
||||
roleConfig?.permissions?.includes("manage") ||
|
||||
roleConfig?.permissions?.includes("edit")
|
||||
);
|
||||
};
|
||||
|
||||
const user = auth.getCurrentUser();
|
||||
// Initialize page
|
||||
const initializePage = async () => {
|
||||
try {
|
||||
// Show loading state
|
||||
if (pageLoadingState) pageLoadingState.classList.remove("hidden");
|
||||
if (pageErrorState) pageErrorState.classList.add("hidden");
|
||||
if (notAuthenticatedState)
|
||||
notAuthenticatedState.classList.add("hidden");
|
||||
if (mainContent) mainContent.classList.add("hidden");
|
||||
|
||||
// Update stats
|
||||
if (eventsAttendedValue) {
|
||||
const eventsAttended = user.events_attended?.length || 0;
|
||||
eventsAttendedValue.textContent = eventsAttended.toString();
|
||||
}
|
||||
// Check auth state
|
||||
if (!auth.isAuthenticated()) {
|
||||
if (pageLoadingState) pageLoadingState.classList.add("hidden");
|
||||
if (notAuthenticatedState)
|
||||
notAuthenticatedState.classList.remove("hidden");
|
||||
return;
|
||||
}
|
||||
|
||||
if (loyaltyPointsValue && loyaltyPointsChange) {
|
||||
const points = user.points || 0;
|
||||
loyaltyPointsValue.textContent = points.toString();
|
||||
const pointsChange = user.points_change_30d || 0;
|
||||
loyaltyPointsChange.textContent =
|
||||
pointsChange >= 0
|
||||
? `↗︎ ${pointsChange} points (30 days)`
|
||||
: `↘︎ ${Math.abs(pointsChange)} points (30 days)`;
|
||||
}
|
||||
const user = auth.getCurrentUser();
|
||||
|
||||
if (activityLevelValue && activityLevelDesc) {
|
||||
const eventsAttended = user.events_attended?.length || 0;
|
||||
const points = user.points || 0;
|
||||
let activityLevel = "Low";
|
||||
let description = "Occasional Member";
|
||||
// Update stats
|
||||
if (eventsAttendedValue) {
|
||||
const eventsAttended = user.events_attended?.length || 0;
|
||||
eventsAttendedValue.textContent = eventsAttended.toString();
|
||||
}
|
||||
|
||||
if (eventsAttended > 5 || points > 50) {
|
||||
activityLevel = "High";
|
||||
description = "Active Member";
|
||||
} else if (eventsAttended > 2 || points > 20) {
|
||||
activityLevel = "Medium";
|
||||
description = "Regular Member";
|
||||
if (loyaltyPointsValue && loyaltyPointsChange) {
|
||||
const points = user.points || 0;
|
||||
loyaltyPointsValue.textContent = points.toString();
|
||||
const pointsChange = user.points_change_30d || 0;
|
||||
loyaltyPointsChange.textContent =
|
||||
pointsChange >= 0
|
||||
? `↗︎ ${pointsChange} points (30 days)`
|
||||
: `↘︎ ${Math.abs(pointsChange)} points (30 days)`;
|
||||
}
|
||||
|
||||
if (activityLevelValue && activityLevelDesc) {
|
||||
const eventsAttended = user.events_attended?.length || 0;
|
||||
const points = user.points || 0;
|
||||
let activityLevel = "Low";
|
||||
let description = "Occasional Member";
|
||||
|
||||
if (eventsAttended > 5 || points > 50) {
|
||||
activityLevel = "High";
|
||||
description = "Active Member";
|
||||
} else if (eventsAttended > 2 || points > 20) {
|
||||
activityLevel = "Medium";
|
||||
description = "Regular Member";
|
||||
}
|
||||
|
||||
activityLevelValue.textContent = activityLevel;
|
||||
activityLevelDesc.textContent = description;
|
||||
}
|
||||
|
||||
// Show appropriate view based on user role
|
||||
if (showOfficerView(user)) {
|
||||
if (officerView) officerView.classList.remove("hidden");
|
||||
if (defaultView) defaultView.classList.add("hidden");
|
||||
} else {
|
||||
if (officerView) officerView.classList.add("hidden");
|
||||
if (defaultView) defaultView.classList.remove("hidden");
|
||||
}
|
||||
|
||||
// Hide loading state and show content
|
||||
if (pageLoadingState) pageLoadingState.classList.add("hidden");
|
||||
if (mainContent) mainContent.classList.remove("hidden");
|
||||
} catch (error) {
|
||||
console.error("Failed to initialize page:", error);
|
||||
if (pageLoadingState) pageLoadingState.classList.add("hidden");
|
||||
if (pageErrorState) pageErrorState.classList.remove("hidden");
|
||||
if (mainContent) mainContent.classList.add("hidden");
|
||||
}
|
||||
};
|
||||
|
||||
activityLevelValue.textContent = activityLevel;
|
||||
activityLevelDesc.textContent = description;
|
||||
}
|
||||
|
||||
// Show appropriate view based on user role
|
||||
if (showOfficerView(user)) {
|
||||
if (officerView) officerView.classList.remove("hidden");
|
||||
if (defaultView) defaultView.classList.add("hidden");
|
||||
} else {
|
||||
if (officerView) officerView.classList.add("hidden");
|
||||
if (defaultView) defaultView.classList.remove("hidden");
|
||||
}
|
||||
|
||||
// Hide loading state and show content
|
||||
if (pageLoadingState) pageLoadingState.classList.add("hidden");
|
||||
if (mainContent) mainContent.classList.remove("hidden");
|
||||
} catch (error) {
|
||||
console.error("Failed to initialize page:", error);
|
||||
if (pageLoadingState) pageLoadingState.classList.add("hidden");
|
||||
if (pageErrorState) pageErrorState.classList.remove("hidden");
|
||||
if (mainContent) mainContent.classList.add("hidden");
|
||||
}
|
||||
};
|
||||
|
||||
// Check on load and auth changes
|
||||
initializePage();
|
||||
auth.onAuthStateChange(() => {
|
||||
// Check on load and auth changes
|
||||
initializePage();
|
||||
});
|
||||
|
||||
// Handle default view tab switching
|
||||
const defaultViewTabs = document.querySelectorAll("[data-default-tab]");
|
||||
defaultViewTabs.forEach((tab) => {
|
||||
tab.addEventListener("click", () => {
|
||||
// Update tab styles
|
||||
defaultViewTabs.forEach((t) => t.classList.remove("tab-active"));
|
||||
tab.classList.add("tab-active");
|
||||
|
||||
// Update content visibility
|
||||
const tabId = (tab as HTMLElement).dataset.defaultTab;
|
||||
const views = {
|
||||
events: defaultView,
|
||||
settings: settingsView,
|
||||
};
|
||||
|
||||
// Hide all views first
|
||||
Object.values(views).forEach((view) => {
|
||||
if (view) view.classList.add("hidden");
|
||||
});
|
||||
|
||||
// Show the selected view
|
||||
const selectedView = views[tabId as keyof typeof views];
|
||||
if (selectedView) {
|
||||
selectedView.classList.remove("hidden");
|
||||
}
|
||||
auth.onAuthStateChange(() => {
|
||||
initializePage();
|
||||
});
|
||||
});
|
||||
|
||||
// Add login button event listener
|
||||
const loginButtons = document.querySelectorAll(".login-button");
|
||||
loginButtons.forEach((button) => {
|
||||
button.addEventListener("click", async () => {
|
||||
try {
|
||||
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");
|
||||
}
|
||||
// Handle default view tab switching
|
||||
const defaultViewTabs = document.querySelectorAll("[data-default-tab]");
|
||||
defaultViewTabs.forEach((tab) => {
|
||||
tab.addEventListener("click", () => {
|
||||
// Update tab styles
|
||||
defaultViewTabs.forEach((t) => t.classList.remove("tab-active"));
|
||||
tab.classList.add("tab-active");
|
||||
|
||||
// Update content visibility
|
||||
const tabId = (tab as HTMLElement).dataset.defaultTab;
|
||||
const views = {
|
||||
events: defaultView,
|
||||
settings: settingsView,
|
||||
};
|
||||
|
||||
// Hide all views first
|
||||
Object.values(views).forEach((view) => {
|
||||
if (view) view.classList.add("hidden");
|
||||
});
|
||||
|
||||
// Show the selected view
|
||||
const selectedView = views[tabId as keyof typeof views];
|
||||
if (selectedView) {
|
||||
selectedView.classList.remove("hidden");
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Add login button event listener
|
||||
const loginButtons = document.querySelectorAll(".login-button");
|
||||
loginButtons.forEach((button) => {
|
||||
button.addEventListener("click", async () => {
|
||||
try {
|
||||
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");
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.hidden {
|
||||
display: none !important;
|
||||
}
|
||||
.hidden {
|
||||
display: none !important;
|
||||
}
|
||||
</style>
|
||||
|
|
Loading…
Reference in a new issue