'use client' import { useCallback, useEffect, useMemo, useState } from 'react' import { useParams, useRouter } from 'next/navigation' import { ApiError } from '@/lib/api/client' import { getFunnel, getFunnelStats, deleteFunnel, type Funnel, type FunnelStats } from '@/lib/api/funnels' import { toast, LoadingOverlay, Select, DatePicker, ChevronLeftIcon, ArrowRightIcon, TrashIcon, useTheme } from '@ciphera-net/ui' import Link from 'next/link' import { BarChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, Cell } from 'recharts' import { getDateRange } from '@/lib/utils/format' const CHART_COLORS_LIGHT = { border: '#E5E5E5', axis: '#A3A3A3', tooltipBg: '#ffffff', tooltipBorder: '#E5E5E5', } const CHART_COLORS_DARK = { border: '#404040', axis: '#737373', tooltipBg: '#262626', tooltipBorder: '#404040', } const BRAND_ORANGE = '#FD5E0F' export default function FunnelReportPage() { const params = useParams() const router = useRouter() const siteId = params.id as string const funnelId = params.funnelId as string const [funnel, setFunnel] = useState(null) const [stats, setStats] = useState(null) const [loading, setLoading] = useState(true) const [dateRange, setDateRange] = useState(getDateRange(30)) const [datePreset, setDatePreset] = useState<'7' | '30' | 'custom'>('30') const [isDatePickerOpen, setIsDatePickerOpen] = useState(false) const [loadError, setLoadError] = useState<'not_found' | 'error' | null>(null) const loadData = useCallback(async () => { setLoadError(null) try { setLoading(true) const [funnelData, statsData] = await Promise.all([ getFunnel(siteId, funnelId), getFunnelStats(siteId, funnelId, dateRange.start, dateRange.end) ]) setFunnel(funnelData) setStats(statsData) } catch (error) { const is404 = error instanceof ApiError && error.status === 404 setLoadError(is404 ? 'not_found' : 'error') if (!is404) toast.error('Failed to load funnel data') } finally { setLoading(false) } }, [siteId, funnelId, dateRange]) useEffect(() => { loadData() }, [loadData]) const { resolvedTheme } = useTheme() const chartColors = useMemo( () => (resolvedTheme === 'dark' ? CHART_COLORS_DARK : CHART_COLORS_LIGHT), [resolvedTheme] ) const handleDelete = async () => { if (!confirm('Are you sure you want to delete this funnel?')) return try { await deleteFunnel(siteId, funnelId) toast.success('Funnel deleted') router.push(`/sites/${siteId}/funnels`) } catch (error) { toast.error('Failed to delete funnel') } } if (loading && !funnel) { return } if (loadError === 'not_found' || (!funnel && !stats && !loadError)) { return (

Funnel not found

) } if (loadError === 'error') { return (

Failed to load funnel data

) } if (!funnel || !stats) { return (

Funnel not found

) } const chartData = stats.steps.map(s => ({ name: s.step.name, visitors: s.visitors, dropoff: s.dropoff, conversion: s.conversion })) return (

{funnel.name}

{funnel.description && (

{funnel.description}

)}