From 98f68f7a1fd22682e7a48bc297f610cb82b06ce6 Mon Sep 17 00:00:00 2001 From: le king fu Date: Mon, 27 Apr 2026 08:11:23 -0400 Subject: [PATCH] feat(prices): useIsPremium hook from license.edition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Reads useLicense().state.edition === 'premium' - Ergonomic only — server enforces independently (ADR 0011) - 3 vitest tests (premium, base, free) - CLAUDE.md hook count 12 -> 13 Closes #157 --- CLAUDE.md | 2 +- src/hooks/useIsPremium.test.ts | 42 ++++++++++++++++++++++++++++++++++ src/hooks/useIsPremium.ts | 10 ++++++++ 3 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 src/hooks/useIsPremium.test.ts create mode 100644 src/hooks/useIsPremium.ts diff --git a/CLAUDE.md b/CLAUDE.md index 9ca1969..76c3aba 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -49,7 +49,7 @@ src/ │ ├── shared/ # Composants réutilisables │ └── transactions/ # Transactions ├── contexts/ # ProfileContext (état global profil) -├── hooks/ # 12 hooks custom (useReducer) +├── hooks/ # 13 hooks custom (useReducer) ├── pages/ # 11 pages ├── services/ # 14 services métier ├── shared/ # Types et constantes partagés diff --git a/src/hooks/useIsPremium.test.ts b/src/hooks/useIsPremium.test.ts new file mode 100644 index 0000000..4ca5c8a --- /dev/null +++ b/src/hooks/useIsPremium.test.ts @@ -0,0 +1,42 @@ +import { describe, it, expect, vi } from "vitest"; +import { useIsPremium } from "./useIsPremium"; + +vi.mock("./useLicense", () => ({ + useLicense: vi.fn(), +})); + +import { useLicense } from "./useLicense"; + +const mockUseLicense = vi.mocked(useLicense); + +describe("useIsPremium", () => { + it('returns true when edition is "premium"', () => { + mockUseLicense.mockReturnValue({ + state: { status: "ready", edition: "premium", info: null, error: null }, + refresh: vi.fn(), + submitKey: vi.fn(), + checkEntitlement: vi.fn(), + }); + expect(useIsPremium()).toBe(true); + }); + + it('returns false when edition is "base"', () => { + mockUseLicense.mockReturnValue({ + state: { status: "ready", edition: "base", info: null, error: null }, + refresh: vi.fn(), + submitKey: vi.fn(), + checkEntitlement: vi.fn(), + }); + expect(useIsPremium()).toBe(false); + }); + + it('returns false when edition is "free"', () => { + mockUseLicense.mockReturnValue({ + state: { status: "ready", edition: "free", info: null, error: null }, + refresh: vi.fn(), + submitKey: vi.fn(), + checkEntitlement: vi.fn(), + }); + expect(useIsPremium()).toBe(false); + }); +}); diff --git a/src/hooks/useIsPremium.ts b/src/hooks/useIsPremium.ts new file mode 100644 index 0000000..fdfbc7d --- /dev/null +++ b/src/hooks/useIsPremium.ts @@ -0,0 +1,10 @@ +import { useLicense } from "./useLicense"; + +/** + * Returns true if the active license edition is "premium". + * Ergonomic helper only — the server enforces entitlements independently (cf. ADR 0011 §UX). + */ +export function useIsPremium(): boolean { + const { state } = useLicense(); + return state.edition === "premium"; +}