import { useState, useEffect } from 'react'; import { useParams, useNavigate } from 'react-router-dom'; import { useAuthStore } from '../stores/authStore.ts'; import api from '../services/api.ts'; import { Pencil, Trash2, ArrowLeft, Calendar, Euro, FileText, Layers, FolderOpen, ListChecks, Plus } from 'lucide-react'; import FunctionGroupEditor from '../components/FunctionGroupEditor.tsx'; interface ProjectDetailData { id: string; account_id: string; name: string; description: string | null; status: string; start_date: string | null; end_date: string | null; budget: number | null; total_costs: number; notes: string | null; created_at: string; updated_at: string; } interface SubProjectItem { id: string; name: string; project_id: string; parent_id: string | null; sort_order: number; } interface FunctionGroupItem { id: string; name: string; project_id: string; sort_order: number; } interface FunctionItem { id: string; name: string; function_group_id: string; quantity: number; daily_costs: number; total_costs: number; sort_order: number; } export default function ProjectDetail() { const { projectId } = useParams<{ projectId: string }>(); const { user } = useAuthStore(); const navigate = useNavigate(); const [project, setProject] = useState(null); const [subProjects, setSubProjects] = useState([]); const [functionGroups, setFunctionGroups] = useState([]); const [functionsMap, setFunctionsMap] = useState>({}); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const canWrite = user?.permissions?.includes('projects:write'); const canDelete = user?.permissions?.includes('projects:delete'); useEffect(() => { loadAll(); }, [projectId]); const loadAll = async () => { try { setLoading(true); // Load project details const projectRes = await api.get(`/projects/${projectId}`); setProject(projectRes.data); // Load subprojects const subRes = await api.get(`/projects/${projectId}/subprojects?size=100`); setSubProjects(subRes.data.items || []); // Load function groups const fgRes = await api.get(`/projects/${projectId}/function-groups?size=100`); const fgs: FunctionGroupItem[] = fgRes.data.items || []; setFunctionGroups(fgs); // Load functions for each function group const funcMap: Record = {}; await Promise.all( fgs.map(async (fg) => { try { const funcRes = await api.get(`/projects/${projectId}/function-groups/${fg.id}/functions?size=100`); funcMap[fg.id] = funcRes.data.items || []; } catch { funcMap[fg.id] = []; } }) ); setFunctionsMap(funcMap); } catch (err: any) { setError(err.response?.data?.detail || 'Failed to load project'); } finally { setLoading(false); } }; const handleDelete = async () => { if (!confirm(`Delete project "${project?.name}"?`)) return; try { await api.delete(`/projects/${projectId}`); navigate('/projects'); } catch (err: any) { alert(err.response?.data?.detail || 'Failed to delete project'); } }; const getStatusBadge = (status: string) => { const styles: Record = { draft: 'bg-gray-100 text-gray-800', confirmed: 'bg-blue-100 text-blue-800', in_progress: 'bg-yellow-100 text-yellow-800', completed: 'bg-green-100 text-green-800', cancelled: 'bg-red-100 text-red-800', }; return styles[status] || 'bg-gray-100 text-gray-800'; }; const formatDate = (dateStr: string | null) => { if (!dateStr) return '-'; const d = new Date(dateStr); return d.toLocaleDateString('de-DE', { day: '2-digit', month: '2-digit', year: 'numeric' }); }; const iconClass = "w-5 h-5 text-text-secondary mt-0.5 flex-shrink-0"; const labelClass = "text-sm text-text-secondary min-w-[120px]"; const valueClass = "text-sm text-text-primary"; const fieldRowClass = "flex items-start gap-3 py-2"; const sectionClass = "mb-8"; const headingClass = "text-lg font-semibold text-text-primary mb-3"; if (loading) return

Loading project...

; if (error) return

{error}

; if (!project) return

Project not found.

; return (
{/* Header */}
{canWrite && ( )} {canDelete && ( )}
{/* Title */}

{project.name}

{project.status.replace(/_/g, ' ').replace(/\b\w/g, c => c.toUpperCase())}
{/* Project Details */}

Project Details

{project.description && (
Description {project.description}
)}
Start Date {formatDate(project.start_date)}
End Date {formatDate(project.end_date)}
Budget {project.budget != null ? `€${project.budget.toFixed(2)}` : '-'}
Total Costs {project.total_costs != null ? `€${project.total_costs.toFixed(2)}` : '-'}
{project.notes && (
Notes {project.notes}
)}
{/* SubProjects Section */}

Sub-Projects ({subProjects.length})

{subProjects.length === 0 ? (

No sub-projects defined yet.

) : (
{subProjects.map(sp => (

{sp.name}

Sort order: {sp.sort_order}

{sp.parent_id && ( Child )}
))}
)}
{/* Function Groups Section - Inline Editor */}

Function Groups ({functionGroups.length})

); }