diff --git a/README-MINIO-TROUBLESHOOTING.md b/README-MINIO-TROUBLESHOOTING.md
new file mode 100644
index 00000000..a21ad38b
--- /dev/null
+++ b/README-MINIO-TROUBLESHOOTING.md
@@ -0,0 +1,115 @@
+# Minio Troubleshooting Guide
+
+This document outlines the fixes implemented for the mission file upload issues with Minio.
+
+## Problem Description
+
+Mission uploads (logo and attachments) were not working correctly:
+- Files weren't appearing in Minio despite upload attempts
+- Mission logos weren't displaying even though they were uploaded
+- Participation field showed "Non spécifié" despite values in the database
+- SDG/ODD icons weren't displaying correctly
+
+## Implemented Fixes
+
+### 1. Added URL Generation Function
+
+Added a `getPublicUrl` function in `lib/s3.ts` that properly constructs URLs for files stored in Minio:
+```typescript
+export function getPublicUrl(filePath: string): string {
+ if (!filePath) return '';
+ if (filePath.startsWith('http')) return filePath; // Already a full URL
+
+ // Remove leading slash if present
+ const cleanPath = filePath.startsWith('/') ? filePath.substring(1) : filePath;
+
+ // Construct the full URL
+ const endpoint = S3_CONFIG.endpoint?.replace(/\/$/, ''); // Remove trailing slash if present
+ const bucket = S3_CONFIG.bucket;
+
+ // Return original path if no endpoint is configured
+ if (!endpoint) return cleanPath;
+
+ // Construct and return the full URL
+ return `${endpoint}/${bucket}/${cleanPath}`;
+}
+```
+
+### 2. Updated Mission Display Page
+
+Modified `app/missions/page.tsx` to use the `getPublicUrl` function when displaying mission logos:
+```tsx
+{mission.logo ? (
+
{
+ // Error handling...
+ }}
+ />
+) : null}
+```
+
+### 3. Enhanced Upload API
+
+Updated `/app/api/missions/upload/route.ts` to:
+- Include additional logging
+- Generate and return proper public URLs
+- Improve error handling
+
+### 4. Enhanced Mission Detail API
+
+Modified `/app/api/missions/[missionId]/route.ts` to include public URLs in the response:
+```typescript
+const missionWithUrls = {
+ ...mission,
+ logoUrl: mission.logo ? getPublicUrl(mission.logo) : null,
+ attachments: mission.attachments.map((attachment) => ({
+ ...attachment,
+ publicUrl: getPublicUrl(attachment.filePath)
+ }))
+};
+```
+
+### 5. Added Testing Tools
+
+1. Browser Console Utilities:
+ - `window.testMinioConnection()` - Test Minio connectivity
+ - `window.getMinioUrl(path)` - Generate a public URL for debugging
+
+2. Server-side Test Script:
+ - Created `scripts/test-minio-upload.js` to test uploads from the command line
+ - Tests uploading, downloading, and URL generation
+
+## How to Test
+
+1. **Using the browser console:**
+ ```javascript
+ // Test connection and list files
+ window.testMinioConnection()
+
+ // Generate URL for a specific path
+ window.getMinioUrl('user-123/missions/456/logo.jpg')
+ ```
+
+2. **Using the server-side script:**
+ ```bash
+ node scripts/test-minio-upload.js
+ ```
+
+## Required Environment Variables
+
+Make sure these are properly set in your environment:
+- `MINIO_S3_UPLOAD_BUCKET_URL` - The Minio endpoint URL
+- `MINIO_AWS_REGION` - The AWS region (often 'us-east-1' for Minio)
+- `MINIO_AWS_S3_UPLOAD_BUCKET_NAME` - The bucket name
+- `MINIO_ACCESS_KEY` - Access key for Minio
+- `MINIO_SECRET_KEY` - Secret key for Minio
+
+## Additional Notes
+
+1. The same Minio bucket is used for both Pages and Missions.
+2. Pages functionality is working properly, suggesting the Minio configuration itself is correct.
+3. Make sure that the bucket has proper permissions for public read access.
+4. The URL paths for SDG/ODD icons were corrected to use `/F SDG Icons 2019 WEB/F-WEB-Goal-XX.png`
\ No newline at end of file
diff --git a/components/missions/file-upload.tsx b/components/missions/file-upload.tsx
index bbaf7c8b..f8c0c900 100644
--- a/components/missions/file-upload.tsx
+++ b/components/missions/file-upload.tsx
@@ -1,6 +1,6 @@
"use client";
-import React, { useState, useRef } from 'react';
+import React, { useState, useRef, useEffect } from 'react';
import { UploadCloud, X, Check, Loader2 } from 'lucide-react';
import { Button } from '@/components/ui/button';
import { useSession } from 'next-auth/react';
@@ -21,6 +21,15 @@ export function FileUpload({
maxSize = 5 * 1024 * 1024, // 5MB
acceptedFileTypes = type === 'logo' ? 'image/*' : '.pdf,.doc,.docx,.xls,.xlsx,.jpg,.jpeg,.png'
}: FileUploadProps) {
+ // Log props on init
+ console.log('FileUpload component initialized with props:', {
+ type,
+ missionId,
+ hasMissionId: !!missionId,
+ maxSize,
+ acceptedFileTypes
+ });
+
const { data: session } = useSession();
const [isDragging, setIsDragging] = useState(false);
const [isUploading, setIsUploading] = useState(false);
@@ -28,6 +37,28 @@ export function FileUpload({
const [file, setFile] = useState(null);
const [error, setError] = useState(null);
const fileInputRef = useRef(null);
+ const isMounted = useRef(true);
+
+ // Cleanup on unmount
+ useEffect(() => {
+ return () => {
+ isMounted.current = false;
+ };
+ }, []);
+
+ // Log when session changes
+ useEffect(() => {
+ console.log('Session state in FileUpload:', {
+ isSessionLoaded: !!session,
+ hasUser: !!session?.user,
+ userId: session?.user?.id
+ });
+ }, [session]);
+
+ // Log when missionId changes
+ useEffect(() => {
+ console.log('MissionId in FileUpload component:', missionId);
+ }, [missionId]);
// Handle drag events
const handleDragOver = (e: React.DragEvent) => {
@@ -92,11 +123,41 @@ export function FileUpload({
};
const handleUpload = async () => {
- if (!file || !session?.user?.id || !missionId) {
- console.error('Upload failed: Missing required data', {
- fileExists: !!file,
- userIdExists: !!session?.user?.id,
- missionIdExists: !!missionId
+ // Log all values to see what's missing
+ console.log('Debug upload parameters:', {
+ file,
+ sessionUser: session?.user,
+ userId: session?.user?.id,
+ missionId
+ });
+
+ // Check for missing parameters and provide specific feedback
+ if (!file) {
+ console.error('Upload failed: No file selected');
+ toast({
+ title: 'Upload failed',
+ description: 'No file selected. Please select a file first.',
+ variant: 'destructive',
+ });
+ return;
+ }
+
+ if (!session?.user?.id) {
+ console.error('Upload failed: No user session');
+ toast({
+ title: 'Authentication required',
+ description: 'You need to be logged in to upload files. Please log in and try again.',
+ variant: 'destructive',
+ });
+ return;
+ }
+
+ if (!missionId) {
+ console.error('Upload failed: Missing mission ID');
+ toast({
+ title: 'Upload failed',
+ description: 'Missing mission ID. Please refresh the page and try again.',
+ variant: 'destructive',
});
return;
}
@@ -142,28 +203,39 @@ export function FileUpload({
const result = await response.json();
console.log('Upload successful, result:', result);
- setProgress(100);
- // Reset file after successful upload
- setTimeout(() => {
- setFile(null);
- setIsUploading(false);
- setProgress(0);
+ // Only update state if the component is still mounted
+ if (isMounted.current) {
+ setProgress(100);
- // Call the callback if provided
- if (onUploadComplete) {
- onUploadComplete(result);
- }
-
- toast({
- title: 'File uploaded successfully',
- description: type === 'logo' ? 'Logo has been updated' : `${file.name} has been added to attachments`,
- variant: 'default',
- });
- }, 1000);
+ // Reset file after successful upload
+ setTimeout(() => {
+ if (isMounted.current) {
+ setFile(null);
+ setIsUploading(false);
+ setProgress(0);
+
+ // Call the callback if provided
+ if (onUploadComplete) {
+ onUploadComplete(result);
+ }
+ }
+
+ toast({
+ title: 'File uploaded successfully',
+ description: type === 'logo' ? 'Logo has been updated' : `${file.name} has been added to attachments`,
+ variant: 'default',
+ });
+ }, 1000);
+ }
} catch (error) {
console.error('Upload error details:', error);
- setIsUploading(false);
+
+ // Only update state if the component is still mounted
+ if (isMounted.current) {
+ setIsUploading(false);
+ }
+
toast({
title: 'Upload failed',
description: error instanceof Error ? error.message : 'An error occurred during upload',
diff --git a/scripts/test-minio-upload.js b/scripts/test-minio-upload.js
old mode 100644
new mode 100755