# app/services/mood_calendar_service.rb class MoodCalendarService def self.generate_calendar(moods, start_date: nil, end_date: Date.current) # Preload modes with their image attachments mode_ids = moods.joins(:mode).pluck("modes.id").uniq modes_by_id = Mode.where(id: mode_ids) .with_attached_image .index_by(&:id) data = moods.joins(:mode) .order(:recorded_at) .pluck(:recorded_at, "modes.label", "modes.color", "modes.id") .map do |recorded_at, label, color, mode_id| mode = modes_by_id[mode_id] { mode: { label: label, color: color, image_url: mode&.image&.attached? ? Rails.application.routes.url_helpers.rails_blob_url(mode.image, only_path: true) : nil }, recorded_at: recorded_at } end # Convertir la relation ActiveRecord en tableau de hash if data.empty? start_date = Date.current else start_date ||= data.first[:recorded_at].to_date end if end_date < (start_date + 5.months) end_date = start_date + 5.months end # Convertir en Date si ce sont des DateTime ou Time start_date = start_date.to_date end_date = end_date&.to_date # Grouper par jour et garder le plus récent pour chaque jour data_by_date = data.group_by { |d| d[:recorded_at].to_date } .transform_values { |entries| entries.max_by { |e| e[:recorded_at] } } # Trouver le dernier mood avant start_date pour initialiser le guess last_mode = data.select { |d| d[:recorded_at].to_date < start_date } .max_by { |d| d[:recorded_at] } &.[](:mode) # Générer le tableau complet avec tous les jours complete_data = (start_date..end_date).map do |date| if data_by_date[date] last_mode = data_by_date[date][:mode] data_by_date[date] else { mode: nil, recorded_at: date.to_datetime, guess: last_mode } end end # Regrouper par mois avec semaines commençant au premier lundi complete_data.group_by { |d| d[:recorded_at].to_date.beginning_of_month } .map do |month_start, month_data| first_monday = month_start first_monday = first_monday.next_occurring(:monday) unless first_monday.monday? next_month_start = month_start.next_month.beginning_of_month next_first_monday = next_month_start next_first_monday = next_first_monday.next_occurring(:monday) unless next_first_monday.monday? month_end = next_first_monday - 1.day data_hash = complete_data.index_by { |d| d[:recorded_at].to_date } all_days = (first_monday..month_end).map do |date| data_hash[date] || { mode: nil, recorded_at: date.to_datetime, guess: nil } end weeks = all_days.group_by { |d| d[:recorded_at].to_date.beginning_of_week(:monday) } .sort_by { |week_start, _| week_start } .map { |_, week_moods| week_moods } { month: month_start, weeks: weeks } end end end#