feat: implement consistent 20-color mapping for visible products across dashboard charts
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 55s
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 55s
This commit is contained in:
@@ -7,8 +7,12 @@ import type { OrderData, DateRange } from '../types';
|
|||||||
import { parseOrderDate } from '../dataService';
|
import { parseOrderDate } from '../dataService';
|
||||||
|
|
||||||
const COLORS = [
|
const COLORS = [
|
||||||
|
// 10 Strong Base Colors
|
||||||
'#10b981', '#3b82f6', '#8b5cf6', '#f43f5e', '#f97316',
|
'#10b981', '#3b82f6', '#8b5cf6', '#f43f5e', '#f97316',
|
||||||
'#06b6d4', '#ec4899', '#eab308', '#6366f1', '#14b8a6'
|
'#06b6d4', '#ec4899', '#eab308', '#6366f1', '#14b8a6',
|
||||||
|
// 10 Softer Versions
|
||||||
|
'#6ee7b7', '#93c5fd', '#c4b5fd', '#fda4af', '#fdba74',
|
||||||
|
'#67e8f9', '#f9a8d4', '#fde047', '#a5b4fc', '#5eead4'
|
||||||
];
|
];
|
||||||
|
|
||||||
const formatCurrency = (value: number) => {
|
const formatCurrency = (value: number) => {
|
||||||
@@ -63,35 +67,33 @@ const Dashboard = () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const uniqueProducts = Array.from(new Set(filteredData.map(order => order.Descricao_Produto.split(' TAMANHO')[0]))).sort();
|
// Identify which products will actually be displayed in both charts (Top 10 of each)
|
||||||
|
const topSalesNames = Object.keys(productSalesMap).sort((a, b) => productSalesMap[b] - productSalesMap[a]).slice(0, 10);
|
||||||
|
const topRevenueNames = Object.keys(productRevenueMap).sort((a, b) => productRevenueMap[b] - productRevenueMap[a]).slice(0, 10);
|
||||||
|
|
||||||
|
// Combine them into a unique set to assign colors only to the VISIBLE products
|
||||||
|
const displayProducts = Array.from(new Set([...topSalesNames, ...topRevenueNames])).sort();
|
||||||
const productColors: Record<string, string> = {};
|
const productColors: Record<string, string> = {};
|
||||||
uniqueProducts.forEach((productName, index) => {
|
|
||||||
productColors[productName] = COLORS[index % COLORS.length];
|
displayProducts.forEach((name, index) => {
|
||||||
|
productColors[name] = COLORS[index % COLORS.length];
|
||||||
});
|
});
|
||||||
|
|
||||||
const productsData = Object.keys(productSalesMap).map(key => ({
|
const productsData = topSalesNames.map(name => ({
|
||||||
name: key,
|
name,
|
||||||
value: productSalesMap[key]
|
value: productSalesMap[name],
|
||||||
})).sort((a, b) => b.value - a.value).slice(0, 10).map(item => ({
|
fill: productColors[name]
|
||||||
...item,
|
|
||||||
fill: productColors[item.name]
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const revenueData = Object.keys(productRevenueMap).map(key => ({
|
const revenueData = topRevenueNames.map(name => ({
|
||||||
name: key,
|
name,
|
||||||
value: productRevenueMap[key]
|
value: productRevenueMap[name],
|
||||||
})).sort((a, b) => b.value - a.value).slice(0, 10).map(item => ({
|
fill: productColors[name]
|
||||||
...item,
|
|
||||||
fill: productColors[item.name]
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
return { totalRevenue: revenue, totalOrders: totalItems, averageOrderValue: revenue / (filteredData.length || 1), salesByProduct: productsData, revenueByProduct: revenueData };
|
return { totalRevenue: revenue, totalOrders: totalItems, averageOrderValue: revenue / (filteredData.length || 1), salesByProduct: productsData, revenueByProduct: revenueData };
|
||||||
}, [filteredData]);
|
}, [filteredData]);
|
||||||
|
|
||||||
const formatCurrency = (value: number) => {
|
|
||||||
return new Intl.NumberFormat('pt-BR', { style: 'currency', currency: 'BRL' }).format(value);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-6">
|
<div className="space-y-6">
|
||||||
<div className="flex flex-col md:flex-row md:items-center justify-between gap-4">
|
<div className="flex flex-col md:flex-row md:items-center justify-between gap-4">
|
||||||
|
|||||||
Reference in New Issue
Block a user