d612b7916c
Segunda isla de la home: la tabla de estado (nombre, online, login, hora, dirección) pasa de plantilla Django a componente React. - API: home_status_api -> /api/home/status/ (server_name, address, expansion, online_characters, status). Reutiliza check_server_status y get_online_characters_count de views/pages. - React: ServerStatus.tsx (fetch + reloj en vivo con setInterval, mismas clases CSS). El entry home.tsx ahora monta dos islas: #home-news-app y #home-status-app. - partials/noticias.html: la <table> de estado se sustituye por el contenedor. Verificado: check OK, ambos endpoints 200, la home monta las dos islas. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
75 lines
2.0 KiB
TypeScript
75 lines
2.0 KiB
TypeScript
import { useEffect, useState } from 'react'
|
|
import type { ServerStatusData } from '../types'
|
|
|
|
function useClock(): string {
|
|
const [time, setTime] = useState(() => new Date().toLocaleTimeString('es-ES'))
|
|
useEffect(() => {
|
|
const id = setInterval(() => setTime(new Date().toLocaleTimeString('es-ES')), 1000)
|
|
return () => clearInterval(id)
|
|
}, [])
|
|
return time
|
|
}
|
|
|
|
export function ServerStatus() {
|
|
const [data, setData] = useState<ServerStatusData | null>(null)
|
|
const clock = useClock()
|
|
|
|
useEffect(() => {
|
|
let cancelled = false
|
|
fetch('/api/home/status/', { headers: { Accept: 'application/json' } })
|
|
.then((r) => {
|
|
if (!r.ok) throw new Error(`HTTP ${r.status}`)
|
|
return r.json()
|
|
})
|
|
.then((d: ServerStatusData) => {
|
|
if (!cancelled) setData(d)
|
|
})
|
|
.catch(() => {
|
|
if (!cancelled) setData(null)
|
|
})
|
|
return () => {
|
|
cancelled = true
|
|
}
|
|
}, [])
|
|
|
|
const online = data ? data.online_characters : 0
|
|
const status = data ? data.status : 'Offline'
|
|
const loginClass = status === 'Online' ? 'green-info' : 'red-info'
|
|
|
|
return (
|
|
<table className="max-center-table">
|
|
<tbody>
|
|
<tr>
|
|
<td className="yellow-info">
|
|
{data?.server_name ?? '—'}{' '}
|
|
<span className="blue-info small-font">{data?.expansion ?? ''}</span>
|
|
</td>
|
|
<td className="real-info-box green-info">{online}</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Login</td>
|
|
<td className={`real-info-box ${loginClass}`}>{status}</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Hora</td>
|
|
<td className="real-info-box">
|
|
<span id="server-time">{clock}</span>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td colSpan={2}>
|
|
<hr />
|
|
</td>
|
|
</tr>
|
|
<tr className="centered">
|
|
<td colSpan={2}>
|
|
<p>
|
|
<span>{data?.address ?? ''}</span>
|
|
</p>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
)
|
|
}
|