Home Projects Jportal Feature Modules Analytics Dashboard

Analytics Dashboard

Purpose and Scope

This page documents the Analytics Dashboard feature, which provides web analytics visualization using Cloudflare's Web Analytics GraphQL API. The dashboard displays visitor statistics, page views, browser/OS distributions, and time-series data with interactive date range selection.

This page covers the Cloudflare component and its associated DateRangeSelector component. For information about other feature modules, see Feature Modules. For UI component documentation, see UI Components.


Overview

The Analytics Dashboard is a standalone feature accessible via the /stats route. It operates independently of the authentication system and does not require the w (WebPortal) prop like other feature modules. Instead, it connects directly to Cloudflare's GraphQL API to fetch and visualize web analytics data.

The dashboard provides:

  • Aggregate statistics: Total visitors and page views for a selected time range
  • Time-series visualizations: Visits and page views over time displayed as area charts
  • Distribution analytics: Browser and OS usage shown as pie and bar charts
  • Flexible date range selection: Preset ranges (15 minutes to 7 days) and custom date/time selection

Sources: jportal/src/components/Cloudflare.jsx1-497


Component Architecture

Main Component Structure

Architecture Diagram

Diagram: Cloudflare Component Architecture

The Cloudflare component (jportal/src/components/Cloudflare.jsx16-497) orchestrates the entire analytics dashboard. It manages date range state, invokes custom hooks for data fetching, and renders multiple visualization types using Recharts components wrapped in shadcn/ui chart containers.

Sources: jportal/src/components/Cloudflare.jsx1-497


State Management

Date Range State

The component maintains date range state initialized to the last 7 days:

State Variable Type Purpose
dateRange {from: Date, to: Date} Current selected date range for analytics queries
themeState Zustand store Theme configuration for dynamic chart colors
forceUpdate {} Triggers re-render when theme changes

Sources: jportal/src/components/Cloudflare.jsx17-38

Theme Integration

The component subscribes to the theme store to dynamically retrieve chart colors:

getChartColor(index) => getComputedStyle(document.documentElement)
  .getPropertyValue(`--chart-${(index % 5) + 1}`)

This function retrieves CSS custom properties (--chart-1 through --chart-5) defined by the current theme preset, ensuring visualizations match the selected theme.

Sources: jportal/src/components/Cloudflare.jsx17-31


Data Fetching Layer

Custom Hooks Architecture

Architecture Diagram

Diagram: Data Fetching Flow

Each custom hook makes GraphQL queries to Cloudflare's Web Analytics API through a CORS proxy. The hooks accept from and to Date parameters and return data objects along with loading states.

Sources: jportal/src/components/Cloudflare.jsx4-9 jportal/src/components/Cloudflare.jsx91-100

Hook Invocations

The component invokes four hooks with the current date range:

// Aggregate stats
const { data: aggregateData, isLoading: aggregateLoading } = 
  useFetchWebAnalyticsAggregate(dateRange.from, dateRange.to)

// Browser distribution  
const { data: browserData, isLoading: browserLoading } = 
  useFetchWebAnalyticsBrowser(dateRange.from, dateRange.to)

// OS distribution
const { data: osData, isLoading: osLoading } = 
  useFetchWebAnalyticsOS(dateRange.from, dateRange.to)

// Time-series data
const { data: sparklineData, isLoading: sparklineLoading } = 
  useFetchWebAnalyticsSparkline(dateRange.from, dateRange.to)

Sources: jportal/src/components/Cloudflare.jsx91-100


Date Range Selection

DateRangeSelector Component

Architecture Diagram

Diagram: DateRangeSelector Component Structure

The DateRangeSelector component provides two interaction modes:

  1. Preset selection: Quick access to common time ranges via dropdown
  2. Custom selection: Date range picker with calendar and time inputs

Sources: jportal/src/components/DateRangeSelector.jsx1-177

Preset Ranges Configuration

The component defines preset ranges in the PRESET_RANGES object:

Preset Key Label Duration (minutes)
15min Last 15 minutes 15
1hour Last hour 60
6hours Last 6 hours 360
24hours Last 24 hours 1440
7days Last 7 days 10080
custom Custom range null

Sources: jportal/src/components/DateRangeSelector.jsx10-17

Preset Range Selection

When a user selects a preset:

handlePresetChange(value) {
  if (value === "custom") {
    // Open calendar popover
    setTimeout(() => setIsCalendarOpen(true), 100)
    return
  }

  // Calculate date range from preset
  const preset = PRESET_RANGES[value]
  const to = new Date()
  const from = new Date(to.getTime() - preset.minutes * 60 * 1000)
  onDateRangeChange({ from, to })
}

Sources: jportal/src/components/DateRangeSelector.jsx37-57

Custom Range Selection

When custom is selected, a Popover opens with:

The calendar restricts selection to dates between 2020-01-01 and the current date.

Sources: jportal/src/components/DateRangeSelector.jsx59-103 jportal/src/components/DateRangeSelector.jsx136-159

Time Picker Components

The TimePicker component (jportal/src/components/ui/time-picker.tsx14-40) uses two TimePickerInput instances for hours and minutes. It manages:

  • Hour input: 24-hour format (00-23)
  • Minute input: Standard format (00-59)
  • Arrow navigation: Left/right arrow keys move between inputs
  • Up/down arrows: Increment/decrement time values

Sources: jportal/src/components/ui/time-picker.tsx1-40 jportal/src/components/ui/time-picker-input.tsx1-122


Visualizations

Aggregate Statistics Cards

The dashboard displays two metric cards at the top:

┌─────────────────────────┐  ┌─────────────────────────┐
│ Total Visitors          │  │ Total Page Views        │
│                         │  │                         │
│ 1,234                   │  │ 5,678                   │
└─────────────────────────┘  └─────────────────────────┘

These cards use the aggregateData from useFetchWebAnalyticsAggregate:

  • aggregateData.visits → Total Visitors
  • aggregateData.pageViews → Total Page Views

While loading, Skeleton components display placeholder UI.

Sources: jportal/src/components/Cloudflare.jsx119-145

Time-Series Charts

Visits Over Time (Area Chart)

The component renders an AreaChart with:

  • Data source: sparklineData.visits array of { timestamp, visits } objects
  • X-axis: Timestamps formatted as "MMM DD"
  • Y-axis: Visit counts
  • Styling: Gradient fill with dynamic theme color
  • Tooltip: Custom tooltip showing formatted date/time and visit count

Sources: jportal/src/components/Cloudflare.jsx147-231

Page Views Over Time (Area Chart)

Similar structure to the visits chart but uses sparklineData.pageviews:

  • Data source: sparklineData.pageviews array
  • Color: Uses getChartColor(1) (second theme color)

Sources: jportal/src/components/Cloudflare.jsx233-317

Distribution Charts

Both browser and OS distributions use a dual-chart approach:

Chart Configuration

Each distribution section displays:

  1. Pie Chart: Donut style with innerRadius={60}
  2. Bar Chart: Horizontal layout showing exact counts

Architecture Diagram

Diagram: Distribution Chart Architecture

Sources: jportal/src/components/Cloudflare.jsx319-493

Browser Distribution Implementation

The browser distribution card (jportal/src/components/Cloudflare.jsx321-407):

  • Maps browserData array to pie chart format with dynamic colors
  • Displays horizontal bar chart with browser names as Y-axis labels
  • Uses ChartContainer config for consistent theming

OS Distribution Implementation

The OS distribution card (jportal/src/components/Cloudflare.jsx409-492) follows identical structure to browser distribution but uses osData.


Dynamic Date Range Description

The component includes a helper function getDateRangeDescription() (jportal/src/components/Cloudflare.jsx44-89) that generates human-readable descriptions for chart subtitles:

Condition Description Output
Last 15-30 minutes "last 15 minutes" / "last 30 minutes"
Last 1 hour "last hour"
Last 3-6-12-24 hours "last 3 hours" / "last 6 hours" / etc.
Last 1-7 days "last 7 days"
Custom range "5 days (Jan 1 to Jan 5)"

This description appears in the CardDescription for time-series charts.

Sources: jportal/src/components/Cloudflare.jsx44-89 jportal/src/components/Cloudflare.jsx151 jportal/src/components/Cloudflare.jsx237


Configuration

Environment Variables

The analytics dashboard requires the following environment variables (defined in jportal/.env.example1-7):

Variable Purpose Example Value
VITE_CLOUDFLARE_API_TOKEN Authentication token for Cloudflare API g29zrxuDBV3FfsTpC3q4_...
VITE_CLOUDFLARE_PROXY_URL CORS proxy endpoint https://cors-header-proxy.my-malikyash.workers.dev
VITE_CLOUDFLARE_BASE_URL Cloudflare GraphQL endpoint https://api.cloudflare.com/client/v4/graphql
VITE_CLOUDFLARE_ACCOUNT_TAG Cloudflare account identifier 2af5100754a8644e0e2a576365803123
VITE_CLOUDFLARE_SITE_TAG Site/zone identifier b34248b80c7a4ca6ba091bdefee60093

These variables are accessed by the custom hooks (not shown in provided files) to construct GraphQL queries.

Sources: jportal/.env.example1-7


Integration with Application

Routing and Navigation

The analytics dashboard is accessible via the /stats route. Unlike other feature modules that are rendered within AuthenticatedApp, the Cloudflare component:

Layout Structure

┌──────────────────────────────────────┐
│ PublicHeader (sticky, showBackButton)│
├──────────────────────────────────────┤
│ Stats for Nerds 🤓                   │
│ Web Analytics Dashboard              │
│                        [Date Selector]│
├──────────────────────────────────────┤
│ [Total Visitors] [Total Page Views]  │
├──────────────────────────────────────┤
│ Visits Over Time (Area Chart)        │
├──────────────────────────────────────┤
│ Page Views Over Time (Area Chart)    │
├──────────────────────────────────────┤
│ [Browser Dist.] [OS Distribution]    │
└──────────────────────────────────────┘

The layout uses responsive grid classes:

  • Aggregate cards: grid gap-4 md:grid-cols-2
  • Distribution charts: grid gap-6 xl:grid-cols-2

Sources: jportal/src/components/Cloudflare.jsx102-494


Loading and Error States

The component handles loading states for each data source independently:

Data Type Loading Check Skeleton Display
Aggregate stats aggregateLoading <Skeleton className="h-8 w-24" />
Time-series sparklineLoading <Skeleton className="h-[300px] w-full" />
Browser data browserLoading <Skeleton className="h-[400px] w-full" />
OS data osLoading <Skeleton className="h-[400px] w-full" />

When data is unavailable (empty arrays), the component displays fallback messages:

  • "No visits data available"
  • "No pageviews data available"
  • "No browser data available"
  • "No OS data available"

Sources: jportal/src/components/Cloudflare.jsx126-140 jportal/src/components/Cloudflare.jsx154-229 jportal/src/components/Cloudflare.jsx328-405 jportal/src/components/Cloudflare.jsx416-490