浏览代码

modify the cards and modify the charts

gdias 1 月之前
父节点
当前提交
617f617eb5
共有 3 个文件被更改,包括 604 次插入302 次删除
  1. 0 4
      README.md
  2. 70 0
      src/lib/core/models/mock-data.js
  3. 534 298
      src/routes/(app)/dashboard/+page.svelte

+ 0 - 4
README.md

@@ -1,7 +1,3 @@
-# sv
-
-Everything you need to build a Svelte project, powered by [`sv`](https://github.com/sveltejs/cli).
-
 ## Creating a project
 
 If you're seeing this, you've probably already done this step. Congrats!

+ 70 - 0
src/lib/core/models/mock-data.js

@@ -116,3 +116,73 @@ export const mockAspectsData = [
     { aspect: 'Entrega', positive: 60, negative: 40 },
     { aspect: 'Monetário', positive: 30, negative: 20 },
 ];
+
+export const mockAspectsDrilldown = {
+    Atendimento: {
+        positive: [
+            { label: 'Satisfacao com atendimento', value: 285 },
+            { label: 'Educacao e cordialidade', value: 22 },
+            { label: 'Rapidez no retorno', value: 11 },
+            { label: 'Clareza nas respostas', value: 10 },
+            { label: 'Resolucao na primeira resposta', value: 8 },
+            { label: 'Empatia', value: 7 },
+            { label: 'Acompanhamento ate fechar', value: 5 },
+        ],
+        negative: [
+            { label: 'Demora no retorno', value: 13 },
+            { label: 'Falta de continuidade', value: 3 },
+            { label: 'Respostas vagas', value: 2 },
+            { label: 'Tom pouco cordial', value: 1 },
+            { label: 'Nao resolveu a duvida', value: 1 },
+        ]
+    },
+    Produto: {
+        positive: [
+            { label: 'Qualidade percebida', value: 71 },
+            { label: 'Variedade de opcoes', value: 24 },
+            { label: 'Bom custo beneficio', value: 13 },
+            { label: 'Design aprovado', value: 9 },
+            { label: 'Durabilidade', value: 7 },
+            { label: 'Disponibilidade em estoque', value: 6 },
+        ],
+        negative: [
+            { label: 'Preco alto', value: 16 },
+            { label: 'Falta de tamanho/cor', value: 11 },
+            { label: 'Duvida sobre material', value: 7 },
+            { label: 'Diferenca entre foto e produto', value: 4 },
+            { label: 'Poucas opcoes para perfil', value: 2 },
+        ]
+    },
+    Entrega: {
+        positive: [
+            { label: 'Entrega rapida', value: 29 },
+            { label: 'Prazo cumprido', value: 12 },
+            { label: 'Atualizacao de rastreio', value: 9 },
+            { label: 'Embalagem elogiada', value: 6 },
+            { label: 'Retirada facilitada', value: 4 },
+        ],
+        negative: [
+            { label: 'Atraso na entrega', value: 22 },
+            { label: 'Falta de rastreio', value: 8 },
+            { label: 'Taxa de frete alta', value: 5 },
+            { label: 'Produto chegou com avaria', value: 3 },
+            { label: 'Tentativa de entrega sem aviso', value: 2 },
+        ]
+    },
+    Monetário: {
+        positive: [
+            { label: 'Desconto aprovado', value: 14 },
+            { label: 'Condição de pagamento', value: 7 },
+            { label: 'Parcelamento facilitado', value: 4 },
+            { label: 'Cashback percebido', value: 3 },
+            { label: 'Transparencia no valor final', value: 2 },
+        ],
+        negative: [
+            { label: 'Frete elevado', value: 8 },
+            { label: 'Preco final acima esperado', value: 6 },
+            { label: 'Juros no parcelamento', value: 3 },
+            { label: 'Pouca flexibilidade comercial', value: 2 },
+            { label: 'Cupom nao aplicou', value: 1 },
+        ]
+    }
+};

+ 534 - 298
src/routes/(app)/dashboard/+page.svelte

@@ -1,316 +1,552 @@
 <script>
-    import { Users, MessageSquare, AlertTriangle, ThumbsUp, Activity, Smartphone, Monitor } from 'lucide-svelte';
-    import { Chart, Svg, Axis, Bar, Line, Spline, Highlight, Group } from 'layerchart';
-    import { scaleTime, scaleLinear, scaleBand } from 'd3-scale';
-    import { format } from 'date-fns';
-    import { ptBR } from 'date-fns/locale';
-    
-    import { 
-        mockKpis, 
-        mockPriorityQueue, 
-        mockRadarData, 
-        mockVolumeData,
-        mockSentimentDistribution,
-        mockAspectsData
-    } from '$lib/core/models/mock-data.js';
+	import {
+		Users,
+		MessageSquare,
+		AlertTriangle,
+		ThumbsUp,
+		Activity,
+		UserRoundCog,
+		UserX
+	} from 'lucide-svelte';
+	import { Chart, Svg, Axis, Bar, Line, Spline, Highlight, Group } from 'layerchart';
+	import { scaleTime, scaleLinear, scaleBand } from 'd3-scale';
+	import { format } from 'date-fns';
+	import { ptBR } from 'date-fns/locale';
 
-    // Map KPIs to UI format
-    const kpis = [
-        { title: 'Mensagens WhatsApp', value: mockKpis.whatsappMessages.current, subvalue: `${mockKpis.whatsappMessages.total} Total`, icon: MessageSquare, color: 'text-sky-600 dark:text-sky-400', bg: 'bg-sky-50 dark:bg-sky-400/10', border: 'border-sky-200 dark:border-sky-400/20' },
-        { title: 'Linhas CRM', value: mockKpis.crmLines.current, subvalue: `${mockKpis.crmLines.total} Total`, icon: Activity, color: 'text-indigo-600 dark:text-indigo-400', bg: 'bg-indigo-50 dark:bg-indigo-400/10', border: 'border-indigo-200 dark:border-indigo-400/20' },
-        { title: 'Pessoas Novas', value: mockKpis.newPeople.new, subvalue: `${mockKpis.newPeople.recurring} Recorrente`, icon: Users, color: 'text-emerald-600 dark:text-emerald-400', bg: 'bg-emerald-50 dark:bg-emerald-400/10', border: 'border-emerald-200 dark:border-emerald-400/20' },
-        { title: 'Sentimento Geral', value: mockKpis.generalSentiment.value, subvalue: 'Média', icon: ThumbsUp, color: 'text-amber-600 dark:text-amber-400', bg: 'bg-amber-50 dark:bg-amber-400/10', border: 'border-amber-200 dark:border-amber-400/20' },
-        { title: 'Fontes Ativas', value: mockKpis.activeSources.value, subvalue: 'Conectadas', icon: Smartphone, color: 'text-blue-600 dark:text-blue-400', bg: 'bg-blue-50 dark:bg-blue-400/10', border: 'border-blue-200 dark:border-blue-400/20' },
-        { title: 'Atendimento Ativo', value: mockKpis.activeService.value, subvalue: 'Agentes online', icon: Monitor, color: 'text-purple-600 dark:text-purple-400', bg: 'bg-purple-50 dark:bg-purple-400/10', border: 'border-purple-200 dark:border-purple-400/20' },
-    ];
+	import {
+		mockKpis,
+		mockPriorityQueue,
+		mockRadarData,
+		mockVolumeData,
+		mockSentimentDistribution,
+		mockAspectsData,
+		mockAspectsDrilldown
+	} from '$lib/core/models/mock-data.js';
 
-    // Data-driven Radar Chart logic
-    const radarRadius = 80;
-    const radarCenter = 100;
-    const angleStep = (Math.PI * 2) / mockRadarData.length;
-    
-    const radarPoints = $derived(mockRadarData.map((d, i) => {
-        const angle = i * angleStep - Math.PI / 2;
-        const r = (d.value / 100) * radarRadius;
-        return {
-            ...d,
-            x: radarCenter + r * Math.cos(angle),
-            y: radarCenter + r * Math.sin(angle),
-            labelX: radarCenter + (radarRadius + 18) * Math.cos(angle),
-            labelY: radarCenter + (radarRadius + 15) * Math.sin(angle),
-            axisX: radarCenter + radarRadius * Math.cos(angle),
-            axisY: radarCenter + radarRadius * Math.sin(angle),
-        };
-    }));
+	function getSentimentLabel(sentimentScore) {
+		if (sentimentScore >= 0.35) return 'Positivo';
+		if (sentimentScore <= -0.35) return 'Negativo';
+		return 'Neutro';
+	}
 
-    const radarPath = $derived(radarPoints.map(p => `${p.x},${p.y}`).join(' '));
+	let selectedAspectDrilldown = $state(null);
 
-    const gridLevels = [0.2, 0.4, 0.6, 0.8, 1].map(level => {
-        return mockRadarData.map((_, i) => {
-            const angle = i * angleStep - Math.PI / 2;
-            const r = level * radarRadius;
-            return `${radarCenter + r * Math.cos(angle)},${radarCenter + r * Math.sin(angle)}`;
-        }).join(' ');
-    });
+	function openAspectDrilldown(aspect, tone) {
+		selectedAspectDrilldown = { aspect, tone };
+	}
+
+	function clearAspectDrilldown() {
+		selectedAspectDrilldown = null;
+	}
+
+	const drilldownItems = $derived(
+		selectedAspectDrilldown
+			? (mockAspectsDrilldown[selectedAspectDrilldown.aspect]?.[selectedAspectDrilldown.tone] ?? []).slice(
+					0,
+					6
+				)
+			: []
+	);
+
+	const maxDrilldownValue = $derived(Math.max(1, ...drilldownItems.map((item) => item.value)));
+
+	const drilldownTitle = $derived(
+		selectedAspectDrilldown
+			? `${selectedAspectDrilldown.aspect} • ${
+					selectedAspectDrilldown.tone === 'positive' ? 'Pontos Positivos' : 'Pontos Negativos'
+				}`
+			: 'Distribuição de Aspectos'
+	);
+
+	// Map KPIs to UI format
+	const kpis = [
+		{
+			title: 'Usuários Cadastrados',
+			value: mockKpis.newPeople.new,
+			// subvalue: `${mockKpis.newPeople.recurring} entrada / 0 saída`,
+			icon: Users,
+			color: 'text-emerald-600 dark:text-emerald-400',
+			bg: 'bg-emerald-50 dark:bg-emerald-400/10',
+			border: 'border-emerald-200 dark:border-emerald-400/20'
+		},
+		{
+			title: 'Atendentes Ativos',
+			value: mockKpis.activeService.value,
+			// subvalue: 'Com conversas no período',
+			icon: UserRoundCog,
+			color: 'text-purple-600 dark:text-purple-400',
+			bg: 'bg-purple-50 dark:bg-purple-400/10',
+			border: 'border-purple-200 dark:border-purple-400/20'
+		},
+		{
+			title: 'Conversas Ativas',
+			value: mockKpis.whatsappMessages.current,
+			// subvalue: `${mockKpis.whatsappMessages.total} total geral`,
+			icon: MessageSquare,
+			color: 'text-sky-600 dark:text-sky-400',
+			bg: 'bg-sky-50 dark:bg-sky-400/10',
+			border: 'border-sky-200 dark:border-sky-400/20'
+		},
+		{
+			title: 'Sentimento Geral',
+			value: getSentimentLabel(mockKpis.generalSentiment.value),
+			// subvalue: `Score ${mockKpis.generalSentiment.value.toFixed(1).replace('.', ',')}`,
+			icon: ThumbsUp,
+			color: 'text-amber-600 dark:text-amber-400',
+			bg: 'bg-amber-50 dark:bg-amber-400/10',
+			border: 'border-amber-200 dark:border-amber-400/20'
+		},
+		{
+			title: 'Usuários Não Cadastrados',
+			value: mockKpis.crmLines.total,
+			// subvalue: 'Base sem cadastro no CRM',
+			icon: UserX,
+			color: 'text-indigo-600 dark:text-indigo-400',
+			bg: 'bg-indigo-50 dark:bg-indigo-400/10',
+			border: 'border-indigo-200 dark:border-indigo-400/20'
+		}
+	];
+
+	// Data-driven Radar Chart logic
+	const radarRadius = 80;
+	const radarCenter = 100;
+	const angleStep = (Math.PI * 2) / mockRadarData.length;
+
+	const radarPoints = $derived(
+		mockRadarData.map((d, i) => {
+			const angle = i * angleStep - Math.PI / 2;
+			const r = (d.value / 100) * radarRadius;
+			return {
+				...d,
+				x: radarCenter + r * Math.cos(angle),
+				y: radarCenter + r * Math.sin(angle),
+				labelX: radarCenter + (radarRadius + 18) * Math.cos(angle),
+				labelY: radarCenter + (radarRadius + 15) * Math.sin(angle),
+				axisX: radarCenter + radarRadius * Math.cos(angle),
+				axisY: radarCenter + radarRadius * Math.sin(angle)
+			};
+		})
+	);
+
+	const radarPath = $derived(radarPoints.map((p) => `${p.x},${p.y}`).join(' '));
+
+	const gridLevels = [0.2, 0.4, 0.6, 0.8, 1].map((level) => {
+		return mockRadarData
+			.map((_, i) => {
+				const angle = i * angleStep - Math.PI / 2;
+				const r = level * radarRadius;
+				return `${radarCenter + r * Math.cos(angle)},${radarCenter + r * Math.sin(angle)}`;
+			})
+			.join(' ');
+	});
 </script>
 
 <svelte:head>
-    <title>Dashboard - Nettown Analytics</title>
+	<title>Dashboard - Nettown Analytics</title>
 </svelte:head>
 
-<div class="space-y-6 max-w-[1600px] mx-auto">
-    <!-- Header/Filters -->
-    <div class="bg-white dark:bg-[#1e293b] p-4 rounded-xl border border-slate-200 dark:border-slate-800 flex flex-wrap items-center gap-4 text-sm shadow-sm transition-colors duration-200">
-        <div class="flex items-center gap-2">
-            <span class="text-slate-600 dark:text-slate-400 font-medium">Período:</span>
-            <select class="bg-slate-50 dark:bg-slate-900 border border-slate-300 dark:border-slate-700 text-slate-900 dark:text-slate-200 rounded-lg px-3 py-1.5 focus:outline-none focus:border-indigo-500 focus:ring-1 focus:ring-indigo-500 transition-colors">
-                <option>Hoje (24h)</option>
-                <option>Ontem</option>
-                <option>Últimos 7 dias</option>
-            </select>
-        </div>
-        <div class="flex items-center gap-2">
-            <span class="text-slate-600 dark:text-slate-400 font-medium">Unidade:</span>
-            <select class="bg-slate-50 dark:bg-slate-900 border border-slate-300 dark:border-slate-700 text-slate-900 dark:text-slate-200 rounded-lg px-3 py-1.5 focus:outline-none focus:border-indigo-500 focus:ring-1 focus:ring-indigo-500 transition-colors">
-                <option>Sem segmento</option>
-            </select>
-        </div>
-        <div class="flex items-center gap-2">
-            <span class="text-slate-600 dark:text-slate-400 font-medium">Área:</span>
-            <select class="bg-slate-50 dark:bg-slate-900 border border-slate-300 dark:border-slate-700 text-slate-900 dark:text-slate-200 rounded-lg px-3 py-1.5 focus:outline-none focus:border-indigo-500 focus:ring-1 focus:ring-indigo-500 transition-colors">
-                <option>Sem segmento de setor</option>
-            </select>
-        </div>
-        <div class="flex items-center gap-2">
-            <span class="text-slate-600 dark:text-slate-400 font-medium">Sentimento:</span>
-            <select class="bg-slate-50 dark:bg-slate-900 border border-slate-300 dark:border-slate-700 text-slate-900 dark:text-slate-200 rounded-lg px-3 py-1.5 focus:outline-none focus:border-indigo-500 focus:ring-1 focus:ring-indigo-500 transition-colors">
-                <option>Todos</option>
-                <option>Positivo</option>
-                <option>Neutro</option>
-                <option>Negativo</option>
-            </select>
-        </div>
-    </div>
+<div class="mx-auto max-w-[1600px] space-y-6">
+	<!-- Header/Filters -->
+	<div
+		class="flex flex-wrap items-center gap-4 rounded-xl border border-slate-200 bg-white p-4 text-sm shadow-sm transition-colors duration-200 dark:border-slate-800 dark:bg-[#1e293b]"
+	>
+		<div class="flex items-center gap-2">
+			<span class="font-medium text-slate-600 dark:text-slate-400">Período:</span>
+			<select
+				class="rounded-lg border border-slate-300 bg-slate-50 px-3 py-1.5 text-slate-900 transition-colors focus:border-indigo-500 focus:ring-1 focus:ring-indigo-500 focus:outline-none dark:border-slate-700 dark:bg-slate-900 dark:text-slate-200"
+			>
+				<option>Hoje (24h)</option>
+				<option>Ontem</option>
+				<option>Últimos 7 dias</option>
+			</select>
+		</div>
+		<div class="flex items-center gap-2">
+			<span class="font-medium text-slate-600 dark:text-slate-400">Unidade:</span>
+			<select
+				class="rounded-lg border border-slate-300 bg-slate-50 px-3 py-1.5 text-slate-900 transition-colors focus:border-indigo-500 focus:ring-1 focus:ring-indigo-500 focus:outline-none dark:border-slate-700 dark:bg-slate-900 dark:text-slate-200"
+			>
+				<option>Sem segmento</option>
+			</select>
+		</div>
+		<div class="flex items-center gap-2">
+			<span class="font-medium text-slate-600 dark:text-slate-400">Área:</span>
+			<select
+				class="rounded-lg border border-slate-300 bg-slate-50 px-3 py-1.5 text-slate-900 transition-colors focus:border-indigo-500 focus:ring-1 focus:ring-indigo-500 focus:outline-none dark:border-slate-700 dark:bg-slate-900 dark:text-slate-200"
+			>
+				<option>Sem segmento de setor</option>
+			</select>
+		</div>
+		<div class="flex items-center gap-2">
+			<span class="font-medium text-slate-600 dark:text-slate-400">Sentimento:</span>
+			<select
+				class="rounded-lg border border-slate-300 bg-slate-50 px-3 py-1.5 text-slate-900 transition-colors focus:border-indigo-500 focus:ring-1 focus:ring-indigo-500 focus:outline-none dark:border-slate-700 dark:bg-slate-900 dark:text-slate-200"
+			>
+				<option>Todos</option>
+				<option>Positivo</option>
+				<option>Neutro</option>
+				<option>Negativo</option>
+			</select>
+		</div>
+	</div>
+
+	<!-- KPIs -->
+	<div class="grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-5">
+		{#each kpis as kpi}
+			{@const Icon = kpi.icon}
+			<div
+				class="rounded-xl border bg-white p-5 dark:bg-[#1e293b] {kpi.border} shadow-sm transition-colors duration-200 hover:border-indigo-200 dark:hover:border-slate-600"
+			>
+				<div class="flex items-start gap-4">
+					<div
+						class="h-10 w-10 rounded-lg {kpi.bg} {kpi.color} flex shrink-0 items-center justify-center"
+					>
+						<Icon size={20} strokeWidth={2.5} />
+					</div>
+					<div>
+						<div
+							class="mb-1 text-xs font-semibold tracking-wider text-slate-500 uppercase dark:text-slate-400"
+						>
+							{kpi.title}
+						</div>
+						<div class="mb-0.5 text-2xl font-bold text-slate-900 dark:text-white">{kpi.value}</div>
+						<div class="text-xs text-slate-500">{kpi.subvalue}</div>
+					</div>
+				</div>
+			</div>
+		{/each}
+	</div>
+
+	<!-- Main Content Area -->
+	<div class="grid grid-cols-1 gap-6 xl:grid-cols-3">
+		<!-- Fila Priorizada / Alertas -->
+		<div
+			class="flex h-[500px] flex-col overflow-hidden rounded-xl border border-slate-200 bg-white shadow-sm transition-colors duration-200 xl:col-span-2 dark:border-slate-800 dark:bg-[#1e293b]"
+		>
+			<div
+				class="flex items-center justify-between border-b border-slate-200 bg-slate-50 p-4 dark:border-slate-800 dark:bg-[#1e293b]"
+			>
+				<div class="flex items-center gap-2">
+					<AlertTriangle size={18} class="text-amber-600 dark:text-amber-500" />
+					<h2 class="text-base font-bold text-slate-900 dark:text-white">
+						Fila Priorizada • Conversas Inacabadas
+					</h2>
+				</div>
+				<div class="flex gap-2">
+					<span
+						class="rounded-md border border-red-200 bg-red-50 px-2.5 py-1 text-xs font-medium text-red-600 dark:border-red-500/20 dark:bg-red-500/10 dark:text-red-400"
+						>22 fora da janela</span
+					>
+					<span
+						class="rounded-md border border-amber-200 bg-amber-50 px-2.5 py-1 text-xs font-medium text-amber-700 dark:border-amber-500/20 dark:bg-amber-500/10 dark:text-amber-400"
+						>Potencial: R$ 81.004</span
+					>
+				</div>
+			</div>
+
+			<div
+				class="flex gap-2 border-b border-slate-200 bg-slate-50/50 p-4 dark:border-slate-800 dark:bg-slate-900"
+			>
+				<button
+					class="rounded-lg border border-slate-300 bg-white px-4 py-1.5 text-sm font-medium text-slate-900 shadow-sm dark:border-slate-700 dark:bg-[#1e293b] dark:text-white dark:shadow-none"
+					>Todas (22)</button
+				>
+				<button
+					class="rounded-lg border border-transparent bg-transparent px-4 py-1.5 text-sm font-medium text-slate-600 transition-colors hover:border-slate-300 hover:text-slate-900 dark:text-slate-400 dark:hover:border-slate-700 dark:hover:text-white"
+					>Pela vendedora (13)</button
+				>
+				<button
+					class="rounded-lg border border-transparent bg-transparent px-4 py-1.5 text-sm font-medium text-slate-600 transition-colors hover:border-slate-300 hover:text-slate-900 dark:text-slate-400 dark:hover:border-slate-700 dark:hover:text-white"
+					>Pelo cliente (9)</button
+				>
+			</div>
+
+			<div class="flex-1 space-y-4 overflow-y-auto p-4">
+				{#each mockPriorityQueue as item}
+					<div
+						class="group relative overflow-hidden rounded-lg border border-red-200 bg-white p-4 shadow-sm transition-colors hover:border-red-300 dark:border-red-500/30 dark:bg-slate-900 dark:shadow-none dark:hover:border-red-500/60"
+					>
+						<div class="absolute top-0 bottom-0 left-0 w-1 bg-red-500"></div>
+						<div class="mb-3 flex items-start justify-between">
+							<div>
+								<div class="mb-1 flex items-center gap-2">
+									<span class="font-bold text-slate-900 dark:text-white"
+										>#{item.id} {item.customerName}</span
+									>
+									<span
+										class="rounded border border-slate-200 bg-slate-100 px-2 py-0.5 text-[10px] font-bold text-slate-600 dark:border-slate-700 dark:bg-slate-800 dark:text-slate-300"
+										>{item.segment}</span
+									>
+									<span
+										class="rounded border border-red-100 bg-red-50 px-2 py-0.5 text-[10px] font-bold text-red-600 dark:border-transparent dark:bg-red-500/20 dark:text-red-400"
+										>{item.status}</span
+									>
+								</div>
+								<div class="text-sm text-slate-600 dark:text-slate-400">
+									Vendedora: <span class="font-medium text-slate-900 dark:text-slate-200"
+										>{item.sellerName}</span
+									>
+									· {item.lastMessage}
+								</div>
+							</div>
+							<div class="text-right">
+								<div class="mb-1 text-xs font-medium text-red-600 dark:text-red-400">
+									{item.slaStatus}
+								</div>
+								<div class="text-xs text-slate-500">{item.timeAgo}</div>
+							</div>
+						</div>
+						<div
+							class="mb-3 flex items-center gap-2 rounded-md bg-slate-50 p-2 text-sm text-slate-600 dark:bg-transparent dark:p-0 dark:text-slate-300"
+						>
+							<Activity size={14} class="shrink-0 text-slate-400 dark:text-slate-500" />
+							<span>Motivo: <span class="font-medium">{item.motive}</span></span>
+						</div>
+						<div class="flex items-center justify-between text-xs">
+							<div class="flex gap-4">
+								<span class="text-slate-500 dark:text-slate-400"
+									>Impacto: <span class="font-bold text-red-600 dark:text-red-400"
+										>R$ {item.impact.toLocaleString('pt-BR')}</span
+									></span
+								>
+								<span class="text-slate-500 dark:text-slate-400"
+									>Ticket: <span class="font-medium text-slate-900 dark:text-slate-200"
+										>R$ {item.ticket}</span
+									></span
+								>
+								<span class="text-slate-500 dark:text-slate-400"
+									>Chance: <span class="font-bold text-emerald-600 dark:text-emerald-400"
+										>{item.chance}%</span
+									></span
+								>
+							</div>
+							<div class="flex gap-2">
+								<button
+									class="rounded-md border border-slate-300 bg-white px-3 py-1.5 font-medium text-slate-700 shadow-sm transition-colors hover:bg-slate-50 dark:border-slate-700 dark:bg-slate-800 dark:text-slate-200 dark:shadow-none dark:hover:bg-slate-700"
+									>Sugerir mensagem</button
+								>
+								<button
+									class="rounded-md border border-emerald-200 bg-emerald-50 px-3 py-1.5 font-medium text-emerald-700 transition-colors hover:bg-emerald-100 dark:border-emerald-500/20 dark:bg-emerald-500/10 dark:text-emerald-400 dark:hover:bg-emerald-500/20"
+									>Resolver</button
+								>
+							</div>
+						</div>
+					</div>
+				{/each}
+			</div>
+		</div>
+
+		<!-- Radar Chart / Humor da base -->
+		<div
+			class="flex h-[500px] flex-col rounded-xl border border-slate-200 bg-white p-4 shadow-sm transition-colors duration-200 dark:border-slate-800 dark:bg-[#1e293b]"
+		>
+			<div class="mb-6 flex items-center justify-between">
+				<div class="flex items-center gap-2">
+					<div
+						class="flex h-8 w-8 items-center justify-center rounded-lg border border-indigo-100 bg-indigo-50 text-indigo-600 dark:border-transparent dark:bg-indigo-500/10 dark:text-indigo-400"
+					>
+						<Activity size={18} />
+					</div>
+					<h2 class="text-base font-bold text-slate-900 dark:text-white">Humor da Base</h2>
+				</div>
+				<span
+					class="rounded bg-slate-100 px-2 py-1 text-xs font-medium text-slate-600 dark:bg-slate-800 dark:text-slate-400"
+					>Hoje</span
+				>
+			</div>
+
+			<div class="relative flex h-full w-full flex-1 items-center justify-center">
+				<!-- Pure SVG Data-driven Radar Chart -->
+				<svg viewBox="0 0 200 200" class="h-auto w-full max-w-[300px] overflow-visible">
+					<defs>
+						<linearGradient id="radarArea" x1="0%" y1="0%" x2="100%" y2="100%">
+							<stop offset="0%" stop-color="#10b981" stop-opacity="0.4" />
+							<stop offset="100%" stop-color="#3b82f6" stop-opacity="0.1" />
+						</linearGradient>
+					</defs>
+
+					<!-- Background Grid -->
+					{#each gridLevels as points, i}
+						<polygon
+							{points}
+							class="fill-none stroke-slate-300 dark:stroke-slate-700"
+							stroke-width={i === 4 ? '1.5' : '0.5'}
+							stroke-dasharray={i === 4 ? 'none' : '2 2'}
+						/>
+					{/each}
 
-    <!-- KPIs -->
-    <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-6 gap-4">
-        {#each kpis as kpi}
-            {@const Icon = kpi.icon}
-            <div class="bg-white dark:bg-[#1e293b] p-5 rounded-xl border {kpi.border} hover:border-indigo-200 dark:hover:border-slate-600 transition-colors shadow-sm duration-200">
-                <div class="flex items-start gap-4">
-                    <div class="w-10 h-10 rounded-lg {kpi.bg} {kpi.color} flex items-center justify-center shrink-0">
-                        <Icon size={20} strokeWidth={2.5} />
-                    </div>
-                    <div>
-                        <div class="text-xs font-semibold text-slate-500 dark:text-slate-400 uppercase tracking-wider mb-1">{kpi.title}</div>
-                        <div class="text-2xl font-bold text-slate-900 dark:text-white mb-0.5">{kpi.value}</div>
-                        <div class="text-xs text-slate-500">{kpi.subvalue}</div>
-                    </div>
-                </div>
-            </div>
-        {/each}
-    </div>
+					<!-- Axes -->
+					{#each radarPoints as point}
+						<line
+							x1={radarCenter}
+							y1={radarCenter}
+							x2={point.axisX}
+							y2={point.axisY}
+							class="stroke-slate-300 dark:stroke-slate-700"
+							stroke-width="1"
+						/>
+						<!-- Labels -->
+						<text
+							x={point.labelX}
+							y={point.labelY}
+							text-anchor="middle"
+							dominant-baseline="middle"
+							class="fill-slate-500 text-[8px] font-medium dark:fill-slate-400"
+						>
+							{point.name}
+						</text>
+						<!-- Value Labels -->
+						<text
+							x={point.labelX}
+							y={point.labelY + 12}
+							text-anchor="middle"
+							dominant-baseline="middle"
+							class="fill-slate-900 text-[9px] font-bold dark:fill-white"
+						>
+							{point.value}%
+						</text>
+					{/each}
 
-    <!-- Main Content Area -->
-    <div class="grid grid-cols-1 xl:grid-cols-3 gap-6">
-        <!-- Fila Priorizada / Alertas -->
-        <div class="xl:col-span-2 bg-white dark:bg-[#1e293b] rounded-xl border border-slate-200 dark:border-slate-800 shadow-sm overflow-hidden flex flex-col h-[500px] transition-colors duration-200">
-            <div class="p-4 border-b border-slate-200 dark:border-slate-800 flex justify-between items-center bg-slate-50 dark:bg-[#1e293b]">
-                <div class="flex items-center gap-2">
-                    <AlertTriangle size={18} class="text-amber-600 dark:text-amber-500" />
-                    <h2 class="text-base font-bold text-slate-900 dark:text-white">Fila Priorizada • Conversas Inacabadas</h2>
-                </div>
-                <div class="flex gap-2">
-                    <span class="px-2.5 py-1 rounded-md bg-red-50 dark:bg-red-500/10 text-red-600 dark:text-red-400 text-xs font-medium border border-red-200 dark:border-red-500/20">22 fora da janela</span>
-                    <span class="px-2.5 py-1 rounded-md bg-amber-50 dark:bg-amber-500/10 text-amber-700 dark:text-amber-400 text-xs font-medium border border-amber-200 dark:border-amber-500/20">Potencial: R$ 81.004</span>
-                </div>
-            </div>
-            
-            <div class="p-4 bg-slate-50/50 dark:bg-slate-900 border-b border-slate-200 dark:border-slate-800 flex gap-2">
-                <button class="px-4 py-1.5 bg-white dark:bg-[#1e293b] text-slate-900 dark:text-white text-sm font-medium rounded-lg border border-slate-300 dark:border-slate-700 shadow-sm dark:shadow-none">Todas (22)</button>
-                <button class="px-4 py-1.5 bg-transparent text-slate-600 dark:text-slate-400 hover:text-slate-900 dark:hover:text-white text-sm font-medium rounded-lg border border-transparent hover:border-slate-300 dark:hover:border-slate-700 transition-colors">Pela vendedora (13)</button>
-                <button class="px-4 py-1.5 bg-transparent text-slate-600 dark:text-slate-400 hover:text-slate-900 dark:hover:text-white text-sm font-medium rounded-lg border border-transparent hover:border-slate-300 dark:hover:border-slate-700 transition-colors">Pelo cliente (9)</button>
-            </div>
+					<!-- Data Polygon -->
+					<polygon
+						points={radarPath}
+						class="origin-center fill-[url(#radarArea)] stroke-emerald-500 drop-shadow-md transition-all duration-700 ease-out hover:scale-105 dark:stroke-emerald-400"
+						stroke-width="2.5"
+					/>
 
-            <div class="flex-1 overflow-y-auto p-4 space-y-4">
-                {#each mockPriorityQueue as item}
-                    <div class="p-4 rounded-lg bg-white dark:bg-slate-900 border border-red-200 dark:border-red-500/30 relative overflow-hidden group hover:border-red-300 dark:hover:border-red-500/60 shadow-sm dark:shadow-none transition-colors">
-                        <div class="absolute left-0 top-0 bottom-0 w-1 bg-red-500"></div>
-                        <div class="flex justify-between items-start mb-3">
-                            <div>
-                                <div class="flex items-center gap-2 mb-1">
-                                    <span class="font-bold text-slate-900 dark:text-white">#{item.id} {item.customerName}</span>
-                                    <span class="px-2 py-0.5 rounded text-[10px] font-bold bg-slate-100 dark:bg-slate-800 text-slate-600 dark:text-slate-300 border border-slate-200 dark:border-slate-700">{item.segment}</span>
-                                    <span class="px-2 py-0.5 rounded text-[10px] font-bold bg-red-50 dark:bg-red-500/20 text-red-600 dark:text-red-400 border border-red-100 dark:border-transparent">{item.status}</span>
-                                </div>
-                                <div class="text-sm text-slate-600 dark:text-slate-400">Vendedora: <span class="text-slate-900 dark:text-slate-200 font-medium">{item.sellerName}</span> · {item.lastMessage}</div>
-                            </div>
-                            <div class="text-right">
-                                <div class="text-xs text-red-600 dark:text-red-400 font-medium mb-1">{item.slaStatus}</div>
-                                <div class="text-xs text-slate-500">{item.timeAgo}</div>
-                            </div>
-                        </div>
-                        <div class="flex items-center gap-2 text-sm text-slate-600 dark:text-slate-300 mb-3 bg-slate-50 dark:bg-transparent p-2 dark:p-0 rounded-md">
-                            <Activity size={14} class="text-slate-400 dark:text-slate-500 shrink-0" />
-                            <span>Motivo: <span class="font-medium">{item.motive}</span></span>
-                        </div>
-                        <div class="flex items-center justify-between text-xs">
-                            <div class="flex gap-4">
-                                <span class="text-slate-500 dark:text-slate-400">Impacto: <span class="text-red-600 dark:text-red-400 font-bold">R$ {item.impact.toLocaleString('pt-BR')}</span></span>
-                                <span class="text-slate-500 dark:text-slate-400">Ticket: <span class="text-slate-900 dark:text-slate-200 font-medium">R$ {item.ticket}</span></span>
-                                <span class="text-slate-500 dark:text-slate-400">Chance: <span class="text-emerald-600 dark:text-emerald-400 font-bold">{item.chance}%</span></span>
-                            </div>
-                            <div class="flex gap-2">
-                                <button class="px-3 py-1.5 bg-white dark:bg-slate-800 hover:bg-slate-50 dark:hover:bg-slate-700 text-slate-700 dark:text-slate-200 rounded-md transition-colors font-medium border border-slate-300 dark:border-slate-700 shadow-sm dark:shadow-none">Sugerir mensagem</button>
-                                <button class="px-3 py-1.5 bg-emerald-50 dark:bg-emerald-500/10 hover:bg-emerald-100 dark:hover:bg-emerald-500/20 text-emerald-700 dark:text-emerald-400 rounded-md transition-colors font-medium border border-emerald-200 dark:border-emerald-500/20">Resolver</button>
-                            </div>
-                        </div>
-                    </div>
-                {/each}
-            </div>
-        </div>
+					<!-- Data Points -->
+					{#each radarPoints as point}
+						<circle
+							cx={point.x}
+							cy={point.y}
+							r="3"
+							class="hover:r-[5] fill-white stroke-emerald-500 transition-all duration-300 dark:fill-slate-900 dark:stroke-emerald-400"
+							stroke-width="2"
+						>
+							<title>{point.name}: {point.value}%</title>
+						</circle>
+					{/each}
+				</svg>
+			</div>
+		</div>
+	</div>
 
-        <!-- Radar Chart / Humor da base -->
-        <div class="bg-white dark:bg-[#1e293b] rounded-xl border border-slate-200 dark:border-slate-800 shadow-sm p-4 flex flex-col h-[500px] transition-colors duration-200">
-            <div class="flex justify-between items-center mb-6">
-                <div class="flex items-center gap-2">
-                    <div class="w-8 h-8 rounded-lg bg-indigo-50 dark:bg-indigo-500/10 text-indigo-600 dark:text-indigo-400 flex items-center justify-center border border-indigo-100 dark:border-transparent">
-                        <Activity size={18} />
-                    </div>
-                    <h2 class="text-base font-bold text-slate-900 dark:text-white">Humor da Base</h2>
-                </div>
-                <span class="text-xs font-medium text-slate-600 dark:text-slate-400 bg-slate-100 dark:bg-slate-800 px-2 py-1 rounded">Hoje</span>
-            </div>
-            
-            <div class="flex-1 w-full h-full relative flex items-center justify-center">
-                <!-- Pure SVG Data-driven Radar Chart -->
-                <svg viewBox="0 0 200 200" class="w-full max-w-[300px] h-auto overflow-visible">
-                    <defs>
-                        <linearGradient id="radarArea" x1="0%" y1="0%" x2="100%" y2="100%">
-                            <stop offset="0%" stop-color="#10b981" stop-opacity="0.4" />
-                            <stop offset="100%" stop-color="#3b82f6" stop-opacity="0.1" />
-                        </linearGradient>
-                    </defs>
-                    
-                    <!-- Background Grid -->
-                    {#each gridLevels as points, i}
-                        <polygon 
-                            {points} 
-                            class="stroke-slate-300 dark:stroke-slate-700 fill-none" 
-                            stroke-width={i === 4 ? "1.5" : "0.5"}
-                            stroke-dasharray={i === 4 ? "none" : "2 2"}
-                        />
-                    {/each}
+	<!-- Secondary Charts Row -->
+	<div class="grid grid-cols-1 gap-6 xl:grid-cols-2">
+		<!-- Volume over time -->
+		<div
+			class="flex h-[400px] flex-col rounded-xl border border-slate-200 bg-white p-4 shadow-sm transition-colors duration-200 dark:border-slate-800 dark:bg-[#1e293b]"
+		>
+			<div class="mb-6 flex items-center justify-between">
+				<h2 class="text-base font-bold text-slate-900 dark:text-white">Volume por Canal</h2>
+				<select
+					class="rounded-lg border border-slate-300 bg-slate-50 px-2 py-1 text-xs text-slate-900 focus:border-indigo-500 focus:outline-none dark:border-slate-700 dark:bg-slate-900 dark:text-slate-200"
+				>
+					<option>Por Hora</option>
+				</select>
+			</div>
 
-                    <!-- Axes -->
-                    {#each radarPoints as point}
-                        <line 
-                            x1={radarCenter} 
-                            y1={radarCenter} 
-                            x2={point.axisX} 
-                            y2={point.axisY} 
-                            class="stroke-slate-300 dark:stroke-slate-700" 
-                            stroke-width="1"
-                        />
-                        <!-- Labels -->
-                        <text 
-                            x={point.labelX} 
-                            y={point.labelY} 
-                            text-anchor="middle" 
-                            dominant-baseline="middle"
-                            class="text-[8px] font-medium fill-slate-500 dark:fill-slate-400"
-                        >
-                            {point.name}
-                        </text>
-                        <!-- Value Labels -->
-                        <text 
-                            x={point.labelX} 
-                            y={point.labelY + 12} 
-                            text-anchor="middle" 
-                            dominant-baseline="middle"
-                            class="text-[9px] font-bold fill-slate-900 dark:fill-white"
-                        >
-                            {point.value}%
-                        </text>
-                    {/each}
+			<div class="h-full w-full flex-1">
+				<Chart
+					data={mockVolumeData}
+					x="date"
+					y="whatsapp"
+					yDomain={[0, 250]}
+					padding={{ top: 10, right: 10, bottom: 20, left: 30 }}
+				>
+					<Svg>
+						<Axis
+							placement="left"
+							grid={{ class: 'stroke-slate-200 dark:stroke-slate-700', strokeDasharray: '2 2' }}
+							class="fill-slate-500 text-xs dark:fill-slate-400"
+						/>
+						<Axis
+							placement="bottom"
+							format={(d) => format(d, 'HH:mm')}
+							class="fill-slate-500 text-xs dark:fill-slate-400"
+						/>
+						<Spline stroke="#38bdf8" strokeWidth={2} />
+						<Highlight
+							points={{
+								fill: '#38bdf8',
+								class: 'stroke-white dark:stroke-slate-900',
+								strokeWidth: 2
+							}}
+						/>
+					</Svg>
+				</Chart>
+			</div>
+		</div>
 
-                    <!-- Data Polygon -->
-                    <polygon 
-                        points={radarPath} 
-                        class="fill-[url(#radarArea)] stroke-emerald-500 dark:stroke-emerald-400 drop-shadow-md origin-center transition-all duration-700 ease-out hover:scale-105"
-                        stroke-width="2.5"
-                    />
+		<!-- Sentiment and Aspects distribution -->
+		<div
+			class="flex h-[400px] flex-col rounded-xl border border-slate-200 bg-white p-4 shadow-sm transition-colors duration-200 dark:border-slate-800 dark:bg-[#1e293b]"
+		>
+			<div class="mb-6 flex items-center justify-between">
+				<h2 class="text-base font-bold text-slate-900 dark:text-white">
+					{drilldownTitle}
+				</h2>
+				{#if selectedAspectDrilldown}
+					<button
+						type="button"
+						onclick={clearAspectDrilldown}
+						class="rounded-md border border-slate-300 bg-white px-3 py-1.5 text-xs font-medium text-slate-700 transition-colors hover:bg-slate-50 dark:border-slate-700 dark:bg-slate-900 dark:text-slate-300 dark:hover:bg-slate-800"
+					>
+						Voltar
+					</button>
+				{/if}
+			</div>
 
-                    <!-- Data Points -->
-                    {#each radarPoints as point}
-                        <circle 
-                            cx={point.x} 
-                            cy={point.y} 
-                            r="3" 
-                            class="fill-white dark:fill-slate-900 stroke-emerald-500 dark:stroke-emerald-400 transition-all duration-300 hover:r-[5]"
-                            stroke-width="2"
-                        >
-                            <title>{point.name}: {point.value}%</title>
-                        </circle>
-                    {/each}
-                </svg>
-            </div>
-        </div>
-    </div>
-    
-    <!-- Secondary Charts Row -->
-    <div class="grid grid-cols-1 xl:grid-cols-2 gap-6">
-        <!-- Volume over time -->
-        <div class="bg-white dark:bg-[#1e293b] rounded-xl border border-slate-200 dark:border-slate-800 shadow-sm p-4 flex flex-col h-[400px] transition-colors duration-200">
-            <div class="flex justify-between items-center mb-6">
-                <h2 class="text-base font-bold text-slate-900 dark:text-white">Volume por Canal</h2>
-                <select class="bg-slate-50 dark:bg-slate-900 border border-slate-300 dark:border-slate-700 text-slate-900 dark:text-slate-200 text-xs rounded-lg px-2 py-1 focus:outline-none focus:border-indigo-500">
-                    <option>Por Hora</option>
-                </select>
-            </div>
-            
-            <div class="flex-1 w-full h-full">
-                <Chart data={mockVolumeData} x="date" y="whatsapp" yDomain={[0, 250]} padding={{ top: 10, right: 10, bottom: 20, left: 30 }}>
-                    <Svg>
-                        <Axis placement="left" grid={{ class: 'stroke-slate-200 dark:stroke-slate-700', strokeDasharray: '2 2' }} class="text-xs fill-slate-500 dark:fill-slate-400" />
-                        <Axis 
-                            placement="bottom" 
-                            format={(d) => format(d, 'HH:mm')}
-                            class="text-xs fill-slate-500 dark:fill-slate-400"
-                        />
-                        <Spline stroke="#38bdf8" strokeWidth={2} />
-                        <Highlight points={{ fill: '#38bdf8', class: 'stroke-white dark:stroke-slate-900', strokeWidth: 2 }} />
-                    </Svg>
-                </Chart>
-            </div>
-        </div>
-        
-        <!-- Sentiment and Aspects distribution -->
-        <div class="bg-white dark:bg-[#1e293b] rounded-xl border border-slate-200 dark:border-slate-800 shadow-sm p-4 flex flex-col h-[400px] transition-colors duration-200">
-            <h2 class="text-base font-bold text-slate-900 dark:text-white mb-6">Distribuição de Aspectos</h2>
-            
-            <div class="flex-1 w-full h-full relative overflow-y-auto pr-2 custom-scrollbar">
-                <div class="space-y-4">
-                    {#each mockAspectsData as aspect}
-                        <div>
-                            <div class="flex justify-between text-xs text-slate-600 dark:text-slate-300 mb-1">
-                                <span class="font-medium">{aspect.aspect}</span>
-                                <span>{aspect.positive + aspect.negative} interações</span>
-                            </div>
-                            <div class="h-6 w-full bg-slate-100 dark:bg-slate-800 rounded overflow-hidden flex shadow-inner">
-                                <div 
-                                    class="h-full bg-emerald-500" 
-                                    style="width: {(aspect.positive / (aspect.positive + aspect.negative)) * 100}%"
-                                ></div>
-                                <div 
-                                    class="h-full bg-red-500" 
-                                    style="width: {(aspect.negative / (aspect.positive + aspect.negative)) * 100}%"
-                                ></div>
-                            </div>
-                        </div>
-                    {/each}
-                </div>
-            </div>
-        </div>
-    </div>
+			<div class="custom-scrollbar relative h-full w-full flex-1 overflow-y-auto pr-2">
+				{#if !selectedAspectDrilldown}
+					<div class="space-y-4">
+						{#each mockAspectsData as aspect}
+							<div>
+								<div class="mb-1 flex justify-between text-xs text-slate-600 dark:text-slate-300">
+									<span class="font-medium">{aspect.aspect}</span>
+									<span>{aspect.positive + aspect.negative} interações</span>
+								</div>
+								<div
+									class="flex h-7 w-full overflow-hidden rounded bg-slate-100 shadow-inner dark:bg-slate-800"
+								>
+									<button
+										type="button"
+										class="h-full bg-emerald-500 transition-opacity hover:opacity-90"
+										style="width: {(aspect.positive / (aspect.positive + aspect.negative)) * 100}%"
+										onclick={() => openAspectDrilldown(aspect.aspect, 'positive')}
+										aria-label={`Ver pontos positivos de ${aspect.aspect}`}
+									></button>
+									<button
+										type="button"
+										class="h-full bg-red-500 transition-opacity hover:opacity-90"
+										style="width: {(aspect.negative / (aspect.positive + aspect.negative)) * 100}%"
+										onclick={() => openAspectDrilldown(aspect.aspect, 'negative')}
+										aria-label={`Ver pontos negativos de ${aspect.aspect}`}
+									></button>
+								</div>
+							</div>
+						{/each}
+					</div>
+				{:else}
+					<div class="space-y-3">
+						{#each drilldownItems as item}
+							<div>
+								<div class="mb-1 flex justify-between text-xs text-slate-600 dark:text-slate-300">
+									<span class="font-medium">{item.label}</span>
+									<span>{item.value}</span>
+								</div>
+								<div class="h-5 w-full rounded bg-slate-100 dark:bg-slate-800">
+									<div
+										class="h-full rounded {selectedAspectDrilldown.tone === 'positive'
+											? 'bg-emerald-500'
+											: 'bg-red-500'}"
+										style="width: {(item.value / maxDrilldownValue) * 100}%"
+									></div>
+								</div>
+							</div>
+						{/each}
+					</div>
+				{/if}
+			</div>
+		</div>
+	</div>
 </div>