refactor(fe): replace TanStack Query with SWR + UI/data cleanup
Build & Deploy (Nix) / build-and-deploy (backend) (push) Successful in 2m56s
Build & Deploy (Nix) / build-and-deploy (discord-gateway) (push) Successful in 3m42s
Build & Deploy (Nix) / build-and-deploy (proxy) (push) Successful in 3m59s

Rombak data layer frontend:
- Hapus @tanstack/react-query (package.json, lockfile, provider di
  dashboard layout) — ganti SWR 2.4.2 + SWRConfig (revalidateOnFocus
  false, deduping 10s, no retry on 404)
- Semua hooks data ditulis ulang ke useSWR; useAction() helper baru
  pengganti useMutation dengan surface kompatibel (mutate/mutateAsync/
  isPending/error)
- useMessages + useMessagesHasMore share satu SWR key — probe cursor
  yang tadinya dobel fetch API sekarang deduped
- WS sync (messages/media/recordings) pindah dari queryClient ke
  SWR mutate dengan filter key + revalidate:false
- useMessageSearch() dipakai search-panel & search-overlay; search
  overlay backdrop div -> button (fix a11y lint)

Rapikan UI + isi data:
- Tab stats recordings: placeholder 'coming soon' diganti stat asli
  (total, ukuran, speaker unik, top speakers)
- Empty states konsisten via EmptyState (images/review/recordings),
  EmptyState terima className
- biome check --write: 0 error, 8 warning pre-existing
- Verifikasi: tsc --noEmit PASS, next build PASS (11 halaman static),
  API live dicek — semua endpoint dashboard/messages/guilds/config/
  voice/media/recordings/review balikin data
This commit is contained in:
asepharyana
2026-08-01 09:19:39 +07:00
parent 1f91f99de3
commit 01c18b2060
26 changed files with 5145 additions and 329 deletions
@@ -1,9 +1,9 @@
"use client";
import { type LucideIcon } from "lucide-react";
import type { LucideIcon } from "lucide-react";
import { Area, AreaChart, ResponsiveContainer } from "recharts";
import { GlassCard } from "@/components/glass/card";
import { cn } from "@/lib/utils";
import { Area, AreaChart, ResponsiveContainer } from "recharts";
interface StatCardProps {
label: string;
@@ -43,7 +43,10 @@ export function StatCard({
<Icon className="size-4" />
</div>
</div>
<div className="text-2xl font-mono font-semibold tracking-tight" style={{ color: accentColor }}>
<div
className="text-2xl font-mono font-semibold tracking-tight"
style={{ color: accentColor }}
>
{formatter(numValue)}
</div>
<div className="text-[11px] text-text-secondary font-medium mt-0.5 tracking-wide uppercase">
@@ -56,7 +59,13 @@ export function StatCard({
<ResponsiveContainer width="100%" height="100%">
<AreaChart data={sparklineData}>
<defs>
<linearGradient id={`spark-grad-${label}`} x1="0" y1="0" x2="0" y2="1">
<linearGradient
id={`spark-grad-${label}`}
x1="0"
y1="0"
x2="0"
y2="1"
>
<stop offset="0%" stopColor={accentColor} stopOpacity={0.5} />
<stop offset="100%" stopColor={accentColor} stopOpacity={0} />
</linearGradient>