feat: Implement authentication checks for profile actions and user layout, and add presigned URL fetching for file viewing.
This commit is contained in:
@@ -444,6 +444,7 @@ function RangeSlider({ field, value, onChange }: RangeSliderProps) {
|
||||
// File Upload Types
|
||||
interface UploadedFile {
|
||||
id: string;
|
||||
key?: string; // S3 key for fetching presigned URL
|
||||
name: string;
|
||||
size: number;
|
||||
type: string;
|
||||
@@ -459,6 +460,12 @@ interface UploadingFile {
|
||||
error?: string;
|
||||
}
|
||||
|
||||
// Map to store presigned URLs by file ID
|
||||
interface FileWithPresignedUrl extends UploadedFile {
|
||||
presignedUrl?: string;
|
||||
isLoadingUrl?: boolean;
|
||||
}
|
||||
|
||||
// File Upload Component
|
||||
interface FileUploadProps {
|
||||
field: ProfileField;
|
||||
@@ -471,6 +478,8 @@ function FileUpload({ field, fieldSlug, value, onChange }: FileUploadProps) {
|
||||
const fileInputRef = useRef<HTMLInputElement>(null);
|
||||
const [isDragging, setIsDragging] = useState(false);
|
||||
const [uploadingFiles, setUploadingFiles] = useState<UploadingFile[]>([]);
|
||||
const [presignedUrls, setPresignedUrls] = useState<Record<string, string>>({});
|
||||
const [loadingUrls, setLoadingUrls] = useState<Record<string, boolean>>({});
|
||||
|
||||
// Get allowed formats from field config or use defaults
|
||||
const allowedFormats = field.validation?.allowedFormats || ['PDF', 'DOCX', 'JPG', 'PNG'];
|
||||
@@ -631,6 +640,42 @@ function FileUpload({ field, fieldSlug, value, onChange }: FileUploadProps) {
|
||||
fileInputRef.current?.click();
|
||||
};
|
||||
|
||||
const handleViewFile = async (file: UploadedFile) => {
|
||||
// Check if we already have a presigned URL
|
||||
if (presignedUrls[file.id]) {
|
||||
window.open(presignedUrls[file.id], '_blank');
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the key - either from file.key, file.id, or file.url if it's an S3 key
|
||||
const fileKey = file.key || file.id || file.url;
|
||||
|
||||
// If the URL is already a full URL (http/https), just open it directly
|
||||
if (fileKey.startsWith('http://') || fileKey.startsWith('https://')) {
|
||||
window.open(fileKey, '_blank');
|
||||
return;
|
||||
}
|
||||
|
||||
// Set loading state
|
||||
setLoadingUrls(prev => ({ ...prev, [file.id]: true }));
|
||||
|
||||
try {
|
||||
const { uploadService } = await import('@/services/upload.service');
|
||||
const presignedUrl = await uploadService.getPresignedDownloadUrl(fileKey);
|
||||
|
||||
// Store for future use
|
||||
setPresignedUrls(prev => ({ ...prev, [file.id]: presignedUrl }));
|
||||
|
||||
// Open the file
|
||||
window.open(presignedUrl, '_blank');
|
||||
} catch (error) {
|
||||
console.error('Failed to get presigned URL:', error);
|
||||
alert('Failed to open file. Please try again.');
|
||||
} finally {
|
||||
setLoadingUrls(prev => ({ ...prev, [file.id]: false }));
|
||||
}
|
||||
};
|
||||
|
||||
const isUploading = uploadingFiles.length > 0;
|
||||
|
||||
return (
|
||||
@@ -744,20 +789,14 @@ function FileUpload({ field, fieldSlug, value, onChange }: FileUploadProps) {
|
||||
>
|
||||
<div className="flex-1 min-w-0">
|
||||
<div className="flex items-center gap-2">
|
||||
{file.url ? (
|
||||
<a
|
||||
href={file.url}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-[14px] font-serif text-[#E58625] hover:underline truncate"
|
||||
>
|
||||
{file.name}
|
||||
</a>
|
||||
) : (
|
||||
<span className="text-[14px] font-serif text-[#00293D] truncate">
|
||||
{file.name}
|
||||
</span>
|
||||
)}
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => handleViewFile(file)}
|
||||
disabled={loadingUrls[file.id]}
|
||||
className="text-[14px] font-serif text-[#E58625] hover:underline truncate text-left disabled:opacity-50"
|
||||
>
|
||||
{loadingUrls[file.id] ? 'Loading...' : file.name}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => handleRemoveFile(file.id)}
|
||||
|
||||
Reference in New Issue
Block a user