diff options
| author | Fuwn <[email protected]> | 2026-02-10 01:32:16 -0800 |
|---|---|---|
| committer | Fuwn <[email protected]> | 2026-02-10 01:32:16 -0800 |
| commit | 293f9ccc308b69f507e752af01a49652faee330f (patch) | |
| tree | b699e52309cfab03d539a048de34a98158d6168b /apps/web/app/reader/_components | |
| parent | feat: add automatic timeline refresh with scroll position preservation (diff) | |
| download | asa.news-293f9ccc308b69f507e752af01a49652faee330f.tar.xz asa.news-293f9ccc308b69f507e752af01a49652faee330f.zip | |
feat: gate offline reading to pro and developer plans
Service worker now only caches Supabase REST responses when the user's
tier allows offline reading. Client syncs tier status to SW via
postMessage after profile loads. Free users see a descriptive offline
banner instead of stale cached data.
Diffstat (limited to 'apps/web/app/reader/_components')
| -rw-r--r-- | apps/web/app/reader/_components/offline-banner.tsx | 10 | ||||
| -rw-r--r-- | apps/web/app/reader/_components/reader-layout-shell.tsx | 2 |
2 files changed, 11 insertions, 1 deletions
diff --git a/apps/web/app/reader/_components/offline-banner.tsx b/apps/web/app/reader/_components/offline-banner.tsx index 81ebf8f..b6089de 100644 --- a/apps/web/app/reader/_components/offline-banner.tsx +++ b/apps/web/app/reader/_components/offline-banner.tsx @@ -1,6 +1,8 @@ "use client" import { useSyncExternalStore } from "react" +import { TIER_LIMITS, type SubscriptionTier } from "@asa-news/shared" +import { useUserProfile } from "@/lib/queries/use-user-profile" function subscribe(callback: () => void) { window.addEventListener("online", callback) @@ -21,12 +23,18 @@ function getServerSnapshot() { export function OfflineBanner() { const isOnline = useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot) + const { data: userProfile } = useUserProfile() if (isOnline) return null + const tier = (userProfile?.tier ?? "free") as SubscriptionTier + const allowsOffline = TIER_LIMITS[tier]?.allowsOfflineReading ?? false + return ( <div className="border-b border-border bg-background-tertiary px-3 py-1.5 text-center text-text-dim"> - you are offline — showing cached content + {allowsOffline + ? "you are offline \u2014 showing cached content" + : "you are offline \u2014 offline reading is available on pro and developer plans"} </div> ) } diff --git a/apps/web/app/reader/_components/reader-layout-shell.tsx b/apps/web/app/reader/_components/reader-layout-shell.tsx index 7ec1002..17ae0b5 100644 --- a/apps/web/app/reader/_components/reader-layout-shell.tsx +++ b/apps/web/app/reader/_components/reader-layout-shell.tsx @@ -14,6 +14,7 @@ import { KeyboardShortcutsDialog } from "./keyboard-shortcuts-dialog" import { MfaChallenge } from "./mfa-challenge" import { OfflineBanner } from "./offline-banner" import { useKeyboardNavigation } from "@/lib/hooks/use-keyboard-navigation" +import { useOfflineAccessSync } from "@/lib/hooks/use-offline-access-sync" import { createSupabaseBrowserClient } from "@/lib/supabase/client" import { useSubscriptions } from "@/lib/queries/use-subscriptions" import { useCustomFeeds } from "@/lib/queries/use-custom-feeds" @@ -58,6 +59,7 @@ export function ReaderLayoutShell({ const { data: subscriptionsData } = useSubscriptions() const { data: customFeedsData } = useCustomFeeds() const { data: userProfile } = useUserProfile() + useOfflineAccessSync(userProfile?.tier as "free" | "pro" | "developer" | undefined) const sidebarMaxWidth = useMemo(() => { if (typeof window === "undefined") return "35%" |