From 29e8ac69099e9a3d3ddd6543d29a3861f66846aa Mon Sep 17 00:00:00 2001 From: Kamil Krzywda Date: Tue, 29 Sep 2026 02:45:38 +0000 Subject: [PATCH] feat(ui): EVENT LOG tab renders the real game log MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Self-fetching EventLogPanel (MissionPanel pattern — refetches on each tab open). One terminal line per event: T // , 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. --- components/event-log.tsx | 59 ++++++++++++++++++++++++++++++++++ components/mission-control.tsx | 27 +++------------- 2 files changed, 63 insertions(+), 23 deletions(-) create mode 100644 components/event-log.tsx diff --git a/components/event-log.tsx b/components/event-log.tsx new file mode 100644 index 0000000..17d35a7 --- /dev/null +++ b/components/event-log.tsx @@ -0,0 +1,59 @@ +'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 // , newest first. + +export function EventLogPanel() { + const [lines, setLines] = useState(null) + const [error, setError] = useState(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 ( +
+ {error.toUpperCase()} +
+ ) + } + + if (!lines) { + return ( +
+ LOADING EVENT LOG… +
+ ) + } + + return ( + + ) +} diff --git a/components/mission-control.tsx b/components/mission-control.tsx index db87c58..957a8fc 100644 --- a/components/mission-control.tsx +++ b/components/mission-control.tsx @@ -7,8 +7,8 @@ import { Progress } from '@/components/ui/progress' import { StatCard } from '@/components/ui/stat-card' import { StatusGrid, type SystemEntry } from '@/components/ui/status-grid' import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs' -import { Terminal, type TerminalLine } from '@/components/ui/terminal' import { CrewPanel } from '@/components/crew-panel' +import { EventLogPanel } from '@/components/event-log' import { LocalSystemPanel } from '@/components/local-system' import { MissionPanel } from '@/components/missions' import { ShipSystemsPanel } from '@/components/ship-systems' @@ -21,9 +21,8 @@ import type { TechDto } from '@/lib/game/tech' // Interface base: layout + visual treatment rebuilt from the scificn-ui Mission Control // showcase (src/app/_pages/showcase/mission-control-content.tsx in baxy5/scificn-ui). The -// WORLD MAP, LOCAL SYSTEM, CREW, SHIP SYSTEMS, SKILL TREE and MISSIONS tabs render live data -// (/api/world, /api/system, /api/crew, /api/ship, /api/tech, /api/missions); the EVENT LOG tab -// keeps placeholder content until its own issue lands. Single player, no auth, by design. +// All seven tabs render live data (/api/world, /api/system, /api/crew, /api/ship, /api/tech, +// /api/missions, /api/events). Single player, no auth, by design. function useNarrow(threshold = 900): boolean { const [narrow, setNarrow] = useState( @@ -37,10 +36,6 @@ function useNarrow(threshold = 900): boolean { return narrow } -function now(): string { - return new Date().toLocaleTimeString('en-GB', { hour12: false }) -} - // ── Placeholder content (no game logic — real values land with the turn engine) ── const encounters = [ @@ -59,15 +54,6 @@ const shipData = [ { label: 'TURN', value: '12' }, ] -const logLines: TerminalLine[] = [ - { type: 'system', text: 'SPACEWANDERER // INITIALIZING SHIP SYSTEMS...', timestamp: now() }, - { type: 'output', text: 'HULL SCAN COMPLETE — INTEGRITY 87%', timestamp: now() }, - { type: 'output', text: 'REACTOR OUTPUT STABLE AT 94.2%', timestamp: now() }, - { type: 'output', text: 'CREW MANIFEST LOADED — 3 ACTIVE PERSONNEL', timestamp: now() }, - { type: 'warn', text: 'WEAPONS OFFLINE — MODULE NOT INSTALLED', timestamp: now() }, - { type: 'system', text: 'ALL SYSTEMS NOMINAL. AWAITING FIRST TURN.', timestamp: now() }, -] - export function MissionControl() { const narrow = useNarrow() const [tick, setTick] = useState(0) @@ -393,12 +379,7 @@ export function MissionControl() { {/* EVENT LOG TAB */} - +