Fix and restyle stock and purchases components
This commit is contained in:
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user