feat: comprehensive CMS improvements
- Fix DOMPurify SSR crash (use isomorphic-dompurify) - Fix SanitizedHtml to sanitize by default - Add auth guards to studio/catalog maintenance pages - Add update/edit to vouchers CRUD - Add update/edit to rare-values CRUD - Add approve workflow to applications page - Add edit form to guilds detail page - Add SEO metadata to all public pages (21 pages) - Fix mobile nav accessibility (focus trap, aria attributes) - Fix missing labels and table accessibility - Add dynamic imports for heavy client components (6 components) - Fix silent error swallowing (40+ locations) - Add content scheduling for articles (publishAt, status) - Wire up 12 missing webhook notification triggers - Add global search to admin panel - Add bulk actions to admin users table - Fix JSON formatting and a11y issues
This commit is contained in:
1 parent
b810b16672
commit
30c95b1a5c
78 files changed
+2252
-134
No files matched your search
@@ -83,3 +83,58 @@ export async function deleteVoucher(input: {
|
||||
return actionError("Could not delete voucher");
|
||||
}
|
||||
}
|
||||
|
||||
export async function updateVoucher(input: {
|
||||
id: string;
|
||||
code: string;
|
||||
amount: number;
|
||||
maxUses: number;
|
||||
expiresAt?: string;
|
||||
}): Promise<ActionResult> {
|
||||
await requirePermission(PERMS.SHOP_EDIT);
|
||||
|
||||
const id = positiveBigInt(String(input.id ?? "").trim());
|
||||
if (!id) return actionError("Missing voucher id");
|
||||
|
||||
const code = String(input.code ?? "")
|
||||
.normalize("NFC")
|
||||
.trim()
|
||||
.slice(0, 255);
|
||||
const amount = Number(input.amount);
|
||||
const maxUsesRaw = Number(input.maxUses);
|
||||
const maxUses =
|
||||
Number.isFinite(maxUsesRaw) && maxUsesRaw > 0 ? Math.floor(maxUsesRaw) : 1;
|
||||
|
||||
if (!code || !(amount > 0)) {
|
||||
return actionError("Code and a positive amount are required");
|
||||
}
|
||||
|
||||
let expiresAt: Date | null = null;
|
||||
const expiresRaw = String(input.expiresAt ?? "")
|
||||
.normalize("NFC")
|
||||
.trim();
|
||||
if (expiresRaw) {
|
||||
const parsed = new Date(expiresRaw);
|
||||
if (!Number.isNaN(parsed.getTime())) expiresAt = parsed;
|
||||
}
|
||||
|
||||
try {
|
||||
await db
|
||||
.update(WebsiteShopVouchers)
|
||||
.set({
|
||||
code,
|
||||
amount: Math.floor(amount),
|
||||
maxUses,
|
||||
expiresAt,
|
||||
updatedAt: new Date(),
|
||||
})
|
||||
.where(eq(WebsiteShopVouchers.id, id));
|
||||
revalidatePath("/admin/vouchers");
|
||||
return actionOk();
|
||||
} catch (error) {
|
||||
logServerError("admin.voucher_update_failed", error, {
|
||||
voucherId: String(id),
|
||||
});
|
||||
return actionError("Could not update voucher (code may already exist)");
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user