Просмотр исходного кода

finishe the frontend now need start de backend

gdias 1 месяц назад
Родитель
Сommit
90d580878a

+ 17 - 1
.claude/settings.local.json

@@ -1,7 +1,23 @@
 {
   "permissions": {
     "allow": [
-      "Bash(npm run *)"
+      "Bash(npm run *)",
+      "Bash(cd \"\\\\\\\\wsl.localhost\\\\Ubuntu\\\\home\\\\gabrielrd\\\\workspace2\\\\nettown_front\")",
+      "Bash(sed -n '665,671p' \"//wsl.localhost/Ubuntu/home/gabrielrd/workspace2/nettown_front/src/routes/\\(app\\)/dashboard/agents/+page.svelte\" | cat -A)",
+      "Read(///wsl.localhost/Ubuntu/home/gabrielrd/workspace2/nettown_front/src/routes/\\(app\\)/dashboard/agents/**)",
+      "Bash(sed -i '669d' \"//wsl.localhost/Ubuntu/home/gabrielrd/workspace2/nettown_front/src/routes/\\(app\\)/dashboard/agents/+page.svelte\")",
+      "Bash(awk 'NR>=184 { *)",
+      "Read(///wsl.localhost/Ubuntu/home/gabrielrd/workspace2/nettown_front/src/routes/\\(app\\)/dashboard/executive/**)",
+      "Bash(sed -n '475,485p' \"//wsl.localhost/Ubuntu/home/gabrielrd/workspace2/nettown_front/src/routes/\\(app\\)/dashboard/executive/+page.svelte\" | cat -A)",
+      "Bash(sed -i '481d' \"//wsl.localhost/Ubuntu/home/gabrielrd/workspace2/nettown_front/src/routes/\\(app\\)/dashboard/executive/+page.svelte\")",
+      "Read(///wsl.localhost/Ubuntu/home/gabrielrd/workspace2/**)",
+      "Bash(npx svelte-check *)",
+      "Bash(wsl -e bash -c \"cd /home/gabrielrd/workspace2/nettown_front && npx svelte-check --tsconfig ./tsconfig.json 2>&1 | head -40\")",
+      "Bash(wsl -e bash -c \"cd /home/gabrielrd/workspace2/nettown_front && npx svelte-check 2>&1 | tail -20\")"
+    ],
+    "additionalDirectories": [
+      "\\\\wsl.localhost\\Ubuntu\\home\\gabrielrd\\workspace2\\nettown_front\\src\\routes\\(app)\\dashboard\\agents",
+      "\\\\wsl.localhost\\Ubuntu\\home\\gabrielrd\\workspace2\\nettown_front\\src\\routes\\(app)\\dashboard\\executive"
     ]
   }
 }

+ 35 - 1
src/lib/features/sentiment/ui/GainLossChart.svelte

@@ -11,7 +11,10 @@
 		selectedPeriod = null,
 		timeframeOptions = defaultTimeframeOptions,
 		selectedTimeframe = 'week',
-		onTimeframeChange = () => {}
+		onTimeframeChange = () => {},
+		onConfirmCustomDates = () => {},
+		customDateStart = $bindable(''),
+		customDateEnd = $bindable('')
 	} = $props();
 
 	const chartWidth = 760;
@@ -66,6 +69,37 @@
 		</label>
 	</div>
 
+	{#if selectedTimeframe === 'custom'}
+		<div class="mb-3 flex flex-wrap items-center gap-3 rounded-lg border border-indigo-200 bg-indigo-50 px-4 py-2.5 shrink-0 dark:border-indigo-500/30 dark:bg-indigo-500/10">
+			<span class="text-xs font-semibold text-indigo-700 dark:text-indigo-400">Período personalizado:</span>
+			<div class="flex items-center gap-2">
+				<label class="text-xs font-medium text-slate-600 dark:text-slate-400">De</label>
+				<input
+					type="date"
+					bind:value={customDateStart}
+					class="rounded-md border border-slate-300 bg-white px-2 py-1 text-xs text-slate-900 focus:border-indigo-500 focus:outline-none dark:border-slate-700 dark:bg-[#0f172a] dark:text-slate-200"
+				/>
+			</div>
+			<div class="flex items-center gap-2">
+				<label class="text-xs font-medium text-slate-600 dark:text-slate-400">Até</label>
+				<input
+					type="date"
+					bind:value={customDateEnd}
+					class="rounded-md border border-slate-300 bg-white px-2 py-1 text-xs text-slate-900 focus:border-indigo-500 focus:outline-none dark:border-slate-700 dark:bg-[#0f172a] dark:text-slate-200"
+				/>
+			</div>
+			{#if customDateStart && customDateEnd}
+				<button
+					type="button"
+					onclick={() => onConfirmCustomDates(customDateStart, customDateEnd)}
+					class="rounded-md bg-indigo-600 px-3 py-1 text-xs font-semibold text-white transition-colors hover:bg-indigo-700 dark:bg-indigo-500 dark:hover:bg-indigo-600"
+				>
+					Confirmar
+				</button>
+			{/if}
+		</div>
+	{/if}
+
 	<div class="flex-1 w-full flex items-center justify-center pt-2">
 		<svg viewBox={`0 0 ${chartWidth} ${chartHeight}`} class="h-full w-full overflow-visible">
 			<!-- Background Grid -->

+ 3 - 5
src/routes/(app)/+layout.svelte

@@ -20,8 +20,7 @@
 		CreditCard,
 		HelpCircle,
 		PieChart,
-		Users,
-		ShieldCheck
+		Users
 	} from 'lucide-svelte';
 	import { goto } from '$app/navigation';
 	import logoWhite from '$lib/assets/images/nettown_white_logo.svg';
@@ -42,15 +41,14 @@
 	});
 
 	const navItems = [
+		{ name: 'Dashboard Executivo', href: '/dashboard/executive', icon: PieChart },
 		{ name: 'Visão Geral', href: '/dashboard', icon: LayoutDashboard },
 		{ name: 'Interações', href: '/dashboard/interactions', icon: MessageSquare },
 		{ name: 'Análise de Sentimento', href: '/dashboard/analytics', icon: BarChart2 },
 		{ name: 'Personas', href: '/dashboard/personas', icon: UserRound },
 		{ name: 'Evolução', href: '/dashboard/evolucao', icon: TrendingUp },
 		{ name: 'Configurações', href: '/dashboard/settings', icon: Settings },
-		{ name: 'Dashboard Executivo', href: '/dashboard/executive', icon: PieChart },
-		{ name: 'Agentes', href: '/dashboard/agents', icon: Users },
-		{ name: 'Config. SLA', href: '/dashboard/sla', icon: ShieldCheck }
+		{ name: 'Operadores', href: '/dashboard/agents', icon: Users }
 	];
 
 	function handleLogout() {

+ 129 - 24
src/routes/(app)/dashboard/+page.svelte

@@ -77,6 +77,9 @@
 	let selectedSentimentFilter = $state(sentimentFilterOptions[0].id);
 	let volumeView = $state(volumeViewOptions[0].id);
 	let queueTab = $state('all');
+	let hoveredRadarPoint = $state(null);
+
+	const totalBase = 4011;
 
 	function openAspectDrilldown(aspect, tone) {
 		selectedAspectDrilldown = { aspect, tone };
@@ -105,7 +108,7 @@
 					selectedAspectDrilldown.tone === 'positive' ? 'Pontos Positivos' :
 					selectedAspectDrilldown.tone === 'neutral' ? 'Pontos Neutros' : 'Pontos Negativos'
 				}`
-			: 'Distribuição de Aspectos'
+			: 'Tema da Conversa'
 	);
 
 	const selectedFilterContext = $derived({
@@ -152,7 +155,7 @@
 			format: (value) => value.toLocaleString('pt-BR')
 		},
 		{
-			title: 'Sentimento Geral',
+			title: 'Emoção Geral',
 			icon: ThumbsUp,
 			color: 'text-amber-600 dark:text-amber-400',
 			bg: 'bg-amber-50 dark:bg-amber-400/10',
@@ -196,6 +199,28 @@
 		}))
 	);
 
+	// Channel filter for the Tema da Conversa chart — add new channels to this array
+	const channelOptions = [
+		{ id: 'Todos', label: 'Todos', multiplier: 1 },
+		{ id: 'WhatsApp', label: 'WhatsApp', multiplier: 0.76 },
+		{ id: 'Instagram', label: 'Instagram', multiplier: 0.24 }
+	];
+	let selectedAspectChannel = $state('Todos');
+
+	const channelMultiplier = $derived(
+		channelOptions.find((o) => o.id === selectedAspectChannel)?.multiplier ?? 1
+	);
+
+	// Tema da Conversa bars always show all channels combined
+	const filteredAspectsData = $derived(aspectsData);
+
+	const totalInteractions = $derived(
+		aspectsData.reduce((sum, a) => sum + a.positive + a.neutral + a.negative, 0)
+	);
+
+	// Separate total for the channel filter display in Total de Conversas section
+	const channelDisplayTotal = $derived(Math.round(totalInteractions * channelMultiplier));
+
 	const baseDailyVolume = (() => {
 		const grouped = new Map();
 		for (const record of mockVolumeData) {
@@ -229,7 +254,7 @@
 		const base = volumeView === 'day' ? baseDailyVolume : mockVolumeData;
 		return base.map((entry, idx) => ({
 			date: entry.date,
-			whatsapp: Math.max(0, Math.round(entry.whatsapp * (combinedMultiplier + idx * 0.02)))
+			whatsapp: Math.max(0, Math.round(entry.whatsapp * (combinedMultiplier + idx * 0.02) * channelMultiplier))
 		}));
 	});
 
@@ -297,6 +322,7 @@
 			const r = (d.value / 100) * radarRadius;
 			return {
 				...d,
+				count: Math.round((d.value / 100) * totalBase),
 				x: radarCenter + r * Math.cos(angle),
 				y: radarCenter + r * Math.sin(angle),
 				labelX: radarCenter + (radarRadius + 18) * Math.cos(angle),
@@ -525,14 +551,19 @@
 		<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="mb-4 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>
+						<h2 class="text-base font-bold text-slate-900 dark:text-white">Humor da Base</h2>
+						<p class="text-xs text-slate-500 dark:text-slate-400">
+							{totalBase.toLocaleString('pt-BR')} clientes na base
+						</p>
+					</div>
 				</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"
@@ -540,6 +571,23 @@
 				>
 			</div>
 
+			<!-- Tooltip shown on hover of radar points -->
+			<div class="mb-3 h-7">
+				{#if hoveredRadarPoint}
+					<div
+						class="flex items-center gap-2 rounded-lg border border-slate-200 bg-slate-50 px-3 py-1.5 text-xs dark:border-slate-700 dark:bg-slate-900"
+					>
+						<span class="font-semibold text-slate-900 dark:text-white">{hoveredRadarPoint.name}</span>
+						<span class="text-slate-400">—</span>
+						<span class="text-slate-600 dark:text-slate-300">{hoveredRadarPoint.value}%</span>
+						<span class="text-slate-400 dark:text-slate-500">·</span>
+						<span class="font-medium text-slate-700 dark:text-slate-300">
+							{hoveredRadarPoint.count.toLocaleString('pt-BR')} clientes
+						</span>
+					</div>
+				{/if}
+			</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">
@@ -607,8 +655,10 @@
 							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"
+							onmouseenter={() => (hoveredRadarPoint = point)}
+							onmouseleave={() => (hoveredRadarPoint = null)}
 						>
-							<title>{point.name}: {point.value}%</title>
+							<title>{point.name}: {point.value}% · {point.count.toLocaleString('pt-BR')} clientes</title>
 						</circle>
 					{/each}
 				</svg>
@@ -622,8 +672,8 @@
 		<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>
+			<div class="mb-3 flex items-center justify-between">
+				<h2 class="text-base font-bold text-slate-900 dark:text-white">Total de Conversas</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"
 					bind:value={volumeView}
@@ -634,6 +684,25 @@
 				</select>
 			</div>
 
+			<!-- Channel filter + total -->
+			<div class="mb-3 flex items-center justify-between border-b border-slate-100 pb-3 dark:border-slate-800">
+				<div class="flex items-center gap-1.5 text-xs">
+					<span class="font-medium text-slate-500 dark:text-slate-400">Total:</span>
+					<span class="font-bold text-slate-900 dark:text-white">{channelDisplayTotal.toLocaleString('pt-BR')}</span>
+				</div>
+				<div class="flex gap-1">
+					{#each channelOptions as ch}
+						<button
+							type="button"
+							onclick={() => (selectedAspectChannel = ch.id)}
+							class="rounded-md px-2.5 py-1 text-xs font-medium transition-colors {selectedAspectChannel === ch.id
+								? 'bg-indigo-50 text-indigo-700 dark:bg-indigo-500/10 dark:text-indigo-400'
+								: 'text-slate-500 hover:text-slate-800 dark:text-slate-400 dark:hover:text-slate-200'}"
+						>{ch.label}</button>
+					{/each}
+				</div>
+			</div>
+
 			<div class="h-full w-full flex-1">
 				<Chart
 					data={volumeData}
@@ -666,14 +735,24 @@
 			</div>
 		</div>
 
-		<!-- Sentiment and Aspects distribution -->
+		<!-- Tema da Conversa / 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>
+			<!-- Header with optional Total de Interações counter -->
+			<div class="mb-3 flex items-center justify-between">
+				<div class="flex items-center gap-3">
+					<h2 class="text-base font-bold text-slate-900 dark:text-white">
+						{drilldownTitle}
+					</h2>
+					{#if !selectedAspectDrilldown}
+						<span
+							class="rounded-full bg-slate-100 px-2.5 py-0.5 text-xs font-medium text-slate-600 dark:bg-slate-800 dark:text-slate-400"
+						>
+							{totalInteractions.toLocaleString('pt-BR')} interações
+						</span>
+					{/if}
+				</div>
 				{#if selectedAspectDrilldown}
 					<button
 						type="button"
@@ -688,36 +767,61 @@
 			<div class="custom-scrollbar relative h-full w-full flex-1 overflow-y-auto pr-2">
 				{#if !selectedAspectDrilldown}
 					<div class="space-y-4">
-						{#each aspectsData as aspect}
+						{#each filteredAspectsData as aspect}
+							{@const total = aspect.positive + aspect.neutral + aspect.negative}
+							{@const posPct = total > 0 ? (aspect.positive / total) * 100 : 0}
+							{@const neuPct = total > 0 ? (aspect.neutral / total) * 100 : 0}
+							{@const negPct = total > 0 ? (aspect.negative / total) * 100 : 0}
 							<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.neutral + aspect.negative} interações</span>
+									<span>{total} 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.neutral + aspect.negative)) * 100}%"
+										class="relative h-full bg-emerald-500 transition-opacity hover:opacity-90"
+										style="width: {posPct}%"
 										onclick={() => openAspectDrilldown(aspect.aspect, 'positive')}
 										aria-label={`Ver pontos positivos de ${aspect.aspect}`}
-									></button>
+									>
+										{#if posPct >= 12}
+											<span
+												class="pointer-events-none absolute inset-0 flex items-center justify-center text-[10px] font-bold text-white"
+												>{Math.round(posPct)}%</span
+											>
+										{/if}
+									</button>
 									<button
 										type="button"
-										class="h-full bg-slate-400 transition-opacity hover:opacity-90"
-										style="width: {(aspect.neutral / (aspect.positive + aspect.neutral + aspect.negative)) * 100}%"
+										class="relative h-full bg-slate-400 transition-opacity hover:opacity-90"
+										style="width: {neuPct}%"
 										onclick={() => openAspectDrilldown(aspect.aspect, 'neutral')}
 										aria-label={`Ver pontos neutros de ${aspect.aspect}`}
-									></button>
+									>
+										{#if neuPct >= 12}
+											<span
+												class="pointer-events-none absolute inset-0 flex items-center justify-center text-[10px] font-bold text-white"
+												>{Math.round(neuPct)}%</span
+											>
+										{/if}
+									</button>
 									<button
 										type="button"
-										class="h-full bg-red-500 transition-opacity hover:opacity-90"
-										style="width: {(aspect.negative / (aspect.positive + aspect.neutral + aspect.negative)) * 100}%"
+										class="relative h-full bg-red-500 transition-opacity hover:opacity-90"
+										style="width: {negPct}%"
 										onclick={() => openAspectDrilldown(aspect.aspect, 'negative')}
 										aria-label={`Ver pontos negativos de ${aspect.aspect}`}
-									></button>
+									>
+										{#if negPct >= 12}
+											<span
+												class="pointer-events-none absolute inset-0 flex items-center justify-center text-[10px] font-bold text-white"
+												>{Math.round(negPct)}%</span
+											>
+										{/if}
+									</button>
 								</div>
 							</div>
 						{/each}
@@ -754,6 +858,7 @@
 					</div>
 				{/if}
 			</div>
+
 		</div>
 	</div>
 </div>

+ 13 - 93
src/routes/(app)/dashboard/agents/+page.svelte

@@ -12,15 +12,6 @@
 		ShieldCheck,
 		MessageSquare
 	} from 'lucide-svelte';
-	import { onMount } from 'svelte';
-
-	let isLoading = $state(true);
-	onMount(() => {
-		setTimeout(() => {
-			isLoading = false;
-		}, 700);
-	});
-
 	// ── Mock agents ───────────────────────────────────────────────────────────
 	let agents = $state([
 		{
@@ -297,7 +288,7 @@
 </script>
 
 <svelte:head>
-	<title>Agentes - Nettown Analytics</title>
+	<title>Operadores - Nettown Analytics</title>
 </svelte:head>
 
 <!-- New Agent Modal -->
@@ -317,7 +308,7 @@
 				class="flex items-center justify-between border-b border-slate-200 p-5 dark:border-slate-700"
 			>
 				<h2 class="text-base font-bold text-slate-900 dark:text-white">
-					{editingId !== null ? 'Editar Agente' : 'Cadastrar Novo Agente'}
+					{editingId !== null ? 'Editar Operador' : 'Cadastrar Novo Operador'}
 				</h2>
 				<button
 					onclick={() => (showModal = false)}
@@ -463,9 +454,9 @@
 				<Users size={20} strokeWidth={2.5} />
 			</div>
 			<div>
-				<h1 class="text-xl font-bold text-slate-900 dark:text-white">Gestão de Agentes</h1>
+				<h1 class="text-xl font-bold text-slate-900 dark:text-white">Gestão de Operadores</h1>
 				<p class="text-sm text-slate-500 dark:text-slate-400">
-					Gerencie a equipe de atendimento e configure escalonamentos
+					Gerencie a equipe de atendimento e seus operadores
 				</p>
 			</div>
 		</div>
@@ -474,23 +465,14 @@
 			class="flex items-center gap-2 rounded-lg bg-indigo-600 px-4 py-2.5 text-sm font-semibold text-white shadow-sm transition-all hover:-translate-y-0.5 hover:bg-indigo-700 hover:shadow-md dark:bg-indigo-500 dark:hover:bg-indigo-600"
 		>
 			<UserPlus size={16} strokeWidth={2.5} />
-			+ Cadastrar Agente
+			+ Cadastrar Operador
 		</button>
 	</div>
 
 	<!-- Stats row -->
-	{#if isLoading}
-		<div class="grid grid-cols-2 gap-4 xl:grid-cols-4">
-			{#each [1, 2, 3, 4] as _}
-				<div
-					class="h-20 animate-pulse rounded-xl border border-slate-200 bg-slate-100 dark:border-slate-800 dark:bg-slate-800"
-				></div>
-			{/each}
-		</div>
-	{:else}
-		<div class="grid grid-cols-2 gap-4 xl:grid-cols-4">
+	<div class="grid grid-cols-2 gap-4 xl:grid-cols-4">
 			{#each [
-				{ label: 'Total de Agentes', value: stats.total, color: 'text-slate-900 dark:text-white', icon: Users, bg: 'bg-slate-100 dark:bg-slate-800', iconCls: 'text-slate-600 dark:text-slate-400' },
+				{ label: 'Total de Operadores', value: stats.total, color: 'text-slate-900 dark:text-white', icon: Users, bg: 'bg-slate-100 dark:bg-slate-800', iconCls: 'text-slate-600 dark:text-slate-400' },
 				{ label: 'Ativos agora', value: stats.active, color: 'text-emerald-600 dark:text-emerald-400', icon: CheckCircle, bg: 'bg-emerald-50 dark:bg-emerald-400/10', iconCls: 'text-emerald-600 dark:text-emerald-400' },
 				{ label: 'Em atendimento', value: stats.inAttendance, color: 'text-sky-600 dark:text-sky-400', icon: MessageSquare, bg: 'bg-sky-50 dark:bg-sky-400/10', iconCls: 'text-sky-600 dark:text-sky-400' },
 				{ label: 'Disp. para escalonamento', value: stats.availableForEscalation, color: 'text-indigo-600 dark:text-indigo-400', icon: ShieldCheck, bg: 'bg-indigo-50 dark:bg-indigo-400/10', iconCls: 'text-indigo-600 dark:text-indigo-400' }
@@ -508,8 +490,7 @@
 					</div>
 				</div>
 			{/each}
-		</div>
-	{/if}
+	</div>
 
 	<!-- Filter bar -->
 	<div
@@ -566,16 +547,7 @@
 	<div
 		class="overflow-hidden rounded-xl border border-slate-200 bg-white shadow-sm transition-colors duration-200 dark:border-slate-800 dark:bg-[#1e293b]"
 	>
-		{#if isLoading}
-			<div class="space-y-3 p-4">
-				{#each [1, 2, 3, 4, 5] as _}
-					<div
-						class="h-14 animate-pulse rounded-lg bg-slate-100 dark:bg-slate-800"
-					></div>
-				{/each}
-			</div>
-		{:else}
-			<div class="overflow-x-auto">
+		<div class="overflow-x-auto">
 				<table class="w-full min-w-[960px] text-sm">
 					<thead>
 						<tr class="border-b border-slate-200 bg-slate-50 dark:border-slate-800 dark:bg-slate-900/50">
@@ -583,22 +555,19 @@
 							<th class="px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-slate-500 dark:text-slate-400">Depto</th>
 							<th class="px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-slate-500 dark:text-slate-400">Canal</th>
 							<th class="px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-slate-500 dark:text-slate-400">Status</th>
-							<th class="px-4 py-3 text-center text-xs font-semibold uppercase tracking-wide text-slate-500 dark:text-slate-400">Escalonamento</th>
-							<th class="px-4 py-3 text-center text-xs font-semibold uppercase tracking-wide text-slate-500 dark:text-slate-400">Hoje</th>
 							<th class="px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-slate-500 dark:text-slate-400">T. Médio Resp.</th>
-							<th class="px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-slate-500 dark:text-slate-400">SLA Cumprido</th>
 							<th class="px-4 py-3 text-center text-xs font-semibold uppercase tracking-wide text-slate-500 dark:text-slate-400">Ações</th>
 						</tr>
 					</thead>
 					<tbody class="divide-y divide-slate-100 dark:divide-slate-800">
 						{#if filteredAgents.length === 0}
 							<tr>
-								<td colspan="9" class="py-16 text-center">
+								<td colspan="6" class="py-16 text-center">
 									<div class="flex flex-col items-center gap-3">
 										<div class="flex h-12 w-12 items-center justify-center rounded-full bg-slate-100 dark:bg-slate-800">
 											<Users size={20} class="text-slate-400" />
 										</div>
-										<div class="text-sm font-medium text-slate-500 dark:text-slate-400">Nenhum agente encontrado</div>
+										<div class="text-sm font-medium text-slate-500 dark:text-slate-400">Nenhum operador encontrado</div>
 										<div class="text-xs text-slate-400 dark:text-slate-500">Tente ajustar os filtros acima</div>
 									</div>
 								</td>
@@ -661,33 +630,6 @@
 										</div>
 									</td>
 
-									<!-- Escalonamento toggle -->
-									<td class="px-4 py-3 text-center">
-										<button
-											type="button"
-											onclick={() => toggleEscalation(agent.id)}
-											class="relative inline-flex h-5 w-9 shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 focus:outline-none {agent.availableForEscalation
-												? 'bg-indigo-600 dark:bg-indigo-500'
-												: 'bg-slate-200 dark:bg-slate-700'}"
-											title={agent.availableForEscalation
-												? 'Disponível para escalonamento'
-												: 'Indisponível para escalonamento'}
-										>
-											<span
-												class="pointer-events-none inline-block h-4 w-4 transform rounded-full bg-white shadow transition duration-200 {agent.availableForEscalation
-													? 'translate-x-4'
-													: 'translate-x-0'}"
-											></span>
-										</button>
-									</td>
-
-									<!-- Atendimentos hoje -->
-									<td class="px-4 py-3 text-center">
-										<span class="font-semibold text-slate-900 dark:text-white"
-											>{agent.todayAttendances}</span
-										>
-									</td>
-
 									<!-- Tempo médio -->
 									<td class="px-4 py-3">
 										<div class="flex items-center gap-1.5">
@@ -697,34 +639,13 @@
 										</div>
 									</td>
 
-									<!-- SLA progress -->
-									<td class="px-4 py-3">
-										<div class="flex items-center gap-2">
-											<div class="h-2 w-20 overflow-hidden rounded-full bg-slate-100 dark:bg-slate-800">
-												<div
-													class="h-full rounded-full {slaBarClass(agent.slaPct)}"
-													style="width: {agent.slaPct}%"
-												></div>
-											</div>
-											<span
-												class="text-xs font-semibold {agent.slaPct >= 90
-													? 'text-emerald-600 dark:text-emerald-400'
-													: agent.slaPct >= 70
-													? 'text-amber-600 dark:text-amber-400'
-													: 'text-red-600 dark:text-red-400'}"
-											>
-												{agent.slaPct}%
-											</span>
-										</div>
-									</td>
-
 									<!-- Ações -->
 									<td class="px-4 py-3">
 										<div class="flex items-center justify-center gap-2">
 											<button
 												onclick={() => openEditAgent(agent)}
 												class="rounded-md p-1.5 text-slate-400 transition-colors hover:bg-slate-100 hover:text-slate-700 dark:hover:bg-slate-800 dark:hover:text-slate-200"
-												title="Editar agente"
+												title="Editar operador"
 											>
 												<Edit size={15} />
 											</button>
@@ -733,7 +654,7 @@
 												class="rounded-md p-1.5 transition-colors {agent.status === 'Inativo'
 													? 'text-emerald-500 hover:bg-emerald-50 hover:text-emerald-700 dark:hover:bg-emerald-400/10'
 													: 'text-slate-400 hover:bg-red-50 hover:text-red-600 dark:hover:bg-red-400/10 dark:hover:text-red-400'}"
-												title={agent.status === 'Inativo' ? 'Reativar agente' : 'Desativar agente'}
+												title={agent.status === 'Inativo' ? 'Reativar operador' : 'Desativar operador'}
 											>
 												<Power size={15} />
 											</button>
@@ -745,6 +666,5 @@
 					</tbody>
 				</table>
 			</div>
-		{/if}
 	</div>
 </div>

+ 55 - 2
src/routes/(app)/dashboard/analytics/+page.svelte

@@ -16,8 +16,41 @@
 	const timeframeOptions = [
 		{ id: 'day', label: 'Últimos 7 dias' },
 		{ id: 'week', label: 'Últimas 6 semanas' },
-		{ id: 'month', label: 'Últimos 6 meses' }
+		{ id: 'month', label: 'Últimos 6 meses' },
+		{ id: 'custom', label: 'Personalizado' }
 	];
+
+	let customDateStart = $state('');
+	let customDateEnd = $state('');
+	let confirmedCustomStart = $state('');
+	let confirmedCustomEnd = $state('');
+
+	function pseudoRandom(seed) {
+		const x = Math.sin(seed + 1) * 10000;
+		return x - Math.floor(x);
+	}
+
+	function generateCustomTimelineData(startStr, endStr) {
+		const start = new Date(startStr + 'T00:00:00');
+		const end = new Date(endStr + 'T00:00:00');
+		const diffDays = Math.round((end - start) / (1000 * 60 * 60 * 24));
+		if (diffDays <= 0) return [];
+		const step = diffDays <= 14 ? 1 : 7;
+		const points = [];
+		let idx = 0;
+		for (let d = 0; d <= diffDays; d += step) {
+			idx++;
+			const date = new Date(start.getTime() + d * 24 * 60 * 60 * 1000);
+			const gains = Math.round(35 + idx * 2.5 + pseudoRandom(idx * 3.7) * 10);
+			const losses = Math.round(15 + pseudoRandom(idx * 2.1 + 5) * 6);
+			const label = diffDays <= 14
+				? date.toLocaleDateString('pt-BR', { day: '2-digit', month: '2-digit' })
+				: `Sem ${idx}`;
+			points.push({ period: label, gains, losses });
+		}
+		return points;
+	}
+
 	const defaultInsight = {
 		title: 'Painel de decisao',
 		context: 'Clique em um card, alerta ou ponto do grafico para entender o que esta acontecendo e qual acao executar.',
@@ -33,7 +66,13 @@
 	let selectedPeriod = $state(null);
 	let selectedTimeframe = $state('week');
 	let selectedInsight = $state(defaultInsight);
-	const timelineData = $derived(dashboardData.timelineViews?.[selectedTimeframe] ?? dashboardData.timeline);
+
+	const timelineData = $derived.by(() => {
+		if (selectedTimeframe === 'custom' && confirmedCustomStart && confirmedCustomEnd) {
+			return generateCustomTimelineData(confirmedCustomStart, confirmedCustomEnd);
+		}
+		return dashboardData.timelineViews?.[selectedTimeframe] ?? dashboardData.timeline;
+	});
 
 	// Read initial state from URL query parameters
 	let panelAspectId = $state($page.url.searchParams.get('aspect') ?? null);
@@ -75,6 +114,17 @@
 		selectedTimeframe = value;
 		selectedPeriod = null;
 		selectedInsight = defaultInsight;
+		if (value !== 'custom') {
+			confirmedCustomStart = '';
+			confirmedCustomEnd = '';
+		}
+	}
+
+	function handleConfirmCustomDates(start, end) {
+		confirmedCustomStart = start;
+		confirmedCustomEnd = end;
+		selectedPeriod = null;
+		selectedInsight = defaultInsight;
 	}
 </script>
 
@@ -105,6 +155,9 @@
 				timeframeOptions={timeframeOptions}
 				selectedTimeframe={selectedTimeframe}
 				onTimeframeChange={handleTimeframeChange}
+				onConfirmCustomDates={handleConfirmCustomDates}
+				bind:customDateStart
+				bind:customDateEnd
 			/>
 		</div>
 		<div class="2xl:col-span-2 flex flex-col">

+ 35 - 2
src/routes/(app)/dashboard/evolucao/+page.svelte

@@ -6,10 +6,15 @@
 
 	const periodOptions = [
 		{ id: 'week', label: 'Últimos 7 dias', multiplier: 1, sentimentBoost: 0 },
-		{ id: 'month', label: 'Últimos 30 dias', multiplier: 1.25, sentimentBoost: 0.05 },
-		{ id: 'quarter', label: 'Último trimestre', multiplier: 1.5, sentimentBoost: 0.08 }
+		{ id: '6weeks', label: 'Últimas 6 semanas', multiplier: 1.2, sentimentBoost: 0.04 },
+		{ id: '6months', label: 'Últimos 6 meses', multiplier: 1.5, sentimentBoost: 0.08 },
+		{ id: 'quarter', label: 'Último trimestre', multiplier: 1.35, sentimentBoost: 0.06 },
+		{ id: 'custom', label: 'Personalizado', multiplier: 1, sentimentBoost: 0 }
 	];
 
+	let customDateStart = $state('');
+	let customDateEnd = $state('');
+
 	const unitOptions = [
 		{ id: 'all', label: 'Sem segmento', multiplier: 1 },
 		{ id: 'flagship', label: 'Loja Flagship', multiplier: 1.2 },
@@ -272,6 +277,34 @@
 			</div>
 		</div>
 
+		<!-- Custom date range (shown only when Personalizado is selected) -->
+		{#if selectedPeriod === 'custom'}
+			<div class="flex flex-wrap items-center gap-4 rounded-lg border border-indigo-200 bg-indigo-50 px-4 py-3 text-sm dark:border-indigo-500/30 dark:bg-indigo-500/10 mb-6">
+				<span class="text-xs font-semibold text-indigo-700 dark:text-indigo-400">Período personalizado:</span>
+				<div class="flex items-center gap-2">
+					<label class="text-xs font-medium text-slate-600 dark:text-slate-400">De</label>
+					<input
+						type="date"
+						bind:value={customDateStart}
+						class="rounded-md border border-slate-300 bg-white px-2 py-1 text-xs text-slate-900 focus:border-indigo-500 focus:outline-none dark:border-slate-700 dark:bg-[#0f172a] dark:text-slate-200"
+					/>
+				</div>
+				<div class="flex items-center gap-2">
+					<label class="text-xs font-medium text-slate-600 dark:text-slate-400">Até</label>
+					<input
+						type="date"
+						bind:value={customDateEnd}
+						class="rounded-md border border-slate-300 bg-white px-2 py-1 text-xs text-slate-900 focus:border-indigo-500 focus:outline-none dark:border-slate-700 dark:bg-[#0f172a] dark:text-slate-200"
+					/>
+				</div>
+				{#if customDateStart && customDateEnd}
+					<span class="text-xs text-indigo-600 dark:text-indigo-400 font-medium">
+						Exibindo dados de {new Date(customDateStart + 'T00:00:00').toLocaleDateString('pt-BR')} a {new Date(customDateEnd + 'T00:00:00').toLocaleDateString('pt-BR')}
+					</span>
+				{/if}
+			</div>
+		{/if}
+
 		<!-- KPIs -->
 		<div class="grid grid-cols-2 md:grid-cols-5 gap-6 w-full pb-4">
 			<div class="flex flex-col items-center justify-center text-center">

+ 13 - 62
src/routes/(app)/dashboard/executive/+page.svelte

@@ -9,18 +9,8 @@
 		MessageSquare,
 		UserRound,
 		Settings,
-		BarChart2,
-		BookOpen
+		BarChart2
 	} from 'lucide-svelte';
-	import { onMount } from 'svelte';
-
-	let isLoading = $state(true);
-	onMount(() => {
-		setTimeout(() => {
-			isLoading = false;
-		}, 700);
-	});
-
 	// ── Section 1: Top KPIs ──────────────────────────────────────────────────
 	const topKpis = [
 		{
@@ -152,7 +142,7 @@
 			border: 'border-purple-200 dark:border-purple-400/20'
 		},
 		{
-			label: 'Agentes',
+			label: 'Operadores',
 			href: '/dashboard/agents',
 			icon: Users,
 			metric: '12 ativos',
@@ -162,17 +152,6 @@
 			bg: 'bg-emerald-50 dark:bg-emerald-400/10',
 			border: 'border-emerald-200 dark:border-emerald-400/20'
 		},
-		{
-			label: 'Playbooks',
-			href: '/dashboard/evolucao',
-			icon: BookOpen,
-			metric: '3 ativos',
-			trend: '→',
-			trendColor: 'text-slate-500 dark:text-slate-400',
-			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'
-		},
 		{
 			label: 'Configurações',
 			href: '/dashboard/settings',
@@ -222,16 +201,7 @@
 	</div>
 
 	<!-- Section 1: KPI Bar -->
-	{#if isLoading}
-		<div class="grid grid-cols-1 gap-4 sm:grid-cols-2 xl:grid-cols-4">
-			{#each [1, 2, 3, 4] as _}
-				<div
-					class="h-28 animate-pulse rounded-xl border border-slate-200 bg-slate-100 dark:border-slate-800 dark:bg-slate-800"
-				></div>
-			{/each}
-		</div>
-	{:else}
-		<div class="grid grid-cols-1 gap-4 sm:grid-cols-2 xl:grid-cols-4">
+	<div class="grid grid-cols-1 gap-4 sm:grid-cols-2 xl:grid-cols-4">
 			{#each topKpis as kpi}
 				{@const Icon = kpi.icon}
 				<div
@@ -259,20 +229,10 @@
 					</div>
 				</div>
 			{/each}
-		</div>
-	{/if}
+	</div>
 
 	<!-- Section 2: Risk Overview -->
-	{#if isLoading}
-		<div class="grid grid-cols-1 gap-6 lg:grid-cols-3">
-			{#each [1, 2, 3] as _}
-				<div
-					class="h-64 animate-pulse rounded-xl border border-slate-200 bg-slate-100 dark:border-slate-800 dark:bg-slate-800"
-				></div>
-			{/each}
-		</div>
-	{:else}
-		<div class="grid grid-cols-1 gap-6 lg:grid-cols-3">
+	<div class="grid grid-cols-1 gap-6 lg:grid-cols-3">
 			<!-- Churn Donut -->
 			<div
 				class="rounded-xl border border-slate-200 bg-white p-5 shadow-sm transition-colors duration-200 dark:border-slate-800 dark:bg-[#1e293b]"
@@ -420,17 +380,11 @@
 					</div>
 				</div>
 			</div>
-		</div>
-	{/if}
+	</div>
 
 	<!-- Section 3: Sentiment Summary -->
-	{#if isLoading}
-		<div
-			class="h-56 animate-pulse rounded-xl border border-slate-200 bg-slate-100 dark:border-slate-800 dark:bg-slate-800"
-		></div>
-	{:else}
-		<div
-			class="rounded-xl border border-slate-200 bg-white p-5 shadow-sm transition-colors duration-200 dark:border-slate-800 dark:bg-[#1e293b]"
+	<div
+		class="rounded-xl border border-slate-200 bg-white p-5 shadow-sm transition-colors duration-200 dark:border-slate-800 dark:bg-[#1e293b]"
 		>
 			<div class="mb-5 flex items-center gap-2">
 				<div
@@ -524,15 +478,13 @@
 				</div>
 			</div>
 		</div>
-	{/if}
 
 	<!-- Section 4: Quick Access -->
-	{#if !isLoading}
-		<div
-			class="rounded-xl border border-slate-200 bg-white p-5 shadow-sm transition-colors duration-200 dark:border-slate-800 dark:bg-[#1e293b]"
-		>
+	<div
+		class="rounded-xl border border-slate-200 bg-white p-5 shadow-sm transition-colors duration-200 dark:border-slate-800 dark:bg-[#1e293b]"
+	>
 			<h2 class="mb-4 text-base font-bold text-slate-900 dark:text-white">Acesso Rápido</h2>
-			<div class="grid grid-cols-2 gap-4 sm:grid-cols-3 xl:grid-cols-6">
+			<div class="grid grid-cols-2 gap-4 sm:grid-cols-3 xl:grid-cols-5">
 				{#each quickAccessItems as item}
 					{@const Icon = item.icon}
 					<a
@@ -552,6 +504,5 @@
 					</a>
 				{/each}
 			</div>
-		</div>
-	{/if}
+	</div>
 </div>

+ 108 - 6
src/routes/(app)/dashboard/interactions/+page.svelte

@@ -1,5 +1,5 @@
 <script>
-	import { Search, Download, Eye, X, MessageCircle } from 'lucide-svelte';
+	import { Search, Download, Eye, X, MessageCircle, Copy, CheckCircle } from 'lucide-svelte';
 	import { mockInteractions } from '$lib/core/models/mock-data.js';
 
 	let searchQuery = $state('');
@@ -120,9 +120,45 @@
 		}
 	}
 
+	let isSummaryLoading = $state(false);
+	let summaryText = $state(null);
+	let isCopied = $state(false);
+
+	// This summary helps the next agent who takes over the conversation understand the full context quickly
+	function generateSummary() {
+		if (!selectedInteraction) return;
+		isSummaryLoading = true;
+		summaryText = null;
+
+		// Placeholder event — wire to an AI/summary service in production
+		const payload = {
+			conversationId: selectedInteraction.client,
+			messages: selectedInteraction.thread ?? []
+		};
+		if (typeof onGenerateSummary === 'function') onGenerateSummary(payload);
+
+		setTimeout(() => {
+			summaryText = `Cliente ${selectedInteraction.client} — Sentimento detectado: ${selectedInteraction.sentiment} (score ${selectedInteraction.score}). Tema principal: ${selectedInteraction.aspect} / ${selectedInteraction.subaspect}. Atendimento registrado em ${selectedInteraction.datetime} por ${selectedInteraction.agent === '-' ? 'equipe automática' : selectedInteraction.agent}. Recomendar continuidade com foco no tema identificado.`;
+			isSummaryLoading = false;
+		}, 2000);
+	}
+
+	async function copyToClipboard(text) {
+		try {
+			await navigator.clipboard.writeText(text);
+			isCopied = true;
+			setTimeout(() => {
+				isCopied = false;
+			}, 2000);
+		} catch (_) {}
+	}
+
 	function openChat(interaction) {
 		selectedInteraction = interaction;
 		isChatModalOpen = true;
+		summaryText = null;
+		isSummaryLoading = false;
+		isCopied = false;
 	}
 
 	function closeChat() {
@@ -212,10 +248,15 @@
 					>
 						<th class="p-4">Cliente</th>
 						<th class="p-4">Agente</th>
-						<th class="p-4">Sentimento Geral</th>
-						<th class="p-4">Score</th>
-						<th class="p-4">Aspectos Detectados</th>
-						<th class="p-4">Subaspectos Detectados</th>
+						<th class="p-4">Emoção Geral</th>
+						<th class="p-4">
+							Score do Sentimento
+							<div class="text-[10px] font-normal normal-case text-slate-400 dark:text-slate-500">
+								(−1 a +1)
+							</div>
+						</th>
+						<th class="p-4">Tema da Conversa</th>
+						<th class="p-4">Subtemas</th>
 						<th class="p-4">Data e Hora</th>
 						<th class="p-4 text-right">Análise Avançada</th>
 					</tr>
@@ -365,6 +406,67 @@
 								</div>
 							</div>
 						{/each}
+
+						<!-- AI Summary — helps the next agent understand conversation context quickly -->
+						<div class="border-t border-slate-200 pt-5 dark:border-slate-700">
+							{#if summaryText}
+								<div
+									class="mb-4 rounded-lg border border-indigo-200 bg-indigo-50/70 p-4 dark:border-indigo-500/20 dark:bg-indigo-500/10"
+								>
+									<div class="mb-2 flex items-center justify-between">
+										<span
+											class="text-[10px] font-bold tracking-wider text-indigo-600 uppercase dark:text-indigo-400"
+											>Resumo gerado pela IA</span
+										>
+										<button
+											onclick={() => copyToClipboard(summaryText)}
+											class="rounded p-1 text-indigo-400 transition-colors hover:bg-indigo-100 hover:text-indigo-600 dark:hover:bg-indigo-500/20 dark:hover:text-indigo-300"
+											title="Copiar resumo"
+										>
+											{#if isCopied}
+												<CheckCircle size={14} class="text-emerald-500" />
+											{:else}
+												<Copy size={14} />
+											{/if}
+										</button>
+									</div>
+									<p class="text-sm leading-relaxed text-slate-700 dark:text-slate-300">
+										{summaryText}
+									</p>
+								</div>
+							{/if}
+
+							<button
+								onclick={generateSummary}
+								disabled={isSummaryLoading}
+								class="flex w-full items-center justify-center gap-2 rounded-lg border border-slate-300 bg-white px-4 py-2.5 text-sm font-medium text-slate-700 shadow-sm transition-colors hover:bg-slate-50 disabled:cursor-wait disabled:opacity-70 dark:border-slate-700 dark:bg-slate-800/60 dark:text-slate-200 dark:shadow-none dark:hover:bg-slate-700"
+							>
+								{#if isSummaryLoading}
+									<svg
+										class="h-4 w-4 animate-spin text-indigo-500"
+										viewBox="0 0 24 24"
+										fill="none"
+									>
+										<circle
+											class="opacity-25"
+											cx="12"
+											cy="12"
+											r="10"
+											stroke="currentColor"
+											stroke-width="4"
+										></circle>
+										<path
+											class="opacity-75"
+											fill="currentColor"
+											d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"
+										></path>
+									</svg>
+									Gerando resumo...
+								{:else}
+									Gerar Resumo da Conversa
+								{/if}
+							</button>
+						</div>
 					</div>
 				</div>
 
@@ -474,7 +576,7 @@
 								<div
 									class="mb-1 text-xs font-bold tracking-wider text-slate-500 uppercase dark:text-slate-400"
 								>
-									SUBASPECTO
+									SUBTEMA
 								</div>
 								<div class="text-base font-semibold text-slate-700 dark:text-slate-200">
 									{selectedInteraction?.subaspect || 'Informativo'}

+ 1 - 1
src/routes/(app)/dashboard/personas/+page.svelte

@@ -311,7 +311,7 @@
 					<div
 						class="mb-2 text-[11px] font-semibold tracking-wider text-slate-500 uppercase dark:text-slate-400"
 					>
-						Subaspectos Únicos
+						Subtemas Únicos
 					</div>
 					<div class="text-3xl font-bold text-slate-900 dark:text-white">
 						{formatNumber(personaStats.subaspects)}

+ 145 - 21
src/routes/(app)/dashboard/settings/+page.svelte

@@ -1,9 +1,33 @@
 <script>
-	import { Settings, Phone, Bell, HelpCircle } from 'lucide-svelte';
-	import { goto } from '$app/navigation';
+	import { Settings, Phone, Bell, HelpCircle, ShieldCheck, X } from 'lucide-svelte';
 
-	// Settings sections
-	const settingsSections = [
+	// SLA reactive state
+	let slaConfig = $state([
+		{ dept: 'SAC', responseHours: 2, resolutionHours: 24 },
+		{ dept: 'Vendas', responseHours: 1, resolutionHours: 12 },
+		{ dept: 'Suporte', responseHours: 4, resolutionHours: 48 }
+	]);
+
+	// SLA edit modal
+	let showSlaModal = $state(false);
+	let editingSla = $state(null);
+
+	function openSlaEdit(dept) {
+		const found = slaConfig.find((s) => s.dept === dept);
+		if (found) {
+			editingSla = { ...found };
+			showSlaModal = true;
+		}
+	}
+
+	function saveSla() {
+		const idx = slaConfig.findIndex((s) => s.dept === editingSla.dept);
+		if (idx >= 0) slaConfig[idx] = { ...editingSla };
+		showSlaModal = false;
+	}
+
+	// Static settings sections (non-SLA)
+	const staticSections = [
 		{
 			title: 'Integrações',
 			icon: Phone,
@@ -62,15 +86,7 @@
 	];
 
 	function handleAction(item) {
-		// Handle different actions based on item
 		console.log(`Action: ${item.action} for ${item.title}`);
-		
-		// For WhatsApp integration, we could open a modal or navigate to a specific page
-		if (item.title === 'WhatsApp Business') {
-			// TODO: Open WhatsApp configuration modal
-		} else if (item.title === 'WhatsApp dos Vendedores') {
-			// TODO: Open sellers WhatsApp configuration
-		}
 	}
 
 	function getStatusBadge(status) {
@@ -80,15 +96,87 @@
 			enabled: { text: 'Ativo', class: 'bg-green-100 text-green-800 dark:bg-green-900/30 dark:text-green-400' },
 			disabled: { text: 'Inativo', class: 'bg-slate-100 text-slate-800 dark:bg-slate-900/30 dark:text-slate-400' },
 			configured: { text: 'Configurado', class: 'bg-green-100 text-green-800 dark:bg-green-900/30 dark:text-green-400' },
-			available: { text: 'Disponível', class: 'bg-blue-100 text-blue-800 dark:bg-blue-900/30 dark:text-blue-400' },
-			dark: { text: 'Escuro', class: 'bg-slate-100 text-slate-800 dark:bg-slate-900/30 dark:text-slate-400' },
-			'pt-BR': { text: 'Português', class: 'bg-blue-100 text-blue-800 dark:bg-blue-900/30 dark:text-blue-400' }
+			available: { text: 'Disponível', class: 'bg-blue-100 text-blue-800 dark:bg-blue-900/30 dark:text-blue-400' }
 		};
-
 		return statusConfig[status] || statusConfig.available;
 	}
 </script>
 
+<!-- SLA Edit Modal -->
+{#if showSlaModal && editingSla}
+	<div
+		class="fixed inset-0 z-50 flex items-center justify-center bg-slate-950/80 p-4"
+		onclick={(e) => e.target === e.currentTarget && (showSlaModal = false)}
+		onkeydown={(e) => e.key === 'Escape' && (showSlaModal = false)}
+		role="dialog"
+		aria-modal="true"
+		tabindex="-1"
+	>
+		<div class="w-full max-w-md rounded-xl border border-slate-200 bg-white shadow-2xl dark:border-slate-700 dark:bg-[#1e293b]">
+			<div class="flex items-center justify-between border-b border-slate-200 p-5 dark:border-slate-700">
+				<h2 class="text-base font-bold text-slate-900 dark:text-white">
+					Editar SLA — {editingSla.dept}
+				</h2>
+				<button
+					onclick={() => (showSlaModal = false)}
+					class="rounded-lg p-1.5 text-slate-400 transition-colors hover:bg-slate-100 hover:text-slate-700 dark:hover:bg-slate-800 dark:hover:text-white"
+				>
+					<X size={18} />
+				</button>
+			</div>
+
+			<div class="space-y-5 p-5">
+				<div>
+					<label class="mb-1.5 block text-xs font-semibold uppercase tracking-wide text-slate-500 dark:text-slate-400">
+						Tempo máximo de resposta (horas)
+					</label>
+					<div class="flex items-center gap-3">
+						<input
+							type="number"
+							min="1"
+							max="72"
+							bind:value={editingSla.responseHours}
+							class="w-28 rounded-lg border border-slate-300 bg-slate-50 px-3 py-2 text-sm text-slate-900 focus:border-indigo-500 focus:bg-white focus:ring-1 focus:ring-indigo-500 focus:outline-none dark:border-slate-700 dark:bg-slate-900 dark:text-slate-200"
+						/>
+						<span class="text-sm text-slate-500 dark:text-slate-400">hora{editingSla.responseHours !== 1 ? 's' : ''}</span>
+					</div>
+				</div>
+
+				<div>
+					<label class="mb-1.5 block text-xs font-semibold uppercase tracking-wide text-slate-500 dark:text-slate-400">
+						Tempo máximo de resolução (horas)
+					</label>
+					<div class="flex items-center gap-3">
+						<input
+							type="number"
+							min="1"
+							max="720"
+							bind:value={editingSla.resolutionHours}
+							class="w-28 rounded-lg border border-slate-300 bg-slate-50 px-3 py-2 text-sm text-slate-900 focus:border-indigo-500 focus:bg-white focus:ring-1 focus:ring-indigo-500 focus:outline-none dark:border-slate-700 dark:bg-slate-900 dark:text-slate-200"
+						/>
+						<span class="text-sm text-slate-500 dark:text-slate-400">hora{editingSla.resolutionHours !== 1 ? 's' : ''}</span>
+					</div>
+				</div>
+			</div>
+
+			<div class="flex justify-end gap-3 border-t border-slate-200 p-5 dark:border-slate-700">
+				<button
+					onclick={() => (showSlaModal = false)}
+					class="rounded-lg border border-slate-300 bg-white px-4 py-2 text-sm font-medium text-slate-700 transition-colors hover:bg-slate-50 dark:border-slate-700 dark:bg-slate-800 dark:text-slate-200 dark:hover:bg-slate-700"
+				>
+					Cancelar
+				</button>
+				<button
+					onclick={saveSla}
+					class="rounded-lg bg-indigo-600 px-4 py-2 text-sm font-semibold text-white transition-colors hover:bg-indigo-700 dark:bg-indigo-500 dark:hover:bg-indigo-600"
+				>
+					Salvar
+				</button>
+			</div>
+		</div>
+	</div>
+{/if}
+
 <div class="mx-auto max-w-[1600px] space-y-6">
 	<!-- Header -->
 	<div class="rounded-xl border border-slate-200 bg-white p-5 md:p-6 shadow-sm transition-colors duration-200 dark:border-slate-800 dark:bg-[#161f30]">
@@ -103,11 +191,10 @@
 		</p>
 	</div>
 
-	<!-- Settings Sections -->
+	<!-- Static Settings Sections -->
 	<div class="grid grid-cols-1 gap-6">
-		{#each settingsSections as section}
+		{#each staticSections as section}
 			<div class="rounded-xl border border-slate-200 bg-white shadow-sm transition-colors duration-200 dark:border-slate-800 dark:bg-[#161f30]">
-				<!-- Section Header -->
 				<div class="border-b border-slate-200 p-5 dark:border-slate-800">
 					<div class="flex items-center gap-3">
 						<div class="h-8 w-8 shrink-0 rounded-lg bg-slate-100 text-slate-600 flex items-center justify-center dark:bg-slate-800 dark:text-slate-400">
@@ -116,8 +203,6 @@
 						<h2 class="text-lg font-semibold text-slate-900 dark:text-white">{section.title}</h2>
 					</div>
 				</div>
-
-				<!-- Section Items -->
 				<div class="divide-y divide-slate-200 dark:divide-slate-800">
 					{#each section.items as item}
 						<div class="p-5 hover:bg-slate-50 transition-colors duration-150 dark:hover:bg-slate-800/50">
@@ -148,5 +233,44 @@
 				</div>
 			</div>
 		{/each}
+
+		<!-- SLA Section (reactive) -->
+		<div class="rounded-xl border border-slate-200 bg-white shadow-sm transition-colors duration-200 dark:border-slate-800 dark:bg-[#161f30]">
+			<div class="border-b border-slate-200 p-5 dark:border-slate-800">
+				<div class="flex items-center gap-3">
+					<div class="h-8 w-8 shrink-0 rounded-lg bg-slate-100 text-slate-600 flex items-center justify-center dark:bg-slate-800 dark:text-slate-400">
+						<ShieldCheck size={18} strokeWidth={2} />
+					</div>
+					<h2 class="text-lg font-semibold text-slate-900 dark:text-white">Configuração de SLA</h2>
+				</div>
+			</div>
+			<div class="divide-y divide-slate-200 dark:divide-slate-800">
+				{#each slaConfig as sla}
+					<div class="p-5 hover:bg-slate-50 transition-colors duration-150 dark:hover:bg-slate-800/50">
+						<div class="flex items-center justify-between">
+							<div class="flex-1 min-w-0">
+								<div class="flex items-center gap-3">
+									<h3 class="text-sm font-medium text-slate-900 dark:text-white">{sla.dept}</h3>
+									<span class="inline-flex items-center px-2 py-1 rounded-full text-xs font-medium bg-green-100 text-green-800 dark:bg-green-900/30 dark:text-green-400">
+										Configurado
+									</span>
+								</div>
+								<p class="mt-1 text-sm text-slate-600 dark:text-slate-400">
+									Resposta máxima: {sla.responseHours}h · Resolução máxima: {sla.resolutionHours}h
+								</p>
+							</div>
+							<div class="ml-4">
+								<button
+									onclick={() => openSlaEdit(sla.dept)}
+									class="inline-flex items-center px-3 py-1.5 text-xs font-medium rounded-md bg-indigo-600 text-white hover:bg-indigo-700 transition-colors duration-150"
+								>
+									editar
+								</button>
+							</div>
+						</div>
+					</div>
+				{/each}
+			</div>
+		</div>
 	</div>
 </div>