From 7b81bbc791baab2db0be14e406d1cf9752334bc1 Mon Sep 17 00:00:00 2001 From: gosangam Date: Tue, 23 Jun 2026 14:21:59 +0530 Subject: [PATCH] feat: enhance user limits --- app/(app)/u/me/bookmarks/page.tsx | 7 +++---- app/(app)/u/me/collections/page.tsx | 16 +++++++++++----- components/text-selection-toolbar.tsx | 7 +++++-- lib/auth.ts | 8 ++++++++ 4 files changed, 27 insertions(+), 11 deletions(-) diff --git a/app/(app)/u/me/bookmarks/page.tsx b/app/(app)/u/me/bookmarks/page.tsx index 0dec095b..8d2657eb 100644 --- a/app/(app)/u/me/bookmarks/page.tsx +++ b/app/(app)/u/me/bookmarks/page.tsx @@ -8,9 +8,6 @@ import { useAuth } from "@/components/auth/auth-provider"; import { appendHighlight, hasHighlight } from "@/lib/text-highlight"; import { displaySourceLabel } from "@/lib/source-reference"; -const FREE_LIMIT = 1; -const PREMIUM_LIMIT = 5; - export default function MyBookmarksPage() { const { user } = useAuth(); const [list, setList] = useState([]); @@ -40,7 +37,9 @@ export default function MyBookmarksPage() { } } - const limit = user?.role === "admin" || user?.plan === "premium" ? PREMIUM_LIMIT : FREE_LIMIT; + // Effective cap from the server (plan default merged with any admin + // override). -1 would mean unlimited (bookmarks aren't, today). + const limit = user?.limits?.bookmarks ?? 1; if (loading) return

Loading…

; diff --git a/app/(app)/u/me/collections/page.tsx b/app/(app)/u/me/collections/page.tsx index 066b4643..e1476bcc 100644 --- a/app/(app)/u/me/collections/page.tsx +++ b/app/(app)/u/me/collections/page.tsx @@ -54,7 +54,11 @@ export default function MyCollectionsPage() { } } - const isPremium = user?.plan === "premium"; + // Effective per-visibility caps from the server (plan default merged with any + // admin override). -1 means unlimited (premium default). + const pubLimit = user?.limits?.public_collections ?? 5; + const privLimit = user?.limits?.private_collections ?? 5; + const unlimited = pubLimit < 0 && privLimit < 0; const publicCount = list.filter((c) => c.is_public).length; const privateCount = list.filter((c) => !c.is_public).length; @@ -62,12 +66,14 @@ export default function MyCollectionsPage() {

- {isPremium ? ( - <>Premium — unlimited collections. + {unlimited ? ( + <>Unlimited collections. ) : ( <> - {publicCount} / 5 public ·{" "} - {privateCount} / 5 private + {publicCount} / {pubLimit}{" "} + public ·{" "} + {privateCount} / {privLimit}{" "} + private )}

diff --git a/components/text-selection-toolbar.tsx b/components/text-selection-toolbar.tsx index 043f8e33..96cee0c2 100644 --- a/components/text-selection-toolbar.tsx +++ b/components/text-selection-toolbar.tsx @@ -73,8 +73,11 @@ export function TextSelectionToolbar() { }; }, [user]); - const bookmarkLimit = user?.plan === "premium" ? 5 : 1; - const limitReached = !!user && bookmarkCount >= bookmarkLimit; + // Effective bookmark cap from the server (plan default merged with any admin + // override). -1 would mean unlimited (never reached). + const bookmarkLimit = user?.limits?.bookmarks ?? 1; + const limitReached = + !!user && bookmarkLimit >= 0 && bookmarkCount >= bookmarkLimit; // Track whether the user is interacting with our toolbar/popovers const interactingRef = useRef(false); diff --git a/lib/auth.ts b/lib/auth.ts index a81ec572..fe2f118f 100644 --- a/lib/auth.ts +++ b/lib/auth.ts @@ -49,6 +49,14 @@ export type User = { * later — surfaced here for completeness, no UI edits them today. */ preferred_chanting_time: string | null; peak_active_time: string | null; + /** Effective save limits in force for this user (plan default merged with + * any admin override). -1 means unlimited. Drives the "X / Y used" displays + * and the create-action gates. */ + limits: { + bookmarks: number; + public_collections: number; + private_collections: number; + }; created_at: string; updated_at: string; };