revise ads and alerts

This commit is contained in:
2026-08-03 22:48:06 +08:00
parent 32c72f0b39
commit 573cfb98af
16 changed files with 414 additions and 17 deletions
+14 -6
View File
@@ -61,8 +61,6 @@ function deriveStatus(advertisement) {
return "active";
}
const ALLOWED_CTA_VARIANTS = ["default", "outline"];
function normalizeCtas(ctas) {
if (!Array.isArray(ctas)) return [];
return ctas
@@ -71,12 +69,22 @@ function normalizeCtas(ctas) {
.map((c, i) => ({
label: c.label.trim(),
link: c.link.trim(),
// First CTA defaults to "default" (primary), second to "outline" — but
// an explicit, valid variant from the client always wins.
variant: ALLOWED_CTA_VARIANTS.includes(c.variant) ? c.variant : (i === 0 ? "default" : "outline"),
// Variant is always derived from position — first CTA is "default"
// (primary), second is "outline" — not user-selectable, so any
// client-sent variant is ignored.
variant: i === 0 ? "default" : "outline",
}));
}
// Hard cap: max 2 badge labels per advertisement (matches MAX_BADGE_LABELS on the frontend)
function normalizeBadgeLabels(labels) {
if (!Array.isArray(labels)) return [];
return labels
.filter((l) => typeof l === "string" && l.trim().length > 0)
.map((l) => l.trim())
.slice(0, 2);
}
async function applyAdvertisementFields(advertisement, body) {
// placement is the only settable "where" — type/format is always derived
// from the placement's registry entry, never accepted directly from the body.
@@ -103,7 +111,7 @@ async function applyAdvertisementFields(advertisement, body) {
advertisement.content_mode = body.content_mode;
}
if (body.badge_label !== undefined) advertisement.badge_label = body.badge_label;
if (body.badge_labels !== undefined) advertisement.badge_labels = normalizeBadgeLabels(body.badge_labels);
if (body.headline !== undefined) advertisement.headline = body.headline;
if (body.description !== undefined) advertisement.description = body.description;
if (body.image_url !== undefined) advertisement.image_url = body.image_url;