feat: implement site limits based on subscription plans across dashboard and new site creation; enhance UI feedback for plan limits

This commit is contained in:
Usman Baig
2026-02-20 02:46:23 +01:00
parent f9eb6bf5c0
commit 826dbdbe63
4 changed files with 35 additions and 11 deletions

View File

@@ -13,6 +13,7 @@ import { Button } from '@ciphera-net/ui'
import { BarChartIcon, LockIcon, ZapIcon, CheckCircleIcon, XIcon, GlobeIcon } from '@ciphera-net/ui'
import { toast } from '@ciphera-net/ui'
import { getAuthErrorMessage } from '@ciphera-net/ui'
import { getSitesLimitForPlan } from '@/lib/plans'
function DashboardPreview() {
return (
@@ -337,10 +338,13 @@ export default function HomePage() {
<h1 className="text-2xl font-bold text-neutral-900 dark:text-white">Your Sites</h1>
<p className="mt-1 text-sm text-neutral-500 dark:text-neutral-400">Manage your analytics sites and view insights.</p>
</div>
{subscription?.plan_id === 'solo' && sites.length >= 1 ? (
{(() => {
const siteLimit = getSitesLimitForPlan(subscription?.plan_id)
const atLimit = siteLimit != null && sites.length >= siteLimit
return atLimit ? (
<div className="flex items-center gap-3">
<span className="text-sm font-medium text-neutral-500 dark:text-neutral-400 bg-neutral-100 dark:bg-neutral-800 px-3 py-1.5 rounded-lg border border-neutral-200 dark:border-neutral-700">
Limit reached (1/1)
Limit reached ({sites.length}/{siteLimit})
</span>
<Link href="/pricing">
<Button variant="primary" className="text-sm">
@@ -348,7 +352,8 @@ export default function HomePage() {
</Button>
</Link>
</div>
) : (
) : null
})() ?? (
<Link href="/sites/new">
<Button variant="primary" className="text-sm">
Add New Site
@@ -388,7 +393,10 @@ export default function HomePage() {
{(typeof subscription.sites_count === 'number' || (subscription.pageview_limit > 0 && typeof subscription.pageview_usage === 'number')) && (
<p className="text-sm text-neutral-600 dark:text-neutral-400 mt-1">
{typeof subscription.sites_count === 'number' && (
<span>Sites: {subscription.plan_id === 'solo' && subscription.sites_count > 0 ? `${subscription.sites_count}/1` : subscription.sites_count}</span>
<span>Sites: {(() => {
const limit = getSitesLimitForPlan(subscription.plan_id)
return limit != null && typeof subscription.sites_count === 'number' ? `${subscription.sites_count}/${limit}` : subscription.sites_count
})()}</span>
)}
{typeof subscription.sites_count === 'number' && subscription.pageview_limit > 0 && typeof subscription.pageview_usage === 'number' && ' · '}
{subscription.pageview_limit > 0 && typeof subscription.pageview_usage === 'number' && (

View File

@@ -5,6 +5,7 @@ import { useRouter } from 'next/navigation'
import Link from 'next/link'
import { createSite, listSites, getSite, type Site } from '@/lib/api/sites'
import { getSubscription } from '@/lib/api/billing'
import { getSitesLimitForPlan } from '@/lib/plans'
import { trackSiteCreatedFromDashboard, trackSiteCreatedScriptCopied } from '@/lib/welcomeAnalytics'
import { toast } from '@ciphera-net/ui'
import { getAuthErrorMessage } from '@ciphera-net/ui'
@@ -57,9 +58,10 @@ export default function NewSitePage() {
getSubscription()
])
if (subscription?.plan_id === 'solo' && sites.length >= 1) {
const siteLimit = subscription?.plan_id ? getSitesLimitForPlan(subscription.plan_id) : null
if (siteLimit != null && sites.length >= siteLimit) {
setAtLimit(true)
toast.error('Solo plan limit reached (1 site). Please upgrade to add more sites.')
toast.error(`${subscription.plan_id} plan limit reached (${siteLimit} site${siteLimit === 1 ? '' : 's'}). Please upgrade to add more sites.`)
router.replace('/')
}
} catch (error) {