import { useEffect, useState, type ReactElement } from 'react'
import { usePublish, usePublishText, type PanelRef } from '@jaspers-ai/sdk'
// What the calendar and the call share: the ticker field, the way a failure reads, a publish from a
// branch that has nothing else to render, and dates written for people.
/**
* Enter opens the ticker typed; a ticker the orchestrator sets shows here. Enter is read off the key,
* not a form: the view's frame is sandboxed without allow-forms, so a form never submits.
*/
export function TickerField({ symbol, onSymbol }: { symbol: string; onSymbol: (symbol: string) => void }): ReactElement {
const [draft, setDraft] = useState(symbol)
useEffect(() => setDraft(symbol), [symbol])
return (
setDraft(event.target.value)}
onKeyDown={(event) => {
if (event.key !== 'Enter' || event.nativeEvent.isComposing) return
event.preventDefault()
const next = draft.trim().toUpperCase()
if (next) onSymbol(next)
}}
/>
)
}
/** What a branch shows, published: its output, and its text, which only a transcript has. */
export function Publish({ panel, output, text }: { panel: PanelRef; output: Record; text: string | null }): null {
usePublish(panel, output)
usePublishText(panel, text)
return null
}
/** The message as the server wrote it, without the wrapping the IPC adds. */
export function cleanError(message: string): string {
return message.replace(/^Error invoking remote method '[^']*': (?:Error: )?/, '')
}
/** 'Wed, Jul 29, 2026' for a day or for the day part of a timestamp. */
export function longDate(value: string | null): string {
const match = value ? /^(\d{4})-(\d{2})-(\d{2})/.exec(value) : null
if (!match) return ''
const day = new Date(Date.UTC(Number(match[1]), Number(match[2]) - 1, Number(match[3])))
return day.toLocaleDateString('en-US', { weekday: 'short', month: 'short', day: 'numeric', year: 'numeric', timeZone: 'UTC' })
}
/** A call's start in the viewer's own zone, like '5:30 PM'. */
export function localTime(value: string | null): string {
const time = value ? Date.parse(value) : NaN
return Number.isNaN(time) ? '—' : new Date(time).toLocaleTimeString('en-US', { hour: 'numeric', minute: '2-digit' })
}