// src/components/MilestoneAddModal.js import React, { useState, useEffect } from 'react'; import authFetch from '../utils/authFetch.js'; const MilestoneAddModal = ({ show, onClose, defaultScenarioId, scenarioId, // which scenario this milestone applies to editMilestone, // if editing an existing milestone, pass its data apiURL }) => { // Basic milestone fields const [title, setTitle] = useState(''); const [description, setDescription] = useState(''); // We'll store an array of impacts. Each impact is { impact_type, direction, amount, start_month, end_month } const [impacts, setImpacts] = useState([]); // On open, if editing, fill in existing fields useEffect(() => { if (!show) return; // if modal is hidden, do nothing if (editMilestone) { setTitle(editMilestone.title || ''); setDescription(editMilestone.description || ''); // If editing, you might fetch existing impacts from the server or they could be passed in if (editMilestone.impacts) { setImpacts(editMilestone.impacts); } else { // fetch from backend if needed // e.g. GET /api/premium/milestones/:id/impacts } } else { // Creating a new milestone setTitle(''); setDescription(''); setImpacts([]); } }, [show, editMilestone]); // Handler: add a new blank impact const handleAddImpact = () => { setImpacts((prev) => [ ...prev, { impact_type: 'ONE_TIME', direction: 'subtract', amount: 0, start_month: 0, end_month: null } ]); }; // Handler: update a single impact in the array const handleImpactChange = (index, field, value) => { setImpacts((prev) => { const updated = [...prev]; updated[index] = { ...updated[index], [field]: value }; return updated; }); }; // Handler: remove an impact row const handleRemoveImpact = (index) => { setImpacts((prev) => prev.filter((_, i) => i !== index)); }; // Handler: Save everything to the server const handleSave = async () => { try { let milestoneId; if (editMilestone) { // 1) Update existing milestone milestoneId = editMilestone.id; await authFetch(`${apiURL}/premium/milestones/${milestoneId}`, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ title, description, scenario_id: scenarioId, // Possibly other fields }) }); // Then handle impacts below... } else { // 1) Create new milestone const res = await authFetch(`${apiURL}/premium/milestones`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ title, description, scenario_id: scenarioId }) }); if (!res.ok) throw new Error('Failed to create milestone'); const created = await res.json(); milestoneId = created.id; // assuming the response returns { id: newMilestoneId } } // 2) For the impacts, we can do a batch approach or individual calls // For simplicity, let's do multiple POST calls for (const impact of impacts) { // If editing, you might do a PUT if the impact already has an id await authFetch(`${apiURL}/premium/milestone-impacts`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ milestone_id: milestoneId, impact_type: impact.impact_type, direction: impact.direction, amount: parseFloat(impact.amount) || 0, start_month: parseInt(impact.start_month, 10) || 0, end_month: impact.end_month !== null ? parseInt(impact.end_month, 10) : null, created_at: new Date().toISOString(), updated_at: new Date().toISOString() }) }); } // Done, close modal onClose(); } catch (err) { console.error('Failed to save milestone + impacts:', err); // Show some UI error if needed } }; if (!show) return null; return (
Impact #{i + 1}