Fix trends count mismatch between TrendsPage and sidebar (ditto#45)

This commit is contained in:
Alex Gleason
2026-03-16 17:39:18 -05:00
parent d7c55aa7d4
commit 6570d7d901
+61 -29
View File
@@ -1,25 +1,29 @@
import { useSeoMeta } from '@unhead/react';
import { useAppContext } from '@/hooks/useAppContext';
import { Flame, TrendingUp, Swords, Loader2 } from 'lucide-react';
import { useState, useMemo, useEffect } from 'react';
import { useInView } from 'react-intersection-observer';
import { Link } from 'react-router-dom';
import { NoteCard } from '@/components/NoteCard';
import { Skeleton } from '@/components/ui/skeleton';
import { useTrendingTags, useInfiniteSortedPosts, type SortMode } from '@/hooks/useTrending';
import { useMuteList } from '@/hooks/useMuteList';
import { isEventMuted } from '@/lib/muteHelpers';
import { cn } from '@/lib/utils';
import { useSeoMeta } from "@unhead/react";
import { Flame, Loader2, Swords, TrendingUp } from "lucide-react";
import { useEffect, useMemo, useState } from "react";
import { useInView } from "react-intersection-observer";
import { Link } from "react-router-dom";
import { NoteCard } from "@/components/NoteCard";
import { Skeleton } from "@/components/ui/skeleton";
import { useAppContext } from "@/hooks/useAppContext";
import { useMuteList } from "@/hooks/useMuteList";
import {
type SortMode,
useInfiniteSortedPosts,
useTrendingTags,
} from "@/hooks/useTrending";
import { isEventMuted } from "@/lib/muteHelpers";
import { cn } from "@/lib/utils";
export function TrendsPage() {
const { config } = useAppContext();
useSeoMeta({
title: `Trends | ${config.appName}`,
description: 'Trending hashtags and posts on Nostr',
description: "Trending hashtags and posts on Nostr",
});
const [trendSort, setTrendSort] = useState<SortMode>('hot');
const [trendSort, setTrendSort] = useState<SortMode>("hot");
const { data: trends, isLoading: trendsLoading } = useTrendingTags(true);
const {
@@ -35,18 +39,21 @@ export function TrendsPage() {
// Flatten, deduplicate, and filter muted posts from paginated sorted results
const sortedPosts = useMemo(() => {
const seen = new Set<string>();
return sortedData?.pages.flat().filter((event) => {
if (seen.has(event.id)) return false;
seen.add(event.id);
if (muteItems.length > 0 && isEventMuted(event, muteItems)) return false;
return true;
}) ?? [];
return (
sortedData?.pages.flat().filter((event) => {
if (seen.has(event.id)) return false;
seen.add(event.id);
if (muteItems.length > 0 && isEventMuted(event, muteItems))
return false;
return true;
}) ?? []
);
}, [sortedData?.pages, muteItems]);
// Intersection observer for infinite scroll on sorted posts
const { ref: sortedScrollRef, inView: sortedInView } = useInView({
threshold: 0,
rootMargin: '400px',
rootMargin: "400px",
});
useEffect(() => {
@@ -78,7 +85,10 @@ export function TrendsPage() {
) : trends && trends.tags.length > 0 ? (
<div className="flex flex-wrap gap-2 px-4 pb-4">
{trends.tags.slice(0, 5).map((trend, index) => (
<TrendItem key={index} trend={{ tag: trend.tag, count: trend.uses }} />
<TrendItem
key={index}
trend={{ tag: trend.tag, count: trend.accounts }}
/>
))}
</div>
) : (
@@ -87,9 +97,24 @@ export function TrendsPage() {
{/* Sort sub-tabs */}
<div className="flex border-b border-border">
<SortTabButton icon={<Flame className="size-4" />} label="Hot" active={trendSort === 'hot'} onClick={() => setTrendSort('hot')} />
<SortTabButton icon={<TrendingUp className="size-4" />} label="Rising" active={trendSort === 'rising'} onClick={() => setTrendSort('rising')} />
<SortTabButton icon={<Swords className="size-4" />} label="Controversial" active={trendSort === 'controversial'} onClick={() => setTrendSort('controversial')} />
<SortTabButton
icon={<Flame className="size-4" />}
label="Hot"
active={trendSort === "hot"}
onClick={() => setTrendSort("hot")}
/>
<SortTabButton
icon={<TrendingUp className="size-4" />}
label="Rising"
active={trendSort === "rising"}
onClick={() => setTrendSort("rising")}
/>
<SortTabButton
icon={<Swords className="size-4" />}
label="Controversial"
active={trendSort === "controversial"}
onClick={() => setTrendSort("controversial")}
/>
</div>
{/* Sorted posts — infinite scroll */}
@@ -121,7 +146,12 @@ export function TrendsPage() {
);
}
function SortTabButton({ icon, label, active, onClick }: {
function SortTabButton({
icon,
label,
active,
onClick,
}: {
icon: React.ReactNode;
label: string;
active: boolean;
@@ -131,8 +161,8 @@ function SortTabButton({ icon, label, active, onClick }: {
<button
onClick={onClick}
className={cn(
'flex-1 py-2.5 flex items-center justify-center gap-1.5 text-sm font-medium transition-colors relative hover:bg-secondary/40',
active ? 'text-foreground' : 'text-muted-foreground',
"flex-1 py-2.5 flex items-center justify-center gap-1.5 text-sm font-medium transition-colors relative hover:bg-secondary/40",
active ? "text-foreground" : "text-muted-foreground",
)}
>
{icon}
@@ -152,7 +182,9 @@ function TrendItem({ trend }: { trend: { tag: string; count: number } }) {
>
#{trend.tag}
{trend.count > 0 && (
<span className="text-xs text-muted-foreground font-normal">{trend.count}</span>
<span className="text-xs text-muted-foreground font-normal">
{trend.count}
</span>
)}
</Link>
);