[dyad] wrote 3 file(s)
This commit is contained in:
parent
06cb8c1a6b
commit
bdbcf2d811
3 changed files with 93 additions and 26 deletions
|
|
@ -1,17 +1,18 @@
|
|||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
import { ResponsiveContainer, BarChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip, Legend } from 'recharts';
|
||||
|
||||
const data = [
|
||||
{ name: 'Jan', stockIn: 400, stockOut: 240 },
|
||||
{ name: 'Feb', stockIn: 300, stockOut: 139 },
|
||||
{ name: 'Mar', stockIn: 200, stockOut: 980 },
|
||||
{ name: 'Apr', stockIn: 278, stockOut: 390 },
|
||||
{ name: 'May', stockIn: 189, stockOut: 480 },
|
||||
{ name: 'Jun', stockIn: 239, stockOut: 380 },
|
||||
{ name: 'Jul', stockIn: 349, stockOut: 430 },
|
||||
];
|
||||
import { useDashboardData } from '@/hooks/useDashboardData';
|
||||
|
||||
const StockActivityChart = () => {
|
||||
const { monthlyActivityData, loading, error } = useDashboardData();
|
||||
|
||||
if (loading) {
|
||||
return <Card className="col-span-1"><CardContent className="h-80 flex items-center justify-center text-gray-500">Loading chart data...</CardContent></Card>;
|
||||
}
|
||||
|
||||
if (error) {
|
||||
return <Card className="col-span-1"><CardContent className="h-80 flex items-center justify-center text-red-500">Error loading chart: {error}</CardContent></Card>;
|
||||
}
|
||||
|
||||
return (
|
||||
<Card className="col-span-1">
|
||||
<CardHeader>
|
||||
|
|
@ -19,7 +20,7 @@ const StockActivityChart = () => {
|
|||
</CardHeader>
|
||||
<CardContent className="h-80">
|
||||
<ResponsiveContainer width="100%" height="100%">
|
||||
<BarChart data={data}>
|
||||
<BarChart data={monthlyActivityData}>
|
||||
<CartesianGrid strokeDasharray="3 3" />
|
||||
<XAxis dataKey="name" />
|
||||
<YAxis />
|
||||
|
|
|
|||
|
|
@ -1,17 +1,18 @@
|
|||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
import { ResponsiveContainer, LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, Legend } from 'recharts';
|
||||
|
||||
const data = [
|
||||
{ name: 'Jan', stockIn: 4000, stockOut: 2400 },
|
||||
{ name: 'Feb', stockIn: 3000, stockOut: 1398 },
|
||||
{ name: 'Mar', stockIn: 2000, stockOut: 9800 },
|
||||
{ name: 'Apr', stockIn: 2780, stockOut: 3908 },
|
||||
{ name: 'May', stockIn: 1890, stockOut: 4800 },
|
||||
{ name: 'Jun', stockIn: 2390, stockOut: 3800 },
|
||||
{ name: 'Jul', stockIn: 3490, stockOut: 4300 },
|
||||
];
|
||||
import { useDashboardData } from '@/hooks/useDashboardData';
|
||||
|
||||
const StockChart = () => {
|
||||
const { monthlyActivityData, loading, error } = useDashboardData();
|
||||
|
||||
if (loading) {
|
||||
return <Card className="col-span-1 lg:col-span-2"><CardContent className="h-80 flex items-center justify-center text-gray-500">Loading chart data...</CardContent></Card>;
|
||||
}
|
||||
|
||||
if (error) {
|
||||
return <Card className="col-span-1 lg:col-span-2"><CardContent className="h-80 flex items-center justify-center text-red-500">Error loading chart: {error}</CardContent></Card>;
|
||||
}
|
||||
|
||||
return (
|
||||
<Card className="col-span-1 lg:col-span-2">
|
||||
<CardHeader>
|
||||
|
|
@ -19,7 +20,7 @@ const StockChart = () => {
|
|||
</CardHeader>
|
||||
<CardContent className="h-80">
|
||||
<ResponsiveContainer width="100%" height="100%">
|
||||
<LineChart data={data}>
|
||||
<LineChart data={monthlyActivityData}>
|
||||
<CartesianGrid strokeDasharray="3 3" />
|
||||
<XAxis dataKey="name" />
|
||||
<YAxis />
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { useState, useEffect, useCallback } from "react";
|
||||
import pb from "@/lib/pocketbase";
|
||||
import { subDays } from "date-fns";
|
||||
import { subDays, format, startOfMonth, eachMonthOfInterval } from "date-fns";
|
||||
|
||||
interface DashboardStats {
|
||||
totalStockValue: string;
|
||||
|
|
@ -9,6 +9,12 @@ interface DashboardStats {
|
|||
lowStockAlerts: string;
|
||||
}
|
||||
|
||||
interface MonthlyActivity {
|
||||
name: string; // Month name, e.g., 'Jan'
|
||||
stockIn: number;
|
||||
stockOut: number;
|
||||
}
|
||||
|
||||
export function useDashboardData() {
|
||||
const [stats, setStats] = useState<DashboardStats>({
|
||||
totalStockValue: "R0.00",
|
||||
|
|
@ -16,6 +22,7 @@ export function useDashboardData() {
|
|||
stockOutLast30Days: "0",
|
||||
lowStockAlerts: "0",
|
||||
});
|
||||
const [monthlyActivityData, setMonthlyActivityData] = useState<MonthlyActivity[]>([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
|
|
@ -42,12 +49,12 @@ export function useDashboardData() {
|
|||
|
||||
// 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({
|
||||
const bookOutRecordsLast30Days = await pb.collection('book_out_records').getFullList({
|
||||
filter: `date_booked_out >= "${thirtyDaysAgo}"`,
|
||||
});
|
||||
|
||||
let calculatedStockOutLast30Days = 0;
|
||||
bookOutRecords.forEach((record: any) => {
|
||||
bookOutRecordsLast30Days.forEach((record: any) => {
|
||||
calculatedStockOutLast30Days += record.quantity;
|
||||
});
|
||||
|
||||
|
|
@ -60,6 +67,63 @@ export function useDashboardData() {
|
|||
stockOutLast30Days: calculatedStockOutLast30Days.toString(),
|
||||
lowStockAlerts: calculatedLowStockAlerts.toString(),
|
||||
});
|
||||
|
||||
// --- Monthly Activity Data for Charts ---
|
||||
const now = new Date();
|
||||
const twelveMonthsAgo = subDays(now, 365); // Roughly 12 months ago
|
||||
const monthsInterval = eachMonthOfInterval({
|
||||
start: startOfMonth(twelveMonthsAgo),
|
||||
end: startOfMonth(now),
|
||||
});
|
||||
|
||||
const monthlyDataMap = new Map<string, { stockIn: number; stockOut: number }>();
|
||||
|
||||
monthsInterval.forEach(month => {
|
||||
const monthKey = format(month, 'MMM'); // e.g., 'Jan', 'Feb'
|
||||
monthlyDataMap.set(monthKey, { stockIn: 0, stockOut: 0 });
|
||||
});
|
||||
|
||||
// Process stock items for 'stockIn' (based on creation date)
|
||||
stockRecords.forEach((item: any) => {
|
||||
const createdDate = new Date(item.created);
|
||||
if (createdDate >= twelveMonthsAgo) {
|
||||
const monthKey = format(createdDate, 'MMM');
|
||||
if (monthlyDataMap.has(monthKey)) {
|
||||
const current = monthlyDataMap.get(monthKey)!;
|
||||
current.stockIn += item.quantity;
|
||||
monthlyDataMap.set(monthKey, current);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Process all book out records for 'stockOut'
|
||||
const allBookOutRecords = await pb.collection('book_out_records').getFullList({
|
||||
sort: '-created',
|
||||
});
|
||||
|
||||
allBookOutRecords.forEach((record: any) => {
|
||||
const bookedOutDate = new Date(record.date_booked_out);
|
||||
if (bookedOutDate >= twelveMonthsAgo) {
|
||||
const monthKey = format(bookedOutDate, 'MMM');
|
||||
if (monthlyDataMap.has(monthKey)) {
|
||||
const current = monthlyDataMap.get(monthKey)!;
|
||||
current.stockOut += record.quantity;
|
||||
monthlyDataMap.set(monthKey, current);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Convert map to array, maintaining chronological order
|
||||
const sortedMonthlyData: MonthlyActivity[] = monthsInterval.map(month => {
|
||||
const monthKey = format(month, 'MMM');
|
||||
return {
|
||||
name: monthKey,
|
||||
...monthlyDataMap.get(monthKey),
|
||||
};
|
||||
});
|
||||
|
||||
setMonthlyActivityData(sortedMonthlyData);
|
||||
|
||||
} catch (err) {
|
||||
console.error("Failed to fetch dashboard data:", err);
|
||||
setError("Failed to load dashboard data.");
|
||||
|
|
@ -69,6 +133,7 @@ export function useDashboardData() {
|
|||
stockOutLast30Days: "0",
|
||||
lowStockAlerts: "0",
|
||||
});
|
||||
setMonthlyActivityData([]);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
|
|
@ -78,5 +143,5 @@ export function useDashboardData() {
|
|||
fetchDashboardStats();
|
||||
}, [fetchDashboardStats]);
|
||||
|
||||
return { stats, loading, error, refresh: fetchDashboardStats };
|
||||
return { stats, monthlyActivityData, loading, error, refresh: fetchDashboardStats };
|
||||
}
|
||||
Loading…
Reference in a new issue