no more console logs

This commit is contained in:
chark1es 2025-03-08 22:23:30 -08:00
parent 16d9ec9e1d
commit 27bc2f4e70
32 changed files with 3752 additions and 4000 deletions

View file

@ -1,18 +1,22 @@
<script>
const observer = new IntersectionObserver((entries) => {
const observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
entry.target.classList.add("in-view");
entry.target.classList.remove("opacity-0");
console.log("Added 'in-view' class to:", entry.target);
// console.log("Added 'in-view' class to:", entry.target);
} else {
entry.target.classList.remove("in-view");
entry.target.classList.add("opacity-0");
console.log("Removed 'in-view' class from:", entry.target);
// console.log("Removed 'in-view' class from:", entry.target);
}
});
}, { threshold: 0.2 });
document.querySelectorAll("[data-inview]").forEach((el) => observer.observe(el));
</script>
},
{ threshold: 0.2 },
);
document
.querySelectorAll("[data-inview]")
.forEach((el) => observer.observe(el));
</script>

View file

@ -5,151 +5,144 @@ import EventLoad from "./EventsSection/EventLoad";
---
<div id="" class="">
<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 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-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>
<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 />
<!-- 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 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 text-sm sm:text-base"
>Coming Soon</span
>
</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 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 text-sm sm:text-base"
>Coming Soon</span
>
</div>
<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 text-sm sm:text-base"
>Select an event to register</span
>
</label>
<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>Social Event - Game Night</option>
</select>
<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 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 text-sm sm:text-base"
>Select an event to register</span
>
</label>
<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>Social Event - Game Night</option>
</select>
<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 />
<EventLoad client:load />
</div>
<!-- Event Details Modal -->
<dialog id="eventDetailsModal" class="modal">
<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 text-xs sm:text-sm"
onclick="window.downloadAllFiles()"
>
<iconify-icon
icon="heroicons:arrow-down-tray-20-solid"
className="h-3 w-3 sm:h-4 sm:w-4"></iconify-icon>
Download All
</button>
</div>
<button
class="btn btn-circle btn-ghost btn-sm sm:btn-md"
onclick="window.closeEventDetailsModal()"
>
<iconify-icon
icon="heroicons:x-mark"
className="h-4 w-4 sm:h-6 sm:w-6"></iconify-icon>
</button>
</div>
<div id="filesContent" class="space-y-3 sm:space-y-4">
<!-- Files list will be populated here -->
</div>
<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 text-xs sm:text-sm"
onclick="window.downloadAllFiles()"
>
<iconify-icon
icon="heroicons:arrow-down-tray-20-solid"
className="h-3 w-3 sm:h-4 sm:w-4"></iconify-icon>
Download All
</button>
</div>
<button
class="btn btn-circle btn-ghost btn-sm sm:btn-md"
onclick="window.closeEventDetailsModal()"
>
<iconify-icon icon="heroicons:x-mark" className="h-4 w-4 sm:h-6 sm:w-6"
></iconify-icon>
</button>
</div>
<form method="dialog" class="modal-backdrop">
<button onclick="window.closeEventDetailsModal()">close</button>
</form>
<div id="filesContent" class="space-y-3 sm:space-y-4">
<!-- Files list will be populated here -->
</div>
</div>
<form method="dialog" class="modal-backdrop">
<button onclick="window.closeEventDetailsModal()">close</button>
</form>
</dialog>
<!-- Universal File Preview Modal -->
<dialog id="filePreviewModal" class="modal">
<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 text-xs sm:text-sm"
onclick="window.closeFilePreviewEvents()">Close</button
>
<h3
class="font-bold text-base sm:text-lg truncate"
id="previewFileName"
>
</h3>
</div>
</div>
<div class="relative" id="previewContainer">
<div
id="previewLoadingSpinner"
class="absolute inset-0 flex items-center justify-center bg-base-200 bg-opacity-50 hidden"
>
<span class="loading loading-spinner loading-md sm:loading-lg"
></span>
</div>
<div id="previewContent" class="w-full">
<FilePreview client:load isModal={true} />
</div>
</div>
<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 text-xs sm:text-sm"
onclick="window.closeFilePreviewEvents()">Close</button
>
<h3
class="font-bold text-base sm:text-lg truncate"
id="previewFileName"
>
</h3>
</div>
</div>
<form method="dialog" class="modal-backdrop">
<button onclick="window.closeFilePreviewEvents()">close</button>
</form>
<div class="relative" id="previewContainer">
<div
id="previewLoadingSpinner"
class="absolute inset-0 flex items-center justify-center bg-base-200 bg-opacity-50 hidden"
>
<span class="loading loading-spinner loading-md sm:loading-lg"></span>
</div>
<div id="previewContent" class="w-full">
<FilePreview client:load isModal={true} />
</div>
</div>
</div>
<form method="dialog" class="modal-backdrop">
<button onclick="window.closeFilePreviewEvents()">close</button>
</form>
</dialog>
<script>
import { toast } from "react-hot-toast";
import JSZip from "jszip";
import { toast } from "react-hot-toast";
import JSZip from "jszip";
// Add styles to the document
const style = document.createElement("style");
style.textContent = `
// Add styles to the document
const style = document.createElement("style");
style.textContent = `
/* Custom styles for the event details modal */
.event-details-grid {
display: grid;
@ -165,234 +158,227 @@ import EventLoad from "./EventsSection/EventLoad";
/* Remove custom toast styles since we're using react-hot-toast */
`;
document.head.appendChild(style);
document.head.appendChild(style);
// Add helper functions for file preview
function getFileType(filename: string): string {
const extension = filename.split(".").pop()?.toLowerCase();
const mimeTypes: { [key: string]: string } = {
pdf: "application/pdf",
jpg: "image/jpeg",
jpeg: "image/jpeg",
png: "image/png",
gif: "image/gif",
mp4: "video/mp4",
mp3: "audio/mpeg",
txt: "text/plain",
doc: "application/msword",
docx: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
xls: "application/vnd.ms-excel",
xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
json: "application/json",
};
// Add helper functions for file preview
function getFileType(filename: string): string {
const extension = filename.split(".").pop()?.toLowerCase();
const mimeTypes: { [key: string]: string } = {
pdf: "application/pdf",
jpg: "image/jpeg",
jpeg: "image/jpeg",
png: "image/png",
gif: "image/gif",
mp4: "video/mp4",
mp3: "audio/mpeg",
txt: "text/plain",
doc: "application/msword",
docx: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
xls: "application/vnd.ms-excel",
xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
json: "application/json",
};
return mimeTypes[extension || ""] || "application/octet-stream";
return mimeTypes[extension || ""] || "application/octet-stream";
}
// Universal file preview function for events section
window.previewFileEvents = function (url: string, filename: string) {
// console.log("previewFileEvents called with:", { url, filename });
// console.log("URL type:", typeof url, "URL length:", url?.length || 0);
// console.log(
// "Filename type:",
// typeof filename,
// "Filename length:",
// filename?.length || 0
// );
// Validate inputs
if (!url || typeof url !== "string") {
console.error("Invalid URL provided to previewFileEvents:", url);
toast.error("Cannot preview file: Invalid URL");
return;
}
// Universal file preview function for events section
window.previewFileEvents = function (url: string, filename: string) {
console.log("previewFileEvents called with:", { url, filename });
console.log("URL type:", typeof url, "URL length:", url?.length || 0);
console.log(
"Filename type:",
typeof filename,
"Filename length:",
filename?.length || 0
);
if (!filename || typeof filename !== "string") {
console.error(
"Invalid filename provided to previewFileEvents:",
filename,
);
toast.error("Cannot preview file: Invalid filename");
return;
}
// Validate inputs
if (!url || typeof url !== "string") {
console.error("Invalid URL provided to previewFileEvents:", url);
toast.error("Cannot preview file: Invalid URL");
return;
}
// Ensure URL is properly formatted
if (!url.startsWith("http")) {
console.warn("URL doesn't start with http, attempting to fix:", url);
if (url.startsWith("/")) {
url = `https://pocketbase.ieeeucsd.org${url}`;
} else {
url = `https://pocketbase.ieeeucsd.org/${url}`;
}
// console.log("Fixed URL:", url);
}
if (!filename || typeof filename !== "string") {
console.error(
"Invalid filename provided to previewFileEvents:",
filename
);
toast.error("Cannot preview file: Invalid filename");
return;
}
const modal = document.getElementById(
"filePreviewModal",
) as HTMLDialogElement;
const previewFileName = document.getElementById("previewFileName");
const previewContent = document.getElementById("previewContent");
const loadingSpinner = document.getElementById("previewLoadingSpinner");
// Ensure URL is properly formatted
if (!url.startsWith("http")) {
console.warn(
"URL doesn't start with http, attempting to fix:",
url
);
if (url.startsWith("/")) {
url = `https://pocketbase.ieeeucsd.org${url}`;
} else {
url = `https://pocketbase.ieeeucsd.org/${url}`;
}
console.log("Fixed URL:", url);
}
if (modal && previewFileName && previewContent) {
// console.log("Found all required elements");
const modal = document.getElementById(
"filePreviewModal"
) as HTMLDialogElement;
const previewFileName = document.getElementById("previewFileName");
const previewContent = document.getElementById("previewContent");
const loadingSpinner = document.getElementById("previewLoadingSpinner");
// Show loading spinner
if (loadingSpinner) {
loadingSpinner.classList.remove("hidden");
}
if (modal && previewFileName && previewContent) {
console.log("Found all required elements");
// Update the filename display
previewFileName.textContent = filename;
// Show loading spinner
if (loadingSpinner) {
loadingSpinner.classList.remove("hidden");
}
// Show the modal
modal.showModal();
// Update the filename display
previewFileName.textContent = filename;
// Show the modal
modal.showModal();
// Test the URL with a fetch before dispatching the event
fetch(url, { method: "HEAD" })
.then((response) => {
console.log(
"URL test response:",
response.status,
response.ok
);
if (!response.ok) {
console.warn("URL might not be accessible:", url);
toast(
"File might not be accessible. Attempting to preview anyway.",
{
icon: "⚠️",
style: {
borderRadius: "10px",
background: "#FFC107",
color: "#000",
},
}
);
}
})
.catch((err) => {
console.error("Error testing URL:", err);
})
.finally(() => {
// Dispatch state change event to update the FilePreview component
console.log(
"Dispatching filePreviewStateChange event with:",
{ url, filename }
);
window.dispatchEvent(
new CustomEvent("filePreviewStateChange", {
detail: { url, filename },
})
);
});
// Hide loading spinner after a short delay
setTimeout(() => {
if (loadingSpinner) {
loadingSpinner.classList.add("hidden");
}
}, 1000); // Increased delay to allow for URL testing
} else {
console.error("Missing required elements for file preview");
toast.error("Could not initialize file preview");
}
};
// Close file preview for events section
window.closeFilePreviewEvents = function () {
console.log("closeFilePreviewEvents called");
const modal = document.getElementById(
"filePreviewModal"
) as HTMLDialogElement;
const previewFileName = document.getElementById("previewFileName");
const previewContent = document.getElementById("previewContent");
const loadingSpinner = document.getElementById("previewLoadingSpinner");
if (loadingSpinner) {
loadingSpinner.classList.add("hidden");
}
if (modal && previewFileName && previewContent) {
console.log("Resetting preview and closing modal");
// First reset the preview state by dispatching an event with empty values
// This ensures the FilePreview component clears its internal state
window.dispatchEvent(
new CustomEvent("filePreviewStateChange", {
detail: { url: "", filename: "" },
})
);
// Reset the UI
previewFileName.textContent = "";
// Close the modal
modal.close();
console.log("File preview modal closed and state reset");
} else {
console.error("Could not find elements to close file preview");
}
};
// Update the showFilePreview function for events section
window.showFilePreviewEvents = function (file: {
url: string;
name: string;
}) {
console.log("showFilePreviewEvents called with:", file);
if (!file || !file.url || !file.name) {
console.error("Invalid file data:", file);
toast.error("Could not preview file: missing file information");
return;
}
window.previewFileEvents(file.url, file.name);
};
// Update the openDetailsModal function to use the events-specific preview
window.openDetailsModal = function (event: any) {
const modal = document.getElementById(
"eventDetailsModal"
) as HTMLDialogElement;
const filesContent = document.getElementById(
"filesContent"
) as HTMLDivElement;
// Check if event has ended
const eventEndDate = new Date(event.end_date);
const now = new Date();
if (eventEndDate > now) {
toast("Files are only available after the event has ended.", {
// Test the URL with a fetch before dispatching the event
fetch(url, { method: "HEAD" })
.then((response) => {
// console.log(
// "URL test response:",
// response.status,
// response.ok
// );
if (!response.ok) {
console.warn("URL might not be accessible:", url);
toast(
"File might not be accessible. Attempting to preview anyway.",
{
icon: "⚠️",
style: {
borderRadius: "10px",
background: "#FFC107",
color: "#000",
borderRadius: "10px",
background: "#FFC107",
color: "#000",
},
});
return;
},
);
}
})
.catch((err) => {
console.error("Error testing URL:", err);
})
.finally(() => {
// Dispatch state change event to update the FilePreview component
// console.log(
// "Dispatching filePreviewStateChange event with:",
// { url, filename }
// );
window.dispatchEvent(
new CustomEvent("filePreviewStateChange", {
detail: { url, filename },
}),
);
});
// Hide loading spinner after a short delay
setTimeout(() => {
if (loadingSpinner) {
loadingSpinner.classList.add("hidden");
}
}, 1000); // Increased delay to allow for URL testing
} else {
console.error("Missing required elements for file preview");
toast.error("Could not initialize file preview");
}
};
// Reset state
window.currentEventId = event.id;
if (filesContent) filesContent.classList.remove("hidden");
// Close file preview for events section
window.closeFilePreviewEvents = function () {
// console.log("closeFilePreviewEvents called");
const modal = document.getElementById(
"filePreviewModal",
) as HTMLDialogElement;
const previewFileName = document.getElementById("previewFileName");
const previewContent = document.getElementById("previewContent");
const loadingSpinner = document.getElementById("previewLoadingSpinner");
// Populate files content
if (
event.files &&
Array.isArray(event.files) &&
event.files.length > 0
) {
const baseUrl = "https://pocketbase.ieeeucsd.org";
const collectionId = "events";
const recordId = event.id;
if (loadingSpinner) {
loadingSpinner.classList.add("hidden");
}
filesContent.innerHTML = `
if (modal && previewFileName && previewContent) {
// console.log("Resetting preview and closing modal");
// First reset the preview state by dispatching an event with empty values
// This ensures the FilePreview component clears its internal state
window.dispatchEvent(
new CustomEvent("filePreviewStateChange", {
detail: { url: "", filename: "" },
}),
);
// Reset the UI
previewFileName.textContent = "";
// Close the modal
modal.close();
// console.log("File preview modal closed and state reset");
} else {
console.error("Could not find elements to close file preview");
}
};
// Update the showFilePreview function for events section
window.showFilePreviewEvents = function (file: {
url: string;
name: string;
}) {
// console.log("showFilePreviewEvents called with:", file);
if (!file || !file.url || !file.name) {
console.error("Invalid file data:", file);
toast.error("Could not preview file: missing file information");
return;
}
window.previewFileEvents(file.url, file.name);
};
// Update the openDetailsModal function to use the events-specific preview
window.openDetailsModal = function (event: any) {
const modal = document.getElementById(
"eventDetailsModal",
) as HTMLDialogElement;
const filesContent = document.getElementById(
"filesContent",
) as HTMLDivElement;
// Check if event has ended
const eventEndDate = new Date(event.end_date);
const now = new Date();
if (eventEndDate > now) {
toast("Files are only available after the event has ended.", {
icon: "⚠️",
style: {
borderRadius: "10px",
background: "#FFC107",
color: "#000",
},
});
return;
}
// Reset state
window.currentEventId = event.id;
if (filesContent) filesContent.classList.remove("hidden");
// Populate files content
if (event.files && Array.isArray(event.files) && event.files.length > 0) {
const baseUrl = "https://pocketbase.ieeeucsd.org";
const collectionId = "events";
const recordId = event.id;
filesContent.innerHTML = `
<div class="overflow-x-auto">
<table class="table table-zebra w-full">
<thead>
@ -403,16 +389,16 @@ import EventLoad from "./EventsSection/EventLoad";
</thead>
<tbody>
${event.files
.map((file: string) => {
// Ensure the file URL is properly formatted
const fileUrl = `${baseUrl}/api/files/${collectionId}/${recordId}/${file}`;
const fileType = getFileType(file);
// Properly escape the data for the onclick handler
const fileData = {
url: fileUrl,
name: file,
};
return `
.map((file: string) => {
// Ensure the file URL is properly formatted
const fileUrl = `${baseUrl}/api/files/${collectionId}/${recordId}/${file}`;
const fileType = getFileType(file);
// Properly escape the data for the onclick handler
const fileData = {
url: fileUrl,
name: file,
};
return `
<tr>
<td>${file}</td>
<td class="text-right">
@ -425,123 +411,123 @@ import EventLoad from "./EventsSection/EventLoad";
</td>
</tr>
`;
})
.join("")}
})
.join("")}
</tbody>
</table>
</div>
`;
} else {
filesContent.innerHTML = `
} else {
filesContent.innerHTML = `
<div class="text-center py-8 text-base-content/70">
<iconify-icon icon="heroicons:document-duplicate" className="h-12 w-12 mx-auto mb-4 opacity-50" />
<p>No files attached to this event</p>
</div>
`;
}
modal.showModal();
};
// Add downloadAllFiles function
window.downloadAllFiles = async function () {
const downloadBtn = document.getElementById(
"downloadAllBtn",
) as HTMLButtonElement;
if (!downloadBtn) return;
const originalBtnContent = downloadBtn.innerHTML;
try {
// Show loading state
downloadBtn.innerHTML =
'<span class="loading loading-spinner loading-xs"></span> Preparing...';
downloadBtn.disabled = true;
const zip = new JSZip();
// Get current event files
const baseUrl = "https://pocketbase.ieeeucsd.org";
const collectionId = "events";
const recordId = window.currentEventId;
// Get the current event from the window object
const eventDataId = `event_${window.currentEventId}`;
const event = window[eventDataId];
if (!event || !event.files || event.files.length === 0) {
throw new Error("No files available to download");
}
// Download each file and add to zip
const filePromises = event.files.map(async (filename: string) => {
const fileUrl = `${baseUrl}/api/files/${collectionId}/${recordId}/${filename}`;
const response = await fetch(fileUrl);
if (!response.ok) {
throw new Error(`Failed to download ${filename}`);
}
const blob = await response.blob();
zip.file(filename, blob);
});
modal.showModal();
};
await Promise.all(filePromises);
// Add downloadAllFiles function
window.downloadAllFiles = async function () {
const downloadBtn = document.getElementById(
"downloadAllBtn"
) as HTMLButtonElement;
if (!downloadBtn) return;
const originalBtnContent = downloadBtn.innerHTML;
// Generate and download zip
const zipBlob = await zip.generateAsync({ type: "blob" });
const downloadUrl = URL.createObjectURL(zipBlob);
const link = document.createElement("a");
link.href = downloadUrl;
link.download = `${event.event_name}_files.zip`;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
URL.revokeObjectURL(downloadUrl);
try {
// Show loading state
downloadBtn.innerHTML =
'<span class="loading loading-spinner loading-xs"></span> Preparing...';
downloadBtn.disabled = true;
// Show success message
toast.success("Files downloaded successfully!");
} catch (error: any) {
console.error("Failed to download files:", error);
toast.error(
error?.message || "Failed to download files. Please try again.",
);
} finally {
// Reset button state
downloadBtn.innerHTML = originalBtnContent;
downloadBtn.disabled = false;
}
};
const zip = new JSZip();
// Close event details modal
window.closeEventDetailsModal = function () {
const modal = document.getElementById(
"eventDetailsModal",
) as HTMLDialogElement;
const filesContent = document.getElementById("filesContent");
// Get current event files
const baseUrl = "https://pocketbase.ieeeucsd.org";
const collectionId = "events";
const recordId = window.currentEventId;
if (modal) {
// Reset the files content
if (filesContent) {
filesContent.innerHTML = "";
}
// Get the current event from the window object
const eventDataId = `event_${window.currentEventId}`;
const event = window[eventDataId];
// Reset any other state if needed
window.currentEventId = "";
if (!event || !event.files || event.files.length === 0) {
throw new Error("No files available to download");
}
// Close the modal
modal.close();
}
};
// Download each file and add to zip
const filePromises = event.files.map(async (filename: string) => {
const fileUrl = `${baseUrl}/api/files/${collectionId}/${recordId}/${filename}`;
const response = await fetch(fileUrl);
if (!response.ok) {
throw new Error(`Failed to download ${filename}`);
}
const blob = await response.blob();
zip.file(filename, blob);
});
await Promise.all(filePromises);
// Generate and download zip
const zipBlob = await zip.generateAsync({ type: "blob" });
const downloadUrl = URL.createObjectURL(zipBlob);
const link = document.createElement("a");
link.href = downloadUrl;
link.download = `${event.event_name}_files.zip`;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
URL.revokeObjectURL(downloadUrl);
// Show success message
toast.success("Files downloaded successfully!");
} catch (error: any) {
console.error("Failed to download files:", error);
toast.error(
error?.message || "Failed to download files. Please try again."
);
} finally {
// Reset button state
downloadBtn.innerHTML = originalBtnContent;
downloadBtn.disabled = false;
}
};
// Close event details modal
window.closeEventDetailsModal = function () {
const modal = document.getElementById(
"eventDetailsModal"
) as HTMLDialogElement;
const filesContent = document.getElementById("filesContent");
if (modal) {
// Reset the files content
if (filesContent) {
filesContent.innerHTML = "";
}
// Reset any other state if needed
window.currentEventId = "";
// Close the modal
modal.close();
}
};
// Make helper functions available globally
window.showFilePreview = window.showFilePreviewEvents;
window.handlePreviewError = function () {
const previewContent = document.getElementById("previewContent");
if (previewContent) {
previewContent.innerHTML = `
// Make helper functions available globally
window.showFilePreview = window.showFilePreviewEvents;
window.handlePreviewError = function () {
const previewContent = document.getElementById("previewContent");
if (previewContent) {
previewContent.innerHTML = `
<div class="alert alert-error">
<Icon icon="heroicons:x-circle" className="h-6 w-6" />
<span>Failed to load file preview</span>
</div>
`;
}
};
}
};
</script>

View file

@ -249,8 +249,6 @@ const EventCheckIn = () => {
// Create the attendee record in PocketBase
const newAttendee = await update.create(Collections.EVENT_ATTENDEES, attendeeData);
console.log("Successfully created attendance record");
// Update user's total points
// First, get all the user's attendance records to calculate total points
const userAttendance = await get.getList<EventAttendee>(
@ -267,7 +265,7 @@ const EventCheckIn = () => {
});
// Log the points update
console.log(`Updating user points to: ${totalPoints}`);
// console.log(`Updating user points to: ${totalPoints}`);
// Update the user record with the new total points
await update.updateFields(Collections.USERS, userId, {

View file

@ -74,9 +74,9 @@ const EventLoad = () => {
// Clear events table
if (db && db.events) {
console.log("Clearing events cache...");
// console.log("Clearing events cache...");
await db.events.clear();
console.log("Events cache cleared successfully");
// console.log("Events cache cleared successfully");
}
// Reset sync timestamp for events by updating it to 0
@ -84,7 +84,7 @@ const EventLoad = () => {
const currentInfo = await dexieService.getLastSync(Collections.EVENTS);
// Then update it with a timestamp of 0 (forcing a fresh sync)
await dexieService.updateLastSync(Collections.EVENTS);
console.log("Events sync timestamp reset");
// console.log("Events sync timestamp reset");
// Reload events
setLoading(true);
@ -245,7 +245,7 @@ const EventLoad = () => {
const dataSync = DataSyncService.getInstance();
const auth = Authentication.getInstance();
console.log("Starting to load events...");
// console.log("Starting to load events...");
// Check if user is authenticated
if (!auth.isAuthenticated()) {
@ -255,7 +255,7 @@ const EventLoad = () => {
}
// Force sync to ensure we have the latest data
console.log("Syncing events collection...");
// console.log("Syncing events collection...");
let syncSuccess = false;
let retryCount = 0;
const maxRetries = 3;
@ -263,13 +263,13 @@ const EventLoad = () => {
while (!syncSuccess && retryCount < maxRetries) {
try {
if (retryCount > 0) {
console.log(`Retry attempt ${retryCount} of ${maxRetries}...`);
// console.log(`Retry attempt ${retryCount} of ${maxRetries}...`);
// Add a small delay between retries
await new Promise(resolve => setTimeout(resolve, 1000 * retryCount));
}
await dataSync.syncCollection(Collections.EVENTS, "published = true", "-start_date");
console.log("Events collection synced successfully");
// console.log("Events collection synced successfully");
syncSuccess = true;
} catch (syncError) {
retryCount++;
@ -282,7 +282,7 @@ const EventLoad = () => {
}
// Get events from IndexedDB
console.log("Fetching events from IndexedDB...");
// console.log("Fetching events from IndexedDB...");
const allEvents = await dataSync.getData<Event>(
Collections.EVENTS,
false, // Don't force sync again
@ -290,27 +290,27 @@ const EventLoad = () => {
"-start_date"
);
console.log(`Retrieved ${allEvents.length} events from IndexedDB`);
// console.log(`Retrieved ${allEvents.length} events from IndexedDB`);
// Filter out invalid events
const validEvents = allEvents.filter(event => isValidEvent(event));
console.log(`Filtered out ${allEvents.length - validEvents.length} invalid events`);
// console.log(`Filtered out ${allEvents.length - validEvents.length} invalid events`);
// If no valid events found in IndexedDB, try fetching directly from PocketBase as fallback
let eventsToProcess = validEvents;
if (allEvents.length === 0) {
console.log("No events found in IndexedDB, trying direct PocketBase fetch...");
// console.log("No events found in IndexedDB, trying direct PocketBase fetch...");
try {
const pbEvents = await get.getAll<Event>(
Collections.EVENTS,
"published = true",
"-start_date"
);
console.log(`Retrieved ${pbEvents.length} events directly from PocketBase`);
// console.log(`Retrieved ${pbEvents.length} events directly from PocketBase`);
// Filter out invalid events from PocketBase results
const validPbEvents = pbEvents.filter(event => isValidEvent(event));
console.log(`Filtered out ${pbEvents.length - validPbEvents.length} invalid events from PocketBase`);
// console.log(`Filtered out ${pbEvents.length - validPbEvents.length} invalid events from PocketBase`);
eventsToProcess = validPbEvents;
@ -319,7 +319,7 @@ const EventLoad = () => {
const dexieService = DexieService.getInstance();
const db = dexieService.getDB();
if (db && db.events) {
console.log(`Storing ${validPbEvents.length} valid PocketBase events in IndexedDB...`);
// console.log(`Storing ${validPbEvents.length} valid PocketBase events in IndexedDB...`);
await db.events.bulkPut(validPbEvents);
}
}
@ -329,7 +329,7 @@ const EventLoad = () => {
}
// Split events into upcoming, ongoing, and past based on start and end dates
console.log("Categorizing events...");
// console.log("Categorizing events...");
const now = new Date();
const { upcoming, ongoing, past } = eventsToProcess.reduce(
(acc, event) => {
@ -382,7 +382,7 @@ const EventLoad = () => {
}
);
console.log(`Categorized events: ${upcoming.length} upcoming, ${ongoing.length} ongoing, ${past.length} past`);
// console.log(`Categorized events: ${upcoming.length} upcoming, ${ongoing.length} ongoing, ${past.length} past`);
// Sort events
upcoming.sort((a, b) => new Date(a.start_date).getTime() - new Date(b.start_date).getTime());
@ -409,16 +409,16 @@ const EventLoad = () => {
// Try to load from IndexedDB only as a last resort
try {
console.log("Attempting to load events from IndexedDB only...");
// console.log("Attempting to load events from IndexedDB only...");
const dexieService = DexieService.getInstance();
const db = dexieService.getDB();
if (db && db.events) {
const allCachedEvents = await db.events.filter(event => event.published === true).toArray();
console.log(`Found ${allCachedEvents.length} cached events in IndexedDB`);
// console.log(`Found ${allCachedEvents.length} cached events in IndexedDB`);
// Filter out invalid events
const cachedEvents = allCachedEvents.filter(event => isValidEvent(event));
console.log(`Filtered out ${allCachedEvents.length - cachedEvents.length} invalid cached events`);
// console.log(`Filtered out ${allCachedEvents.length - cachedEvents.length} invalid cached events`);
if (cachedEvents.length > 0) {
// Process these events
@ -458,7 +458,7 @@ const EventLoad = () => {
ongoing: ongoing.slice(0, 50),
past: past.slice(0, 50)
});
console.log("Successfully loaded events from cache");
// console.log("Successfully loaded events from cache");
}
}
} catch (cacheError) {

File diff suppressed because it is too large Load diff

View file

@ -287,7 +287,7 @@ export default function Attendees() {
const fetchEventData = async () => {
if (!eventId || !auth.isAuthenticated()) {
if (!auth.isAuthenticated()) {
console.log('User not authenticated');
// console.log('User not authenticated');
setError('Authentication required');
}
return;

View file

@ -631,7 +631,7 @@ export default function EventEditor({ onEventSaved }: EventEditorProps) {
has_food: eventData.has_food || false
});
console.log("Event data loaded successfully:", eventData);
// console.log("Event data loaded successfully:", eventData);
} else {
setEvent({
id: '',
@ -784,7 +784,7 @@ export default function EventEditor({ onEventSaved }: EventEditorProps) {
// 1. Remove files marked for deletion
if (filesToDelete.size > 0) {
console.log(`Removing ${filesToDelete.size} files from event ${event.id}`);
// console.log(`Removing ${filesToDelete.size} files from event ${event.id}`);
currentFiles = currentFiles.filter(file => !filesToDelete.has(file));
// Update the files field first to remove deleted files
@ -797,7 +797,7 @@ export default function EventEditor({ onEventSaved }: EventEditorProps) {
// 2. Add new files one by one to preserve existing ones
if (selectedFiles.size > 0) {
console.log(`Adding ${selectedFiles.size} new files to event ${event.id}`);
// console.log(`Adding ${selectedFiles.size} new files to event ${event.id}`);
// Convert Map to array of File objects
const newFiles = Array.from(selectedFiles.values());
@ -849,7 +849,7 @@ export default function EventEditor({ onEventSaved }: EventEditorProps) {
// Then upload files if any
if (selectedFiles.size > 0 && newEvent?.id) {
console.log(`Adding ${selectedFiles.size} files to new event ${newEvent.id}`);
// console.log(`Adding ${selectedFiles.size} files to new event ${newEvent.id}`);
// Convert Map to array of File objects
const newFiles = Array.from(selectedFiles.values());

View file

@ -25,313 +25,295 @@ let error: string | null = null;
// This provides initial data for server-side rendering
// Client-side will use IndexedDB for data management
if (auth.isAuthenticated()) {
try {
const userId = auth.getUserId();
if (userId) {
userEventRequests = await get.getAll<EventRequest>(
Collections.EVENT_REQUESTS,
`requested_user="${userId}"`,
"-created"
);
}
} catch (err) {
console.error("Failed to fetch user event requests:", err);
error = "Failed to load your event requests. Please try again later.";
try {
const userId = auth.getUserId();
if (userId) {
userEventRequests = await get.getAll<EventRequest>(
Collections.EVENT_REQUESTS,
`requested_user="${userId}"`,
"-created",
);
}
} catch (err) {
console.error("Failed to fetch user event requests:", err);
error = "Failed to load your event requests. Please try again later.";
}
}
---
<div class="w-full max-w-6xl mx-auto py-8 px-4">
<div class="mb-8">
<h1 class="text-3xl font-bold text-white mb-2">Event Request Form</h1>
<p class="text-gray-300 mb-4">
Submit your event request at least 6 weeks before your event. After
submitting, please notify PR and/or Coordinators in the #-events
Slack channel.
</p>
<div class="bg-base-300/50 p-4 rounded-lg text-sm text-gray-300">
<p class="font-medium mb-2">This form includes sections for:</p>
<ul class="list-disc list-inside space-y-1 ml-2">
<li>PR Materials (if needed)</li>
<li>Event Details</li>
<li>TAP Form Information</li>
<li>AS Funding (if needed)</li>
</ul>
<p class="mt-3">
Your progress is automatically saved as you fill out the form.
</p>
</div>
<div class="mb-8">
<h1 class="text-3xl font-bold text-white mb-2">Event Request Form</h1>
<p class="text-gray-300 mb-4">
Submit your event request at least 6 weeks before your event. After
submitting, please notify PR and/or Coordinators in the #-events Slack
channel.
</p>
<div class="bg-base-300/50 p-4 rounded-lg text-sm text-gray-300">
<p class="font-medium mb-2">This form includes sections for:</p>
<ul class="list-disc list-inside space-y-1 ml-2">
<li>PR Materials (if needed)</li>
<li>Event Details</li>
<li>TAP Form Information</li>
<li>AS Funding (if needed)</li>
</ul>
<p class="mt-3">
Your progress is automatically saved as you fill out the form.
</p>
</div>
</div>
<!-- Tabs -->
<div class="tabs tabs-boxed mb-6">
<a class="tab tab-lg tab-active" id="form-tab">Submit Event Request</a>
<a class="tab tab-lg" id="submissions-tab">View Your Submissions</a>
<!-- Tabs -->
<div class="tabs tabs-boxed mb-6">
<a class="tab tab-lg tab-active" id="form-tab">Submit Event Request</a>
<a class="tab tab-lg" id="submissions-tab">View Your Submissions</a>
</div>
<!-- Form Tab Content -->
<div
id="form-content"
class="bg-base-200 rounded-lg shadow-xl overflow-hidden"
>
<div class="p-6">
<EventRequestForm client:load />
</div>
</div>
<!-- Form Tab Content -->
<div
id="form-content"
class="bg-base-200 rounded-lg shadow-xl overflow-hidden"
>
<div class="p-6">
<EventRequestForm client:load />
</div>
</div>
<!-- Submissions Tab Content -->
<div id="submissions-content" class="hidden">
<div class="bg-base-200 rounded-lg shadow-xl overflow-hidden p-6">
<h2 class="text-2xl font-bold text-white mb-4">
Your Event Request Submissions
</h2>
{
error && (
<div class="alert alert-error mb-6">
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-6 w-6 stroke-current shrink-0"
fill="none"
viewBox="0 0 24 24"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z"
/>
</svg>
<span>{error}</span>
</div>
)
}
{
!error && (
<UserEventRequests
client:load
eventRequests={userEventRequests}
/>
)
}
</div>
<!-- Submissions Tab Content -->
<div id="submissions-content" class="hidden">
<div class="bg-base-200 rounded-lg shadow-xl overflow-hidden p-6">
<h2 class="text-2xl font-bold text-white mb-4">
Your Event Request Submissions
</h2>
{
error && (
<div class="alert alert-error mb-6">
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-6 w-6 stroke-current shrink-0"
fill="none"
viewBox="0 0 24 24"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z"
/>
</svg>
<span>{error}</span>
</div>
)
}
{
!error && (
<UserEventRequests client:load eventRequests={userEventRequests} />
)
}
</div>
</div>
</div>
<style is:global>
/* Ensure the modal container is always visible */
#event-request-preview-modal-container {
position: fixed !important;
top: 0 !important;
left: 0 !important;
width: 100vw !important;
height: 100vh !important;
z-index: 99999 !important;
overflow: auto !important;
margin: 0 !important;
padding: 0 !important;
}
/* Ensure the modal container is always visible */
#event-request-preview-modal-container {
position: fixed !important;
top: 0 !important;
left: 0 !important;
width: 100vw !important;
height: 100vh !important;
z-index: 99999 !important;
overflow: auto !important;
margin: 0 !important;
padding: 0 !important;
}
/* Style for the modal backdrop */
#event-request-preview-modal-container > div > div:first-child {
position: fixed !important;
top: 0 !important;
left: 0 !important;
width: 100vw !important;
height: 100vh !important;
z-index: 99999 !important;
background-color: rgba(0, 0, 0, 0.8) !important;
backdrop-filter: blur(8px) !important;
display: flex !important;
align-items: center !important;
justify-content: center !important;
overflow: auto !important;
}
/* Style for the modal backdrop */
#event-request-preview-modal-container > div > div:first-child {
position: fixed !important;
top: 0 !important;
left: 0 !important;
width: 100vw !important;
height: 100vh !important;
z-index: 99999 !important;
background-color: rgba(0, 0, 0, 0.8) !important;
backdrop-filter: blur(8px) !important;
display: flex !important;
align-items: center !important;
justify-content: center !important;
overflow: auto !important;
}
/* Style for the modal content */
#event-request-preview-modal-container > div > div > div {
z-index: 100000 !important;
position: relative !important;
max-width: 90vw !important;
width: 100% !important;
max-height: 90vh !important;
overflow: auto !important;
margin: 2rem !important;
}
/* Style for the modal content */
#event-request-preview-modal-container > div > div > div {
z-index: 100000 !important;
position: relative !important;
max-width: 90vw !important;
width: 100% !important;
max-height: 90vh !important;
overflow: auto !important;
margin: 2rem !important;
}
</style>
<!-- Add the modal component -->
<EventRequestFormPreviewModal client:load />
<div class="dashboard-section hidden" id="eventRequestFormSection">
<!-- ... existing code ... -->
<!-- ... existing code ... -->
</div>
<script is:inline>
// Define the global function immediately to ensure it's available
window.showEventRequestFormPreview = function (formData) {
console.log(
"Global showEventRequestFormPreview called with data",
formData
);
// Define the global function immediately to ensure it's available
window.showEventRequestFormPreview = function (formData) {
// console.log(
// "Global showEventRequestFormPreview called with data",
// formData
// );
// Remove any elements that might be obstructing the view
const removeObstructions = () => {
// Find any elements with high z-index that might be obstructing
document.querySelectorAll('[style*="z-index"]').forEach((el) => {
if (
el.id !== "event-request-preview-modal-container" &&
!el.closest("#event-request-preview-modal-container")
) {
// Store original z-index to restore later
if (!el.dataset.originalZIndex) {
el.dataset.originalZIndex = el.style.zIndex;
}
// Temporarily lower z-index
el.style.zIndex = "0";
}
});
};
// Create a custom event to trigger the preview
const event = new CustomEvent("showEventRequestPreviewModal", {
detail: { formData },
});
// Remove obstructions before showing modal
removeObstructions();
// Dispatch event to show modal
document.dispatchEvent(event);
console.log("showEventRequestPreviewModal event dispatched");
// Ensure modal container is visible
setTimeout(() => {
const modalContainer = document.getElementById(
"event-request-preview-modal-container"
);
if (modalContainer) {
modalContainer.style.zIndex = "99999";
modalContainer.style.position = "fixed";
modalContainer.style.top = "0";
modalContainer.style.left = "0";
modalContainer.style.width = "100vw";
modalContainer.style.height = "100vh";
modalContainer.style.overflow = "auto";
modalContainer.style.margin = "0";
modalContainer.style.padding = "0";
// Force body to allow scrolling
document.body.style.overflow = "auto";
// Ensure the modal content is properly sized
const modalContent =
modalContainer.querySelector("div > div > div");
if (modalContent) {
modalContent.style.maxWidth = "90vw";
modalContent.style.width = "100%";
modalContent.style.maxHeight = "90vh";
modalContent.style.overflow = "auto";
modalContent.style.margin = "2rem";
}
}
}, 100);
// Remove any elements that might be obstructing the view
const removeObstructions = () => {
// Find any elements with high z-index that might be obstructing
document.querySelectorAll('[style*="z-index"]').forEach((el) => {
if (
el.id !== "event-request-preview-modal-container" &&
!el.closest("#event-request-preview-modal-container")
) {
// Store original z-index to restore later
if (!el.dataset.originalZIndex) {
el.dataset.originalZIndex = el.style.zIndex;
}
// Temporarily lower z-index
el.style.zIndex = "0";
}
});
};
// Create a custom event to trigger the preview
const event = new CustomEvent("showEventRequestPreviewModal", {
detail: { formData },
});
// Remove obstructions before showing modal
removeObstructions();
// Dispatch event to show modal
document.dispatchEvent(event);
// console.log("showEventRequestPreviewModal event dispatched");
// Ensure modal container is visible
setTimeout(() => {
const modalContainer = document.getElementById(
"event-request-preview-modal-container",
);
if (modalContainer) {
modalContainer.style.zIndex = "99999";
modalContainer.style.position = "fixed";
modalContainer.style.top = "0";
modalContainer.style.left = "0";
modalContainer.style.width = "100vw";
modalContainer.style.height = "100vh";
modalContainer.style.overflow = "auto";
modalContainer.style.margin = "0";
modalContainer.style.padding = "0";
// Force body to allow scrolling
document.body.style.overflow = "auto";
// Ensure the modal content is properly sized
const modalContent = modalContainer.querySelector("div > div > div");
if (modalContent) {
modalContent.style.maxWidth = "90vw";
modalContent.style.width = "100%";
modalContent.style.maxHeight = "90vh";
modalContent.style.overflow = "auto";
modalContent.style.margin = "2rem";
}
}
}, 100);
};
</script>
<script>
// Import the DataSyncService for client-side use
import { DataSyncService } from "../../scripts/database/DataSyncService";
import { Collections } from "../../schemas/pocketbase/schema";
import { Authentication } from "../../scripts/pocketbase/Authentication";
// Import the DataSyncService for client-side use
import { DataSyncService } from "../../scripts/database/DataSyncService";
import { Collections } from "../../schemas/pocketbase/schema";
import { Authentication } from "../../scripts/pocketbase/Authentication";
// Tab switching logic
document.addEventListener("DOMContentLoaded", async () => {
// Initialize DataSyncService for client-side
const dataSync = DataSyncService.getInstance();
const auth = Authentication.getInstance();
// Tab switching logic
document.addEventListener("DOMContentLoaded", async () => {
// Initialize DataSyncService for client-side
const dataSync = DataSyncService.getInstance();
const auth = Authentication.getInstance();
// Prefetch data into IndexedDB if authenticated
if (auth.isAuthenticated()) {
try {
const userId = auth.getUserId();
if (userId) {
// Force sync to ensure we have the latest data
await dataSync.syncCollection(
Collections.EVENT_REQUESTS,
`requested_user="${userId}"`,
"-created"
);
console.log(
"Initial data sync complete for user event requests"
);
}
} catch (err) {
console.error("Error during initial data sync:", err);
}
// Prefetch data into IndexedDB if authenticated
if (auth.isAuthenticated()) {
try {
const userId = auth.getUserId();
if (userId) {
// Force sync to ensure we have the latest data
await dataSync.syncCollection(
Collections.EVENT_REQUESTS,
`requested_user="${userId}"`,
"-created",
);
// console.log("Initial data sync complete for user event requests");
}
} catch (err) {
// console.error("Error during initial data sync:", err);
}
}
const formTab = document.getElementById("form-tab");
const submissionsTab = document.getElementById("submissions-tab");
const formContent = document.getElementById("form-content");
const submissionsContent = document.getElementById(
"submissions-content"
);
const formTab = document.getElementById("form-tab");
const submissionsTab = document.getElementById("submissions-tab");
const formContent = document.getElementById("form-content");
const submissionsContent = document.getElementById("submissions-content");
// Function to switch tabs
const switchTab = (
activeTab: HTMLElement,
activeContent: HTMLElement,
inactiveTab: HTMLElement,
inactiveContent: HTMLElement
) => {
// Update tab classes
activeTab.classList.add("tab-active");
inactiveTab.classList.remove("tab-active");
// Function to switch tabs
const switchTab = (
activeTab: HTMLElement,
activeContent: HTMLElement,
inactiveTab: HTMLElement,
inactiveContent: HTMLElement,
) => {
// Update tab classes
activeTab.classList.add("tab-active");
inactiveTab.classList.remove("tab-active");
// Show/hide content
activeContent.classList.remove("hidden");
inactiveContent.classList.add("hidden");
// Show/hide content
activeContent.classList.remove("hidden");
inactiveContent.classList.add("hidden");
// Dispatch event to refresh submissions when switching to submissions tab
if (activeTab.id === "submissions-tab") {
// Dispatch a custom event that the UserEventRequests component listens for
document.dispatchEvent(new CustomEvent("dashboardTabVisible"));
}
};
// Dispatch event to refresh submissions when switching to submissions tab
if (activeTab.id === "submissions-tab") {
// Dispatch a custom event that the UserEventRequests component listens for
document.dispatchEvent(new CustomEvent("dashboardTabVisible"));
}
};
// Add click event listeners to tabs
formTab?.addEventListener("click", (e) => {
e.preventDefault();
if (formContent && submissionsContent && submissionsTab) {
switchTab(
formTab,
formContent,
submissionsTab,
submissionsContent
);
}
});
submissionsTab?.addEventListener("click", (e) => {
e.preventDefault();
if (formContent && submissionsContent && formTab) {
switchTab(
submissionsTab,
submissionsContent,
formTab,
formContent
);
}
});
// Listen for visibility changes
document.addEventListener("visibilitychange", () => {
if (document.visibilityState === "visible") {
// Dispatch custom event that components can listen for
document.dispatchEvent(new CustomEvent("dashboardTabVisible"));
}
});
// Add click event listeners to tabs
formTab?.addEventListener("click", (e) => {
e.preventDefault();
if (formContent && submissionsContent && submissionsTab) {
switchTab(formTab, formContent, submissionsTab, submissionsContent);
}
});
submissionsTab?.addEventListener("click", (e) => {
e.preventDefault();
if (formContent && submissionsContent && formTab) {
switchTab(submissionsTab, submissionsContent, formTab, formContent);
}
});
// Listen for visibility changes
document.addEventListener("visibilitychange", () => {
if (document.visibilityState === "visible") {
// Dispatch custom event that components can listen for
document.dispatchEvent(new CustomEvent("dashboardTabVisible"));
}
});
});
</script>

View file

@ -12,7 +12,7 @@ export const EventRequestFormPreviewModal: React.FC = () => {
// Function to handle showing the modal
const showModal = (data: any) => {
console.log('showModal called with data', data);
// console.log('showModal called with data', data);
setFormData(data);
setIsOpen(true);
};
@ -24,23 +24,23 @@ export const EventRequestFormPreviewModal: React.FC = () => {
// Define the global function
window.showEventRequestFormPreview = (data: any) => {
console.log('Global showEventRequestFormPreview called with data', data);
// console.log('Global showEventRequestFormPreview called with data', data);
showModal(data);
};
// Listen for the custom event as a fallback
const handleShowModal = (event: CustomEvent) => {
console.log('Received showEventRequestPreviewModal event', event.detail);
// console.log('Received showEventRequestPreviewModal event', event.detail);
if (event.detail && event.detail.formData) {
showModal(event.detail.formData);
} else {
console.error('Event detail or formData is missing', event.detail);
// console.error('Event detail or formData is missing', event.detail);
}
};
// Add event listener
document.addEventListener('showEventRequestPreviewModal', handleShowModal as EventListener);
console.log('Event listener for showEventRequestPreviewModal added');
// console.log('Event listener for showEventRequestPreviewModal added');
// Clean up
return () => {
@ -53,12 +53,12 @@ export const EventRequestFormPreviewModal: React.FC = () => {
}
document.removeEventListener('showEventRequestPreviewModal', handleShowModal as EventListener);
console.log('Event listener for showEventRequestPreviewModal removed');
// console.log('Event listener for showEventRequestPreviewModal removed');
};
}, []); // Empty dependency array - only run once on mount
const handleClose = () => {
console.log('Modal closed');
// console.log('Modal closed');
setIsOpen(false);
};
@ -122,7 +122,7 @@ const EventRequestFormPreview: React.FC<EventRequestFormPreviewProps> = ({
const parsedData = JSON.parse(savedData);
setFormData(parsedData);
} catch (e) {
console.error('Error parsing saved form data:', e);
// console.error('Error parsing saved form data:', e);
}
}
setLoading(false);

View file

@ -69,7 +69,7 @@ const UserEventRequests: React.FC<UserEventRequestsProps> = ({ eventRequests: in
// Listen for tab visibility changes and refresh data when tab becomes visible
useEffect(() => {
const handleTabVisible = () => {
console.log("Tab became visible, refreshing event requests...");
// console.log("Tab became visible, refreshing event requests...");
refreshEventRequests();
};
@ -411,19 +411,19 @@ const UserEventRequests: React.FC<UserEventRequestsProps> = ({ eventRequests: in
className="btn btn-sm btn-primary"
onClick={(e) => {
e.stopPropagation();
console.log('Full Preview button clicked', selectedRequest);
// console.log('Full Preview button clicked', selectedRequest);
try {
// Direct call to the global function
if (typeof window.showEventRequestFormPreview === 'function') {
window.showEventRequestFormPreview(selectedRequest);
} else {
console.error('showEventRequestFormPreview is not a function', window.showEventRequestFormPreview);
// console.log('Fallback: showEventRequestPreviewModal event dispatched');
// Fallback to event dispatch if function is not available
const event = new CustomEvent("showEventRequestPreviewModal", {
detail: { formData: selectedRequest }
});
document.dispatchEvent(event);
console.log('Fallback: showEventRequestPreviewModal event dispatched');
// console.log('Fallback: showEventRequestPreviewModal event dispatched');
}
} catch (error) {
console.error('Error showing full preview:', error);

View file

@ -37,7 +37,7 @@ try {
// Don't check authentication here - let the client component handle it
// The server-side check is causing issues when the token is valid client-side but not server-side
console.log("Fetching event requests in Astro component...");
// console.log("Fetching event requests in Astro component...");
// Expand the requested_user field to get user details
allEventRequests = await get
.getAll<ExtendedEventRequest>(Collections.EVENT_REQUESTS, "", "-created", {
@ -49,9 +49,9 @@ try {
return [];
});
console.log(
`Fetched ${allEventRequests.length} event requests in Astro component`,
);
// console.log(
// `Fetched ${allEventRequests.length} event requests in Astro component`,
// );
// Process the event requests to add the requested_user_expand property
allEventRequests = allEventRequests.map((request) => {
@ -172,9 +172,9 @@ try {
"-created",
{ expand: "requested_user" },
);
console.log("Initial data sync complete");
// console.log("Initial data sync complete");
} catch (err) {
console.error("Error during initial data sync:", err);
// console.error("Error during initial data sync:", err);
}
// Check for error message in the UI
@ -183,9 +183,9 @@ try {
errorElement &&
errorElement.textContent?.includes("Authentication error")
) {
console.log(
"Authentication error detected in UI, redirecting to login...",
);
// console.log(
// "Authentication error detected in UI, redirecting to login...",
// );
// Redirect to login page after a short delay
setTimeout(() => {
window.location.href = "/login";
@ -196,13 +196,13 @@ try {
// Also check if we have any event requests
const tableContainer = document.querySelector(".event-table-container");
if (tableContainer) {
console.log(
"Event table container found, component should load normally",
);
// console.log(
// "Event table container found, component should load normally",
// );
} else {
console.log(
"Event table container not found, might be an issue with rendering",
);
// console.log(
// "Event table container not found, might be an issue with rendering",
// );
}
});
</script>

View file

@ -56,7 +56,7 @@ const EventRequestManagementTable = ({ eventRequests: initialEventRequests }: Ev
// Don't check authentication here - try to fetch anyway
// The token might be valid for the API even if isAuthenticated() returns false
console.log("Fetching event requests...");
// console.log("Fetching event requests...");
// Use DataSyncService to get data from IndexedDB with forced sync
const updatedRequests = await dataSync.getData<ExtendedEventRequest>(
@ -67,12 +67,12 @@ const EventRequestManagementTable = ({ eventRequests: initialEventRequests }: Ev
'requested_user'
);
console.log(`Fetched ${updatedRequests.length} event requests`);
// console.log(`Fetched ${updatedRequests.length} event requests`);
setEventRequests(updatedRequests);
applyFilters(updatedRequests);
} catch (error) {
console.error('Error refreshing event requests:', error);
// console.error('Error refreshing event requests:', error);
toast.error('Failed to refresh event requests');
} finally {
setIsRefreshing(false);
@ -169,7 +169,7 @@ const EventRequestManagementTable = ({ eventRequests: initialEventRequests }: Ev
const eventRequest = eventRequests.find(req => req.id === id);
const eventName = eventRequest?.name || 'Event';
console.error('Error updating status:', error);
// console.error('Error updating status:', error);
toast.error(`Failed to update status for "${eventName}"`);
throw error; // Re-throw the error to be caught by the caller
}
@ -242,7 +242,7 @@ const EventRequestManagementTable = ({ eventRequests: initialEventRequests }: Ev
// Toast is now shown in updateEventRequestStatus
closeUpdateModal();
} catch (error) {
console.error('Error in handleUpdateStatus:', error);
// console.error('Error in handleUpdateStatus:', error);
// Toast is now shown in updateEventRequestStatus
// Keep modal open so user can try again
}
@ -273,14 +273,14 @@ const EventRequestManagementTable = ({ eventRequests: initialEventRequests }: Ev
// Check if we're authenticated
if (!auth.isAuthenticated()) {
console.log("Authentication check failed - attempting to continue anyway");
// console.log("Authentication check failed - attempting to continue anyway");
// Don't show error or redirect immediately - try to refresh first
try {
// Try to refresh event requests anyway - the token might be valid
await refreshEventRequests();
} catch (err) {
console.error("Failed to refresh after auth check:", err);
// console.error("Failed to refresh after auth check:", err);
toast.error("Authentication error. Please log in again.");
// Only redirect if refresh fails
@ -289,7 +289,7 @@ const EventRequestManagementTable = ({ eventRequests: initialEventRequests }: Ev
}, 2000);
}
} else {
console.log("Authentication check passed");
// console.log("Authentication check passed");
}
};
@ -304,7 +304,7 @@ const EventRequestManagementTable = ({ eventRequests: initialEventRequests }: Ev
// Listen for tab visibility changes and refresh data when tab becomes visible
useEffect(() => {
const handleTabVisible = () => {
console.log("Tab became visible, refreshing event requests...");
// console.log("Tab became visible, refreshing event requests...");
refreshEventRequests();
};

View file

@ -49,7 +49,7 @@ export default function ShowProfileLogs() {
try {
setIsFetchingAll(true);
console.log("Fetching logs for user:", userId);
// console.log("Fetching logs for user:", userId);
// Use DataSyncService to fetch logs
const dataSync = DataSyncService.getInstance();
@ -70,15 +70,15 @@ export default function ShowProfileLogs() {
"-created"
);
console.log("Fetched logs:", fetchedLogs.length);
// console.log("Fetched logs:", fetchedLogs.length);
if (fetchedLogs.length === 0) {
// If no logs found, try to fetch directly from PocketBase
console.log("No logs found in IndexedDB, trying direct fetch from PocketBase");
// console.log("No logs found in IndexedDB, trying direct fetch from PocketBase");
try {
const sendLog = SendLog.getInstance();
const directLogs = await sendLog.getUserLogs(userId);
console.log("Direct fetch logs:", directLogs.length);
// console.log("Direct fetch logs:", directLogs.length);
if (directLogs.length > 0) {
setAllLogs(directLogs);
@ -90,7 +90,7 @@ export default function ShowProfileLogs() {
setTotalLogs(fetchedLogs.length);
}
} catch (directError) {
console.error("Failed to fetch logs directly:", directError);
// console.error("Failed to fetch logs directly:", directError);
setAllLogs(fetchedLogs);
setTotalPages(Math.ceil(fetchedLogs.length / LOGS_PER_PAGE));
setTotalLogs(fetchedLogs.length);
@ -101,7 +101,7 @@ export default function ShowProfileLogs() {
setTotalLogs(fetchedLogs.length);
}
} catch (error) {
console.error("Failed to fetch logs:", error);
// console.error("Failed to fetch logs:", error);
setError("Error loading activity");
} finally {
setLoading(false);
@ -134,7 +134,7 @@ export default function ShowProfileLogs() {
// Update displayed logs whenever filtered results change
useEffect(() => {
setLogs(filteredLogs);
console.log("Filtered logs updated:", filteredLogs.length, "logs");
// console.log("Filtered logs updated:", filteredLogs.length, "logs");
}, [filteredLogs]);
// Debounced search handler
@ -178,12 +178,12 @@ export default function ShowProfileLogs() {
setTimeout(async () => {
// Check if logs were loaded
if (allLogs.length === 0) {
console.log("No logs found after initial fetch, trying direct fetch");
// console.log("No logs found after initial fetch, trying direct fetch");
await directFetchLogs();
}
}, 1000);
} catch (error) {
console.error("Failed to load logs with retry:", error);
// console.error("Failed to load logs with retry:", error);
}
};
@ -200,14 +200,14 @@ export default function ShowProfileLogs() {
// Check if the logs collection exists and has any records
const result = await pb.collection(Collections.LOGS).getList(1, 1);
console.log("Logs collection check:", {
totalItems: result.totalItems,
page: result.page,
perPage: result.perPage,
totalPages: result.totalPages
});
// console.log("Logs collection check:", {
// totalItems: result.totalItems,
// page: result.page,
// perPage: result.perPage,
// totalPages: result.totalPages
// });
} catch (error) {
console.error("Failed to check logs collection:", error);
// console.error("Failed to check logs collection:", error);
}
};
@ -255,7 +255,7 @@ export default function ShowProfileLogs() {
return;
}
console.log("Direct fetching logs for user:", userId);
// console.log("Direct fetching logs for user:", userId);
// Fetch logs directly from PocketBase
const result = await pb.collection(Collections.LOGS).getList<Log>(1, 100, {
@ -264,10 +264,10 @@ export default function ShowProfileLogs() {
expand: "user"
});
console.log("Direct fetch result:", {
totalItems: result.totalItems,
items: result.items.length
});
// console.log("Direct fetch result:", {
// totalItems: result.totalItems,
// items: result.items.length
// });
if (result.items.length > 0) {
setAllLogs(result.items);
@ -275,7 +275,7 @@ export default function ShowProfileLogs() {
setTotalLogs(result.items.length);
}
} catch (error) {
console.error("Failed to direct fetch logs:", error);
// console.error("Failed to direct fetch logs:", error);
setError("Error loading activity");
} finally {
setLoading(false);
@ -315,13 +315,13 @@ export default function ShowProfileLogs() {
}
// Debug logs
console.log("Render state:", {
logsLength: logs.length,
allLogsLength: allLogs.length,
searchQuery,
loading,
currentPage
});
// console.log("Render state:", {
// logsLength: logs.length,
// allLogsLength: allLogs.length,
// searchQuery,
// loading,
// currentPage
// });
if (allLogs.length === 0 && !searchQuery && !loading) {
return (
@ -348,10 +348,10 @@ export default function ShowProfileLogs() {
"Test log created for debugging",
userId
);
console.log("Created test log");
// console.log("Created test log");
setTimeout(() => fetchLogs(true), 1000);
} catch (error) {
console.error("Failed to create test log:", error);
// console.error("Failed to create test log:", error);
}
}}
>

View file

@ -13,14 +13,6 @@ const logtoEndpoint = import.meta.env.LOGTO_ENDPOINT;
const logtoTokenEndpoint = import.meta.env.LOGTO_TOKEN_ENDPOINT;
const logtoApiEndpoint = import.meta.env.LOGTO_API_ENDPOINT;
// Log environment variables for debugging
console.log("Environment variables in Astro file:");
console.log("LOGTO_APP_ID:", logtoAppId);
console.log("LOGTO_APP_SECRET:", logtoAppSecret);
console.log("LOGTO_ENDPOINT:", logtoEndpoint);
console.log("LOGTO_TOKEN_ENDPOINT:", logtoTokenEndpoint);
console.log("LOGTO_API_ENDPOINT:", logtoApiEndpoint);
// Define fallback values if environment variables are not set
const safeLogtoAppId = logtoAppId || "missing_app_id";
const safeLogtoAppSecret = logtoAppSecret || "missing_app_secret";

View file

@ -162,7 +162,7 @@ export default function DisplaySettings() {
if (Object.keys(updateData).length > 0) {
await update.updateFields(Collections.USERS, userId, updateData);
console.log('Initialized default display and accessibility settings');
// console.log('Initialized default display and accessibility settings');
}
} catch (error) {
console.error('Error initializing default settings:', error);

View file

@ -67,7 +67,7 @@ export default function NotificationSettings() {
{ notification_preferences: JSON.stringify(DEFAULT_NOTIFICATION_PREFERENCES) }
);
setPreferences(DEFAULT_NOTIFICATION_PREFERENCES);
console.log('Initialized default notification preferences');
// console.log('Initialized default notification preferences');
} catch (error) {
console.error('Error initializing default notification preferences:', error);
}

View file

@ -45,29 +45,7 @@ export default function PasswordChangeSettings({
const logtoTokenEndpoint = envLogtoTokenEndpoint || propLogtoTokenEndpoint;
const logtoApiEndpoint = envLogtoApiEndpoint || propLogtoApiEndpoint;
// Log props and environment variables for debugging
useEffect(() => {
console.log("PasswordChangeSettings props and env vars:");
console.log("Props - logtoAppId:", propLogtoAppId);
console.log("Props - logtoAppSecret:", propLogtoAppSecret);
console.log("Props - logtoEndpoint:", propLogtoEndpoint);
console.log("Props - logtoTokenEndpoint:", propLogtoTokenEndpoint);
console.log("Props - logtoApiEndpoint:", propLogtoApiEndpoint);
console.log("Env - LOGTO_APP_ID:", envLogtoAppId);
console.log("Env - LOGTO_APP_SECRET:", envLogtoAppSecret);
console.log("Env - LOGTO_ENDPOINT:", envLogtoEndpoint);
console.log("Env - LOGTO_TOKEN_ENDPOINT:", envLogtoTokenEndpoint);
console.log("Env - LOGTO_API_ENDPOINT:", envLogtoApiEndpoint);
console.log("Using - logtoAppId:", logtoAppId);
console.log("Using - logtoAppSecret:", logtoAppSecret);
console.log("Using - logtoEndpoint:", logtoEndpoint);
console.log("Using - logtoTokenEndpoint:", logtoTokenEndpoint);
console.log("Using - logtoApiEndpoint:", logtoApiEndpoint);
}, [
propLogtoAppId, propLogtoAppSecret, propLogtoEndpoint, propLogtoTokenEndpoint, propLogtoApiEndpoint,
envLogtoAppId, envLogtoAppSecret, envLogtoEndpoint, envLogtoTokenEndpoint, envLogtoApiEndpoint,
logtoAppId, logtoAppSecret, logtoEndpoint, logtoTokenEndpoint, logtoApiEndpoint
]);
// Get the user's Logto ID on component mount
useEffect(() => {
@ -80,17 +58,17 @@ export default function PasswordChangeSettings({
return;
}
console.log("Current user:", user);
// console.log("Current user:", user);
const pb = auth.getPocketBase();
try {
const externalAuthRecord = await pb.collection('_externalAuths').getFirstListItem(`recordRef="${user.id}" && provider="oidc"`);
console.log("Found external auth record:", externalAuthRecord);
// console.log("Found external auth record:", externalAuthRecord);
const userId = externalAuthRecord.providerId;
if (userId) {
setLogtoUserId(userId);
console.log("Set Logto user ID:", userId);
// console.log("Set Logto user ID:", userId);
} else {
console.error("No providerId found in external auth record");
toast.error("Could not determine your user ID. Please try again later or contact support.");
@ -153,7 +131,7 @@ export default function PasswordChangeSettings({
try {
const response = await fetch('/api/check-env');
const data = await response.json();
console.log("Environment variables status:", data);
// console.log("Environment variables status:", data);
// Check if all required environment variables are set
const { envStatus } = data;
@ -244,7 +222,7 @@ export default function PasswordChangeSettings({
const iframeDocument = iframe.contentDocument || iframe.contentWindow?.document;
if (iframeDocument) {
const responseText = iframeDocument.body.innerText;
console.log("Response from iframe:", responseText);
// console.log("Response from iframe:", responseText);
if (responseText) {
try {
@ -308,7 +286,7 @@ export default function PasswordChangeSettings({
} else {
// Use the fetch API with JSON
const endpoint = '/api/change-password';
console.log(`Calling server-side API endpoint: ${endpoint}`);
// console.log(`Calling server-side API endpoint: ${endpoint}`);
// Ensure we have the Logto user ID
if (!logtoUserId) {
@ -317,13 +295,13 @@ export default function PasswordChangeSettings({
}
// Log the values we're about to use
console.log("Values being used for API call:");
console.log("- logtoUserId:", logtoUserId);
console.log("- newPassword:", formData.newPassword ? "[PRESENT]" : "[MISSING]");
console.log("- logtoAppId:", logtoAppId);
console.log("- logtoAppSecret:", logtoAppSecret ? "[PRESENT]" : "[MISSING]");
console.log("- logtoTokenEndpoint:", logtoTokenEndpoint);
console.log("- logtoApiEndpoint:", logtoApiEndpoint);
// console.log("Values being used for API call:");
// console.log("- logtoUserId:", logtoUserId);
// console.log("- newPassword:", formData.newPassword ? "[PRESENT]" : "[MISSING]");
// console.log("- logtoAppId:", logtoAppId);
// console.log("- logtoAppSecret:", logtoAppSecret ? "[PRESENT]" : "[MISSING]");
// console.log("- logtoTokenEndpoint:", logtoTokenEndpoint);
// console.log("- logtoApiEndpoint:", logtoApiEndpoint);
// Prepare request data with explicit values (not relying on variable references that might be undefined)
const requestData = {
@ -336,12 +314,12 @@ export default function PasswordChangeSettings({
logtoApiEndpoint: logtoApiEndpoint || logtoEndpoint
};
console.log("Request data:", {
...requestData,
currentPassword: "[REDACTED]",
newPassword: "[REDACTED]",
logtoAppSecret: "[REDACTED]"
});
// console.log("Request data:", {
// ...requestData,
// currentPassword: "[REDACTED]",
// newPassword: "[REDACTED]",
// logtoAppSecret: "[REDACTED]"
// });
// Validate request data before sending
if (!requestData.userId) {
@ -368,7 +346,7 @@ export default function PasswordChangeSettings({
// Stringify the request data to ensure it's valid JSON
const requestBody = JSON.stringify(requestData);
console.log("Request body (stringified):", requestBody);
// console.log("Request body (stringified):", requestBody);
// Create a debug object to display in the UI
const debugObj = {
@ -394,13 +372,13 @@ export default function PasswordChangeSettings({
body: requestBody
});
console.log("Response status:", response.status);
// console.log("Response status:", response.status);
// Process the response
let result: any;
try {
const responseText = await response.text();
console.log("Raw response:", responseText);
// console.log("Raw response:", responseText);
if (responseText) {
result = JSON.parse(responseText);
@ -408,7 +386,7 @@ export default function PasswordChangeSettings({
result = { success: false, message: 'Empty response from server' };
}
console.log("API response:", result);
// console.log("API response:", result);
// Add response to debug info
setDebugInfo((prev: any) => ({
@ -470,13 +448,13 @@ export default function PasswordChangeSettings({
type="button"
className="btn btn-sm btn-warning"
onClick={() => {
console.log("Debug Info:");
console.log("- logtoUserId:", logtoUserId);
console.log("- Environment Variables:");
console.log(" - LOGTO_APP_ID:", import.meta.env.LOGTO_APP_ID);
console.log(" - LOGTO_ENDPOINT:", import.meta.env.LOGTO_ENDPOINT);
console.log(" - LOGTO_TOKEN_ENDPOINT:", import.meta.env.LOGTO_TOKEN_ENDPOINT);
console.log(" - LOGTO_API_ENDPOINT:", import.meta.env.LOGTO_API_ENDPOINT);
// console.log("Debug Info:");
// console.log("- logtoUserId:", logtoUserId);
// console.log("- Environment Variables:");
// console.log(" - LOGTO_APP_ID:", import.meta.env.LOGTO_APP_ID);
// console.log(" - LOGTO_ENDPOINT:", import.meta.env.LOGTO_ENDPOINT);
// console.log(" - LOGTO_TOKEN_ENDPOINT:", import.meta.env.LOGTO_TOKEN_ENDPOINT);
// console.log(" - LOGTO_API_ENDPOINT:", import.meta.env.LOGTO_API_ENDPOINT);
toast.success("Debug info logged to console");
}}

View file

@ -104,17 +104,17 @@ export default function ResumeSettings() {
const loadingToast = toast.loading('Uploading resume...');
// Log the file being uploaded for debugging
console.log('Uploading file:', {
name: resumeFile.name,
size: resumeFile.size,
type: resumeFile.type
});
// console.log('Uploading file:', {
// name: resumeFile.name,
// size: resumeFile.size,
// type: resumeFile.type
// });
let updatedUserData: User;
try {
// Use the FileManager to upload the file directly
console.log('Using FileManager to upload resume file');
// console.log('Using FileManager to upload resume file');
// Upload the file using the FileManager's uploadFile method
const result = await fileManager.uploadFile<User>(
@ -130,18 +130,18 @@ export default function ResumeSettings() {
throw new Error('Resume was not properly saved to the user record');
}
console.log('Resume upload successful:', result.resume);
// console.log('Resume upload successful:', result.resume);
// Store the updated user data
updatedUserData = result;
// Fetch the updated user record to ensure we have the latest data
const refreshedUser = await get.getOne<User>(Collections.USERS, user.id);
console.log('Refreshed user data:', refreshedUser);
// console.log('Refreshed user data:', refreshedUser);
// Double check that the resume field is populated
if (!refreshedUser.resume) {
console.warn('Resume field is missing in the refreshed user data');
// console.warn('Resume field is missing in the refreshed user data');
}
} catch (uploadError) {
console.error('Error in file upload process:', uploadError);
@ -173,7 +173,7 @@ export default function ResumeSettings() {
toast.success('Resume uploaded successfully');
// Log the successful upload
console.log('Resume uploaded successfully:', updatedUserData.resume);
// console.log('Resume uploaded successfully:', updatedUserData.resume);
// Dispatch a custom event to notify the dashboard about the resume upload
const event = new CustomEvent('resumeUploaded', {
@ -223,14 +223,14 @@ export default function ResumeSettings() {
const loadingToast = toast.loading('Deleting resume...');
// Log the deletion attempt
console.log('Attempting to delete resume for user:', user.id);
// console.log('Attempting to delete resume for user:', user.id);
// Create a FormData with empty resume field to remove the file
const formData = new FormData();
formData.append('resume', '');
try {
console.log('Using FileManager to delete resume file');
// console.log('Using FileManager to delete resume file');
// Use the FileManager's deleteFile method to remove the file
const result = await fileManager.deleteFile<User>(
@ -241,22 +241,22 @@ export default function ResumeSettings() {
// Verify the file was deleted
if (result.resume) {
console.warn('Resume field still exists after deletion attempt:', result.resume);
// console.warn('Resume field still exists after deletion attempt:', result.resume);
toast.dismiss(loadingToast);
toast.error('Failed to completely remove the resume. Please try again.');
setUploading(false);
return;
}
console.log('Resume deletion successful for user:', user.id);
// console.log('Resume deletion successful for user:', user.id);
// Fetch the updated user record to ensure we have the latest data
const refreshedUser = await get.getOne<User>(Collections.USERS, user.id);
console.log('Refreshed user data after deletion:', refreshedUser);
// console.log('Refreshed user data after deletion:', refreshedUser);
// Double check that the resume field is empty
if (refreshedUser.resume) {
console.warn('Resume field is still present in the refreshed user data:', refreshedUser.resume);
// console.warn('Resume field is still present in the refreshed user data:', refreshedUser.resume);
}
} catch (deleteError) {
console.error('Error in file deletion process:', deleteError);
@ -275,7 +275,7 @@ export default function ResumeSettings() {
toast.success('Resume deleted successfully');
// Log the successful deletion
console.log('Resume deleted successfully for user:', user.id);
// console.log('Resume deleted successfully for user:', user.id);
// Dispatch a custom event to notify the dashboard about the resume deletion
const event = new CustomEvent('resumeUploaded', {
@ -356,11 +356,11 @@ export default function ResumeSettings() {
const loadingToast = toast.loading('Replacing resume...');
// Log the file being uploaded for debugging
console.log('Replacing resume with file:', {
name: file.name,
size: file.size,
type: file.type
});
// console.log('Replacing resume with file:', {
// name: file.name,
// size: file.size,
// type: file.type
// });
// Create a FormData object for the file upload
const formData = new FormData();

View file

@ -112,27 +112,27 @@ export default function ReimbursementList() {
const fileManager = FileManager.getInstance();
useEffect(() => {
console.log('Component mounted');
// console.log('Component mounted');
fetchReimbursements();
}, []);
// Add effect to monitor requests state
useEffect(() => {
console.log('Requests state updated:', requests);
console.log('Number of requests:', requests.length);
// console.log('Requests state updated:', requests);
// console.log('Number of requests:', requests.length);
}, [requests]);
// Add a useEffect to log preview URL and filename changes
useEffect(() => {
console.log('Preview URL changed:', previewUrl);
console.log('Preview filename changed:', previewFilename);
// console.log('Preview URL changed:', previewUrl);
// console.log('Preview filename changed:', previewFilename);
}, [previewUrl, previewFilename]);
// Add a useEffect to log when the preview modal is shown/hidden
useEffect(() => {
console.log('Show preview changed:', showPreview);
// console.log('Show preview changed:', showPreview);
if (showPreview) {
console.log('Selected receipt:', selectedReceipt);
// console.log('Selected receipt:', selectedReceipt);
}
}, [showPreview, selectedReceipt]);
@ -167,7 +167,7 @@ export default function ReimbursementList() {
'-created'
);
console.log('Reimbursement records from IndexedDB:', reimbursementRecords);
// console.log('Reimbursement records from IndexedDB:', reimbursementRecords);
// Process the records
const processedRecords = reimbursementRecords.map(record => {
@ -183,7 +183,7 @@ export default function ReimbursementList() {
auditNotes = record.audit_notes;
}
} catch (e) {
console.error('Error parsing audit notes:', e);
// console.error('Error parsing audit notes:', e);
}
}
@ -217,7 +217,7 @@ export default function ReimbursementList() {
itemizedExpenses = receiptRecord.itemized_expenses as ItemizedExpense[];
}
} catch (e) {
console.error('Error parsing itemized expenses:', e);
// console.error('Error parsing itemized expenses:', e);
}
}
@ -241,13 +241,13 @@ export default function ReimbursementList() {
}));
}
} catch (e) {
console.error(`Error fetching receipt ${receiptId}:`, e);
// console.error(`Error fetching receipt ${receiptId}:`, e);
}
}
}
}
} catch (err) {
console.error('Error fetching reimbursements:', err);
// console.error('Error fetching reimbursements:', err);
setError('Failed to load reimbursements. Please try again.');
} finally {
setLoading(false);
@ -256,7 +256,7 @@ export default function ReimbursementList() {
const handlePreviewFile = async (request: ReimbursementRequest, receiptId: string) => {
try {
console.log('Previewing file for receipt ID:', receiptId);
// console.log('Previewing file for receipt ID:', receiptId);
const pb = auth.getPocketBase();
const fileManager = FileManager.getInstance();
@ -265,13 +265,13 @@ export default function ReimbursementList() {
// Check if we already have the receipt details in our map
if (receiptDetailsMap[receiptId]) {
console.log('Using cached receipt details');
// console.log('Using cached receipt details');
// Use the cached receipt details
setSelectedReceipt(receiptDetailsMap[receiptId]);
// Check if the receipt has a file
if (!receiptDetailsMap[receiptId].file) {
console.error('Receipt has no file attached');
// console.error('Receipt has no file attached');
toast.error('This receipt has no file attached');
setPreviewUrl('');
setPreviewFilename('');
@ -280,7 +280,7 @@ export default function ReimbursementList() {
}
// Get the file URL with token for protected files
console.log('Getting file URL with token');
// console.log('Getting file URL with token');
const url = await fileManager.getFileUrlWithToken(
'receipts',
receiptId,
@ -290,7 +290,7 @@ export default function ReimbursementList() {
// Check if the URL is empty
if (!url) {
console.error('Failed to get file URL: Empty URL returned');
// console.error('Failed to get file URL: Empty URL returned');
toast.error('Failed to load receipt: Could not generate file URL');
// Still show the preview modal but with empty URL to display the error message
setPreviewUrl('');
@ -299,7 +299,7 @@ export default function ReimbursementList() {
return;
}
console.log('Got URL:', url.substring(0, 50) + '...');
// console.log('Got URL:', url.substring(0, 50) + '...');
// Set the preview URL and filename
setPreviewUrl(url);
@ -309,28 +309,28 @@ export default function ReimbursementList() {
setShowPreview(true);
// Log the current state
console.log('Current state after setting:', {
previewUrl: url,
previewFilename: receiptDetailsMap[receiptId].file,
showPreview: true
});
// console.log('Current state after setting:', {
// previewUrl: url,
// previewFilename: receiptDetailsMap[receiptId].file,
// showPreview: true
// });
return;
}
// If not in the map, get the receipt record using its ID
console.log('Fetching receipt details from server');
// console.log('Fetching receipt details from server');
const receiptRecord = await pb.collection('receipts').getOne(receiptId, {
$autoCancel: false
});
if (receiptRecord) {
console.log('Receipt record found:', receiptRecord.id);
console.log('Receipt file:', receiptRecord.file);
// console.log('Receipt record found:', receiptRecord.id);
// console.log('Receipt file:', receiptRecord.file);
// Check if the receipt has a file
if (!receiptRecord.file) {
console.error('Receipt has no file attached');
// console.error('Receipt has no file attached');
toast.error('This receipt has no file attached');
setPreviewUrl('');
setPreviewFilename('');
@ -367,7 +367,7 @@ export default function ReimbursementList() {
setSelectedReceipt(receiptDetails);
// Get the file URL with token for protected files
console.log('Getting file URL with token for new receipt');
// console.log('Getting file URL with token for new receipt');
const url = await fileManager.getFileUrlWithToken(
'receipts',
receiptRecord.id,
@ -377,7 +377,7 @@ export default function ReimbursementList() {
// Check if the URL is empty
if (!url) {
console.error('Failed to get file URL: Empty URL returned');
// console.error('Failed to get file URL: Empty URL returned');
toast.error('Failed to load receipt: Could not generate file URL');
// Still show the preview modal but with empty URL to display the error message
setPreviewUrl('');
@ -386,7 +386,7 @@ export default function ReimbursementList() {
return;
}
console.log('Got URL:', url.substring(0, 50) + '...');
// console.log('Got URL:', url.substring(0, 50) + '...');
// Set the preview URL and filename
setPreviewUrl(url);
@ -396,16 +396,16 @@ export default function ReimbursementList() {
setShowPreview(true);
// Log the current state
console.log('Current state after setting:', {
previewUrl: url,
previewFilename: receiptRecord.file,
showPreview: true
});
// console.log('Current state after setting:', {
// previewUrl: url,
// previewFilename: receiptRecord.file,
// showPreview: true
// });
} else {
throw new Error('Receipt not found');
}
} catch (error) {
console.error('Error loading receipt:', error);
// console.error('Error loading receipt:', error);
toast.error('Failed to load receipt. Please try again.');
// Show the preview modal with empty URL to display the error message
setPreviewUrl('');
@ -423,7 +423,7 @@ export default function ReimbursementList() {
};
if (loading) {
console.log('Rendering loading state');
// console.log('Rendering loading state');
return (
<motion.div
initial={{ opacity: 0 }}
@ -437,7 +437,7 @@ export default function ReimbursementList() {
}
if (error) {
console.log('Rendering error state:', error);
// console.log('Rendering error state:', error);
return (
<motion.div
initial={{ opacity: 0, y: -20 }}
@ -450,8 +450,8 @@ export default function ReimbursementList() {
);
}
console.log('Rendering main component. Requests:', requests);
console.log('Requests length:', requests.length);
// console.log('Rendering main component. Requests:', requests);
// console.log('Requests length:', requests.length);
return (
<>
@ -482,7 +482,7 @@ export default function ReimbursementList() {
>
<AnimatePresence mode="popLayout">
{requests.map((request, index) => {
console.log('Rendering request:', request);
// console.log('Rendering request:', request);
return (
<motion.div
key={request.id}

View file

@ -134,7 +134,6 @@ export default function ReimbursementManagementPortal() {
}
const records = await get.getAll<ExtendedReimbursement>('reimbursement', filter, sort);
console.log('Loaded reimbursements:', records);
// Load user data for submitters
const userIds = new Set(records.map(r => r.submitted_by));
@ -165,11 +164,9 @@ export default function ReimbursementManagementPortal() {
// Load associated receipts
const receiptIds = enrichedRecords.flatMap(r => r.receipts || []);
console.log('Extracted receipt IDs:', receiptIds, 'from reimbursements:', enrichedRecords.map(r => ({ id: r.id, receipts: r.receipts })));
if (receiptIds.length > 0) {
try {
console.log('Attempting to load receipts with IDs:', receiptIds);
const receiptRecords = await Promise.all(
receiptIds.map(async id => {
try {
@ -202,12 +199,10 @@ export default function ReimbursementManagementPortal() {
);
const validReceipts = receiptRecords.filter((r): r is ExtendedReceipt => r !== null);
console.log('Successfully loaded receipt records:', validReceipts);
const receiptMap = Object.fromEntries(
validReceipts.map(receipt => [receipt.id, receipt])
);
console.log('Created receipt map:', receiptMap);
setReceipts(receiptMap);
} catch (error: any) {
console.error('Error loading receipts:', error);
@ -219,7 +214,7 @@ export default function ReimbursementManagementPortal() {
toast.error('Failed to load receipts: ' + (error?.message || 'Unknown error'));
}
} else {
console.log('No receipt IDs found in reimbursements');
// console.log('No receipt IDs found in reimbursements');
setReceipts({});
}
} catch (error) {

View file

@ -29,7 +29,7 @@ const ImageWithFallback = ({ url, filename, onError }: ImageWithFallbackProps) =
try {
// Try to fetch the image as a blob and create an object URL
console.log('Trying to fetch image as blob:', url);
// console.log('Trying to fetch image as blob:', url);
const response = await fetch(url, { mode: 'cors' });
if (!response.ok) {
@ -38,7 +38,7 @@ const ImageWithFallback = ({ url, filename, onError }: ImageWithFallbackProps) =
const blob = await response.blob();
const objectUrl = URL.createObjectURL(blob);
console.log('Created object URL:', objectUrl);
// console.log('Created object URL:', objectUrl);
// Update the image source with the object URL
setImgSrc(objectUrl);
@ -48,10 +48,10 @@ const ImageWithFallback = ({ url, filename, onError }: ImageWithFallbackProps) =
onError('Failed to load image. This might be due to permission issues or the file may not exist.');
// Log additional details
console.log('Image URL that failed:', url);
console.log('Current auth status:',
Authentication.getInstance().isAuthenticated() ? 'Authenticated' : 'Not authenticated'
);
// console.log('Image URL that failed:', url);
// console.log('Current auth status:',
// Authentication.getInstance().isAuthenticated() ? 'Authenticated' : 'Not authenticated'
// );
}
};

View file

@ -76,26 +76,26 @@ const Calendar = ({ CALENDAR_API_KEY, EVENT_CALENDAR_ID }) => {
const loadGapiAndListEvents = async () => {
try {
console.log("Starting to load events...");
// console.log("Starting to load events...");
if (typeof window.gapi === "undefined") {
console.log("Loading GAPI script...");
// console.log("Loading GAPI script...");
await new Promise((resolve, reject) => {
const script = document.createElement("script");
script.src = "https://apis.google.com/js/api.js";
document.body.appendChild(script);
script.onload = () => {
console.log("GAPI script loaded");
// console.log("GAPI script loaded");
window.gapi.load("client", resolve);
};
script.onerror = () => {
console.error("Failed to load GAPI script");
// console.error("Failed to load GAPI script");
reject(new Error("Failed to load the Google API script."));
};
});
}
console.log("Initializing GAPI client...");
// console.log("Initializing GAPI client...");
await window.gapi.client.init({
apiKey: CALENDAR_API_KEY,
discoveryDocs: [
@ -115,7 +115,7 @@ const Calendar = ({ CALENDAR_API_KEY, EVENT_CALENDAR_ID }) => {
0,
);
console.log("Fetching events...");
// console.log("Fetching events...");
const response = await window.gapi.client.calendar.events.list({
calendarId: calendarId,
timeZone: userTimeZone,
@ -125,13 +125,13 @@ const Calendar = ({ CALENDAR_API_KEY, EVENT_CALENDAR_ID }) => {
orderBy: "startTime",
});
console.log("Response received:", response);
// console.log("Response received:", response);
if (response.result.items) {
setEvents(response.result.items);
}
} catch (error) {
console.error("Detailed Error: ", error);
// console.error("Detailed Error: ", error);
setError(error.message || "Failed to load events");
} finally {
setLoading(false);

View file

@ -48,16 +48,16 @@ const EventList = ({ CALENDAR_API_KEY, EVENT_CALENDAR_ID }) => {
const loadGapiAndListEvents = async () => {
try {
console.log("Starting to load events...");
// console.log("Starting to load events...");
if (typeof window.gapi === "undefined") {
console.log("Loading GAPI script...");
// console.log("Loading GAPI script...");
await new Promise((resolve, reject) => {
const script = document.createElement("script");
script.src = "https://apis.google.com/js/api.js";
document.body.appendChild(script);
script.onload = () => {
console.log("GAPI script loaded");
// console.log("GAPI script loaded");
window.gapi.load("client", resolve);
};
script.onerror = () => {
@ -67,7 +67,7 @@ const EventList = ({ CALENDAR_API_KEY, EVENT_CALENDAR_ID }) => {
});
}
console.log("Initializing GAPI client...");
// console.log("Initializing GAPI client...");
await window.gapi.client.init({
apiKey: apiKey,
discoveryDocs: [
@ -75,7 +75,7 @@ const EventList = ({ CALENDAR_API_KEY, EVENT_CALENDAR_ID }) => {
],
});
console.log("Fetching events...");
// console.log("Fetching events...");
const response = await window.gapi.client.calendar.events.list({
calendarId: calendarId,
timeZone: userTimeZone,
@ -85,7 +85,7 @@ const EventList = ({ CALENDAR_API_KEY, EVENT_CALENDAR_ID }) => {
orderBy: "startTime",
});
console.log("Response received:", response);
// console.log("Response received:", response);
if (response.result.items) {
setEvents(response.result.items);

View file

@ -11,8 +11,6 @@ async function getLogtoAccessToken(
scope: string = "all",
): Promise<string | null> {
try {
console.log("Attempting to get access token from Logto");
// Create Basic auth string
const authString = Buffer.from(`${clientId}:${clientSecret}`).toString(
"base64",
@ -59,8 +57,6 @@ async function verifyUserPassword(
accessToken: string,
): Promise<boolean> {
try {
console.log("Verifying current password");
const response = await fetch(
`${logtoApiEndpoint}/api/users/${userId}/password/verify`,
{
@ -75,7 +71,6 @@ async function verifyUserPassword(
// 204 means password matches, 422 means it doesn't match
if (response.status === 204) {
console.log("Current password verified successfully");
return true;
}
@ -101,8 +96,6 @@ async function verifyUserPassword(
export const POST: APIRoute = async ({ request }) => {
try {
console.log("Received change password request");
// Parse request body
const contentType = request.headers.get("content-type");
const rawBody = await request.text();
@ -161,6 +154,7 @@ export const POST: APIRoute = async ({ request }) => {
}
// Get access token
// console.log("Attempting to get access token from Logto");
const accessToken = await getLogtoAccessToken(
logtoTokenEndpoint,
logtoAppId,
@ -181,6 +175,7 @@ export const POST: APIRoute = async ({ request }) => {
}
// Verify current password before proceeding
// console.log("Verifying current password");
const isPasswordValid = await verifyUserPassword(
logtoApiEndpoint,
userId,
@ -202,6 +197,7 @@ export const POST: APIRoute = async ({ request }) => {
}
// Change password using Logto Management API
// console.log("Current password verified successfully");
const changePasswordResponse = await fetch(
`${logtoApiEndpoint}/api/users/${userId}/password`,
{

File diff suppressed because it is too large Load diff

View file

@ -60,7 +60,7 @@ export class RedirectHandler {
{ emailVisibility: false },
);
console.log("Auth successful:", authData);
// console.log("Auth successful:", authData);
this.contentEl.innerHTML = `
<p class="text-3xl font-bold text-green-500 mb-4">Authentication Successful!</p>
<p class="text-2xl font-medium">Initializing your data...</p>
@ -99,19 +99,15 @@ export class RedirectHandler {
private async initializeDataSync(): Promise<void> {
try {
// Dynamically import the AuthSyncService to avoid circular dependencies
const { AuthSyncService } = await import('../database/AuthSyncService');
const { AuthSyncService } = await import("../database/AuthSyncService");
// Get the instance and trigger a full sync
const authSync = AuthSyncService.getInstance();
const syncResult = await authSync.handleLogin();
if (syncResult) {
console.log('Initial data sync completed successfully');
} else {
console.warn('Initial data sync completed with issues');
}
// console.log('Initial data sync completed successfully');
} catch (error) {
console.error('Failed to initialize data sync:', error);
console.error("Failed to initialize data sync:", error);
// Continue with login process even if sync fails
}
}

View file

@ -78,7 +78,7 @@ export class AuthSyncService {
if (!isBrowser) return true;
if (this.isSyncing) {
console.log("Sync already in progress, queueing login sync");
// console.log("Sync already in progress, queueing login sync");
if (this.syncPromise) {
this.syncPromise = this.syncPromise.then(() => this.performLoginSync());
} else {
@ -100,7 +100,7 @@ export class AuthSyncService {
if (!isBrowser) return;
if (!this.auth.isAuthenticated()) {
console.log("Not authenticated, skipping login sync");
// console.log("Not authenticated, skipping login sync");
return;
}
@ -108,7 +108,7 @@ export class AuthSyncService {
this.syncErrors = {};
try {
console.log("Starting login sync process...");
// console.log("Starting login sync process...");
// Display sync notification if in browser environment
this.showSyncNotification("Syncing your data...");
@ -123,7 +123,7 @@ export class AuthSyncService {
);
// Log the sync operation
console.log("User data synchronized on login");
// console.log("User data synchronized on login");
}
// Sync all collections in parallel with conflict resolution
@ -131,9 +131,9 @@ export class AuthSyncService {
this.collectionsToSync.map(async (collection) => {
try {
await this.dataSync.syncCollection(collection);
console.log(`Successfully synced ${collection}`);
// console.log(`Successfully synced ${collection}`);
} catch (error) {
console.error(`Error syncing ${collection}:`, error);
// console.error(`Error syncing ${collection}:`, error);
this.syncErrors[collection] = error as Error;
}
}),
@ -146,17 +146,17 @@ export class AuthSyncService {
const syncVerification = await this.verifySyncSuccess();
if (syncVerification.success) {
console.log("Login sync completed successfully");
// console.log("Login sync completed successfully");
this.showSyncNotification("Data sync complete!", "success");
} else {
console.warn(
"Login sync completed with issues:",
syncVerification.errors,
);
// console.warn(
// "Login sync completed with issues:",
// syncVerification.errors,
// );
this.showSyncNotification("Some data could not be synced", "warning");
}
} catch (error) {
console.error("Error during login sync:", error);
// console.error("Error during login sync:", error);
this.showSyncNotification("Failed to sync data", "error");
} finally {
this.isSyncing = false;
@ -180,7 +180,7 @@ export class AuthSyncService {
if (!isBrowser) return true;
if (this.isSyncing) {
console.log("Sync already in progress, queueing logout cleanup");
// console.log("Sync already in progress, queueing logout cleanup");
this.syncQueue.push("logout");
return true;
}
@ -188,7 +188,7 @@ export class AuthSyncService {
this.isSyncing = true;
try {
console.log("Starting logout cleanup process...");
// console.log("Starting logout cleanup process...");
// Ensure any pending changes are synced before logout
await this.syncPendingChanges();
@ -196,10 +196,10 @@ export class AuthSyncService {
// Clear all data from IndexedDB
await this.dexieService.clearAllData();
console.log("Logout cleanup completed successfully");
// console.log("Logout cleanup completed successfully");
return true;
} catch (error) {
console.error("Error during logout cleanup:", error);
// console.error("Error during logout cleanup:", error);
return false;
} finally {
this.isSyncing = false;
@ -224,7 +224,7 @@ export class AuthSyncService {
// This would be implemented if we had offline capabilities
// For now, we just log that we would sync pending changes
console.log("Checking for pending changes to sync before logout...");
// console.log("Checking for pending changes to sync before logout...");
// In a real implementation, this would sync any offline changes
}
@ -284,7 +284,7 @@ export class AuthSyncService {
window.toast(message, { type });
} else {
// Fallback to console
console.log(`[${type.toUpperCase()}] ${message}`);
// console.log(`[${type.toUpperCase()}] ${message}`);
}
}
@ -293,7 +293,7 @@ export class AuthSyncService {
*/
public async forceSyncAll(): Promise<boolean> {
if (this.isSyncing) {
console.log("Sync already in progress, queueing full sync");
// console.log("Sync already in progress, queueing full sync");
this.syncQueue.push("login"); // Reuse login sync logic
return true;
}

View file

@ -83,7 +83,7 @@ export class DataSyncService {
private async handleOnline(): Promise<void> {
if (!isBrowser) return;
console.log("Device is online, syncing pending changes...");
// console.log("Device is online, syncing pending changes...");
this.offlineMode = false;
await this.syncOfflineChanges();
}
@ -94,7 +94,7 @@ export class DataSyncService {
private handleOffline(): void {
if (!isBrowser) return;
console.log("Device is offline, enabling offline mode...");
// console.log("Device is offline, enabling offline mode...");
this.offlineMode = true;
}
@ -109,13 +109,13 @@ export class DataSyncService {
): Promise<T[]> {
// Skip in non-browser environments
if (!isBrowser) {
console.log(`Skipping sync for ${collection} in non-browser environment`);
// console.log(`Skipping sync for ${collection} in non-browser environment`);
return [];
}
// Prevent multiple syncs of the same collection at the same time
if (this.syncInProgress[collection]) {
console.log(`Sync already in progress for ${collection}`);
// console.log(`Sync already in progress for ${collection}`);
return [];
}
@ -124,19 +124,19 @@ export class DataSyncService {
try {
// Check if we're authenticated
if (!this.auth.isAuthenticated()) {
console.log(`Not authenticated, skipping sync for ${collection}`);
// console.log(`Not authenticated, skipping sync for ${collection}`);
return [];
}
// Check if we're offline
if (this.offlineMode) {
console.log(`Device is offline, using cached data for ${collection}`);
// console.log(`Device is offline, using cached data for ${collection}`);
const db = this.dexieService.getDB();
const table = this.getTableForCollection(collection);
return table ? ((await table.toArray()) as T[]) : [];
}
console.log(`Syncing ${collection}...`);
// console.log(`Syncing ${collection}...`);
// Normalize expand parameter to be an array of strings
let normalizedExpand: string[] | undefined;
@ -158,7 +158,7 @@ export class DataSyncService {
const items = await this.get.getAll<T>(collection, filter, sort, {
expand: normalizedExpand,
});
console.log(`Fetched ${items.length} items from ${collection}`);
// console.log(`Fetched ${items.length} items from ${collection}`);
// Get the database table
const db = this.dexieService.getDB();
@ -181,11 +181,11 @@ export class DataSyncService {
const existingItem = existingItemsMap.get(item.id);
// SECURITY FIX: Remove event_code from events before storing in IndexedDB
if (collection === Collections.EVENTS && 'event_code' in item) {
if (collection === Collections.EVENTS && "event_code" in item) {
// Keep the event_code but ensure files array is properly handled
if ('files' in item && Array.isArray((item as any).files)) {
if ("files" in item && Array.isArray((item as any).files)) {
// Ensure files array is properly stored
console.log(`Event ${item.id} has ${(item as any).files.length} files`);
// console.log(`Event ${item.id} has ${(item as any).files.length} files`);
} else {
// Initialize empty files array if not present
(item as any).files = [];
@ -232,18 +232,21 @@ export class DataSyncService {
// For events, ensure we handle the files field properly
if (collection === Collections.EVENTS) {
// Ensure files array is properly handled
if ('files' in serverItem && Array.isArray((serverItem as any).files)) {
console.log(`Server event ${serverItem.id} has ${(serverItem as any).files.length} files`);
if ("files" in serverItem && Array.isArray((serverItem as any).files)) {
// console.log(`Server event ${serverItem.id} has ${(serverItem as any).files.length} files`);
} else {
// Initialize empty files array if not present
(serverItem as any).files = [];
}
// If local item has files but server doesn't, preserve local files
if ('files' in localItem && Array.isArray((localItem as any).files) &&
(localItem as any).files.length > 0 &&
(!('files' in serverItem) || !(serverItem as any).files.length)) {
console.log(`Preserving local files for event ${localItem.id}`);
if (
"files" in localItem &&
Array.isArray((localItem as any).files) &&
(localItem as any).files.length > 0 &&
(!("files" in serverItem) || !(serverItem as any).files.length)
) {
// console.log(`Preserving local files for event ${localItem.id}`);
(serverItem as any).files = (localItem as any).files;
}
}
@ -255,9 +258,9 @@ export class DataSyncService {
);
if (pendingChanges.length > 0) {
console.log(
`Found ${pendingChanges.length} pending changes for ${collection}:${localItem.id}`,
);
// console.log(
// `Found ${pendingChanges.length} pending changes for ${collection}:${localItem.id}`,
// );
// Server-wins strategy by default, but preserve local changes that haven't been synced
const mergedItem = { ...serverItem };
@ -268,12 +271,16 @@ export class DataSyncService {
// Apply each field change individually
Object.entries(change.data).forEach(([key, value]) => {
// Special handling for files array
if (key === 'files' && Array.isArray(value)) {
if (key === "files" && Array.isArray(value)) {
// Merge files arrays, removing duplicates
const existingFiles = Array.isArray((mergedItem as any)[key]) ? (mergedItem as any)[key] : [];
const existingFiles = Array.isArray((mergedItem as any)[key])
? (mergedItem as any)[key]
: [];
const newFiles = value as string[];
(mergedItem as any)[key] = [...new Set([...existingFiles, ...newFiles])];
console.log(`Merged files for ${collection}:${localItem.id}`, (mergedItem as any)[key]);
(mergedItem as any)[key] = [
...new Set([...existingFiles, ...newFiles]),
];
// console.log(`Merged files for ${collection}:${localItem.id}`, (mergedItem as any)[key]);
} else {
(mergedItem as any)[key] = value;
}
@ -326,11 +333,11 @@ export class DataSyncService {
.toArray();
if (pendingChanges.length === 0) {
console.log("No pending offline changes to sync");
// console.log("No pending offline changes to sync");
return true;
}
console.log(`Syncing ${pendingChanges.length} offline changes...`);
// console.log(`Syncing ${pendingChanges.length} offline changes...`);
// Group changes by collection for more efficient processing
const changesByCollection = pendingChanges.reduce(
@ -411,9 +418,9 @@ export class DataSyncService {
};
const id = await this.offlineChangesTable.add(change as OfflineChange);
console.log(
`Recorded offline change: ${operation} on ${collection}:${recordId}`,
);
// console.log(
// `Recorded offline change: ${operation} on ${collection}:${recordId}`,
// );
// Try to sync immediately if we're online
if (!this.offlineMode) {
@ -500,7 +507,7 @@ export class DataSyncService {
// SECURITY FIX: Remove event_code from events before returning them
if (collection === Collections.EVENTS) {
data = data.map((item: any) => {
if ('event_code' in item) {
if ("event_code" in item) {
const { event_code, ...rest } = item;
return rest;
}
@ -538,17 +545,22 @@ export class DataSyncService {
// For events, ensure we handle the files field properly
if (collection === Collections.EVENTS) {
// Ensure files array is properly handled
if (!('files' in pbItem) || !Array.isArray((pbItem as any).files)) {
if (!("files" in pbItem) || !Array.isArray((pbItem as any).files)) {
(pbItem as any).files = [];
}
// If we already have a local item with files, preserve them if server has none
if (item && 'files' in item && Array.isArray((item as any).files) &&
(item as any).files.length > 0 && !(pbItem as any).files.length) {
console.log(`Preserving local files for event ${id}`);
if (
item &&
"files" in item &&
Array.isArray((item as any).files) &&
(item as any).files.length > 0 &&
!(pbItem as any).files.length
) {
// console.log(`Preserving local files for event ${id}`);
(pbItem as any).files = (item as any).files;
}
await table.put(pbItem);
item = pbItem;
} else {
@ -587,21 +599,21 @@ export class DataSyncService {
}
// Special handling for files field in events
if (collection === Collections.EVENTS && 'files' in data) {
console.log(`Updating files for event ${id}`, (data as any).files);
if (collection === Collections.EVENTS && "files" in data) {
// console.log(`Updating files for event ${id}`, (data as any).files);
// Ensure files is an array
if (!Array.isArray((data as any).files)) {
(data as any).files = [];
}
// If we're updating files, make sure we're not losing any
if ('files' in currentItem && Array.isArray((currentItem as any).files)) {
if ("files" in currentItem && Array.isArray((currentItem as any).files)) {
// Merge files arrays, removing duplicates
const existingFiles = (currentItem as any).files as string[];
const newFiles = (data as any).files as string[];
(data as any).files = [...new Set([...existingFiles, ...newFiles])];
console.log(`Merged files for event ${id}`, (data as any).files);
// console.log(`Merged files for event ${id}`, (data as any).files);
}
}
@ -689,11 +701,14 @@ export class DataSyncService {
try {
// Store in localStorage instead of IndexedDB for security
localStorage.setItem('pending_event_code', eventCode);
localStorage.setItem('pending_event_code_timestamp', Date.now().toString());
console.log('Event code stored for offline check-in');
localStorage.setItem("pending_event_code", eventCode);
localStorage.setItem(
"pending_event_code_timestamp",
Date.now().toString(),
);
// console.log('Event code stored for offline check-in');
} catch (error) {
console.error('Error storing event code:', error);
console.error("Error storing event code:", error);
}
}
@ -704,11 +719,11 @@ export class DataSyncService {
if (!isBrowser) return;
try {
localStorage.removeItem('pending_event_code');
localStorage.removeItem('pending_event_code_timestamp');
console.log('Event code cleared');
localStorage.removeItem("pending_event_code");
localStorage.removeItem("pending_event_code_timestamp");
// console.log('Event code cleared');
} catch (error) {
console.error('Error clearing event code:', error);
console.error("Error clearing event code:", error);
}
}
@ -716,21 +731,24 @@ export class DataSyncService {
* Get the stored event code from local storage
* @returns The stored event code, or null if none exists
*/
public async getStoredEventCode(): Promise<{ code: string; timestamp: number } | null> {
public async getStoredEventCode(): Promise<{
code: string;
timestamp: number;
} | null> {
if (!isBrowser) return null;
try {
const code = localStorage.getItem('pending_event_code');
const timestamp = localStorage.getItem('pending_event_code_timestamp');
const code = localStorage.getItem("pending_event_code");
const timestamp = localStorage.getItem("pending_event_code_timestamp");
if (!code || !timestamp) return null;
return {
code,
timestamp: parseInt(timestamp)
timestamp: parseInt(timestamp),
};
} catch (error) {
console.error('Error getting stored event code:', error);
console.error("Error getting stored event code:", error);
return null;
}
}
@ -745,31 +763,31 @@ export class DataSyncService {
try {
const db = this.dexieService.getDB();
const table = this.getTableForCollection(Collections.EVENTS);
if (!table) {
console.error('Events table not found');
console.error("Events table not found");
return;
}
// Get all events
const events = await table.toArray();
// Remove event_code from each event
const updatedEvents = events.map(event => {
if ('event_code' in event) {
const updatedEvents = events.map((event) => {
if ("event_code" in event) {
const { event_code, ...rest } = event;
return rest;
}
return event;
});
// Clear the table and add the updated events
await table.clear();
await table.bulkAdd(updatedEvents);
console.log('Successfully purged event codes from IndexedDB');
// console.log('Successfully purged event codes from IndexedDB');
} catch (error) {
console.error('Error purging event codes:', error);
console.error("Error purging event codes:", error);
}
}
}

View file

@ -65,16 +65,17 @@ export class DashboardDatabase extends Dexie {
offlineChanges:
"id, collection, recordId, operation, timestamp, synced, syncAttempts",
});
// Add version 3 with eventAttendees table and updated events table (no attendees field)
this.version(3).stores({
events: "id, event_name, event_code, start_date, end_date, published",
eventAttendees: "id, user, event, time_checked_in",
});
// Add version 4 with files field in events table
this.version(4).stores({
events: "id, event_name, event_code, start_date, end_date, published, files",
events:
"id, event_name, event_code, start_date, end_date, published, files",
});
}
@ -125,7 +126,7 @@ export class DexieService {
this.db.initialize();
} else {
// Use a mock database in non-browser environments
console.log("Running in Node.js environment, using mock database");
// console.log("Running in Node.js environment, using mock database");
this.db = new MockDashboardDatabase() as any;
}
}

View file

@ -1,4 +1,4 @@
import { Authentication } from '../pocketbase/Authentication';
import { Authentication } from "../pocketbase/Authentication";
/**
* Initialize authentication synchronization
@ -9,27 +9,27 @@ export async function initAuthSync(): Promise<void> {
try {
// Get Authentication instance
const auth = Authentication.getInstance();
// This will trigger the lazy loading of AuthSyncService
// through the onAuthStateChange mechanism
auth.onAuthStateChange(() => {
console.log('Auth sync initialized and listening for auth state changes');
// console.log('Auth sync initialized and listening for auth state changes');
});
console.log('Auth sync initialization complete');
// console.log('Auth sync initialization complete');
} catch (error) {
console.error('Failed to initialize auth sync:', error);
console.error("Failed to initialize auth sync:", error);
}
}
// Export a function to manually trigger a full sync
export async function forceFullSync(): Promise<boolean> {
try {
const { AuthSyncService } = await import('./AuthSyncService');
const { AuthSyncService } = await import("./AuthSyncService");
const authSync = AuthSyncService.getInstance();
return await authSync.forceSyncAll();
} catch (error) {
console.error('Failed to force full sync:', error);
console.error("Failed to force full sync:", error);
return false;
}
}
}

View file

@ -87,20 +87,20 @@ export class Authentication {
try {
// Initialize AuthSyncService if needed (lazy loading)
await this.initAuthSyncService();
// Get AuthSyncService instance
const { AuthSyncService } = await import('../database/AuthSyncService');
const { AuthSyncService } = await import("../database/AuthSyncService");
const authSync = AuthSyncService.getInstance();
// Handle data cleanup before actual logout
await authSync.handleLogout();
// Clear auth store
this.pb.authStore.clear();
console.log('Logout completed successfully with data cleanup');
// console.log('Logout completed successfully with data cleanup');
} catch (error) {
console.error('Error during logout:', error);
console.error("Error during logout:", error);
// Fallback to basic logout if sync fails
this.pb.authStore.clear();
}
@ -133,9 +133,12 @@ export class Authentication {
*/
public onAuthStateChange(callback: (isValid: boolean) => void): void {
this.authChangeCallbacks.push(callback);
// Initialize AuthSyncService when first callback is registered
if (!this.authSyncServiceInitialized && this.authChangeCallbacks.length === 1) {
if (
!this.authSyncServiceInitialized &&
this.authChangeCallbacks.length === 1
) {
this.initAuthSyncService();
}
}
@ -164,32 +167,32 @@ export class Authentication {
const isValid = this.pb.authStore.isValid;
this.authChangeCallbacks.forEach((callback) => callback(isValid));
}
/**
* Initialize the AuthSyncService (lazy loading)
*/
private async initAuthSyncService(): Promise<void> {
if (this.authSyncServiceInitialized) return;
try {
// Dynamically import AuthSyncService to avoid circular dependencies
const { AuthSyncService } = await import('../database/AuthSyncService');
const { AuthSyncService } = await import("../database/AuthSyncService");
// Initialize the service
AuthSyncService.getInstance();
this.authSyncServiceInitialized = true;
console.log('AuthSyncService initialized successfully');
// console.log('AuthSyncService initialized successfully');
// If user is already authenticated, trigger initial sync
if (this.isAuthenticated()) {
const authSync = AuthSyncService.getInstance();
authSync.handleLogin().catch(err => {
console.error('Error during initial data sync:', err);
authSync.handleLogin().catch((err) => {
console.error("Error during initial data sync:", err);
});
}
} catch (error) {
console.error('Failed to initialize AuthSyncService:', error);
console.error("Failed to initialize AuthSyncService:", error);
}
}
}

View file

@ -3,7 +3,7 @@ import { Authentication } from "./Authentication";
export class FileManager {
private auth: Authentication;
private static instance: FileManager;
private static UNSUPPORTED_EXTENSIONS = ['afdesign', 'psd', 'ai', 'sketch'];
private static UNSUPPORTED_EXTENSIONS = ["afdesign", "psd", "ai", "sketch"];
private constructor() {
this.auth = Authentication.getInstance();
@ -25,15 +25,18 @@ export class FileManager {
* @returns Object with validation result and reason if invalid
*/
public validateFileType(file: File): { valid: boolean; reason?: string } {
const fileExtension = file.name.split('.').pop()?.toLowerCase();
if (fileExtension && FileManager.UNSUPPORTED_EXTENSIONS.includes(fileExtension)) {
return {
valid: false,
reason: `File type .${fileExtension} is not supported. Please convert to PDF or image format.`
const fileExtension = file.name.split(".").pop()?.toLowerCase();
if (
fileExtension &&
FileManager.UNSUPPORTED_EXTENSIONS.includes(fileExtension)
) {
return {
valid: false,
reason: `File type .${fileExtension} is not supported. Please convert to PDF or image format.`,
};
}
return { valid: true };
}
@ -51,7 +54,7 @@ export class FileManager {
recordId: string,
field: string,
file: File,
append: boolean = false
append: boolean = false,
): Promise<T> {
if (!this.auth.isAuthenticated()) {
throw new Error("User must be authenticated to upload files");
@ -60,16 +63,18 @@ export class FileManager {
try {
this.auth.setUpdating(true);
const pb = this.auth.getPocketBase();
// Validate file size
const maxSize = 200 * 1024 * 1024; // 200MB
if (file.size > maxSize) {
throw new Error(`File size ${(file.size / 1024 / 1024).toFixed(2)}MB exceeds 200MB limit`);
throw new Error(
`File size ${(file.size / 1024 / 1024).toFixed(2)}MB exceeds 200MB limit`,
);
}
// Check for potentially problematic file types
const fileExtension = file.name.split('.').pop()?.toLowerCase();
const fileExtension = file.name.split(".").pop()?.toLowerCase();
// Validate file type
const validation = this.validateFileType(file);
if (!validation.valid) {
@ -77,49 +82,50 @@ export class FileManager {
}
// Log upload attempt
console.log('Attempting file upload:', {
name: file.name,
size: file.size,
type: file.type,
extension: fileExtension,
collection: collectionName,
recordId: recordId,
field: field,
append: append
});
// console.log('Attempting file upload:', {
// name: file.name,
// size: file.size,
// type: file.type,
// extension: fileExtension,
// collection: collectionName,
// recordId: recordId,
// field: field,
// append: append
// });
// Create FormData for the upload
const formData = new FormData();
// Use the + prefix for the field name if append is true
const fieldName = append ? `${field}+` : field;
// Get existing record to preserve existing files
let existingRecord: any = null;
let existingFiles: string[] = [];
try {
if (recordId) {
existingRecord = await pb.collection(collectionName).getOne(recordId);
existingFiles = existingRecord[field] || [];
}
} catch (error) {
console.warn('Could not fetch existing record:', error);
// console.warn('Could not fetch existing record:', error);
}
// Check if the file already exists
const fileExists = existingFiles.some(existingFile =>
existingFile.toLowerCase() === file.name.toLowerCase()
const fileExists = existingFiles.some(
(existingFile) =>
existingFile.toLowerCase() === file.name.toLowerCase(),
);
if (fileExists) {
console.warn(`File with name ${file.name} already exists. Renaming to avoid conflicts.`);
// console.warn(`File with name ${file.name} already exists. Renaming to avoid conflicts.`);
const timestamp = new Date().getTime();
const nameParts = file.name.split('.');
const nameParts = file.name.split(".");
const extension = nameParts.pop();
const baseName = nameParts.join('.');
const baseName = nameParts.join(".");
const newFileName = `${baseName}_${timestamp}.${extension}`;
// Create a new file with the modified name
const newFile = new File([file], newFileName, { type: file.type });
formData.append(fieldName, newFile);
@ -128,60 +134,71 @@ export class FileManager {
}
try {
const result = await pb.collection(collectionName).update<T>(recordId, formData);
console.log('Upload successful:', {
result,
fileInfo: {
name: file.name,
size: file.size,
type: file.type
},
collection: collectionName,
recordId: recordId
});
const result = await pb
.collection(collectionName)
.update<T>(recordId, formData);
// console.log('Upload successful:', {
// result,
// fileInfo: {
// name: file.name,
// size: file.size,
// type: file.type
// },
// collection: collectionName,
// recordId: recordId
// });
// Verify the file was actually added to the record
try {
const updatedRecord = await pb.collection(collectionName).getOne(recordId);
console.log('Updated record files:', {
files: updatedRecord.files,
recordId: recordId
});
const updatedRecord = await pb
.collection(collectionName)
.getOne(recordId);
// console.log('Updated record files:', {
// files: updatedRecord.files,
// recordId: recordId
// });
} catch (verifyError) {
console.warn('Could not verify file upload:', verifyError);
// console.warn('Could not verify file upload:', verifyError);
}
return result;
} catch (pbError: any) {
// Log detailed PocketBase error
console.error('PocketBase upload error:', {
status: pbError?.status,
response: pbError?.response,
data: pbError?.data,
message: pbError?.message
});
// console.error('PocketBase upload error:', {
// status: pbError?.status,
// response: pbError?.response,
// data: pbError?.data,
// message: pbError?.message
// });
// More specific error message based on file type
if (fileExtension && FileManager.UNSUPPORTED_EXTENSIONS.includes(fileExtension)) {
throw new Error(`Upload failed: File type .${fileExtension} is not supported. Please convert to PDF or image format.`);
if (
fileExtension &&
FileManager.UNSUPPORTED_EXTENSIONS.includes(fileExtension)
) {
throw new Error(
`Upload failed: File type .${fileExtension} is not supported. Please convert to PDF or image format.`,
);
}
throw new Error(`Upload failed: ${pbError?.message || 'Unknown PocketBase error'}`);
throw new Error(
`Upload failed: ${pbError?.message || "Unknown PocketBase error"}`,
);
}
} catch (err) {
console.error(`Failed to upload file to ${collectionName}:`, {
error: err,
fileInfo: {
name: file.name,
size: file.size,
type: file.type
},
auth: {
isAuthenticated: this.auth.isAuthenticated(),
userId: this.auth.getUserId()
}
});
// console.error(`Failed to upload file to ${collectionName}:`, {
// error: err,
// fileInfo: {
// name: file.name,
// size: file.size,
// type: file.type
// },
// auth: {
// isAuthenticated: this.auth.isAuthenticated(),
// userId: this.auth.getUserId()
// }
// });
if (err instanceof Error) {
throw err;
}
@ -224,7 +241,7 @@ export class FileManager {
`File ${file.name} is too large. Maximum size is 50MB.`,
);
}
// Validate file type
const validation = this.validateFileType(file);
if (!validation.valid) {
@ -241,7 +258,7 @@ export class FileManager {
.getOne<T>(recordId);
existingFiles = (record as any)[field] || [];
} catch (error) {
console.warn("Failed to fetch existing record:", error);
// console.warn("Failed to fetch existing record:", error);
}
}
@ -260,7 +277,7 @@ export class FileManager {
processedFile = await this.compressImageIfNeeded(file, 50); // 50MB max size
}
} catch (error) {
console.warn(`Failed to process file ${file.name}:`, error);
// console.warn(`Failed to process file ${file.name}:`, error);
processedFile = file; // Use original file if processing fails
}
@ -298,7 +315,7 @@ export class FileManager {
.getOne<T>(recordId);
return finalRecord;
} catch (err) {
console.error(`Failed to upload files to ${collectionName}:`, err);
// console.error(`Failed to upload files to ${collectionName}:`, err);
throw err;
} finally {
this.auth.setUpdating(false);
@ -324,33 +341,33 @@ export class FileManager {
const record = await pb.collection(collectionName).getOne(recordId);
existingFiles = record[field] || [];
} catch (error) {
console.warn("Failed to fetch existing record for duplicate check:", error);
// console.warn("Failed to fetch existing record for duplicate check:", error);
}
// Add new files, renaming duplicates if needed
for (const file of files) {
let fileToUpload = file;
// Check if filename already exists
if (Array.isArray(existingFiles) && existingFiles.includes(file.name)) {
const timestamp = new Date().getTime();
const nameParts = file.name.split('.');
const nameParts = file.name.split(".");
const extension = nameParts.pop();
const baseName = nameParts.join('.');
const baseName = nameParts.join(".");
const newFileName = `${baseName}_${timestamp}.${extension}`;
// Create a new file with the modified name
fileToUpload = new File([file], newFileName, { type: file.type });
console.log(`Renamed duplicate file from ${file.name} to ${newFileName}`);
// console.log(`Renamed duplicate file from ${file.name} to ${newFileName}`);
}
formData.append(field, fileToUpload);
}
// Tell PocketBase to keep existing files
if (existingFiles.length > 0) {
formData.append(`${field}@`, ''); // This tells PocketBase to keep existing files
formData.append(`${field}@`, ""); // This tells PocketBase to keep existing files
}
try {
@ -396,28 +413,28 @@ export class FileManager {
// Create FormData for the new files only
const formData = new FormData();
// Tell PocketBase to keep existing files
formData.append(`${field}@`, '');
formData.append(`${field}@`, "");
// Append new files, renaming if needed to avoid duplicates
for (const file of files) {
let fileToUpload = file;
// Check if filename already exists
if (existingFilenames.has(file.name)) {
const timestamp = new Date().getTime();
const nameParts = file.name.split('.');
const nameParts = file.name.split(".");
const extension = nameParts.pop();
const baseName = nameParts.join('.');
const baseName = nameParts.join(".");
const newFileName = `${baseName}_${timestamp}.${extension}`;
// Create a new file with the modified name
fileToUpload = new File([file], newFileName, { type: file.type });
console.log(`Renamed duplicate file from ${file.name} to ${newFileName}`);
// console.log(`Renamed duplicate file from ${file.name} to ${newFileName}`);
}
formData.append(field, fileToUpload);
}
@ -426,7 +443,7 @@ export class FileManager {
.update<T>(recordId, formData);
return result;
} catch (err) {
console.error(`Failed to append files to ${collectionName}:`, err);
// console.error(`Failed to append files to ${collectionName}:`, err);
throw err;
} finally {
this.auth.setUpdating(false);
@ -477,7 +494,7 @@ export class FileManager {
.update<T>(recordId, data);
return result;
} catch (err) {
console.error(`Failed to delete file from ${collectionName}:`, err);
// console.error(`Failed to delete file from ${collectionName}:`, err);
throw err;
} finally {
this.auth.setUpdating(false);
@ -512,7 +529,7 @@ export class FileManager {
const result = await response.blob();
return result;
} catch (err) {
console.error(`Failed to download file from ${collectionName}:`, err);
// console.error(`Failed to download file from ${collectionName}:`, err);
throw err;
} finally {
this.auth.setUpdating(false);
@ -552,7 +569,7 @@ export class FileManager {
return fileUrls;
} catch (err) {
console.error(`Failed to get files from ${collectionName}:`, err);
// console.error(`Failed to get files from ${collectionName}:`, err);
throw err;
} finally {
this.auth.setUpdating(false);
@ -643,22 +660,22 @@ export class FileManager {
public async getFileToken(): Promise<string> {
// Check authentication status
if (!this.auth.isAuthenticated()) {
console.warn("User is not authenticated when trying to get file token");
// console.warn("User is not authenticated when trying to get file token");
// Try to refresh the auth if possible
try {
const pb = this.auth.getPocketBase();
if (pb.authStore.isValid) {
console.log(
"Auth store is valid, but auth check failed. Trying to refresh token.",
);
// console.log(
// "Auth store is valid, but auth check failed. Trying to refresh token.",
// );
await pb.collection("users").authRefresh();
console.log("Auth refreshed successfully");
// console.log("Auth refreshed successfully");
} else {
throw new Error("User must be authenticated to get a file token");
}
} catch (refreshError) {
console.error("Failed to refresh authentication:", refreshError);
// console.error("Failed to refresh authentication:", refreshError);
throw new Error("User must be authenticated to get a file token");
}
}
@ -668,19 +685,19 @@ export class FileManager {
const pb = this.auth.getPocketBase();
// Log auth status
console.log("Auth status before getting token:", {
isValid: pb.authStore.isValid,
token: pb.authStore.token
? pb.authStore.token.substring(0, 10) + "..."
: "none",
model: pb.authStore.model ? pb.authStore.model.id : "none",
});
// console.log("Auth status before getting token:", {
// isValid: pb.authStore.isValid,
// token: pb.authStore.token
// ? pb.authStore.token.substring(0, 10) + "..."
// : "none",
// model: pb.authStore.model ? pb.authStore.model.id : "none",
// });
const result = await pb.files.getToken();
console.log("Got file token:", result.substring(0, 10) + "...");
// console.log("Got file token:", result.substring(0, 10) + "...");
return result;
} catch (err) {
console.error("Failed to get file token:", err);
// console.error("Failed to get file token:", err);
throw err;
} finally {
this.auth.setUpdating(false);
@ -705,25 +722,25 @@ export class FileManager {
// Check if filename is empty
if (!filename) {
console.error(
`Empty filename provided for ${collectionName}/${recordId}`,
);
// console.error(
// `Empty filename provided for ${collectionName}/${recordId}`,
// );
return "";
}
// Check if user is authenticated
if (!this.auth.isAuthenticated()) {
console.warn("User is not authenticated when trying to get file URL");
// console.warn("User is not authenticated when trying to get file URL");
}
// Always try to use token for protected files
if (useToken) {
try {
console.log(
`Getting file token for ${collectionName}/${recordId}/${filename}`,
);
// console.log(
// `Getting file token for ${collectionName}/${recordId}/${filename}`,
// );
const token = await this.getFileToken();
console.log(`Got token: ${token.substring(0, 10)}...`);
// console.log(`Got token: ${token.substring(0, 10)}...`);
// Make sure to pass the token as a query parameter
const url = pb.files.getURL(
@ -731,16 +748,16 @@ export class FileManager {
filename,
{ token },
);
console.log(`Generated URL with token: ${url.substring(0, 50)}...`);
// console.log(`Generated URL with token: ${url.substring(0, 50)}...`);
return url;
} catch (error) {
console.error("Error getting file token:", error);
// console.error("Error getting file token:", error);
// Fall back to URL without token
const url = pb.files.getURL(
{ id: recordId, collectionId: collectionName },
filename,
);
console.log(`Fallback URL without token: ${url.substring(0, 50)}...`);
// console.log(`Fallback URL without token: ${url.substring(0, 50)}...`);
return url;
}
}
@ -750,7 +767,7 @@ export class FileManager {
{ id: recordId, collectionId: collectionName },
filename,
);
console.log(`Generated URL without token: ${url.substring(0, 50)}...`);
// console.log(`Generated URL without token: ${url.substring(0, 50)}...`);
return url;
}
}