From 06cb8c1a6b855246c6f83866c796f007c709cfaf Mon Sep 17 00:00:00 2001 From: "[dyad]" Date: Wed, 10 Sep 2025 13:20:17 +0200 Subject: [PATCH] [dyad] Updated dashboard to display dynamic data from PocketBase - wrote 2 file(s) --- src/hooks/useDashboardData.ts | 82 +++++++++++++++++++++++++++++++++++ src/pages/Index.tsx | 20 +++++++-- 2 files changed, 98 insertions(+), 4 deletions(-) create mode 100644 src/hooks/useDashboardData.ts diff --git a/src/hooks/useDashboardData.ts b/src/hooks/useDashboardData.ts new file mode 100644 index 0000000..4bc9088 --- /dev/null +++ b/src/hooks/useDashboardData.ts @@ -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({ + totalStockValue: "R0.00", + totalItemsInStock: "0", + stockOutLast30Days: "0", + lowStockAlerts: "0", + }); + const [loading, setLoading] = useState(true); + const [error, setError] = useState(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 }; +} \ No newline at end of file diff --git a/src/pages/Index.tsx b/src/pages/Index.tsx index caeacb2..51e7543 100644 --- a/src/pages/Index.tsx +++ b/src/pages/Index.tsx @@ -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
Loading dashboard data...
; + } + + if (error) { + return
Error: {error}
; + } + return (
} iconBgColor="bg-slate-blue" /> } iconBgColor="bg-teal-accent" /> } iconBgColor="bg-slate-blue" /> } iconBgColor="bg-primary-dark" />
+ {/* These charts still use static data. We can update them in a future request if needed! */}