diff --git a/PROJECTS/advanced/monitor-the-situation-dashboard/frontend/src/pages/dashboard/Dashboard.tsx b/PROJECTS/advanced/monitor-the-situation-dashboard/frontend/src/pages/dashboard/Dashboard.tsx index 6e76f1d2..d191ab81 100644 --- a/PROJECTS/advanced/monitor-the-situation-dashboard/frontend/src/pages/dashboard/Dashboard.tsx +++ b/PROJECTS/advanced/monitor-the-situation-dashboard/frontend/src/pages/dashboard/Dashboard.tsx @@ -6,6 +6,7 @@ import { BTCPanel } from '@/pages/panels/BTCPanel' import { CVEVelocityPanel } from '@/pages/panels/CVEVelocityPanel' import { DShieldPanel } from '@/pages/panels/DShieldPanel' import { ETHPanel } from '@/pages/panels/ETHPanel' +import { ISSPanel } from '@/pages/panels/ISSPanel' import { KEVPanel } from '@/pages/panels/KEVPanel' import { RansomwarePanel } from '@/pages/panels/RansomwarePanel' import { SpaceWeatherPanel } from '@/pages/panels/SpaceWeatherPanel' @@ -33,6 +34,7 @@ export function Dashboard(): React.ReactElement { +
diff --git a/PROJECTS/advanced/monitor-the-situation-dashboard/frontend/src/pages/panels/ISSPanel.module.scss b/PROJECTS/advanced/monitor-the-situation-dashboard/frontend/src/pages/panels/ISSPanel.module.scss new file mode 100644 index 00000000..afede6b4 --- /dev/null +++ b/PROJECTS/advanced/monitor-the-situation-dashboard/frontend/src/pages/panels/ISSPanel.module.scss @@ -0,0 +1,29 @@ +// ©AngelaMos | 2026 +// ISSPanel.module.scss + +.row { + display: grid; + grid-template-columns: 90px 1fr; + gap: 8px; + padding: 4px 8px; + align-items: center; + font-family: var(--font-mono); + font-size: var(--type-body); + font-variant-numeric: tabular-nums; +} + +.label { + font-family: var(--font-sans); + font-size: var(--type-label); + letter-spacing: var(--letter-spacing-label); + text-transform: uppercase; + color: var(--fg-3); +} + +.value { + color: var(--fg-1); +} + +.muted { + color: var(--fg-3); +} diff --git a/PROJECTS/advanced/monitor-the-situation-dashboard/frontend/src/pages/panels/ISSPanel.tsx b/PROJECTS/advanced/monitor-the-situation-dashboard/frontend/src/pages/panels/ISSPanel.tsx new file mode 100644 index 00000000..37d691df --- /dev/null +++ b/PROJECTS/advanced/monitor-the-situation-dashboard/frontend/src/pages/panels/ISSPanel.tsx @@ -0,0 +1,70 @@ +// ©AngelaMos | 2026 +// ISSPanel.tsx + +import { useSnapshot } from '@/api/snapshot' +import styles from './ISSPanel.module.scss' +import { Panel } from './Panel' + +const STALE_AFTER_MS = 30_000 +const COORDS_DECIMALS = 2 +const ALT_DECIMALS = 0 + +interface IssPositionData { + latitude: number + longitude: number + altitude: number + velocity: number + timestamp: number + fetched_at?: string +} + +export function ISSPanel(): React.ReactElement { + const { data } = useSnapshot() + const iss = data?.iss_position as IssPositionData | undefined + + const lastTickAt = iss?.fetched_at + ? new Date(iss.fetched_at).getTime() + : undefined + const isStale = + lastTickAt !== undefined + ? Date.now() - lastTickAt > STALE_AFTER_MS + : undefined + + return ( + +
+ Lat, Lon + + {iss + ? `${iss.latitude.toFixed(COORDS_DECIMALS)}°, ${iss.longitude.toFixed(COORDS_DECIMALS)}°` + : '—'} + +
+
+ Alt + + {iss ? `${iss.altitude.toFixed(ALT_DECIMALS)} km` : '—'} + +
+
+ Vel + + {iss ? `${Math.round(iss.velocity).toLocaleString()} km/h` : '—'} + +
+
+ Next Pass + +
+
+ ) +} + +ISSPanel.displayName = 'ISSPanel'