diff --git a/src/pages/Dashboard.tsx b/src/pages/Dashboard.tsx
index 4960523..f273114 100644
--- a/src/pages/Dashboard.tsx
+++ b/src/pages/Dashboard.tsx
@@ -1,7 +1,7 @@
import { useCallback, useEffect, useMemo, useState } from 'react';
import { useOutletContext, useNavigate } from 'react-router-dom';
import { AreaChart, Area, BarChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, PieChart, Pie, Cell } from 'recharts';
-import { DollarSign, ShoppingCart, TrendingUp } from 'lucide-react';
+import { AlertTriangle, Bot, ClipboardList, DollarSign, Package, ShoppingCart, TrendingUp } from 'lucide-react';
import DateRangePicker from '../components/DateRangePicker';
import RefreshStatus from '../components/RefreshStatus';
import type { DashboardAnalytics, OrderData, DateRange } from '../types';
@@ -161,6 +161,15 @@ const kpiIconStyle = (color: string) => ({
color
});
+type OperationalInsight = {
+ title: string;
+ description: string;
+ icon: typeof Bot;
+ accentClassName: string;
+ actionLabel: string;
+ actionTo: string;
+};
+
const DashboardSkeleton = () => (
@@ -502,6 +511,60 @@ const Dashboard = () => {
const focusedSeller = focusedSellerId ? sellerTimeSeries.sellers.find(seller => seller.id === focusedSellerId) : null;
const effectiveFocusedSellerId = focusedSeller?.id || null;
+ const operationalInsights = useMemo
(() => {
+ const insights: OperationalInsight[] = [];
+ const topProduct = salesByProduct[0];
+ const topRevenueProduct = revenueByProduct[0];
+ const topSeller = chartRevenueBySeller[0];
+ const soldUnits = salesByProduct.reduce((total, product) => total + product.value, 0);
+ const topProductShare = topProduct && soldUnits ? topProduct.value / soldUnits : 0;
+
+ if (topProduct && topProductShare >= 0.35) {
+ insights.push({
+ title: `${topProduct.name} concentra ${Math.round(topProductShare * 100)}% das unidades vendidas`,
+ description: 'Priorize a conferência de estoque e corte para evitar ruptura no item mais sensível do período.',
+ icon: AlertTriangle,
+ accentClassName: 'border-amber-400/30 bg-amber-400/10 text-amber-300',
+ actionLabel: 'Abrir corte',
+ actionTo: '/cutting'
+ });
+ }
+
+ if (topRevenueProduct && topRevenueProduct.value > 0) {
+ insights.push({
+ title: `${topRevenueProduct.name} lidera a receita do período`,
+ description: `${formatCurrency(topRevenueProduct.value)} em receita. Compare disponibilidade e necessidade de compra antes de vender sem cobertura.`,
+ icon: Package,
+ accentClassName: 'border-sky-400/30 bg-sky-400/10 text-sky-300',
+ actionLabel: 'Ver suprimentos',
+ actionTo: '/supplies'
+ });
+ }
+
+ if (topSeller && topSeller.value > 0) {
+ insights.push({
+ title: `${topSeller.name} puxa a maior receita por vendedor`,
+ description: `${formatCurrency(topSeller.value)} no período selecionado. Use o gráfico abaixo para comparar ritmo e concentração.`,
+ icon: TrendingUp,
+ accentClassName: 'border-emerald-400/30 bg-emerald-400/10 text-emerald-300',
+ actionLabel: 'Analisar vendas',
+ actionTo: '/graph'
+ });
+ }
+
+ if (totalOrders > 0 && averageOrderValue > 0) {
+ insights.push({
+ title: `Ticket médio por item em ${formatCurrency(averageOrderValue)}`,
+ description: `${new Intl.NumberFormat('pt-BR').format(totalOrders)} unidades vendidas no período. Revise mix de produtos e abastecimento dos campeões.`,
+ icon: ClipboardList,
+ accentClassName: 'border-brand-primary/30 bg-brand-primary/10 text-brand-primary',
+ actionLabel: 'Ver produtos',
+ actionTo: '/products'
+ });
+ }
+
+ return insights.slice(0, 4);
+ }, [averageOrderValue, chartRevenueBySeller, revenueByProduct, salesByProduct, totalOrders]);
const handleManualRefresh = () => {
void loadDashboardMetrics(dateRange, { force: true });
@@ -532,6 +595,62 @@ const Dashboard = () => {
) : (
+
+
+
+
+
+
+
+
+
Copiloto operacional
+
+ Leituras automáticas do período selecionado para orientar vendas, estoque e produção.
+
+
+
+
+
+
+
+ {operationalInsights.length ? (
+
+ {operationalInsights.map((insight) => (
+
+
+
+
+
+
+
{insight.title}
+
{insight.description}
+
+
+
+
+ ))}
+
+ ) : (
+
+
+ Sem sinais operacionais suficientes no período selecionado.
+
+
+ )}
+
+