fix: improve error handling in admin pages to show user-friendly error messages

- Add error display to help questions new/edit pages
- Improve error visibility in admin-badges, admin-applications, admin-logs, admin-users pages
- Update createHelpQuestion action to properly handle and display unique name collisions and database errors
- Add user-friendly error messages to admin error handling
- Enhances admin page error reporting for better user experience
This commit is contained in:
remco committed 2026-07-01 21:25:30 +02:00
1 parent d775e893f4
commit 0323c3fcaa
13 files changed
+222 -221

No files matched your search

+2
View File
@@ -1,3 +1,5 @@
"use client";
import type { ReactNode } from "react";
export interface OnlineUser {
+6 -5
View File
@@ -56,11 +56,12 @@ export function LanguageSwitcher() {
</svg>
</button>
{open && (
<div
className="glass-dropdown absolute right-0 top-full mt-0.5 min-w-[160px] rounded-xl z-50 py-2"
>
{LOCALES.map((l) => (
{open && (
<div
className="dropdown-menu absolute right-0 top-full mt-0.5 min-w-[160px] rounded-xl z-50 py-2"
>
{LOCALES.map((l) => (
<button
key={l.code}
type="button"
+7 -6
View File
@@ -70,12 +70,13 @@ export function NavbarColorPicker() {
</svg>
</button>
{mounted && open && (
<div
className="glass-dropdown absolute right-0 top-full mt-0.5 min-w-[200px] rounded-xl z-50 py-3 px-2"
>
<div className="text-xs font-semibold uppercase tracking-wider mb-2 px-2" style={{ color: "var(--color-text-muted)" }}>Navbar kleur</div>
<div className="grid grid-cols-5 gap-1.5">
{mounted && open && (
<div
className="dropdown-menu absolute right-0 top-full mt-0.5 min-w-[200px] rounded-xl z-50 py-3 px-2"
>
<div className="text-xs font-semibold uppercase tracking-wider mb-2 px-2" style={{ color: "var(--color-text-muted)" }}>Navbar kleur</div>
<div className="grid grid-cols-5 gap-1.5">
{COLORS.map((c, i) => (
<button
key={c.name}
+3 -3
View File
@@ -36,7 +36,7 @@ export async function Navigation() {
{t("community")}
<svg className="ml-auto md:ml-1 w-3 h-3 transition-transform duration-200 group-open:rotate-180" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" /></svg>
</summary>
<div className="glass-dropdown md:absolute left-0 top-full mt-0.5 min-w-[200px] rounded-xl z-50 py-2">
<div className="dropdown-menu md:absolute left-0 top-full mt-0.5 min-w-[200px] rounded-xl z-50 py-2">
<Link href="/news" className="dropdown-item">{t("articles")}</Link>
<Link href="/photos" className="dropdown-item">{t("photos")}</Link>
<Link href="/staff" className="dropdown-item">{t("staff")}</Link>
@@ -51,7 +51,7 @@ export async function Navigation() {
{t("shop")}
<svg className="ml-auto md:ml-1 w-3 h-3 transition-transform duration-200 group-open:rotate-180" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" /></svg>
</summary>
<div className="glass-dropdown md:absolute left-0 top-full mt-0.5 min-w-[200px] rounded-xl z-50 py-2">
<div className="dropdown-menu md:absolute left-0 top-full mt-0.5 min-w-[200px] rounded-xl z-50 py-2">
<Link href="/shop" className="dropdown-item">{t("shop")}</Link>
<Link href="/marketplace" className="dropdown-item">{t("market")}</Link>
<Link href="/rares" className="dropdown-item">{t("rareValues")}</Link>
@@ -74,7 +74,7 @@ export async function Navigation() {
{t("assistance")}
<svg className="ml-auto md:ml-1 w-3 h-3 transition-transform duration-200 group-open:rotate-180" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" /></svg>
</summary>
<div className="glass-dropdown md:absolute left-0 top-full mt-0.5 min-w-[200px] rounded-xl z-50 py-2">
<div className="dropdown-menu md:absolute left-0 top-full mt-0.5 min-w-[200px] rounded-xl z-50 py-2">
<Link href="/help" className="dropdown-item">{t("helpCenter")}</Link>
{session?.user ? (
<Link href="/help/tickets" className="dropdown-item">{t("myTickets")}</Link>
+68 -67
View File
@@ -66,71 +66,72 @@ export async function TopHeader() {
>
Administration
</summary>
<div
className="glass-dropdown absolute right-0 top-full mt-0.5 min-w-[180px] rounded-xl z-50 py-2"
>
<Link href="/admin" className="dropdown-item">
Admin panel
</Link>
<Link href="/admin/commandocentrum" className="dropdown-item">
Commandocentrum
</Link>
<Link href="/admin/logs" className="dropdown-item">
Logs
</Link>
</div>
</details>
) : null}
<details className="relative">
<summary className="list-none cursor-pointer flex items-center [&::-webkit-details-marker]:hidden">
{/* biome-ignore lint/performance/noImgElement: external imager */}
<img className="w-[54px] h-[62px] bg-no-repeat bg-center" src={avatar} alt="" />
<span className="-ml-2 font-semibold" style={{ color: "var(--color-navbar-text, var(--color-text))" }}>{session.user.name}</span>
</summary>
<div
className="glass-dropdown absolute right-0 top-full mt-0.5 min-w-[200px] rounded-xl z-50 py-2"
>
<Link href="/me" className="dropdown-item">
My dashboard
</Link>
<Link href={`/u/${session.user.name}`} className="dropdown-item">
My profile
</Link>
<Link href="/settings" className="dropdown-item">
User settings
</Link>
<Link href="/settings/2fa" className="dropdown-item">
Two-factor
</Link>
<Link href="/settings/sessions" className="dropdown-item">
Login activity
</Link>
<div className="h-px my-1 mx-3" style={{ backgroundColor: "color-mix(in srgb, var(--color-text-muted) 12%, transparent)" }} />
<form
action={async () => {
"use server";
await signOut({ redirectTo: "/" });
}}
>
<button
type="submit"
className="dropdown-item w-full text-center mx-1 rounded-lg"
style={{
backgroundColor: "color-mix(in srgb, var(--button-danger-color) 12%, transparent)",
color: "var(--button-danger-color)",
border: "none",
cursor: "pointer",
width: "calc(100% - 8px)",
}}
>
Logout
</button>
</form>
</div>
</details>
</div>
</div>
</div>
);
<div
className="dropdown-menu absolute right-0 top-full mt-0.5 min-w-[180px] rounded-xl z-50 py-2"
>
<Link href="/admin" className="dropdown-item">
Admin panel
</Link>
<Link href="/admin/commandocentrum" className="dropdown-item">
Commandocentrum
</Link>
<Link href="/admin/logs" className="dropdown-item">
Logs
</Link>
</div>
</details>
) : null}
<details className="relative">
<summary className="list-none cursor-pointer flex items-center [&::-webkit-details-marker]:hidden">
{/* biome-ignore lint/performance/noImgElement: external imager */}
<img className="w-[54px] h-[62px] bg-no-repeat bg-center" src={avatar} alt="" />
<span className="-ml-2 font-semibold" style={{ color: "var(--color-navbar-text, var(--color-text))" }}>{session.user.name}</span>
</summary>
<div
className="dropdown-menu absolute right-0 top-full mt-0.5 min-w-[200px] rounded-xl z-50 py-2"
>
<Link href="/me" className="dropdown-item">
My dashboard
</Link>
<Link href={`/u/${session.user.name}`} className="dropdown-item">
My profile
</Link>
<Link href="/settings" className="dropdown-item">
User settings
</Link>
<Link href="/settings/2fa" className="dropdown-item">
Two-factor
</Link>
<Link href="/settings/sessions" className="dropdown-item">
Login activity
</Link>
<div className="h-px my-1 mx-3" style={{ backgroundColor: "color-mix(in srgb, var(--color-text-muted) 12%, transparent)" }} />
<form
action={async () => {
"use server";
await signOut({ redirectTo: "/" });
}}
>
<button
type="submit"
className="dropdown-item w-full text-center mx-1 rounded-lg"
style={{
backgroundColor: "color-mix(in srgb, var(--button-danger-color) 12%, transparent)",
color: "var(--button-danger-color)",
border: "none",
cursor: "pointer",
width: "calc(100% - 8px)",
}}
>
Logout
</button>
</form>
</div>
</details>
</div>
</div>
</div>
);
}