add pagination
This commit is contained in:
parent
2eba751204
commit
9277d216af
1 changed files with 123 additions and 55 deletions
|
@ -63,7 +63,7 @@ const currentPage = eventResponse.page;
|
||||||
declare global {
|
declare global {
|
||||||
interface Window {
|
interface Window {
|
||||||
[key: string]: any;
|
[key: string]: any;
|
||||||
openEditModal: (event: Event) => void;
|
openEditModal: (event?: any) => void;
|
||||||
deleteFile: (eventId: string, filename: string) => void;
|
deleteFile: (eventId: string, filename: string) => void;
|
||||||
previewFile: (url: string, filename: string) => void;
|
previewFile: (url: string, filename: string) => void;
|
||||||
openDetailsModal: (event: Event) => void;
|
openDetailsModal: (event: Event) => void;
|
||||||
|
@ -87,7 +87,7 @@ declare global {
|
||||||
<h2 class="text-2xl font-bold">Event Management</h2>
|
<h2 class="text-2xl font-bold">Event Management</h2>
|
||||||
<p class="opacity-70">Manage and create IEEE UCSD events</p>
|
<p class="opacity-70">Manage and create IEEE UCSD events</p>
|
||||||
</div>
|
</div>
|
||||||
<button class="btn btn-primary gap-2">
|
<button class="btn btn-primary gap-2" onclick="window.openEditModal()">
|
||||||
<Icon name="heroicons:plus" class="h-5 w-5" />
|
<Icon name="heroicons:plus" class="h-5 w-5" />
|
||||||
Add New Event
|
Add New Event
|
||||||
</button>
|
</button>
|
||||||
|
@ -158,12 +158,17 @@ declare global {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Load More Button -->
|
<!-- Pagination -->
|
||||||
<div class="flex justify-center mt-6 hidden" id="loadMoreContainer">
|
<div class="flex justify-center mt-6" id="paginationContainer">
|
||||||
<button class="btn btn-outline btn-primary gap-2" id="loadMoreButton">
|
<div class="join">
|
||||||
<Icon name="heroicons:arrow-down" class="h-5 w-5" />
|
<button class="join-item btn btn-sm" id="firstPageBtn">«</button>
|
||||||
Load More Events
|
<button class="join-item btn btn-sm" id="prevPageBtn">‹</button>
|
||||||
</button>
|
<button class="join-item btn 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-sm" id="lastPageBtn">»</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -172,7 +177,7 @@ declare global {
|
||||||
<!-- Edit Event Modal -->
|
<!-- Edit Event Modal -->
|
||||||
<dialog id="editEventModal" class="modal">
|
<dialog id="editEventModal" class="modal">
|
||||||
<div class="modal-box max-w-2xl">
|
<div class="modal-box max-w-2xl">
|
||||||
<h3 class="font-bold text-lg mb-4">Edit Event</h3>
|
<h3 class="font-bold text-lg mb-4" id="editModalTitle">Edit Event</h3>
|
||||||
<form id="editEventForm" class="space-y-4">
|
<form id="editEventForm" class="space-y-4">
|
||||||
<input type="hidden" id="editEventId" />
|
<input type="hidden" id="editEventId" />
|
||||||
|
|
||||||
|
@ -423,13 +428,14 @@ declare global {
|
||||||
let tempFiles: File[] = [];
|
let tempFiles: File[] = [];
|
||||||
|
|
||||||
// Make openEditModal available globally
|
// Make openEditModal available globally
|
||||||
window.openEditModal = function (event: any) {
|
window.openEditModal = function (event?: any) {
|
||||||
// Convert event times to local time
|
// Convert event times to local time if event exists
|
||||||
const localEvent = Get.convertUTCToLocal(event);
|
const localEvent = event ? Get.convertUTCToLocal(event) : null;
|
||||||
|
|
||||||
const modal = document.getElementById(
|
const modal = document.getElementById(
|
||||||
"editEventModal",
|
"editEventModal",
|
||||||
) as HTMLDialogElement;
|
) as HTMLDialogElement;
|
||||||
|
const modalTitle = document.getElementById("editModalTitle");
|
||||||
const form = document.getElementById("editEventForm") as HTMLFormElement;
|
const form = document.getElementById("editEventForm") as HTMLFormElement;
|
||||||
const idInput = document.getElementById("editEventId") as HTMLInputElement;
|
const idInput = document.getElementById("editEventId") as HTMLInputElement;
|
||||||
const nameInput = document.getElementById(
|
const nameInput = document.getElementById(
|
||||||
|
@ -460,21 +466,28 @@ declare global {
|
||||||
"currentFiles",
|
"currentFiles",
|
||||||
) as HTMLDivElement;
|
) as HTMLDivElement;
|
||||||
|
|
||||||
|
// Update modal title based on whether we're editing or creating
|
||||||
|
if (modalTitle) {
|
||||||
|
modalTitle.textContent = localEvent ? "Edit Event" : "Create New Event";
|
||||||
|
}
|
||||||
|
|
||||||
// Set values
|
// Set values
|
||||||
idInput.value = localEvent.id;
|
idInput.value = localEvent?.id || "";
|
||||||
nameInput.value = localEvent.event_name;
|
nameInput.value = localEvent?.event_name || "";
|
||||||
descInput.value = localEvent.event_description || "";
|
descInput.value = localEvent?.event_description || "";
|
||||||
codeInput.value = localEvent.event_code || "";
|
codeInput.value = localEvent?.event_code || "";
|
||||||
locationInput.value = localEvent.location || "";
|
locationInput.value = localEvent?.location || "";
|
||||||
pointsInput.value = localEvent.points_to_reward?.toString() || "0";
|
pointsInput.value = localEvent?.points_to_reward?.toString() || "0";
|
||||||
|
|
||||||
// Format dates properly for datetime-local input
|
// Format dates properly for datetime-local input
|
||||||
try {
|
try {
|
||||||
const startDate = new Date(localEvent.start_date);
|
const now = new Date();
|
||||||
const endDate = new Date(localEvent.end_date);
|
const startDate = localEvent ? new Date(localEvent.start_date) : now;
|
||||||
|
const endDate = localEvent
|
||||||
|
? new Date(localEvent.end_date)
|
||||||
|
: new Date(now.getTime() + 60 * 60 * 1000); // Default to 1 hour duration
|
||||||
|
|
||||||
if (!isNaN(startDate.getTime())) {
|
if (!isNaN(startDate.getTime())) {
|
||||||
// Format date as YYYY-MM-DDThh:mm in local timezone
|
|
||||||
startDateInput.value = new Date(
|
startDateInput.value = new Date(
|
||||||
startDate.getTime() - startDate.getTimezoneOffset() * 60000,
|
startDate.getTime() - startDate.getTimezoneOffset() * 60000,
|
||||||
)
|
)
|
||||||
|
@ -483,7 +496,6 @@ declare global {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isNaN(endDate.getTime())) {
|
if (!isNaN(endDate.getTime())) {
|
||||||
// Format date as YYYY-MM-DDThh:mm in local timezone
|
|
||||||
endDateInput.value = new Date(
|
endDateInput.value = new Date(
|
||||||
endDate.getTime() - endDate.getTimezoneOffset() * 60000,
|
endDate.getTime() - endDate.getTimezoneOffset() * 60000,
|
||||||
)
|
)
|
||||||
|
@ -494,7 +506,7 @@ declare global {
|
||||||
console.error("Error formatting dates:", e);
|
console.error("Error formatting dates:", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
publishedInput.checked = localEvent.published || false;
|
publishedInput.checked = localEvent?.published || false;
|
||||||
|
|
||||||
// Reset temp files
|
// Reset temp files
|
||||||
tempFiles = [];
|
tempFiles = [];
|
||||||
|
@ -502,7 +514,7 @@ declare global {
|
||||||
newFilesDiv.innerHTML = "";
|
newFilesDiv.innerHTML = "";
|
||||||
|
|
||||||
// Display current files if any
|
// Display current files if any
|
||||||
if (localEvent.files && localEvent.files.length > 0) {
|
if (localEvent?.files && localEvent.files.length > 0) {
|
||||||
const baseUrl = "https://pocketbase.ieeeucsd.org";
|
const baseUrl = "https://pocketbase.ieeeucsd.org";
|
||||||
const collectionId = "events";
|
const collectionId = "events";
|
||||||
const recordId = localEvent.id;
|
const recordId = localEvent.id;
|
||||||
|
@ -653,7 +665,7 @@ declare global {
|
||||||
.join("");
|
.join("");
|
||||||
};
|
};
|
||||||
|
|
||||||
// Update form submission to handle temp files
|
// Update form submission to handle both create and edit
|
||||||
const editForm = document.getElementById("editEventForm") as HTMLFormElement;
|
const editForm = document.getElementById("editEventForm") as HTMLFormElement;
|
||||||
if (editForm) {
|
if (editForm) {
|
||||||
editForm.addEventListener("submit", async (e) => {
|
editForm.addEventListener("submit", async (e) => {
|
||||||
|
@ -680,8 +692,8 @@ declare global {
|
||||||
const pointsValue = parseInt(formData.get("editEventPoints") as string);
|
const pointsValue = parseInt(formData.get("editEventPoints") as string);
|
||||||
const points = isNaN(pointsValue) ? 0 : pointsValue;
|
const points = isNaN(pointsValue) ? 0 : pointsValue;
|
||||||
|
|
||||||
// Prepare update data with dates in UTC
|
// Prepare base event data without attendees
|
||||||
const updateData = {
|
const baseEventData = {
|
||||||
event_name: formData.get("editEventName"),
|
event_name: formData.get("editEventName"),
|
||||||
event_description: formData.get("editEventDescription"),
|
event_description: formData.get("editEventDescription"),
|
||||||
event_code: formData.get("editEventCode"),
|
event_code: formData.get("editEventCode"),
|
||||||
|
@ -692,26 +704,40 @@ declare global {
|
||||||
published: formData.get("editEventPublished") === "on",
|
published: formData.get("editEventPublished") === "on",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// For new events, add empty attendees list
|
||||||
|
const eventData = eventId
|
||||||
|
? baseEventData
|
||||||
|
: { ...baseEventData, attendees: [] };
|
||||||
|
|
||||||
// Update event details
|
// Update event details
|
||||||
auth.setUpdating(true);
|
auth.setUpdating(true);
|
||||||
try {
|
try {
|
||||||
await update.updateFields("events", eventId, updateData);
|
const pb = auth.getPocketBase();
|
||||||
|
let result;
|
||||||
|
|
||||||
|
if (eventId) {
|
||||||
|
// Update existing event
|
||||||
|
result = await update.updateFields("events", eventId, eventData);
|
||||||
|
} else {
|
||||||
|
// Create new event
|
||||||
|
result = await pb.collection("events").create(eventData);
|
||||||
|
}
|
||||||
|
|
||||||
// Upload temp files if any
|
// Upload temp files if any
|
||||||
if (tempFiles.length > 0) {
|
if (tempFiles.length > 0) {
|
||||||
await fileManager.uploadFiles(
|
await fileManager.uploadFiles(
|
||||||
"events",
|
"events",
|
||||||
eventId,
|
result.id,
|
||||||
"files",
|
"files",
|
||||||
tempFiles,
|
tempFiles,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Log the update
|
// Log the action
|
||||||
await sendLog.send(
|
await sendLog.send(
|
||||||
"update",
|
eventId ? "update" : "create",
|
||||||
"events",
|
"events",
|
||||||
`Updated event ${updateData.event_name}`,
|
`${eventId ? "Updated" : "Created"} event ${eventData.event_name}`,
|
||||||
);
|
);
|
||||||
|
|
||||||
modal.close();
|
modal.close();
|
||||||
|
@ -720,8 +746,8 @@ declare global {
|
||||||
auth.setUpdating(false);
|
auth.setUpdating(false);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Failed to update event:", error);
|
console.error("Failed to save event:", error);
|
||||||
alert("Failed to update event. Please try again.");
|
alert("Failed to save event. Please try again.");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1025,7 +1051,8 @@ declare global {
|
||||||
|
|
||||||
async function fetchEvents() {
|
async function fetchEvents() {
|
||||||
const eventsList = document.getElementById("eventsList");
|
const eventsList = document.getElementById("eventsList");
|
||||||
if (!eventsList) return;
|
const paginationContainer = document.getElementById("paginationContainer");
|
||||||
|
if (!eventsList || !paginationContainer) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (!auth.isAuthenticated()) {
|
if (!auth.isAuthenticated()) {
|
||||||
|
@ -1037,6 +1064,7 @@ declare global {
|
||||||
<p>Please log in to view events</p>
|
<p>Please log in to view events</p>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
paginationContainer.classList.add("hidden");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1064,6 +1092,7 @@ declare global {
|
||||||
const totalEventsLabelEl = document.getElementById("totalEventsLabel");
|
const totalEventsLabelEl = document.getElementById("totalEventsLabel");
|
||||||
const currentPageEl = document.getElementById("currentPage");
|
const currentPageEl = document.getElementById("currentPage");
|
||||||
const totalPagesLabelEl = document.getElementById("totalPagesLabel");
|
const totalPagesLabelEl = document.getElementById("totalPagesLabel");
|
||||||
|
const currentPageNumber = document.getElementById("currentPageNumber");
|
||||||
|
|
||||||
if (totalEventsEl)
|
if (totalEventsEl)
|
||||||
totalEventsEl.textContent = response.totalItems.toString();
|
totalEventsEl.textContent = response.totalItems.toString();
|
||||||
|
@ -1074,6 +1103,36 @@ declare global {
|
||||||
if (currentPageEl) currentPageEl.textContent = response.page.toString();
|
if (currentPageEl) currentPageEl.textContent = response.page.toString();
|
||||||
if (totalPagesLabelEl)
|
if (totalPagesLabelEl)
|
||||||
totalPagesLabelEl.textContent = `of ${response.totalPages}`;
|
totalPagesLabelEl.textContent = `of ${response.totalPages}`;
|
||||||
|
if (currentPageNumber)
|
||||||
|
currentPageNumber.textContent = response.page.toString();
|
||||||
|
|
||||||
|
// Update pagination buttons state
|
||||||
|
const firstPageBtn = document.getElementById(
|
||||||
|
"firstPageBtn",
|
||||||
|
) as HTMLButtonElement;
|
||||||
|
const prevPageBtn = document.getElementById(
|
||||||
|
"prevPageBtn",
|
||||||
|
) as HTMLButtonElement;
|
||||||
|
const nextPageBtn = document.getElementById(
|
||||||
|
"nextPageBtn",
|
||||||
|
) as HTMLButtonElement;
|
||||||
|
const lastPageBtn = document.getElementById(
|
||||||
|
"lastPageBtn",
|
||||||
|
) as HTMLButtonElement;
|
||||||
|
|
||||||
|
if (firstPageBtn) firstPageBtn.disabled = response.page <= 1;
|
||||||
|
if (prevPageBtn) prevPageBtn.disabled = response.page <= 1;
|
||||||
|
if (nextPageBtn)
|
||||||
|
nextPageBtn.disabled = response.page >= response.totalPages;
|
||||||
|
if (lastPageBtn)
|
||||||
|
lastPageBtn.disabled = response.page >= response.totalPages;
|
||||||
|
|
||||||
|
// Show/hide pagination based on total pages
|
||||||
|
if (response.totalPages <= 1) {
|
||||||
|
paginationContainer.classList.add("hidden");
|
||||||
|
} else {
|
||||||
|
paginationContainer.classList.remove("hidden");
|
||||||
|
}
|
||||||
|
|
||||||
// Update events list
|
// Update events list
|
||||||
if (localEvents.length === 0) {
|
if (localEvents.length === 0) {
|
||||||
|
@ -1154,16 +1213,6 @@ declare global {
|
||||||
})
|
})
|
||||||
.join("");
|
.join("");
|
||||||
|
|
||||||
// Update load more button
|
|
||||||
const loadMoreContainer = document.getElementById("loadMoreContainer");
|
|
||||||
if (loadMoreContainer) {
|
|
||||||
if (response.page < response.totalPages) {
|
|
||||||
loadMoreContainer.classList.remove("hidden");
|
|
||||||
} else {
|
|
||||||
loadMoreContainer.classList.add("hidden");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
totalPages = response.totalPages;
|
totalPages = response.totalPages;
|
||||||
} finally {
|
} finally {
|
||||||
auth.setUpdating(false);
|
auth.setUpdating(false);
|
||||||
|
@ -1178,19 +1227,38 @@ declare global {
|
||||||
<span>Failed to load events. Please try refreshing the page.</span>
|
<span>Failed to load events. Please try refreshing the page.</span>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
paginationContainer.classList.add("hidden");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load more events when button is clicked
|
// Add pagination event listeners
|
||||||
const loadMoreButton = document.getElementById("loadMoreButton");
|
document.getElementById("firstPageBtn")?.addEventListener("click", () => {
|
||||||
if (loadMoreButton) {
|
if (currentPage > 1) {
|
||||||
loadMoreButton.addEventListener("click", async (e: MouseEvent) => {
|
currentPage = 1;
|
||||||
if (currentPage < totalPages) {
|
fetchEvents();
|
||||||
currentPage++;
|
}
|
||||||
await fetchEvents();
|
});
|
||||||
}
|
|
||||||
});
|
document.getElementById("prevPageBtn")?.addEventListener("click", () => {
|
||||||
}
|
if (currentPage > 1) {
|
||||||
|
currentPage--;
|
||||||
|
fetchEvents();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
document.getElementById("nextPageBtn")?.addEventListener("click", () => {
|
||||||
|
if (currentPage < totalPages) {
|
||||||
|
currentPage++;
|
||||||
|
fetchEvents();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
document.getElementById("lastPageBtn")?.addEventListener("click", () => {
|
||||||
|
if (currentPage < totalPages) {
|
||||||
|
currentPage = totalPages;
|
||||||
|
fetchEvents();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Initial fetch - only call once
|
// Initial fetch - only call once
|
||||||
fetchEvents();
|
fetchEvents();
|
||||||
|
|
Loading…
Reference in a new issue