import { useEffect, useMemo, useRef, useState } from 'react' import Tree from '../Tree/Tree' import FallingLeaves from '../Tree/FallingLeaves' const numberFormat = new Intl.NumberFormat('en-GB') const dateFormat = new Intl.DateTimeFormat('en-GB', { dateStyle: 'medium', timeStyle: 'short', }) const apiEndpoints = { health: '/health', teams: '/api/tss/leaderboard/teams?limit=100', teamsHealth: '/api/tss/leaderboard/teams?limit=1', resolve: (name) => `/api/tss/teams/resolve?name=${encodeURIComponent(name)}`, detail: (name) => `/api/tss/teams/${encodeURIComponent(name)}`, history: (name) => `/api/tss/teams/${encodeURIComponent(name)}/history`, games: (name) => `/api/tss/teams/${encodeURIComponent(name)}/games`, } const navItems = [ { path: '/', label: 'Home' }, { path: '/teams', label: 'Team leaderboard' }, { path: '/battle-logs', label: 'Battle Logs' }, ] async function fetchJson(path, signal) { const response = await fetch(path, { signal, headers: { Accept: 'application/json' }, }) const body = await response.json().catch(() => null) if (!response.ok) { throw new Error(body?.error || `Request failed with ${response.status}`) } return body } function parseRoute(pathname = window.location.pathname) { if (pathname === '/') return { page: 'home', teamName: '' } if (pathname === '/teams') return { page: 'teams', teamName: '' } if (pathname === '/uptime') return { page: 'uptime', teamName: '' } if (pathname.startsWith('/teams/')) { const teamName = decodeURIComponent(pathname.slice('/teams/'.length)) return { page: 'team', teamName } } if (pathname === '/battle-logs' || pathname === '/live') return { page: 'battle-logs', teamName: '' } return { page: 'home', teamName: '' } } function teamPath(name) { return `/teams/${encodeURIComponent(name)}` } function formatNumber(value) { return numberFormat.format(Number(value || 0)) } function formatDate(timestamp) { if (!timestamp) return 'Unknown time' return dateFormat.format(new Date(Number(timestamp) * 1000)) } function bestTeamName(team) { return team?.tag_name || team?.short_name || team?.long_name || '' } async function fetchRecentTssGames(teams, signal) { const teamNames = teams.map(bestTeamName).filter(Boolean).slice(0, 12) if (!teamNames.length) { return { matches: [] } } const responses = await Promise.allSettled( teamNames.map((name) => fetchJson(apiEndpoints.games(name), signal).then((data) => ({ name, data }))), ) const bySession = new Map() responses.forEach((result) => { if (result.status !== 'fulfilled') return const { name, data } = result.value ;(data.games || []).forEach((game) => { if (!game.session_id) return const existing = bySession.get(game.session_id) const currentTimestamp = Number(game.timestamp || 0) if (existing && Number(existing.timestamp || 0) >= currentTimestamp) return bySession.set(game.session_id, { ...game, team_name: data.tag_name || name, long_name: data.long_name || '', }) }) }) return { matches: Array.from(bySession.values()) .sort((a, b) => Number(b.timestamp || 0) - Number(a.timestamp || 0)) .slice(0, 50), } } function Stat({ label, value }) { return (

{label}

{value}

) } function App() { const [route, setRoute] = useState(() => parseRoute()) const [leaderboard, setLeaderboard] = useState({ status: 'idle', data: null, error: null }) const [live, setLive] = useState({ status: 'idle', data: null, error: null }) const [uptime, setUptime] = useState({ status: 'idle', checks: [], history: [], updatedAt: null }) const [teamQuery, setTeamQuery] = useState('') const [searchHint, setSearchHint] = useState({ status: 'idle', name: '' }) const [profile, setProfile] = useState({ teamName: '', detail: { status: 'idle', data: null, error: null }, history: { status: 'idle', data: null, error: null }, games: { status: 'idle', data: null, error: null }, }) const teams = useMemo( () => leaderboard.data?.teams || leaderboard.data?.squadrons || [], [leaderboard.data], ) const matches = live.data?.matches || [] function navigate(path) { window.history.pushState({}, '', path) setRoute(parseRoute(path)) } useEffect(() => { const onPopState = () => setRoute(parseRoute()) window.addEventListener('popstate', onPopState) return () => window.removeEventListener('popstate', onPopState) }, []) useEffect(() => { const title = route.page === 'team' && route.teamName ? `${route.teamName} | Toothless' TSS Bot` : route.page === 'teams' ? "Team leaderboard | Toothless' TSS Bot" : route.page === 'battle-logs' ? "Battle Logs | Toothless' TSS Bot" : route.page === 'uptime' ? "Uptime | Toothless' TSS Bot" : "Toothless' TSS Bot" document.title = title }, [route.page, route.teamName]) useEffect(() => { const onKeyDown = (event) => { if (event.key === 'Escape') { navigate('/') } } window.addEventListener('keydown', onKeyDown) return () => window.removeEventListener('keydown', onKeyDown) }, []) useEffect(() => { const query = teamQuery.trim() if (query.length < 2) { setSearchHint({ status: 'idle', name: '' }) return } const controller = new AbortController() const timer = window.setTimeout(() => { setSearchHint({ status: 'loading', name: '' }) fetchJson(apiEndpoints.resolve(query), controller.signal) .then((data) => { const name = data.tag_name || data.short_name || data.long_name || query setSearchHint({ status: 'ready', name }) }) .catch(() => { if (!controller.signal.aborted) { setSearchHint({ status: 'error', name: '' }) } }) }, 350) return () => { window.clearTimeout(timer) controller.abort() } }, [teamQuery]) useEffect(() => { if (!['home', 'teams', 'team', 'battle-logs'].includes(route.page)) return if (leaderboard.status === 'ready' || leaderboard.status === 'loading') return const controller = new AbortController() setLeaderboard({ status: 'loading', data: null, error: null }) fetchJson(apiEndpoints.teams, controller.signal) .then((data) => setLeaderboard({ status: 'ready', data, error: null })) .catch((error) => { if (!controller.signal.aborted) { setLeaderboard({ status: 'error', data: null, error: error.message }) } }) return () => controller.abort() }, [leaderboard.status, route.page]) useEffect(() => { if (!['home', 'teams', 'team', 'battle-logs'].includes(route.page)) return const controller = new AbortController() const timer = window.setInterval(() => { fetchJson(apiEndpoints.teams, controller.signal) .then((data) => setLeaderboard({ status: 'ready', data, error: null })) .catch((error) => { if (!controller.signal.aborted) { setLeaderboard((current) => ({ ...current, error: error.message })) } }) }, 60000) return () => { window.clearInterval(timer) controller.abort() } }, [route.page]) useEffect(() => { if (!['home', 'battle-logs'].includes(route.page)) return if (!teams.length) return const controller = new AbortController() setLive((current) => current.status === 'ready' ? current : { status: 'loading', data: null, error: null }, ) fetchRecentTssGames(teams, controller.signal) .then((data) => setLive({ status: 'ready', data, error: null })) .catch((error) => { if (!controller.signal.aborted) { setLive({ status: 'error', data: null, error: error.message }) } }) return () => controller.abort() }, [route.page, teams]) useEffect(() => { if (!['home', 'battle-logs'].includes(route.page)) return if (!teams.length) return const controller = new AbortController() const timer = window.setInterval(() => { fetchRecentTssGames(teams, controller.signal) .then((data) => setLive({ status: 'ready', data, error: null })) .catch((error) => { if (!controller.signal.aborted) { setLive((current) => ({ ...current, error: error.message })) } }) }, 15000) return () => { window.clearInterval(timer) controller.abort() } }, [route.page, teams]) useEffect(() => { if (route.page !== 'team' || !route.teamName) return const controller = new AbortController() setProfile({ teamName: route.teamName, detail: { status: 'loading', data: null, error: null }, history: { status: 'loading', data: null, error: null }, games: { status: 'loading', data: null, error: null }, }) Promise.allSettled([ fetchJson(apiEndpoints.detail(route.teamName), controller.signal), fetchJson(apiEndpoints.history(route.teamName), controller.signal), fetchJson(apiEndpoints.games(route.teamName), controller.signal), ]).then(([detailResult, historyResult, gamesResult]) => { if (controller.signal.aborted) return setProfile({ teamName: route.teamName, detail: detailResult.status === 'fulfilled' ? { status: 'ready', data: detailResult.value, error: null } : { status: 'error', data: null, error: detailResult.reason.message }, history: historyResult.status === 'fulfilled' ? { status: 'ready', data: historyResult.value, error: null } : { status: 'error', data: null, error: historyResult.reason.message }, games: gamesResult.status === 'fulfilled' ? { status: 'ready', data: gamesResult.value, error: null } : { status: 'error', data: null, error: gamesResult.reason.message }, }) }) return () => controller.abort() }, [route.page, route.teamName]) useEffect(() => { if (route.page !== 'uptime') return const controller = new AbortController() async function checkUptime() { setUptime((current) => ({ status: current.status === 'ready' ? 'refreshing' : 'loading', checks: current.checks, history: current.history, updatedAt: current.updatedAt, })) const startedAt = performance.now() const healthResult = await fetchJson(apiEndpoints.health, controller.signal) .then(() => ({ ok: true, label: 'Operational' })) .catch((error) => ({ ok: false, label: error.message })) const apiResult = await fetchJson(apiEndpoints.teamsHealth, controller.signal) .then((data) => { const teamCount = data.teams?.length || data.squadrons?.length || 0 return { ok: true, label: `${teamCount} sample team${teamCount === 1 ? '' : 's'} returned` } }) .catch((error) => ({ ok: false, label: error.message })) if (controller.signal.aborted) return setUptime((current) => { const checks = [ { name: 'Website', detail: 'App shell and static assets', ok: true, label: 'Online', latency: Math.round(performance.now() - startedAt), }, { name: 'Health endpoint', detail: apiEndpoints.health, ok: healthResult.ok, label: healthResult.label, latency: Math.round(performance.now() - startedAt), }, { name: 'TSS data proxy', detail: apiEndpoints.teamsHealth, ok: apiResult.ok, label: apiResult.label, latency: Math.round(performance.now() - startedAt), }, ] const onlineChecks = checks.filter((check) => check.ok).length return { status: 'ready', updatedAt: Date.now(), checks, history: [ ...current.history, { timestamp: Date.now(), onlineChecks, totalChecks: checks.length, ok: onlineChecks === checks.length, }, ].slice(-48), } }) } checkUptime() const timer = window.setInterval(checkUptime, 30000) return () => { window.clearInterval(timer) controller.abort() } }, [route.page]) useEffect(() => { if (route.page !== 'team' || !route.teamName) return const controller = new AbortController() const timer = window.setInterval(() => { Promise.allSettled([ fetchJson(apiEndpoints.detail(route.teamName), controller.signal), fetchJson(apiEndpoints.history(route.teamName), controller.signal), fetchJson(apiEndpoints.games(route.teamName), controller.signal), ]).then(([detailResult, historyResult, gamesResult]) => { if (controller.signal.aborted) return setProfile((current) => ({ teamName: route.teamName, detail: detailResult.status === 'fulfilled' ? { status: 'ready', data: detailResult.value, error: null } : current.detail, history: historyResult.status === 'fulfilled' ? { status: 'ready', data: historyResult.value, error: null } : current.history, games: gamesResult.status === 'fulfilled' ? { status: 'ready', data: gamesResult.value, error: null } : current.games, })) }) }, 60000) return () => { window.clearInterval(timer) controller.abort() } }, [route.page, route.teamName]) const topTeamName = bestTeamName(teams[0]) const searchPlaceholder = searchHint.status === 'ready' ? `Found ${searchHint.name}` : topTeamName || 'Search teams' async function handleTeamSearch(event) { event.preventDefault() const name = teamQuery.trim() if (!name) return try { const resolved = await fetchJson(apiEndpoints.resolve(name)) navigate(teamPath(resolved.tag_name || resolved.short_name || resolved.long_name || name)) } catch { navigate(teamPath(name)) } } const activeNavPath = route.page === 'team' ? '/teams' : route.page === 'battle-logs' ? '/battle-logs' : window.location.pathname return (
setTeamQuery(event.target.value)} />
{route.page === 'home' ? ( ) : null} {route.page === 'teams' ? ( ) : null} {route.page === 'team' ? ( ) : null} {route.page === 'battle-logs' ? : null} {route.page === 'uptime' ? : null}
) } function Footer({ navigate }) { return ( ) } function Landing({ live, matches, navigate }) { const treeRef = useRef(null) return (

BorisBot got nothin on THIS

Toothless' TSS Bot

Powered by Spectra. TSS analytics.

) } function RecentGamesSection({ live, matches, navigate }) { const recentMatches = matches.slice(0, 6) return (

Recent activity

Latest games

{recentMatches.map((match) => (

{match.map_name || 'Unknown map'}

{formatDate(match.timestamp)}

{match.result || 'Unknown'}

{match.team_name || 'TSS team'}

{formatNumber(match.player_count)} players

{formatNumber(match.stats?.ground_kills)} ground {formatNumber(match.stats?.air_kills)} air {formatNumber(match.stats?.deaths)} deaths
))}
{!recentMatches.length ? (

{live.status === 'loading' ? 'Loading latest games' : live.error || 'No games returned'}

) : null}
) } function PixelMountains() { const canvasRef = useRef(null) useEffect(() => { const canvas = canvasRef.current const ctx = canvas.getContext('2d') const WORLD_W = 1920 const WORLD_H = 900 function interpolate(points, x) { for (let i = 0; i < points.length - 1; i++) { const [x0, y0] = points[i] const [x1, y1] = points[i + 1] if (x >= x0 && x <= x1) { const t = (x - x0) / Math.max(1, x1 - x0) return y0 + (y1 - y0) * t } } return points.at(-1)[1] } function drawMountain(points, color, jitter = 0) { const width = WORLD_W const height = WORLD_H ctx.fillStyle = color for (let x = 0; x < width; x++) { const wave = jitter ? Math.sin(x * 0.08) * jitter + Math.sin(x * 0.021) * jitter * 1.8 : 0 const y = Math.round(interpolate(points, x) + wave) ctx.fillRect(x, y, 1, height - y) } } function draw() { const width = WORLD_W const height = WORLD_H canvas.width = WORLD_W canvas.height = WORLD_H ctx.imageSmoothingEnabled = false ctx.clearRect(0, 0, WORLD_W, WORLD_H) drawMountain( [ [0, height * 0.82], [width * 0.12, height * 0.73], [width * 0.26, height * 0.66], [width * 0.39, height * 0.76], [width * 0.55, height * 0.58], [width * 0.64, height * 0.46], [width * 0.73, height * 0.62], [width * 0.86, height * 0.56], [width, height * 0.64], ], '#fcfbcf', 1.1, ) drawMountain( [ [0, height * 0.86], [width * 0.15, height * 0.78], [width * 0.31, height * 0.81], [width * 0.43, height * 0.69], [width * 0.52, height * 0.76], [width * 0.62, height * 0.43], [width * 0.69, height * 0.31], [width * 0.78, height * 0.48], [width, height * 0.5], ], '#fff2e6', 1.6, ) drawMountain( [ [0, height * 0.94], [width * 0.17, height * 0.9], [width * 0.32, height * 0.92], [width * 0.47, height * 0.83], [width * 0.58, height * 0.89], [width * 0.66, height * 0.61], [width * 0.71, height * 0.5], [width * 0.84, height * 0.7], [width, height * 0.68], ], '#fee5cd', 2.1, ) drawMountain( [ [0, height * 0.98], [width * 0.17, height * 0.96], [width * 0.34, height * 0.99], [width * 0.48, height * 0.93], [width * 0.62, height * 0.97], [width * 0.72, height * 0.88], [width * 0.86, height * 0.95], [width, height * 0.93], ], '#fdca9b', 1.4, ) } draw() }, []) return