fe(fe): enrich dashboard Top Reacted Messages

Show relative time, always-on username with channel context, and
collapse top emojis to two; add VIEW ALL toggle to reveal all 20
fetched reactions instead of the top 4.
This commit is contained in:
asepharyana committed 2026-09-23 23:56:02 +07:00
1 parent b12eb0a038
commit 8583bcdf17
1 file changed
+57 -36
@@ -13,7 +13,7 @@ import {
Zap, Zap,
} from "lucide-react"; } from "lucide-react";
import Link from "next/link"; import Link from "next/link";
import { useEffect } from "react"; import { useEffect, useState } from "react";
import { useAmbient } from "@/components/ambient/ambient-context"; import { useAmbient } from "@/components/ambient/ambient-context";
import { AreaActivity, RadialGauge } from "@/components/charts"; import { AreaActivity, RadialGauge } from "@/components/charts";
import { GlassPanel } from "@/components/primitives"; import { GlassPanel } from "@/components/primitives";
@@ -28,7 +28,7 @@ import {
} from "@/components/shared"; } from "@/components/shared";
import { useActivity, useStats, useTopReactions } from "@/hooks"; import { useActivity, useStats, useTopReactions } from "@/hooks";
import { useStaggerReveal } from "@/hooks/use-gsap-animation"; import { useStaggerReveal } from "@/hooks/use-gsap-animation";
import { formatNumber } from "@/lib/format"; import { formatNumber, formatRelativeTime } from "@/lib/format";
import type { DashboardStats } from "@/lib/types"; import type { DashboardStats } from "@/lib/types";
import { staggerDelay } from "@/lib/utils"; import { staggerDelay } from "@/lib/utils";
@@ -65,6 +65,7 @@ export function DashboardView({
} = useStats(initialStats); } = useStats(initialStats);
const { data: activity } = useActivity(14, initialActivity); const { data: activity } = useActivity(14, initialActivity);
const { data: reactions } = useTopReactions(); const { data: reactions } = useTopReactions();
const [showAllReactions, setShowAllReactions] = useState(false);
const ambient = useAmbient(); const ambient = useAmbient();
const hudRef = useStaggerReveal<HTMLDivElement>(".linear-tile", { const hudRef = useStaggerReveal<HTMLDivElement>(".linear-tile", {
@@ -359,44 +360,64 @@ export function DashboardView({
<SectionHeader <SectionHeader
eyebrow="Engagement" eyebrow="Engagement"
title="Top Reacted Messages" title="Top Reacted Messages"
action={
<button
type="button"
onClick={() => setShowAllReactions((v) => !v)}
className="font-mono text-[10px] text-ink-muted transition-colors hover:text-ink"
>
{showAllReactions
? "SHOW TOP 4"
: `VIEW ALL ${reactions.length}`}
</button>
}
/> />
<div className="mt-3 space-y-2"> <div className="mt-3 space-y-2">
{reactions.slice(0, 4).map((r) => ( {(showAllReactions ? reactions : reactions.slice(0, 4)).map(
<div (r) => (
key={r.message_id} <div
className="hud-card flex items-start justify-between gap-2 p-2.5" key={r.message_id}
> className="hud-card flex items-start justify-between gap-2 p-2.5"
<div className="min-w-0 flex-1"> >
<span className="line-clamp-1 block text-xs text-ink-soft"> <div className="min-w-0 flex-1">
{r.content || "[Media/Attachment]"} <span className="line-clamp-1 block text-xs text-ink-soft">
</span> {r.content || "[Media/Attachment]"}
{r.username && (
<span className="mt-0.5 block font-mono text-[10px] text-ink-muted">
@{r.username}
{r.channel_name && ` in #${r.channel_name}`}
</span> </span>
)} <span className="mt-0.5 block font-mono text-[10px] text-ink-muted">
@{r.username || "unknown"}
{r.channel_name && ` in #${r.channel_name}`}
{r.created_at != null && (
<>
{" "}
·{" "}
<span suppressHydrationWarning>
{formatRelativeTime(r.created_at)}
</span>
</>
)}
</span>
</div>
<div className="shrink-0 text-right">
<span className="font-mono text-xs font-semibold text-signal">
{formatNumber(r.reaction_count)}
</span>
{r.top_emojis && r.top_emojis.length > 0 && (
<div className="mt-0.5 flex gap-0.5">
{r.top_emojis.slice(0, 2).map((e) => (
<span
key={e.emoji}
className="text-[10px]"
title={`${e.emoji} ×${e.count}`}
>
{e.emoji}
</span>
))}
</div>
)}
</div>
</div> </div>
<div className="shrink-0 text-right"> ),
<span className="font-mono text-xs font-semibold text-signal"> )}
{formatNumber(r.reaction_count)}
</span>
{r.top_emojis && r.top_emojis.length > 0 && (
<div className="mt-0.5 flex gap-0.5">
{r.top_emojis.map((e) => (
<span
key={e.emoji}
className="text-[10px]"
title={`${e.emoji} ×${e.count}`}
>
{e.emoji}
</span>
))}
</div>
)}
</div>
</div>
))}
</div> </div>
</GlassPanel> </GlassPanel>
)} )}