Allinea i numeri della dashboard tra griglia, funnel e liste di attenzione.
Il funnel mostra stage attuale e cumulato, i KPI escludono Da contattare e le liste usano il totale reale invece del tetto a 20. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1,10 +1,11 @@
|
||||
<% items = items.to_a %>
|
||||
<% total = local_assigns.fetch(:total) { items.size } %>
|
||||
<% empty_class = "mt-2 text-sm text-amber-900/75 dark:text-amber-100/75" %>
|
||||
<% if items.blank? %>
|
||||
<% if total.to_i.zero? %>
|
||||
<p class="<%= empty_class %>"><%= empty %></p>
|
||||
<% else %>
|
||||
<ul class="mt-2 space-y-1 text-sm">
|
||||
<% items.first(8).each do |item| %>
|
||||
<% items.each do |item| %>
|
||||
<li>
|
||||
<% if block_given? %>
|
||||
<%= yield item %>
|
||||
@@ -13,8 +14,8 @@
|
||||
<% end %>
|
||||
</li>
|
||||
<% end %>
|
||||
<% if items.size > 8 %>
|
||||
<li class="text-xs text-amber-900/70 dark:text-amber-100/70">+ altre <%= items.size - 8 %></li>
|
||||
<% if total > items.size %>
|
||||
<li class="text-xs text-amber-900/70 dark:text-amber-100/70">+ altre <%= total - items.size %></li>
|
||||
<% end %>
|
||||
</ul>
|
||||
<% end %>
|
||||
|
||||
@@ -36,39 +36,47 @@
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="grid grid-cols-2 gap-3 md:grid-cols-3 xl:grid-cols-4">
|
||||
<% [
|
||||
["Prospect totali", @metrics.prospect_count],
|
||||
["Contattati", @stage_counts["contacted"]],
|
||||
["Risposte", @stage_counts["replied"]],
|
||||
["Interessati", @stage_counts["interested"]],
|
||||
["Demo/Trial", @stage_counts["demo_trial"]],
|
||||
["Primo utilizzo", @stage_counts["first_use"]],
|
||||
["Proposte", @stage_counts["proposal"]],
|
||||
["Clienti acquisiti", @stage_counts["won"]],
|
||||
["Persi", @stage_counts["lost"]],
|
||||
["Valore WON", format_money(@metrics.won_value)],
|
||||
["Pipeline aperta", format_money(@metrics.open_pipeline_value)],
|
||||
["Task scaduti", @metrics.overdue_tasks_count]
|
||||
].each do |label, value| %>
|
||||
<div class="rounded-xl border border-zinc-200 bg-white text-zinc-900 dark:border-zinc-800 dark:bg-zinc-900 dark:text-zinc-100 p-4">
|
||||
<div class="text-xs font-medium uppercase tracking-wide text-slate-500"><%= label %></div>
|
||||
<div class="mt-1 text-2xl font-semibold tabular-nums"><%= value %></div>
|
||||
</div>
|
||||
<% end %>
|
||||
<section>
|
||||
<p class="mb-3 text-sm text-slate-500">Conteggio per stage attuale: quante opportunità sono in quello stato ora.</p>
|
||||
<div class="grid grid-cols-2 gap-3 md:grid-cols-3 xl:grid-cols-4">
|
||||
<% [
|
||||
["Prospect totali", @metrics.prospect_count],
|
||||
["Da contattare", @stage_counts["to_contact"]],
|
||||
["Contattati", @stage_counts["contacted"]],
|
||||
["Risposte", @stage_counts["replied"]],
|
||||
["Interessati", @stage_counts["interested"]],
|
||||
["Demo/Trial", @stage_counts["demo_trial"]],
|
||||
["Primo utilizzo", @stage_counts["first_use"]],
|
||||
["Proposte", @stage_counts["proposal"]],
|
||||
["Clienti acquisiti", @stage_counts["won"]],
|
||||
["Persi", @stage_counts["lost"]],
|
||||
["Valore WON", format_money(@metrics.won_value)],
|
||||
["Pipeline aperta", format_money(@metrics.open_pipeline_value)],
|
||||
["Task scaduti", @metrics.overdue_tasks_count]
|
||||
].each do |label, value| %>
|
||||
<div class="rounded-xl border border-zinc-200 bg-white text-zinc-900 dark:border-zinc-800 dark:bg-zinc-900 dark:text-zinc-100 p-4">
|
||||
<div class="text-xs font-medium uppercase tracking-wide text-slate-500"><%= label %></div>
|
||||
<div class="mt-1 text-2xl font-semibold tabular-nums"><%= value %></div>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="grid gap-4 lg:grid-cols-2">
|
||||
<div class="rounded-xl border border-zinc-200 bg-white text-zinc-900 dark:border-zinc-800 dark:bg-zinc-900 dark:text-zinc-100 p-5">
|
||||
<h2 class="text-lg font-semibold">Funnel commerciale</h2>
|
||||
<p class="mt-1 text-sm text-slate-500">Numero grande: in questo stage ora. In piccolo: arrivati almeno a questo punto (stage attuale + successivi, esclusi i persi).</p>
|
||||
<div class="mt-4 space-y-2">
|
||||
<% @funnel.each_with_index do |step, idx| %>
|
||||
<% if step[:rate] %>
|
||||
<div class="text-center text-xs font-medium text-slate-500">↓ <%= step[:rate] %>%</div>
|
||||
<% @funnel.each do |step| %>
|
||||
<% if step[:conversion_label] %>
|
||||
<div class="text-center text-xs font-medium text-slate-500"><%= step[:conversion_label] %> (<%= step[:rate] %>%)</div>
|
||||
<% end %>
|
||||
<div class="flex items-center justify-between rounded-lg bg-zinc-50 px-4 py-3 dark:bg-zinc-800">
|
||||
<span class="font-medium text-zinc-800 dark:text-zinc-100"><%= step[:label].upcase %></span>
|
||||
<span class="text-xl font-semibold tabular-nums"><%= step[:count] %></span>
|
||||
<span class="text-right">
|
||||
<span class="text-xl font-semibold tabular-nums"><%= step[:current] %></span>
|
||||
<span class="ml-2 text-xs font-medium text-slate-500"><%= step[:reached] %> da qui in poi</span>
|
||||
</span>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
@@ -79,10 +87,10 @@
|
||||
<dl class="mt-4 space-y-3 text-sm break-anywhere">
|
||||
<div class="flex justify-between"><dt class="text-slate-500">Giorni medi contatto → WON</dt><dd class="font-semibold"><%= @metrics.avg_days_to_won || "—" %></dd></div>
|
||||
<div class="flex justify-between"><dt class="text-slate-500">Giorni medi dall'ultima attività</dt><dd class="font-semibold"><%= @metrics.avg_days_since_last_activity || "—" %></dd></div>
|
||||
<div class="flex justify-between"><dt class="text-slate-500">Prospect senza attività > 7gg</dt><dd class="font-semibold"><%= @metrics.prospects_without_activity_over_7_days %></dd></div>
|
||||
<div class="flex justify-between"><dt class="text-slate-500">Opp. senza next action</dt><dd class="font-semibold"><%= @metrics.opportunities_without_next_action %></dd></div>
|
||||
<div class="flex justify-between"><dt class="text-slate-500">Demo/Trial → WON</dt><dd class="font-semibold"><%= @metrics.demo_to_won_conversion %>%</dd></div>
|
||||
<div class="flex justify-between"><dt class="text-slate-500">First Use → WON</dt><dd class="font-semibold"><%= @metrics.first_use_to_won_conversion %>%</dd></div>
|
||||
<div class="flex justify-between"><dt class="text-slate-500">Senza attività in timeline da > 7 giorni</dt><dd class="font-semibold"><%= @metrics.prospects_without_activity_over_7_days %></dd></div>
|
||||
<div class="flex justify-between"><dt class="text-slate-500">In trattativa senza next action</dt><dd class="font-semibold"><%= @metrics.opportunities_without_next_action %></dd></div>
|
||||
<div class="flex justify-between"><dt class="text-slate-500">Demo/Trial → WON</dt><dd class="font-semibold"><%= format_conversion_rate(@metrics.demo_to_won_conversion) %></dd></div>
|
||||
<div class="flex justify-between"><dt class="text-slate-500">First Use → WON</dt><dd class="font-semibold"><%= format_conversion_rate(@metrics.first_use_to_won_conversion) %></dd></div>
|
||||
<div class="flex justify-between"><dt class="text-slate-500">ARPA (WON)</dt><dd class="font-semibold"><%= format_money(@metrics.arpa) %></dd></div>
|
||||
<div class="flex justify-between"><dt class="text-slate-500">Pipeline value</dt><dd class="font-semibold"><%= format_money(@metrics.open_pipeline_value) %></dd></div>
|
||||
</dl>
|
||||
@@ -111,40 +119,40 @@
|
||||
|
||||
<div class="mt-4 grid gap-4 md:grid-cols-2 xl:grid-cols-3">
|
||||
<div>
|
||||
<h3 class="text-sm font-semibold text-amber-800 dark:text-amber-200">Interessati senza follow-up</h3>
|
||||
<h3 class="text-sm font-semibold text-amber-800 dark:text-amber-200">Interessati senza follow-up (<%= @attention[:interested_without_followup][:total] %>)</h3>
|
||||
<p class="mt-0.5 text-xs text-amber-900/70 dark:text-amber-100/70">Hanno detto sì in linea: manca la prossima chiamata/email in agenda.</p>
|
||||
<%= render "dashboard/attention_list", items: @attention[:interested_without_followup], empty: "Nessuno: nessun interessato scoperto." %>
|
||||
<%= render "dashboard/attention_list", items: @attention[:interested_without_followup][:items], total: @attention[:interested_without_followup][:total], empty: "Nessuno: nessun interessato scoperto." %>
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="text-sm font-semibold text-amber-800 dark:text-amber-200">Opportunità ferme da oltre 7 giorni</h3>
|
||||
<h3 class="text-sm font-semibold text-amber-800 dark:text-amber-200">Opportunità ferme da oltre 7 giorni (<%= @attention[:stalled_opportunities][:total] %>)</h3>
|
||||
<p class="mt-0.5 text-xs text-amber-900/70 dark:text-amber-100/70">Lo stage non si è mosso: va rilanciato o chiuso come perso.</p>
|
||||
<%= render "dashboard/attention_list", items: @attention[:stalled_opportunities], empty: "Nessuna: nessuna trattativa ferma." do |opp| %>
|
||||
<%= render "dashboard/attention_list", items: @attention[:stalled_opportunities][:items], total: @attention[:stalled_opportunities][:total], empty: "Nessuna: nessuna trattativa ferma." do |opp| %>
|
||||
<%= link_to "#{opp.organization.name} (#{opp.days_in_current_stage}gg)", opp.organization, class: "hover:underline" %>
|
||||
<% end %>
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="text-sm font-semibold text-amber-800 dark:text-amber-200">Task scaduti</h3>
|
||||
<h3 class="text-sm font-semibold text-amber-800 dark:text-amber-200">Task scaduti (<%= @attention[:overdue_tasks][:total] %>)</h3>
|
||||
<p class="mt-0.5 text-xs text-amber-900/70 dark:text-amber-100/70">Promemoria già passati: completarli o ripianificarli.</p>
|
||||
<%= render "dashboard/attention_list", items: @attention[:overdue_tasks], empty: "Nessuno: nessun task in ritardo." do |task| %>
|
||||
<%= render "dashboard/attention_list", items: @attention[:overdue_tasks][:items], total: @attention[:overdue_tasks][:total], empty: "Nessuno: nessun task in ritardo." do |task| %>
|
||||
<%= link_to "#{task.organization.name}: #{task.title}", task.organization, class: "hover:underline" %>
|
||||
<% end %>
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="text-sm font-semibold text-amber-800 dark:text-amber-200">Senza contatto</h3>
|
||||
<h3 class="text-sm font-semibold text-amber-800 dark:text-amber-200">Senza contatto (<%= @attention[:organizations_without_contacts][:total] %>)</h3>
|
||||
<p class="mt-0.5 text-xs text-amber-900/70 dark:text-amber-100/70">Manca una persona a cui scrivere o telefonare.</p>
|
||||
<%= render "dashboard/attention_list", items: @attention[:organizations_without_contacts], empty: "Nessuna: tutte hanno un contatto." do |org| %>
|
||||
<%= render "dashboard/attention_list", items: @attention[:organizations_without_contacts][:items], total: @attention[:organizations_without_contacts][:total], empty: "Nessuna: tutte hanno un contatto." do |org| %>
|
||||
<%= link_to org.name, org, class: "hover:underline" %>
|
||||
<% end %>
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="text-sm font-semibold text-amber-800 dark:text-amber-200">Senza valore (già in trattativa)</h3>
|
||||
<h3 class="text-sm font-semibold text-amber-800 dark:text-amber-200">Senza valore (già in trattativa) (<%= @attention[:opportunities_without_value][:total] %>)</h3>
|
||||
<p class="mt-0.5 text-xs text-amber-900/70 dark:text-amber-100/70">Dopo il primo contatto serve un importo stimato (Light/Full…) per la pipeline.</p>
|
||||
<%= render "dashboard/attention_list", items: @attention[:opportunities_without_value], empty: "Nessuna in trattativa senza valore." %>
|
||||
<%= render "dashboard/attention_list", items: @attention[:opportunities_without_value][:items], total: @attention[:opportunities_without_value][:total], empty: "Nessuna in trattativa senza valore." %>
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="text-sm font-semibold text-amber-800 dark:text-amber-200">Senza prossima azione (già in trattativa)</h3>
|
||||
<h3 class="text-sm font-semibold text-amber-800 dark:text-amber-200">Senza prossima azione (già in trattativa) (<%= @attention[:opportunities_without_next_action][:total] %>)</h3>
|
||||
<p class="mt-0.5 text-xs text-amber-900/70 dark:text-amber-100/70">Dopo l’invio o la risposta manca un task in agenda: la trattativa si ferma.</p>
|
||||
<%= render "dashboard/attention_list", items: @attention[:opportunities_without_next_action], empty: "Nessuna in trattativa senza next action." %>
|
||||
<%= render "dashboard/attention_list", items: @attention[:opportunities_without_next_action][:items], total: @attention[:opportunities_without_next_action][:total], empty: "Nessuna in trattativa senza next action." %>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
Reference in New Issue
Block a user