diff --git a/attached_assets/{56D2641F-E36F-413A-9B5A-9D6E39B88B8E}_1760435149127.png b/attached_assets/{56D2641F-E36F-413A-9B5A-9D6E39B88B8E}_1760435149127.png new file mode 100644 index 0000000..c815a2c Binary files /dev/null and b/attached_assets/{56D2641F-E36F-413A-9B5A-9D6E39B88B8E}_1760435149127.png differ diff --git a/client/src/components/media-upload.tsx b/client/src/components/media-upload.tsx index 9340414..6200180 100644 --- a/client/src/components/media-upload.tsx +++ b/client/src/components/media-upload.tsx @@ -115,7 +115,14 @@ export default function MediaUpload() { const handleCameraCapture = (e: React.ChangeEvent) => { const file = e.target.files?.[0]; if (file) { - uploadMutation.mutate(file); + // Correction Android : créer un nom valide si le fichier n'a pas de nom + let fileToUpload = file; + if (!file.name || file.name === 'blob' || file.name === '') { + const extension = file.type.split('/')[1] || 'jpg'; + const newFileName = `camera-${Date.now()}.${extension}`; + fileToUpload = new File([file], newFileName, { type: file.type }); + } + uploadMutation.mutate(fileToUpload); // Réinitialiser l'input pour permettre de capturer la même photo à nouveau e.target.value = ''; } diff --git a/client/src/pages/new-post.tsx b/client/src/pages/new-post.tsx index c841d79..83fd9dc 100644 --- a/client/src/pages/new-post.tsx +++ b/client/src/pages/new-post.tsx @@ -294,7 +294,14 @@ export default function NewPost() { const handleCameraCapture = (e: React.ChangeEvent) => { const file = e.target.files?.[0]; if (file) { - uploadMutation.mutate(file); + // Correction Android : créer un nom valide si le fichier n'a pas de nom + let fileToUpload = file; + if (!file.name || file.name === 'blob' || file.name === '') { + const extension = file.type.split('/')[1] || 'jpg'; + const newFileName = `camera-${Date.now()}.${extension}`; + fileToUpload = new File([file], newFileName, { type: file.type }); + } + uploadMutation.mutate(fileToUpload); } }; diff --git a/replit.md b/replit.md index 463934a..24f59b3 100644 --- a/replit.md +++ b/replit.md @@ -11,6 +11,7 @@ Preferred communication style: Simple, everyday language. ## Recent Changes ### October 14, 2025 +- **Android Camera Upload Fix**: Fixed critical Android camera capture bug where uploads failed with 400 error. Android devices send captured files with invalid names (empty, 'blob', etc.) that Multer rejects. Solution: `handleCameraCapture` now detects invalid filenames and creates new File object with generated name `camera-${timestamp}.${extension}` while preserving MIME type. Applied to both new-post and media-upload components. iPhone functionality unaffected. - **Mobile Performance Optimizations**: Implemented comprehensive mobile speed optimizations for "Nouvelle publication" and "Médiathèque" pages. Changes include: (1) Adaptive initial loading - 6 media items on mobile (<768px), 12 on desktop; (2) Optimized thumbnail URLs - replaced `originalUrl` with `facebookFeedUrl` (1080x1080 Cloudinary transformed images) for 70-90% reduction in data transfer while keeping `originalUrl` for zoom/preview quality; (3) Native lazy loading - added `loading="lazy"` attribute to all `` tags for deferred off-screen image loading; (4) Responsive grid layout - 2 columns on mobile, 3 on desktop (sm:grid-cols-3) for better touch targets. Expected impact: Initial load time reduced from 3-5s to <1s on mobile devices. - **Camera Capture in Media Library**: Added camera button 📷 to MediaUpload component, mirroring functionality from new-post page. Mobile users (lg:hidden) can now capture photos/videos directly from device camera and auto-upload to media library. Implementation includes hidden file input with `capture="environment"`, `handleCameraCapture` handler with input value reset (`e.target.value = ''`) to enable repeated captures, and integration with existing `uploadMutation` for seamless cloud storage. - **Video Publishing for Facebook**: Implemented complete video support for Facebook feed and stories. Added `publishVideoPost()` method using `/videos` endpoint with `file_url` parameter for feed videos, and `publishVideoStory()` using `/video_stories` endpoint for story videos. Modified `publishStory()` to detect video media type and route to appropriate handler. Updated `publishPost()` logic to separate image vs video media filtering and use correct publishing methods. Video preview now uses `