module Api module V1 class DashboardController < BaseController def show current_user.update_required_matrices! entries = current_user.entries.where("date <= ?", Date.current) progress = User::PRAKTIKUMSTYPEN.flat_map do |typ| User.entry_arten_for(typ).map do |art| spent = entries.where(praktikums_typ: typ, entry_art: art).sum("COALESCE(hours, 0) * 60 + COALESCE(minutes, 0)").to_i target = current_user.required_hours_for(typ, art).to_f * 60 remaining = [target - spent, 0].max.to_i weekly_target = current_user.weekly_target_for(typ, art).to_f dates = entries.where(praktikums_typ: typ, entry_art: art).where("COALESCE(hours, 0) > 0 OR COALESCE(minutes, 0) > 0") first_date = dates.minimum(:date) last_date = dates.maximum(:date) period_end = spent >= target && last_date ? last_date : Date.current weeks = first_date ? [[(period_end - first_date).to_i + 1, 7].max / 7.0, 1].max : nil actual_weekly = weeks ? ((spent / 60.0) / weeks).round(2) : nil estimated_end = weekly_target.positive? && remaining.positive? ? Date.current + (remaining / 60.0 / weekly_target).ceil.weeks : nil { typ:, art:, spent_minutes: spent, target_minutes: target.to_i, remaining_minutes: remaining, percent: target.positive? ? [(spent / target * 100).round(1), 100].min : 0, weekly_target:, actual_weekly:, estimated_end: } end end total_spent = progress.sum { |row| row[:spent_minutes] } total_target = progress.sum { |row| row[:target_minutes] } render json: { total_minutes: total_spent, target_minutes: total_target, remaining_minutes: [total_target - total_spent, 0].max, completed_percent: total_target.positive? ? (total_spent.to_f / total_target * 100).round(1) : 0, total_distance_km: current_user.entries.sum(:distance_km), costs_by_year: costs_by_year, running_entry: current_user.entries.find_by(end_time: nil, beschreibung: "Timer"), mediation_presence_days: current_user.mediation_praesenzmodule_completed, mediation_presence_days_required: current_user.mediation_praesenzmodule_required, last_entry: current_user.entries.where("date <= ?", Date.current).order(date: :desc).first, progress: } end private def costs_by_year years = current_user.entries.pluck(Arel.sql("DISTINCT EXTRACT(YEAR FROM date)::int")).compact.sort.reverse km = Entry.total_kilometer_cost_by_year(current_user) total = Entry.total_gesamtkosten_by_year(current_user) training = Entry.total_fortbildungskosten_by_year(current_user) experience = Entry.total_selbsterfahrungskosten_by_year(current_user) supervision = Entry.total_supervision_by_year(current_user) semester = Entry.total_semesterkosten_by_year(current_user) years.map { |year| { year:, kilometer: km[year].to_f, fortbildung: training[year].to_f, selbsterfahrung: experience[year].to_f, supervision: supervision[year].to_f, semester: semester[year].to_f, total: total[year].to_f } } end end end end