// src/components/MilestoneTimeline.js import React, { useEffect, useState, useCallback } from 'react'; const today = new Date(); const MilestoneTimeline = ({ careerPathId, authFetch, activeView, setActiveView }) => { const [milestones, setMilestones] = useState({ Career: [], Financial: [], Retirement: [] }); const [newMilestone, setNewMilestone] = useState({ title: '', date: '', description: '', progress: 0 }); const [showForm, setShowForm] = useState(false); const [editingMilestone, setEditingMilestone] = useState(null); const fetchMilestones = useCallback(async () => { if (!careerPathId) { console.warn('No careerPathId provided.'); return; } const res = await authFetch(`/api/premium/milestones?careerPathId=${careerPathId}`); if (!res) { console.error('Failed to fetch milestones.'); return; } const data = await res.json(); const raw = Array.isArray(data.milestones[0]) ? data.milestones.flat() : data.milestones.milestones || data.milestones; const flatMilestones = Array.isArray(data.milestones[0]) ? data.milestones.flat() : data.milestones; const filteredMilestones = raw.filter( (m) => m.career_path_id === careerPathId ); const categorized = { Career: [], Financial: [], Retirement: [] }; filteredMilestones.forEach((m) => { const type = m.milestone_type; if (categorized[type]) { categorized[type].push(m); } else { console.warn(`Unknown milestone type: ${type}`); } }); setMilestones(categorized); console.log('Milestones set for view:', categorized); }, [careerPathId, authFetch]); // ✅ useEffect simply calls the function useEffect(() => { fetchMilestones(); }, [fetchMilestones]); const saveMilestone = async () => { const url = editingMilestone ? `/api/premium/milestones/${editingMilestone.id}` : `/api/premium/milestone`; const method = editingMilestone ? 'PUT' : 'POST'; const payload = { milestone_type: activeView, title: newMilestone.title, description: newMilestone.description, date: newMilestone.date, career_path_id: careerPathId, progress: newMilestone.progress, status: newMilestone.progress === 100 ? 'completed' : 'planned', }; try { console.log('Sending request to:', url); console.log('HTTP Method:', method); console.log('Payload:', payload); const res = await authFetch(url, { method, headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload), }); if (!res.ok) { const errorData = await res.json(); console.error('Failed to save milestone:', errorData); let message = 'An error occurred while saving the milestone.'; if (errorData?.error === 'Missing required fields') { message = 'Please complete all required fields before saving.'; console.warn('Missing fields:', errorData.details); } alert(message); // Replace with your preferred UI messaging return; } const savedMilestone = await res.json(); // Update state locally instead of fetching all milestones setMilestones((prevMilestones) => { const updatedMilestones = { ...prevMilestones }; if (editingMilestone) { // Update the existing milestone updatedMilestones[activeView] = updatedMilestones[activeView].map((m) => m.id === editingMilestone.id ? savedMilestone : m ); } else { // Add the new milestone updatedMilestones[activeView].push(savedMilestone); } return updatedMilestones; }); setShowForm(false); setEditingMilestone(null); setNewMilestone({ title: '', description: '', date: '', progress: 0 }); } catch (error) { console.error('Error saving milestone:', error); } }; // Calculate last milestone date properly by combining all arrays const allMilestones = [...milestones.Career, ...milestones.Financial, ...milestones.Retirement]; const lastDate = allMilestones.reduce( (latest, m) => (new Date(m.date) > latest ? new Date(m.date) : latest), today ); const calcPosition = (date) => { const start = today.getTime(); const end = lastDate.getTime(); const position = ((new Date(date).getTime() - start) / (end - start)) * 100; return Math.min(Math.max(position, 0), 100); }; console.log('Rendering view:', activeView, milestones?.[activeView]); if (!activeView || !milestones?.[activeView]) { return (
Loading milestones...