// EditProjectModal - Modal for editing project details (admin) function EditProjectModal({ project, referenti, users, onClose, onSuccess }) { // Get today's date in YYYY-MM-DD format for fallback const today = new Date().toISOString().split('T')[0]; const [formData, setFormData] = React.useState({ name: project.name || '', description: project.description || '', start_date: project.start_date || today, due_date: project.due_date || '', priority: project.priority || 'medium', notes: project.notes || '', }); // Initialize selected referenti based on those currently assigned to this project const [selectedReferenti, setSelectedReferenti] = React.useState(() => { if (!referenti) return []; return referenti .filter(r => r.project_ids && r.project_ids.includes(project.id)) .map(r => r.id); }); const [initialReferenti] = React.useState(() => { if (!referenti) return []; return referenti .filter(r => r.project_ids && r.project_ids.includes(project.id)) .map(r => r.id); }); // User assignments state const [assignments, setAssignments] = React.useState([]); const [initialAssignments, setInitialAssignments] = React.useState([]); const [loadingAssignments, setLoadingAssignments] = React.useState(true); const [loading, setLoading] = React.useState(false); const [error, setError] = React.useState(''); // Load current assignments on mount React.useEffect(() => { const loadAssignments = async () => { setLoadingAssignments(true); try { const data = await ApiUtils.getProjectAssignments(project.id); const assignedUserIds = data.map(a => a.user_id); setAssignments(assignedUserIds); setInitialAssignments(assignedUserIds); } catch (err) { console.error('Failed to load assignments:', err); } finally { setLoadingAssignments(false); } }; loadAssignments(); }, [project.id]); const handleReferenteToggle = (referenteId) => { setSelectedReferenti(prev => prev.includes(referenteId) ? prev.filter(id => id !== referenteId) : [...prev, referenteId] ); }; const handleUserToggle = (userId) => { setAssignments(prev => prev.includes(userId) ? prev.filter(id => id !== userId) : [...prev, userId] ); }; const handleSubmit = async (e) => { e.preventDefault(); setError(''); setLoading(true); try { // Convert empty strings to null for date fields const payload = { ...formData, start_date: formData.start_date || null, due_date: formData.due_date || null, }; await ApiUtils.updateProject(project.id, payload); // Update referenti assignments const addedReferenti = selectedReferenti.filter(id => !initialReferenti.includes(id)); const removedReferenti = initialReferenti.filter(id => !selectedReferenti.includes(id)); // Add new referenti to the project for (const referenteId of addedReferenti) { try { const referente = referenti.find(r => r.id === referenteId); if (referente) { const updatedProjectIds = [...(referente.project_ids || []), project.id]; await ApiUtils.updateReferente(referenteId, { project_ids: updatedProjectIds }); } } catch (assignErr) { console.error('Failed to add referente:', assignErr); } } // Remove referenti from the project for (const referenteId of removedReferenti) { try { const referente = referenti.find(r => r.id === referenteId); if (referente) { const updatedProjectIds = (referente.project_ids || []).filter(id => id !== project.id); await ApiUtils.updateReferente(referenteId, { project_ids: updatedProjectIds }); } } catch (assignErr) { console.error('Failed to remove referente:', assignErr); } } // Update user assignments const addedUsers = assignments.filter(id => !initialAssignments.includes(id)); const removedUsers = initialAssignments.filter(id => !assignments.includes(id)); // Add new users to the project for (const userId of addedUsers) { try { await ApiUtils.assignUserToProject(project.id, { user_id: userId }); } catch (assignErr) { console.error('Failed to assign user:', assignErr); } } // Remove users from the project for (const userId of removedUsers) { try { await ApiUtils.removeUserFromProject(project.id, userId); } catch (assignErr) { console.error('Failed to remove user:', assignErr); } } onSuccess(); } catch (err) { setError(err.message); } finally { setLoading(false); } }; return (