mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-13 22:32:04 +00:00
The sleep, blood-glucose, workouts, and recovery insights pages fetched their series and half-rendered when the backing module was disabled — a disabled account that navigated straight to the URL saw the surface flash before any guard. They now resolve a shared useModulePageGuard hook (mirroring the cycle page): an unauthenticated visitor bounces to login, a disabled-module account bounces to /insights, and the page renders a calm loader until the gate clears. The backing /api routes enforce the gate server-side, so this is the UX layer, not the security boundary.
46 lines
1.6 KiB
TypeScript
46 lines
1.6 KiB
TypeScript
"use client";
|
|
|
|
import { useEffect } from "react";
|
|
import { useRouter } from "next/navigation";
|
|
|
|
import { useAuth } from "@/hooks/use-auth";
|
|
import type { ModuleKey } from "@/lib/modules/registry";
|
|
|
|
/**
|
|
* v1.18.0 B1 — client-side page guard for a toggleable module.
|
|
*
|
|
* Mirrors the cycle page (`src/app/cycle/page.tsx`): an unauthenticated
|
|
* visitor bounces to login; an authenticated account without the module
|
|
* enabled bounces to `/insights`. The nav entry is already hidden for a
|
|
* disabled account, so this only catches a direct URL hit. Every backing
|
|
* `/api/*` route enforces the gate server-side, so this is a UX redirect,
|
|
* not the security boundary.
|
|
*
|
|
* Returns `ready` — `true` only once auth has resolved, the visitor is
|
|
* authenticated, AND the module is enabled. While `false` the caller
|
|
* should render a calm loader / nothing rather than the (about-to-
|
|
* redirect) module surface, so a disabled-module page never half-renders.
|
|
*
|
|
* Default-on (disabled allowlist): an absent map, a missing key, or any
|
|
* non-`false` value reads as enabled — matching the server gate.
|
|
*/
|
|
export function useModulePageGuard(moduleKey: ModuleKey): {
|
|
ready: boolean;
|
|
} {
|
|
const { user, isLoading, isAuthenticated } = useAuth();
|
|
const router = useRouter();
|
|
|
|
const enabled = user?.modules?.[moduleKey] !== false;
|
|
|
|
useEffect(() => {
|
|
if (isLoading) return;
|
|
if (!isAuthenticated) {
|
|
router.push("/auth/login");
|
|
} else if (!enabled) {
|
|
router.push("/insights");
|
|
}
|
|
}, [isLoading, isAuthenticated, enabled, router]);
|
|
|
|
return { ready: !isLoading && isAuthenticated && enabled };
|
|
}
|