28 lines
1.2 KiB
TypeScript
28 lines
1.2 KiB
TypeScript
import { NextRequest, NextResponse } from 'next/server';
|
|
|
|
import { withAuth, withPermission } from '@/lib/api/helpers';
|
|
import { getRevenueForecast } from '@/lib/services/dashboard.service';
|
|
import { parseRangeSlug, rangeToBounds } from '@/lib/analytics/range';
|
|
|
|
/**
|
|
* GET /api/v1/dashboard/forecast
|
|
* GET /api/v1/dashboard/forecast?range=7d|30d|90d|today|custom-<from>-<to>
|
|
*
|
|
* Same range semantics as /kpis - the weighted forecast scopes to
|
|
* interests whose createdAt falls inside the window when range is set,
|
|
* or all-time when not.
|
|
*/
|
|
export const GET = withAuth(
|
|
withPermission('reports', 'view_dashboard', async (req: NextRequest, ctx) => {
|
|
const url = new URL(req.url);
|
|
const rangeSlug = url.searchParams.get('range');
|
|
const range = rangeSlug ? parseRangeSlug(rangeSlug) : null;
|
|
const bounds = range ? rangeToBounds(range) : null;
|
|
const result = await getRevenueForecast(ctx.portId, bounds);
|
|
// L34 carve-out: deliberate bare-shape response (NOT the `{ data }`
|
|
// envelope). The dashboard widgets read these fields off the root of
|
|
// the JSON; wrapping them would break the consumers. Left as-is.
|
|
return NextResponse.json(result);
|
|
}),
|
|
);
|