Refactor AdminAnalytics helpers and formatting
All checks were successful
Build Frontend / build (push) Successful in 1m12s
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:
@@ -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">
|
||||
|
||||
Reference in New Issue
Block a user