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' }) }