From df10d4e747d92a60c0d0f5e4822b5c2287736d9d Mon Sep 17 00:00:00 2001 From: Usman Baig Date: Sun, 15 Mar 2026 22:00:58 +0100 Subject: [PATCH] feat: add actionable CTAs to all dashboard empty states - Campaigns: "Build a UTM URL" opens UTM builder modal directly - Pages/Referrers/Locations/Technology: "Install tracking script" links to /installation - Matches existing CTA pattern from GoalStats --- CHANGELOG.md | 1 + components/dashboard/Campaigns.tsx | 10 +++++----- components/dashboard/ContentStats.tsx | 10 +++++++++- components/dashboard/Locations.tsx | 10 +++++++++- components/dashboard/TechSpecs.tsx | 10 +++++++++- components/dashboard/TopReferrers.tsx | 10 +++++++++- 6 files changed, 42 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4f887e7..8bbcc5a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), ### Improved +- **Actionable empty states.** When a dashboard section has no data yet, you now get a direct action — like "Install tracking script" or "Build a UTM URL" — instead of just passive text. Gets you set up faster. - **Animated numbers across the dashboard.** Stats like visitors, pageviews, bounce rate, and visit duration now smoothly count up or down when you switch date ranges, apply filters, or when real-time visitor counts change — instead of just jumping to the new value. - **Inline bar charts on dashboard lists.** Pages, referrers, locations, technology, and campaigns now show subtle proportional bars behind each row, making it easier to compare values at a glance without reading numbers. - **Redesigned Top Paths.** The Top Paths section on the Journeys page has been completely rebuilt — from bulky cards to a clean, compact list with inline bars that matches the rest of Pulse. Long path sequences are truncated so they stay readable. diff --git a/components/dashboard/Campaigns.tsx b/components/dashboard/Campaigns.tsx index 0d5c745..02bf7c5 100644 --- a/components/dashboard/Campaigns.tsx +++ b/components/dashboard/Campaigns.tsx @@ -206,13 +206,13 @@ export default function Campaigns({ siteId, dateRange, filters, onFilter }: Camp

Add UTM parameters to your links to see campaign performance here.

- setIsBuilderOpen(true)} + className="inline-flex items-center gap-2 text-sm font-medium text-brand-orange hover:text-brand-orange/90 hover:underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-brand-orange/20 rounded cursor-pointer" > - Learn more + Build a UTM URL - + )} diff --git a/components/dashboard/ContentStats.tsx b/components/dashboard/ContentStats.tsx index 4b0a460..38e7209 100644 --- a/components/dashboard/ContentStats.tsx +++ b/components/dashboard/ContentStats.tsx @@ -6,8 +6,9 @@ import { logger } from '@/lib/utils/logger' import { formatNumber } from '@ciphera-net/ui' import { useTabListKeyboard } from '@/lib/hooks/useTabListKeyboard' import { TopPage, getTopPages, getEntryPages, getExitPages } from '@/lib/api/stats' +import Link from 'next/link' import { Files, FrameCornersIcon } from '@phosphor-icons/react' -import { Modal, ArrowUpRightIcon, LayoutDashboardIcon } from '@ciphera-net/ui' +import { Modal, ArrowUpRightIcon, ArrowRightIcon, LayoutDashboardIcon } from '@ciphera-net/ui' import { ListSkeleton } from '@/components/skeletons' import VirtualList from './VirtualList' import { type DimensionFilter } from '@/lib/filters' @@ -199,6 +200,13 @@ export default function ContentStats({ topPages, entryPages, exitPages, domain,

Your most visited pages will appear here as traffic arrives.

+ + Install tracking script + + )} diff --git a/components/dashboard/Locations.tsx b/components/dashboard/Locations.tsx index 0fd83ac..147963f 100644 --- a/components/dashboard/Locations.tsx +++ b/components/dashboard/Locations.tsx @@ -11,7 +11,8 @@ import iso3166 from 'iso-3166-2' const DottedMap = dynamic(() => import('./DottedMap'), { ssr: false }) const Globe = dynamic(() => import('./Globe'), { ssr: false }) -import { Modal, GlobeIcon } from '@ciphera-net/ui' +import Link from 'next/link' +import { Modal, GlobeIcon, ArrowRightIcon } from '@ciphera-net/ui' import { ListSkeleton } from '@/components/skeletons' import VirtualList from './VirtualList' import { ShieldCheck, Detective, Broadcast, MapPin, FrameCornersIcon } from '@phosphor-icons/react' @@ -280,6 +281,13 @@ export default function Locations({ countries, cities, regions, geoDataLevel = '

Visitor locations will appear here based on anonymous geographic data.

+ + Install tracking script + + ) ) : ( diff --git a/components/dashboard/TechSpecs.tsx b/components/dashboard/TechSpecs.tsx index 2fa2b62..d40f0ef 100644 --- a/components/dashboard/TechSpecs.tsx +++ b/components/dashboard/TechSpecs.tsx @@ -6,8 +6,9 @@ import { logger } from '@/lib/utils/logger' import { formatNumber } from '@ciphera-net/ui' import { useTabListKeyboard } from '@/lib/hooks/useTabListKeyboard' import { getBrowserIcon, getOSIcon, getDeviceIcon } from '@/lib/utils/icons' +import Link from 'next/link' import { Monitor, DeviceMobile, FrameCornersIcon } from '@phosphor-icons/react' -import { Modal, GridIcon } from '@ciphera-net/ui' +import { Modal, GridIcon, ArrowRightIcon } from '@ciphera-net/ui' import { ListSkeleton } from '@/components/skeletons' import VirtualList from './VirtualList' import { getBrowsers, getOS, getDevices, getScreenResolutions } from '@/lib/api/stats' @@ -223,6 +224,13 @@ export default function TechSpecs({ browsers, os, devices, screenResolutions, co

Browser, OS, and device information will appear as visitors arrive.

+ + Install tracking script + + )} diff --git a/components/dashboard/TopReferrers.tsx b/components/dashboard/TopReferrers.tsx index 434efca..c8f5ce2 100644 --- a/components/dashboard/TopReferrers.tsx +++ b/components/dashboard/TopReferrers.tsx @@ -5,8 +5,9 @@ import { logger } from '@/lib/utils/logger' import Image from 'next/image' import { formatNumber } from '@ciphera-net/ui' import { getReferrerDisplayName, getReferrerFavicon, getReferrerIcon, mergeReferrersByDisplayName } from '@/lib/utils/icons' +import Link from 'next/link' import { ArrowSquareOut, FrameCornersIcon } from '@phosphor-icons/react' -import { Modal, GlobeIcon } from '@ciphera-net/ui' +import { Modal, GlobeIcon, ArrowRightIcon } from '@ciphera-net/ui' import { ListSkeleton } from '@/components/skeletons' import VirtualList from './VirtualList' import { getTopReferrers, TopReferrer } from '@/lib/api/stats' @@ -155,6 +156,13 @@ export default function TopReferrers({ referrers, collectReferrers = true, siteI

Traffic sources will appear here when visitors come from external sites.

+ + Install tracking script + + )}