Page editor fixes and improvements and restructuring

This commit is contained in:
Reece
2025-06-24 23:31:21 +01:00
parent 2f90220b7b
commit ffe5b9577b
11 changed files with 313 additions and 265 deletions

View File

@@ -21,7 +21,6 @@ interface FilePickerModalProps {
onClose: () => void;
storedFiles: any[]; // Files from storage (FileWithUrl format)
onSelectFiles: (selectedFiles: File[]) => void;
allowMultiple?: boolean;
}
const FilePickerModal = ({
@@ -29,7 +28,6 @@ const FilePickerModal = ({
onClose,
storedFiles,
onSelectFiles,
allowMultiple = true,
}: FilePickerModalProps) => {
const { t } = useTranslation();
const [selectedFileIds, setSelectedFileIds] = useState<string[]>([]);
@@ -43,21 +41,14 @@ const FilePickerModal = ({
const toggleFileSelection = (fileId: string) => {
setSelectedFileIds(prev => {
if (allowMultiple) {
return prev.includes(fileId)
? prev.filter(id => id !== fileId)
: [...prev, fileId];
} else {
// Single selection mode
return prev.includes(fileId) ? [] : [fileId];
}
return prev.includes(fileId)
? prev.filter(id => id !== fileId)
: [...prev, fileId];
});
};
const selectAll = () => {
if (allowMultiple) {
setSelectedFileIds(storedFiles.map(f => f.id || f.name));
}
setSelectedFileIds(storedFiles.map(f => f.id || f.name));
};
const selectNone = () => {
@@ -145,20 +136,18 @@ const FilePickerModal = ({
<Group justify="space-between">
<Text size="sm" c="dimmed">
{storedFiles.length} {t("fileUpload.filesAvailable", "files available")}
{allowMultiple && selectedFileIds.length > 0 && (
{selectedFileIds.length > 0 && (
<> {selectedFileIds.length} selected</>
)}
</Text>
{allowMultiple && (
<Group gap="xs">
<Button size="xs" variant="light" onClick={selectAll}>
{t("pageEdit.selectAll", "Select All")}
</Button>
<Button size="xs" variant="light" onClick={selectNone}>
{t("pageEdit.deselectAll", "Select None")}
</Button>
</Group>
)}
<Group gap="xs">
<Button size="xs" variant="light" onClick={selectAll}>
{t("pageEdit.selectAll", "Select All")}
</Button>
<Button size="xs" variant="light" onClick={selectNone}>
{t("pageEdit.deselectAll", "Select None")}
</Button>
</Group>
</Group>
{/* File grid */}
@@ -186,21 +175,11 @@ const FilePickerModal = ({
onClick={() => toggleFileSelection(fileId)}
>
<Group gap="sm" align="flex-start">
{allowMultiple ? (
<Checkbox
checked={isSelected}
onChange={() => toggleFileSelection(fileId)}
onClick={(e) => e.stopPropagation()}
/>
) : (
<input
type="radio"
checked={isSelected}
onChange={() => toggleFileSelection(fileId)}
onClick={(e) => e.stopPropagation()}
style={{ margin: '4px' }}
/>
)}
<Checkbox
checked={isSelected}
onChange={() => toggleFileSelection(fileId)}
onClick={(e) => e.stopPropagation()}
/>
{/* Thumbnail */}
<Box

View File

@@ -1,4 +1,4 @@
import React, { useState, useCallback } from 'react';
import React, { useState, useCallback, useRef } from 'react';
import { Stack, Button, Text, Center } from '@mantine/core';
import { Dropzone } from '@mantine/dropzone';
import UploadFileIcon from '@mui/icons-material/UploadFile';
@@ -13,9 +13,8 @@ interface FileUploadSelectorProps {
// File handling
sharedFiles?: any[];
onFileSelect: (file: File) => void;
onFilesSelect?: (files: File[]) => void;
allowMultiple?: boolean;
onFileSelect?: (file: File) => void;
onFilesSelect: (files: File[]) => void;
accept?: string[];
// Loading state
@@ -30,39 +29,54 @@ const FileUploadSelector = ({
sharedFiles = [],
onFileSelect,
onFilesSelect,
allowMultiple = false,
accept = ["application/pdf"],
loading = false,
disabled = false,
}: FileUploadSelectorProps) => {
const { t } = useTranslation();
const [showFilePickerModal, setShowFilePickerModal] = useState(false);
const fileInputRef = useRef<HTMLInputElement>(null);
const handleFileUpload = useCallback((uploadedFiles: File[]) => {
if (uploadedFiles.length === 0) return;
if (allowMultiple && onFilesSelect) {
if (onFilesSelect) {
onFilesSelect(uploadedFiles);
} else {
} else if (onFileSelect) {
onFileSelect(uploadedFiles[0]);
}
}, [allowMultiple, onFileSelect, onFilesSelect]);
}, [onFileSelect, onFilesSelect]);
const handleFileInputChange = useCallback((event: React.ChangeEvent<HTMLInputElement>) => {
const files = event.target.files;
if (files && files.length > 0) {
const fileArray = Array.from(files);
console.log('File input change:', fileArray.length, 'files');
handleFileUpload(fileArray);
}
// Reset input
if (fileInputRef.current) {
fileInputRef.current.value = '';
}
}, [handleFileUpload]);
const openFileDialog = useCallback(() => {
fileInputRef.current?.click();
}, []);
const handleStorageSelection = useCallback((selectedFiles: File[]) => {
if (selectedFiles.length === 0) return;
if (allowMultiple && onFilesSelect) {
if (onFilesSelect) {
onFilesSelect(selectedFiles);
} else {
} else if (onFileSelect) {
onFileSelect(selectedFiles[0]);
}
}, [allowMultiple, onFileSelect, onFilesSelect]);
}, [onFileSelect, onFilesSelect]);
// Get default title and subtitle from translations if not provided
const displayTitle = title || t(allowMultiple ? "fileUpload.selectFiles" : "fileUpload.selectFile",
allowMultiple ? "Select files" : "Select a file");
const displaySubtitle = subtitle || t(allowMultiple ? "fileUpload.chooseFromStorageMultiple" : "fileUpload.chooseFromStorage",
allowMultiple ? "Choose files from storage or upload new PDFs" : "Choose a file from storage or upload a new PDF");
const displayTitle = title || t("fileUpload.selectFiles", "Select files");
const displaySubtitle = subtitle || t("fileUpload.chooseFromStorageMultiple", "Choose files from storage or upload new PDFs");
return (
<>
@@ -98,15 +112,15 @@ const FileUploadSelector = ({
<Dropzone
onDrop={handleFileUpload}
accept={accept}
multiple={allowMultiple}
multiple={true}
disabled={disabled || loading}
style={{ width: '100%', minHeight: 120 }}
activateOnClick={true}
>
<Center>
<Stack align="center" gap="sm">
<Text size="md" fw={500}>
{t(allowMultiple ? "fileUpload.dropFilesHere" : "fileUpload.dropFileHere",
allowMultiple ? "Drop files here or click to upload" : "Drop file here or click to upload")}
{t("fileUpload.dropFilesHere", "Drop files here or click to upload")}
</Text>
<Text size="sm" c="dimmed">
{accept.includes('application/pdf')
@@ -118,23 +132,27 @@ const FileUploadSelector = ({
</Center>
</Dropzone>
) : (
<Dropzone
onDrop={handleFileUpload}
accept={accept}
multiple={allowMultiple}
disabled={disabled || loading}
style={{ display: 'contents' }}
>
<Stack align="center" gap="sm">
<Button
variant="outline"
size="lg"
disabled={disabled}
loading={loading}
onClick={openFileDialog}
>
{t(allowMultiple ? "fileUpload.uploadFiles" : "fileUpload.uploadFile",
allowMultiple ? "Upload Files" : "Upload File")}
{t("fileUpload.uploadFiles", "Upload Files")}
</Button>
</Dropzone>
{/* Manual file input as backup */}
<input
ref={fileInputRef}
type="file"
multiple={true}
accept={accept.join(',')}
onChange={handleFileInputChange}
style={{ display: 'none' }}
/>
</Stack>
)}
</Stack>
</Stack>
@@ -145,7 +163,6 @@ const FileUploadSelector = ({
onClose={() => setShowFilePickerModal(false)}
storedFiles={sharedFiles}
onSelectFiles={handleStorageSelection}
allowMultiple={allowMultiple}
/>
</>
);