Self-fetching EventLogPanel (MissionPanel pattern — refetches on each tab open). One terminal line per event: T<turn> // <MESSAGE>, newest first, with the event's local time as the timestamp; new_game lines render as system lines. Placeholder feed + now() removed from mission-control.
60 lines
2.0 KiB
TypeScript
60 lines
2.0 KiB
TypeScript
'use client'
|
|
|
|
import { useEffect, useState } from 'react'
|
|
import { Terminal, type TerminalLine } from '@/components/ui/terminal'
|
|
import type { EventDto } from '@/lib/game/events'
|
|
|
|
// EVENT LOG tab — live data. Fetches /api/events on mount (Radix Tabs unmounts inactive tabs, so it
|
|
// refetches whenever the tab is opened). One terminal line per event: T<turn> // <MESSAGE>, newest first.
|
|
|
|
export function EventLogPanel() {
|
|
const [lines, setLines] = useState<TerminalLine[] | null>(null)
|
|
const [error, setError] = useState<string | null>(null)
|
|
|
|
useEffect(() => {
|
|
let cancelled = false
|
|
fetch('/api/events')
|
|
.then(async (res) => {
|
|
if (!res.ok) throw new Error(`HTTP ${res.status}`)
|
|
return (await res.json()) as EventDto[]
|
|
})
|
|
.then((events) => {
|
|
if (!cancelled) {
|
|
setLines(
|
|
events.map((e) => ({
|
|
type: e.type === 'new_game' ? 'system' : 'output',
|
|
text: `T${e.turn} // ${e.message.toUpperCase()}`,
|
|
timestamp: new Date(e.createdAt).toLocaleTimeString('en-GB', { hour12: false }),
|
|
}))
|
|
)
|
|
}
|
|
})
|
|
.catch((err: unknown) => {
|
|
if (!cancelled) setError(err instanceof Error ? err.message : String(err))
|
|
})
|
|
return () => {
|
|
cancelled = true
|
|
}
|
|
}, [])
|
|
|
|
if (error) {
|
|
return (
|
|
<div style={{ border: '1px solid var(--border)', background: 'var(--surface)', padding: '0.75rem' }}>
|
|
<span style={{ fontSize: '0.62rem', color: 'var(--color-red)', letterSpacing: '0.08em' }}>{error.toUpperCase()}</span>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
if (!lines) {
|
|
return (
|
|
<div style={{ border: '1px solid var(--border)', background: 'var(--surface)', padding: '0.75rem' }}>
|
|
<span style={{ fontSize: '0.62rem', color: 'var(--text-muted)', letterSpacing: '0.12em' }}>LOADING EVENT LOG…</span>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
return (
|
|
<Terminal lines={lines} title="SHIP LOG" height="22rem" style={{ width: '100%' }} />
|
|
)
|
|
}
|