+page.svelte 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. <script>
  2. import { Users, AlertTriangle, DollarSign, Compass, UserRound, TrendingUp, HeartHandshake } from 'lucide-svelte';
  3. import { mockPersonasKpis, mockPersonas } from '$lib/core/models/mock-data.js';
  4. let selectedPersona = $state(null);
  5. function openPersonaDetails(persona) {
  6. selectedPersona = persona;
  7. }
  8. function closePersonaDetails() {
  9. selectedPersona = null;
  10. }
  11. </script>
  12. <svelte:head>
  13. <title>Laboratório de Personas - Nettown Analytics</title>
  14. </svelte:head>
  15. <div class="mx-auto max-w-[1600px] space-y-6">
  16. <!-- Top Section: Header, Filters, KPIs -->
  17. <div class="rounded-xl border border-slate-200 bg-white p-5 md:p-8 shadow-sm transition-colors duration-200 dark:border-slate-800 dark:bg-[#161f30]">
  18. <div class="flex items-center gap-3 mb-8">
  19. <div class="h-8 w-8 shrink-0 rounded-lg bg-amber-500/20 text-amber-500 flex items-center justify-center">
  20. <Compass size={20} strokeWidth={2.5} />
  21. </div>
  22. <h1 class="text-xl font-bold text-slate-900 dark:text-white">Expansão: Laboratório de Personas</h1>
  23. </div>
  24. <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 w-full text-sm mb-12">
  25. <div class="flex items-center justify-center gap-2">
  26. <span class="text-slate-500 dark:text-slate-400 whitespace-nowrap">Período:</span>
  27. <select class="rounded-md border border-slate-200 bg-white px-3 py-1.5 text-slate-900 focus:border-indigo-500 focus:outline-none dark:border-slate-700 dark:bg-[#0f172a] dark:text-slate-200">
  28. <option>Últimos 7 dias</option>
  29. </select>
  30. </div>
  31. <div class="flex items-center justify-center gap-2">
  32. <span class="text-slate-500 dark:text-slate-400 whitespace-nowrap">Unidade:</span>
  33. <select class="rounded-md border border-slate-200 bg-white px-3 py-1.5 text-slate-900 focus:border-indigo-500 focus:outline-none dark:border-slate-700 dark:bg-[#0f172a] dark:text-slate-200">
  34. <option>Sem segmento</option>
  35. </select>
  36. </div>
  37. <div class="flex items-center justify-center gap-2">
  38. <span class="text-slate-500 dark:text-slate-400 whitespace-nowrap">Área:</span>
  39. <select class="rounded-md border border-slate-200 bg-white px-3 py-1.5 text-slate-900 focus:border-indigo-500 focus:outline-none dark:border-slate-700 dark:bg-[#0f172a] dark:text-slate-200">
  40. <option>Sem segmento de setor</option>
  41. </select>
  42. </div>
  43. <div class="flex items-center justify-center gap-2">
  44. <span class="text-slate-500 dark:text-slate-400 whitespace-nowrap">Sentimento:</span>
  45. <select class="rounded-md border border-slate-200 bg-white px-3 py-1.5 text-slate-900 focus:border-indigo-500 focus:outline-none dark:border-slate-700 dark:bg-[#0f172a] dark:text-slate-200">
  46. <option>Todos</option>
  47. </select>
  48. </div>
  49. </div>
  50. <!-- KPIs -->
  51. <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 w-full pb-4">
  52. <div class="flex flex-col items-center justify-center text-center">
  53. <UserRound size={24} class="text-amber-500 mb-3 mx-auto" />
  54. <div class="text-3xl font-bold text-slate-900 dark:text-white mb-1">{mockPersonasKpis.ativas}</div>
  55. <div class="text-[11px] font-semibold tracking-wider text-slate-500 uppercase dark:text-slate-400">Personas Ativas</div>
  56. </div>
  57. <div class="flex flex-col items-center justify-center text-center">
  58. <AlertTriangle size={24} class="text-red-500 mb-3 mx-auto" />
  59. <div class="text-3xl font-bold text-slate-900 dark:text-white mb-1">{mockPersonasKpis.riscoChurn}</div>
  60. <div class="text-[11px] font-semibold tracking-wider text-slate-500 uppercase dark:text-slate-400">Risco de Churn</div>
  61. </div>
  62. <div class="flex flex-col items-center justify-center text-center">
  63. <DollarSign size={24} class="text-red-500 mb-3 mx-auto" />
  64. <div class="text-3xl font-bold text-slate-900 dark:text-white mb-1">{mockPersonasKpis.perdaMensalEst}</div>
  65. <div class="text-[11px] font-semibold tracking-wider text-slate-500 uppercase dark:text-slate-400">Perda Mensal Est.</div>
  66. </div>
  67. <div class="flex flex-col items-center justify-center text-center">
  68. <DollarSign size={24} class="text-amber-500 mb-3 mx-auto" />
  69. <div class="text-3xl font-bold text-slate-900 dark:text-white mb-1">{mockPersonasKpis.potencialExpansao}</div>
  70. <div class="text-[11px] font-semibold tracking-wider text-slate-500 uppercase dark:text-slate-400">Potencial de Expansão</div>
  71. </div>
  72. </div>
  73. </div>
  74. <!-- Personas Grid & Details -->
  75. <div class="grid grid-cols-1 xl:grid-cols-3 gap-6">
  76. <div class="xl:col-span-2 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]">
  77. <div class="flex flex-wrap items-center justify-between gap-4 mb-8">
  78. <div class="flex items-center gap-3">
  79. <div class="flex items-center justify-center text-slate-700 dark:text-slate-300">
  80. <UserRound size={20} />
  81. </div>
  82. <h2 class="text-lg font-bold text-slate-900 dark:text-white">Minhas Personas</h2>
  83. <span class="text-sm text-slate-500 dark:text-slate-400">Conheça sua base de forma humana</span>
  84. </div>
  85. <button class="rounded-lg bg-indigo-600 px-5 py-2 text-sm font-semibold text-white transition-colors hover:bg-indigo-700 shadow-sm whitespace-nowrap">
  86. Meus Clientes
  87. </button>
  88. </div>
  89. <!-- Header Stats -->
  90. <div class="grid grid-cols-2 md:grid-cols-4 gap-4 mb-8 pb-8 border-b border-slate-100 dark:border-slate-800/60">
  91. <div class="flex flex-col items-start text-left">
  92. <div class="text-[11px] font-semibold tracking-wider text-slate-500 uppercase dark:text-slate-400 mb-2">
  93. Personas Identificadas
  94. </div>
  95. <div class="text-3xl font-bold text-slate-900 dark:text-white">0</div>
  96. </div>
  97. <div class="flex flex-col items-start text-left">
  98. <div class="text-[11px] font-semibold tracking-wider text-slate-500 uppercase dark:text-slate-400 mb-2">
  99. Volume Total de Mensagens Analisadas
  100. </div>
  101. <div class="text-3xl font-bold text-slate-900 dark:text-white">0</div>
  102. </div>
  103. <div class="flex flex-col items-start text-left">
  104. <div class="text-[11px] font-semibold tracking-wider text-slate-500 uppercase dark:text-slate-400 mb-2">
  105. Aspectos Únicos
  106. </div>
  107. <div class="text-3xl font-bold text-slate-900 dark:text-white">0</div>
  108. </div>
  109. <div class="flex flex-col items-start text-left">
  110. <div class="text-[11px] font-semibold tracking-wider text-slate-500 uppercase dark:text-slate-400 mb-2">
  111. Subaspectos Únicos
  112. </div>
  113. <div class="text-3xl font-bold text-slate-900 dark:text-white">0</div>
  114. </div>
  115. </div>
  116. <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4">
  117. {#each mockPersonas as persona}
  118. <button
  119. type="button"
  120. onclick={() => openPersonaDetails(persona)}
  121. class={`flex flex-col items-center justify-start rounded-xl border p-6 text-center transition-all duration-200 ${
  122. selectedPersona?.id === persona.id
  123. ? 'border-indigo-400 bg-indigo-50/50 shadow-[0_0_15px_rgba(99,102,241,0.15)] dark:border-indigo-500/80 dark:bg-[#1e293b] dark:shadow-[0_0_20px_rgba(99,102,241,0.1)]'
  124. : 'border-slate-200 bg-white hover:border-slate-300 dark:border-slate-700/60 dark:bg-[#1e293b]/40 dark:hover:border-slate-600 dark:hover:bg-[#1e293b]/60'
  125. }`}
  126. >
  127. <span class="inline-block rounded-full bg-indigo-100 px-4 py-1 text-[10px] font-bold text-indigo-700 dark:bg-indigo-500/20 dark:text-indigo-400 mb-6 tracking-wider">
  128. {persona.tipo}
  129. </span>
  130. <UserRound size={36} strokeWidth={1.5} class="text-slate-400 dark:text-slate-500 mb-4 mx-auto" />
  131. <h3 class="text-sm font-bold text-slate-900 dark:text-white mb-2 leading-snug text-center">{persona.nome}</h3>
  132. <p class="text-xs text-slate-500 dark:text-slate-400 leading-relaxed font-medium text-center">{persona.descricao}</p>
  133. </button>
  134. {/each}
  135. </div>
  136. </div>
  137. <!-- Next Best Action Panel -->
  138. <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] flex flex-col h-[600px]">
  139. <div class="mb-4">
  140. <h2 class="text-lg font-bold text-slate-900 dark:text-white">Next Best Action</h2>
  141. <p class="text-sm text-slate-500 dark:text-slate-400">Recomendações estratégicas por persona</p>
  142. </div>
  143. <div class="flex-1 overflow-y-auto custom-scrollbar pr-2">
  144. {#if selectedPersona}
  145. <div class="space-y-6">
  146. <div>
  147. <div class="flex items-center gap-2 mb-2">
  148. <UserRound size={18} class="text-indigo-500" />
  149. <h3 class="font-bold text-slate-900 dark:text-white">{selectedPersona.nome}</h3>
  150. </div>
  151. <p class="text-sm text-slate-600 dark:text-slate-300 bg-slate-50 dark:bg-slate-800 p-3 rounded-lg border border-slate-100 dark:border-slate-700">
  152. {selectedPersona.detalhes}
  153. </p>
  154. </div>
  155. <div class="space-y-4">
  156. <div class="rounded-lg border border-emerald-200 bg-emerald-50 p-4 dark:border-emerald-500/20 dark:bg-emerald-500/5">
  157. <h4 class="font-bold text-emerald-800 dark:text-emerald-400 mb-2 flex items-center gap-2">
  158. <TrendingUp size={16} />
  159. Expansão
  160. </h4>
  161. <p class="text-sm text-emerald-700 dark:text-emerald-300">
  162. {selectedPersona.expansao}
  163. </p>
  164. </div>
  165. <div class="rounded-lg border border-red-200 bg-red-50 p-4 dark:border-red-500/20 dark:bg-red-500/5">
  166. <h4 class="font-bold text-red-800 dark:text-red-400 mb-2 flex items-center gap-2">
  167. <HeartHandshake size={16} />
  168. Engajamento (Salvar Churn)
  169. </h4>
  170. <p class="text-sm text-red-700 dark:text-red-300">
  171. {selectedPersona.engajamento}
  172. </p>
  173. </div>
  174. </div>
  175. </div>
  176. {:else}
  177. <div class="flex h-full flex-col items-center justify-center text-center text-slate-500 dark:text-slate-400">
  178. <UserRound size={48} class="mb-4 opacity-20" />
  179. <p>Selecione uma persona ao lado para ver o Next Best Action.</p>
  180. </div>
  181. {/if}
  182. </div>
  183. </div>
  184. </div>
  185. </div>