feat(frontend): rewire dashboard to use AZ data endpoint

Main dashboard now uses /api/az/dashboard for dispensary, product, and
brand counts instead of the legacy /api/dashboard/stats endpoint. This
ensures the dashboard displays consistent data with the /az pages.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Kelly
2025-12-03 17:28:22 -07:00
parent cac414dafd
commit e234dc2947

View File

@@ -6,8 +6,7 @@ import {
Package, Package,
Target, Target,
Image as ImageIcon, Image as ImageIcon,
MousePointer, Tag,
Shield,
TrendingUp, TrendingUp,
TrendingDown, TrendingDown,
RefreshCw, RefreshCw,
@@ -62,12 +61,42 @@ export function Dashboard() {
const loadData = async () => { const loadData = async () => {
try { try {
const [statsData, activityData] = await Promise.all([ // Fetch AZ dashboard data (primary data source)
api.getDashboardStats(), const azDashboard = await api.getDutchieAZDashboard();
api.getDashboardActivity()
]); // Map AZ dashboard data to the expected stats format
setStats(statsData); setStats({
setActivity(activityData); products: {
total: azDashboard.productCount,
in_stock: azDashboard.productCount, // All AZ products are in stock by default
with_images: 0 // Not tracked in AZ pipeline
},
stores: {
total: azDashboard.dispensaryCount,
active: azDashboard.dispensaryCount // All are active in AZ
},
brands: {
total: azDashboard.brandCount
},
campaigns: {
active: 0,
total: 0
},
clicks: {
clicks_24h: azDashboard.snapshotCount24h // Use snapshots as activity metric
},
failedJobs: azDashboard.failedJobCount,
lastCrawlTime: azDashboard.lastCrawlTime
});
// Try to fetch activity data (may fail if not authenticated)
try {
const activityData = await api.getDashboardActivity();
setActivity(activityData);
} catch {
// Activity data requires auth, just skip it
setActivity(null);
}
} catch (error) { } catch (error) {
console.error('Failed to load dashboard:', error); console.error('Failed to load dashboard:', error);
} finally { } finally {
@@ -196,9 +225,9 @@ export function Dashboard() {
</div> </div>
</div> </div>
<div className="space-y-1"> <div className="space-y-1">
<p className="text-sm font-medium text-gray-600">Active Stores</p> <p className="text-sm font-medium text-gray-600">Total Dispensaries</p>
<p className="text-3xl font-semibold text-gray-900">{stats?.stores?.active || 0}</p> <p className="text-3xl font-semibold text-gray-900">{stats?.stores?.total || 0}</p>
<p className="text-xs text-gray-500">{stats?.stores?.total || 0} total stores</p> <p className="text-xs text-gray-500">{stats?.stores?.active || 0} active (crawlable)</p>
</div> </div>
</div> </div>
@@ -242,33 +271,33 @@ export function Dashboard() {
</div> </div>
</div> </div>
{/* Clicks */} {/* Snapshots (24h) */}
<div className="bg-white rounded-xl border border-gray-200 p-6"> <div className="bg-white rounded-xl border border-gray-200 p-6">
<div className="flex items-center justify-between mb-4"> <div className="flex items-center justify-between mb-4">
<div className="p-2 bg-cyan-50 rounded-lg"> <div className="p-2 bg-cyan-50 rounded-lg">
<MousePointer className="w-5 h-5 text-cyan-600" /> <Activity className="w-5 h-5 text-cyan-600" />
</div> </div>
<Clock className="w-4 h-4 text-gray-400" /> <Clock className="w-4 h-4 text-gray-400" />
</div> </div>
<div className="space-y-1"> <div className="space-y-1">
<p className="text-sm font-medium text-gray-600">Clicks (24h)</p> <p className="text-sm font-medium text-gray-600">Snapshots (24h)</p>
<p className="text-3xl font-semibold text-gray-900">{stats?.clicks?.clicks_24h?.toLocaleString() || 0}</p> <p className="text-3xl font-semibold text-gray-900">{stats?.clicks?.clicks_24h?.toLocaleString() || 0}</p>
<p className="text-xs text-gray-500">Last 24 hours</p> <p className="text-xs text-gray-500">Product snapshots created</p>
</div> </div>
</div> </div>
{/* Proxies */} {/* Brands */}
<div className="bg-white rounded-xl border border-gray-200 p-6"> <div className="bg-white rounded-xl border border-gray-200 p-6">
<div className="flex items-center justify-between mb-4"> <div className="flex items-center justify-between mb-4">
<div className="p-2 bg-indigo-50 rounded-lg"> <div className="p-2 bg-indigo-50 rounded-lg">
<Shield className="w-5 h-5 text-indigo-600" /> <Tag className="w-5 h-5 text-indigo-600" />
</div> </div>
<Activity className="w-4 h-4 text-gray-400" /> <Activity className="w-4 h-4 text-gray-400" />
</div> </div>
<div className="space-y-1"> <div className="space-y-1">
<p className="text-sm font-medium text-gray-600">Active Proxies</p> <p className="text-sm font-medium text-gray-600">Brands</p>
<p className="text-3xl font-semibold text-gray-900">{stats?.proxies?.active || 0}</p> <p className="text-3xl font-semibold text-gray-900">{stats?.brands?.total || stats?.products?.unique_brands || 0}</p>
<p className="text-xs text-gray-500">{stats?.proxies?.total || 0} total proxies</p> <p className="text-xs text-gray-500">Unique brands tracked</p>
</div> </div>
</div> </div>
</div> </div>