feat: add realtime Discord leaderboards
This commit is contained in:
@@ -0,0 +1,122 @@
|
||||
import type { Metadata } from "next";
|
||||
import { redirect } from "next/navigation";
|
||||
import { ChannelSelect } from "@/components/leaderboard/channel-select";
|
||||
import { LeaderboardBoard } from "@/components/leaderboard/leaderboard-board";
|
||||
import { LeaderboardError } from "@/components/leaderboard/leaderboard-error";
|
||||
import { LeaderboardShell } from "@/components/leaderboard/leaderboard-shell";
|
||||
import { RealtimeRefresh } from "@/components/realtime-refresh";
|
||||
import { getVoiceLeaderboardPage } from "@/lib/leaderboard/database";
|
||||
import { getCurrentDiscordVoiceChannels } from "@/lib/leaderboard/discord";
|
||||
import { normalizeRequestedPage } from "@/lib/leaderboard/ranking";
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "อันดับเวลาในห้องเสียง",
|
||||
description: "ดูอันดับเวลารวมในห้องเสียงและห้องเวที Discord ปัจจุบันของ Erika!",
|
||||
alternates: {
|
||||
canonical: "/leaderboard/vc",
|
||||
},
|
||||
};
|
||||
|
||||
type VoiceLeaderboardPageProps = {
|
||||
searchParams: Promise<{
|
||||
channel?: string | string[];
|
||||
page?: string | string[];
|
||||
}>;
|
||||
};
|
||||
|
||||
function voiceLeaderboardUrl(page: number, channelId?: string) {
|
||||
const params = new URLSearchParams();
|
||||
if (channelId) params.set("channel", channelId);
|
||||
if (page > 1) params.set("page", String(page));
|
||||
const query = params.toString();
|
||||
return query ? `/leaderboard/vc?${query}` : "/leaderboard/vc";
|
||||
}
|
||||
|
||||
export default async function VoiceLeaderboardPage({
|
||||
searchParams,
|
||||
}: VoiceLeaderboardPageProps) {
|
||||
const query = await searchParams;
|
||||
const requestedPage = normalizeRequestedPage(query.page);
|
||||
|
||||
let channels;
|
||||
try {
|
||||
channels = await getCurrentDiscordVoiceChannels();
|
||||
} catch (error) {
|
||||
console.error("Failed to load Discord voice channels", error);
|
||||
return (
|
||||
<LeaderboardShell
|
||||
active="vc"
|
||||
title="อันดับเวลาในห้องเสียง"
|
||||
description="รวมเวลาจากห้องเสียงและห้องเวทีที่ยังอยู่ใน Discord ตอนนี้ หรือเลือกดูเฉพาะห้องได้"
|
||||
>
|
||||
<LeaderboardError source="discord" />
|
||||
</LeaderboardShell>
|
||||
);
|
||||
}
|
||||
|
||||
const requestedChannelId = typeof query.channel === "string"
|
||||
? query.channel
|
||||
: undefined;
|
||||
const selectedChannelId = channels.some(
|
||||
(channel) => channel.id === requestedChannelId,
|
||||
)
|
||||
? requestedChannelId
|
||||
: undefined;
|
||||
const invalidChannel = query.channel !== undefined && !selectedChannelId;
|
||||
|
||||
let data;
|
||||
try {
|
||||
data = await getVoiceLeaderboardPage(
|
||||
channels.map((channel) => channel.id),
|
||||
requestedPage,
|
||||
selectedChannelId,
|
||||
);
|
||||
} catch (error) {
|
||||
console.error("Failed to load voice leaderboard", error);
|
||||
return (
|
||||
<LeaderboardShell
|
||||
active="vc"
|
||||
title="อันดับเวลาในห้องเสียง"
|
||||
description="รวมเวลาจากห้องเสียงและห้องเวทีที่ยังอยู่ใน Discord ตอนนี้ หรือเลือกดูเฉพาะห้องได้"
|
||||
>
|
||||
<ChannelSelect
|
||||
channels={channels}
|
||||
selectedChannelId={selectedChannelId}
|
||||
/>
|
||||
<LeaderboardError source="database" />
|
||||
</LeaderboardShell>
|
||||
);
|
||||
}
|
||||
|
||||
if (
|
||||
invalidChannel
|
||||
|| (query.page !== undefined && query.page !== String(data.page))
|
||||
) {
|
||||
redirect(voiceLeaderboardUrl(data.page, selectedChannelId));
|
||||
}
|
||||
|
||||
return (
|
||||
<LeaderboardShell
|
||||
active="vc"
|
||||
title="อันดับเวลาในห้องเสียง"
|
||||
description="รวมเวลาจากห้องเสียงและห้องเวทีที่ยังอยู่ใน Discord ตอนนี้ หรือเลือกดูเฉพาะห้องได้"
|
||||
>
|
||||
<RealtimeRefresh
|
||||
topic="leaderboards"
|
||||
leaderboard="vc"
|
||||
channelId={selectedChannelId}
|
||||
/>
|
||||
<ChannelSelect
|
||||
channels={channels}
|
||||
selectedChannelId={selectedChannelId}
|
||||
/>
|
||||
<LeaderboardBoard
|
||||
kind="vc"
|
||||
data={data}
|
||||
channelId={selectedChannelId}
|
||||
/>
|
||||
</LeaderboardShell>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user