From 1f43a7c29e3b4799bd59566b9bec2ecd10121891 Mon Sep 17 00:00:00 2001 From: GeorgeWebberley Date: Wed, 28 Jan 2026 20:39:18 +0100 Subject: [PATCH] Added next rocket data --- Dockerfile | 3 + app/page.tsx | 22 +++++-- components/EventCard.tsx | 16 +++-- components/MissionControl.tsx | 29 +++++----- config/events.json | 67 +++++++++++++++++++++ scripts/update-space.ts | 106 +++++++++++++++++++++++++--------- types/space.ts | 10 +++- 7 files changed, 199 insertions(+), 54 deletions(-) create mode 100644 config/events.json diff --git a/Dockerfile b/Dockerfile index 99c74b8..3a2866a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -12,6 +12,9 @@ COPY --from=builder /app/public ./public COPY --from=builder /app/.next/standalone ./ COPY --from=builder /app/.next/static ./.next/static COPY --from=builder /app/lib ./lib +COPY --from=builder /app/config ./config + +RUN mkdir -p /app/data EXPOSE 3000 CMD ["node", "server.js"] \ No newline at end of file diff --git a/app/page.tsx b/app/page.tsx index 6bf2a80..c31ae9d 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -2,7 +2,6 @@ import MissionControl from '@/components/MissionControl'; import db from '@/lib/db'; export default function Home() { - // SQLite handles the 'now' comparison perfectly const issRow = db.prepare(` SELECT pass_time, end_time FROM iss_passes @@ -10,26 +9,41 @@ export default function Home() { ORDER BY datetime(pass_time) ASC LIMIT 1 `).get() as { pass_time: string, end_time: string } | undefined; - // 2. Fetch Moon const moonRow = db.prepare(` SELECT title, event_time FROM global_events WHERE id = 'moon_phase' `).get() as { title: string, event_time: string } | undefined; - // Prepare Dates + const cosmicRow = db.prepare(` + SELECT title, event_time + FROM global_events + WHERE id = 'next_cosmic_event' + `).get() as { title: string, event_time: string } | undefined; + + const launchRow = db.prepare( + "SELECT title, event_time FROM global_events WHERE id = 'next_launch'" + ).get() as { title: string, event_time: string } | undefined; + + const launchStart = launchRow ? new Date(launchRow.event_time) : null; + const launchEnd = launchStart ? new Date(launchStart.getTime() + 7200000) : null; + const issStart = issRow ? new Date(issRow.pass_time) : null; const issEnd = issRow ? new Date(issRow.end_time) : null; const moonStart = moonRow ? new Date(moonRow.event_time) : null; - // Moon "Event" lasts 24 hours const moonEnd = moonStart ? new Date(moonStart.getTime() + 86400000) : null; + const cosmicStart = cosmicRow ? new Date(cosmicRow.event_time) : null; + const cosmicEnd = cosmicStart ? new Date(cosmicStart.getTime() + 14400000) : null; + return (
); diff --git a/components/EventCard.tsx b/components/EventCard.tsx index bec5998..7070051 100644 --- a/components/EventCard.tsx +++ b/components/EventCard.tsx @@ -112,20 +112,17 @@ export default function EventCard({ id, title, targetDate, endDate, icon }: Even
{parseInt(timeLeft.d) >= 2 ? ( - /* Case 1: More than 2 days - Keep it super simple */ <> {timeLeft.d} Days ) : parseInt(timeLeft.d) === 1 ? ( - /* Case 2: Between 24 and 48 hours - Show Day + Hours */ <> 01d : {timeLeft.h}h ) : ( - /* Case 3: Under 24 hours - The full high-precision clock */ <> {timeLeft.h} : @@ -135,9 +132,18 @@ export default function EventCard({ id, title, targetDate, endDate, icon }: Even )}
-

- {parseInt(timeLeft.d) > 0 ? "Until event" : "T-Minus to Horizon"} + {isLive ? ( + "Mission in Progress" + ) : id === 'iss' ? ( + "T-Minus to Horizon" + ) : id === 'launch' ? ( + "T-Minus to Ignition" + ) : id === 'moon' ? ( + "Until Lunar Phase" + ) : ( + "Days to Peak Phase" + )}

)} diff --git a/components/MissionControl.tsx b/components/MissionControl.tsx index a27d312..2655646 100644 --- a/components/MissionControl.tsx +++ b/components/MissionControl.tsx @@ -12,10 +12,7 @@ const Starfield = dynamic(() => import('@/components/Starfield'), { }); -export default function MissionControl({ iss, moon }: MissionControlProps) { - - const BASE_TIME = 1769610273000; - +export default function MissionControl({ iss, moon, cosmic, launch }: MissionControlProps) { const events = useMemo(() => [ { id: 'iss', @@ -32,20 +29,20 @@ export default function MissionControl({ iss, moon }: MissionControlProps) { icon: , }, { - id: 'starlink', - title: "Starlink Train", - date: new Date(BASE_TIME + 1000 * 60 * 45), - endDate: new Date(BASE_TIME + 1000 * 60 * 55), - icon: , + id: 'cosmic', + title: cosmic.title, + date: cosmic.start, + endDate: cosmic.end, + icon: , }, { - id: 'meteor', - title: "Meteor Shower", - date: new Date(BASE_TIME + 1000 * 60 * 60 * 24 * 10), - endDate: new Date(BASE_TIME + 1000 * 60 * 60 * 24 * 10.1), - icon: , + id: 'launch', + title: launch.title, + date: launch.start, + endDate: launch.end, + icon: , } - ], [iss, moon]); + ], [iss, moon, cosmic, launch]); return (
@@ -63,7 +60,7 @@ export default function MissionControl({ iss, moon }: MissionControlProps) {
{events.map((event) => ( 0) { - targetDate = new Date(now.getTime() + daysToFullMoon * 86400000); - title = "Next Full Moon"; - } else { - targetDate = new Date(now.getTime() + daysToNewMoon * 86400000); - title = "Next New Moon"; + const moon = daysToFull > 0 + ? { title: "Next Full Moon", date: new Date(now.getTime() + daysToFull * 86400000) } + : { title: "Next New Moon", date: new Date(now.getTime() + daysToNew * 86400000) }; + + db.prepare(` + INSERT INTO global_events (id, title, event_time) VALUES ('moon_phase', ?, ?) + ON CONFLICT(id) DO UPDATE SET title=excluded.title, event_time=excluded.event_time + `).run(moon.title, moon.date.toISOString()); + + console.log(`🌙 Moon: ${moon.title}`); +} + +function updateCosmicEvents() { + const configPath = path.resolve(process.cwd(), 'config/events.json'); + if (!fs.existsSync(configPath)) return; + + const events: CosmicEvent[] = JSON.parse(fs.readFileSync(configPath, 'utf-8')); + const now = new Date(); + + const next = events + .filter((e) => new Date(e.event_time) > now) + .sort((a, b) => new Date(a.event_time).getTime() - new Date(b.event_time).getTime())[0]; + + if (next) { + db.prepare(` + INSERT INTO global_events (id, title, event_time) VALUES ('next_cosmic_event', ?, ?) + ON CONFLICT(id) DO UPDATE SET title=excluded.title, event_time=excluded.event_time + `).run(next.title, next.event_time); + console.log(`✨ Cosmic: ${next.title}`); } +} - return { title, targetDate }; +async function updateRocketLaunches() { + try { + const nowISO = new Date().toISOString(); + const url = `https://lldev.thespacedevs.com/2.2.0/launch/upcoming/?limit=1&mode=list&net__gt=${nowISO}`; + + const response = await fetch(url); + const data = await response.json(); + + if (data.results && data.results.length > 0) { + const launch = data.results[0]; + + db.prepare(` + INSERT INTO global_events (id, title, event_time) + VALUES ('next_launch', ?, ?) + ON CONFLICT(id) DO UPDATE SET title=excluded.title, event_time=excluded.event_time + `).run( + `Launch: ${launch.name}`, + launch.net + ); + + console.log(`🚀 Rocket Sync: ${launch.name}`); + } + } catch (error) { + console.error("❌ Rocket Fetch Error:", error); + } } async function updateAllData() { - await updateISSData(); + console.log("📡 Starting Ground Station sync..."); - const moon = getNextMoonPhase(); - const upsertMoon = db.prepare(` - INSERT INTO global_events (id, title, event_time) - VALUES ('moon_phase', ?, ?) - ON CONFLICT(id) DO UPDATE SET title=excluded.title, event_time=excluded.event_time - `); - upsertMoon.run(moon.title, moon.targetDate.toISOString()); - - console.log(`🌙 Updated Moon Phase: ${moon.title}`); + try { + await updateISSData(); + updateMoonPhase(); + updateCosmicEvents(); + await updateRocketLaunches(); + + console.log("✅ All systems synchronized."); + } catch (error) { + console.error("❌ Sync failed:", error); + } } updateAllData().catch(console.error); diff --git a/types/space.ts b/types/space.ts index 38b2d20..994b88d 100644 --- a/types/space.ts +++ b/types/space.ts @@ -32,4 +32,12 @@ export interface EventCardProps { export interface MissionControlProps { iss: { start: Date | null; end: Date | null }; moon: { title: string; start: Date | null; end: Date | null }; -} \ No newline at end of file + cosmic: { title: string; start: Date | null; end: Date | null }; + launch: { title: string; start: Date | null; end: Date | null }; +} + +export interface CosmicEvent { + id: string; + title: string; + event_time: string; +}