Fix stats bar counts — use /api/stats endpoint instead of page slice

Added /api/stats to backend (returns route counts + total, respects
same search/category/route filters as the main query). StatsBar now
shows accurate counts across all records, not just the current page.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Maddox 2026-04-08 18:03:41 -04:00
parent e97f620dff
commit 5fc745edd3
3 changed files with 27 additions and 18 deletions

View file

@ -1,7 +1,7 @@
import { useState, useCallback } from 'react'
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
import { Plus, LayoutGrid, Table2, ShoppingBag } from 'lucide-react'
import { fetchStores, fetchFilters, createStore, updateStore, deleteStore } from './api'
import { fetchStores, fetchFilters, fetchStats, createStore, updateStore, deleteStore } from './api'
import type { Store, StoreFilters } from './types'
import { StatsBar } from './components/StatsBar'
import { FilterBar } from './components/FilterBar'
@ -72,6 +72,15 @@ export default function App() {
staleTime: 60_000,
})
const { data: statsData } = useQuery({
queryKey: ['stats', filters.search, filters.category, filters.route],
queryFn: () => fetchStats({
search: filters.search,
category: filters.category,
route: filters.route,
}),
})
const createMut = useMutation({
mutationFn: createStore,
onSuccess: () => {
@ -163,7 +172,7 @@ export default function App() {
</header>
<main className="max-w-7xl mx-auto px-4 py-5 space-y-4">
<StatsBar stores={stores} total={pagination?.total ?? 0} />
<StatsBar stats={statsData} />
<FilterBar
filters={filters}

View file

@ -13,6 +13,13 @@ export async function fetchFilters(): Promise<FiltersResponse> {
return data
}
export async function fetchStats(params: Record<string, string> = {}): Promise<{
auto: number; ask: number; verify: number; ignore: number; total: number
}> {
const { data } = await client.get('/stats', { params })
return data
}
export async function createStore(payload: Omit<Store, 'id' | 'created_at'>): Promise<{ id: number }> {
const { data } = await client.post('/stores', payload)
return data

View file

@ -1,28 +1,21 @@
import { Database, Zap, HelpCircle, CheckCircle, EyeOff } from 'lucide-react'
import type { Store } from '../types'
interface Props {
stores: Store[]
total: number
stats: { auto: number; ask: number; verify: number; ignore: number; total: number } | undefined
}
export function StatsBar({ stores, total }: Props) {
const counts = stores.reduce(
(acc, s) => ({ ...acc, [s.route]: (acc[s.route as keyof typeof acc] ?? 0) + 1 }),
{ auto: 0, ask: 0, verify: 0, ignore: 0 } as Record<string, number>
)
const stats = [
{ label: 'Total', value: total, icon: Database, color: 'text-slate-400' },
{ label: 'Auto', value: counts.auto, icon: Zap, color: 'text-green-400' },
{ label: 'Ask', value: counts.ask, icon: HelpCircle, color: 'text-amber-400' },
{ label: 'Verify', value: counts.verify, icon: CheckCircle, color: 'text-blue-400' },
{ label: 'Ignore', value: counts.ignore, icon: EyeOff, color: 'text-slate-500' },
export function StatsBar({ stats }: Props) {
const entries = [
{ label: 'Total', value: stats?.total ?? 0, icon: Database, color: 'text-slate-400' },
{ label: 'Auto', value: stats?.auto ?? 0, icon: Zap, color: 'text-green-400' },
{ label: 'Ask', value: stats?.ask ?? 0, icon: HelpCircle, color: 'text-amber-400' },
{ label: 'Verify', value: stats?.verify ?? 0, icon: CheckCircle, color: 'text-blue-400' },
{ label: 'Ignore', value: stats?.ignore ?? 0, icon: EyeOff, color: 'text-slate-500' },
]
return (
<div className="grid grid-cols-2 sm:grid-cols-5 gap-2">
{stats.map(({ label, value, icon: Icon, color }) => (
{entries.map(({ label, value, icon: Icon, color }) => (
<div key={label} className="glass rounded-xl px-4 py-3 flex items-center gap-3">
<Icon size={16} className={`${color} shrink-0`} />
<div>