Fix trends count mismatch between TrendsPage and sidebar (ditto#45)
This commit is contained in:
+61
-29
@@ -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>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user