feat: shop buy, forum replies, tickets, messages, sessions, and UX hardening
Complete remaining product gaps: credit-based shop purchases, guild thread replies, help ticket detail/reply/close, offline message compose, sign-out-everywhere via JWT version, ads delete confirm, soft-fail feedback, rate limits, loading states, and single auth() in site layout. Co-authored-by: Cursor <[email protected]>
This commit is contained in:
1 parent
ed7db6e048
commit
803e8f36c1
47 files changed
+2793
-358
No files matched your search
@@ -1,9 +1,11 @@
|
||||
import { Megaphone } from "lucide-react";
|
||||
import Link from "next/link";
|
||||
import { notFound, redirect } from "next/navigation";
|
||||
import { deleteAd, updateAd } from "@/actions/admin-ads";
|
||||
import { getTranslations } from "next-intl/server";
|
||||
import { updateAd } from "@/actions/admin-ads";
|
||||
import { prisma } from "@/lib/prisma";
|
||||
import { canAccess, getAdminContext, PERMS } from "@/lib/permissions";
|
||||
import { EditAdDeleteButton } from "../ads-table";
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
|
||||
@@ -26,6 +28,8 @@ export default async function EditAd({
|
||||
}
|
||||
if (!ad) notFound();
|
||||
|
||||
const t = await getTranslations("pages.admin.ads");
|
||||
|
||||
return (
|
||||
<main>
|
||||
<div className="flex items-center gap-3 mb-6">
|
||||
@@ -34,10 +38,10 @@ export default async function EditAd({
|
||||
</div>
|
||||
<div>
|
||||
<h1 className="m-0 text-xl font-extrabold text-[var(--admin-text)]">
|
||||
Edit advertisement
|
||||
{t("edit")} #{String(ad.id)}
|
||||
</h1>
|
||||
<p className="m-0 text-xs text-[var(--admin-text-muted)] mt-0.5">
|
||||
<Link href="/admin/ads">← Advertisements</Link>
|
||||
<Link href="/admin/ads">← {t("title")}</Link>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -46,20 +50,17 @@ export default async function EditAd({
|
||||
<input
|
||||
name="image"
|
||||
defaultValue={ad.image}
|
||||
placeholder="Image URL"
|
||||
placeholder={t("form.imagePlaceholder")}
|
||||
required
|
||||
maxLength={255}
|
||||
/>
|
||||
<button type="submit" className="btn btn-primary">
|
||||
Save
|
||||
</button>
|
||||
</form>
|
||||
<form action={deleteAd} style={{ marginTop: "1rem" }}>
|
||||
<input type="hidden" name="id" value={String(ad.id)} />
|
||||
<button type="submit" className="btn btn-danger">
|
||||
Delete advertisement
|
||||
{t("form.save")}
|
||||
</button>
|
||||
</form>
|
||||
<div style={{ marginTop: "1rem" }}>
|
||||
<EditAdDeleteButton id={String(ad.id)} />
|
||||
</div>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user