Files
panel/src/app/api/dashboard/route.js

262 lines
8.3 KiB
JavaScript

// 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 });
}
}