4 changed files with 105 additions and 1 deletions
@ -0,0 +1,29 @@ |
|||||
|
# app/controllers/dashboards_controller.rb |
||||
|
class DashboardsController < ApplicationController |
||||
|
def show |
||||
|
@entries = current_user.entries.order(date: :desc) |
||||
|
|
||||
|
valid_entries = @entries.select { |e| e.date.present? } |
||||
|
|
||||
|
@report = valid_entries.group_by { |e| e.date.beginning_of_month } |
||||
|
.transform_values do |entries| |
||||
|
entries.group_by { |e| [e.praktikums_typ, e.entry_art] } |
||||
|
.transform_values do |subset| |
||||
|
minutes = subset.sum(&:total_minutes) |
||||
|
{ hours: minutes / 60, minutes: minutes % 60 } |
||||
|
end |
||||
|
end |
||||
|
|
||||
|
@monthly_minutes_chart_data = @report.transform_keys { |date| date.strftime("%b") } |
||||
|
.transform_values do |groups| |
||||
|
groups.values.sum { |data| data[:hours] * 60 + data[:minutes] } |
||||
|
end |
||||
|
|
||||
|
@monthly_targets = Hash.new(1500) # z.B. 25h im Monat als Ziel → 1500min |
||||
|
|
||||
|
@total_minutes = @entries.sum(&:total_minutes) |
||||
|
@last_entry = @entries.first |
||||
|
@completed_percent = ((@total_minutes.to_f / 10000) * 100).round(1) |
||||
|
@remaining_total = [10000 - @total_minutes, 0].max |
||||
|
end |
||||
|
end |
||||
@ -0,0 +1,36 @@ |
|||||
|
<!-- Summary-Kacheln --> |
||||
|
<div class="col-sm-6 col-lg-3"> |
||||
|
<div class="card shadow-sm text-center"> |
||||
|
<div class="card-body"> |
||||
|
<h5 class="card-title">🕒 Gesamtzeit</h5> |
||||
|
<p class="display-6"><%= @total_minutes / 60 %>h <%= @total_minutes % 60 %>min</p> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
|
||||
|
<div class="col-sm-6 col-lg-3"> |
||||
|
<div class="card shadow-sm text-center"> |
||||
|
<div class="card-body"> |
||||
|
<h5 class="card-title">🚧 Offen</h5> |
||||
|
<p class="display-6 text-warning"><%= @remaining_total / 60 %>h</p> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
|
||||
|
<div class="col-sm-6 col-lg-3"> |
||||
|
<div class="card shadow-sm text-center"> |
||||
|
<div class="card-body"> |
||||
|
<h5 class="card-title">✅ Erledigt</h5> |
||||
|
<p class="display-6 text-success"><%= @completed_percent %>%</p> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
|
||||
|
<div class="col-sm-6 col-lg-3"> |
||||
|
<div class="card shadow-sm text-center"> |
||||
|
<div class="card-body"> |
||||
|
<h5 class="card-title">📅 Letzter Eintrag</h5> |
||||
|
<p class="text-muted"><%= l(@last_entry.date, format: :long) if @last_entry %></p> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
@ -0,0 +1,39 @@ |
|||||
|
<h1 class="mb-4">📊 Dashboard</h1> |
||||
|
|
||||
|
<!-- Kacheln --> |
||||
|
<div class="row g-4 mb-4"> |
||||
|
<%= render partial: 'dashboards/summary_tiles' %> |
||||
|
</div> |
||||
|
|
||||
|
<!-- Monatsverlauf als Bar Chart --> |
||||
|
<div class="card shadow-sm mb-4"> |
||||
|
<div class="card-body"> |
||||
|
<h5 class="card-title">📈 Monatsverlauf</h5> |
||||
|
<%= column_chart @monthly_minutes_chart_data, height: "250px", colors: ["#0d6efd"] %> |
||||
|
</div> |
||||
|
</div> |
||||
|
|
||||
|
<!-- Scrollbare Monatsübersicht mit ProgressBars --> |
||||
|
<div class="d-flex overflow-auto gap-3 pb-3"> |
||||
|
<% @report.each do |month, groups| %> |
||||
|
<% total_minutes = groups.values.map { |data| (data[:hours] * 60 + data[:minutes]) }.sum %> |
||||
|
<% total_hours = total_minutes / 60 %> |
||||
|
<% rest_min = total_minutes % 60 %> |
||||
|
<% percent = ((total_minutes.to_f / @monthly_targets[month]) * 100).round rescue 0 %> |
||||
|
|
||||
|
<div class="card flex-shrink-0 shadow-sm" style="min-width: 320px;"> |
||||
|
<div class="card-header bg-white fw-bold"><%= month.strftime("%B %Y") %></div> |
||||
|
<div class="card-body"> |
||||
|
<p class="mb-2">⏱️ <strong><%= total_hours %>h <%= rest_min %>min</strong></p> |
||||
|
<p class="mb-1">🎯 Ziel: <%= @monthly_targets[month] / 60 %>h</p> |
||||
|
<div class="progress" style="height: 20px;"> |
||||
|
<div class="progress-bar <%= percent >= 100 ? 'bg-success' : 'bg-primary' %>" role="progressbar" |
||||
|
style="width: <%= [percent, 100].min %>%;" aria-valuenow="<%= percent %>" |
||||
|
aria-valuemin="0" aria-valuemax="100"> |
||||
|
<%= percent %>% |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
<% end %> |
||||
|
</div> |
||||
Loading…
Reference in new issue