feat(reports): operational route — Area filter + areaOptions + hasData

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-02 10:11:26 +02:00
parent 10b3b68851
commit 68da165b37

View File

@@ -3,6 +3,7 @@ import { z } from 'zod';
import { withAuth, withPermission } from '@/lib/api/helpers'; import { withAuth, withPermission } from '@/lib/api/helpers';
import { errorResponse } from '@/lib/errors'; import { errorResponse } from '@/lib/errors';
import { parseOperationalFilters } from '@/lib/services/reports/operational-filters';
import { import {
getOperationalKpis, getOperationalKpis,
getUtilisationHeatmap, getUtilisationHeatmap,
@@ -16,6 +17,8 @@ import {
getVacantBerths, getVacantBerths,
getStuckSigning, getStuckSigning,
getHighestValueVacant, getHighestValueVacant,
getOperationalAreaOptions,
operationalHasData,
} from '@/lib/services/reports/operational.service'; } from '@/lib/services/reports/operational.service';
const querySchema = z.object({ const querySchema = z.object({
@@ -42,6 +45,7 @@ export const GET = withAuth(
to: params.get('to') ?? undefined, to: params.get('to') ?? undefined,
}); });
const range = resolveRange(from, to); const range = resolveRange(from, to);
const filters = parseOperationalFilters(params);
const [ const [
kpis, kpis,
@@ -56,19 +60,23 @@ export const GET = withAuth(
vacantBerths, vacantBerths,
stuckSigning, stuckSigning,
highestValueVacant, highestValueVacant,
areaOptions,
hasData,
] = await Promise.all([ ] = await Promise.all([
getOperationalKpis(ctx.portId, range), getOperationalKpis(ctx.portId, range, filters),
getUtilisationHeatmap(ctx.portId), getUtilisationHeatmap(ctx.portId, 24, filters),
getStatusMixOverTime(ctx.portId), getStatusMixOverTime(ctx.portId),
getTenancyChurn(ctx.portId), getTenancyChurn(ctx.portId),
getTenureDistribution(ctx.portId), getTenureDistribution(ctx.portId),
getSigningBoxPlot(ctx.portId), getSigningBoxPlot(ctx.portId),
getOccupancyByArea(ctx.portId), getOccupancyByArea(ctx.portId, filters),
getDocumentsInPipeline(ctx.portId), getDocumentsInPipeline(ctx.portId),
getTenanciesEndingSoon(ctx.portId), getTenanciesEndingSoon(ctx.portId),
getVacantBerths(ctx.portId), getVacantBerths(ctx.portId, 60, filters),
getStuckSigning(ctx.portId), getStuckSigning(ctx.portId),
getHighestValueVacant(ctx.portId), getHighestValueVacant(ctx.portId, 10, filters),
getOperationalAreaOptions(ctx.portId),
operationalHasData(ctx.portId),
]); ]);
return NextResponse.json({ return NextResponse.json({
@@ -85,6 +93,8 @@ export const GET = withAuth(
vacantBerths, vacantBerths,
stuckSigning, stuckSigning,
highestValueVacant, highestValueVacant,
areaOptions,
hasData,
range: { range: {
from: range.from.toISOString(), from: range.from.toISOString(),
to: range.to.toISOString(), to: range.to.toISOString(),