"use client"; import Image from "next/image"; import { useEffect, useState } from "react"; import type { Dictionary } from "@/lib/i18n/get-dictionary"; import { activityImageUrl, discordAvatarUrl, lanyardUrl, type DiscordStatus, type LanyardActivity, type LanyardData, } from "@/lib/lanyard"; const STATUS_DOT: Record = { online: "bg-emerald-400", idle: "bg-amber-400", dnd: "bg-rose-500", offline: "bg-zinc-500", }; const POLL_MS = 15_000; function formatElapsed(start: number): string { const seconds = Math.max(0, Math.floor((Date.now() - start) / 1000)); const hours = Math.floor(seconds / 3600); const minutes = Math.floor((seconds % 3600) / 60); if (hours > 0) { return `${hours}h ${minutes}m`; } if (minutes > 0) { return `${minutes}m`; } return "<1m"; } function ActivityRow({ activity }: { activity: LanyardActivity }) { const large = activityImageUrl(activity, false); const small = activityImageUrl(activity, true); return (
{large ? (
{activity.assets?.large_text {small ? ( {activity.assets?.small_text ) : null}
) : null}

{activity.name}

{activity.details ? (

{activity.details}

) : null} {activity.state ? (

{activity.state}

) : null} {activity.timestamps?.start ? (

{formatElapsed(activity.timestamps.start)}

) : null}
); } export function DiscordCard({ initial, dict, }: { initial: LanyardData | null; dict: Dictionary["discord"]; }) { const [data, setData] = useState(initial); useEffect(() => { async function poll(): Promise { const response = await fetch(lanyardUrl(), { cache: "no-store" }); if (!response.ok) { return; } const json = (await response.json()) as { success: boolean; data: LanyardData }; if (json.success) { setData(json.data); } } function tick(): void { void poll().catch(() => undefined); } const timer = window.setInterval(tick, POLL_MS); return () => window.clearInterval(timer); }, []); if (!data) { return (
{dict.offline}
); } const user = data.discord_user; const displayName = user.display_name ?? user.global_name ?? user.username; const customStatus = data.activities.find((a) => a.type === 4); const games = data.activities.filter((a) => a.type === 0); return (
{displayName}

{displayName}

@{user.username}

{dict[data.discord_status]} · {dict.live}

{customStatus?.state ? (

{dict.customStatus} {customStatus.emoji?.name ? ( {customStatus.emoji.name} ) : null} {customStatus.state}

) : null} {games.length > 0 ? (

{dict.playing}

{games.map((game) => ( ))}
) : null} {data.listening_to_spotify && data.spotify ? (
{data.spotify.album_art_url ? ( {data.spotify.album} ) : null}

{dict.listening} Spotify

{data.spotify.song}

{data.spotify.artist} — {data.spotify.album}

) : null} {games.length === 0 && !data.listening_to_spotify && !customStatus?.state ? (

{dict.noActivity}

) : null}
); }