// Force this API route to use Node.js runtime export const runtime = "nodejs"; import { NextResponse } from "next/server"; import { auth } from "@/lib/auth"; import { getAllProjects } from "@/lib/queries/projects"; export async function GET(request) { try { const session = await auth(); if (!session?.user) { return NextResponse.json({ error: "Unauthorized" }, { status: 401 }); } // Only team leads can access dashboard data if (session.user.role !== 'team_lead') { return NextResponse.json({ error: "Forbidden" }, { status: 403 }); } const { searchParams } = new URL(request.url); const selectedYear = searchParams.get('year') ? parseInt(searchParams.get('year')) : null; // Get all projects const projects = getAllProjects(); // Calculate realised and unrealised values by project type const projectTypes = ['design', 'design+construction', 'construction']; const typeSummary = {}; projectTypes.forEach(type => { typeSummary[type] = { realisedValue: 0, unrealisedValue: 0 }; }); projects.forEach(project => { const value = parseFloat(project.wartosc_zlecenia) || 0; const type = project.project_type; if (!type || !projectTypes.includes(type)) return; if (project.project_status === 'fulfilled' && project.completion_date && project.wartosc_zlecenia) { typeSummary[type].realisedValue += value; } else if (project.wartosc_zlecenia && project.project_status !== 'cancelled') { typeSummary[type].unrealisedValue += value; } }); // Calculate overall totals let realisedValue = 0; let unrealisedValue = 0; Object.values(typeSummary).forEach(summary => { realisedValue += summary.realisedValue; unrealisedValue += summary.unrealisedValue; }); // Filter completed projects (those with completion_date and fulfilled status) const completedProjects = projects.filter(project => project.completion_date && project.wartosc_zlecenia && project.project_status === 'fulfilled' ); // If no data, return sample data for demonstration let chartData; let summary; if (completedProjects.length === 0) { // Generate continuous sample data based on selected year or default range const currentDate = new Date(); let startDate, endDate; if (selectedYear) { startDate = new Date(selectedYear, 0, 1); // Jan 1st of selected year endDate = new Date(selectedYear, 11, 31); // Dec 31st of selected year if (endDate > currentDate) endDate = currentDate; } else { startDate = new Date(2024, 0, 1); // Jan 2024 endDate = currentDate; } chartData = []; let cumulative = 0; let tempDate = new Date(startDate); while (tempDate <= endDate) { const monthName = tempDate.toLocaleDateString('en-US', { year: 'numeric', month: 'short' }); let monthlyValue = 0; // Add some sample values for certain months (only if they match the selected year or no year selected) const shouldAddData = !selectedYear || tempDate.getFullYear() === selectedYear; if (shouldAddData) { if (tempDate.getMonth() === 0 && tempDate.getFullYear() === 2024) monthlyValue = 50000; // Jan 2024 else if (tempDate.getMonth() === 1 && tempDate.getFullYear() === 2024) monthlyValue = 75000; // Feb 2024 else if (tempDate.getMonth() === 2 && tempDate.getFullYear() === 2024) monthlyValue = 60000; // Mar 2024 else if (tempDate.getMonth() === 7 && tempDate.getFullYear() === 2024) monthlyValue = 10841; // Aug 2024 (real data) else if (tempDate.getMonth() === 8 && tempDate.getFullYear() === 2024) monthlyValue = 18942; // Sep 2024 else if (tempDate.getMonth() === 9 && tempDate.getFullYear() === 2024) monthlyValue = 13945; // Oct 2024 else if (tempDate.getMonth() === 10 && tempDate.getFullYear() === 2024) monthlyValue = 12542; // Nov 2024 else if (tempDate.getMonth() === 0 && tempDate.getFullYear() === 2025) monthlyValue = 25000; // Jan 2025 else if (tempDate.getMonth() === 1 && tempDate.getFullYear() === 2025) monthlyValue = 35000; // Feb 2025 } cumulative += monthlyValue; chartData.push({ month: monthName, value: monthlyValue, cumulative: cumulative }); tempDate.setMonth(tempDate.getMonth() + 1); } summary = { total: { realisedValue: 958000, unrealisedValue: 1242000 }, byType: { design: { realisedValue: 320000, unrealisedValue: 480000 }, 'design+construction': { realisedValue: 480000, unrealisedValue: 520000 }, construction: { realisedValue: 158000, unrealisedValue: 242000 } } }; } else { // Group by month and calculate monthly totals first const monthlyData = {}; // Sort projects by completion date completedProjects.sort((a, b) => new Date(a.completion_date) - new Date(b.completion_date)); // First pass: calculate monthly totals completedProjects.forEach(project => { const date = new Date(project.completion_date); const monthKey = `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}`; const monthName = date.toLocaleDateString('en-US', { year: 'numeric', month: 'short' }); if (!monthlyData[monthKey]) { monthlyData[monthKey] = { month: monthName, value: 0 }; } const projectValue = parseFloat(project.wartosc_zlecenia) || 0; monthlyData[monthKey].value += projectValue; }); // Generate continuous timeline from earliest completion to current date let startDate = new Date(); let endDate = new Date(); if (completedProjects.length > 0) { // Find earliest completion date const earliestCompletion = completedProjects.reduce((earliest, project) => { const projectDate = new Date(project.completion_date); return projectDate < earliest ? projectDate : earliest; }, new Date()); startDate = new Date(earliestCompletion.getFullYear(), earliestCompletion.getMonth(), 1); } else { // If no completed projects, start from 6 months ago startDate = new Date(); startDate.setMonth(startDate.getMonth() - 6); startDate = new Date(startDate.getFullYear(), startDate.getMonth(), 1); } // If a specific year is selected, adjust the date range if (selectedYear) { startDate = new Date(selectedYear, 0, 1); // January 1st of selected year endDate = new Date(selectedYear, 11, 31); // December 31st of selected year // Don't go beyond current date if (endDate > new Date()) { endDate = new Date(); } } // Generate all months from start to current const allMonths = {}; let currentDate = new Date(startDate); while (currentDate <= endDate) { const monthKey = `${currentDate.getFullYear()}-${String(currentDate.getMonth() + 1).padStart(2, '0')}`; const monthName = currentDate.toLocaleDateString('en-US', { year: 'numeric', month: 'short' }); allMonths[monthKey] = { month: monthName, value: monthlyData[monthKey]?.value || 0 }; currentDate.setMonth(currentDate.getMonth() + 1); } // Calculate cumulative values let cumulativeValue = 0; const sortedMonths = Object.keys(allMonths).sort((a, b) => a.localeCompare(b)); sortedMonths.forEach(monthKey => { cumulativeValue += allMonths[monthKey].value; allMonths[monthKey].cumulative = cumulativeValue; }); // Convert to array chartData = sortedMonths.map(monthKey => ({ month: allMonths[monthKey].month, value: Math.round(allMonths[monthKey].value), cumulative: Math.round(allMonths[monthKey].cumulative) })); summary = { total: { realisedValue: Math.round(realisedValue), unrealisedValue: Math.round(unrealisedValue) }, byType: Object.fromEntries( Object.entries(typeSummary).map(([type, data]) => [ type, { realisedValue: Math.round(data.realisedValue), unrealisedValue: Math.round(data.unrealisedValue) } ]) ) }; } return NextResponse.json({ chartData, summary: { total: { realisedValue: Math.round(realisedValue), unrealisedValue: Math.round(unrealisedValue) }, byType: Object.fromEntries( Object.entries(typeSummary).map(([type, data]) => [ type, { realisedValue: Math.round(data.realisedValue), unrealisedValue: Math.round(data.unrealisedValue) } ]) ) } }); } catch (error) { console.error('Dashboard API error:', error); return NextResponse.json({ error: "Internal server error" }, { status: 500 }); } }