Files
eminuxCRM/app/views/dashboard/show.html.erb
T
eminuxandCursor c4e5f289cf
CI / scan_ruby (push) Failing after 11m20s
CI / scan_js (push) Successful in 10m35s
CI / lint (push) Has been cancelled
Commit iniziale di eminuxCRM: CRM Rails con pipeline, campagne email e Docker.
Include autenticazione, progetti isolati, mail marketing HTML con SMTP, test A/B e editor WYSIWYG.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-17 23:01:48 +02:00

152 lines
9.8 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-2xl font-semibold tracking-tight">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 %>
</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">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">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 class="grid gap-4 md:grid-cols-2 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>
<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>
<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>
<% 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>
</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">
<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">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</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." %>
</div>
<div>
<h3 class="text-sm font-semibold text-amber-800 dark:text-amber-200">Opportunità ferme da oltre 7 giorni</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| %>
<%= 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>
<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| %>
<%= 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>
<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| %>
<%= 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>
<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." %>
</div>
<div>
<h3 class="text-sm font-semibold text-amber-800 dark:text-amber-200">Senza prossima azione (già in trattativa)</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], empty: "Nessuna in trattativa senza next action." %>
</div>
</div>
</section>
</div>