mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-12 14:16:12 +00:00
fix(settings): keep the Coach entry for a managed record
The Settings Coach entry now follows whether the Coach can answer, as the sidebar does, with Settings, AI keeping the stored memory in reach. A managed record has no Settings, AI, so while its Coach could not answer yet (no operator key, no consent) the guardian lost the only way to the record's Coach data scope and its switch. For a managed record the entry follows the module switch alone again.
This commit is contained in:
1 parent
8b6d9826ea
commit
5b8543f471
2 files changed
+40
-3
No files matched your search
@@ -15,7 +15,10 @@
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { renderToStaticMarkup } from "react-dom/server";
|
||||
|
||||
const h = vi.hoisted(() => ({ coachAvailable: true }));
|
||||
const h = vi.hoisted(() => ({
|
||||
coachAvailable: true,
|
||||
active: null as Record<string, unknown> | null,
|
||||
}));
|
||||
|
||||
vi.mock("next/navigation", () => ({
|
||||
usePathname: () => "/settings/ai",
|
||||
@@ -24,7 +27,12 @@ vi.mock("next/navigation", () => ({
|
||||
vi.mock("@/hooks/use-mounted", () => ({ useMounted: () => true }));
|
||||
vi.mock("@/hooks/use-auth", () => ({
|
||||
useAuth: () => ({
|
||||
user: { id: "u1", role: "USER", modules: { coach: true } },
|
||||
user: {
|
||||
id: "u1",
|
||||
role: "USER",
|
||||
modules: { coach: true },
|
||||
accountAccess: { active: h.active },
|
||||
},
|
||||
isAuthenticated: true,
|
||||
isLoading: false,
|
||||
refetch: vi.fn(),
|
||||
@@ -68,6 +76,7 @@ function render(node: React.ReactNode) {
|
||||
describe("the Coach entry in Settings", () => {
|
||||
beforeEach(() => {
|
||||
h.coachAvailable = true;
|
||||
h.active = null;
|
||||
});
|
||||
|
||||
it("is listed while the Coach can answer, and the memory lives there", () => {
|
||||
@@ -86,4 +95,18 @@ describe("the Coach entry in Settings", () => {
|
||||
).not.toContain('href="/settings/coach"');
|
||||
expect(render(<AiSection />)).toContain('data-slot="stored-coach-memory"');
|
||||
});
|
||||
|
||||
it("stays for a managed record whose Coach cannot answer yet", () => {
|
||||
// A record has no Settings, AI: the guardian reaches the record's Coach
|
||||
// data scope and switch through this entry only.
|
||||
h.coachAvailable = false;
|
||||
h.active = {
|
||||
recordKind: "managed",
|
||||
level: "manage",
|
||||
manageableDomains: [],
|
||||
};
|
||||
expect(
|
||||
render(<SettingsShell active="coach">body</SettingsShell>),
|
||||
).toContain('href="/settings/coach"');
|
||||
});
|
||||
});
|
||||
@@ -356,6 +356,20 @@ function deriveActiveSlug(
|
||||
return isSettingsSectionSlug(candidate) ? candidate : "account";
|
||||
}
|
||||
|
||||
/**
|
||||
* The module map the section list reads, the sidebar's. A managed record has
|
||||
* no Settings, AI to list its Coach settings (its data scope, its switch), so
|
||||
* there the Coach entry follows the module switch alone, not whether the
|
||||
* record's Coach can answer yet.
|
||||
*/
|
||||
function useSectionModules() {
|
||||
const { user } = useAuth();
|
||||
const navModules = useNavModules();
|
||||
return user?.accountAccess?.active?.recordKind === "managed"
|
||||
? user.modules
|
||||
: navModules;
|
||||
}
|
||||
|
||||
export function SettingsShell({
|
||||
active,
|
||||
heading,
|
||||
@@ -391,7 +405,7 @@ export function SettingsShell({
|
||||
// effect (which the lint rule flags as a cascading render), and no risk of
|
||||
// the two passes disagreeing.
|
||||
const hydrated = useMounted();
|
||||
const modules = useNavModules();
|
||||
const modules = useSectionModules();
|
||||
const activeRecord = user?.accountAccess?.active ?? null;
|
||||
const allVisibleSections = SETTINGS_SECTIONS.filter(
|
||||
(section) =>
|
||||
|
||||
Reference in new issue
Block a user