updating the playtime frontend with claude only code to replace the one graph with a dumb-bell graph, having each individual map show its players at beginning versus end and also the overall impact of maps + their popularity

This commit is contained in:
jenz
2026-10-02 14:43:45 +02:00
parent 6019e6854d
commit 8a76454784
14 changed files with 3300 additions and 159 deletions
@@ -0,0 +1,48 @@
import { NextRequest, NextResponse } from 'next/server';
import { getMapPeriod } from '@/lib/queries';
import { parseDbDate } from '@/lib/dates';
import { computePopulationSeries } from '@/lib/populationSeries';
export async function GET(req: NextRequest) {
const mapIdParam = req.nextUrl.searchParams.get('mapId');
const mapId = Number(mapIdParam);
if (!Number.isInteger(mapId)) {
return NextResponse.json({ error: 'mapId query param is required' }, { status: 400 });
}
const period = await getMapPeriod(mapId);
if (!period) {
return NextResponse.json({ error: 'map session not found' }, { status: 404 });
}
const mapStart = parseDbDate(period.map_start_dt);
const mapEnd = period.map_end_dt ? parseDbDate(period.map_end_dt) : new Date();
// Pad a bit on either side of the session's own window so the chart
// shows the transition into and out of the map, not just a flat line
// bounded exactly at its edges. Capped relative to the session's own
// duration so a 10-minute map doesn't get a 10-minute pad that's as long
// as the map itself.
const durationMs = Math.max(1, mapEnd.getTime() - mapStart.getTime());
const padMs = Math.min(10 * 60_000, Math.max(1 * 60_000, durationMs * 0.25));
const rangeStart = new Date(mapStart.getTime() - padMs);
const now = new Date();
const rangeEnd = period.map_end_dt ? new Date(Math.min(mapEnd.getTime() + padMs, now.getTime())) : now;
// Smaller target than the general population chart (150) — map sessions
// are usually tens of minutes to a couple hours, and a coarser bucket
// would flatten exactly the kind of mid-session swing this view exists
// to surface.
const { bucketMinutes, points, mapBoundaries } = await computePopulationSeries(rangeStart, rangeEnd, {
targetPoints: 90,
});
return NextResponse.json({
bucketMinutes,
points,
mapBoundaries,
mapStart: mapStart.toISOString(),
mapEnd: period.map_end_dt ? mapEnd.toISOString() : null,
});
}