Add customer insights to order details page

Introduces a customer insights panel on the order details page, displaying metrics such as total orders, total spent, payment success rate, and customer tenure. Removes customer insights logic and display from the order table component for a more focused and relevant presentation.
This commit is contained in:
NotII
2025-08-31 18:30:54 +01:00
parent 9cf226526f
commit a10b9e0094
3 changed files with 105 additions and 108 deletions

View File

@@ -30,18 +30,12 @@ import {
MessageCircle,
AlertTriangle,
Tag,
Percent,
TrendingUp,
Users,
DollarSign,
ShoppingCart,
Calendar
Percent
} from "lucide-react";
import Link from "next/link";
import { clientFetch } from '@/lib/api';
import { toast } from "sonner";
import { Checkbox } from "@/components/ui/checkbox";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
import {
AlertDialog,
AlertDialogAction,
@@ -75,34 +69,7 @@ interface Order {
subtotalBeforeDiscount?: number;
}
interface CustomerInsights {
overview: {
totalOrders: number;
completedOrders: number;
cancelledOrders: number;
uniqueCustomers: number;
completionRate: number;
paymentSuccessRate: number;
cancellationRate: number;
};
financial: {
totalRevenue: number;
averageOrderValue: number;
};
recent30Days: {
orders: number;
revenue: number;
newCustomers: number;
};
}
interface OrdersResponse {
orders: Order[];
page: number;
totalPages: number;
totalOrders: number;
customerInsights: CustomerInsights;
}
type SortableColumns = "orderId" | "totalPrice" | "status" | "orderDate" | "paidAt";
@@ -155,67 +122,7 @@ const PageSizeSelector = ({ currentSize, onChange, options }: { currentSize: num
);
};
// Customer Insights Display Component
const CustomerInsightsDisplay = ({ insights }: { insights: CustomerInsights }) => {
return (
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4 mb-6">
{/* Overview Stats */}
<Card>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">Total Orders</CardTitle>
<ShoppingCart className="h-4 w-4 text-muted-foreground" />
</CardHeader>
<CardContent>
<div className="text-2xl font-bold">{insights.overview.totalOrders}</div>
<p className="text-xs text-muted-foreground">
{insights.overview.uniqueCustomers} unique customers
</p>
</CardContent>
</Card>
<Card>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">Success Rate</CardTitle>
<TrendingUp className="h-4 w-4 text-muted-foreground" />
</CardHeader>
<CardContent>
<div className="text-2xl font-bold text-green-600">
{insights.overview.paymentSuccessRate.toFixed(1)}%
</div>
<p className="text-xs text-muted-foreground">
{insights.overview.completionRate.toFixed(1)}% completion rate
</p>
</CardContent>
</Card>
<Card>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">Total Revenue</CardTitle>
<DollarSign className="h-4 w-4 text-muted-foreground" />
</CardHeader>
<CardContent>
<div className="text-2xl font-bold">£{insights.financial.totalRevenue.toFixed(2)}</div>
<p className="text-xs text-muted-foreground">
£{insights.financial.averageOrderValue.toFixed(2)} avg order
</p>
</CardContent>
</Card>
<Card>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">Last 30 Days</CardTitle>
<Calendar className="h-4 w-4 text-muted-foreground" />
</CardHeader>
<CardContent>
<div className="text-2xl font-bold">{insights.recent30Days.orders}</div>
<p className="text-xs text-muted-foreground">
£{insights.recent30Days.revenue.toFixed(2)} revenue
</p>
</CardContent>
</Card>
</div>
);
};
export default function OrderTable() {
const [orders, setOrders] = useState<Order[]>([]);
@@ -224,7 +131,6 @@ export default function OrderTable() {
const [currentPage, setCurrentPage] = useState(1);
const [totalPages, setTotalPages] = useState(1);
const [totalOrders, setTotalOrders] = useState(0);
const [customerInsights, setCustomerInsights] = useState<CustomerInsights | null>(null);
const [sortConfig, setSortConfig] = useState<{
column: SortableColumns;
direction: "asc" | "desc";
@@ -257,13 +163,12 @@ export default function OrderTable() {
...(statusFilter !== "all" && { status: statusFilter }),
});
const data: OrdersResponse = await clientFetch(`/orders?${queryParams}`);
const data = await clientFetch(`/orders?${queryParams}`);
console.log("Fetched orders with fresh data:", data.orders?.length || 0);
setOrders(data.orders || []);
setTotalPages(data.totalPages || 1);
setTotalOrders(data.totalOrders || 0);
setCustomerInsights(data.customerInsights || null);
} catch (error) {
toast.error("Failed to fetch orders");
console.error("Fetch error:", error);
@@ -464,9 +369,6 @@ export default function OrderTable() {
return (
<div className="space-y-4">
{/* Customer Insights */}
{customerInsights && <CustomerInsightsDisplay insights={customerInsights} />}
<div className="border border-zinc-800 rounded-md bg-black/40 overflow-hidden">
{/* Filters header */}
<div className="p-4 border-b border-zinc-800 bg-black/60">