From 7ce224f4ed469d92ff60145dc2d899bfaa589bbb Mon Sep 17 00:00:00 2001 From: Cho Young-Hwi Date: Thu, 19 Mar 2026 12:55:44 +0000 Subject: [PATCH] [#358] Remove Rising and Completed sort options from home page Remove "Rising" and "Completed" from sort options, case branches, and the getRisingStorylines function from ranking.ts. Both were redundant/unused with the current storyline count. Co-Authored-By: Claude Opus 4.6 (1M context) --- lib/ranking.ts | 121 ----------------------------------- src/app/page.tsx | 25 +------- src/components/FilterBar.tsx | 2 - 3 files changed, 2 insertions(+), 146 deletions(-) diff --git a/lib/ranking.ts b/lib/ranking.ts index 24e3d9cc..aa1737e5 100644 --- a/lib/ranking.ts +++ b/lib/ranking.ts @@ -155,124 +155,3 @@ export async function getTrendingStorylines( return enriched.slice(offset, offset + limit); } -/** - * Fetch rising storylines — stories with accelerating signals. - * - * Computes the same 4 signals in a recent window (last 3 days) vs - * prior window (days 3-6). TVL is point-in-time (same for both windows, - * as historical TVL requires snapshots). Price change is inherently - * recent (24h lookback), so prior window uses the same value as a - * baseline denominator — acceleration comes from rating + plot signals. - */ -export async function getRisingStorylines( - supabase: SupabaseClient, - limit = 20, - writerType?: number, - offset = 0, - genre?: string, - lang?: string, -): Promise { - const { storylines } = await fetchCandidatesAndRatings(supabase, writerType, genre, lang); - if (storylines.length === 0) return []; - - const now = new Date(); - const threeDaysAgo = new Date(now.getTime() - 3 * 24 * 60 * 60 * 1000).toISOString(); - const sixDaysAgo = new Date(now.getTime() - 6 * 24 * 60 * 60 * 1000).toISOString(); - - // Exclude storylines younger than the prior window (6 days) — they have - // no meaningful prior activity to compare against. - const eligible = storylines.filter((sl) => { - if (!sl.block_timestamp) return false; - return new Date(sl.block_timestamp).getTime() <= new Date(sixDaysAgo).getTime(); - }); - if (eligible.length === 0) return []; - - const storylineIds = eligible.map((sl) => sl.storyline_id); - - // Batch: windowed ratings - const { data: recentRatings } = await supabase.from("ratings") - .select("storyline_id, rating") - .in("storyline_id", storylineIds) - .eq("contract_address", STORY_FACTORY.toLowerCase()) - .gte("updated_at", threeDaysAgo); - - const { data: priorRatings } = await supabase.from("ratings") - .select("storyline_id, rating") - .in("storyline_id", storylineIds) - .eq("contract_address", STORY_FACTORY.toLowerCase()) - .gte("updated_at", sixDaysAgo) - .lt("updated_at", threeDaysAgo); - - // Batch: windowed plot counts - const { data: recentPlots } = await supabase.from("plots") - .select("storyline_id") - .in("storyline_id", storylineIds) - .eq("contract_address", STORY_FACTORY.toLowerCase()) - .gte("block_timestamp", threeDaysAgo); - - const { data: priorPlots } = await supabase.from("plots") - .select("storyline_id") - .in("storyline_id", storylineIds) - .eq("contract_address", STORY_FACTORY.toLowerCase()) - .gte("block_timestamp", sixDaysAgo) - .lt("block_timestamp", threeDaysAgo); - - function avgFromRows(rows: { storyline_id: number; rating: number }[] | null, slId: number): number { - if (!rows) return 0; - const filtered = rows.filter((r: { storyline_id: number }) => r.storyline_id === slId); - if (filtered.length === 0) return 0; - return filtered.reduce((s: number, r: { rating: number }) => s + r.rating, 0) / filtered.length; - } - - function countFromRows(rows: { storyline_id: number }[] | null, slId: number): number { - if (!rows) return 0; - return rows.filter((r: { storyline_id: number }) => r.storyline_id === slId).length; - } - - // Single parallel batch for all on-chain reads - const onChainResults = await Promise.all( - eligible.map((sl) => enrichWithOnChain(sl)), - ); - - const enriched = eligible.map((sl, i): RankedStoryline => { - const { priceChange, tvlRaw, tvlDecimals } = onChainResults[i]; - - // Recent window composite (all 4 signals) - const recentAvgRating = avgFromRows(recentRatings, sl.storyline_id); - const recentPlotCount = countFromRows(recentPlots, sl.storyline_id); - const recentScore = computeTrendScore( - recentAvgRating, - priceChange, - tvlRaw, - tvlDecimals, - recentPlotCount, - threeDaysAgo, - ); - - // Prior window composite (same 4 signals, same TVL + price as baseline) - const priorAvgRating = avgFromRows(priorRatings, sl.storyline_id); - const priorPlotCount = countFromRows(priorPlots, sl.storyline_id); - const priorScore = computeTrendScore( - priorAvgRating, - priceChange, // same baseline — acceleration from rating/plot signals - tvlRaw, // point-in-time, same for both windows - tvlDecimals, - priorPlotCount, - sixDaysAgo, - ); - - // Require minimum prior activity (at least 1 rating or 1 plot in prior window) - const hasPriorActivity = priorAvgRating > 0 || priorPlotCount > 0; - if (!hasPriorActivity) { - return { ...sl, trendScore: 0 }; - } - - // Rise = recent / prior (acceleration ratio) - const trendScore = recentScore / (priorScore + 0.01); - - return { ...sl, trendScore }; - }); - - enriched.sort((a, b) => b.trendScore - a.trendScore); - return enriched.filter((s) => s.trendScore > 1).slice(offset, offset + limit); -} diff --git a/src/app/page.tsx b/src/app/page.tsx index f6c6f2ac..f087dfee 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -1,6 +1,6 @@ import { createServerClient, type Storyline } from "../../lib/supabase"; import { STORY_FACTORY } from "../../lib/contracts/constants"; -import { getTrendingStorylines, getRisingStorylines } from "../../lib/ranking"; +import { getTrendingStorylines } from "../../lib/ranking"; import { StoryCard } from "../components/StoryCard"; import { FilterBar, type WriterFilterValue } from "../components/FilterBar"; import { GENRES, LANGUAGES } from "../../lib/genres"; @@ -8,7 +8,7 @@ import Link from "next/link"; export const revalidate = 120; -const TABS = ["new", "trending", "rising", "completed"] as const; +const TABS = ["new", "trending"] as const; type Tab = (typeof TABS)[number]; const WRITER_VALUES: WriterFilterValue[] = ["all", "human", "agent"]; @@ -148,21 +148,6 @@ async function queryTab( return data ?? []; } - case "completed": { - let q = supabase - .from("storylines") - .select("*") - .eq("hidden", false) - .eq("sunset", true) - .eq("contract_address", STORY_FACTORY.toLowerCase()); - q = applyFilters(q); - const { data } = await q - .order("plot_count", { ascending: false }) - .range(from, to) - .returns(); - return data ?? []; - } - case "trending": { const wt = writer === "human" ? 0 : writer === "agent" ? 1 : undefined; const g = genre !== "all" ? genre : undefined; @@ -170,11 +155,5 @@ async function queryTab( return getTrendingStorylines(supabase, PAGE_SIZE, wt, from, g, l); } - case "rising": { - const wt = writer === "human" ? 0 : writer === "agent" ? 1 : undefined; - const g = genre !== "all" ? genre : undefined; - const l = lang !== "all" ? lang : undefined; - return getRisingStorylines(supabase, PAGE_SIZE, wt, from, g, l); - } } } diff --git a/src/components/FilterBar.tsx b/src/components/FilterBar.tsx index d6157c9c..ad1c30cc 100644 --- a/src/components/FilterBar.tsx +++ b/src/components/FilterBar.tsx @@ -8,8 +8,6 @@ const WRITER_OPTIONS = ["All", "Human", "AI"] as const; const SORT_OPTIONS = [ { value: "new", label: "Recent" }, { value: "trending", label: "Trending" }, - { value: "rising", label: "Rising" }, - { value: "completed", label: "Completed" }, ] as const; export type WriterFilterValue = "all" | "human" | "agent";