feat: mobile nav, radio layout/requests, leaderboard tabs, client i18n, habbo background, navbar fixes
This commit is contained in:
1 parent
16096eff0f
commit
d6ccc250f6
20 files changed
+936
-140
No files matched your search
@@ -0,0 +1,143 @@
|
||||
import { getTranslations } from "next-intl/server";
|
||||
import { ContentCard, EmptyState } from "@/components/public/ui";
|
||||
import { auth } from "@/lib/auth";
|
||||
import { prisma } from "@/lib/prisma";
|
||||
import { submitRequest } from "@/actions/radio-requests";
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
|
||||
function formatDate(d: Date | null | undefined): string {
|
||||
return d ? d.toISOString().slice(0, 16).replace("T", " ") : "";
|
||||
}
|
||||
|
||||
const DAYS = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"] as const;
|
||||
|
||||
function formatDay(d: Date): string {
|
||||
return DAYS[d.getUTCDay()] ?? "";
|
||||
}
|
||||
|
||||
export default async function RadioRequestsPage() {
|
||||
const t = await getTranslations("pages.radioRequests");
|
||||
const genericT = await getTranslations("pages.radio");
|
||||
|
||||
const [requests, session] = await Promise.all([
|
||||
prisma.radioSongRequests
|
||||
.findMany({
|
||||
orderBy: { createdAt: "desc" },
|
||||
take: 50,
|
||||
})
|
||||
.catch(() => []),
|
||||
auth(),
|
||||
]);
|
||||
|
||||
const isLoggedIn = Boolean(session?.user?.id);
|
||||
|
||||
const userIds = Array.from(new Set(requests.map((r) => Number(r.userId))));
|
||||
const users = userIds.length
|
||||
? await prisma.user
|
||||
.findMany({
|
||||
where: { id: { in: userIds } },
|
||||
select: { id: true, username: true },
|
||||
})
|
||||
.catch(() => [])
|
||||
: [];
|
||||
const userById = new Map(users.map((u) => [u.id, u.username]));
|
||||
|
||||
return (
|
||||
<>
|
||||
<ContentCard
|
||||
icon="🎵"
|
||||
title={genericT("linkRequests")}
|
||||
subtitle={genericT("linkRequestsText")}
|
||||
/>
|
||||
|
||||
{isLoggedIn ? (
|
||||
<ContentCard icon="✍️" title={t("formTitle")} subtitle={t("formSubtitle")}>
|
||||
<form action={submitRequest}>
|
||||
<div className="card-grid sm-2">
|
||||
<div>
|
||||
<label htmlFor="songTitle" className="muted">{t("songLabel")}</label>
|
||||
<input
|
||||
id="songTitle"
|
||||
name="songTitle"
|
||||
type="text"
|
||||
required
|
||||
maxLength={255}
|
||||
placeholder={t("songPlaceholder")}
|
||||
style={{ width: "100%", marginTop: "0.3rem" }}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label htmlFor="artist" className="muted">{t("artistLabel")}</label>
|
||||
<input
|
||||
id="artist"
|
||||
name="artist"
|
||||
type="text"
|
||||
maxLength={255}
|
||||
placeholder={t("artistPlaceholder")}
|
||||
style={{ width: "100%", marginTop: "0.3rem" }}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<button type="submit" className="btn btn-primary" style={{ marginTop: "1rem" }}>
|
||||
{t("submitButton")}
|
||||
</button>
|
||||
</form>
|
||||
</ContentCard>
|
||||
) : (
|
||||
<ContentCard padded>
|
||||
<EmptyState icon="🔒">{t("loginToRequest")}</EmptyState>
|
||||
</ContentCard>
|
||||
)}
|
||||
|
||||
<ContentCard
|
||||
icon="📋"
|
||||
title={t("latestTitle")}
|
||||
subtitle={t("latestSubtitle")}
|
||||
padded={requests.length === 0}
|
||||
>
|
||||
{requests.length === 0 ? (
|
||||
<EmptyState icon="🎵">{t("empty")}</EmptyState>
|
||||
) : (
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{t("colSong")}</th>
|
||||
<th>{t("colArtist")}</th>
|
||||
<th>{t("colRequester")}</th>
|
||||
<th>{t("colDate")}</th>
|
||||
<th>{t("colStatus")}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{requests.map((r) => {
|
||||
const requester = userById.get(Number(r.userId));
|
||||
const isPlayed = r.isPlayed;
|
||||
const isApproved = r.isApproved;
|
||||
let status = t("statusPending");
|
||||
if (isPlayed) status = t("statusPlayed");
|
||||
else if (isApproved) status = t("statusApproved");
|
||||
|
||||
return (
|
||||
<tr key={String(r.id)}>
|
||||
<td>{r.songTitle || <span className="muted">—</span>}</td>
|
||||
<td>{r.artist || <span className="muted">—</span>}</td>
|
||||
<td>
|
||||
{requester ? (
|
||||
<span>{requester}</span>
|
||||
) : (
|
||||
<span className="muted">#{String(r.userId)}</span>
|
||||
)}
|
||||
</td>
|
||||
<td className="muted">{r.submittedAt ? formatDate(r.submittedAt) : "—"}</td>
|
||||
<td>{status}</td>
|
||||
</tr>
|
||||
);
|
||||
})}
|
||||
</tbody>
|
||||
</table>
|
||||
)}
|
||||
</ContentCard>
|
||||
</>
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user