Rearrange component contents to match IP
This commit is contained in:
@@ -53,16 +53,19 @@ export function BestSellers() {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
<CardTitle className="text-lg font-medium">Best Sellers</CardTitle>
|
<div className="flex flex-row items-center justify-between">
|
||||||
|
<CardTitle className="text-lg font-medium">Best Sellers</CardTitle>
|
||||||
|
<Tabs defaultValue="products">
|
||||||
|
<TabsList>
|
||||||
|
<TabsTrigger value="products">Products</TabsTrigger>
|
||||||
|
<TabsTrigger value="vendors">Vendors</TabsTrigger>
|
||||||
|
<TabsTrigger value="categories">Categories</TabsTrigger>
|
||||||
|
</TabsList>
|
||||||
|
</Tabs>
|
||||||
|
</div>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent>
|
<CardContent>
|
||||||
<Tabs defaultValue="products">
|
<Tabs defaultValue="products">
|
||||||
<TabsList className="mb-4">
|
|
||||||
<TabsTrigger value="products">Products</TabsTrigger>
|
|
||||||
<TabsTrigger value="vendors">Vendors</TabsTrigger>
|
|
||||||
<TabsTrigger value="categories">Categories</TabsTrigger>
|
|
||||||
</TabsList>
|
|
||||||
|
|
||||||
<TabsContent value="products">
|
<TabsContent value="products">
|
||||||
<ScrollArea className="h-[400px] w-full">
|
<ScrollArea className="h-[400px] w-full">
|
||||||
<Table>
|
<Table>
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@
|
|||||||
import { useState } from "react"
|
import { useState } from "react"
|
||||||
import config from "@/config"
|
import config from "@/config"
|
||||||
import { formatCurrency } from "@/lib/utils"
|
import { formatCurrency } from "@/lib/utils"
|
||||||
|
import { TrendingUp, DollarSign } from "lucide-react" // Importing icons
|
||||||
|
|
||||||
interface ForecastData {
|
interface ForecastData {
|
||||||
forecastSales: number
|
forecastSales: number
|
||||||
@@ -41,7 +42,7 @@ export function ForecastMetrics() {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<CardHeader className="flex flex-row items-center justify-between">
|
<CardHeader className="flex flex-row items-center justify-between">
|
||||||
<CardTitle className="text-lg font-medium">Sales Forecast</CardTitle>
|
<CardTitle className="text-xl font-medium">Forecast</CardTitle>
|
||||||
<Select value={period} onValueChange={setPeriod}>
|
<Select value={period} onValueChange={setPeriod}>
|
||||||
<SelectTrigger className="w-[120px]">
|
<SelectTrigger className="w-[120px]">
|
||||||
<SelectValue placeholder="Select period" />
|
<SelectValue placeholder="Select period" />
|
||||||
@@ -56,13 +57,19 @@ export function ForecastMetrics() {
|
|||||||
</Select>
|
</Select>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent>
|
<CardContent>
|
||||||
<div className="grid grid-cols-2 gap-4 mb-6">
|
<div className="flex flex-col gap-4">
|
||||||
<div>
|
<div className="flex items-baseline justify-between">
|
||||||
<p className="text-sm font-medium text-muted-foreground">Forecast Sales</p>
|
<div className="flex items-center gap-2">
|
||||||
|
<TrendingUp className="h-4 w-4 text-muted-foreground" />
|
||||||
|
<p className="text-sm font-medium text-muted-foreground">Forecast Sales</p>
|
||||||
|
</div>
|
||||||
<p className="text-2xl font-bold">{data?.forecastSales.toLocaleString() || 0}</p>
|
<p className="text-2xl font-bold">{data?.forecastSales.toLocaleString() || 0}</p>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div className="flex items-baseline justify-between">
|
||||||
<p className="text-sm font-medium text-muted-foreground">Forecast Revenue</p>
|
<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">Forecast Revenue</p>
|
||||||
|
</div>
|
||||||
<p className="text-2xl font-bold">{formatCurrency(data?.forecastRevenue || 0)}</p>
|
<p className="text-2xl font-bold">{formatCurrency(data?.forecastRevenue || 0)}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { useQuery } from "@tanstack/react-query"
|
import { useQuery } from "@tanstack/react-query"
|
||||||
import { CardHeader, CardTitle, CardContent } from "@/components/ui/card"
|
import { CardHeader, CardTitle, CardContent } from "@/components/ui/card"
|
||||||
import { BarChart, Bar, ResponsiveContainer, XAxis, YAxis, Tooltip } from "recharts"
|
|
||||||
import config from "@/config"
|
import config from "@/config"
|
||||||
import { formatCurrency } from "@/lib/utils"
|
import { formatCurrency } from "@/lib/utils"
|
||||||
|
import { Package, Layers, DollarSign, ShoppingCart } from "lucide-react"
|
||||||
|
|
||||||
interface OverstockMetricsData {
|
interface OverstockMetricsData {
|
||||||
overstockedProducts: number
|
overstockedProducts: number
|
||||||
@@ -32,71 +32,39 @@ export function OverstockMetrics() {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
<CardTitle className="text-lg font-medium">Overstock Overview</CardTitle>
|
<CardTitle className="text-xl font-medium">Overstock</CardTitle>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent>
|
<CardContent>
|
||||||
<div className="grid grid-cols-2 gap-4 mb-6">
|
<div className="flex flex-col gap-4">
|
||||||
<div>
|
<div className="flex items-baseline justify-between">
|
||||||
<p className="text-sm font-medium text-muted-foreground">Overstocked Products</p>
|
<div className="flex items-center gap-2">
|
||||||
|
<Package className="h-4 w-4 text-muted-foreground" />
|
||||||
|
<p className="text-sm font-medium text-muted-foreground">Overstocked Products</p>
|
||||||
|
</div>
|
||||||
<p className="text-2xl font-bold">{data?.overstockedProducts.toLocaleString() || 0}</p>
|
<p className="text-2xl font-bold">{data?.overstockedProducts.toLocaleString() || 0}</p>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div className="flex items-baseline justify-between">
|
||||||
<p className="text-sm font-medium text-muted-foreground">Overstocked Units</p>
|
<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">Overstocked Units</p>
|
||||||
|
</div>
|
||||||
<p className="text-2xl font-bold">{data?.overstockedUnits.toLocaleString() || 0}</p>
|
<p className="text-2xl font-bold">{data?.overstockedUnits.toLocaleString() || 0}</p>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div className="flex items-baseline justify-between">
|
||||||
<p className="text-sm font-medium text-muted-foreground">Total Cost</p>
|
<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">Overstocked Cost</p>
|
||||||
|
</div>
|
||||||
<p className="text-2xl font-bold">{formatCurrency(data?.overstockedCost || 0)}</p>
|
<p className="text-2xl font-bold">{formatCurrency(data?.overstockedCost || 0)}</p>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div className="flex items-baseline justify-between">
|
||||||
<p className="text-sm font-medium text-muted-foreground">Total Retail</p>
|
<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">Overstocked Retail</p>
|
||||||
|
</div>
|
||||||
<p className="text-2xl font-bold">{formatCurrency(data?.overstockedRetail || 0)}</p>
|
<p className="text-2xl font-bold">{formatCurrency(data?.overstockedRetail || 0)}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="h-[300px] w-full">
|
|
||||||
<ResponsiveContainer width="100%" height="100%">
|
|
||||||
<BarChart data={data?.overstockByCategory || []}>
|
|
||||||
<XAxis
|
|
||||||
dataKey="category"
|
|
||||||
tickLine={false}
|
|
||||||
axisLine={false}
|
|
||||||
fontSize={12}
|
|
||||||
/>
|
|
||||||
<YAxis
|
|
||||||
tickLine={false}
|
|
||||||
axisLine={false}
|
|
||||||
fontSize={12}
|
|
||||||
tickFormatter={(value) => value.toLocaleString()}
|
|
||||||
/>
|
|
||||||
<Tooltip
|
|
||||||
formatter={(value: number, name: string) => [
|
|
||||||
name === "cost" ? formatCurrency(value) : value.toLocaleString(),
|
|
||||||
name === "cost" ? "Cost" : name === "products" ? "Products" : "Units"
|
|
||||||
]}
|
|
||||||
labelFormatter={(label) => `Category: ${label}`}
|
|
||||||
/>
|
|
||||||
<Bar
|
|
||||||
dataKey="products"
|
|
||||||
name="Products"
|
|
||||||
fill="#0088FE"
|
|
||||||
radius={[4, 4, 0, 0]}
|
|
||||||
/>
|
|
||||||
<Bar
|
|
||||||
dataKey="units"
|
|
||||||
name="Units"
|
|
||||||
fill="#00C49F"
|
|
||||||
radius={[4, 4, 0, 0]}
|
|
||||||
/>
|
|
||||||
<Bar
|
|
||||||
dataKey="cost"
|
|
||||||
name="Cost"
|
|
||||||
fill="#FFBB28"
|
|
||||||
radius={[4, 4, 0, 0]}
|
|
||||||
/>
|
|
||||||
</BarChart>
|
|
||||||
</ResponsiveContainer>
|
|
||||||
</div>
|
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { CardHeader, CardTitle, CardContent } from "@/components/ui/card"
|
|||||||
import { PieChart, Pie, ResponsiveContainer, Cell, Tooltip } from "recharts"
|
import { PieChart, Pie, ResponsiveContainer, Cell, Tooltip } from "recharts"
|
||||||
import config from "@/config"
|
import config from "@/config"
|
||||||
import { formatCurrency } from "@/lib/utils"
|
import { formatCurrency } from "@/lib/utils"
|
||||||
|
import { ClipboardList, AlertCircle, Layers, DollarSign, ShoppingCart } from "lucide-react" // Importing icons
|
||||||
|
|
||||||
interface PurchaseMetricsData {
|
interface PurchaseMetricsData {
|
||||||
activePurchaseOrders: number
|
activePurchaseOrders: number
|
||||||
@@ -45,58 +46,81 @@ export function PurchaseMetrics() {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
<CardTitle className="text-lg font-medium">Purchase Overview</CardTitle>
|
<CardTitle className="text-xl font-medium">Purchases</CardTitle>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent>
|
<CardContent>
|
||||||
<div className="grid grid-cols-2 gap-4 mb-6">
|
<div className="flex justify-between gap-8">
|
||||||
<div>
|
<div className="flex-1">
|
||||||
<p className="text-sm font-medium text-muted-foreground">Active Orders</p>
|
<div className="flex flex-col gap-4">
|
||||||
<p className="text-2xl font-bold">{data?.activePurchaseOrders.toLocaleString() || 0}</p>
|
<div className="flex items-baseline justify-between">
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<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>
|
||||||
|
</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>
|
||||||
|
</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>
|
||||||
|
</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>
|
||||||
|
</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>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div className="flex-1">
|
||||||
<p className="text-sm font-medium text-muted-foreground">Overdue Orders</p>
|
<div className="flex flex-col">
|
||||||
<p className="text-2xl font-bold">{data?.overduePurchaseOrders.toLocaleString() || 0}</p>
|
<div className="text-lg flex justify-center font-medium mb-4">Purchase Orders By Vendor</div>
|
||||||
|
<div className="h-[200px]">
|
||||||
|
<ResponsiveContainer width="100%" height="100%">
|
||||||
|
<PieChart>
|
||||||
|
<Pie
|
||||||
|
data={data?.vendorOrders || []}
|
||||||
|
dataKey="cost"
|
||||||
|
nameKey="vendor"
|
||||||
|
cx="50%"
|
||||||
|
cy="50%"
|
||||||
|
innerRadius={60}
|
||||||
|
outerRadius={80}
|
||||||
|
paddingAngle={2}
|
||||||
|
>
|
||||||
|
{data?.vendorOrders?.map((entry, index) => (
|
||||||
|
<Cell
|
||||||
|
key={entry.vendor}
|
||||||
|
fill={COLORS[index % COLORS.length]}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</Pie>
|
||||||
|
<Tooltip
|
||||||
|
formatter={(value: number) => formatCurrency(value)}
|
||||||
|
labelFormatter={(label: string) => `Vendor: ${label}`}
|
||||||
|
/>
|
||||||
|
</PieChart>
|
||||||
|
</ResponsiveContainer>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
|
||||||
<p className="text-sm font-medium text-muted-foreground">Units On Order</p>
|
|
||||||
<p className="text-2xl font-bold">{data?.onOrderUnits.toLocaleString() || 0}</p>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<p className="text-sm font-medium text-muted-foreground">Order Cost</p>
|
|
||||||
<p className="text-2xl font-bold">{formatCurrency(data?.onOrderCost || 0)}</p>
|
|
||||||
</div>
|
|
||||||
<div className="col-span-2">
|
|
||||||
<p className="text-sm font-medium text-muted-foreground">Order Retail</p>
|
|
||||||
<p className="text-2xl font-bold">{formatCurrency(data?.onOrderRetail || 0)}</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="h-[300px] w-full">
|
|
||||||
<ResponsiveContainer width="100%" height="100%">
|
|
||||||
<PieChart>
|
|
||||||
<Pie
|
|
||||||
data={data?.vendorOrders || []}
|
|
||||||
dataKey="cost"
|
|
||||||
nameKey="vendor"
|
|
||||||
cx="50%"
|
|
||||||
cy="50%"
|
|
||||||
innerRadius={60}
|
|
||||||
outerRadius={80}
|
|
||||||
paddingAngle={2}
|
|
||||||
>
|
|
||||||
{data?.vendorOrders?.map((entry, index) => (
|
|
||||||
<Cell
|
|
||||||
key={entry.vendor}
|
|
||||||
fill={COLORS[index % COLORS.length]}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</Pie>
|
|
||||||
<Tooltip
|
|
||||||
formatter={(value: number) => formatCurrency(value)}
|
|
||||||
labelFormatter={(label: string) => `Vendor: ${label}`}
|
|
||||||
/>
|
|
||||||
</PieChart>
|
|
||||||
</ResponsiveContainer>
|
|
||||||
</div>
|
</div>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { useQuery } from "@tanstack/react-query"
|
import { useQuery } from "@tanstack/react-query"
|
||||||
import { CardHeader, CardTitle, CardContent } from "@/components/ui/card"
|
import { CardHeader, CardTitle, CardContent } from "@/components/ui/card"
|
||||||
import { BarChart, Bar, ResponsiveContainer, XAxis, YAxis, Tooltip } from "recharts"
|
|
||||||
import config from "@/config"
|
import config from "@/config"
|
||||||
import { formatCurrency } from "@/lib/utils"
|
import { formatCurrency } from "@/lib/utils"
|
||||||
|
import { Package, DollarSign, ShoppingCart } from "lucide-react" // Importing icons
|
||||||
|
|
||||||
interface ReplenishmentMetricsData {
|
interface ReplenishmentMetricsData {
|
||||||
totalUnitsToReplenish: number
|
totalUnitsToReplenish: number
|
||||||
@@ -30,61 +30,32 @@ export function ReplenishmentMetrics() {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
<CardTitle className="text-lg font-medium">Replenishment Overview</CardTitle>
|
<CardTitle className="text-xl font-medium">Replenishment</CardTitle>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent>
|
<CardContent>
|
||||||
<div className="grid grid-cols-3 gap-4 mb-6">
|
<div className="flex flex-col gap-4">
|
||||||
<div>
|
<div className="flex items-baseline justify-between">
|
||||||
<p className="text-sm font-medium text-muted-foreground">Units to Replenish</p>
|
<div className="flex items-center gap-2">
|
||||||
|
<Package className="h-4 w-4 text-muted-foreground" />
|
||||||
|
<p className="text-sm font-medium text-muted-foreground">Units to Replenish</p>
|
||||||
|
</div>
|
||||||
<p className="text-2xl font-bold">{data?.totalUnitsToReplenish.toLocaleString() || 0}</p>
|
<p className="text-2xl font-bold">{data?.totalUnitsToReplenish.toLocaleString() || 0}</p>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div className="flex items-baseline justify-between">
|
||||||
<p className="text-sm font-medium text-muted-foreground">Total Cost</p>
|
<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">Replenishment Cost</p>
|
||||||
|
</div>
|
||||||
<p className="text-2xl font-bold">{formatCurrency(data?.totalReplenishmentCost || 0)}</p>
|
<p className="text-2xl font-bold">{formatCurrency(data?.totalReplenishmentCost || 0)}</p>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div className="flex items-baseline justify-between">
|
||||||
<p className="text-sm font-medium text-muted-foreground">Total Retail</p>
|
<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">Replenishment Retail</p>
|
||||||
|
</div>
|
||||||
<p className="text-2xl font-bold">{formatCurrency(data?.totalReplenishmentRetail || 0)}</p>
|
<p className="text-2xl font-bold">{formatCurrency(data?.totalReplenishmentRetail || 0)}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="h-[300px] w-full">
|
|
||||||
<ResponsiveContainer width="100%" height="100%">
|
|
||||||
<BarChart data={data?.replenishmentByCategory || []}>
|
|
||||||
<XAxis
|
|
||||||
dataKey="category"
|
|
||||||
tickLine={false}
|
|
||||||
axisLine={false}
|
|
||||||
fontSize={12}
|
|
||||||
/>
|
|
||||||
<YAxis
|
|
||||||
tickLine={false}
|
|
||||||
axisLine={false}
|
|
||||||
fontSize={12}
|
|
||||||
tickFormatter={(value) => value.toLocaleString()}
|
|
||||||
/>
|
|
||||||
<Tooltip
|
|
||||||
formatter={(value: number, name: string) => [
|
|
||||||
name === "cost" ? formatCurrency(value) : value.toLocaleString(),
|
|
||||||
name === "cost" ? "Cost" : "Units"
|
|
||||||
]}
|
|
||||||
labelFormatter={(label) => `Category: ${label}`}
|
|
||||||
/>
|
|
||||||
<Bar
|
|
||||||
dataKey="units"
|
|
||||||
name="Units"
|
|
||||||
fill="#0088FE"
|
|
||||||
radius={[4, 4, 0, 0]}
|
|
||||||
/>
|
|
||||||
<Bar
|
|
||||||
dataKey="cost"
|
|
||||||
name="Cost"
|
|
||||||
fill="#00C49F"
|
|
||||||
radius={[4, 4, 0, 0]}
|
|
||||||
/>
|
|
||||||
</BarChart>
|
|
||||||
</ResponsiveContainer>
|
|
||||||
</div>
|
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@
|
|||||||
import { useState } from "react"
|
import { useState } from "react"
|
||||||
import config from "@/config"
|
import config from "@/config"
|
||||||
import { formatCurrency } from "@/lib/utils"
|
import { formatCurrency } from "@/lib/utils"
|
||||||
|
import { ClipboardList, Package, DollarSign, ShoppingCart } from "lucide-react"
|
||||||
|
|
||||||
interface SalesData {
|
interface SalesData {
|
||||||
totalOrders: number
|
totalOrders: number
|
||||||
@@ -44,7 +45,7 @@ export function SalesMetrics() {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<CardHeader className="flex flex-row items-center justify-between">
|
<CardHeader className="flex flex-row items-center justify-between">
|
||||||
<CardTitle className="text-lg font-medium">Sales Overview</CardTitle>
|
<CardTitle className="text-xl font-medium">Sales Overview</CardTitle>
|
||||||
<Select value={period} onValueChange={setPeriod}>
|
<Select value={period} onValueChange={setPeriod}>
|
||||||
<SelectTrigger className="w-[120px]">
|
<SelectTrigger className="w-[120px]">
|
||||||
<SelectValue placeholder="Select period" />
|
<SelectValue placeholder="Select period" />
|
||||||
@@ -59,21 +60,33 @@ export function SalesMetrics() {
|
|||||||
</Select>
|
</Select>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent>
|
<CardContent>
|
||||||
<div className="grid grid-cols-2 gap-4 mb-6">
|
<div className="flex flex-col gap-4">
|
||||||
<div>
|
<div className="flex items-baseline justify-between">
|
||||||
<p className="text-sm font-medium text-muted-foreground">Total Orders</p>
|
<div className="flex items-center gap-2">
|
||||||
|
<ClipboardList className="h-4 w-4 text-muted-foreground" />
|
||||||
|
<p className="text-sm font-medium text-muted-foreground">Total Orders</p>
|
||||||
|
</div>
|
||||||
<p className="text-2xl font-bold">{data?.totalOrders.toLocaleString() || 0}</p>
|
<p className="text-2xl font-bold">{data?.totalOrders.toLocaleString() || 0}</p>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div className="flex items-baseline justify-between">
|
||||||
<p className="text-sm font-medium text-muted-foreground">Units Sold</p>
|
<div className="flex items-center gap-2">
|
||||||
|
<Package className="h-4 w-4 text-muted-foreground" />
|
||||||
|
<p className="text-sm font-medium text-muted-foreground">Units Sold</p>
|
||||||
|
</div>
|
||||||
<p className="text-2xl font-bold">{data?.totalUnitsSold.toLocaleString() || 0}</p>
|
<p className="text-2xl font-bold">{data?.totalUnitsSold.toLocaleString() || 0}</p>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div className="flex items-baseline justify-between">
|
||||||
<p className="text-sm font-medium text-muted-foreground">Cost of Goods</p>
|
<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">Cost of Goods</p>
|
||||||
|
</div>
|
||||||
<p className="text-2xl font-bold">{formatCurrency(data?.totalCogs || 0)}</p>
|
<p className="text-2xl font-bold">{formatCurrency(data?.totalCogs || 0)}</p>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div className="flex items-baseline justify-between">
|
||||||
<p className="text-sm font-medium text-muted-foreground">Revenue</p>
|
<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">Revenue</p>
|
||||||
|
</div>
|
||||||
<p className="text-2xl font-bold">{formatCurrency(data?.totalRevenue || 0)}</p>
|
<p className="text-2xl font-bold">{formatCurrency(data?.totalRevenue || 0)}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { CardHeader, CardTitle, CardContent } from "@/components/ui/card"
|
|||||||
import { PieChart, Pie, ResponsiveContainer, Cell, Tooltip } from "recharts"
|
import { PieChart, Pie, ResponsiveContainer, Cell, Tooltip } from "recharts"
|
||||||
import config from "@/config"
|
import config from "@/config"
|
||||||
import { formatCurrency } from "@/lib/utils"
|
import { formatCurrency } from "@/lib/utils"
|
||||||
|
import { Package, Layers, DollarSign, ShoppingCart } from "lucide-react" // Importing icons
|
||||||
|
|
||||||
interface StockMetricsData {
|
interface StockMetricsData {
|
||||||
totalProducts: number
|
totalProducts: number
|
||||||
@@ -45,58 +46,81 @@ export function StockMetrics() {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
<CardTitle className="text-lg font-medium">Stock Overview</CardTitle>
|
<CardTitle className="text-xl font-medium">Stock</CardTitle>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent>
|
<CardContent>
|
||||||
<div className="grid grid-cols-2 gap-4 mb-6">
|
<div className="flex justify-between gap-8">
|
||||||
<div>
|
<div className="flex-1">
|
||||||
<p className="text-sm font-medium text-muted-foreground">Total Products</p>
|
<div className="flex flex-col gap-4">
|
||||||
<p className="text-2xl font-bold">{data?.totalProducts.toLocaleString() || 0}</p>
|
<div className="flex items-baseline justify-between">
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<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>
|
||||||
|
</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>
|
||||||
|
</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>
|
||||||
|
</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>
|
||||||
|
</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>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div className="flex-1">
|
||||||
<p className="text-sm font-medium text-muted-foreground">Products In Stock</p>
|
<div className="flex flex-col">
|
||||||
<p className="text-2xl font-bold">{data?.productsInStock.toLocaleString() || 0}</p>
|
<div className="text-lg flex justify-center font-medium mb-4">Stock Retail By Brand</div>
|
||||||
|
<div className="h-[200px]">
|
||||||
|
<ResponsiveContainer width="100%" height="100%">
|
||||||
|
<PieChart>
|
||||||
|
<Pie
|
||||||
|
data={data?.vendorStock || []}
|
||||||
|
dataKey="cost"
|
||||||
|
nameKey="vendor"
|
||||||
|
cx="50%"
|
||||||
|
cy="50%"
|
||||||
|
innerRadius={60}
|
||||||
|
outerRadius={80}
|
||||||
|
paddingAngle={2}
|
||||||
|
>
|
||||||
|
{data?.vendorStock?.map((entry, index) => (
|
||||||
|
<Cell
|
||||||
|
key={entry.vendor}
|
||||||
|
fill={COLORS[index % COLORS.length]}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</Pie>
|
||||||
|
<Tooltip
|
||||||
|
formatter={(value: number) => formatCurrency(value)}
|
||||||
|
labelFormatter={(label: string) => `Vendor: ${label}`}
|
||||||
|
/>
|
||||||
|
</PieChart>
|
||||||
|
</ResponsiveContainer>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
|
||||||
<p className="text-sm font-medium text-muted-foreground">Total Stock Units</p>
|
|
||||||
<p className="text-2xl font-bold">{data?.totalStockUnits.toLocaleString() || 0}</p>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<p className="text-sm font-medium text-muted-foreground">Total Stock Cost</p>
|
|
||||||
<p className="text-2xl font-bold">{formatCurrency(data?.totalStockCost || 0)}</p>
|
|
||||||
</div>
|
|
||||||
<div className="col-span-2">
|
|
||||||
<p className="text-sm font-medium text-muted-foreground">Total Stock Retail</p>
|
|
||||||
<p className="text-2xl font-bold">{formatCurrency(data?.totalStockRetail || 0)}</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="h-[300px] w-full">
|
|
||||||
<ResponsiveContainer width="100%" height="100%">
|
|
||||||
<PieChart>
|
|
||||||
<Pie
|
|
||||||
data={data?.vendorStock || []}
|
|
||||||
dataKey="cost"
|
|
||||||
nameKey="vendor"
|
|
||||||
cx="50%"
|
|
||||||
cy="50%"
|
|
||||||
innerRadius={60}
|
|
||||||
outerRadius={80}
|
|
||||||
paddingAngle={2}
|
|
||||||
>
|
|
||||||
{data?.vendorStock?.map((entry, index) => (
|
|
||||||
<Cell
|
|
||||||
key={entry.vendor}
|
|
||||||
fill={COLORS[index % COLORS.length]}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</Pie>
|
|
||||||
<Tooltip
|
|
||||||
formatter={(value: number) => formatCurrency(value)}
|
|
||||||
labelFormatter={(label: string) => `Vendor: ${label}`}
|
|
||||||
/>
|
|
||||||
</PieChart>
|
|
||||||
</ResponsiveContainer>
|
|
||||||
</div>
|
</div>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -30,10 +30,10 @@ export function TopOverstockedProducts() {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
<CardTitle className="text-lg font-medium">Top Overstocked Products</CardTitle>
|
<CardTitle className="text-xl font-medium">Top Overstocked Products</CardTitle>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent>
|
<CardContent>
|
||||||
<ScrollArea className="h-[400px] w-full">
|
<ScrollArea className="h-[300px] w-full">
|
||||||
<Table>
|
<Table>
|
||||||
<TableHeader>
|
<TableHeader>
|
||||||
<TableRow>
|
<TableRow>
|
||||||
|
|||||||
@@ -31,10 +31,10 @@ export function TopReplenishProducts() {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
<CardTitle className="text-lg font-medium">Top Products to Replenish</CardTitle>
|
<CardTitle className="text-xl font-medium">Top Products To Replenish</CardTitle>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent>
|
<CardContent>
|
||||||
<ScrollArea className="h-[400px] w-full">
|
<ScrollArea className="max-h-[650px] w-full overflow-y-auto">
|
||||||
<Table>
|
<Table>
|
||||||
<TableHeader>
|
<TableHeader>
|
||||||
<TableRow>
|
<TableRow>
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ import { useLocation, useNavigate, Link } from "react-router-dom";
|
|||||||
|
|
||||||
const items = [
|
const items = [
|
||||||
{
|
{
|
||||||
title: "Dashboard",
|
title: "Overview",
|
||||||
icon: Home,
|
icon: Home,
|
||||||
url: "/",
|
url: "/",
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ export function Dashboard() {
|
|||||||
return (
|
return (
|
||||||
<motion.div layout className="flex-1 space-y-4 p-4 md:p-8 pt-6">
|
<motion.div layout className="flex-1 space-y-4 p-4 md:p-8 pt-6">
|
||||||
<div className="flex items-center justify-between space-y-2">
|
<div className="flex items-center justify-between space-y-2">
|
||||||
<h2 className="text-3xl font-bold tracking-tight">Dashboard</h2>
|
<h2 className="text-3xl font-bold tracking-tight">Overview</h2>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* First row - Stock and Purchase metrics */}
|
{/* First row - Stock and Purchase metrics */}
|
||||||
@@ -32,7 +32,7 @@ export function Dashboard() {
|
|||||||
<Card className="col-span-2">
|
<Card className="col-span-2">
|
||||||
<TopReplenishProducts />
|
<TopReplenishProducts />
|
||||||
</Card>
|
</Card>
|
||||||
<div className="col-span-1 grid gap-4 grid-rows-2">
|
<div className="col-span-1 grid gap-4">
|
||||||
<Card>
|
<Card>
|
||||||
<ReplenishmentMetrics />
|
<ReplenishmentMetrics />
|
||||||
</Card>
|
</Card>
|
||||||
|
|||||||
Reference in New Issue
Block a user