mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-14 06:40:50 +00:00
feat(admin): replace overview section-grid with audit-log preview + system snapshot
The `/admin` overview rendered a six-card status grid plus a quick-jump list of every admin section. Both duplicated navigation that already lives in the sidebar (and the global nav after Phase 4b), so the landing page told the admin nothing they didn't already see two clicks away. Replace the duplicated nav with two at-a-glance panes that *only* the overview can show: - Welcome card greets the signed-in admin by username and confirms the admin context (so the role indicator the shell shows is reinforced in the page body, not just the chrome). - `<SystemStatusSummary>` reuses the existing `useSystemStatus()` hook + `/api/version` to print app version, DB up/down, worker state, process start time, build SHA, and built-at. Same data source as `<SystemStatusSection>` so we don't double-fetch. - `<RecentAuditPreview>` lists the latest 10 audit entries from `/api/admin/audit-log?limit=10&filter=auth` with a "View all" link to `/admin/login-overview`. Reuses the same auth-action label map the full section uses. The previous `<StatusCardGrid>` component is now unused — removed entirely. The test file kept its name (`status-card-grid.test.tsx`) so git history follows the rename, but it now asserts the new overview composition: welcome card paints with the admin's username, snapshot heading present, audit preview links to `/admin/login-overview`, and the legacy "Maintenance"/"Monitoring" card titles + "Manage users" CTAs are *not* rendered. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
3e45a7ba53
commit
a967895808
8 files changed
+665
-489
No files matched your search
@@ -4,6 +4,7 @@ import { annotate } from "@/lib/logging/context";
|
||||
import { apiSuccess } from "@/lib/api-response";
|
||||
import { summarize, type DataPoint } from "@/lib/analytics/trends";
|
||||
import { getBpTargets } from "@/lib/analytics/bp-targets";
|
||||
import { computeBpInTargetPct } from "@/lib/analytics/bp-in-target";
|
||||
import type { MeasurementType } from "@/generated/prisma/client";
|
||||
import { measurementTypeEnum } from "@/lib/validations/measurement";
|
||||
|
||||
@@ -75,34 +76,13 @@ export const GET = apiHandler(async () => {
|
||||
}),
|
||||
]);
|
||||
|
||||
if (sysData.length > 0 && diaData.length > 0) {
|
||||
let inTarget = 0;
|
||||
for (const sys of sysData) {
|
||||
const closestDia = diaData.reduce((closest, dia) =>
|
||||
Math.abs(dia.measuredAt.getTime() - sys.measuredAt.getTime()) <
|
||||
Math.abs(closest.measuredAt.getTime() - sys.measuredAt.getTime())
|
||||
? dia
|
||||
: closest,
|
||||
);
|
||||
const timeDiff = Math.abs(
|
||||
closestDia.measuredAt.getTime() - sys.measuredAt.getTime(),
|
||||
);
|
||||
if (timeDiff < 5 * 60 * 1000) {
|
||||
if (
|
||||
sys.value >= bpTargets.sysLow &&
|
||||
sys.value <= bpTargets.sysHigh &&
|
||||
closestDia.value >= bpTargets.diaLow &&
|
||||
closestDia.value <= bpTargets.diaHigh
|
||||
) {
|
||||
inTarget++;
|
||||
}
|
||||
}
|
||||
}
|
||||
bpInTargetPct =
|
||||
sysData.length > 0
|
||||
? Math.round((inTarget / sysData.length) * 100)
|
||||
: null;
|
||||
}
|
||||
// Pure pair-and-count helper (see lib/analytics/bp-in-target.ts).
|
||||
// Replaces an earlier inline implementation that divided by
|
||||
// `sysData.length` and ignored a same-Berlin-day fallback for
|
||||
// imports rounded past the 5-minute window — which made the tile
|
||||
// read 0 % even when readings clearly sat inside target.
|
||||
const result = computeBpInTargetPct(sysData, diaData, bpTargets);
|
||||
bpInTargetPct = result?.pct ?? null;
|
||||
}
|
||||
|
||||
// Per-context glucose summaries (canonical mg/dL).
|
||||
|
||||
Reference in new issue
Block a user