'use client' import { useEffect, useState } from 'react' import Link from 'next/link' import { motion } from 'framer-motion' import { useAuth } from '@/lib/auth/context' import { initiateOAuthFlow, initiateSignupFlow } from '@/lib/api/oauth' import { listSites, deleteSite, type Site } from '@/lib/api/sites' import { getStats } from '@/lib/api/stats' import type { Stats } from '@/lib/api/stats' import { getSubscription, type SubscriptionDetails } from '@/lib/api/billing' import { LoadingOverlay } from '@ciphera-net/ui' import SiteList from '@/components/sites/SiteList' 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 (
Dashboard Preview
The lightweight, privacy-friendly alternative.
| Feature | Pulse | Google Analytics |
|---|---|---|
| {row.feature} |
{row.pulse === true ? (
|
{row.ga === true ? ( Yes ) : ( {row.ga} )} |
{feature.desc}
No credit card required • Cancel anytime
Finish setting up your workspace and add your first site.
Manage your analytics sites and view insights.
Total Sites
{sites.length}
Total Visitors (24h)
{sites.length === 0 || Object.keys(siteStats).length < sites.length ? '--' : Object.values(siteStats).reduce((sum, { stats }) => sum + (stats?.visitors ?? 0), 0).toLocaleString()}
Plan & usage
{subscriptionLoading ? ({(() => { const raw = subscription.plan_id?.startsWith('price_') ? 'Pro' : subscription.plan_id === 'free' || !subscription.plan_id ? 'Free' : subscription.plan_id const label = raw === 'Free' || raw === 'Pro' ? raw : raw.charAt(0).toUpperCase() + raw.slice(1) return `${label} Plan` })()}
{(typeof subscription.sites_count === 'number' || (subscription.pageview_limit > 0 && typeof subscription.pageview_usage === 'number') || (subscription.next_invoice_amount_due != null && subscription.next_invoice_currency && !subscription.cancel_at_period_end && (subscription.subscription_status === 'active' || subscription.subscription_status === 'trialing'))) && ({typeof subscription.sites_count === 'number' && ( Sites: {(() => { const limit = getSitesLimitForPlan(subscription.plan_id) return limit != null && typeof subscription.sites_count === 'number' ? `${subscription.sites_count}/${limit}` : subscription.sites_count })()} )} {typeof subscription.sites_count === 'number' && (subscription.pageview_limit > 0 && typeof subscription.pageview_usage === 'number') && ' · '} {subscription.pageview_limit > 0 && typeof subscription.pageview_usage === 'number' && ( Pageviews: {subscription.pageview_usage.toLocaleString()}/{subscription.pageview_limit.toLocaleString()} )} {subscription.next_invoice_amount_due != null && subscription.next_invoice_currency && !subscription.cancel_at_period_end && (subscription.subscription_status === 'active' || subscription.subscription_status === 'trialing') && ( Renews {(() => { const ts = subscription.next_invoice_period_end ?? subscription.current_period_end const d = ts ? new Date(typeof ts === 'number' ? ts * 1000 : ts) : null const dateStr = d && !Number.isNaN(d.getTime()) && d.getTime() !== 0 ? d.toLocaleDateString(undefined, { month: 'short', day: 'numeric', year: 'numeric' }) : null const amount = (subscription.next_invoice_amount_due / 100).toLocaleString('en-US', { style: 'currency', currency: subscription.next_invoice_currency.toUpperCase(), }) return dateStr ? `${dateStr} for ${amount}` : amount })()} )}
)}Free Plan
)}Connect a domain to start collecting privacy-friendly analytics. You can add more sites later from the dashboard.