feat: enhance user limits
This commit is contained in:
@@ -8,9 +8,6 @@ import { useAuth } from "@/components/auth/auth-provider";
|
|||||||
import { appendHighlight, hasHighlight } from "@/lib/text-highlight";
|
import { appendHighlight, hasHighlight } from "@/lib/text-highlight";
|
||||||
import { displaySourceLabel } from "@/lib/source-reference";
|
import { displaySourceLabel } from "@/lib/source-reference";
|
||||||
|
|
||||||
const FREE_LIMIT = 1;
|
|
||||||
const PREMIUM_LIMIT = 5;
|
|
||||||
|
|
||||||
export default function MyBookmarksPage() {
|
export default function MyBookmarksPage() {
|
||||||
const { user } = useAuth();
|
const { user } = useAuth();
|
||||||
const [list, setList] = useState<Bookmark[]>([]);
|
const [list, setList] = useState<Bookmark[]>([]);
|
||||||
@@ -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 <p className="text-sm text-muted-foreground">Loading…</p>;
|
if (loading) return <p className="text-sm text-muted-foreground">Loading…</p>;
|
||||||
|
|
||||||
|
|||||||
@@ -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 publicCount = list.filter((c) => c.is_public).length;
|
||||||
const privateCount = list.filter((c) => !c.is_public).length;
|
const privateCount = list.filter((c) => !c.is_public).length;
|
||||||
|
|
||||||
@@ -62,12 +66,14 @@ export default function MyCollectionsPage() {
|
|||||||
<div className="space-y-5">
|
<div className="space-y-5">
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<p className="text-sm text-muted-foreground">
|
<p className="text-sm text-muted-foreground">
|
||||||
{isPremium ? (
|
{unlimited ? (
|
||||||
<>Premium — unlimited collections.</>
|
<>Unlimited collections.</>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<span className="tabular-nums">{publicCount}</span> / 5 public ·{" "}
|
<span className="tabular-nums">{publicCount}</span> / {pubLimit}{" "}
|
||||||
<span className="tabular-nums">{privateCount}</span> / 5 private
|
public ·{" "}
|
||||||
|
<span className="tabular-nums">{privateCount}</span> / {privLimit}{" "}
|
||||||
|
private
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</p>
|
</p>
|
||||||
|
|||||||
@@ -73,8 +73,11 @@ export function TextSelectionToolbar() {
|
|||||||
};
|
};
|
||||||
}, [user]);
|
}, [user]);
|
||||||
|
|
||||||
const bookmarkLimit = user?.plan === "premium" ? 5 : 1;
|
// Effective bookmark cap from the server (plan default merged with any admin
|
||||||
const limitReached = !!user && bookmarkCount >= bookmarkLimit;
|
// 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
|
// Track whether the user is interacting with our toolbar/popovers
|
||||||
const interactingRef = useRef(false);
|
const interactingRef = useRef(false);
|
||||||
|
|||||||
@@ -49,6 +49,14 @@ export type User = {
|
|||||||
* later — surfaced here for completeness, no UI edits them today. */
|
* later — surfaced here for completeness, no UI edits them today. */
|
||||||
preferred_chanting_time: string | null;
|
preferred_chanting_time: string | null;
|
||||||
peak_active_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;
|
created_at: string;
|
||||||
updated_at: string;
|
updated_at: string;
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user