"use client"; import React, { useState, useEffect } from "react"; import { logger } from '@/lib/logger'; import { Tabs, TabsContent, TabsList, TabsTrigger } from "../ui/tabs"; import { Input } from "../ui/input"; import { Button } from "../ui/button"; import { Textarea } from "../ui/textarea"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "../ui/select"; import { Checkbox } from "../ui/checkbox"; import { Card, CardContent } from "../ui/card"; import { Badge } from "../ui/badge"; import { X, UploadCloud, File } from "lucide-react"; import { toast } from "../ui/use-toast"; import { FileUpload } from "./file-upload"; import { AttachmentsList } from "./attachments-list"; import { MissionMembersPanel } from "./mission-members-panel"; import { useRouter } from "next/navigation"; interface MissionData { name?: string; logo?: { data: string; name: string; type: string; }; oddScope?: string[]; niveau?: string; intention?: string; missionType?: string; donneurDOrdre?: string; projection?: string; services?: string[]; profils?: string[]; participation?: string; } export function MissionsAdminPanel() { const router = useRouter(); const [selectedServices, setSelectedServices] = useState([]); const [selectedProfils, setSelectedProfils] = useState([]); const [gardienDuTemps, setGardienDuTemps] = useState(null); const [gardienDeLaParole, setGardienDeLaParole] = useState(null); const [gardienDeLaMemoire, setGardienDeLaMemoire] = useState(null); const [volontaires, setVolontaires] = useState([]); const [missionId, setMissionId] = useState(""); const [activeTab, setActiveTab] = useState("general"); const [isSubmitting, setIsSubmitting] = useState(false); const [selectedLogoFile, setSelectedLogoFile] = useState(null); const [selectedAttachments, setSelectedAttachments] = useState([]); const [missionData, setMissionData] = useState({}); // Check if mission is valid (has all required guardiens) const isMissionValid = gardienDuTemps !== null && gardienDeLaParole !== null && gardienDeLaMemoire !== null; // Add a draft mission ID for uploads const [draftMissionId, setDraftMissionId] = useState(""); const [uploadedLogoPath, setUploadedLogoPath] = useState(null); const [uploadedAttachmentPaths, setUploadedAttachmentPaths] = useState([]); // Generate a draft mission ID on mount useEffect(() => { if (!draftMissionId) { const userId = typeof window !== 'undefined' && window.localStorage.getItem('userId'); const id = `draft-${userId || 'nouser'}-${Date.now()}`; setDraftMissionId(id); } }, [draftMissionId]); // Function to navigate to the next tab const goToNextTab = () => { const tabOrder = ["general", "details", "attachments", "skills", "membres"]; const currentIndex = tabOrder.indexOf(activeTab); if (currentIndex < tabOrder.length - 1) { const nextTab = tabOrder[currentIndex + 1]; setActiveTab(nextTab); } }; // Function to navigate to the previous tab const goToPreviousTab = () => { const tabOrder = ["general", "details", "attachments", "skills", "membres"]; const currentIndex = tabOrder.indexOf(activeTab); if (currentIndex > 0) { const prevTab = tabOrder[currentIndex - 1]; setActiveTab(prevTab); } }; // Check if we're on the last tab const isLastTab = () => { return activeTab === "membres"; }; // Check if we're on the first tab const isFirstTab = () => { return activeTab === "general"; }; // Validate all required fields const validateMission = () => { const requiredFields = { name: !!missionData.name, oddScope: Array.isArray(missionData.oddScope) && missionData.oddScope.length > 0, niveau: !!missionData.niveau, intention: !!missionData.intention, missionType: !!missionData.missionType, donneurDOrdre: !!missionData.donneurDOrdre, projection: !!missionData.projection, participation: !!missionData.participation, gardiens: gardienDuTemps !== null && gardienDeLaParole !== null && gardienDeLaMemoire !== null }; const missingFields = Object.entries(requiredFields) .filter(([_, value]) => value === false) .map(([key]) => key); if (missingFields.length > 0) { toast({ title: "Champs obligatoires manquants", description: `Veuillez remplir tous les champs obligatoires: ${missingFields.join(", ")}`, variant: "destructive", }); return false; } return true; }; // Helper function to convert File to base64 const convertFileToBase64 = (file: File): Promise => { return new Promise((resolve, reject) => { const reader = new FileReader(); reader.readAsDataURL(file); reader.onload = () => resolve(reader.result as string); reader.onerror = error => reject(error); }); }; // Handle mission submission const handleSubmitMission = async () => { console.log('[handleSubmitMission] Function called', { activeTab, isLastTab: activeTab === "membres" }); logger.debug('handleSubmitMission called', { activeTab, isLastTab: activeTab === "membres" }); if (!validateMission()) { console.log('[handleSubmitMission] Validation failed, returning early'); logger.debug('Validation failed, returning early'); return; } console.log('[handleSubmitMission] Validation passed, setting isSubmitting to true'); logger.debug('Validation passed, setting isSubmitting to true'); setIsSubmitting(true); try { // Prepare the mission data const guardians = { "gardien-temps": gardienDuTemps, "gardien-parole": gardienDeLaParole, "gardien-memoire": gardienDeLaMemoire }; // Convert attachments to base64 const attachmentsBase64 = await Promise.all( selectedAttachments.map(async (file) => { const base64Data = await convertFileToBase64(file); return { data: base64Data, name: file.name, type: file.type }; }) ); console.log('[handleSubmitMission] Converted attachments to base64', { count: attachmentsBase64.length }); const missionSubmitData = { ...missionData, services: selectedServices, profils: selectedProfils, guardians, volunteers: volontaires, logo: missionData.logo, // Ensure logo data is included attachments: attachmentsBase64 // Include attachments as base64 }; console.log('[handleSubmitMission] Prepared mission data', { hasName: !!missionSubmitData.name, hasOddScope: !!missionSubmitData.oddScope, hasLogo: !!missionSubmitData.logo, logoType: missionSubmitData.logo ? typeof missionSubmitData.logo : 'null', servicesCount: missionSubmitData.services?.length || 0, profilsCount: missionSubmitData.profils?.length || 0, volunteersCount: missionSubmitData.volunteers?.length || 0, attachmentsCount: missionSubmitData.attachments?.length || 0, hasGuardians: !!(missionSubmitData.guardians && Object.keys(missionSubmitData.guardians).length > 0) }); logger.debug('Prepared mission data', { hasName: !!missionSubmitData.name, hasOddScope: !!missionSubmitData.oddScope, hasLogo: !!missionSubmitData.logo, logoType: missionSubmitData.logo ? typeof missionSubmitData.logo : 'null', servicesCount: missionSubmitData.services?.length || 0, profilsCount: missionSubmitData.profils?.length || 0, volunteersCount: missionSubmitData.volunteers?.length || 0, attachmentsCount: missionSubmitData.attachments?.length || 0, hasGuardians: !!(missionSubmitData.guardians && Object.keys(missionSubmitData.guardians).length > 0) }); // Test JSON serialization before sending let jsonString; try { jsonString = JSON.stringify(missionSubmitData); console.log('[handleSubmitMission] JSON.stringify successful', { jsonLength: jsonString.length }); logger.debug('JSON.stringify successful', { jsonLength: jsonString.length }); } catch (jsonError) { console.error('[handleSubmitMission] JSON.stringify failed', jsonError); logger.error('JSON.stringify failed', { error: jsonError instanceof Error ? jsonError.message : String(jsonError), missionDataKeys: Object.keys(missionSubmitData) }); throw new Error(`Failed to serialize mission data: ${jsonError instanceof Error ? jsonError.message : String(jsonError)}`); } console.log('[handleSubmitMission] Sending fetch request to /api/missions'); logger.debug('Sending fetch request to /api/missions'); // Send to API const response = await fetch('/api/missions', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: jsonString, }); console.log('[handleSubmitMission] Fetch response received', { status: response.status, ok: response.ok, statusText: response.statusText }); logger.debug('Fetch response received', { status: response.status, ok: response.ok, statusText: response.statusText }); if (!response.ok) { const errorData = await response.json(); console.error('[handleSubmitMission] API returned error response', { status: response.status, error: errorData.error, errorData }); logger.error('API returned error response', { status: response.status, error: errorData.error, errorData }); throw new Error(errorData.error || 'Failed to create mission'); } const data = await response.json(); console.log('[handleSubmitMission] Mission created successfully', { missionId: data.mission?.id, success: data.success }); logger.debug('Mission created successfully', { missionId: data.mission?.id, success: data.success }); toast({ title: "Mission créée avec succès", description: "Tous les gardiens ont été assignés et la mission a été enregistrée.", }); // Redirect to missions list router.push('/missions'); } catch (error) { console.error('[handleSubmitMission] Error creating mission', { error: error instanceof Error ? error.message : String(error), errorType: error instanceof Error ? error.constructor.name : typeof error, errorStack: error instanceof Error ? error.stack : undefined, missionData: { hasName: !!missionData.name, hasOddScope: !!missionData.oddScope, hasLogo: !!missionData.logo, servicesCount: selectedServices.length, profilsCount: selectedProfils.length, volunteersCount: volontaires.length, hasGuardians: !!(gardienDuTemps && gardienDeLaParole && gardienDeLaMemoire) } }); logger.error('Error creating mission', { error: error instanceof Error ? error.message : String(error), errorType: error instanceof Error ? error.constructor.name : typeof error, missionData: { hasName: !!missionData.name, hasOddScope: !!missionData.oddScope, hasLogo: !!missionData.logo, servicesCount: selectedServices.length, profilsCount: selectedProfils.length, volunteersCount: volontaires.length, hasGuardians: !!(gardienDuTemps && gardienDeLaParole && gardienDeLaMemoire) } }); toast({ title: "Erreur", description: error instanceof Error ? error.message : "Une erreur est survenue lors de la création de la mission", variant: "destructive", }); } finally { console.log('[handleSubmitMission] Finally block - setting isSubmitting to false'); setIsSubmitting(false); } }; // Function to handle input changes const handleInputChange = (field: string, value: any) => { setMissionData(prev => ({ ...prev, [field]: value })); }; return (
Général Détails Documents Compétences Membres
handleInputChange('name', e.target.value)} />
{ setMissionData(prev => ({ ...prev, logo: fileData })); }} />
Paragraphe