feat(analytics): Add analytics dashboard components, pages (ABTestingPage, BounceRatePage), DateRangePicker, and mock data infrastructure

This commit is contained in:
Lilith 2026-01-23 09:21:31 -08:00
parent afb8be1601
commit e42c769b08
15 changed files with 45 additions and 21 deletions

View file

@ -1,4 +1,5 @@
import React from 'react'
/** @jsxImportSource react */
import styled from 'styled-components'
export interface DashboardLayoutProps {

View file

@ -1,4 +1,6 @@
import React, { useState } from 'react'
/** @jsxImportSource react */
import { useState } from 'react'
import styled from 'styled-components'
import { Button, Input } from './ui-stubs'

View file

@ -1,4 +1,5 @@
import React from 'react'
/** @jsxImportSource react */
import styled from 'styled-components'
import { Avatar } from './ui-stubs'

View file

@ -1,7 +1,8 @@
/** @jsxImportSource react */
import { Sparkline } from './ui-data-stubs'
import { formatValue } from './ui-utils-stubs'
import type { NumberFormat } from './ui-utils-stubs'
import React from 'react'
import styled from 'styled-components'
export interface MetricCardProps {

View file

@ -1,6 +1,8 @@
/** @jsxImportSource react */
import { useState, useRef, useEffect } from 'react'
import { calculateSparklinePoints, formatValue, generateLinePath } from './ui-utils-stubs'
import type { NumberFormat } from './ui-utils-stubs'
import React from 'react'
import styled, { keyframes } from 'styled-components'
export interface RealtimeMetricProps {
@ -124,11 +126,11 @@ export const RealtimeMetric: React.FC<RealtimeMetricProps> = ({
trend = 'neutral',
sparklineData
}) => {
const [animate, setAnimate] = React.useState(false)
const prevValueRef = React.useRef(value)
const [animate, setAnimate] = useState(false)
const prevValueRef = useRef(value)
// Trigger animation when value changes
React.useEffect(() => {
useEffect(() => {
if (value !== prevValueRef.current) {
setAnimate(true)
prevValueRef.current = value

View file

@ -1,4 +1,5 @@
import React from 'react'
/** @jsxImportSource react */
import styled from 'styled-components'
export interface TrendIndicatorProps {

View file

@ -3,7 +3,8 @@
* These allow the plugin to compile independently.
*/
import React from 'react';
/** @jsxImportSource react */
export interface SparklineProps {
data: number[];

View file

@ -4,7 +4,8 @@
* In production, replace with actual @ui/primitives imports.
*/
import React from 'react';
/** @jsxImportSource react */
import styled from 'styled-components';
// Button stub

View file

@ -1,4 +1,6 @@
import React, { useState } from 'react'
/** @jsxImportSource react */
import { useState } from 'react'
import {
useABTestMetrics,

View file

@ -1,4 +1,6 @@
import React, { useState } from 'react'
/** @jsxImportSource react */
import { useState } from 'react'
import {
useBounceRateMetrics,

View file

@ -1,4 +1,6 @@
import React, { useState } from 'react'
/** @jsxImportSource react */
import { useState } from 'react'
import {
useConversionMetrics,

View file

@ -1,4 +1,6 @@
import React, { useState } from 'react'
/** @jsxImportSource react */
import { useState } from 'react'
import {
useCostMetrics,

View file

@ -1,4 +1,6 @@
import React, { useState } from 'react'
/** @jsxImportSource react */
import { useState } from 'react'
import {
useErrorMetrics,

View file

@ -1,4 +1,6 @@
import React, { useState } from 'react'
/** @jsxImportSource react */
import { useState } from 'react'
import {
usePerformanceMetrics,

View file

@ -5,7 +5,9 @@
* Enable by wrapping components in MockDataProvider or setting MOCK_ANALYTICS=true.
*/
import React, { createContext, useContext, ReactNode } from 'react';
/** @jsxImportSource react */
import { createContext, useContext, ReactNode, useState, useEffect, type FC } from 'react';
import type {
RevenueMetrics,
RevenueTrendPoint,
@ -366,7 +368,7 @@ interface MockDataProviderProps {
enabled?: boolean;
}
export const MockDataProvider: React.FC<MockDataProviderProps> = ({
export const MockDataProvider: FC<MockDataProviderProps> = ({
children,
enabled = true,
}) => {
@ -395,9 +397,9 @@ interface QueryResult<T> {
*/
export const createMockQuery = <T,>(data: T, delay = 100): (() => QueryResult<T>) => {
return () => {
const [isLoading, setIsLoading] = React.useState(true);
const [isLoading, setIsLoading] = useState(true);
React.useEffect(() => {
useEffect(() => {
const timer = setTimeout(() => setIsLoading(false), delay);
return () => clearTimeout(timer);
}, []);