Session 19: Sports design overhaul — player cards with headshots, game card redesign, scan page tonight's players, odds diagnostic logging, tier gate utility (1444 tests)
This commit is contained in:
@@ -0,0 +1,53 @@
|
||||
/**
|
||||
* Tier-gating helpers (Session 19).
|
||||
*
|
||||
* Shared, declarative answers to the questions every list-rendering
|
||||
* component asks: "should this user see everything, or a teaser?"
|
||||
* Centralized so we don't drift across components (one screen
|
||||
* showing 3 rows + upgrade hint, another showing 5 rows + lock
|
||||
* icon, a third showing all rows with a partial blur — that path
|
||||
* leads to chaos).
|
||||
*
|
||||
* The actual SECURITY boundary on tier-locked data lives on the
|
||||
* server (the API routes that produce these lists already filter by
|
||||
* the bearer token's tier). These helpers govern presentation only,
|
||||
* matching the server-supplied limit so the UI doesn't promise more
|
||||
* than the API will deliver.
|
||||
*
|
||||
* Free users see top 3. Paid (analyst + desk) see everything.
|
||||
* Africa tier (entry-level subscription) also sees everything for
|
||||
* lists; gradient features live behind canSeeGradeDetails.
|
||||
*/
|
||||
|
||||
export type Tier = 'free' | 'africa' | 'analyst' | 'desk' | string;
|
||||
|
||||
const PAID_TIERS: ReadonlySet<string> = new Set(['analyst', 'desk']);
|
||||
const FULL_LIST_TIERS: ReadonlySet<string> = new Set(['africa', 'analyst', 'desk']);
|
||||
|
||||
const FREE_VISIBLE_COUNT = 3;
|
||||
|
||||
export function canSeeFullLists(tier: Tier): boolean {
|
||||
if (!tier) return false;
|
||||
return FULL_LIST_TIERS.has(String(tier).toLowerCase());
|
||||
}
|
||||
|
||||
export function canSeeGradeDetails(tier: Tier): boolean {
|
||||
if (!tier) return false;
|
||||
return PAID_TIERS.has(String(tier).toLowerCase());
|
||||
}
|
||||
|
||||
export function getVisibleCount(tier: Tier, totalCount: number): number {
|
||||
if (totalCount <= 0) return 0;
|
||||
if (canSeeFullLists(tier)) return totalCount;
|
||||
return Math.min(FREE_VISIBLE_COUNT, totalCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inverse helper for UX copy — "Upgrade to see N more results."
|
||||
* Returns 0 when the tier already sees everything (so the upsell
|
||||
* line can short-circuit without arithmetic).
|
||||
*/
|
||||
export function getHiddenCount(tier: Tier, totalCount: number): number {
|
||||
if (canSeeFullLists(tier)) return 0;
|
||||
return Math.max(0, totalCount - FREE_VISIBLE_COUNT);
|
||||
}
|
||||
Reference in New Issue
Block a user