// MyProjectsView - Vista progetti assegnati per utenti function MyProjectsView({ pendingProjectId, onPendingHandled, onViewProject }) { const { user: currentUser, isAdmin } = useAuth(); const toast = useToast(); const [projects, setProjects] = React.useState([]); const [timelines, setTimelines] = React.useState({}); const [loading, setLoading] = React.useState(true); const [editingProject, setEditingProject] = React.useState(null); const [timelineProject, setTimelineProject] = React.useState(null); const [confirmModal, setConfirmModal] = React.useState(null); const loadData = async () => { setLoading(true); try { const projectsData = await ApiUtils.fetchProjects(); // Sort by creation time (newest first) and force new array reference for React to detect changes const sortedProjects = [...projectsData].sort((a, b) => new Date(b.created_at) - new Date(a.created_at)); setProjects(sortedProjects); // Fetch timeline data for each project to get step progress const timelinePromises = projectsData.map(async (project) => { try { const timeline = await ApiUtils.getProjectTimeline(project.id, false); return { projectId: project.id, timeline }; } catch (err) { console.error(`Failed to load timeline for project ${project.id}:`, err); return { projectId: project.id, timeline: null }; } }); const timelineResults = await Promise.all(timelinePromises); const timelinesMap = {}; timelineResults.forEach(({ projectId, timeline }) => { timelinesMap[projectId] = timeline; }); setTimelines(timelinesMap); } catch (err) { toast('Errore nel caricamento progetti: ' + err.message, 'error'); } finally { setLoading(false); } }; React.useEffect(() => { loadData(); }, []); // Handle pending project from notification click React.useEffect(() => { if (pendingProjectId && projects.length > 0 && !loading) { const project = projects.find(p => p.id === pendingProjectId); if (project) { setTimelineProject(project); } // Clear the pending project if (onPendingHandled) { onPendingHandled(); } } }, [pendingProjectId, projects, loading, onPendingHandled]); const getProgressInfo = (projectId) => { const timeline = timelines[projectId]; if (!timeline || !timeline.steps || timeline.steps.length === 0) { return { completed: 0, total: 0, percent: 0, lastUpdated: null }; } const completed = timeline.steps.filter(s => s.status === 'completato').length; const total = timeline.steps.length; const percent = Math.round((completed / total) * 100); // Find the most recent update across all steps let lastUpdated = null; timeline.steps.forEach(step => { const stepDate = step.updated_at ? new Date(step.updated_at) : null; if (stepDate && (!lastUpdated || stepDate > lastUpdated)) { lastUpdated = stepDate; } }); return { completed, total, percent, lastUpdated }; }; // Use shared utilities const formatRelativeTime = Formatters.formatRelativeTime; // Refresh timeline data for a specific project after step changes const refreshProjectTimeline = async (projectId) => { try { const timeline = await ApiUtils.getProjectTimeline(projectId, false); setTimelines(prev => ({ ...prev, [projectId]: timeline })); } catch (err) { console.error(`Failed to refresh timeline for project ${projectId}:`, err); } }; const handleCancel = (project) => { setConfirmModal({ type: 'cancel', project, title: 'Annulla Pratica', message: `Sei sicuro di voler annullare la pratica "${project.name}"?\n\nIl workflow sara bloccato e non sara possibile modificare gli stati degli step.`, confirmText: 'Annulla Pratica', variant: 'danger', }); }; const handleUncancel = (project) => { setConfirmModal({ type: 'uncancel', project, title: 'Ripristina Pratica', message: `Sei sicuro di voler ripristinare la pratica "${project.name}"?\n\nIl workflow sara sbloccato.`, confirmText: 'Ripristina', variant: 'info', }); }; const executeConfirmedAction = async () => { if (!confirmModal) return; const { type, project } = confirmModal; setConfirmModal({ ...confirmModal, loading: true }); try { if (type === 'cancel') { await ApiUtils.cancelProject(project.id); toast('Pratica annullata', 'success'); } else if (type === 'uncancel') { await ApiUtils.uncancelProject(project.id); toast('Pratica ripristinata', 'success'); } setConfirmModal(null); loadData(); } catch (err) { toast('Errore: ' + err.message, 'error'); setConfirmModal(null); } }; // If admin, redirect to full projects view if (isAdmin) { return (
Pratiche a cui sei assegnato
Caricamento progetti...
Non sei ancora assegnato a nessuna pratica
Contatta un amministratore per essere assegnato a una pratica
{project.description}
)} {project.notes && (Note:
{project.notes}