Refactor AdminAnalytics helpers and formatting
All checks were successful
Build Frontend / build (push) Successful in 1m12s

Refactored helper functions (transformChartData, combineOrdersAndRevenue, CustomTooltip, formatCurrency, calculateBestMonth) to be defined outside the main component for improved readability and maintainability. Updated code formatting and indentation for consistency, with no changes to business logic.
This commit is contained in:
g
2026-01-13 08:55:03 +00:00
parent 38779c2033
commit fe6d544511
2 changed files with 53 additions and 28 deletions

View File

@@ -58,6 +58,15 @@ import {
TableSkeleton
} from "../analytics/SkeletonLoaders";
// Format currency for admin analytics
const formatAdminCurrency = (value: number) => {
return new Intl.NumberFormat("en-GB", {
style: "currency",
currency: "GBP",
maximumFractionDigits: 0,
}).format(value);
};
const renderActiveShape = (props: any) => {
const RADIAN = Math.PI / 180;
const {
@@ -86,7 +95,7 @@ const renderActiveShape = (props: any) => {
return (
<g>
<text x={cx} y={cy} dy={8} textAnchor="middle" fill={fill} className="text-xl font-bold">
{payload.name.split(" ")[0]}
{payload.name ? payload.name.split(" ")[0] : "Product"}
</text>
<Sector
cx={cx}
@@ -148,7 +157,7 @@ const getSmartInsights = (data?: AnalyticsData | null, growth?: GrowthData | nul
if (data.predictions && data.predictions.predicted > 0) {
insights.push({
type: 'positive',
message: `AI Forecast: Projected ${formatCurrency(data.predictions.predicted)} revenue over the next 7 days.`,
message: `AI Forecast: Projected ${formatAdminCurrency(data.predictions.predicted)} revenue over the next 7 days.`,
icon: Zap,
color: 'text-purple-500',
bg: 'bg-purple-500/10'
@@ -185,7 +194,7 @@ const getSmartInsights = (data?: AnalyticsData | null, growth?: GrowthData | nul
rawInsights.push({
score: Math.abs(revPercent) * (label === '1w' ? 1.5 : 1), // Weight recent changes higher
type: revPercent > 0 ? 'positive' : 'neutral',
message: `Revenue is ${revPercent > 0 ? 'up' : 'down'} ${Math.abs(revPercent).toFixed(1)}% vs ${timeframeName} (${formatCurrency(Math.abs(revDiff))} difference).`,
message: `Revenue is ${revPercent > 0 ? 'up' : 'down'} ${Math.abs(revPercent).toFixed(1)}% vs ${timeframeName} (${formatAdminCurrency(Math.abs(revDiff))} difference).`,
icon: revPercent > 0 ? TrendingUp : TrendingDown,
color: revPercent > 0 ? 'text-green-500' : 'text-orange-500',
bg: revPercent > 0 ? 'bg-green-500/10' : 'bg-orange-500/10'
@@ -544,7 +553,6 @@ export default function AdminAnalytics() {
</div>
);
}
// Helper to transform data for recharts
const transformChartData = (
data: Array<{ date: string;[key: string]: any }>,
@@ -554,6 +562,16 @@ export default function AdminAnalytics() {
return data.map((item) => {
const dateStr = item.date;
if (!dateStr) {
return {
date: "Unknown",
formattedDate: "Unknown",
value: Number(item[valueKey]) || 0,
[valueKey]: Number(item[valueKey]) || 0,
};
}
// Parse YYYY-MM-DD format
const parts = dateStr.split("-");
const date =
@@ -600,15 +618,28 @@ export default function AdminAnalytics() {
>();
if (revenue && revenue.length > 0) {
revenue.forEach((r) => {
revenueMap.set(r.date, {
amount: r.amount || 0,
avgOrderValue: r.avgOrderValue || 0,
});
if (r.date) {
revenueMap.set(r.date, {
amount: r.amount || 0,
avgOrderValue: r.avgOrderValue || 0,
});
}
});
}
return orders.map((order) => {
const dateStr = order.date;
if (!dateStr) {
return {
date: "Unknown",
formattedDate: "Unknown",
orders: order.count || 0,
revenue: 0,
avgOrderValue: 0
};
}
const parts = dateStr.split("-");
const date =
parts.length === 3
@@ -641,6 +672,7 @@ export default function AdminAnalytics() {
});
};
// Custom tooltip for charts
const CustomTooltip = ({ active, payload, label }: any) => {
if (active && payload && payload.length) {
@@ -701,14 +733,7 @@ export default function AdminAnalytics() {
// Format currency
const formatCurrency = (value: number) => {
return new Intl.NumberFormat("en-GB", {
style: "currency",
currency: "GBP",
maximumFractionDigits: 0,
}).format(value);
};
// Calculate best month from daily data (for YTD, full year, or previous years)
const calculateBestMonth = (): { month: string; revenue: number; orders: number } | null => {
@@ -950,7 +975,7 @@ export default function AdminAnalytics() {
Revenue
</div>
<div className="text-2xl font-bold bg-gradient-to-r from-green-600 to-green-400 bg-clip-text text-transparent">
{formatCurrency(bestMonth.revenue)}
{formatAdminCurrency(bestMonth.revenue)}
</div>
<div className="text-sm text-muted-foreground mt-1">
{formatNumber(bestMonth.orders)} orders
@@ -993,10 +1018,10 @@ export default function AdminAnalytics() {
icon={DollarSign}
iconColorClass="text-green-500"
iconBgClass="bg-green-500/10"
value={formatCurrency(analyticsData?.revenue?.total || 0)}
value={formatAdminCurrency(analyticsData?.revenue?.total || 0)}
subtext={
<span className="bg-muted/50 px-1.5 py-0.5 rounded">
Today: {formatCurrency(analyticsData?.revenue?.today || 0)}
Today: {formatAdminCurrency(analyticsData?.revenue?.today || 0)}
</span>
}
trend={{
@@ -1221,7 +1246,7 @@ export default function AdminAnalytics() {
Total Revenue
</div>
<div className="text-2xl font-bold text-green-600">
{formatCurrency(
{formatAdminCurrency(
analyticsData.revenue.dailyRevenue.reduce(
(sum, day) => sum + (day.amount || 0),
0,
@@ -1377,7 +1402,7 @@ export default function AdminAnalytics() {
</div>
<div className="text-right">
<div className="font-semibold text-green-600">
{formatCurrency(vendor.totalRevenue)}
{formatAdminCurrency(vendor.totalRevenue)}
</div>
</div>
</div>
@@ -1437,7 +1462,7 @@ export default function AdminAnalytics() {
<Card className="col-span-1 border-green-500/20 bg-green-500/5 backdrop-blur-sm hover:bg-green-500/10 transition-colors">
<CardContent className="pt-4 flex flex-col items-center justify-center text-center">
<div className="text-xs font-medium text-muted-foreground uppercase tracking-wider mb-1">Total Revenue</div>
<div className="text-2xl font-bold text-green-600">{formatCurrency(growthData.cumulative.revenue)}</div>
<div className="text-2xl font-bold text-green-600">{formatAdminCurrency(growthData.cumulative.revenue)}</div>
</CardContent>
</Card>
<Card className="col-span-1 border-border/40 bg-background/50 backdrop-blur-sm hover:bg-background/60 transition-colors">
@@ -1461,7 +1486,7 @@ export default function AdminAnalytics() {
<Card className="col-span-1 border-purple-500/20 bg-purple-500/5 backdrop-blur-sm hover:bg-purple-500/10 transition-colors">
<CardContent className="pt-4 flex flex-col items-center justify-center text-center">
<div className="text-xs font-medium text-muted-foreground uppercase tracking-wider mb-1">Avg Order Value</div>
<div className="text-2xl font-bold text-purple-600">{formatCurrency(growthData.cumulative.avgOrderValue)}</div>
<div className="text-2xl font-bold text-purple-600">{formatAdminCurrency(growthData.cumulative.avgOrderValue)}</div>
</CardContent>
</Card>
</div>
@@ -1542,7 +1567,7 @@ export default function AdminAnalytics() {
<span className="text-sm text-muted-foreground flex items-center gap-2">
<div className="w-2 h-2 rounded-full bg-green-500" /> Revenue
</span>
<span className="font-medium text-green-600">{formatCurrency(data.revenue)}</span>
<span className="font-medium text-green-600">{formatAdminCurrency(data.revenue)}</span>
</div>
<div className="flex items-center justify-between gap-4">
<span className="text-sm text-muted-foreground flex items-center gap-2">
@@ -1747,13 +1772,13 @@ export default function AdminAnalytics() {
</div>
</td>
<td className="text-right p-3 text-green-600 font-semibold">
{formatCurrency(month.revenue)}
{formatAdminCurrency(month.revenue)}
</td>
<td className="text-right p-3 text-muted-foreground">
{month.customers.toLocaleString()}
</td>
<td className="text-right p-3 text-muted-foreground">
{formatCurrency(month.avgOrderValue)}
{formatAdminCurrency(month.avgOrderValue)}
</td>
<td className="text-right p-3 text-muted-foreground">{month.newVendors}</td>
<td className="text-right p-3 text-muted-foreground">

View File

@@ -1,4 +1,4 @@
{
"commitHash": "600ba1e",
"buildTime": "2026-01-13T06:14:18.909Z"
"commitHash": "38779c2",
"buildTime": "2026-01-13T08:38:56.729Z"
}