"use client";
import type { ReactNode } from "react";
export interface OnlineUser {
id: number;
username: string;
look: string;
roomId: number | null;
roomName: string | null;
lastActivity: Date;
}
type State = "ok" | "warn" | "danger" | "neutral";
/** A single live-status tile (online users, emulator, DB, …). */
export function StatusCard({
label,
value,
hint,
state = "neutral",
icon,
}: {
label: string;
value: ReactNode;
hint?: string;
state?: State;
icon?: string;
}) {
return (
{label}
{icon ? (
{icon}
) : null}
{value}
{hint ?
{hint}
: null}
);
}
/** A row in the system-diagnostics list with an ok/warn/error pill. */
export function DiagnosticRow({
label,
detail,
state,
}: {
label: string;
detail: string;
state: Exclude;
}) {
const text = state === "ok" ? "OK" : state === "warn" ? "WARN" : "ERROR";
return (
{label}
{detail}
{text}
);
}
/** Small labelled key/value used in the server-info card. */
export function InfoItem({ label, value }: { label: string; value: ReactNode }) {
return (
{label}
{value}
);
}
/** Live list of online users with room and activity tracking */
export function OnlineUsersWidget({
users,
isLoading = false,
}: {
users: OnlineUser[];
isLoading?: boolean;
}) {
const formatLastSeen = (date: Date) => {
const now = new Date();
const diff = Math.floor((now.getTime() - date.getTime()) / 1000);
if (diff < 60) return "Just now";
if (diff < 3600) return `${Math.floor(diff / 60)}m ago`;
if (diff < 86400) return `${Math.floor(diff / 3600)}h ago`;
return `${Math.floor(diff / 86400)}d ago`;
};
return (
Online Now
{isLoading ? "..." : users.length} users
{users.length === 0 ? (
No users online
) : (
users.map((user) => (
}`})
{user.roomId && user.roomName && (
)}
{user.roomId && user.roomName ? (
🏠 {user.roomName}
) : (
⏱️ {formatLastSeen(user.lastActivity)}
)}
))
)}
);
}