From a837be68021a65b1498e07f9495d38fc38052355 Mon Sep 17 00:00:00 2001 From: accius Date: Mon, 2 Feb 2026 16:26:52 -0500 Subject: [PATCH] updated squished contests --- src/App.jsx | 20 ++-- src/components/ContestPanel.jsx | 175 ++++++++++++++++++++++++++------ 2 files changed, 156 insertions(+), 39 deletions(-) diff --git a/src/App.jsx b/src/App.jsx index 0fa88c0..0c52d4e 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -626,8 +626,8 @@ const App = () => { {/* RIGHT SIDEBAR */}
- {/* DX Cluster - primary panel */} -
+ {/* DX Cluster */} +
{
{/* PSKReporter - digital mode spots */} -
+
{ />
+ {/* Contests - bigger with live indicators */} +
+ +
+ {/* DXpeditions */} -
+
{/* POTA */} -
+
{ onToggleMap={togglePOTA} />
- - {/* Contests */} -
- -
)} diff --git a/src/components/ContestPanel.jsx b/src/components/ContestPanel.jsx index 3991a7d..1aa7714 100644 --- a/src/components/ContestPanel.jsx +++ b/src/components/ContestPanel.jsx @@ -1,6 +1,6 @@ /** * ContestPanel Component - * Displays upcoming contests with contestcalendar.com credit + * Displays upcoming and active contests with live indicators */ import React from 'react'; @@ -22,13 +22,100 @@ export const ContestPanel = ({ data, loading }) => { return date.toLocaleDateString('en-US', { month: 'short', day: 'numeric' }); }; + const formatTime = (dateStr) => { + if (!dateStr) return ''; + const date = new Date(dateStr); + return date.toLocaleTimeString('en-US', { hour: '2-digit', minute: '2-digit', hour12: false }) + 'z'; + }; + + // Check if contest is live (happening now) + const isContestLive = (contest) => { + if (!contest.start || !contest.end) return false; + const now = new Date(); + const start = new Date(contest.start); + const end = new Date(contest.end); + return now >= start && now <= end; + }; + + // Check if contest starts within 24 hours + const isStartingSoon = (contest) => { + if (!contest.start) return false; + const now = new Date(); + const start = new Date(contest.start); + const hoursUntil = (start - now) / (1000 * 60 * 60); + return hoursUntil > 0 && hoursUntil <= 24; + }; + + // Get time remaining or time until start + const getTimeInfo = (contest) => { + if (!contest.start || !contest.end) return formatDate(contest.start); + + const now = new Date(); + const start = new Date(contest.start); + const end = new Date(contest.end); + + if (now >= start && now <= end) { + // Contest is live - show time remaining + const hoursLeft = Math.floor((end - now) / (1000 * 60 * 60)); + const minsLeft = Math.floor(((end - now) % (1000 * 60 * 60)) / (1000 * 60)); + if (hoursLeft > 0) { + return `${hoursLeft}h ${minsLeft}m left`; + } + return `${minsLeft}m left`; + } else if (now < start) { + // Contest hasn't started + const hoursUntil = Math.floor((start - now) / (1000 * 60 * 60)); + if (hoursUntil < 24) { + return `Starts in ${hoursUntil}h`; + } + return formatDate(contest.start); + } + return formatDate(contest.start); + }; + + // Sort contests: live first, then starting soon, then by date + const sortedContests = data ? [...data].sort((a, b) => { + const aLive = isContestLive(a); + const bLive = isContestLive(b); + const aSoon = isStartingSoon(a); + const bSoon = isStartingSoon(b); + + if (aLive && !bLive) return -1; + if (!aLive && bLive) return 1; + if (aSoon && !bSoon) return -1; + if (!aSoon && bSoon) return 1; + + return new Date(a.start) - new Date(b.start); + }) : []; + + // Count live contests + const liveCount = sortedContests.filter(isContestLive).length; + return (
-
- 🏆 CONTESTS + 🏆 CONTESTS + {liveCount > 0 && ( + + 🔴 {liveCount} LIVE + + )}
@@ -36,31 +123,61 @@ export const ContestPanel = ({ data, loading }) => {
- ) : data && data.length > 0 ? ( + ) : sortedContests.length > 0 ? (
- {data.slice(0, 6).map((contest, i) => ( -
-
- {contest.name} -
-
- {contest.mode} - {formatDate(contest.start)} + {sortedContests.slice(0, 8).map((contest, i) => { + const live = isContestLive(contest); + const soon = isStartingSoon(contest); + + return ( +
+
+ {live && ( + + )} + {soon && !live && ( + + )} + + {contest.name} + +
+
+ {contest.mode} + + {getTimeInfo(contest)} + +
-
- ))} + ); + })}
) : (
@@ -71,8 +188,8 @@ export const ContestPanel = ({ data, loading }) => { {/* Contest Calendar Credit */}