Files
eminuxCRM/app/views/dashboard/show.html.erb
T
eminuxandCursor b5737a7ee7 Rende leggibili card, badge e testi mute in tema scuro.
Le righe task di oggi restavano crema con testo chiaro; i badge e gli heading senza dark: si perdevano sullo sfondo.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-03 07:36:48 +02:00

160 lines
11 KiB
ERB
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<div class="space-y-6">
<div class="flex flex-wrap items-end justify-between gap-3">
<div>
<h1 class="text-xl font-semibold tracking-tight md:text-2xl">Dashboard · <%= current_project.name %></h1>
<p class="text-sm text-slate-500">Cosa devo fare oggi per trasformare i prospect in clienti?</p>
</div>
<%= link_to "Apri pagina Oggi →", today_path, class: "#{btn_primary} w-full sm:w-auto" %>
</div>
<% if @goal %>
<section class="rounded-2xl border border-slate-200 bg-gradient-to-br from-slate-900 to-slate-800 p-6 text-white shadow-sm">
<div class="text-xs font-semibold uppercase tracking-wider text-slate-300"><%= @goal.name %></div>
<div class="mt-2 flex flex-wrap items-end gap-4">
<div class="text-4xl font-semibold tabular-nums"><%= @goal.current_value.to_i %> / <%= @goal.target_value.to_i %></div>
<div class="pb-1 text-sm text-slate-300"><%= @goal.metric_label %> · <%= format_date(@goal.start_date) %> <%= format_date(@goal.end_date) %></div>
</div>
<div class="mt-4"><%= progress_bar(@goal.progress_percentage, color: "bg-emerald-400") %></div>
</section>
<% end %>
<section>
<h2 class="mb-3 text-lg font-semibold">Cosa devo fare oggi</h2>
<div class="grid gap-4 lg:grid-cols-3">
<div>
<h3 class="mb-2 text-sm font-semibold uppercase tracking-wide text-rose-700 dark:text-rose-400">In ritardo (<%= @overdue_tasks.size %>)</h3>
<%= render "shared/task_list", tasks: @overdue_tasks %>
</div>
<div>
<h3 class="mb-2 text-sm font-semibold uppercase tracking-wide text-amber-700 dark:text-amber-400">Da fare oggi (<%= @today_tasks.size %>)</h3>
<%= render "shared/task_list", tasks: @today_tasks %>
</div>
<div>
<h3 class="mb-2 text-sm font-semibold uppercase tracking-wide text-zinc-600 dark:text-zinc-400">Prossimi (<%= @upcoming_tasks.size %>)</h3>
<%= render "shared/task_list", tasks: @upcoming_tasks %>
</div>
</div>
</section>
<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-zinc-500 dark:text-zinc-400"><%= 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 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-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>
</div>
<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">KPI processo</h2>
<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">Senza attività in timeline da &gt; 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>
</div>
</section>
<section class="rounded-xl border border-amber-200 bg-amber-50 p-5 text-zinc-900 dark:border-amber-800 dark:bg-amber-950 dark:text-amber-50">
<h2 class="text-lg font-semibold text-amber-900 dark:text-amber-100">Cosa sbloccare adesso</h2>
<p class="mt-1 max-w-3xl text-sm text-amber-900/80 dark:text-amber-100/80">
Non è un errore. Sono i buchi che bloccano la vendita: un contatto da chiamare, unemail da mandare, un follow-up mancante.
Se una lista è vuota, su quel punto sei a posto.
</p>
<% if @attention[:to_send_count].to_i.positive? %>
<div class="mt-4 rounded-lg border border-amber-300 bg-white/70 p-4 dark:border-amber-800 dark:bg-amber-900/40">
<h3 class="text-sm font-semibold text-amber-900 dark:text-amber-100">Campagna lancio · email da inviare (<%= @attention[:to_send_count] %>)</h3>
<p class="mt-1 text-sm text-zinc-700 dark:text-amber-50/90">
Le società sono censite e in stato <strong>Da contattare</strong>. Il passo successivo è mandare le email del test A/B
(1015 al giorno, A e B insieme). Non serve ancora mettere un prezzo o creare un follow-up: quelli arrivano dopo la risposta.
</p>
<p class="mt-2 text-sm">
<%= link_to "Apri la lista da inviare →", organizations_path, class: "font-medium text-zinc-900 underline dark:text-amber-50" %>
</p>
</div>
<% end %>
<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 (<%= @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][: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 (<%= @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][: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 (<%= @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][: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 (<%= @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][: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) (<%= @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][: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) (<%= @attention[:opportunities_without_next_action][:total] %>)</h3>
<p class="mt-0.5 text-xs text-amber-900/70 dark:text-amber-100/70">Dopo linvio o la risposta manca un task in agenda: la trattativa si ferma.</p>
<%= 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>
</div>