add dynamic view
This commit is contained in:
parent
b5cdc7464b
commit
45b278a2fc
5 changed files with 392 additions and 258 deletions
|
@ -7,79 +7,104 @@ import EventLoad from "./EventsSection/EventLoad";
|
|||
---
|
||||
|
||||
<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 class="mb-4 sm:mb-6 px-4 sm:px-6">
|
||||
<h2 class="text-xl sm:text-2xl font-bold">Events</h2>
|
||||
<p class="opacity-70 text-sm sm:text-base">
|
||||
View and manage your IEEE UCSD events
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6 mb-6">
|
||||
<div
|
||||
class="grid grid-cols-1 md:grid-cols-2 gap-4 sm:gap-6 mb-4 sm:mb-6 px-4 sm:px-6"
|
||||
>
|
||||
<!-- Event Check-in Card -->
|
||||
<div class="w-full">
|
||||
<EventCheckIn client:load />
|
||||
</div>
|
||||
|
||||
<!-- Event Registration Card -->
|
||||
<div class="w-full">
|
||||
<div
|
||||
class="card bg-base-100 shadow-xl border border-base-200 opacity-50 cursor-not-allowed relative group"
|
||||
class="card bg-base-100 shadow-xl border border-base-200 opacity-50 cursor-not-allowed relative group h-full"
|
||||
>
|
||||
<div
|
||||
class="absolute inset-0 bg-base-100 opacity-0 group-hover:opacity-90 transition-opacity duration-300 flex items-center justify-center z-10"
|
||||
>
|
||||
<span class="text-base-content font-medium">Coming Soon</span>
|
||||
<span
|
||||
class="text-base-content font-medium text-sm sm:text-base"
|
||||
>Coming Soon</span
|
||||
>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<h3 class="card-title text-lg mb-4">Event Registration</h3>
|
||||
<div class="card-body p-4 sm:p-6">
|
||||
<h3 class="card-title text-base sm:text-lg mb-3 sm:mb-4">
|
||||
Event Registration
|
||||
</h3>
|
||||
<div class="form-control w-full">
|
||||
<label class="label">
|
||||
<span class="label-text"
|
||||
<span class="label-text text-sm sm:text-base"
|
||||
>Select an event to register</span
|
||||
>
|
||||
</label>
|
||||
<div class="flex gap-2">
|
||||
<select class="select select-bordered flex-1" disabled>
|
||||
<option disabled selected>Pick an event</option>
|
||||
<option>Technical Workshop - Web Development</option
|
||||
<div class="flex flex-col sm:flex-row gap-2">
|
||||
<select
|
||||
class="select select-bordered flex-1 text-sm sm:text-base h-10 min-h-[2.5rem] w-full"
|
||||
disabled
|
||||
>
|
||||
<option disabled selected>Pick an event</option>
|
||||
<option
|
||||
>Technical Workshop - Web Development</option
|
||||
>
|
||||
<option
|
||||
>Professional Development Workshop</option
|
||||
>
|
||||
<option>Professional Development Workshop</option>
|
||||
<option>Social Event - Game Night</option>
|
||||
</select>
|
||||
<button class="btn btn-primary" disabled
|
||||
>Register</button
|
||||
<button
|
||||
class="btn btn-primary text-sm sm:text-base h-10 min-h-[2.5rem] w-full sm:w-[100px]"
|
||||
disabled>Register</button
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<EventLoad client:load />
|
||||
</div>
|
||||
|
||||
<!-- Event Details Modal -->
|
||||
<dialog id="eventDetailsModal" class="modal">
|
||||
<div class="modal-box max-w-4xl">
|
||||
<div class="flex justify-between items-center mb-4">
|
||||
<div class="flex items-center gap-3">
|
||||
<h3 class="font-bold text-lg" id="modalTitle">Event Files</h3>
|
||||
<div class="modal-box max-w-[90vw] sm:max-w-4xl p-4 sm:p-6">
|
||||
<div class="flex justify-between items-center mb-3 sm:mb-4">
|
||||
<div class="flex items-center gap-2 sm:gap-3">
|
||||
<h3 class="font-bold text-base sm:text-lg" id="modalTitle">
|
||||
Event Files
|
||||
</h3>
|
||||
<button
|
||||
id="downloadAllBtn"
|
||||
class="btn btn-primary btn-sm gap-1"
|
||||
class="btn btn-primary btn-sm gap-1 text-xs sm:text-sm"
|
||||
onclick="window.downloadAllFiles()"
|
||||
>
|
||||
<Icon
|
||||
icon="heroicons:arrow-down-tray-20-solid"
|
||||
className="h-4 w-4"
|
||||
className="h-3 w-3 sm:h-4 sm:w-4"
|
||||
/>
|
||||
Download All
|
||||
</button>
|
||||
</div>
|
||||
<button
|
||||
class="btn btn-circle btn-ghost"
|
||||
class="btn btn-circle btn-ghost btn-sm sm:btn-md"
|
||||
onclick="window.closeEventDetailsModal()"
|
||||
>
|
||||
<Icon icon="heroicons:x-mark" className="h-6 w-6" />
|
||||
<Icon
|
||||
icon="heroicons:x-mark"
|
||||
className="h-4 w-4 sm:h-6 sm:w-6"
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div id="filesContent" class="space-y-4">
|
||||
<div id="filesContent" class="space-y-3 sm:space-y-4">
|
||||
<!-- Files list will be populated here -->
|
||||
</div>
|
||||
</div>
|
||||
|
@ -90,14 +115,17 @@ import EventLoad from "./EventsSection/EventLoad";
|
|||
|
||||
<!-- Universal File Preview Modal -->
|
||||
<dialog id="filePreviewModal" class="modal">
|
||||
<div class="modal-box max-w-4xl">
|
||||
<div class="flex justify-between items-center mb-4">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="modal-box max-w-[90vw] sm:max-w-4xl p-4 sm:p-6">
|
||||
<div class="flex justify-between items-center mb-3 sm:mb-4">
|
||||
<div class="flex items-center gap-2 sm:gap-3">
|
||||
<button
|
||||
class="btn btn-ghost btn-sm"
|
||||
class="btn btn-ghost btn-sm text-xs sm:text-sm"
|
||||
onclick="window.closeFilePreviewEvents()">Close</button
|
||||
>
|
||||
<h3 class="font-bold text-lg truncate" id="previewFileName">
|
||||
<h3
|
||||
class="font-bold text-base sm:text-lg truncate"
|
||||
id="previewFileName"
|
||||
>
|
||||
</h3>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -106,7 +134,8 @@ import EventLoad from "./EventsSection/EventLoad";
|
|||
id="previewLoadingSpinner"
|
||||
class="absolute inset-0 flex items-center justify-center bg-base-200 bg-opacity-50 hidden"
|
||||
>
|
||||
<span class="loading loading-spinner loading-lg"></span>
|
||||
<span class="loading loading-spinner loading-md sm:loading-lg"
|
||||
></span>
|
||||
</div>
|
||||
<div id="previewContent" class="w-full">
|
||||
<FilePreview client:load isModal={true} />
|
||||
|
|
|
@ -240,12 +240,12 @@ const EventCheckIn = () => {
|
|||
|
||||
return (
|
||||
<>
|
||||
<div className="card bg-base-100 shadow-xl border border-base-200">
|
||||
<div className="card-body">
|
||||
<h3 className="card-title text-lg mb-4">Event Check-in</h3>
|
||||
<div className="card bg-base-100 shadow-xl border border-base-200 h-full">
|
||||
<div className="card-body p-4 sm:p-6">
|
||||
<h3 className="card-title text-base sm:text-lg mb-3 sm:mb-4">Event Check-in</h3>
|
||||
<div className="form-control w-full">
|
||||
<label className="label">
|
||||
<span className="label-text">Enter event code to check in</span>
|
||||
<span className="label-text text-sm sm:text-base">Enter event code to check in</span>
|
||||
</label>
|
||||
<form onSubmit={(e) => {
|
||||
e.preventDefault();
|
||||
|
@ -260,11 +260,11 @@ const EventCheckIn = () => {
|
|||
createToast("Please enter an event code", "warning");
|
||||
}
|
||||
}}>
|
||||
<div className="flex gap-2">
|
||||
<div className="flex flex-col sm:flex-row gap-2">
|
||||
<input
|
||||
type="password"
|
||||
placeholder="Enter code"
|
||||
className="input input-bordered flex-1"
|
||||
className="input input-bordered flex-1 text-sm sm:text-base h-10 min-h-[2.5rem] w-full"
|
||||
onKeyPress={(e) => {
|
||||
if (e.key === "Enter") {
|
||||
e.preventDefault();
|
||||
|
@ -273,7 +273,7 @@ const EventCheckIn = () => {
|
|||
/>
|
||||
<button
|
||||
type="submit"
|
||||
className={`btn btn-primary min-w-[90px] ${isLoading ? "loading" : ""}`}
|
||||
className={`btn btn-primary h-10 min-h-[2.5rem] text-sm sm:text-base w-full sm:w-auto ${isLoading ? "loading" : ""}`}
|
||||
disabled={isLoading}
|
||||
>
|
||||
{isLoading ? (
|
||||
|
@ -289,35 +289,35 @@ const EventCheckIn = () => {
|
|||
</div>
|
||||
|
||||
<dialog id="foodSelectionModal" className="modal">
|
||||
<div className="modal-box">
|
||||
<h3 className="font-bold text-lg mb-4">Food Selection</h3>
|
||||
<form onSubmit={handleSubmit} className="space-y-4">
|
||||
<div className="modal-box max-w-[90vw] sm:max-w-lg p-4 sm:p-6">
|
||||
<h3 className="font-bold text-base sm:text-lg mb-3 sm:mb-4">Food Selection</h3>
|
||||
<form onSubmit={handleSubmit} className="space-y-3 sm:space-y-4">
|
||||
<div className="form-control">
|
||||
<label className="label">
|
||||
<span className="label-text">What food would you like?</span>
|
||||
<span className="label-text text-sm sm:text-base">What food would you like?</span>
|
||||
<span className="label-text-alt text-error">*</span>
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
value={foodInput}
|
||||
onChange={(e) => setFoodInput(e.target.value)}
|
||||
className="input input-bordered"
|
||||
className="input input-bordered text-sm sm:text-base h-10 min-h-[2.5rem] w-full"
|
||||
placeholder="Enter your food choice or 'none'"
|
||||
required
|
||||
/>
|
||||
<label className="label">
|
||||
<span className="label-text-alt text-info">
|
||||
<span className="label-text-alt text-info text-xs sm:text-sm">
|
||||
Enter 'none' if you don't want any food
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
<div className="modal-action">
|
||||
<button type="submit" className="btn btn-primary">
|
||||
<div className="modal-action flex flex-col sm:flex-row gap-2 sm:gap-3">
|
||||
<button type="submit" className="btn btn-primary text-sm sm:text-base h-10 min-h-[2.5rem] w-full sm:w-auto">
|
||||
Submit
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className="btn"
|
||||
className="btn text-sm sm:text-base h-10 min-h-[2.5rem] w-full sm:w-auto"
|
||||
onClick={() => {
|
||||
const modal = document.getElementById("foodSelectionModal") as HTMLDialogElement;
|
||||
modal.close();
|
||||
|
|
|
@ -88,24 +88,20 @@ const EventLoad = () => {
|
|||
|
||||
return (
|
||||
<div key={event.id} className="card bg-base-200 shadow-lg hover:shadow-xl transition-all duration-300 relative overflow-hidden">
|
||||
<div className="card-body p-5">
|
||||
<div className="card-body p-3 sm:p-4">
|
||||
<div className="flex flex-col h-full">
|
||||
<div className="flex items-start justify-between gap-3 mb-2">
|
||||
<div className="flex flex-col gap-2">
|
||||
<div className="flex-1">
|
||||
<h3 className="card-title text-lg font-semibold mb-1 line-clamp-2">{event.event_name}</h3>
|
||||
<div className="flex items-center gap-2 text-sm text-base-content/70">
|
||||
<h3 className="card-title text-base sm:text-lg font-semibold mb-1 line-clamp-2">{event.event_name}</h3>
|
||||
<div className="flex flex-wrap items-center gap-2 text-xs sm:text-sm text-base-content/70">
|
||||
<div className="badge badge-primary badge-sm">{event.points_to_reward} pts</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="text-right shrink-0 text-base-content/80">
|
||||
<div className="text-sm font-medium">
|
||||
<div className="text-xs sm:text-sm opacity-75">
|
||||
{startDate.toLocaleDateString("en-US", {
|
||||
weekday: "short",
|
||||
month: "short",
|
||||
day: "numeric",
|
||||
})}
|
||||
</div>
|
||||
<div className="text-xs mt-0.5 opacity-75">
|
||||
{" • "}
|
||||
{startDate.toLocaleTimeString("en-US", {
|
||||
hour: "numeric",
|
||||
minute: "2-digit",
|
||||
|
@ -113,27 +109,28 @@ const EventLoad = () => {
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="text-sm text-base-content/70 mb-3 line-clamp-2">
|
||||
<div className="text-xs sm:text-sm text-base-content/70 my-2 line-clamp-2">
|
||||
{event.description || "No description available"}
|
||||
</div>
|
||||
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center gap-2 text-base-content/80">
|
||||
<Icon icon="mdi:map-marker" className="w-4 h-4 text-primary shrink-0" />
|
||||
<span className="text-sm">{event.location}</span>
|
||||
</div>
|
||||
{isPastEvent && event.files && event.files.length > 0 && (
|
||||
<div className="flex flex-wrap items-center gap-2 mt-auto pt-2">
|
||||
{event.files && event.files.length > 0 && (
|
||||
<button
|
||||
onClick={() => window.openDetailsModal(event)}
|
||||
className="btn btn-sm btn-primary w-[90px] inline-flex items-center justify-center"
|
||||
className="btn btn-ghost btn-sm text-xs sm:text-sm gap-1 h-8 min-h-0 px-2"
|
||||
>
|
||||
<div className="flex items-center gap-1">
|
||||
<Icon icon="mdi:file-document-outline" className="w-4 h-4" />
|
||||
<span>Files</span>
|
||||
</div>
|
||||
<Icon icon="heroicons:document-duplicate" className="h-3 w-3 sm:h-4 sm:w-4" />
|
||||
Files ({event.files.length})
|
||||
</button>
|
||||
)}
|
||||
{isPastEvent && (
|
||||
<div className="badge badge-ghost text-xs">Past Event</div>
|
||||
)}
|
||||
<div className="text-xs sm:text-sm opacity-75 ml-auto">
|
||||
{event.location}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -147,7 +144,11 @@ const EventLoad = () => {
|
|||
const allEvents = await get.getAll<Event>(
|
||||
"events",
|
||||
"published = true",
|
||||
"-start_date"
|
||||
"-start_date",
|
||||
{
|
||||
fields: ["*"],
|
||||
disableAutoCancellation: true
|
||||
}
|
||||
);
|
||||
|
||||
// Split events into upcoming, ongoing, and past based on start and end dates
|
||||
|
@ -202,7 +203,11 @@ const EventLoad = () => {
|
|||
ongoing.sort((a, b) => new Date(a.end_date).getTime() - new Date(b.end_date).getTime());
|
||||
past.sort((a, b) => new Date(b.end_date).getTime() - new Date(a.end_date).getTime());
|
||||
|
||||
setEvents({ upcoming, ongoing, past });
|
||||
setEvents({
|
||||
upcoming: upcoming.slice(0, 50), // Limit to 50 events per section
|
||||
ongoing: ongoing.slice(0, 50),
|
||||
past: past.slice(0, 50)
|
||||
});
|
||||
setLoading(false);
|
||||
} catch (error) {
|
||||
console.error("Failed to load events:", error);
|
||||
|
@ -214,10 +219,10 @@ const EventLoad = () => {
|
|||
return (
|
||||
<>
|
||||
{/* Ongoing Events */}
|
||||
<div className="card bg-base-100 shadow-xl border border-base-200 hover:border-primary transition-all duration-300 hover:-translate-y-1 transform mb-6">
|
||||
<div className="card-body">
|
||||
<h3 className="card-title mb-4">Ongoing Events</h3>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||
<div className="card bg-base-100 shadow-xl border border-base-200 hover:border-primary transition-all duration-300 hover:-translate-y-1 transform mb-4 sm:mb-6 mx-4 sm:mx-6">
|
||||
<div className="card-body p-4 sm:p-6">
|
||||
<h3 className="card-title text-base sm:text-lg mb-3 sm:mb-4">Ongoing Events</h3>
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4 sm:gap-6">
|
||||
{[...Array(3)].map((_, i) => (
|
||||
<div key={`ongoing-skeleton-${i}`}>{createSkeletonCard()}</div>
|
||||
))}
|
||||
|
@ -226,10 +231,10 @@ const EventLoad = () => {
|
|||
</div>
|
||||
|
||||
{/* Upcoming Events */}
|
||||
<div className="card bg-base-100 shadow-xl border border-base-200 hover:border-primary transition-all duration-300 hover:-translate-y-1 transform mb-6">
|
||||
<div className="card-body">
|
||||
<h3 className="card-title mb-4">Upcoming Events</h3>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||
<div className="card bg-base-100 shadow-xl border border-base-200 hover:border-primary transition-all duration-300 hover:-translate-y-1 transform mb-4 sm:mb-6 mx-4 sm:mx-6">
|
||||
<div className="card-body p-4 sm:p-6">
|
||||
<h3 className="card-title text-base sm:text-lg mb-3 sm:mb-4">Upcoming Events</h3>
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4 sm:gap-6">
|
||||
{[...Array(3)].map((_, i) => (
|
||||
<div key={`upcoming-skeleton-${i}`}>{createSkeletonCard()}</div>
|
||||
))}
|
||||
|
@ -238,10 +243,10 @@ const EventLoad = () => {
|
|||
</div>
|
||||
|
||||
{/* Past Events */}
|
||||
<div className="card bg-base-100 shadow-xl border border-base-200 hover:border-primary transition-all duration-300 hover:-translate-y-1 transform">
|
||||
<div className="card-body">
|
||||
<h3 className="card-title mb-4">Past Events</h3>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||
<div className="card bg-base-100 shadow-xl border border-base-200 hover:border-primary transition-all duration-300 hover:-translate-y-1 transform mx-4 sm:mx-6">
|
||||
<div className="card-body p-4 sm:p-6">
|
||||
<h3 className="card-title text-base sm:text-lg mb-3 sm:mb-4">Past Events</h3>
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4 sm:gap-6">
|
||||
{[...Array(3)].map((_, i) => (
|
||||
<div key={`past-skeleton-${i}`}>{createSkeletonCard()}</div>
|
||||
))}
|
||||
|
@ -256,10 +261,10 @@ const EventLoad = () => {
|
|||
<>
|
||||
{/* Ongoing Events */}
|
||||
{events.ongoing.length > 0 && (
|
||||
<div className="card bg-base-100 shadow-xl border border-base-200 hover:border-primary transition-all duration-300 hover:-translate-y-1 transform mb-6">
|
||||
<div className="card-body">
|
||||
<h3 className="card-title mb-4">Ongoing Events</h3>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||
<div className="card bg-base-100 shadow-xl border border-base-200 hover:border-primary transition-all duration-300 hover:-translate-y-1 transform mb-4 sm:mb-6 mx-4 sm:mx-6">
|
||||
<div className="card-body p-4 sm:p-6">
|
||||
<h3 className="card-title text-base sm:text-lg mb-3 sm:mb-4">Ongoing Events</h3>
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4 sm:gap-6">
|
||||
{events.ongoing.map(renderEventCard)}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -268,10 +273,10 @@ const EventLoad = () => {
|
|||
|
||||
{/* Upcoming Events */}
|
||||
{events.upcoming.length > 0 && (
|
||||
<div className="card bg-base-100 shadow-xl border border-base-200 hover:border-primary transition-all duration-300 hover:-translate-y-1 transform mb-6">
|
||||
<div className="card-body">
|
||||
<h3 className="card-title mb-4">Upcoming Events</h3>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||
<div className="card bg-base-100 shadow-xl border border-base-200 hover:border-primary transition-all duration-300 hover:-translate-y-1 transform mb-4 sm:mb-6 mx-4 sm:mx-6">
|
||||
<div className="card-body p-4 sm:p-6">
|
||||
<h3 className="card-title text-base sm:text-lg mb-3 sm:mb-4">Upcoming Events</h3>
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4 sm:gap-6">
|
||||
{events.upcoming.map(renderEventCard)}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -280,10 +285,10 @@ const EventLoad = () => {
|
|||
|
||||
{/* Past Events */}
|
||||
{events.past.length > 0 && (
|
||||
<div className="card bg-base-100 shadow-xl border border-base-200 hover:border-primary transition-all duration-300 hover:-translate-y-1 transform">
|
||||
<div className="card-body">
|
||||
<h3 className="card-title mb-4">Past Events</h3>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||
<div className="card bg-base-100 shadow-xl border border-base-200 hover:border-primary transition-all duration-300 hover:-translate-y-1 transform mx-4 sm:mx-6">
|
||||
<div className="card-body p-4 sm:p-6">
|
||||
<h3 className="card-title text-base sm:text-lg mb-3 sm:mb-4">Past Events</h3>
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4 sm:gap-6">
|
||||
{events.past.map(renderEventCard)}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -71,23 +71,36 @@ const currentPage = eventResponse.page;
|
|||
---
|
||||
|
||||
<div id="eventManagementSection" class="dashboard-section hidden">
|
||||
<div class="mb-6 flex justify-between items-center">
|
||||
<div
|
||||
class="mb-4 md:mb-6 flex flex-col md:flex-row md:justify-between md:items-center gap-2"
|
||||
>
|
||||
<div>
|
||||
<h2 class="text-2xl font-bold">Event Management</h2>
|
||||
<p class="opacity-70">Manage and create IEEE UCSD events</p>
|
||||
<h2 class="text-xl md:text-2xl font-bold">Event Management</h2>
|
||||
<p class="text-sm md:text-base opacity-70">
|
||||
Manage and create IEEE UCSD events
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Stats Cards -->
|
||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-6 mb-8">
|
||||
<div
|
||||
class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-4 md:gap-6 mb-6 md:mb-8"
|
||||
>
|
||||
<div
|
||||
class="stats shadow-lg bg-base-100 rounded-2xl border border-base-200 hover:border-primary transition-all duration-300 hover:-translate-y-1 transform"
|
||||
>
|
||||
<div class="stat">
|
||||
<div class="stat-title font-medium opacity-80">
|
||||
<div class="stat p-4 md:p-6">
|
||||
<div
|
||||
class="stat-title text-sm md:text-base font-medium opacity-80"
|
||||
>
|
||||
Total Events
|
||||
</div>
|
||||
<div class="stat-value text-primary" id="totalEvents">-</div>
|
||||
<div
|
||||
class="stat-value text-primary text-2xl md:text-3xl"
|
||||
id="totalEvents"
|
||||
>
|
||||
-
|
||||
</div>
|
||||
<div class="stat-desc flex items-center gap-2 mt-1">
|
||||
<div class="badge badge-primary badge-sm" id="quarterLabel">
|
||||
Current Academic Term
|
||||
|
@ -98,11 +111,16 @@ const currentPage = eventResponse.page;
|
|||
<div
|
||||
class="stats shadow-lg bg-base-100 rounded-2xl border border-base-200 hover:border-secondary transition-all duration-300 hover:-translate-y-1 transform"
|
||||
>
|
||||
<div class="stat">
|
||||
<div class="stat-title font-medium opacity-80">
|
||||
<div class="stat p-4 md:p-6">
|
||||
<div
|
||||
class="stat-title text-sm md:text-base font-medium opacity-80"
|
||||
>
|
||||
Unique Attendees
|
||||
</div>
|
||||
<div class="stat-value text-secondary" id="uniqueAttendees">
|
||||
<div
|
||||
class="stat-value text-secondary text-2xl md:text-3xl"
|
||||
id="uniqueAttendees"
|
||||
>
|
||||
-
|
||||
</div>
|
||||
<div class="stat-desc flex items-center gap-2 mt-1">
|
||||
|
@ -113,13 +131,18 @@ const currentPage = eventResponse.page;
|
|||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="stats shadow-lg bg-base-100 rounded-2xl border border-base-200 hover:border-accent transition-all duration-300 hover:-translate-y-1 transform"
|
||||
class="stats shadow-lg bg-base-100 rounded-2xl border border-base-200 hover:border-accent transition-all duration-300 hover:-translate-y-1 transform sm:col-span-2 md:col-span-1"
|
||||
>
|
||||
<div class="stat p-4 md:p-6">
|
||||
<div
|
||||
class="stat-title text-sm md:text-base font-medium opacity-80"
|
||||
>
|
||||
<div class="stat">
|
||||
<div class="stat-title font-medium opacity-80">
|
||||
Recurring Attendees
|
||||
</div>
|
||||
<div class="stat-value text-accent" id="recurringAttendees">
|
||||
<div
|
||||
class="stat-value text-accent text-2xl md:text-3xl"
|
||||
id="recurringAttendees"
|
||||
>
|
||||
-
|
||||
</div>
|
||||
<div class="stat-desc flex items-center gap-2 mt-1">
|
||||
|
@ -135,39 +158,50 @@ const currentPage = eventResponse.page;
|
|||
<div
|
||||
class="card bg-base-100 shadow-lg border border-base-200 hover:border-primary transition-all duration-300"
|
||||
>
|
||||
<div class="card-body">
|
||||
<h3 class="card-title text-xl font-bold flex items-center gap-3">
|
||||
<div class="card-body p-4 md:p-6">
|
||||
<h3
|
||||
class="card-title text-lg md:text-xl font-bold flex flex-col md:flex-row md:items-center gap-3"
|
||||
>
|
||||
<div class="flex items-center gap-2">
|
||||
<div class="badge badge-primary p-3">
|
||||
<Icon name="heroicons:calendar" class="h-5 w-5" />
|
||||
</div>
|
||||
Events List
|
||||
<div class="ml-auto justify-end flex gap-2">
|
||||
</div>
|
||||
<div class="flex-1 flex flex-wrap gap-2 md:justify-end">
|
||||
<button
|
||||
class="btn btn-ghost gap-2"
|
||||
class="btn btn-ghost btn-sm md:btn-md gap-2"
|
||||
onclick="window.refreshEvents()"
|
||||
>
|
||||
<Icon name="heroicons:arrow-path" class="h-5 w-5" />
|
||||
<Icon
|
||||
name="heroicons:arrow-path"
|
||||
class="h-4 w-4 md:h-5 md:w-5"
|
||||
/>
|
||||
Refresh
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-primary gap-2"
|
||||
class="btn btn-primary btn-sm md:btn-md gap-2"
|
||||
onclick="window.openEditModal()"
|
||||
>
|
||||
<Icon name="heroicons:plus" class="h-5 w-5" />
|
||||
<Icon
|
||||
name="heroicons:plus"
|
||||
class="h-4 w-4 md:h-5 md:w-5"
|
||||
/>
|
||||
Add New Event
|
||||
</button>
|
||||
</div>
|
||||
</h3>
|
||||
|
||||
<div class="divider"></div>
|
||||
<div class="divider my-2 md:my-4"></div>
|
||||
|
||||
<!-- Filter Controls -->
|
||||
<div class="mb-4">
|
||||
<!-- All Filters in One Line -->
|
||||
<div class="flex flex-wrap items-end gap-4">
|
||||
<div class="form-control">
|
||||
<!-- All Filters -->
|
||||
<div class="flex flex-wrap gap-4">
|
||||
<div class="form-control w-full sm:w-auto">
|
||||
<label class="label">
|
||||
<span class="label-text font-medium"
|
||||
<span
|
||||
class="label-text text-sm md:text-base font-medium"
|
||||
>Time Filter</span
|
||||
>
|
||||
</label>
|
||||
|
@ -176,7 +210,7 @@ const currentPage = eventResponse.page;
|
|||
type="radio"
|
||||
name="timeFilter"
|
||||
value="all"
|
||||
class="join-item btn btn-sm"
|
||||
class="join-item btn btn-xs md:btn-sm"
|
||||
checked
|
||||
aria-label="All Events"
|
||||
/>
|
||||
|
@ -184,29 +218,33 @@ const currentPage = eventResponse.page;
|
|||
type="radio"
|
||||
name="timeFilter"
|
||||
value="ongoing"
|
||||
class="join-item btn btn-sm"
|
||||
class="join-item btn btn-xs md:btn-sm"
|
||||
aria-label="Ongoing"
|
||||
/>
|
||||
<input
|
||||
type="radio"
|
||||
name="timeFilter"
|
||||
value="upcoming"
|
||||
class="join-item btn btn-sm"
|
||||
class="join-item btn btn-xs md:btn-sm"
|
||||
aria-label="Upcoming"
|
||||
/>
|
||||
<input
|
||||
type="radio"
|
||||
name="timeFilter"
|
||||
value="past"
|
||||
class="join-item btn btn-sm"
|
||||
class="join-item btn btn-xs md:btn-sm"
|
||||
aria-label="Past"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-control">
|
||||
<!-- Other filters with similar responsive adjustments -->
|
||||
<div class="form-control w-full sm:w-auto">
|
||||
<label class="label">
|
||||
<span class="label-text font-medium">Year</span>
|
||||
<span
|
||||
class="label-text text-sm md:text-base font-medium"
|
||||
>Year</span
|
||||
>
|
||||
</label>
|
||||
<div class="dropdown">
|
||||
<label
|
||||
|
@ -251,9 +289,12 @@ const currentPage = eventResponse.page;
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-control">
|
||||
<div class="form-control w-full sm:w-auto">
|
||||
<label class="label">
|
||||
<span class="label-text font-medium">Quarter</span>
|
||||
<span
|
||||
class="label-text text-sm md:text-base font-medium"
|
||||
>Quarter</span
|
||||
>
|
||||
</label>
|
||||
<div class="dropdown">
|
||||
<label
|
||||
|
@ -278,8 +319,8 @@ const currentPage = eventResponse.page;
|
|||
</svg>
|
||||
</label>
|
||||
<div
|
||||
tabindex="0"
|
||||
id="quarterDropdownContent"
|
||||
tabindex="0"
|
||||
class="dropdown-content z-[1] menu p-2 shadow bg-base-100 rounded-box w-52"
|
||||
>
|
||||
<div class="form-control">
|
||||
|
@ -339,9 +380,11 @@ const currentPage = eventResponse.page;
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-control">
|
||||
<div class="form-control w-full sm:w-auto">
|
||||
<label class="label">
|
||||
<span class="label-text font-medium">Published</span
|
||||
<span
|
||||
class="label-text text-sm md:text-base font-medium"
|
||||
>Published</span
|
||||
>
|
||||
</label>
|
||||
<div class="dropdown">
|
||||
|
@ -404,9 +447,11 @@ const currentPage = eventResponse.page;
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-control">
|
||||
<div class="form-control w-full sm:w-auto">
|
||||
<label class="label">
|
||||
<span class="label-text font-medium">Has Files</span
|
||||
<span
|
||||
class="label-text text-sm md:text-base font-medium"
|
||||
>Has Files</span
|
||||
>
|
||||
</label>
|
||||
<div class="dropdown">
|
||||
|
@ -469,9 +514,12 @@ const currentPage = eventResponse.page;
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-control">
|
||||
<div class="form-control w-full sm:w-auto">
|
||||
<label class="label">
|
||||
<span class="label-text font-medium">Has Food</span>
|
||||
<span
|
||||
class="label-text text-sm md:text-base font-medium"
|
||||
>Has Food</span
|
||||
>
|
||||
</label>
|
||||
<div class="dropdown">
|
||||
<label
|
||||
|
@ -536,7 +584,7 @@ const currentPage = eventResponse.page;
|
|||
</div>
|
||||
|
||||
<!-- Search and Per Page Controls -->
|
||||
<div class="flex flex-col md:flex-row gap-4 mb-4">
|
||||
<div class="flex flex-col sm:flex-row gap-4 mb-4">
|
||||
<div class="form-control flex-1">
|
||||
<div class="join w-full">
|
||||
<div
|
||||
|
@ -544,7 +592,7 @@ const currentPage = eventResponse.page;
|
|||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-5 w-5 opacity-70"
|
||||
class="h-4 w-4 md:h-5 md:w-5 opacity-70"
|
||||
viewBox="0 0 20 20"
|
||||
fill="currentColor"
|
||||
>
|
||||
|
@ -558,20 +606,20 @@ const currentPage = eventResponse.page;
|
|||
type="text"
|
||||
id="searchInput"
|
||||
placeholder="Search events..."
|
||||
class="input input-bordered join-item w-full"
|
||||
class="input input-bordered join-item w-full text-sm md:text-base"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-control w-full md:w-auto">
|
||||
<div class="form-control w-full sm:w-auto">
|
||||
<div class="join">
|
||||
<div
|
||||
class="join-item bg-base-200 flex items-center px-3"
|
||||
class="join-item bg-base-200 flex items-center px-3 text-sm md:text-base"
|
||||
>
|
||||
Per Page
|
||||
</div>
|
||||
<select
|
||||
id="perPageSelect"
|
||||
class="select select-bordered join-item"
|
||||
class="select select-bordered join-item text-sm md:text-base"
|
||||
>
|
||||
<option value="5">5</option>
|
||||
<option value="10">10</option>
|
||||
|
@ -583,33 +631,34 @@ const currentPage = eventResponse.page;
|
|||
</div>
|
||||
|
||||
<!-- Event Items -->
|
||||
<div class="space-y-4" id="eventsList">
|
||||
<div class="text-center py-8 text-base-content/70">
|
||||
<Icon
|
||||
name="heroicons:calendar"
|
||||
class="h-12 w-12 mx-auto mb-4 opacity-50"
|
||||
/>
|
||||
<p>Loading events...</p>
|
||||
</div>
|
||||
<div class="space-y-3 md:space-y-4" id="eventsList">
|
||||
<!-- Event items will be populated here with responsive classes -->
|
||||
</div>
|
||||
|
||||
<!-- Pagination -->
|
||||
<div class="flex justify-center mt-6" id="paginationContainer">
|
||||
<div
|
||||
class="flex justify-center mt-4 md:mt-6"
|
||||
id="paginationContainer"
|
||||
>
|
||||
<div class="join">
|
||||
<button class="join-item btn btn-sm" id="firstPageBtn"
|
||||
>«</button
|
||||
<button
|
||||
class="join-item btn btn-xs md:btn-sm"
|
||||
id="firstPageBtn">«</button
|
||||
>
|
||||
<button class="join-item btn btn-sm" id="prevPageBtn"
|
||||
>‹</button
|
||||
<button
|
||||
class="join-item btn btn-xs md:btn-sm"
|
||||
id="prevPageBtn">‹</button
|
||||
>
|
||||
<button class="join-item btn btn-sm"
|
||||
<button class="join-item btn btn-xs md:btn-sm"
|
||||
>Page <span id="currentPageNumber">1</span></button
|
||||
>
|
||||
<button class="join-item btn btn-sm" id="nextPageBtn"
|
||||
>›</button
|
||||
<button
|
||||
class="join-item btn btn-xs md:btn-sm"
|
||||
id="nextPageBtn">›</button
|
||||
>
|
||||
<button class="join-item btn btn-sm" id="lastPageBtn"
|
||||
>»</button
|
||||
<button
|
||||
class="join-item btn btn-xs md:btn-sm"
|
||||
id="lastPageBtn">»</button
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1188,37 +1237,37 @@ const currentPage = eventResponse.page;
|
|||
window[eventDataId] = event;
|
||||
|
||||
return `
|
||||
<div class="flex items-center justify-between p-4 bg-base-200 rounded-xl hover:bg-base-300 transition-all duration-300">
|
||||
<div class="flex items-center gap-4">
|
||||
<div class="flex flex-col sm:flex-row sm:items-center justify-between p-3 md:p-4 bg-base-200 rounded-xl hover:bg-base-300 transition-all duration-300 gap-3">
|
||||
<div class="flex items-start sm:items-center gap-3 md:gap-4">
|
||||
<div class="badge badge-lg p-3 badge-primary">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 md:h-5 md:w-5" viewBox="0 0 20 20" fill="currentColor">
|
||||
<path d="M10 2a6 6 0 00-6 6v3.586l-.707.707A1 1 0 004 14h12a1 1 0 00.707-1.707L16 11.586V8a6 6 0 00-6-6zM10 18a3 3 0 01-3-3h6a3 3 0 01-3 3z" />
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h4 class="font-semibold">${event.event_name}</h4>
|
||||
<p class="text-sm opacity-70">${dateStr}${detailsStr ? ` • ${detailsStr}` : ""}</p>
|
||||
<div class="min-w-0">
|
||||
<h4 class="font-semibold text-sm md:text-base truncate">${event.event_name}</h4>
|
||||
<p class="text-xs md:text-sm opacity-70 truncate">${dateStr}${detailsStr ? ` • ${detailsStr}` : ""}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<button class="btn btn-ghost btn-sm" onclick="window.openDetailsModal(window['${eventDataId}'])">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<div class="flex flex-wrap gap-2 justify-end">
|
||||
<button class="btn btn-ghost btn-xs md:btn-sm" onclick="window.openDetailsModal(window['${eventDataId}'])">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 md:h-5 md:w-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" />
|
||||
<polyline points="14 2 14 8 20 8" />
|
||||
</svg>
|
||||
</button>
|
||||
<button class="btn btn-ghost btn-sm" onclick="window.openAttendeesModal(window['${eventDataId}'])">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
|
||||
<button class="btn btn-ghost btn-xs md:btn-sm" onclick="window.openAttendeesModal(window['${eventDataId}'])">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 md:h-5 md:w-5" 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" />
|
||||
</svg>
|
||||
</button>
|
||||
<button class="btn btn-ghost btn-sm" onclick="window.openEditModal(window['${eventDataId}'])">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
|
||||
<button class="btn btn-ghost btn-xs md:btn-sm" onclick="window.openEditModal(window['${eventDataId}'])">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 md:h-5 md:w-5" viewBox="0 0 20 20" fill="currentColor">
|
||||
<path d="M13.586 3.586a2 2 0 112.828 2.828l-.793.793-2.828-2.828.793-.793zM11.379 5.793L3 14.172V17h2.828l8.38-8.379-2.83-2.828z" />
|
||||
</svg>
|
||||
</button>
|
||||
<button class="btn btn-ghost btn-sm text-error" onclick="window.deleteEvent('${event.id}', '${event.event_name.replace(/'/g, "\\'")}')">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
|
||||
<button class="btn btn-ghost btn-xs md:btn-sm text-error" onclick="window.deleteEvent('${event.id}', '${event.event_name.replace(/'/g, "\\'")}')">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 md:h-5 md:w-5" viewBox="0 0 20 20" fill="currentColor">
|
||||
<path fill-rule="evenodd" d="M9 2a1 1 0 00-.894.553L7.382 4H4a1 1 0 000 2v10a2 2 0 002 2h8a2 2 0 002-2V6a1 1 0 100-2h-3.382l-.724-1.447A1 1 0 0011 2H9zM7 8a1 1 0 012 0v6a1 1 0 11-2 0V8zm5-1a1 1 0 00-1 1v6a1 1 0 102 0V8a1 1 0 00-1-1z" clip-rule="evenodd" />
|
||||
</svg>
|
||||
</button>
|
||||
|
|
|
@ -21,7 +21,7 @@ const title = "Dashboard";
|
|||
<div class="flex h-screen">
|
||||
<!-- Sidebar -->
|
||||
<aside
|
||||
class="bg-base-100 w-80 flex flex-col shadow-xl border-r border-base-200 transition-all duration-300"
|
||||
class="bg-base-100 w-80 flex flex-col shadow-xl border-r border-base-200 transition-all duration-300 fixed lg:relative h-full z-50 -translate-x-full lg:translate-x-0"
|
||||
>
|
||||
<!-- Logo -->
|
||||
<div class="p-6 border-b border-base-200">
|
||||
|
@ -152,9 +152,13 @@ const title = "Dashboard";
|
|||
</aside>
|
||||
|
||||
<!-- Main Content -->
|
||||
<main class="flex-1 overflow-x-hidden overflow-y-auto bg-base-200">
|
||||
<main
|
||||
class="flex-1 overflow-x-hidden overflow-y-auto bg-base-200 w-full lg:w-[calc(100%-20rem)]"
|
||||
>
|
||||
<!-- Mobile Header -->
|
||||
<header class="bg-base-100 p-4 shadow-md lg:hidden">
|
||||
<header
|
||||
class="bg-base-100 p-4 shadow-md lg:hidden sticky top-0 z-40"
|
||||
>
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex items-center gap-2">
|
||||
<button
|
||||
|
@ -169,11 +173,11 @@ const title = "Dashboard";
|
|||
</header>
|
||||
|
||||
<!-- Page Content -->
|
||||
<div class="p-6 max-w-[1600px] mx-auto">
|
||||
<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-8"
|
||||
class="flex flex-col items-center justify-center p-4 sm:p-8"
|
||||
>
|
||||
<div class="loading loading-spinner loading-lg">
|
||||
</div>
|
||||
|
@ -183,7 +187,7 @@ const title = "Dashboard";
|
|||
|
||||
<!-- Error State -->
|
||||
<div id="pageErrorState" class="hidden w-full">
|
||||
<div class="alert alert-error">
|
||||
<div class="alert alert-error mx-2 sm:mx-0">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-6 w-6"
|
||||
|
@ -201,12 +205,14 @@ const title = "Dashboard";
|
|||
|
||||
<!-- 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">
|
||||
<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="mb-4 sm:mb-6">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-16 w-16 opacity-30"
|
||||
class="h-12 w-12 sm:h-16 sm:w-16 opacity-30"
|
||||
viewBox="0 0 20 20"
|
||||
fill="currentColor"
|
||||
>
|
||||
|
@ -216,15 +222,17 @@ const title = "Dashboard";
|
|||
clip-rule="evenodd"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<h2 class="card-title text-2xl mb-2">
|
||||
<h2 class="card-title text-xl sm:text-2xl mb-2">
|
||||
Sign in to Access Dashboard
|
||||
</h2>
|
||||
<p class="opacity-70 mb-6">
|
||||
<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"
|
||||
class="login-button btn btn-primary btn-lg gap-2 w-full sm:w-auto"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
|
@ -237,14 +245,16 @@ const title = "Dashboard";
|
|||
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
|
||||
<span class="whitespace-nowrap"
|
||||
>Sign in with IEEEUCSD SSO</span
|
||||
>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Main Content -->
|
||||
<div id="mainContent" class="hidden">
|
||||
<div id="mainContent" class="hidden space-y-4 sm:space-y-6">
|
||||
<ProfileSection />
|
||||
<EventsSection />
|
||||
<ReimbursementSection />
|
||||
|
@ -291,37 +301,75 @@ const title = "Dashboard";
|
|||
});
|
||||
|
||||
// Update display elements
|
||||
if (userName) {
|
||||
userName.textContent = extendedUser.name || "Unknown User";
|
||||
}
|
||||
|
||||
if (userRole) {
|
||||
userRole.textContent = extendedUser.member_type || "Member";
|
||||
}
|
||||
|
||||
if (userInitials) {
|
||||
const displayName = extendedUser.name || "Unknown User";
|
||||
const displayRole = extendedUser.member_type || "Member";
|
||||
const initials = (extendedUser.name || "U")
|
||||
.split(" ")
|
||||
.map((n: string) => n[0])
|
||||
.join("")
|
||||
.toUpperCase();
|
||||
userInitials.textContent = initials;
|
||||
}
|
||||
|
||||
// Update elements
|
||||
if (userName) userName.textContent = displayName;
|
||||
if (userRole) userRole.textContent = displayRole;
|
||||
if (userInitials) userInitials.textContent = initials;
|
||||
} catch (error) {
|
||||
console.error("Error fetching user profile:", error);
|
||||
if (userName) userName.textContent = "Unknown User";
|
||||
if (userRole) userRole.textContent = "Member";
|
||||
if (userInitials) userInitials.textContent = "?";
|
||||
const fallbackValues = {
|
||||
name: "Unknown User",
|
||||
role: "Member",
|
||||
initials: "?",
|
||||
};
|
||||
|
||||
// Update elements with fallback values
|
||||
if (userName) userName.textContent = fallbackValues.name;
|
||||
if (userRole) userRole.textContent = fallbackValues.role;
|
||||
if (userInitials)
|
||||
userInitials.textContent = fallbackValues.initials;
|
||||
}
|
||||
};
|
||||
|
||||
// Mobile sidebar toggle
|
||||
// Mobile sidebar toggle with overlay
|
||||
const mobileSidebarToggle = document.getElementById("mobileSidebarToggle");
|
||||
if (mobileSidebarToggle && sidebar) {
|
||||
mobileSidebarToggle.addEventListener("click", () => {
|
||||
sidebar.classList.toggle("-translate-x-full");
|
||||
});
|
||||
const toggleSidebar = () => {
|
||||
const isOpen = !sidebar.classList.contains("-translate-x-full");
|
||||
|
||||
if (isOpen) {
|
||||
sidebar.classList.add("-translate-x-full");
|
||||
document.body.classList.remove("overflow-hidden");
|
||||
// Remove overlay if it exists
|
||||
const overlay = document.getElementById("sidebarOverlay");
|
||||
overlay?.remove();
|
||||
} else {
|
||||
sidebar.classList.remove("-translate-x-full");
|
||||
document.body.classList.add("overflow-hidden");
|
||||
// Add overlay
|
||||
const overlay = document.createElement("div");
|
||||
overlay.id = "sidebarOverlay";
|
||||
overlay.className =
|
||||
"fixed inset-0 bg-black bg-opacity-50 z-40 lg:hidden";
|
||||
overlay.addEventListener("click", toggleSidebar);
|
||||
document.body.appendChild(overlay);
|
||||
}
|
||||
};
|
||||
|
||||
mobileSidebarToggle.addEventListener("click", toggleSidebar);
|
||||
}
|
||||
|
||||
// Close sidebar on window resize if screen becomes larger
|
||||
window.addEventListener("resize", () => {
|
||||
if (window.innerWidth >= 1024) {
|
||||
const overlay = document.getElementById("sidebarOverlay");
|
||||
if (overlay) {
|
||||
overlay.remove();
|
||||
document.body.classList.remove("overflow-hidden");
|
||||
}
|
||||
if (sidebar) {
|
||||
sidebar.classList.remove("-translate-x-full");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Handle navigation
|
||||
const handleNavigation = () => {
|
||||
|
@ -343,9 +391,12 @@ const title = "Dashboard";
|
|||
const sectionId = `${button.getAttribute("data-section")}Section`;
|
||||
document.getElementById(sectionId)?.classList.remove("hidden");
|
||||
|
||||
// Close sidebar on mobile after selection
|
||||
// Close sidebar and cleanup overlay on mobile
|
||||
if (window.innerWidth < 1024 && sidebar) {
|
||||
sidebar.classList.add("-translate-x-full");
|
||||
document.body.classList.remove("overflow-hidden");
|
||||
const overlay = document.getElementById("sidebarOverlay");
|
||||
overlay?.remove();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue