123 lines
4.3 KiB
TypeScript
123 lines
4.3 KiB
TypeScript
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>
|
|
);
|
|
}
|