Add authentication #17

Manually merged
Webmaster merged 225 commits from auth into main 2025-03-08 10:37:06 +00:00
4 changed files with 89 additions and 80 deletions
Showing only changes of commit f3efea865b - Show all commits

View file

@ -19,11 +19,15 @@ export const FileViewerModalWrapper: React.FC = () => {
const [files, setFiles] = useState<FileType[]>([]);
useEffect(() => {
let mounted = true;
// Listen for custom events to open/close modal and set files
const handleShowFiles = (event: CustomEvent) => {
const { files } = event.detail;
setFiles(Array.isArray(files) ? files : [files]);
setIsOpen(true);
if (mounted) {
const { files } = event.detail;
setFiles(Array.isArray(files) ? files : [files]);
setIsOpen(true);
}
};
// Add event listeners
@ -31,14 +35,38 @@ export const FileViewerModalWrapper: React.FC = () => {
// Cleanup
return () => {
mounted = false;
window.removeEventListener('showFileViewer' as any, handleShowFiles);
// Reset state on unmount
setIsOpen(false);
setFiles([]);
};
}, []);
// Handle tab visibility changes
useEffect(() => {
const handleVisibilityChange = () => {
if (document.hidden) {
setIsOpen(false);
setFiles([]);
}
};
document.addEventListener('visibilitychange', handleVisibilityChange);
return () => {
document.removeEventListener('visibilitychange', handleVisibilityChange);
};
}, []);
const handleClose = () => {
setIsOpen(false);
setFiles([]);
};
// Only render the modal if we have files and it should be open
if (!isOpen || files.length === 0) return null;
return (
<FileViewerModal
isOpen={isOpen}
@ -57,6 +85,16 @@ const FileViewerModal: React.FC<FileViewerModalProps> = ({ isOpen, onClose, file
const fileArray = Array.isArray(files) ? files : [files];
// Reset state when modal closes
useEffect(() => {
if (!isOpen) {
setLoading(true);
setError(null);
setSelectedFile(null);
setShowPreview(false);
}
}, [isOpen]);
// Helper function to check if file type is previewable
const isPreviewableType = (fileType: string): boolean => {
return (
@ -71,21 +109,19 @@ const FileViewerModal: React.FC<FileViewerModalProps> = ({ isOpen, onClose, file
useEffect(() => {
if (isOpen) {
// Only set loading if the file is previewable
if (selectedFile && isPreviewableType(selectedFile.type)) {
setLoading(true);
// Only show file directly if there's exactly one file
if (fileArray.length === 1) {
const fileToShow = fileArray[0];
setSelectedFile(fileToShow);
setShowPreview(true);
setLoading(isPreviewableType(fileToShow.type));
} else {
// For multiple files, show the file browser
setShowPreview(false);
setSelectedFile(null);
setLoading(false);
}
setError(null);
// If single file, show preview directly
if (!Array.isArray(files)) {
setSelectedFile(files);
setShowPreview(true);
} else {
setShowPreview(false);
setSelectedFile(null);
}
}
}, [isOpen, files]);
@ -101,7 +137,6 @@ const FileViewerModal: React.FC<FileViewerModalProps> = ({ isOpen, onClose, file
const handleFileSelect = (file: FileType) => {
setSelectedFile(file);
setShowPreview(true);
// Only set loading if the file is previewable
setLoading(isPreviewableType(file.type));
setError(null);
};
@ -198,7 +233,6 @@ const FileViewerModal: React.FC<FileViewerModalProps> = ({ isOpen, onClose, file
);
}
// Fallback for unsupported file types
return (
<div className="flex flex-col items-center justify-center p-8">
<div className="text-4xl mb-4">📄</div>
@ -253,19 +287,6 @@ const FileViewerModal: React.FC<FileViewerModalProps> = ({ isOpen, onClose, file
);
};
// Clone the modal with a new ID
const cloneModal = () => {
const newModalId = `${modalId}-${Date.now()}`;
return (
<FileViewerModal
isOpen={isOpen}
onClose={onClose}
files={files}
modalId={newModalId}
/>
);
};
if (!isOpen) return null;
return (
@ -283,13 +304,14 @@ const FileViewerModal: React.FC<FileViewerModalProps> = ({ isOpen, onClose, file
{showPreview && selectedFile ? (
<>
<div className="flex items-center gap-3">
<button
className="btn btn-ghost btn-sm"
onClick={handleBackToList}
style={{ display: Array.isArray(files) ? 'block' : 'none' }}
>
Back
</button>
{fileArray.length > 1 && (
<button
className="btn btn-ghost btn-sm"
onClick={handleBackToList}
>
Back
</button>
)}
<h3 className="font-bold text-lg truncate">{selectedFile.name}</h3>
</div>
</>
@ -297,25 +319,6 @@ const FileViewerModal: React.FC<FileViewerModalProps> = ({ isOpen, onClose, file
<h3 className="font-bold text-lg">File Browser</h3>
)}
<div className="flex gap-2">
<button
className="btn btn-circle btn-ghost"
onClick={cloneModal}
>
<svg
xmlns="http://www.w3.org/2000/svg"
className="h-6 w-6"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z"
/>
</svg>
</button>
<button
className="btn btn-circle btn-ghost"
onClick={onClose}

View file

@ -1,7 +1,4 @@
---
// Import the FileViewerModal component
import FileViewerModal from "../modals/FileViewerModal";
// Define the component's props and setup
interface Props {}
const {} = Astro.props;
@ -124,9 +121,6 @@ const {} = Astro.props;
</div>
</div>
<!-- Add the FileViewerModal component -->
<FileViewerModal client:load />
<script>
// TypeScript declarations
declare global {

View file

@ -1,7 +1,6 @@
---
// Import the majors list and FilePreviewModal
// Import the majors list
import allMajors from "../../data/allUCSDMajors.txt?raw";
import FilePreviewModal from "../modals/FilePreviewModal.astro";
const majorsList: string[] = allMajors
.split("\n")
@ -183,7 +182,7 @@ const majorsList: string[] = allMajors
<button
id="previewResume"
class="btn btn-sm btn-ghost"
onclick="resumeViewer.showModal()"
onclick="showResumePreview(resumeUrl, fileName)"
>
<svg
xmlns="http://www.w3.org/2000/svg"
@ -228,24 +227,19 @@ const majorsList: string[] = allMajors
</div>
</div>
<!-- Replace the old resume viewer modal with the new FilePreviewModal -->
<FilePreviewModal id="resumeViewer" title="Resume Preview" />
<script>
// TypeScript declarations
declare global {
interface Window {
showEventFiles: (eventId: string) => Promise<void>;
}
}
import { Authentication } from "../pocketbase/Authentication";
import { Update } from "../pocketbase/Update";
import { SendLog } from "../pocketbase/SendLog";
import { FileManager } from "../pocketbase/FileManager";
// Add type declaration for the global filePreviewModal
declare global {
interface Window {
filePreviewModal: {
show: (file: { url: string; name: string }) => void;
};
}
}
const auth = Authentication.getInstance();
const update = Update.getInstance();
const logger = SendLog.getInstance();
@ -272,6 +266,23 @@ const majorsList: string[] = allMajors
const resumeDisplay = document.getElementById("resumeDisplay");
const previewResume = document.getElementById("previewResume");
// Function to show resume in FileViewerModal
const showResumePreview = (url: string, fileName: string) => {
// Create and dispatch custom event for FileViewerModal
const showFileViewerEvent = new CustomEvent("showFileViewer", {
detail: {
files: {
url,
name: fileName,
type: fileName.toLowerCase().endsWith(".pdf")
? "application/pdf"
: "application/octet-stream",
},
},
});
window.dispatchEvent(showFileViewerEvent);
};
// Load current user data
const loadUserData = () => {
if (auth.isAuthenticated()) {
@ -300,10 +311,7 @@ const majorsList: string[] = allMajors
// Update preview button to use new modal
if (previewResume) {
previewResume.onclick = () => {
window.filePreviewModal.show({
url: resumeUrl,
name: fileName,
});
showResumePreview(resumeUrl, fileName);
};
}
} else {

View file

@ -4,6 +4,7 @@ import UserProfile from "../components/auth/UserProfile.astro";
import DefaultProfileView from "../components/profile/DefaultProfileView.astro";
import OfficerProfileView from "../components/profile/OfficerView.astro";
import UserSettings from "../components/profile/UserSettings.astro";
import FileViewerModal from "../components/modals/FileViewerModal";
import yaml from "js-yaml";
import profileConfig from "../config/profileConfig.yaml?raw";
import textConfig from "../config/text.yml?raw";
@ -213,6 +214,9 @@ const text = yaml.load(textConfig) as any;
</div>
</div>
</div>
<!-- Add FileViewerModal here, outside of the tab content -->
<FileViewerModal client:load />
</main>
</Layout>