Fix and restyle stock and purchases components

This commit is contained in:
2025-01-17 21:10:35 -05:00
parent de5bd785c1
commit f38174ca2a
3 changed files with 113 additions and 56 deletions

View File

@@ -83,17 +83,25 @@ const renderActiveShape = (props: any) => {
export function PurchaseMetrics() {
const [activeIndex, setActiveIndex] = useState<number | undefined>();
const { data } = useQuery<PurchaseMetricsData>({
const { data, error, isLoading } = useQuery<PurchaseMetricsData>({
queryKey: ["purchase-metrics"],
queryFn: async () => {
console.log('Fetching from:', `${config.apiUrl}/dashboard/purchase/metrics`);
const response = await fetch(`${config.apiUrl}/dashboard/purchase/metrics`)
if (!response.ok) {
throw new Error("Failed to fetch purchase metrics")
const text = await response.text();
console.error('API Error:', text);
throw new Error(`Failed to fetch purchase metrics: ${response.status} ${response.statusText}`);
}
return response.json()
const data = await response.json();
console.log('API Response:', data);
return data;
},
})
if (isLoading) return <div>Loading...</div>;
if (error) return <div>Error loading purchase metrics</div>;
return (
<>
<CardHeader>
@@ -108,41 +116,41 @@ export function PurchaseMetrics() {
<ClipboardList className="h-4 w-4 text-muted-foreground" />
<p className="text-sm font-medium text-muted-foreground">Active Purchase Orders</p>
</div>
<p className="text-2xl font-bold">{data?.activePurchaseOrders.toLocaleString() || 0}</p>
<p className="text-lg font-bold">{data?.activePurchaseOrders.toLocaleString() || 0}</p>
</div>
<div className="flex items-baseline justify-between">
<div className="flex items-center gap-2">
<AlertCircle className="h-4 w-4 text-muted-foreground" />
<p className="text-sm font-medium text-muted-foreground">Overdue Purchase Orders</p>
</div>
<p className="text-2xl font-bold">{data?.overduePurchaseOrders.toLocaleString() || 0}</p>
<p className="text-lg font-bold">{data?.overduePurchaseOrders.toLocaleString() || 0}</p>
</div>
<div className="flex items-baseline justify-between">
<div className="flex items-center gap-2">
<Layers className="h-4 w-4 text-muted-foreground" />
<p className="text-sm font-medium text-muted-foreground">On Order Units</p>
</div>
<p className="text-2xl font-bold">{data?.onOrderUnits.toLocaleString() || 0}</p>
<p className="text-lg font-bold">{data?.onOrderUnits.toLocaleString() || 0}</p>
</div>
<div className="flex items-baseline justify-between">
<div className="flex items-center gap-2">
<DollarSign className="h-4 w-4 text-muted-foreground" />
<p className="text-sm font-medium text-muted-foreground">On Order Cost</p>
</div>
<p className="text-2xl font-bold">{formatCurrency(data?.onOrderCost || 0)}</p>
<p className="text-lg font-bold">{formatCurrency(data?.onOrderCost || 0)}</p>
</div>
<div className="flex items-baseline justify-between">
<div className="flex items-center gap-2">
<ShoppingCart className="h-4 w-4 text-muted-foreground" />
<p className="text-sm font-medium text-muted-foreground">On Order Retail</p>
</div>
<p className="text-2xl font-bold">{formatCurrency(data?.onOrderRetail || 0)}</p>
<p className="text-lg font-bold">{formatCurrency(data?.onOrderRetail || 0)}</p>
</div>
</div>
</div>
<div className="flex-1">
<div className="flex flex-col">
<div className="text-lg flex justify-center font-medium mb-4">Purchase Orders By Vendor</div>
<div className="text-md flex justify-center font-medium">Purchase Orders By Vendor</div>
<div className="h-[200px]">
<ResponsiveContainer width="100%" height="100%">
<PieChart>

View File

@@ -3,7 +3,7 @@ import { CardHeader, CardTitle, CardContent } from "@/components/ui/card"
import { PieChart, Pie, ResponsiveContainer, Cell, Tooltip, Sector } from "recharts"
import config from "@/config"
import { formatCurrency } from "@/lib/utils"
import { Package, Layers, DollarSign, ShoppingCart } from "lucide-react" // Importing icons
import { Package, Layers, DollarSign, ShoppingCart } from "lucide-react"
import { useState } from "react"
interface StockMetricsData {
@@ -12,8 +12,8 @@ interface StockMetricsData {
totalStockUnits: number
totalStockCost: number
totalStockRetail: number
vendorStock: {
vendor: string
brandStock: {
brand: string
variants: number
units: number
cost: number
@@ -33,10 +33,10 @@ const COLORS = [
]
const renderActiveShape = (props: any) => {
const { cx, cy, innerRadius, vendor, cost } = props;
const { cx, cy, innerRadius, brand, retail } = props;
// Split vendor name into words and create lines of max 12 chars
const words = vendor.split(' ');
// Split brand name into words and create lines of max 12 chars
const words = brand.split(' ');
const lines: string[] = [];
let currentLine = '';
@@ -73,7 +73,7 @@ const renderActiveShape = (props: any) => {
fill="#000000"
className="text-base font-medium"
>
{formatCurrency(cost)}
{formatCurrency(retail)}
</text>
{props.children}
</g>
@@ -83,16 +83,24 @@ const renderActiveShape = (props: any) => {
export function StockMetrics() {
const [activeIndex, setActiveIndex] = useState<number | undefined>();
const { data } = useQuery<StockMetricsData>({
const { data, error, isLoading } = useQuery<StockMetricsData>({
queryKey: ["stock-metrics"],
queryFn: async () => {
const response = await fetch(`${config.apiUrl}/dashboard/stock/metrics`)
console.log('Fetching from:', `${config.apiUrl}/dashboard/stock/metrics`);
const response = await fetch(`${config.apiUrl}/dashboard/stock/metrics`);
if (!response.ok) {
throw new Error("Failed to fetch stock metrics")
const text = await response.text();
console.error('API Error:', text);
throw new Error(`Failed to fetch stock metrics: ${response.status} ${response.statusText}`);
}
return response.json()
const data = await response.json();
console.log('API Response:', data);
return data;
},
})
});
if (isLoading) return <div>Loading...</div>;
if (error) return <div>Error loading stock metrics</div>;
return (
<>
@@ -108,48 +116,48 @@ export function StockMetrics() {
<Package className="h-4 w-4 text-muted-foreground" />
<p className="text-sm font-medium text-muted-foreground">Products</p>
</div>
<p className="text-2xl font-bold">{data?.totalProducts.toLocaleString() || 0}</p>
<p className="text-lg font-bold">{data?.totalProducts.toLocaleString() || 0}</p>
</div>
<div className="flex items-baseline justify-between">
<div className="flex items-center gap-2">
<Layers className="h-4 w-4 text-muted-foreground" />
<p className="text-sm font-medium text-muted-foreground">Products In Stock</p>
</div>
<p className="text-2xl font-bold">{data?.productsInStock.toLocaleString() || 0}</p>
<p className="text-lg font-bold">{data?.productsInStock.toLocaleString() || 0}</p>
</div>
<div className="flex items-baseline justify-between">
<div className="flex items-center gap-2">
<Layers className="h-4 w-4 text-muted-foreground" />
<p className="text-sm font-medium text-muted-foreground">Stock Units</p>
</div>
<p className="text-2xl font-bold">{data?.totalStockUnits.toLocaleString() || 0}</p>
<p className="text-lg font-bold">{data?.totalStockUnits.toLocaleString() || 0}</p>
</div>
<div className="flex items-baseline justify-between">
<div className="flex items-center gap-2">
<DollarSign className="h-4 w-4 text-muted-foreground" />
<p className="text-sm font-medium text-muted-foreground">Stock Cost</p>
</div>
<p className="text-2xl font-bold">{formatCurrency(data?.totalStockCost || 0)}</p>
<p className="text-lg font-bold">{formatCurrency(data?.totalStockCost || 0)}</p>
</div>
<div className="flex items-baseline justify-between">
<div className="flex items-center gap-2">
<ShoppingCart className="h-4 w-4 text-muted-foreground" />
<p className="text-sm font-medium text-muted-foreground">Stock Retail</p>
</div>
<p className="text-2xl font-bold">{formatCurrency(data?.totalStockRetail || 0)}</p>
<p className="text-lg font-bold">{formatCurrency(data?.totalStockRetail || 0)}</p>
</div>
</div>
</div>
<div className="flex-1">
<div className="flex flex-col">
<div className="text-lg flex justify-center font-medium mb-4">Stock Retail By Brand</div>
<div className="text-md flex justify-center font-medium ">Stock Retail By Brand</div>
<div className="h-[200px]">
<ResponsiveContainer width="100%" height="100%">
<PieChart>
<Pie
data={data?.vendorStock || []}
dataKey="cost"
nameKey="vendor"
data={data?.brandStock || []}
dataKey="retail"
nameKey="brand"
cx="50%"
cy="50%"
innerRadius={60}
@@ -160,10 +168,11 @@ export function StockMetrics() {
onMouseEnter={(_, index) => setActiveIndex(index)}
onMouseLeave={() => setActiveIndex(undefined)}
>
{data?.vendorStock?.map((entry, index) => (
{data?.brandStock?.map((entry, index) => (
<Cell
key={entry.vendor}
fill={COLORS[index % COLORS.length]}
key={entry.brand}
fill={COLORS[index % COLORS.length]}
style={{ filter: activeIndex === index ? 'brightness(1.2)' : undefined }}
/>
))}
</Pie>