import { useEffect, useRef, useState, type ReactNode } from 'react' import type { ClaudeConfigSelector, DateRange } from '../lib/types' import { Dropdown } from './Dropdown' import { ProviderPop, type ProviderOption } from './ProviderPop' import { RangeCalendar } from './RangeCalendar' import { SegTabs, type SegOption } from './SegTabs' /** Sentinel option value: no --claude-config-source flag (aggregate all configs). */ const ALL_CONFIGS = '' /** The real CLI period vocabulary (`codeburn ... --period`, src/cli-date.ts). */ export const PERIOD_OPTIONS: SegOption[] = [ { value: 'today', label: 'Today' }, { value: 'week', label: '7D' }, { value: '30days', label: '30D' }, { value: 'month', label: 'Month' }, { value: 'all', label: '6M' }, { value: 'lifetime', label: 'Life' }, ] /** The `.bar` top bar: title, scope caption, period SegTabs, provider ProviderPop. */ export function TopBar({ title, scope, period, onPeriodChange, customRange, onRangeSelect, provider, providerLabel, providerOptions, onProviderSelect, claudeConfigs, configSource, onConfigSelect, }: { title: ReactNode scope?: ReactNode period: string onPeriodChange: (value: string) => void customRange: DateRange | null onRangeSelect: (range: DateRange) => void provider: string providerLabel: string providerOptions: ProviderOption[] onProviderSelect: (value: string) => void claudeConfigs?: ClaudeConfigSelector configSource: string | null onConfigSelect: (id: string) => void }) { return (
{title}
{scope !== undefined && {scope}}
{claudeConfigs && }
) } /** Claude config source switcher. Only getOverview honors the selection, so the * footer names the limit; the active label is also echoed in the scope line. */ function ConfigPicker({ configs, value, onSelect }: { configs: ClaudeConfigSelector; value: string | null; onSelect: (id: string) => void }) { const options = [ { value: ALL_CONFIGS, label: 'All Claude configs' }, ...configs.options.map(option => ({ value: option.id, label: option.label })), ] return ( ) } function formatRange(range: DateRange): string { const from = new Date(`${range.from}T12:00:00`) const to = new Date(`${range.to}T12:00:00`) const sameYear = from.getFullYear() === to.getFullYear() const sameMonth = sameYear && from.getMonth() === to.getMonth() const left = from.toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: sameYear ? undefined : 'numeric' }) const right = to.toLocaleDateString('en-US', { month: sameMonth ? undefined : 'short', day: 'numeric', year: sameYear ? undefined : 'numeric' }) return `${left} – ${right}` } export function rangeLabel(range: DateRange): string { return formatRange(range) } function CalendarPop({ value, onSelect }: { value: DateRange | null; onSelect: (range: DateRange) => void }) { const [open, setOpen] = useState(false) const wrapRef = useRef(null) useEffect(() => { if (!open) return const onPointerDown = (event: MouseEvent) => { if (!wrapRef.current?.contains(event.target as Node)) setOpen(false) } const onKeyDown = (event: KeyboardEvent) => { if (event.key === 'Escape') setOpen(false) } document.addEventListener('mousedown', onPointerDown) document.addEventListener('keydown', onKeyDown) return () => { document.removeEventListener('mousedown', onPointerDown) document.removeEventListener('keydown', onKeyDown) } }, [open]) const label = value ? formatRange(value) : 'Choose date range' return (
{open && (
{ onSelect(range) setOpen(false) }} />
)}
) }