2026-02-07 12:09:06 +01:00
|
|
|
# app/services/mood_calendar_service.rb
|
|
|
|
|
class MoodCalendarService
|
|
|
|
|
def self.generate_calendar(moods, start_date: nil, end_date: Date.current)
|
2026-03-19 19:04:16 +01:00
|
|
|
# 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)
|
|
|
|
|
|
2026-03-14 16:35:48 +01:00
|
|
|
data = moods.joins(:mode)
|
2026-03-19 19:04:16 +01:00
|
|
|
.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
|
2026-02-07 12:09:06 +01:00
|
|
|
|
2026-02-18 10:52:54 +01:00
|
|
|
if data.empty?
|
|
|
|
|
start_date = Date.current
|
|
|
|
|
else
|
|
|
|
|
start_date ||= data.first[:recorded_at].to_date
|
|
|
|
|
end
|
2026-02-07 12:09:06 +01:00
|
|
|
|
2026-02-18 10:52:54 +01:00
|
|
|
if end_date < (start_date + 5.months)
|
|
|
|
|
end_date = start_date + 5.months
|
2026-02-11 10:32:16 +01:00
|
|
|
end
|
2026-02-07 12:09:06 +01:00
|
|
|
|
2026-02-18 10:52:54 +01:00
|
|
|
# Convertir en Date si ce sont des DateTime ou Time
|
|
|
|
|
start_date = start_date.to_date
|
|
|
|
|
end_date = end_date&.to_date
|
|
|
|
|
|
2026-02-07 12:09:06 +01:00
|
|
|
# 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
|
2026-03-14 16:35:48 +01:00
|
|
|
end#
|