From f6852be760be8ec856725ed7486c1f407765a0bf Mon Sep 17 00:00:00 2001 From: chahinebrini Date: Mon, 11 May 2026 15:18:59 +0200 Subject: [PATCH] fix(native): useUserPlan derive from useMe (was a stale module cache) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit useUserPlan had its own module-level cache + fetch-once-on-mount, separate from useMe's invalidateMe(). So the __DEV__ tier-override toggle (which calls invalidateMe()) never reached useUserPlan consumers → the app didn't react to a plan switch. Now useUserPlan just reads me.plan from useMe → inherits its live-invalidation, the toggle propagates everywhere. Co-Authored-By: Claude Opus 4.7 (1M context) --- apps/rebreak-native/hooks/useUserPlan.ts | 49 ++++++------------------ 1 file changed, 12 insertions(+), 37 deletions(-) diff --git a/apps/rebreak-native/hooks/useUserPlan.ts b/apps/rebreak-native/hooks/useUserPlan.ts index 3fd1275..31d18a6 100644 --- a/apps/rebreak-native/hooks/useUserPlan.ts +++ b/apps/rebreak-native/hooks/useUserPlan.ts @@ -1,43 +1,18 @@ -import { useEffect, useState } from "react"; -import { apiFetch } from "../lib/api"; +import { useMe } from "./useMe"; +import type { Plan } from "./useMe"; -export type Plan = "free" | "pro" | "legend"; - -type MeResponse = { - id: string; - email: string; - username: string; - plan: Plan; -}; - -let cachedPlan: Plan | null = null; +export type { Plan }; /** - * Holt den User-Plan vom Backend (/api/auth/me). - * Plan wird in DB gespeichert (nicht in user_metadata) — daher BFF-Call nötig. + * Plan des eingeloggten Users — abgeleitet aus useMe() (single source of truth, + * inkl. Live-Invalidierung via invalidateMe()). + * + * Vorher hatte useUserPlan einen eigenen Modul-Cache + fetch-once-on-mount — + * das war ein Bug: der __DEV__-Tier-Toggle (ruft invalidateMe() auf) erreichte + * die useUserPlan-Consumer NICHT, also reagierte die App nicht auf den Plan-Wechsel. + * Jetzt erbt useUserPlan die Invalidierung von useMe → Toggle propagiert überall. */ export function useUserPlan(): { plan: Plan; loading: boolean } { - const [plan, setPlan] = useState(cachedPlan ?? "free"); - const [loading, setLoading] = useState(cachedPlan === null); - - useEffect(() => { - let cancelled = false; - (async () => { - try { - const res = await apiFetch("/api/auth/me"); - if (cancelled) return; - cachedPlan = res.plan ?? "free"; - setPlan(cachedPlan); - } catch (e) { - console.warn("[useUserPlan] failed:", e); - } finally { - if (!cancelled) setLoading(false); - } - })(); - return () => { - cancelled = true; - }; - }, []); - - return { plan, loading }; + const { me, loading } = useMe(); + return { plan: me?.plan ?? "free", loading }; }