From aa0d9540e82f84769bbcff4c6585965ef7621392 Mon Sep 17 00:00:00 2001 From: Local Administrator Date: Mon, 29 Jun 2026 05:45:46 +0000 Subject: [PATCH] Feed: strict newest-first sort; promos are badges only --- src/app/api/public/posts/route.ts | 3 +-- src/app/home-page/components/ArticleFeed.tsx | 12 +++++------- src/lib/promoted-articles.ts | 20 ++------------------ 3 files changed, 8 insertions(+), 27 deletions(-) diff --git a/src/app/api/public/posts/route.ts b/src/app/api/public/posts/route.ts index 459cb1a..9891c45 100644 --- a/src/app/api/public/posts/route.ts +++ b/src/app/api/public/posts/route.ts @@ -33,8 +33,7 @@ export async function GET(request: Request) { source: "imported" as const, })); - // Decorate + reorder so premium and current-advertiser stories surface - // at the top of the feed. + // Decorate with promotion badges; preserve wp_published_at order. const decorated = await decorateHomepageFeed("avbeat", base); const payload = decorated.map((d) => ({ ...d.article, diff --git a/src/app/home-page/components/ArticleFeed.tsx b/src/app/home-page/components/ArticleFeed.tsx index a045870..8a86163 100644 --- a/src/app/home-page/components/ArticleFeed.tsx +++ b/src/app/home-page/components/ArticleFeed.tsx @@ -171,19 +171,14 @@ export default function ArticleFeed({ initialPosts = [] }: ArticleFeedProps) { return matchCat && matchSource && matchSearch && matchDate; }); - // Sort filtered articles based on sortOrder. For every order we honor - // the promoted-tier hierarchy first (premium > advertiser > general) so - // paid placements and advertiser news always lead. Within each tier the - // user's chosen sort applies. + // Recent: strict publish-date order (newest first). Promoted badges stay + // on cards but never reorder the feed. Trending/commented keep promo tier. function promotedTier(a: ArticleItem): number { if (a.promoted_kind === "premium") return 0; if (a.promoted_kind === "client") return 1; return 2; } const sortedFiltered = [...filtered].sort((a, b) => { - const ta = promotedTier(a); - const tb = promotedTier(b); - if (ta !== tb) return ta - tb; if (sortOrder === "recent") { const da = parseArticleDate(a.date); const db = parseArticleDate(b.date); @@ -192,6 +187,9 @@ export default function ArticleFeed({ initialPosts = [] }: ArticleFeedProps) { if (!db) return -1; return db.getTime() - da.getTime(); } + const ta = promotedTier(a); + const tb = promotedTier(b); + if (ta !== tb) return ta - tb; if (sortOrder === "trending") { // Trending: FEATURED category gets a boost, then by recency const featuredBoost = (art: ArticleItem) => (art.category === "FEATURED" ? 2 : 0); diff --git a/src/lib/promoted-articles.ts b/src/lib/promoted-articles.ts index 117d101..6a1530d 100644 --- a/src/lib/promoted-articles.ts +++ b/src/lib/promoted-articles.ts @@ -260,23 +260,7 @@ export async function decorateHomepageFeed( return { article: a, promoted_kind: null, promoted_until: null }; }); - // Sort: premium first (by position asc), then client (by date desc), then general (by date desc) - function tier(d: DecoratedArticle): number { - if (d.promoted_kind === "premium") return 0; - if (d.promoted_kind === "client") return 1; - return 2; - } - function dateTs(d: DecoratedArticle): number { - const t = new Date(d.article.date).getTime(); - return isNaN(t) ? 0 : t; - } - decorated.sort((a, b) => { - const ta = tier(a); - const tb = tier(b); - if (ta !== tb) return ta - tb; - if (ta === 0) return (a.promoted_position ?? 999) - (b.promoted_position ?? 999); - return dateTs(b) - dateTs(a); // newest first - }); - + // Preserve caller order (wp_published_at desc). Promotion flags are visual + // badges only — the Industry News feed stays newest-to-oldest. return decorated; }