EarningsCall Transcripts & Calendar: Shows a company's earnings call transcripts and the daily earnings calendar from EarningsCall.biz in a single panel view.
| 1 | import { useCallback, type ReactElement } from 'react' |
| 2 | import { useBridge, useData, type PanelRef } from '@jaspers-ai/sdk' |
| 3 | import { Calendar } from './Calendar' |
| 4 | import { CallPage } from './Call' |
| 5 | import { readState, stored, type CallsState } from './calls' |
| 6 | import './styles.css' |
| 7 | |
| 8 | // Earnings calls in one panel: a company's call when the state names a ticker, the calendar of a day |
| 9 | // when it does not. One view rather than two, because a row of the calendar opens its call here and a |
| 10 | // view cannot place another. The state is read whole and written whole, so opening another company |
| 11 | // leaves no quarter of the last one behind. |
| 12 | |
| 13 | export function CallsView({ panel }: { panel: PanelRef }): ReactElement { |
| 14 | const bridge = useBridge() |
| 15 | const raw = useData(`workspaces/${panel.workspaceId}/panels/${panel.id}/state`) |
| 16 | const write = useCallback( |
| 17 | (next: CallsState) => void bridge.setState({ id: panel.id, workspaceId: panel.workspaceId }, [], stored(next)), |
| 18 | [bridge, panel.id, panel.workspaceId], |
| 19 | ) |
| 20 | // The state arrives a round trip after the frame mounts; nothing runs until it is here. |
| 21 | if (raw === undefined) { |
| 22 | return ( |
| 23 | <div className="ec-root"> |
| 24 | <div className="ec-bar"> |
| 25 | <span className="ec-muted">Loading…</span> |
| 26 | </div> |
| 27 | </div> |
| 28 | ) |
| 29 | } |
| 30 | const state = readState(raw) |
| 31 | return state.symbol ? <CallPage panel={panel} state={state} write={write} /> : <Calendar panel={panel} state={state} write={write} /> |
| 32 | } |