This commit is contained in:
lovebird 2026-04-06 23:32:34 +02:00
parent d80d046f65
commit 1fac563618
2 changed files with 92 additions and 9 deletions

View File

@ -4,7 +4,7 @@ import { useNavigate } from 'react-router-dom';
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription } from '@/components/ui/dialog';
import { Button } from '@/components/ui/button';
import { T, translate } from '@/i18n';
import { Image, FilePlus, Zap, Mic, Loader2, Upload, Video, Layers, BookPlus, Plus } from 'lucide-react';
import { Image, FilePlus, Zap, Mic, Loader2, Upload, Video, Layers, BookPlus, Plus, HardDrive } from 'lucide-react';
import { usePageGenerator } from '@/hooks/usePageGenerator';
import VoiceRecordingPopup from './VoiceRecordingPopup';
@ -20,6 +20,7 @@ import { createPicture } from '@/modules/posts/client-pictures';
import { fetchPostById } from '@/modules/posts/client-posts';
import { toast } from 'sonner';
import { supabase } from '@/integrations/supabase/client';
import { serverUrl } from '@/lib/db';
interface CreationWizardPopupProps {
isOpen: boolean;
@ -45,6 +46,8 @@ export const CreationWizardPopup: React.FC<CreationWizardPopupProps> = ({
const [isUploadingImage, setIsUploadingImage] = useState(false);
const [isUploadingVideo, setIsUploadingVideo] = useState(false);
const [videoUploadProgress, setVideoUploadProgress] = useState(0);
const [isUploadingFiles, setIsUploadingFiles] = useState(false);
const [fileUploadProgress, setFileUploadProgress] = useState(0);
const imageInputRef = useRef<HTMLInputElement>(null);
const videoInputRef = useRef<HTMLInputElement>(null);
@ -283,6 +286,66 @@ export const CreationWizardPopup: React.FC<CreationWizardPopupProps> = ({
imageInputRef.current?.click();
};
const handleFileUpload = async () => {
const filesToUpload = preloadedImages.filter(img => img.file);
if (filesToUpload.length === 0) {
toast.error(translate('No files to upload'));
return;
}
const { data: { session: authSession } } = await supabase.auth.getSession();
if (!authSession?.access_token) {
toast.error(translate('Please sign in to upload files'));
return;
}
setIsUploadingFiles(true);
setFileUploadProgress(0);
const mount = 'home';
let done = 0;
try {
await Promise.all(filesToUpload.map(img => new Promise<void>((resolve, reject) => {
const file = img.file as File;
const xhr = new XMLHttpRequest();
xhr.open('POST', `${serverUrl}/api/vfs/upload/${mount}/${encodeURIComponent(file.name)}`, true);
xhr.setRequestHeader('Authorization', `Bearer ${authSession.access_token}`);
xhr.upload.onprogress = (evt) => {
if (evt.lengthComputable) {
const filePct = (evt.loaded / evt.total) * 100;
setFileUploadProgress(Math.round(((done * 100) + filePct) / filesToUpload.length));
}
};
xhr.onload = () => {
done++;
setFileUploadProgress(Math.round((done / filesToUpload.length) * 100));
if (xhr.status >= 200 && xhr.status < 300) {
resolve();
} else {
let msg = `Error ${xhr.status}`;
try { const b = JSON.parse(xhr.responseText); msg = b.message || b.error || msg; } catch {}
reject(new Error(msg));
}
};
xhr.onerror = () => reject(new Error('Network error'));
const formData = new FormData();
formData.append('file', file);
xhr.send(formData);
})));
toast.success(translate(`${filesToUpload.length} file(s) uploaded to storage`));
onClose();
} catch (error: any) {
toast.error(error.message || translate('Upload failed'));
} finally {
setIsUploadingFiles(false);
setFileUploadProgress(0);
}
};
// Helper function to upload internal video
const uploadInternalVideo = async (file: File): Promise<void> => {
// Get auth token before creating the XHR
@ -526,6 +589,25 @@ export const CreationWizardPopup: React.FC<CreationWizardPopupProps> = ({
<T>Append to Existing Post</T>
</Button>
)}
{preloadedImages.length > 0 && (
<Button
variant="outline"
onClick={handleFileUpload}
disabled={isUploadingFiles}
>
{isUploadingFiles ? (
<>
<Loader2 className="h-4 w-4 mr-2 animate-spin" />
<T>Uploading</T> {fileUploadProgress}%
</>
) : (
<>
<HardDrive className="h-4 w-4 mr-2" />
<T>Upload as Files</T>
</>
)}
</Button>
)}
</div>
</div>

View File

@ -28,18 +28,19 @@ const GlobalDragDrop = () => {
// Check if it's a valid URL (simplistic check)
const isUrl = url && (url.startsWith('http://') || url.startsWith('https://'));
if (supportedFiles.length === 0 && !isUrl) {
if (files.length > 0) {
toast.error("Unsupported file type. Please drop images or videos.");
}
// Any file type is acceptable — wizard has "Upload as Files" for non-media
if (files.length === 0 && !isUrl) {
return;
}
// Use all files if no media-specific ones found (for VFS file upload)
const filesToPass = supportedFiles.length > 0 ? supportedFiles : files;
try {
if (supportedFiles.length > 0) {
// Normal file workflow
if (files.length > 0) {
// File workflow — wizard shows options incl. "Upload as Files"
await set('share-target', {
files: supportedFiles,
files: filesToPass,
title: '',
text: '',
url: isUrl ? url : '',
@ -142,7 +143,7 @@ const GlobalDragDrop = () => {
<T>Drop files to upload</T>
</h2>
<p className="text-muted-foreground mt-2">
<T>Drag images or videos anywhere to start</T>
<T>Drag files anywhere to start</T>
</p>
</div>
);