Reapply "Add missing admin action files and navigation links"

This reverts commit 4d515bc400.
This commit is contained in:
Simo committed 2026-07-11 20:52:56 +02:00
1 parent 96ed768f14
commit 5b4228261a
338 files changed
+28143 -5948

No files matched your search

+39 -41
View File
@@ -23,7 +23,11 @@ export default async function TwoFactorPage({
const sp = await searchParams;
const id = Number(session.user.id);
let user: { twoFactorSecret: string | null; twoFactorConfirmedAt: Date | null; twoFactorRecoveryCodes: string | null } | null = null;
let user: {
twoFactorSecret: string | null;
twoFactorConfirmedAt: Date | null;
twoFactorRecoveryCodes: string | null;
} | null = null;
try {
user = await prisma.user.findUnique({
where: { id },
@@ -59,40 +63,43 @@ export default async function TwoFactorPage({
<Link href="/settings">{t("backToSettings")}</Link>
</p>
<ContentCard
icon="🔒"
title={t("title")}
subtitle={t("subtitle")}
>
<ContentCard icon="🔒" title={t("title")} subtitle={t("subtitle")}>
{sp.enabled ? (
<>
<p style={{ color: "var(--color-accent)", marginTop: 0 }}>{t("nowEnabled")}</p>
<div style={{
background: "var(--color-surface)",
border: "1px solid var(--color-border)",
borderRadius: 8,
padding: "1rem",
marginTop: "0.5rem",
}}>
<div
style={{
background: "var(--color-surface)",
border: "1px solid var(--color-border)",
borderRadius: 8,
padding: "1rem",
marginTop: "0.5rem",
}}
>
<h4 style={{ margin: "0 0 0.5rem" }}>Recovery Codes</h4>
<p className="muted" style={{ fontSize: "0.85rem", margin: "0 0 0.75rem" }}>
Store these one-time use codes in a safe place. Each can be used once
if you lose access to your authenticator app.
Store these one-time use codes in a safe place. Each can be used once if you lose access to
your authenticator app.
</p>
<div style={{
display: "grid",
gridTemplateColumns: "1fr 1fr",
gap: "0.25rem",
fontFamily: "monospace",
fontSize: "0.9rem",
}}>
<div
style={{
display: "grid",
gridTemplateColumns: "1fr 1fr",
gap: "0.25rem",
fontFamily: "monospace",
fontSize: "0.9rem",
}}
>
{recoveryCodes.map((code) => (
<code key={code} style={{
userSelect: "all",
padding: "0.25rem 0.5rem",
background: "var(--color-background)",
borderRadius: 4,
}}>
<code
key={code}
style={{
userSelect: "all",
padding: "0.25rem 0.5rem",
background: "var(--color-background)",
borderRadius: 4,
}}
>
{code}
</code>
))}
@@ -106,14 +113,10 @@ export default async function TwoFactorPage({
</p>
) : null}
{sp.error === "badcode" ? (
<p style={{ color: "var(--color-danger)", marginTop: 0 }}>
{t("badCode")}
</p>
<p style={{ color: "var(--color-danger)", marginTop: 0 }}>{t("badCode")}</p>
) : null}
{sp.error === "ratelimit" ? (
<p style={{ color: "var(--color-danger)", marginTop: 0 }}>
{t("rateLimit")}
</p>
<p style={{ color: "var(--color-danger)", marginTop: 0 }}>{t("rateLimit")}</p>
) : null}
{!hasAppKey ? (
@@ -145,10 +148,7 @@ export default async function TwoFactorPage({
<p className="muted" style={{ wordBreak: "break-all", fontSize: "0.8rem" }}>
{uri}
</p>
<form
action={confirmTwoFactor}
style={{ display: "flex", gap: "0.5rem", marginTop: "0.5rem" }}
>
<form action={confirmTwoFactor} style={{ display: "flex", gap: "0.5rem", marginTop: "0.5rem" }}>
<input name="code" placeholder={t("codePlaceholder")} inputMode="numeric" required />
<button type="submit" className="btn btn-primary">
{t("confirm")}
@@ -157,9 +157,7 @@ export default async function TwoFactorPage({
</>
) : (
<>
<p style={{ marginTop: 0 }}>
{t("enableIntro")}
</p>
<p style={{ marginTop: 0 }}>{t("enableIntro")}</p>
<form action={beginTwoFactor}>
<button type="submit" className="btn btn-primary">
{t("enable")}
+3 -10
View File
@@ -58,14 +58,9 @@ export default async function ConnectionsPage() {
<Link href="/settings">{t("backToSettings")}</Link>
</p>
<ContentCard
icon="🔗"
title={t("title")}
subtitle={t("subtitle")}
>
<ContentCard icon="🔗" title={t("title")} subtitle={t("subtitle")}>
<p className="muted" style={{ marginTop: 0 }}>
{t("matchByEmail")}{" "}
<strong>{session.user.name}</strong>.
{t("matchByEmail")} <strong>{session.user.name}</strong>.
</p>
{lookupFailed ? (
@@ -105,9 +100,7 @@ export default async function ConnectionsPage() {
// matching hotel account (see auth.ts signIn callback).
<a
className="btn btn-primary"
href={`/api/auth/signin/${p.key}?callbackUrl=${encodeURIComponent(
callbackUrl,
)}`}
href={`/api/auth/signin/${p.key}?callbackUrl=${encodeURIComponent(callbackUrl)}`}
>
{t("connectProvider", { provider: p.label })}
</a>
+3 -14
View File
@@ -36,8 +36,7 @@ export default async function SettingsPage() {
let imagerBase = "https://www.habbo.com/habbo-imaging/avatarimage";
try {
imagerBase =
(await siteSettings.get("habbo_imaging_url", imagerBase)) ?? imagerBase;
imagerBase = (await siteSettings.get("habbo_imaging_url", imagerBase)) ?? imagerBase;
} catch {
// fall back to the default imager base
}
@@ -46,22 +45,12 @@ export default async function SettingsPage() {
return (
<main style={{ display: "grid", gap: "1.5rem" }}>
<ContentCard
icon="⚙️"
title={t("accountSettings")}
subtitle={t("accountSettingsSubtitle")}
/>
<ContentCard icon="⚙️" title={t("accountSettings")} subtitle={t("accountSettingsSubtitle")} />
<ContentCard icon="🙂" title={user.username} subtitle={t("publicProfile")}>
<div style={{ display: "flex", gap: "1.5rem", alignItems: "center", flexWrap: "wrap" }}>
{/* eslint-disable-next-line @next/next/no-img-element */}
<img
className="avatar"
src={avatar}
alt={`${user.username} avatar`}
width={100}
height={150}
/>
<img className="avatar" src={avatar} alt={`${user.username} avatar`} width={100} height={150} />
<div style={{ minWidth: 0 }}>
<p style={{ margin: "0 0 0.5rem", fontSize: "1.05rem" }}>
{user.motto || <span className="muted">{t("noMotto")}</span>}