Add authentication #17
4 changed files with 89 additions and 80 deletions
|
@ -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}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
Loading…
Reference in a new issue