[dyad] Updated dashboard to display dynamic data from PocketBase - wrote 2 file(s)

This commit is contained in:
[dyad] 2025-09-10 13:20:17 +02:00
parent f48d7fdb2f
commit 06cb8c1a6b
2 changed files with 98 additions and 4 deletions

View file

@ -0,0 +1,82 @@
import { useState, useEffect, useCallback } from "react";
import pb from "@/lib/pocketbase";
import { subDays } from "date-fns";
interface DashboardStats {
totalStockValue: string;
totalItemsInStock: string;
stockOutLast30Days: string;
lowStockAlerts: string;
}
export function useDashboardData() {
const [stats, setStats] = useState<DashboardStats>({
totalStockValue: "R0.00",
totalItemsInStock: "0",
stockOutLast30Days: "0",
lowStockAlerts: "0",
});
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
const fetchDashboardStats = useCallback(async () => {
setLoading(true);
setError(null);
try {
// Fetch all stock items
const stockRecords = await pb.collection('stock_items').getFullList({
sort: '-created',
});
let calculatedTotalStockValue = 0;
let calculatedTotalItemsInStock = 0;
let calculatedLowStockAlerts = 0;
stockRecords.forEach((item: any) => {
calculatedTotalStockValue += (item.quantity * item.cost_price);
calculatedTotalItemsInStock += item.quantity;
if (item.quantity < 10) { // Define low stock threshold as < 10
calculatedLowStockAlerts++;
}
});
// Fetch book out records for the last 30 days
const thirtyDaysAgo = subDays(new Date(), 30).toISOString();
const bookOutRecords = await pb.collection('book_out_records').getFullList({
filter: `date_booked_out >= "${thirtyDaysAgo}"`,
});
let calculatedStockOutLast30Days = 0;
bookOutRecords.forEach((record: any) => {
calculatedStockOutLast30Days += record.quantity;
});
setStats({
totalStockValue: new Intl.NumberFormat("en-ZA", {
style: "currency",
currency: "ZAR",
}).format(calculatedTotalStockValue),
totalItemsInStock: calculatedTotalItemsInStock.toString(),
stockOutLast30Days: calculatedStockOutLast30Days.toString(),
lowStockAlerts: calculatedLowStockAlerts.toString(),
});
} catch (err) {
console.error("Failed to fetch dashboard data:", err);
setError("Failed to load dashboard data.");
setStats({
totalStockValue: "R0.00",
totalItemsInStock: "0",
stockOutLast30Days: "0",
lowStockAlerts: "0",
});
} finally {
setLoading(false);
}
}, []);
useEffect(() => {
fetchDashboardStats();
}, [fetchDashboardStats]);
return { stats, loading, error, refresh: fetchDashboardStats };
}

View file

@ -2,37 +2,49 @@ import StatCard from '@/components/StatCard';
import StockChart from '@/components/StockChart';
import StockActivityChart from '@/components/StockActivityChart';
import { DollarSign, Package, ArrowDown, AlertTriangle } from 'lucide-react';
import { useDashboardData } from '@/hooks/useDashboardData'; // Import the new hook
const Index = () => {
const { stats, loading, error } = useDashboardData();
if (loading) {
return <div className="text-center text-gray-500">Loading dashboard data...</div>;
}
if (error) {
return <div className="text-center text-red-500">Error: {error}</div>;
}
return (
<div className="space-y-8">
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-4">
<StatCard
title="Total Stock Value"
value="R2,253,478.35"
value={stats.totalStockValue}
icon={<DollarSign className="h-6 w-6 text-white" />}
iconBgColor="bg-slate-blue"
/>
<StatCard
title="Items in Stock"
value="2,350"
value={stats.totalItemsInStock}
icon={<Package className="h-6 w-6 text-white" />}
iconBgColor="bg-teal-accent"
/>
<StatCard
title="Stock Out (30 days)"
value="924"
value={stats.stockOutLast30Days}
icon={<ArrowDown className="h-6 w-6 text-white" />}
iconBgColor="bg-slate-blue"
/>
<StatCard
title="Low Stock Alerts"
value="12"
value={stats.lowStockAlerts}
icon={<AlertTriangle className="h-6 w-6 text-white" />}
iconBgColor="bg-primary-dark"
/>
</div>
<div className="grid gap-8 md:grid-cols-1 lg:grid-cols-3">
{/* These charts still use static data. We can update them in a future request if needed! */}
<StockChart />
<StockActivityChart />
</div>