Wave 2B: Offseason never-dark hub — NewsWire + FuturesBoard on /explore
Extend /explore (ExploreHub) into the 365-day never-dark hub. Two new self-hiding sections feed REAL always-available data into the offseason: - NewsWire (components/vyndr/NewsWire.tsx): real ESPN headlines from /api/news/:sport (newest-first, mono timestamps, type chips, player/team links) + real injuries from /api/schedule/:sport/injuries (OUT/GTD chips, token colors). Reuses the retired TerminalTemplates INJURY_WIRE layout but never routes its sample constants. Self-hides when both feeds are empty. - FuturesBoard (components/vyndr/FuturesBoard.tsx): real futures from /api/futures/:sport — championship/win-total/award markets, mono tabular prices + movement colored by the contract (shortening=green / drifting=amber / flat=dim, NEVER red; move shown ONLY when the backend supplies one). Carries the honest "TRACKED · NOT GRADED" label — no fabricated grades on futures. Self-hides when markets:[]. - ExploreHub is offseason-aware (via emptyState OFF_SEASON month check): the hub LEADS with futures + wire when the board is dark, COMPLEMENTS the live board in-season. Sport selector kept; each section self-hides independently. - Testable pure helpers: lib/futuresMove.js (move→color, never red) + lib/newsFormat.js (timeAgo mono-stamp, ESPN type labels). Contracts consumed (Wave 2A owns the proxy/service files); code self-hides on fetch failure if a proxy isn't present yet. Tests: tests/unit/newsWire.test.js + futuresBoard.test.js (26 new). Full suite 259 suites / 3144 green; web build exit 0. vyndrParityQA stays green (mono data, no glitch on data surfaces). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -13,8 +13,11 @@ import { playerHref } from '@/lib/playerHref';
|
||||
*/
|
||||
import StreaksPanel from '@/components/StreaksPanel';
|
||||
import HotListPanel from '@/components/HotListPanel';
|
||||
import NewsWire from '@/components/vyndr/NewsWire';
|
||||
import FuturesBoard from '@/components/vyndr/FuturesBoard';
|
||||
import { useAuth } from '@/contexts/AuthContext';
|
||||
import { nextRunLabelET } from '@/lib/pipelineSchedule';
|
||||
import { OFF_SEASON } from '@/lib/emptyState';
|
||||
|
||||
interface Leader {
|
||||
player: string;
|
||||
@@ -54,6 +57,21 @@ export default function ExploreHub() {
|
||||
return q ? leaders.filter((l) => (l.player || '').toLowerCase().includes(q)) : leaders;
|
||||
}, [leaders, query]);
|
||||
|
||||
// Wave 2B — never-dark hub. When the selected sport is in its OFF-SEASON, the
|
||||
// hub LEADS with futures + the wire (real, always-available data) instead of
|
||||
// a dark leaderboard; in-season those sections COMPLEMENT the live board
|
||||
// below. Each self-hides independently on an empty feed — no empty boxes.
|
||||
const off = OFF_SEASON[sport as keyof typeof OFF_SEASON];
|
||||
const isOffseason = !!(off && off.months.includes(new Date().getMonth()));
|
||||
|
||||
// Both sections self-hide (return null) when their feeds are empty.
|
||||
const hubSections = (
|
||||
<>
|
||||
<FuturesBoard sport={sport} />
|
||||
<NewsWire sport={sport} />
|
||||
</>
|
||||
);
|
||||
|
||||
return (
|
||||
<section style={{ maxWidth: 920, margin: '0 auto', padding: '24px 16px 120px' }}>
|
||||
<div style={{ display: 'flex', alignItems: 'flex-end', justifyContent: 'space-between', gap: 14, marginBottom: 22, flexWrap: 'wrap' }}>
|
||||
@@ -78,6 +96,9 @@ export default function ExploreHub() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* OFF-SEASON LEAD — futures + wire come FIRST when the board is dark. */}
|
||||
{isOffseason && hubSections}
|
||||
|
||||
{/* FILTER BAR */}
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: 11, flexWrap: 'wrap', marginBottom: 14, background: 'var(--bg-1)', border: '1px solid var(--border)', borderRadius: 11, padding: '11px 14px' }}>
|
||||
<span className="mono" style={{ fontSize: 14, color: 'var(--text-2)' }}>⌕</span>
|
||||
@@ -135,6 +156,9 @@ export default function ExploreHub() {
|
||||
<StreaksPanel sport={sport} tier={tier} stat="all" />
|
||||
<HotListPanel sport={sport} tier={tier} stat="all" />
|
||||
</div>
|
||||
|
||||
{/* IN-SEASON — futures + wire COMPLEMENT the live board below it. */}
|
||||
{!isOffseason && hubSections}
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user