Compare commits
No commits in common. "1a6d60943a4b1d40a3818712312fe6e38f92e5fd" and "939668c4fb1f9977df452337d179f96b5f1dd4bb" have entirely different histories.
1a6d60943a
...
939668c4fb
30 changed files with 341 additions and 927 deletions
|
|
@ -42,7 +42,32 @@ main {
|
||||||
align-content: center;
|
align-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.bar {
|
.bar-afond {
|
||||||
|
background: black;
|
||||||
|
width: 10px;
|
||||||
|
height: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bar-creatif {
|
||||||
|
background: red;
|
||||||
|
width: 10px;
|
||||||
|
height: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bar-frigo {
|
||||||
|
background: gray;
|
||||||
|
width: 10px;
|
||||||
|
height: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bar-croisiere {
|
||||||
|
background: green;
|
||||||
|
width: 10px;
|
||||||
|
height: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bar-en-charge {
|
||||||
|
background: orange;
|
||||||
width: 10px;
|
width: 10px;
|
||||||
height: 10px;
|
height: 10px;
|
||||||
}
|
}
|
||||||
|
|
@ -55,19 +80,35 @@ main {
|
||||||
}
|
}
|
||||||
|
|
||||||
.selected-day {
|
.selected-day {
|
||||||
border-radius: 50%;
|
border: 2px double white;
|
||||||
box-shadow: 0 0 0 3px white, 0 0 0 5px black;
|
|
||||||
margin: 4px;
|
margin: 4px;
|
||||||
width: 15px;
|
width: 15px;
|
||||||
height: 15px;
|
height: 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.empty-day {
|
.creatif {
|
||||||
border: 1px dashed #aaa;
|
background-color: red;
|
||||||
margin: 4px;
|
}
|
||||||
width: 15px;
|
|
||||||
height: 15px;
|
.unknown {
|
||||||
background: transparent;
|
border: 2px double grey;
|
||||||
|
background-color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.en-charge {
|
||||||
|
background-color: orange;
|
||||||
|
}
|
||||||
|
|
||||||
|
.frigo-vide {
|
||||||
|
background-color: grey;
|
||||||
|
}
|
||||||
|
|
||||||
|
.croisiere {
|
||||||
|
background-color: green;
|
||||||
|
}
|
||||||
|
|
||||||
|
.afond {
|
||||||
|
background-color: black;
|
||||||
}
|
}
|
||||||
|
|
||||||
.info {
|
.info {
|
||||||
|
|
|
||||||
|
|
@ -1,50 +0,0 @@
|
||||||
class DayLogsController < ApplicationController
|
|
||||||
before_action :set_day_log, only: [ :update ]
|
|
||||||
|
|
||||||
def edit
|
|
||||||
@day_log = Current.user.day_logs.find_or_initialize_by(day: params[:day])
|
|
||||||
@mood = Current.user.moods.find_by(recorded_at: params[:day].to_date.beginning_of_day..params[:day].to_date.end_of_day)
|
|
||||||
end
|
|
||||||
|
|
||||||
def create
|
|
||||||
@day_log = Current.user.day_logs.build(day_log_params)
|
|
||||||
|
|
||||||
if @day_log.save
|
|
||||||
handle_mood(@day_log.day, params[:day_log][:mode_id])
|
|
||||||
redirect_to dashboard_path(day: @day_log.day)
|
|
||||||
else
|
|
||||||
render :new, status: :unprocessable_content
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def update
|
|
||||||
if @day_log.update(day_log_params)
|
|
||||||
handle_mood(@day_log.day, params[:day_log][:mode_id])
|
|
||||||
redirect_to dashboard_path(day: @day_log.day)
|
|
||||||
else
|
|
||||||
render :edit, status: :unprocessable_content
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def set_day_log
|
|
||||||
@day_log = Current.user.day_logs.find(params[:id])
|
|
||||||
end
|
|
||||||
|
|
||||||
def handle_mood(day, mode_id)
|
|
||||||
return if mode_id.blank?
|
|
||||||
|
|
||||||
mood = Current.user.moods.find_by(recorded_at: day.beginning_of_day..day.end_of_day)
|
|
||||||
|
|
||||||
if mood
|
|
||||||
mood.update(mode_id: mode_id)
|
|
||||||
else
|
|
||||||
Current.user.moods.create(mode_id: mode_id, recorded_at: day.to_datetime)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def day_log_params
|
|
||||||
params.expect(day_log: [ :day, :info ])
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
class MoodsController < ApplicationController
|
class MoodsController < ApplicationController
|
||||||
def index
|
def index
|
||||||
@user = Current.user
|
@user = Current.user
|
||||||
redirect_to dashboard_path(day: Date.today) unless params[:day]
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -1,37 +1,9 @@
|
||||||
module MoodsHelper
|
module MoodsHelper
|
||||||
def day_status(mood, user)
|
|
||||||
return :filled if mood[:mode].present?
|
|
||||||
return :guessed if mood[:guess].present? && user.guess?
|
|
||||||
return :unknown if mood[:guess].present? && !user.guess?
|
|
||||||
:empty
|
|
||||||
end
|
|
||||||
|
|
||||||
def mode_for(mood, user)
|
|
||||||
case day_status(mood, user)
|
|
||||||
when :filled then mood[:mode]
|
|
||||||
when :guessed then mood[:guess]
|
|
||||||
when :unknown, :empty then Mode.new(label: "unknown", color: "white")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
=begin
|
|
||||||
def mode_for(mood, user)
|
def mode_for(mood, user)
|
||||||
if user.guess?
|
if user.guess?
|
||||||
mood[:mode] || mood[:guess] || { label: "unknown", color: "white", image_url: "unknown.jpg" }
|
mood[:mode] || mood[:guess] || "unknown"
|
||||||
else
|
else
|
||||||
mood[:mode] || { label: "unknown", color: "white", image_url: "unknown.jpg" }
|
mood[:mode] || "unknown"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
=end
|
|
||||||
|
|
||||||
def style_for_mode(mode, status)
|
|
||||||
case status
|
|
||||||
when :empty then ""
|
|
||||||
when :unknown then "background-color: #{mode.color}; border: 2px double grey;"
|
|
||||||
else "background-color: #{mode.color};"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def css_class_for_day(status)
|
|
||||||
status == :empty ? "day empty-day" : "day"
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -1,44 +1,18 @@
|
||||||
import { Controller } from '@hotwired/stimulus'
|
import { Controller } from '@hotwired/stimulus'
|
||||||
|
|
||||||
export default class extends Controller {
|
export default class extends Controller {
|
||||||
static targets = [ "image", "modeDay", "dayLogLink", "dayLogInfo" ];
|
static targets = [ "image", "modeDay" ];
|
||||||
|
|
||||||
connect() {
|
|
||||||
this.lastTarget = null;
|
|
||||||
|
|
||||||
const params = new URLSearchParams(window.location.search);
|
|
||||||
const selectedDay = params.get("day");
|
|
||||||
|
|
||||||
if (selectedDay) {
|
|
||||||
const dayEl = document.querySelector(`[data-day="${selectedDay}"]`);
|
|
||||||
if (dayEl) {
|
|
||||||
dayEl.click();
|
|
||||||
dayEl.scrollIntoView({ block: "center" });
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
const logs = document.querySelector(".logs");
|
|
||||||
if (logs) logs.scrollTop = logs.scrollHeight;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
updateDayInfo(event) {
|
updateDayInfo(event) {
|
||||||
const image = this.imageTarget;
|
const image = this.imageTarget;
|
||||||
const modeDay = this.modeDayTarget;
|
const modeDay = this.modeDayTarget;
|
||||||
const day = event.target.dataset.day;
|
const modeDayContent = event.target.dataset.day + ' : ' + event.target.dataset.mode;
|
||||||
const formattedDay = new Date(day).toLocaleDateString('fr-FR');
|
|
||||||
const modeDayContent = formattedDay + ' : ' + event.target.dataset.mode;
|
|
||||||
image.src = event.target.dataset.image;
|
image.src = event.target.dataset.image;
|
||||||
modeDay.textContent = modeDayContent;
|
modeDay.textContent = modeDayContent;
|
||||||
this.dayLogLinkTarget.href = `/day_logs/edit?day=${day}`;
|
|
||||||
this.dayLogInfoTarget.textContent = event.target.dataset.info || '';
|
|
||||||
event.target.className = "selected-day " + event.target.dataset.mode;
|
event.target.className = "selected-day " + event.target.dataset.mode;
|
||||||
|
}
|
||||||
|
|
||||||
history.pushState({}, '', `?day=${day}`);
|
connect() {
|
||||||
|
window.location = "#end";
|
||||||
if (this.lastTarget) {
|
|
||||||
this.lastTarget.className = "day " + this.lastTarget.dataset.mode;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.lastTarget = event.target;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +0,0 @@
|
||||||
class DayLog < ApplicationRecord
|
|
||||||
belongs_to :user
|
|
||||||
|
|
||||||
validates :day, presence: true
|
|
||||||
validates :info, presence: true
|
|
||||||
end
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
class Mode < ApplicationRecord
|
|
||||||
belongs_to :user
|
|
||||||
has_one_attached :image
|
|
||||||
|
|
||||||
def image_url
|
|
||||||
image.attached? ? Rails.application.routes.url_helpers.rails_blob_path(image, only_path: true) : ActionController::Base.helpers.asset_path("unknown.jpg")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
@ -1,19 +1,3 @@
|
||||||
class Mood < ApplicationRecord
|
class Mood < ApplicationRecord
|
||||||
belongs_to :user
|
belongs_to :user
|
||||||
belongs_to :mode
|
|
||||||
|
|
||||||
validates :recorded_at, presence: true
|
|
||||||
validate :unique_per_day_and_user
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def unique_per_day_and_user
|
|
||||||
return unless recorded_at && user
|
|
||||||
|
|
||||||
existing = user.moods.where.not(id: id).any? do |mood|
|
|
||||||
mood.recorded_at.to_date == recorded_at.to_date
|
|
||||||
end
|
|
||||||
|
|
||||||
errors.add(:recorded_at, :taken) if existing
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,6 @@ class User < ApplicationRecord
|
||||||
has_secure_password
|
has_secure_password
|
||||||
has_many :sessions, dependent: :destroy
|
has_many :sessions, dependent: :destroy
|
||||||
has_many :moods, -> { order "recorded_at" }
|
has_many :moods, -> { order "recorded_at" }
|
||||||
has_many :modes
|
|
||||||
has_many :day_logs
|
|
||||||
|
|
||||||
normalizes :email_address, with: ->(e) { e.strip.downcase }
|
normalizes :email_address, with: ->(e) { e.strip.downcase }
|
||||||
|
|
||||||
|
|
@ -33,14 +31,10 @@ class User < ApplicationRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
def history
|
def history
|
||||||
MoodCalendarService.generate_calendar(self)
|
MoodCalendarService.generate_calendar(moods)
|
||||||
end
|
end
|
||||||
|
|
||||||
def current_mode
|
def current_mood
|
||||||
self.moods.last&.mode || "croisiere"
|
self.moods.last&.mode || "croisiere"
|
||||||
end
|
end
|
||||||
|
|
||||||
def current_day_log
|
|
||||||
self.day_logs.find_by(day: Date.today)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,11 @@
|
||||||
|
# app/services/mood_calendar_service.rb
|
||||||
class MoodCalendarService
|
class MoodCalendarService
|
||||||
def self.generate_calendar(user, start_date: nil, end_date: nil)
|
def self.generate_calendar(moods, start_date: nil, end_date: Date.current)
|
||||||
data = user.moods.includes(:mode)
|
# Convertir la relation ActiveRecord en tableau de hash
|
||||||
.order(:recorded_at)
|
data = moods.order(:recorded_at)
|
||||||
.map { |mood| { mode: mood.mode, recorded_at: mood.recorded_at } }
|
.pluck(:mode, :recorded_at)
|
||||||
|
.map { |mode, recorded_at| { mode: mode, recorded_at: recorded_at } }
|
||||||
|
|
||||||
day_logs_by_date = user.day_logs.index_by(&:day)
|
|
||||||
|
|
||||||
if data.empty?
|
if data.empty?
|
||||||
start_date = Date.current
|
start_date = Date.current
|
||||||
|
|
@ -12,58 +13,66 @@ class MoodCalendarService
|
||||||
start_date ||= data.first[:recorded_at].to_date
|
start_date ||= data.first[:recorded_at].to_date
|
||||||
end
|
end
|
||||||
|
|
||||||
start_date = start_date.to_date
|
if end_date < (start_date + 5.months)
|
||||||
end_date = end_date ? end_date.to_date : [ Date.current, start_date + 5.months ].max
|
|
||||||
=begin
|
|
||||||
if end_date.nil?
|
|
||||||
end_date = start_date + 5.months
|
end_date = start_date + 5.months
|
||||||
else
|
|
||||||
end_date = end_date.to_date
|
|
||||||
end
|
end
|
||||||
=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 }
|
data_by_date = data.group_by { |d| d[:recorded_at].to_date }
|
||||||
.transform_values { |entries| entries.max_by { |e| e[:recorded_at] } }
|
.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 }
|
last_mode = data.select { |d| d[:recorded_at].to_date < start_date }
|
||||||
.max_by { |d| d[:recorded_at] }
|
.max_by { |d| d[:recorded_at] }
|
||||||
&.[](:mode)
|
&.[](:mode)
|
||||||
|
|
||||||
|
# Générer le tableau complet avec tous les jours
|
||||||
complete_data = (start_date..end_date).map do |date|
|
complete_data = (start_date..end_date).map do |date|
|
||||||
day_log = day_logs_by_date[date]
|
|
||||||
if data_by_date[date]
|
if data_by_date[date]
|
||||||
last_mode = data_by_date[date][:mode]
|
last_mode = data_by_date[date][:mode]
|
||||||
data_by_date[date].merge(day_log: day_log)
|
data_by_date[date]
|
||||||
else
|
else
|
||||||
{ mode: nil, recorded_at: date.to_datetime, guess: last_mode, day_log: day_log }
|
{ mode: nil, recorded_at: date.to_datetime, guess: last_mode }
|
||||||
end
|
end
|
||||||
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 }
|
complete_data.group_by { |d| d[:recorded_at].to_date.beginning_of_month }
|
||||||
.map do |month_start, _|
|
.map do |month_start, month_data|
|
||||||
first_monday = month_start
|
# Trouver le premier lundi du mois (à partir du 1er du mois)
|
||||||
first_monday = first_monday.next_occurring(:monday) unless first_monday.monday?
|
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
|
# Trouver le premier lundi du mois SUIVANT
|
||||||
next_first_monday = next_month_start
|
next_month_start = month_start.next_month.beginning_of_month
|
||||||
next_first_monday = next_first_monday.next_occurring(:monday) unless next_first_monday.monday?
|
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
|
# Le dernier jour du mois est le dimanche précédant le premier lundi du mois suivant
|
||||||
|
month_end = next_first_monday - 1.day
|
||||||
|
|
||||||
data_hash = complete_data.index_by { |d| d[:recorded_at].to_date }
|
# Créer un hash pour accès rapide aux données de complete_data (qui contient déjà les guess)
|
||||||
|
data_hash = complete_data.index_by { |d| d[:recorded_at].to_date }
|
||||||
|
|
||||||
all_days = (first_monday..month_end).map do |date|
|
# Générer tous les jours du premier lundi jusqu'au dimanche avant le prochain lundi
|
||||||
data_hash[date] || { mode: nil, recorded_at: date.to_datetime, guess: nil, day_log: nil }
|
all_days = (first_monday..month_end).map do |date|
|
||||||
end
|
# Utiliser directement les données de complete_data qui ont déjà le bon guess
|
||||||
|
data_hash[date] || { mode: nil, recorded_at: date.to_datetime, guess: nil }
|
||||||
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
|
||||||
|
|
||||||
|
# Grouper par semaines
|
||||||
|
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
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -1,25 +0,0 @@
|
||||||
= form_with model: day_log do |f|
|
|
||||||
- @day_log.errors.full_messages.each do |msg|
|
|
||||||
.notification.is-danger= msg
|
|
||||||
|
|
||||||
.field
|
|
||||||
= f.label :info, "Journal", class: "label"
|
|
||||||
.control
|
|
||||||
= f.text_area :info, class: "textarea", rows: 5
|
|
||||||
|
|
||||||
.field
|
|
||||||
= label_tag :mode_id, "Mode", class: "label"
|
|
||||||
.control
|
|
||||||
.select.is-fullwidth
|
|
||||||
= select_tag "day_log[mode_id]",
|
|
||||||
options_from_collection_for_select(Current.user.modes, :id, :label, @mood&.mode_id),
|
|
||||||
include_blank: true
|
|
||||||
|
|
||||||
.field.is-hidden
|
|
||||||
= f.date_field :day
|
|
||||||
|
|
||||||
.field.is-grouped
|
|
||||||
.control
|
|
||||||
= f.submit "Enregistrer", class: "button is-primary"
|
|
||||||
.control
|
|
||||||
= link_to "Annuler", dashboard_path(day: @day_log.day), class: "button is-light"
|
|
||||||
|
|
@ -1,13 +0,0 @@
|
||||||
%main.columns.m-auto
|
|
||||||
.current-day.column.is-hidden-mobile
|
|
||||||
%section.m-4
|
|
||||||
%figure.image.has-ratio
|
|
||||||
= image_tag @mood ? @mood.mode.image_url : "unknown.jpg"
|
|
||||||
|
|
||||||
%section.section.column.has-background-primary-light
|
|
||||||
%h1.title.is-4
|
|
||||||
%span.icon
|
|
||||||
%i.fa-regular.fa-calendar
|
|
||||||
%span= l @day_log.day, format: :long
|
|
||||||
|
|
||||||
= render 'form', day_log: @day_log
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
%h1 Nouveau journal
|
|
||||||
|
|
||||||
= render 'form', day_log: @day_log
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
<div class="current-day column is-hidden-mobile">
|
<div class="current-day column is-hidden-mobile">
|
||||||
<section class="m-4">
|
<section class="m-4">
|
||||||
<figure class="image has-ratio">
|
<figure class="image has-ratio">
|
||||||
<%= image_tag(@user.current_mode.image_url, "data-mood-target": "image") %>
|
<%= image_tag(@user.current_mood + ".jpg", "data-mood-target": "image") %>
|
||||||
</figure>
|
</figure>
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -12,24 +12,33 @@
|
||||||
<div class="is-flex is-align-items-center mr-4">
|
<div class="is-flex is-align-items-center mr-4">
|
||||||
<div class=""><strong>Légende</strong></div>
|
<div class=""><strong>Légende</strong></div>
|
||||||
</div>
|
</div>
|
||||||
<% @user.modes.each do |mode| %>
|
<div class="is-flex is-align-items-center mr-4">
|
||||||
<div class="is-flex is-align-items-center mr-4">
|
<div class="bar-frigo mr-1"></div>
|
||||||
<div class="bar mr-1" style="<%= style_for_mode(mode, :filled) %>"></div>
|
<div class="">Triste</div>
|
||||||
<div class=""><%= mode.label %></div>
|
</div>
|
||||||
</div>
|
<div class="is-flex is-align-items-center mr-4">
|
||||||
<% end %>
|
<div class="bar-en-charge mr-1"></div>
|
||||||
|
<div class="">En charge</div>
|
||||||
|
</div>
|
||||||
|
<div class="is-flex is-align-items-center mr-4">
|
||||||
|
<div class="bar-croisiere mr-1"></div>
|
||||||
|
<div class="">Croisiere</div>
|
||||||
|
</div>
|
||||||
|
<div class="is-flex is-align-items-center mr-4">
|
||||||
|
<div class="bar-creatif mr-1"></div>
|
||||||
|
<div>Creatif</div>
|
||||||
|
</div>
|
||||||
|
<div class="is-flex is-align-items-center mr-4">
|
||||||
|
<div class="bar-afond mr-1"></div>
|
||||||
|
<div class="">A fond</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="container mb-4 p-3 has-background-white day-info">
|
<div class="container mb-4 p-3 has-background-white day-info">
|
||||||
<div class="title is-4">
|
<div class="title is-4">
|
||||||
<span class="icon"><i class="fa-regular fa-calendar"></i></span>
|
<span class="icon"><i class="fa-regular fa-calendar"></i></span>
|
||||||
<span data-mood-target="modeDay">Aujourd'hui : <%= @user.current_mode.label %></span>
|
<span data-mood-target="modeDay">Aujourd'hui : <%= @user.current_mood %></span>
|
||||||
<%= link_to edit_day_log_for_day_path(day: Date.today), "data-mood-target": "dayLogLink" do %>
|
|
||||||
<span class="icon ml-2"><i class="has-text-grey fa-solid fa-pencil fa-xs"></i></span>
|
|
||||||
<% end %>
|
|
||||||
</div>
|
</div>
|
||||||
<p data-mood-target="dayLogInfo"><%= @user.current_day_log&.info %></p>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="logs">
|
<div class="logs">
|
||||||
<div class="is-flex is-flex-direction-row is-flex-wrap-wrap mb-3">
|
<div class="is-flex is-flex-direction-row is-flex-wrap-wrap mb-3">
|
||||||
<% @user.history.each do |month| %>
|
<% @user.history.each do |month| %>
|
||||||
|
|
@ -39,23 +48,15 @@
|
||||||
<% month[:weeks].each do |week| %>
|
<% month[:weeks].each do |week| %>
|
||||||
<div class="is-flex is-flex-direction-column is-flex-wrap-wrap mb-3">
|
<div class="is-flex is-flex-direction-column is-flex-wrap-wrap mb-3">
|
||||||
<% week.each do |mood| %>
|
<% week.each do |mood| %>
|
||||||
<% status = day_status(mood, @user) %>
|
|
||||||
<% mode = mode_for(mood, @user) %>
|
<% mode = mode_for(mood, @user) %>
|
||||||
<div data-image="<%= mode.image_url %>"
|
<div data-image="<%= asset_path(mode + ".jpg") %>" data-mode="<%= mode %>" data-day="<%= l mood[:recorded_at].to_date %>" data-action="click->mood#updateDayInfo" title="<%= l(mood[:recorded_at].to_date) %> : <%= mode %>" class="day <%= mode %>"></div>
|
||||||
data-mode="<%= mode.label %>"
|
|
||||||
data-day="<%= mood[:recorded_at].to_date.iso8601 %>"
|
|
||||||
data-info="<%= mood[:day_log]&.info %>"
|
|
||||||
data-action="click->mood#updateDayInfo"
|
|
||||||
title="<%= l(mood[:recorded_at].to_date) %> : <%= mode.label %>"
|
|
||||||
class="<%= css_class_for_day(status) %>"
|
|
||||||
style="<%= style_for_mode(mode, status) %>">
|
|
||||||
</div>
|
|
||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
<div id="end"></>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,4 @@ Rails.application.routes.draw do
|
||||||
patch "/invite/:token", to: "invitations#update", as: :invitation
|
patch "/invite/:token", to: "invitations#update", as: :invitation
|
||||||
|
|
||||||
get "/moods", to: "moods#index", as: :dashboard
|
get "/moods", to: "moods#index", as: :dashboard
|
||||||
|
|
||||||
get "/day_logs/edit", to: "day_logs#edit", as: :edit_day_log_for_day
|
|
||||||
resources :day_logs, only: [ :create, :update ]
|
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
class CreateModes < ActiveRecord::Migration[8.0]
|
|
||||||
def change
|
|
||||||
create_table :modes do |t|
|
|
||||||
t.string :label
|
|
||||||
t.string :color
|
|
||||||
t.references :user, null: false, foreign_key: true
|
|
||||||
|
|
||||||
t.timestamps
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
@ -1,34 +0,0 @@
|
||||||
class ReplaceMoodModeStringWithModeReference < ActiveRecord::Migration[8.0]
|
|
||||||
def up
|
|
||||||
rename_column :moods, :mode, :mode_string
|
|
||||||
|
|
||||||
# 1. Ajouter la colonne de référence
|
|
||||||
add_reference :moods, :mode, foreign_key: true
|
|
||||||
|
|
||||||
# 2. Pour chaque mood, trouver ou créer le Mode correspondant
|
|
||||||
Mood.find_each do |mood|
|
|
||||||
next if mood.mode_string.blank?
|
|
||||||
|
|
||||||
mode_record = Mode.find_or_create_by!(label: mood.mode_string, user_id: mood.user_id) do |m|
|
|
||||||
m.color = "#000000" # couleur par défaut
|
|
||||||
end
|
|
||||||
|
|
||||||
mood.update_column(:mode_id, mode_record.id)
|
|
||||||
end
|
|
||||||
|
|
||||||
# 3. Supprimer l'ancienne colonne string
|
|
||||||
remove_column :moods, :mode_string, :string
|
|
||||||
end
|
|
||||||
|
|
||||||
def down
|
|
||||||
add_column :moods, :mode_string, :string
|
|
||||||
|
|
||||||
Mood.find_each do |mood|
|
|
||||||
mood.update_column(:mode_string, mood.mode&.label)
|
|
||||||
end
|
|
||||||
|
|
||||||
remove_reference :moods, :mode, foreign_key: true
|
|
||||||
|
|
||||||
rename_column :moods, :mode_string, :mode
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
@ -1,57 +0,0 @@
|
||||||
# This migration comes from active_storage (originally 20170806125915)
|
|
||||||
class CreateActiveStorageTables < ActiveRecord::Migration[7.0]
|
|
||||||
def change
|
|
||||||
# Use Active Record's configured type for primary and foreign keys
|
|
||||||
primary_key_type, foreign_key_type = primary_and_foreign_key_types
|
|
||||||
|
|
||||||
create_table :active_storage_blobs, id: primary_key_type do |t|
|
|
||||||
t.string :key, null: false
|
|
||||||
t.string :filename, null: false
|
|
||||||
t.string :content_type
|
|
||||||
t.text :metadata
|
|
||||||
t.string :service_name, null: false
|
|
||||||
t.bigint :byte_size, null: false
|
|
||||||
t.string :checksum
|
|
||||||
|
|
||||||
if connection.supports_datetime_with_precision?
|
|
||||||
t.datetime :created_at, precision: 6, null: false
|
|
||||||
else
|
|
||||||
t.datetime :created_at, null: false
|
|
||||||
end
|
|
||||||
|
|
||||||
t.index [ :key ], unique: true
|
|
||||||
end
|
|
||||||
|
|
||||||
create_table :active_storage_attachments, id: primary_key_type do |t|
|
|
||||||
t.string :name, null: false
|
|
||||||
t.references :record, null: false, polymorphic: true, index: false, type: foreign_key_type
|
|
||||||
t.references :blob, null: false, type: foreign_key_type
|
|
||||||
|
|
||||||
if connection.supports_datetime_with_precision?
|
|
||||||
t.datetime :created_at, precision: 6, null: false
|
|
||||||
else
|
|
||||||
t.datetime :created_at, null: false
|
|
||||||
end
|
|
||||||
|
|
||||||
t.index [ :record_type, :record_id, :name, :blob_id ], name: :index_active_storage_attachments_uniqueness, unique: true
|
|
||||||
t.foreign_key :active_storage_blobs, column: :blob_id
|
|
||||||
end
|
|
||||||
|
|
||||||
create_table :active_storage_variant_records, id: primary_key_type do |t|
|
|
||||||
t.belongs_to :blob, null: false, index: false, type: foreign_key_type
|
|
||||||
t.string :variation_digest, null: false
|
|
||||||
|
|
||||||
t.index [ :blob_id, :variation_digest ], name: :index_active_storage_variant_records_uniqueness, unique: true
|
|
||||||
t.foreign_key :active_storage_blobs, column: :blob_id
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
def primary_and_foreign_key_types
|
|
||||||
config = Rails.configuration.generators
|
|
||||||
setting = config.options[config.orm][:primary_key_type]
|
|
||||||
primary_key_type = setting || :primary_key
|
|
||||||
foreign_key_type = setting || :bigint
|
|
||||||
[ primary_key_type, foreign_key_type ]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
@ -1,13 +0,0 @@
|
||||||
class CreateDayLogs < ActiveRecord::Migration[8.0]
|
|
||||||
def change
|
|
||||||
create_table :day_logs do |t|
|
|
||||||
t.date :day, null: false
|
|
||||||
t.text :info, null: false
|
|
||||||
t.references :user, null: false, foreign_key: true
|
|
||||||
|
|
||||||
t.index :day, unique: true
|
|
||||||
|
|
||||||
t.timestamps
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
59
db/schema.rb
generated
59
db/schema.rb
generated
|
|
@ -10,61 +10,13 @@
|
||||||
#
|
#
|
||||||
# It's strongly recommended that you check this file into your version control system.
|
# It's strongly recommended that you check this file into your version control system.
|
||||||
|
|
||||||
ActiveRecord::Schema[8.0].define(version: 2026_03_19_181607) do
|
ActiveRecord::Schema[8.0].define(version: 2026_02_26_101258) do
|
||||||
create_table "active_storage_attachments", force: :cascade do |t|
|
|
||||||
t.string "name", null: false
|
|
||||||
t.string "record_type", null: false
|
|
||||||
t.bigint "record_id", null: false
|
|
||||||
t.bigint "blob_id", null: false
|
|
||||||
t.datetime "created_at", null: false
|
|
||||||
t.index ["blob_id"], name: "index_active_storage_attachments_on_blob_id"
|
|
||||||
t.index ["record_type", "record_id", "name", "blob_id"], name: "index_active_storage_attachments_uniqueness", unique: true
|
|
||||||
end
|
|
||||||
|
|
||||||
create_table "active_storage_blobs", force: :cascade do |t|
|
|
||||||
t.string "key", null: false
|
|
||||||
t.string "filename", null: false
|
|
||||||
t.string "content_type"
|
|
||||||
t.text "metadata"
|
|
||||||
t.string "service_name", null: false
|
|
||||||
t.bigint "byte_size", null: false
|
|
||||||
t.string "checksum"
|
|
||||||
t.datetime "created_at", null: false
|
|
||||||
t.index ["key"], name: "index_active_storage_blobs_on_key", unique: true
|
|
||||||
end
|
|
||||||
|
|
||||||
create_table "active_storage_variant_records", force: :cascade do |t|
|
|
||||||
t.bigint "blob_id", null: false
|
|
||||||
t.string "variation_digest", null: false
|
|
||||||
t.index ["blob_id", "variation_digest"], name: "index_active_storage_variant_records_uniqueness", unique: true
|
|
||||||
end
|
|
||||||
|
|
||||||
create_table "day_logs", force: :cascade do |t|
|
|
||||||
t.date "day", null: false
|
|
||||||
t.text "info", null: false
|
|
||||||
t.integer "user_id", null: false
|
|
||||||
t.datetime "created_at", null: false
|
|
||||||
t.datetime "updated_at", null: false
|
|
||||||
t.index ["day"], name: "index_day_logs_on_day", unique: true
|
|
||||||
t.index ["user_id"], name: "index_day_logs_on_user_id"
|
|
||||||
end
|
|
||||||
|
|
||||||
create_table "modes", force: :cascade do |t|
|
|
||||||
t.string "label"
|
|
||||||
t.string "color"
|
|
||||||
t.integer "user_id", null: false
|
|
||||||
t.datetime "created_at", null: false
|
|
||||||
t.datetime "updated_at", null: false
|
|
||||||
t.index ["user_id"], name: "index_modes_on_user_id"
|
|
||||||
end
|
|
||||||
|
|
||||||
create_table "moods", force: :cascade do |t|
|
create_table "moods", force: :cascade do |t|
|
||||||
|
t.string "mode"
|
||||||
t.datetime "recorded_at"
|
t.datetime "recorded_at"
|
||||||
t.datetime "created_at", null: false
|
t.datetime "created_at", null: false
|
||||||
t.datetime "updated_at", null: false
|
t.datetime "updated_at", null: false
|
||||||
t.integer "user_id"
|
t.integer "user_id"
|
||||||
t.integer "mode_id"
|
|
||||||
t.index ["mode_id"], name: "index_moods_on_mode_id"
|
|
||||||
t.index ["user_id"], name: "index_moods_on_user_id"
|
t.index ["user_id"], name: "index_moods_on_user_id"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -75,7 +27,7 @@ ActiveRecord::Schema[8.0].define(version: 2026_03_19_181607) do
|
||||||
t.datetime "updated_at", default: -> { "CURRENT_DATE" }, null: false
|
t.datetime "updated_at", default: -> { "CURRENT_DATE" }, null: false
|
||||||
t.string "chip_id"
|
t.string "chip_id"
|
||||||
t.integer "user_id"
|
t.integer "user_id"
|
||||||
t.index ["identifier"], name: "index_rfid_tags_on_identifier", unique: true
|
t.index ["identifier"], name: "index_rfid_tags_on_identifier"
|
||||||
t.index ["user_id"], name: "index_rfid_tags_on_user_id"
|
t.index ["user_id"], name: "index_rfid_tags_on_user_id"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -100,11 +52,6 @@ ActiveRecord::Schema[8.0].define(version: 2026_03_19_181607) do
|
||||||
t.index ["email_address"], name: "index_users_on_email_address", unique: true
|
t.index ["email_address"], name: "index_users_on_email_address", unique: true
|
||||||
end
|
end
|
||||||
|
|
||||||
add_foreign_key "active_storage_attachments", "active_storage_blobs", column: "blob_id"
|
|
||||||
add_foreign_key "active_storage_variant_records", "active_storage_blobs", column: "blob_id"
|
|
||||||
add_foreign_key "day_logs", "users"
|
|
||||||
add_foreign_key "modes", "users"
|
|
||||||
add_foreign_key "moods", "modes"
|
|
||||||
add_foreign_key "moods", "users"
|
add_foreign_key "moods", "users"
|
||||||
add_foreign_key "rfid_tags", "users"
|
add_foreign_key "rfid_tags", "users"
|
||||||
add_foreign_key "sessions", "users"
|
add_foreign_key "sessions", "users"
|
||||||
|
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
FactoryBot.define do
|
|
||||||
factory :day_log do
|
|
||||||
day { "2026-03-19" }
|
|
||||||
info { "Arrivée à Paris" }
|
|
||||||
user { association :user }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
FactoryBot.define do
|
|
||||||
factory :mode do
|
|
||||||
label { "MyString" }
|
|
||||||
color { "MyString" }
|
|
||||||
user { nil }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
FactoryBot.define do
|
FactoryBot.define do
|
||||||
factory :mood do
|
factory :mood do
|
||||||
recorded_at { DateTime.parse("2026-01-15 10:00:00") }
|
mode { "croisiere" }
|
||||||
|
recorded_at { DateTime.now }
|
||||||
association :user
|
association :user
|
||||||
association :mode
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,6 @@
|
||||||
FactoryBot.define do
|
FactoryBot.define do
|
||||||
factory :user do
|
factory :user do
|
||||||
sequence(:email_address) { |n| "user#{n}@example.com" }
|
sequence(:email_address) { |n| "user#{n}@example.com" }
|
||||||
sequence(:username) { |n| "user#{n}" }
|
password_digest { BCrypt::Password.create('password123') }
|
||||||
password { "obanonalors" }
|
|
||||||
password_digest { BCrypt::Password.create(password) }
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -1,24 +0,0 @@
|
||||||
require 'rails_helper'
|
|
||||||
|
|
||||||
describe DayLog, type: :model do
|
|
||||||
subject { build(:day_log) }
|
|
||||||
|
|
||||||
it { is_expected.to be_valid }
|
|
||||||
|
|
||||||
describe "validations" do
|
|
||||||
it "is invalid without a day" do
|
|
||||||
subject.day = nil
|
|
||||||
expect(subject).not_to be_valid
|
|
||||||
end
|
|
||||||
|
|
||||||
it "is invalid without info" do
|
|
||||||
subject.info = nil
|
|
||||||
expect(subject).not_to be_valid
|
|
||||||
end
|
|
||||||
|
|
||||||
it "is invalid without a user" do
|
|
||||||
subject.user = nil
|
|
||||||
expect(subject).not_to be_valid
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
require 'rails_helper'
|
|
||||||
|
|
||||||
RSpec.describe Mode, type: :model do
|
|
||||||
pending "add some examples to (or delete) #{__FILE__}"
|
|
||||||
end
|
|
||||||
|
|
@ -1,46 +1,7 @@
|
||||||
require 'rails_helper'
|
require 'rails_helper'
|
||||||
|
|
||||||
describe Mood do
|
describe Mood, type: :model do
|
||||||
let(:user) { create(:user) }
|
it 'works' do
|
||||||
let(:mode) { create(:mode, user: user) }
|
expect(true)
|
||||||
|
|
||||||
subject { build(:mood, user: user, mode: mode, recorded_at: DateTime.parse("2026-01-15 10:00:00")) }
|
|
||||||
|
|
||||||
it { is_expected.to be_valid }
|
|
||||||
|
|
||||||
describe "validations" do
|
|
||||||
it "is invalid without a user" do
|
|
||||||
subject.user = nil
|
|
||||||
expect(subject).not_to be_valid
|
|
||||||
end
|
|
||||||
|
|
||||||
it "is invalid without a mode" do
|
|
||||||
subject.mode = nil
|
|
||||||
expect(subject).not_to be_valid
|
|
||||||
end
|
|
||||||
|
|
||||||
it "is invalid without a recorded_at" do
|
|
||||||
subject.recorded_at = nil
|
|
||||||
expect(subject).not_to be_valid
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "uniqueness per day and user" do
|
|
||||||
it "is invalid if a mood already exists for the same day and user" do
|
|
||||||
create(:mood, user: user, mode: mode, recorded_at: DateTime.parse("2026-01-15 18:00:00"))
|
|
||||||
expect(subject).not_to be_valid
|
|
||||||
end
|
|
||||||
|
|
||||||
it "is valid if the same day exists but for a different user" do
|
|
||||||
other_user = create(:user)
|
|
||||||
other_mode = create(:mode, user: other_user)
|
|
||||||
create(:mood, user: other_user, mode: other_mode, recorded_at: DateTime.parse("2026-01-15 10:00:00"))
|
|
||||||
expect(subject).to be_valid
|
|
||||||
end
|
|
||||||
|
|
||||||
it "is valid if the same user has a mood on a different day" do
|
|
||||||
create(:mood, user: user, mode: mode, recorded_at: DateTime.parse("2026-01-14 10:00:00"))
|
|
||||||
expect(subject).to be_valid
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -1,251 +0,0 @@
|
||||||
require 'rails_helper'
|
|
||||||
|
|
||||||
describe "DayLogs", type: :request do
|
|
||||||
let(:user) { create(:user) }
|
|
||||||
let(:mode) { create(:mode, user: user) }
|
|
||||||
let(:day) { Date.parse("2026-01-15") }
|
|
||||||
|
|
||||||
describe "GET /day_logs/edit" do
|
|
||||||
context "when not authenticated" do
|
|
||||||
it "redirects to the login page" do
|
|
||||||
get edit_day_log_for_day_path(day: day)
|
|
||||||
expect(response).to redirect_to(new_session_path)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "when authenticated" do
|
|
||||||
before { login_as(user) }
|
|
||||||
|
|
||||||
context "with an existing day_log for the day" do
|
|
||||||
let!(:day_log) { create(:day_log, user: user, day: day) }
|
|
||||||
|
|
||||||
it "returns http success" do
|
|
||||||
get edit_day_log_for_day_path(day: day)
|
|
||||||
expect(response).to have_http_status(:success)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "without an existing day_log for the day" do
|
|
||||||
it "returns http success" do
|
|
||||||
get edit_day_log_for_day_path(day: day)
|
|
||||||
expect(response).to have_http_status(:success)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "does not persist a day_log" do
|
|
||||||
expect {
|
|
||||||
get edit_day_log_for_day_path(day: day)
|
|
||||||
}.not_to change(DayLog, :count)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "POST /day_logs" do
|
|
||||||
context "when not authenticated" do
|
|
||||||
it "redirects to the login page" do
|
|
||||||
post day_logs_path, params: { day_log: { day: day, info: "Une info" } }
|
|
||||||
expect(response).to redirect_to(new_session_path)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "when authenticated" do
|
|
||||||
before { login_as(user) }
|
|
||||||
|
|
||||||
context "with valid params" do
|
|
||||||
context "without mode" do
|
|
||||||
it "creates a day_log" do
|
|
||||||
expect {
|
|
||||||
post day_logs_path, params: { day_log: { day: day, info: "Une info" } }
|
|
||||||
}.to change(DayLog, :count).by(1)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "does not create a mood" do
|
|
||||||
expect {
|
|
||||||
post day_logs_path, params: { day_log: { day: day, info: "Une info" } }
|
|
||||||
}.not_to change(Mood, :count)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "with mode, no existing mood" do
|
|
||||||
it "creates a day_log" do
|
|
||||||
expect {
|
|
||||||
post day_logs_path, params: { day_log: { day: day, info: "Une info", mode_id: mode.id } }
|
|
||||||
}.to change(DayLog, :count).by(1)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "creates a mood" do
|
|
||||||
expect {
|
|
||||||
post day_logs_path, params: { day_log: { day: day, info: "Une info", mode_id: mode.id } }
|
|
||||||
}.to change(Mood, :count).by(1)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "with mode, existing mood" do
|
|
||||||
let!(:existing_mood) { create(:mood, user: user, mode: mode, recorded_at: DateTime.parse("2026-01-15 08:00:00")) }
|
|
||||||
let(:other_mode) { create(:mode, user: user) }
|
|
||||||
|
|
||||||
it "creates a day_log" do
|
|
||||||
expect {
|
|
||||||
post day_logs_path, params: { day_log: { day: day, info: "Une info", mode_id: other_mode.id } }
|
|
||||||
}.to change(DayLog, :count).by(1)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "does not create a new mood" do
|
|
||||||
expect {
|
|
||||||
post day_logs_path, params: { day_log: { day: day, info: "Une info", mode_id: other_mode.id } }
|
|
||||||
}.not_to change(Mood, :count)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "updates the existing mood mode" do
|
|
||||||
post day_logs_path, params: { day_log: { day: day, info: "Une info", mode_id: other_mode.id } }
|
|
||||||
expect(existing_mood.reload.mode).to eq(other_mode)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
it "redirects after creation" do
|
|
||||||
post day_logs_path, params: { day_log: { day: day, info: "Une info" } }
|
|
||||||
expect(response).to have_http_status(:redirect)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "with invalid params" do
|
|
||||||
it "does not create a day_log" do
|
|
||||||
expect {
|
|
||||||
post day_logs_path, params: { day_log: { day: nil, info: nil } }
|
|
||||||
}.not_to change(DayLog, :count)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "returns unprocessable content" do
|
|
||||||
post day_logs_path, params: { day_log: { day: nil, info: nil } }
|
|
||||||
expect(response).to have_http_status(:unprocessable_content)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "GET /day_logs/:id/edit" do
|
|
||||||
let!(:day_log) { create(:day_log, user: user, day: day) }
|
|
||||||
|
|
||||||
context "when not authenticated" do
|
|
||||||
it "redirects to the login page" do
|
|
||||||
get edit_day_log_path(day_log)
|
|
||||||
expect(response).to redirect_to(new_session_path)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "when authenticated" do
|
|
||||||
before { login_as(user) }
|
|
||||||
|
|
||||||
it "returns http success" do
|
|
||||||
get edit_day_log_path(day_log)
|
|
||||||
expect(response).to have_http_status(:success)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "GET /day_logs/edit" do
|
|
||||||
context "when not authenticated" do
|
|
||||||
it "redirects to the login page" do
|
|
||||||
get edit_day_log_for_day_path(day: day)
|
|
||||||
expect(response).to redirect_to(new_session_path)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "when authenticated" do
|
|
||||||
before { login_as(user) }
|
|
||||||
|
|
||||||
context "with an existing day_log for the day" do
|
|
||||||
let!(:day_log) { create(:day_log, user: user, day: day) }
|
|
||||||
|
|
||||||
it "returns http success" do
|
|
||||||
get edit_day_log_for_day_path(day: day)
|
|
||||||
expect(response).to have_http_status(:success)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "without an existing day_log for the day" do
|
|
||||||
it "returns http success" do
|
|
||||||
get edit_day_log_for_day_path(day: day)
|
|
||||||
expect(response).to have_http_status(:success)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "does not persist a day_log" do
|
|
||||||
expect {
|
|
||||||
get edit_day_log_for_day_path(day: day)
|
|
||||||
}.not_to change(DayLog, :count)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "PATCH /day_logs/:id" do
|
|
||||||
let!(:day_log) { create(:day_log, user: user, day: day) }
|
|
||||||
|
|
||||||
context "when not authenticated" do
|
|
||||||
it "redirects to the login page" do
|
|
||||||
patch day_log_path(day_log), params: { day_log: { info: "Nouvelle info" } }
|
|
||||||
expect(response).to redirect_to(new_session_path)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "when authenticated" do
|
|
||||||
before { login_as(user) }
|
|
||||||
|
|
||||||
context "with valid params" do
|
|
||||||
context "without mode" do
|
|
||||||
it "updates the day_log" do
|
|
||||||
patch day_log_path(day_log), params: { day_log: { info: "Nouvelle info" } }
|
|
||||||
expect(day_log.reload.info).to eq("Nouvelle info")
|
|
||||||
end
|
|
||||||
|
|
||||||
it "does not create a mood" do
|
|
||||||
expect {
|
|
||||||
patch day_log_path(day_log), params: { day_log: { info: "Nouvelle info" } }
|
|
||||||
}.not_to change(Mood, :count)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "redirects to dashboard" do
|
|
||||||
patch day_log_path(day_log), params: { day_log: { info: "Nouvelle info" } }
|
|
||||||
expect(response).to redirect_to(dashboard_path)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "with mode, no existing mood" do
|
|
||||||
it "creates a mood" do
|
|
||||||
expect {
|
|
||||||
patch day_log_path(day_log), params: { day_log: { info: "Nouvelle info", mode_id: mode.id } }
|
|
||||||
}.to change(Mood, :count).by(1)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "with mode, existing mood" do
|
|
||||||
let!(:existing_mood) { create(:mood, user: user, mode: mode, recorded_at: DateTime.parse("2026-01-15 08:00:00")) }
|
|
||||||
let(:other_mode) { create(:mode, user: user) }
|
|
||||||
|
|
||||||
it "does not create a new mood" do
|
|
||||||
expect {
|
|
||||||
patch day_log_path(day_log), params: { day_log: { info: "Nouvelle info", mode_id: other_mode.id } }
|
|
||||||
}.not_to change(Mood, :count)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "updates the existing mood mode" do
|
|
||||||
patch day_log_path(day_log), params: { day_log: { info: "Nouvelle info", mode_id: other_mode.id } }
|
|
||||||
expect(existing_mood.reload.mode).to eq(other_mode)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "with invalid params" do
|
|
||||||
it "does not update the day_log" do
|
|
||||||
patch day_log_path(day_log), params: { day_log: { info: nil } }
|
|
||||||
expect(day_log.reload.info).not_to be_nil
|
|
||||||
end
|
|
||||||
|
|
||||||
it "returns unprocessable content" do
|
|
||||||
patch day_log_path(day_log), params: { day_log: { info: nil } }
|
|
||||||
expect(response).to have_http_status(:unprocessable_content)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
@ -1,231 +1,330 @@
|
||||||
|
# spec/services/mood_calendar_service_spec.rb
|
||||||
require 'rails_helper'
|
require 'rails_helper'
|
||||||
|
|
||||||
RSpec.describe MoodCalendarService do
|
RSpec.describe MoodCalendarService do
|
||||||
let(:user) { create(:user) }
|
|
||||||
let(:mode) { create(:mode, user: user) }
|
|
||||||
|
|
||||||
describe '.generate_calendar' do
|
describe '.generate_calendar' do
|
||||||
context 'avec des jours manquants' do
|
context 'avec un recorded_at pour chaque jour' do
|
||||||
it 'remplit les jours manquants avec mode: nil et guess égal au dernier mode' do
|
it 'génère un calendrier complet sans jours nil' do
|
||||||
mode2 = create(:mode, user: user)
|
# Données du 1er au 7 février 2025 (une semaine complète)
|
||||||
mode3 = create(:mode, user: user)
|
(1..7).each do |day|
|
||||||
create(:mood, user: user, mode: mode2, recorded_at: Time.zone.parse("2025-02-12 14:20:00"))
|
create(:mood, mode: "mood_#{day}", recorded_at: Time.zone.parse("2025-02-0#{day} 10:00:00"))
|
||||||
create(:mood, user: user, mode: mode3, recorded_at: Time.zone.parse("2025-02-15 10:00:00"))
|
end
|
||||||
create(:mood, user: user, mode: mode, recorded_at: Time.zone.parse("2025-02-18 16:45:00"))
|
|
||||||
|
|
||||||
result = MoodCalendarService.generate_calendar(
|
result = MoodCalendarService.generate_calendar(
|
||||||
user,
|
Mood.all,
|
||||||
end_date: Date.parse("2025-02-28")
|
end_date: Date.parse("2025-02-28")
|
||||||
)
|
)
|
||||||
|
|
||||||
expect(result.length).to be >= 1
|
expect(result.length).to eq(1) # Un seul mois
|
||||||
expect(result.any? { |m| m[:month] == Date.parse("2025-02-01") }).to be true
|
expect(result[0][:month]).to eq(Date.parse("2025-02-01"))
|
||||||
|
|
||||||
all_days = result.find { |m| m[:month] == Date.parse("2025-02-01") }[:weeks].flatten
|
# Première semaine commence le lundi 3 février
|
||||||
|
first_week = result[0][:weeks][0]
|
||||||
|
expect(first_week.length).to eq(7) # Du lundi 3 au dimanche 9
|
||||||
|
|
||||||
|
# Vérifier que tous les jours du 3 au 7 ont un mode
|
||||||
|
(3..7).each do |day|
|
||||||
|
mood = first_week.find { |m| m[:recorded_at].day == day }
|
||||||
|
expect(mood[:mode]).to eq("mood_#{day}")
|
||||||
|
expect(mood).not_to have_key(:guess)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Le 8 et 9 février devraient avoir mode: nil avec guess: "mood_7"
|
||||||
|
mood_8 = first_week.find { |m| m[:recorded_at].day == 8 }
|
||||||
|
expect(mood_8[:mode]).to be_nil
|
||||||
|
expect(mood_8[:guess]).to eq("mood_7")
|
||||||
|
|
||||||
|
mood_9 = first_week.find { |m| m[:recorded_at].day == 9 }
|
||||||
|
expect(mood_9[:mode]).to be_nil
|
||||||
|
expect(mood_9[:guess]).to eq("mood_7")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'avec des jours manquants' do
|
||||||
|
it 'remplit les jours manquants avec mode: nil et guess égal au dernier mode' do
|
||||||
|
create(:mood, mode: "triste", recorded_at: Time.zone.parse("2025-02-12 08:30:00"))
|
||||||
|
create(:mood, mode: "content", recorded_at: Time.zone.parse("2025-02-12 14:20:00"))
|
||||||
|
create(:mood, mode: "heureux", recorded_at: Time.zone.parse("2025-02-15 10:00:00"))
|
||||||
|
create(:mood, mode: "calme", recorded_at: Time.zone.parse("2025-02-18 16:45:00"))
|
||||||
|
|
||||||
|
moods = Mood.all
|
||||||
|
result = MoodCalendarService.generate_calendar(
|
||||||
|
moods,
|
||||||
|
end_date: Date.parse("2025-02-28")
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(result.length).to eq(1)
|
||||||
|
expect(result[0][:month]).to eq(Date.parse("2025-02-01"))
|
||||||
|
|
||||||
|
# Trouver tous les jours
|
||||||
|
all_days = result[0][:weeks].flatten
|
||||||
|
|
||||||
|
# Le 12 février devrait avoir le dernier mood (content à 14:20)
|
||||||
mood_12 = all_days.find { |m| m[:recorded_at].to_date == Date.parse("2025-02-12") }
|
mood_12 = all_days.find { |m| m[:recorded_at].to_date == Date.parse("2025-02-12") }
|
||||||
expect(mood_12[:mode]).to eq(mode2)
|
expect(mood_12[:mode]).to eq("content")
|
||||||
expect(mood_12[:recorded_at].to_i).to eq(Time.zone.parse("2025-02-12 14:20:00").to_i)
|
expect(mood_12[:recorded_at].to_i).to eq(Time.zone.parse("2025-02-12 14:20:00").to_i)
|
||||||
|
|
||||||
|
# Le 13 février devrait être nil avec guess: "content"
|
||||||
mood_13 = all_days.find { |m| m[:recorded_at].to_date == Date.parse("2025-02-13") }
|
mood_13 = all_days.find { |m| m[:recorded_at].to_date == Date.parse("2025-02-13") }
|
||||||
expect(mood_13[:mode]).to be_nil
|
expect(mood_13[:mode]).to be_nil
|
||||||
expect(mood_13[:guess]).to eq(mode2)
|
expect(mood_13[:guess]).to eq("content")
|
||||||
|
|
||||||
|
# Le 14 février devrait être nil avec guess: "content"
|
||||||
mood_14 = all_days.find { |m| m[:recorded_at].to_date == Date.parse("2025-02-14") }
|
mood_14 = all_days.find { |m| m[:recorded_at].to_date == Date.parse("2025-02-14") }
|
||||||
expect(mood_14[:mode]).to be_nil
|
expect(mood_14[:mode]).to be_nil
|
||||||
expect(mood_14[:guess]).to eq(mode2)
|
expect(mood_14[:guess]).to eq("content")
|
||||||
|
|
||||||
|
# Le 15 février devrait avoir le mood "heureux"
|
||||||
mood_15 = all_days.find { |m| m[:recorded_at].to_date == Date.parse("2025-02-15") }
|
mood_15 = all_days.find { |m| m[:recorded_at].to_date == Date.parse("2025-02-15") }
|
||||||
expect(mood_15[:mode]).to eq(mode3)
|
expect(mood_15[:mode]).to eq("heureux")
|
||||||
|
|
||||||
|
# Le 16 février devrait être nil avec guess: "heureux"
|
||||||
mood_16 = all_days.find { |m| m[:recorded_at].to_date == Date.parse("2025-02-16") }
|
mood_16 = all_days.find { |m| m[:recorded_at].to_date == Date.parse("2025-02-16") }
|
||||||
expect(mood_16[:mode]).to be_nil
|
expect(mood_16[:mode]).to be_nil
|
||||||
expect(mood_16[:guess]).to eq(mode3)
|
expect(mood_16[:guess]).to eq("heureux")
|
||||||
|
|
||||||
|
# Les jours avant le 12 (à partir du premier lundi 3 février) devraient avoir guess: nil
|
||||||
mood_3 = all_days.find { |m| m[:recorded_at].to_date == Date.parse("2025-02-03") }
|
mood_3 = all_days.find { |m| m[:recorded_at].to_date == Date.parse("2025-02-03") }
|
||||||
expect(mood_3[:mode]).to be_nil
|
expect(mood_3[:mode]).to be_nil
|
||||||
expect(mood_3[:guess]).to be_nil
|
expect(mood_3[:guess]).to be_nil
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'gère correctement plusieurs mois avec des jours manquants' do
|
it 'gère correctement plusieurs mois avec des jours manquants' do
|
||||||
mode2 = create(:mode, user: user)
|
create(:mood, mode: "heureux", recorded_at: Time.zone.parse("2025-02-15 10:00:00"))
|
||||||
create(:mood, user: user, mode: mode, recorded_at: Time.zone.parse("2025-02-15 10:00:00"))
|
create(:mood, mode: "joyeux", recorded_at: Time.zone.parse("2025-04-20 11:30:00"))
|
||||||
create(:mood, user: user, mode: mode2, recorded_at: Time.zone.parse("2025-04-20 11:30:00"))
|
|
||||||
|
|
||||||
result = MoodCalendarService.generate_calendar(
|
result = MoodCalendarService.generate_calendar(
|
||||||
user,
|
Mood.all,
|
||||||
end_date: Date.parse("2025-04-30")
|
end_date: Date.parse("2025-04-30")
|
||||||
)
|
)
|
||||||
|
|
||||||
expect(result.length).to be >= 3
|
# Devrait avoir exactement février, mars et avril
|
||||||
expect(result.any? { |m| m[:month] == Date.parse("2025-02-01") }).to be true
|
expect(result.length).to eq(3)
|
||||||
expect(result.any? { |m| m[:month] == Date.parse("2025-03-01") }).to be true
|
|
||||||
expect(result.any? { |m| m[:month] == Date.parse("2025-04-01") }).to be true
|
|
||||||
|
|
||||||
|
# Vérifier février
|
||||||
|
february = result.find { |m| m[:month] == Date.parse("2025-02-01") }
|
||||||
|
expect(february).not_to be_nil
|
||||||
|
|
||||||
|
# Vérifier mars (tous les jours devraient avoir mode: nil et guess: "heureux")
|
||||||
march = result.find { |m| m[:month] == Date.parse("2025-03-01") }
|
march = result.find { |m| m[:month] == Date.parse("2025-03-01") }
|
||||||
|
expect(march).not_to be_nil
|
||||||
all_march_days = march[:weeks].flatten
|
all_march_days = march[:weeks].flatten
|
||||||
|
|
||||||
|
# Tous les jours de mars (y compris ceux qui débordent début avril) devraient avoir mode: nil
|
||||||
expect(all_march_days.all? { |d| d[:mode].nil? }).to be true
|
expect(all_march_days.all? { |d| d[:mode].nil? }).to be true
|
||||||
|
|
||||||
|
# Tous les jours de mars devraient avoir guess: "heureux"
|
||||||
|
# (le mois de mars va du 3 mars au 6 avril, avant le mood du 20 avril)
|
||||||
all_march_days.each do |day|
|
all_march_days.each do |day|
|
||||||
expect(day[:guess]).to be_present,
|
expect(day[:guess]).to eq("heureux"),
|
||||||
"Le jour #{day[:recorded_at].to_date} devrait avoir un guess"
|
"Le jour #{day[:recorded_at].to_date} devrait avoir guess: 'heureux' mais a: #{day[:guess].inspect}"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Vérifier avril
|
||||||
april = result.find { |m| m[:month] == Date.parse("2025-04-01") }
|
april = result.find { |m| m[:month] == Date.parse("2025-04-01") }
|
||||||
|
expect(april).not_to be_nil
|
||||||
all_april_days = april[:weeks].flatten
|
all_april_days = april[:weeks].flatten
|
||||||
mood_20_april = all_april_days.find { |m| m[:recorded_at].to_date == Date.parse("2025-04-20") }
|
mood_20_april = all_april_days.find { |m| m[:recorded_at].to_date == Date.parse("2025-04-20") }
|
||||||
expect(mood_20_april[:mode]).to eq(mode2)
|
expect(mood_20_april[:mode]).to eq("joyeux")
|
||||||
|
|
||||||
|
# Les jours du 7 au 19 avril devraient avoir guess: "heureux"
|
||||||
mood_10_april = all_april_days.find { |m| m[:recorded_at].to_date == Date.parse("2025-04-10") }
|
mood_10_april = all_april_days.find { |m| m[:recorded_at].to_date == Date.parse("2025-04-10") }
|
||||||
expect(mood_10_april[:guess]).to eq(mode)
|
expect(mood_10_april[:guess]).to eq("heureux")
|
||||||
|
|
||||||
|
# Les jours après le 20 avril devraient avoir guess: "joyeux"
|
||||||
mood_21_april = all_april_days.find { |m| m[:recorded_at].to_date == Date.parse("2025-04-21") }
|
mood_21_april = all_april_days.find { |m| m[:recorded_at].to_date == Date.parse("2025-04-21") }
|
||||||
expect(mood_21_april[:guess]).to eq(mode2)
|
expect(mood_21_april[:guess]).to eq("joyeux")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'sans aucun recorded_at' do
|
context 'sans aucun recorded_at' do
|
||||||
it 'retourne un calendrier à partir de la date courante' do
|
it 'retourne un tableau vide' do
|
||||||
result = MoodCalendarService.generate_calendar(user)
|
result = MoodCalendarService.generate_calendar(Mood.none)
|
||||||
|
|
||||||
expect(result).not_to be_empty
|
expect(result).to eq([])
|
||||||
expect(result.first[:month]).to eq(Date.current.beginning_of_month)
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'avec plusieurs moods le même jour' do
|
||||||
|
it 'garde uniquement le mood le plus récent' do
|
||||||
|
create(:mood, mode: "triste", recorded_at: Time.zone.parse("2025-02-12 08:30:00"))
|
||||||
|
create(:mood, mode: "neutre", recorded_at: Time.zone.parse("2025-02-12 12:00:00"))
|
||||||
|
create(:mood, mode: "content", recorded_at: Time.zone.parse("2025-02-12 14:20:00"))
|
||||||
|
create(:mood, mode: "fatigué", recorded_at: Time.zone.parse("2025-02-12 09:15:00"))
|
||||||
|
|
||||||
|
moods = Mood.all
|
||||||
|
result = MoodCalendarService.generate_calendar(
|
||||||
|
moods,
|
||||||
|
end_date: Date.parse("2025-02-28")
|
||||||
|
)
|
||||||
|
|
||||||
|
all_days = result[0][:weeks].flatten
|
||||||
|
mood_12 = all_days.find { |m| m[:recorded_at].to_date == Date.parse("2025-02-12") }
|
||||||
|
|
||||||
|
expect(mood_12[:mode]).to eq("content")
|
||||||
|
expect(mood_12[:recorded_at].to_i).to eq(Time.zone.parse("2025-02-12 14:20:00").to_i)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'structure du calendrier' do
|
context 'structure du calendrier' do
|
||||||
it 'commence chaque mois par le premier lundi' do
|
it 'commence chaque mois par le premier lundi' do
|
||||||
create(:mood, user: user, mode: mode, recorded_at: Time.zone.parse("2025-02-15 10:00:00"))
|
create(:mood, mode: "heureux", recorded_at: Time.zone.parse("2025-02-15 10:00:00"))
|
||||||
|
|
||||||
result = MoodCalendarService.generate_calendar(
|
result = MoodCalendarService.generate_calendar(
|
||||||
user,
|
Mood.all,
|
||||||
end_date: Date.parse("2025-02-28")
|
end_date: Date.parse("2025-02-28")
|
||||||
)
|
)
|
||||||
|
|
||||||
february = result[0]
|
february = result[0]
|
||||||
first_day = february[:weeks][0][0]
|
first_day = february[:weeks][0][0]
|
||||||
|
|
||||||
|
# Le premier jour de février 2025 devrait être le lundi 3 février
|
||||||
expect(first_day[:recorded_at].to_date).to eq(Date.parse("2025-02-03"))
|
expect(first_day[:recorded_at].to_date).to eq(Date.parse("2025-02-03"))
|
||||||
expect(first_day[:recorded_at].to_date.monday?).to be true
|
expect(first_day[:recorded_at].to_date.monday?).to be true
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'va du premier lundi du mois au dimanche avant le premier lundi du mois suivant' do
|
it 'va du premier lundi du mois au dimanche avant le premier lundi du mois suivant' do
|
||||||
create(:mood, user: user, mode: mode, recorded_at: Time.zone.parse("2025-02-15 10:00:00"))
|
create(:mood, mode: "heureux", recorded_at: Time.zone.parse("2025-02-15 10:00:00"))
|
||||||
|
|
||||||
result = MoodCalendarService.generate_calendar(
|
result = MoodCalendarService.generate_calendar(
|
||||||
user,
|
Mood.all,
|
||||||
end_date: Date.parse("2025-03-31")
|
end_date: Date.parse("2025-03-31")
|
||||||
)
|
)
|
||||||
|
|
||||||
february = result[0]
|
february = result[0]
|
||||||
all_days = february[:weeks].flatten
|
all_days = february[:weeks].flatten
|
||||||
|
|
||||||
|
# Premier jour : lundi 3 février 2025
|
||||||
first_day = all_days.first
|
first_day = all_days.first
|
||||||
expect(first_day[:recorded_at].to_date).to eq(Date.parse("2025-02-03"))
|
expect(first_day[:recorded_at].to_date).to eq(Date.parse("2025-02-03"))
|
||||||
expect(first_day[:recorded_at].to_date.monday?).to be true
|
expect(first_day[:recorded_at].to_date.monday?).to be true
|
||||||
|
|
||||||
|
# Dernier jour : dimanche 2 mars 2025 (veille du premier lundi de mars qui est le 3)
|
||||||
last_day = all_days.last
|
last_day = all_days.last
|
||||||
expect(last_day[:recorded_at].to_date).to eq(Date.parse("2025-03-02"))
|
expect(last_day[:recorded_at].to_date).to eq(Date.parse("2025-03-02"))
|
||||||
expect(last_day[:recorded_at].to_date.sunday?).to be true
|
expect(last_day[:recorded_at].to_date.sunday?).to be true
|
||||||
|
|
||||||
|
# Le 3 mars (premier lundi de mars) ne devrait PAS être dans février
|
||||||
expect(all_days.any? { |d| d[:recorded_at].to_date == Date.parse("2025-03-03") }).to be false
|
expect(all_days.any? { |d| d[:recorded_at].to_date == Date.parse("2025-03-03") }).to be false
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'toutes les semaines ont exactement 7 jours' do
|
it 'toutes les semaines ont exactement 7 jours' do
|
||||||
create(:mood, user: user, mode: mode, recorded_at: Time.zone.parse("2025-02-15 10:00:00"))
|
create(:mood, mode: "heureux", recorded_at: Time.zone.parse("2025-02-15 10:00:00"))
|
||||||
|
|
||||||
result = MoodCalendarService.generate_calendar(
|
result = MoodCalendarService.generate_calendar(
|
||||||
user,
|
Mood.all,
|
||||||
end_date: Date.parse("2025-02-28")
|
end_date: Date.parse("2025-02-28")
|
||||||
)
|
)
|
||||||
|
|
||||||
february = result[0]
|
february = result[0]
|
||||||
|
|
||||||
|
# Toutes les semaines devraient avoir exactement 7 jours
|
||||||
february[:weeks].each do |week|
|
february[:weeks].each do |week|
|
||||||
expect(week.length).to eq(7)
|
expect(week.length).to eq(7)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'retourne month comme Date (le premier du mois)' do
|
it 'retourne month comme Date (le premier du mois)' do
|
||||||
create(:mood, user: user, mode: mode, recorded_at: Time.zone.parse("2025-02-15 10:00:00"))
|
create(:mood, mode: "heureux", recorded_at: Time.zone.parse("2025-02-15 10:00:00"))
|
||||||
|
|
||||||
result = MoodCalendarService.generate_calendar(
|
result = MoodCalendarService.generate_calendar(
|
||||||
user,
|
Mood.all,
|
||||||
end_date: Date.parse("2025-02-28")
|
end_date: Date.parse("2025-02-28")
|
||||||
)
|
)
|
||||||
|
|
||||||
february = result[0]
|
february = result[0]
|
||||||
|
|
||||||
|
# month devrait être une Date
|
||||||
expect(february[:month]).to be_a(Date)
|
expect(february[:month]).to be_a(Date)
|
||||||
expect(february[:month]).to eq(Date.parse("2025-02-01"))
|
expect(february[:month]).to eq(Date.parse("2025-02-01"))
|
||||||
expect(february[:month].day).to eq(1)
|
expect(february[:month].day).to eq(1) # Premier du mois
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'avec paramètres par défaut' do
|
context 'avec paramètres par défaut' do
|
||||||
it "utilise le premier mood comme start_date et aujourd'hui comme end_date" do
|
it 'utilise le premier mood comme start_date et aujourd\'hui comme end_date' do
|
||||||
create(:mood, user: user, mode: mode, recorded_at: Time.zone.parse("2025-02-15 10:00:00"))
|
create(:mood, mode: "heureux", recorded_at: Time.zone.parse("2025-02-15 10:00:00"))
|
||||||
|
|
||||||
result = MoodCalendarService.generate_calendar(user)
|
result = MoodCalendarService.generate_calendar(Mood.all)
|
||||||
|
|
||||||
expect(result).not_to be_empty
|
expect(result).not_to be_empty
|
||||||
|
|
||||||
|
# Devrait commencer en février
|
||||||
expect(result.first[:month]).to eq(Date.parse("2025-02-01"))
|
expect(result.first[:month]).to eq(Date.parse("2025-02-01"))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'avec start_date spécifié' do
|
context 'avec start_date spécifié' do
|
||||||
it 'commence à la date spécifiée' do
|
it 'commence à la date spécifiée' do
|
||||||
create(:mood, user: user, mode: mode, recorded_at: Time.zone.parse("2025-02-15 10:00:00"))
|
create(:mood, mode: "heureux", recorded_at: Time.zone.parse("2025-02-15 10:00:00"))
|
||||||
|
|
||||||
result = MoodCalendarService.generate_calendar(
|
result = MoodCalendarService.generate_calendar(
|
||||||
user,
|
Mood.all,
|
||||||
start_date: Date.parse("2025-03-01"),
|
start_date: Date.parse("2025-03-01"),
|
||||||
end_date: Date.parse("2025-03-31")
|
end_date: Date.parse("2025-03-31")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Devrait commencer en mars même si le mood est en février
|
||||||
expect(result.first[:month]).to eq(Date.parse("2025-03-01"))
|
expect(result.first[:month]).to eq(Date.parse("2025-03-01"))
|
||||||
|
|
||||||
|
# Ne devrait pas contenir février
|
||||||
expect(result.any? { |m| m[:month] == Date.parse("2025-02-01") }).to be false
|
expect(result.any? { |m| m[:month] == Date.parse("2025-02-01") }).to be false
|
||||||
|
|
||||||
|
# Tous les jours de mars devraient avoir guess: "heureux" (du 15 février)
|
||||||
|
all_march_days = result.first[:weeks].flatten
|
||||||
|
puts all_march_days.inspect
|
||||||
|
expect(all_march_days.all? { |d| d[:guess] == "heureux" }).to be true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'avec end_date spécifié' do
|
context 'avec end_date spécifié' do
|
||||||
it 'se termine à end_date' do
|
it 'se termine à la date spécifiée' do
|
||||||
create(:mood, user: user, mode: mode, recorded_at: Time.zone.parse("2025-02-15 10:00:00"))
|
create(:mood, mode: "heureux", recorded_at: Time.zone.parse("2025-02-15 10:00:00"))
|
||||||
|
|
||||||
result = MoodCalendarService.generate_calendar(
|
result = MoodCalendarService.generate_calendar(
|
||||||
user,
|
Mood.all,
|
||||||
end_date: Date.parse("2025-09-30")
|
end_date: Date.parse("2025-02-28")
|
||||||
)
|
)
|
||||||
|
|
||||||
expect(result.last[:month]).to eq(Date.parse("2025-09-01"))
|
# Devrait s'arrêter en février
|
||||||
|
expect(result.last[:month]).to eq(Date.parse("2025-02-01"))
|
||||||
|
|
||||||
|
# Ne devrait pas contenir mars ou au-delà
|
||||||
|
expect(result.any? { |m| m[:month] == Date.parse("2025-03-01") }).to be false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'avec start_date et end_date spécifiés' do
|
context 'avec start_date et end_date spécifiés' do
|
||||||
it 'génère le calendrier pour la plage spécifiée' do
|
it 'génère le calendrier pour la plage spécifiée' do
|
||||||
mode2 = create(:mode, user: user)
|
create(:mood, mode: "heureux", recorded_at: Time.zone.parse("2025-02-15 10:00:00"))
|
||||||
create(:mood, user: user, mode: mode, recorded_at: Time.zone.parse("2025-02-15 10:00:00"))
|
create(:mood, mode: "calme", recorded_at: Time.zone.parse("2025-04-20 10:00:00"))
|
||||||
create(:mood, user: user, mode: mode2, recorded_at: Time.zone.parse("2025-04-20 10:00:00"))
|
|
||||||
|
|
||||||
result = MoodCalendarService.generate_calendar(
|
result = MoodCalendarService.generate_calendar(
|
||||||
user,
|
Mood.all,
|
||||||
start_date: Date.parse("2025-03-01"),
|
start_date: Date.parse("2025-03-01"),
|
||||||
end_date: Date.parse("2025-03-31")
|
end_date: Date.parse("2025-03-31")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Devrait contenir uniquement mars
|
||||||
expect(result.length).to eq(1)
|
expect(result.length).to eq(1)
|
||||||
expect(result.first[:month]).to eq(Date.parse("2025-03-01"))
|
expect(result.first[:month]).to eq(Date.parse("2025-03-01"))
|
||||||
|
|
||||||
|
# Tous les jours de mars devraient avoir guess: "heureux" (du 15 février)
|
||||||
all_days = result.first[:weeks].flatten
|
all_days = result.first[:weeks].flatten
|
||||||
expect(all_days.all? { |d| d[:mode].nil? }).to be true
|
expect(all_days.all? { |d| d[:mode].nil? }).to be true
|
||||||
|
expect(all_days.all? { |d| d[:guess] == "heureux" }).to be true
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'gère une plage de plusieurs mois' do
|
it 'gère une plage de plusieurs mois' do
|
||||||
create(:mood, user: user, mode: mode, recorded_at: Time.zone.parse("2025-02-15 10:00:00"))
|
create(:mood, mode: "heureux", recorded_at: Time.zone.parse("2025-02-15 10:00:00"))
|
||||||
|
|
||||||
result = MoodCalendarService.generate_calendar(
|
result = MoodCalendarService.generate_calendar(
|
||||||
user,
|
Mood.all,
|
||||||
start_date: Date.parse("2025-02-01"),
|
start_date: Date.parse("2025-02-01"),
|
||||||
end_date: Date.parse("2025-04-30")
|
end_date: Date.parse("2025-04-30")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Devrait contenir février, mars et avril
|
||||||
months = result.map { |m| m[:month] }
|
months = result.map { |m| m[:month] }
|
||||||
expect(months).to include(
|
expect(months).to include(
|
||||||
Date.parse("2025-02-01"),
|
Date.parse("2025-02-01"),
|
||||||
|
|
@ -235,10 +334,11 @@ RSpec.describe MoodCalendarService do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'fonctionne avec DateTime en paramètres' do
|
it 'fonctionne avec DateTime en paramètres' do
|
||||||
create(:mood, user: user, mode: mode, recorded_at: Time.zone.parse("2025-02-15 10:00:00"))
|
create(:mood, mode: "heureux", recorded_at: Time.zone.parse("2025-02-15 10:00:00"))
|
||||||
|
|
||||||
|
# Passer des DateTime au lieu de Date
|
||||||
result = MoodCalendarService.generate_calendar(
|
result = MoodCalendarService.generate_calendar(
|
||||||
user,
|
Mood.all,
|
||||||
start_date: Time.zone.parse("2025-02-01 00:00:00"),
|
start_date: Time.zone.parse("2025-02-01 00:00:00"),
|
||||||
end_date: Time.zone.parse("2025-02-28 23:59:59")
|
end_date: Time.zone.parse("2025-02-28 23:59:59")
|
||||||
)
|
)
|
||||||
|
|
@ -250,109 +350,72 @@ RSpec.describe MoodCalendarService do
|
||||||
|
|
||||||
context 'avec une plage ne contenant aucun mood' do
|
context 'avec une plage ne contenant aucun mood' do
|
||||||
it 'génère un calendrier avec tous les jours à nil et guess du dernier mood avant la plage' do
|
it 'génère un calendrier avec tous les jours à nil et guess du dernier mood avant la plage' do
|
||||||
create(:mood, user: user, mode: mode, recorded_at: Time.zone.parse("2025-02-15 10:00:00"))
|
create(:mood, mode: "heureux", recorded_at: Time.zone.parse("2025-02-15 10:00:00"))
|
||||||
|
|
||||||
result = MoodCalendarService.generate_calendar(
|
result = MoodCalendarService.generate_calendar(
|
||||||
user,
|
Mood.all,
|
||||||
start_date: Date.parse("2025-04-01"),
|
start_date: Date.parse("2025-04-01"),
|
||||||
end_date: Date.parse("2025-04-30")
|
end_date: Date.parse("2025-04-30")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Devrait contenir avril
|
||||||
expect(result.first[:month]).to eq(Date.parse("2025-04-01"))
|
expect(result.first[:month]).to eq(Date.parse("2025-04-01"))
|
||||||
|
|
||||||
|
# Tous les jours devraient avoir mode: nil et guess: "heureux"
|
||||||
all_days = result.first[:weeks].flatten
|
all_days = result.first[:weeks].flatten
|
||||||
expect(all_days.all? { |d| d[:mode].nil? }).to be true
|
expect(all_days.all? { |d| d[:mode].nil? }).to be true
|
||||||
|
expect(all_days.all? { |d| d[:guess] == "heureux" }).to be true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'avec plusieurs mois' do
|
context 'avec plusieurs mois' do
|
||||||
it 'chaque mois commence et finit correctement' do
|
it 'chaque mois commence et finit correctement' do
|
||||||
mode2 = create(:mode, user: user)
|
create(:mood, mode: "heureux", recorded_at: Time.zone.parse("2025-02-15 10:00:00"))
|
||||||
create(:mood, user: user, mode: mode, recorded_at: Time.zone.parse("2025-02-15 10:00:00"))
|
create(:mood, mode: "calme", recorded_at: Time.zone.parse("2025-03-20 10:00:00"))
|
||||||
create(:mood, user: user, mode: mode2, recorded_at: Time.zone.parse("2025-03-20 10:00:00"))
|
|
||||||
|
|
||||||
result = MoodCalendarService.generate_calendar(
|
result = MoodCalendarService.generate_calendar(
|
||||||
user,
|
Mood.all,
|
||||||
end_date: Date.parse("2025-03-31")
|
end_date: Date.parse("2025-03-31")
|
||||||
)
|
)
|
||||||
|
|
||||||
february = result.find { |m| m[:month] == Date.parse("2025-02-01") }
|
february = result.find { |m| m[:month] == Date.parse("2025-02-01") }
|
||||||
march = result.find { |m| m[:month] == Date.parse("2025-03-01") }
|
march = result.find { |m| m[:month] == Date.parse("2025-03-01") }
|
||||||
|
|
||||||
|
# Février se termine le dimanche 2 mars
|
||||||
last_day_february = february[:weeks].flatten.last
|
last_day_february = february[:weeks].flatten.last
|
||||||
expect(last_day_february[:recorded_at].to_date).to eq(Date.parse("2025-03-02"))
|
expect(last_day_february[:recorded_at].to_date).to eq(Date.parse("2025-03-02"))
|
||||||
|
|
||||||
|
# Mars commence le lundi 3 mars
|
||||||
first_day_march = march[:weeks].flatten.first
|
first_day_march = march[:weeks].flatten.first
|
||||||
expect(first_day_march[:recorded_at].to_date).to eq(Date.parse("2025-03-03"))
|
expect(first_day_march[:recorded_at].to_date).to eq(Date.parse("2025-03-03"))
|
||||||
|
|
||||||
|
# Pas de chevauchement
|
||||||
expect(last_day_february[:recorded_at].to_date + 1.day).to eq(first_day_march[:recorded_at].to_date)
|
expect(last_day_february[:recorded_at].to_date + 1.day).to eq(first_day_march[:recorded_at].to_date)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'avec un scope spécifique' do
|
context 'avec un scope spécifique' do
|
||||||
it 'fonctionne avec des moods filtrés par user' do
|
it 'fonctionne avec des moods filtrés par user' do
|
||||||
|
user1 = create(:user)
|
||||||
user2 = create(:user)
|
user2 = create(:user)
|
||||||
mode2 = create(:mode, user: user2)
|
|
||||||
create(:mood, user: user, mode: mode, recorded_at: Time.zone.parse("2025-02-15 10:00:00"))
|
|
||||||
create(:mood, user: user2, mode: mode2, recorded_at: Time.zone.parse("2025-02-16 10:00:00"))
|
|
||||||
|
|
||||||
|
create(:mood, mode: "heureux", recorded_at: Time.zone.parse("2025-02-15 10:00:00"), user: user1)
|
||||||
|
create(:mood, mode: "triste", recorded_at: Time.zone.parse("2025-02-16 10:00:00"), user: user2)
|
||||||
|
|
||||||
|
moods = Mood.where(user: user1)
|
||||||
result = MoodCalendarService.generate_calendar(
|
result = MoodCalendarService.generate_calendar(
|
||||||
user,
|
moods,
|
||||||
end_date: Date.parse("2025-02-28")
|
end_date: Date.parse("2025-02-28")
|
||||||
)
|
)
|
||||||
|
|
||||||
all_days = result[0][:weeks].flatten
|
all_days = result[0][:weeks].flatten
|
||||||
mood_15 = all_days.find { |m| m[:recorded_at].to_date == Date.parse("2025-02-15") }
|
mood_15 = all_days.find { |m| m[:recorded_at].to_date == Date.parse("2025-02-15") }
|
||||||
expect(mood_15[:mode]).to eq(mode)
|
expect(mood_15[:mode]).to eq("heureux")
|
||||||
|
|
||||||
|
# Le mood du user2 ne devrait pas apparaître
|
||||||
mood_16 = all_days.find { |m| m[:recorded_at].to_date == Date.parse("2025-02-16") }
|
mood_16 = all_days.find { |m| m[:recorded_at].to_date == Date.parse("2025-02-16") }
|
||||||
expect(mood_16[:mode]).to be_nil
|
expect(mood_16[:mode]).to be_nil
|
||||||
expect(mood_16[:guess]).to eq(mode)
|
expect(mood_16[:guess]).to eq("heureux")
|
||||||
end
|
|
||||||
end
|
|
||||||
context 'avec day_log' do
|
|
||||||
it 'inclut le day_log dans les données du jour correspondant' do
|
|
||||||
create(:mood, user: user, mode: mode, recorded_at: Time.zone.parse("2025-02-15 10:00:00"))
|
|
||||||
day_log = create(:day_log, user: user, day: Date.parse("2025-02-15"), info: "Une belle journée")
|
|
||||||
|
|
||||||
result = MoodCalendarService.generate_calendar(user, end_date: Date.parse("2025-02-28"))
|
|
||||||
|
|
||||||
all_days = result.find { |m| m[:month] == Date.parse("2025-02-01") }[:weeks].flatten
|
|
||||||
day_15 = all_days.find { |m| m[:recorded_at].to_date == Date.parse("2025-02-15") }
|
|
||||||
expect(day_15[:day_log]).to eq(day_log)
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'retourne nil pour day_log quand il n\'en existe pas pour ce jour' do
|
|
||||||
create(:mood, user: user, mode: mode, recorded_at: Time.zone.parse("2025-02-15 10:00:00"))
|
|
||||||
|
|
||||||
result = MoodCalendarService.generate_calendar(user, end_date: Date.parse("2025-02-28"))
|
|
||||||
|
|
||||||
all_days = result.find { |m| m[:month] == Date.parse("2025-02-01") }[:weeks].flatten
|
|
||||||
day_15 = all_days.find { |m| m[:recorded_at].to_date == Date.parse("2025-02-15") }
|
|
||||||
expect(day_15[:day_log]).to be_nil
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'inclut le day_log pour un jour sans mood' do
|
|
||||||
create(:mood, user: user, mode: mode, recorded_at: Time.zone.parse("2025-02-15 10:00:00"))
|
|
||||||
day_log = create(:day_log, user: user, day: Date.parse("2025-02-16"), info: "Jour sans mood")
|
|
||||||
|
|
||||||
result = MoodCalendarService.generate_calendar(user, end_date: Date.parse("2025-02-28"))
|
|
||||||
|
|
||||||
all_days = result.find { |m| m[:month] == Date.parse("2025-02-01") }[:weeks].flatten
|
|
||||||
day_16 = all_days.find { |m| m[:recorded_at].to_date == Date.parse("2025-02-16") }
|
|
||||||
expect(day_16[:mode]).to be_nil
|
|
||||||
expect(day_16[:day_log]).to eq(day_log)
|
|
||||||
end
|
|
||||||
it 'inclut le day_log pour un jour avec mood' do
|
|
||||||
create(:mood, user: user, mode: mode, recorded_at: Time.zone.parse("2025-02-15 10:00:00"))
|
|
||||||
day_log = create(:day_log, user: user, day: Date.parse("2025-02-15"), info: "Jour avec mood")
|
|
||||||
|
|
||||||
result = MoodCalendarService.generate_calendar(user, end_date: Date.parse("2025-02-28"))
|
|
||||||
|
|
||||||
all_days = result.find { |m| m[:month] == Date.parse("2025-02-01") }[:weeks].flatten
|
|
||||||
day_15 = all_days.find { |m| m[:recorded_at].to_date == Date.parse("2025-02-15") }
|
|
||||||
expect(day_15[:mode]).to eq(mode)
|
|
||||||
expect(day_15[:day_log]).to eq(day_log)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -1,12 +0,0 @@
|
||||||
module AuthenticationHelper
|
|
||||||
def login_as(user)
|
|
||||||
post session_path, params: {
|
|
||||||
email_address: user.email_address,
|
|
||||||
password: user.password
|
|
||||||
}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
RSpec.configure do |config|
|
|
||||||
config.include AuthenticationHelper, type: :request
|
|
||||||
end
|
|
||||||
Loading…
Add table
Reference in a new issue