Refactor appointment model and views to use a single date field; update tooltip and calendar display for improved functionality

This commit is contained in:
ricky committed 2026-08-07 21:20:46 -04:00
1 parent 88a40b356c
commit 86533981bc
8 files changed
+66 -76

No files matched your search

@@ -41,8 +41,7 @@ class CustomerAppointmentsController < ApplicationController
def new
@appointment = CustomerAppointment.new
@appointment.project = @project
@appointment.start_date = (params[:start_date].to_date + 9.hours) if params[:start_date].present?
@appointment.end_date = @appointment.start_date + 1.hour if @appointment.start_date.present?
@appointment.date = (params[:start_date].to_date + 9.hours) if params[:start_date].present?
end
def create
@@ -89,8 +88,7 @@ class CustomerAppointmentsController < ApplicationController
:description,
:status,
:user_id,
:start_date,
:end_date,
:date,
:estimated_hours,
:estimate_id,
:duration
+9 -13
View File
@@ -17,8 +17,7 @@ class CustomerAppointment < ActiveRecord::Base
belongs_to :estimate, optional: true
validates :subject, presence: true
validates :start_date, presence: true
validate :date_order
validates :date, presence: true
STATUSES = %w[
Scheduled
@@ -29,9 +28,15 @@ class CustomerAppointment < ActiveRecord::Base
Cancelled
]
# Cast datetime to Date for Redmine Calendar compatibility
def start_date
date&.to_date
end
def due_date
return end_date&.to_date if end_date.present?
return start_date&.to_date
return nil unless date
# Accounts for multi-day duration spanning across dates
start_date + ([duration.to_i, 1].max - 1).days
end
def self.visible(user)
@@ -40,15 +45,6 @@ class CustomerAppointment < ActiveRecord::Base
private
def date_order
return if end_date.blank?
return if start_date.blank?
if end_date < start_date
errors.add( :end_date, "cannot be before start date")
end
end
def log(msg)
Rails.logger.info "[Event] #{msg}"
end
@@ -24,10 +24,9 @@
<%= f.collection_select :user_id, User.active.sorted, :id, :name, { include_blank: true }, { label: false } %>
</p>
<p><%= f.datetime_local_field :start_date %></p>
<p><%= f.date_field :end_date, size: 10 %></p>
<p><%= f.datetime_local_field :date %></p>
<p><%= f.number_field :estimated_hours, step: 0.1, size: 6 %></p>
<p><%= f.number_field :estimated_hours, step: 1, size: 6 %></p>
<p><%= f.number_field :duration, step: 1, size: 6, label: :label_duration %></p>
<p><%= f.select :status, CustomerAppointment::STATUSES, label: :field_status %></p>
@@ -57,7 +57,7 @@
<tr>
<th><%= l(:label_end_date) %></th>
<td><%= format_date(appointment.end_date || appointment.start_date) %></td>
<td><%= format_date(appointment.due_date ) %></td>
</tr>
<tr>
+2 -47
View File
@@ -15,57 +15,12 @@
<span class="appointment-dates">
(<%= format_date(@appointment.start_date) %>
<% if @appointment.end_date && @appointment.start_date != @appointment.end_date %>
- <%= format_date(@appointment.end_date) %>
<% if @appointment.duration > 1 %>
- <%= format_date(@appointment.due_date) %>
<% end %>)
</span>
</h2>
<style>
.calendar-badge {
display: inline-block;
width: 38px;
border: 1px solid #b8c0c8;
border-radius: 4px;
overflow: hidden;
text-align: center;
vertical-align: middle;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
margin-right: 8px;
line-height: 1;
background: #fff;
}
.calendar-badge .month {
background-color: #c22b2b; /* Redmine primary red tone */
color: #ffffff;
font-size: 9px;
font-weight: bold;
padding: 3px 0 2px 0;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.calendar-badge .day {
color: #333333;
font-size: 16px;
font-weight: bold;
padding: 4px 0 3px 0;
}
.appointment-title {
vertical-align: middle;
}
.appointment-dates {
font-size: 70%;
color: #666;
margin-left: 8px;
font-weight: normal;
vertical-align: middle;
}
</style>
<div class="issue details">
<div class="attributes">
<div class="splitcontent">
File renamed without changes.
+48 -5
View File
@@ -23,8 +23,8 @@ table.cal td {
background: #edf4ff;
border: 1px solid #c5d8f3;
border-radius: 3px;
font-size: 10px;
line-height: 1.2;
font-size: 0.9em; /* Matches Redmine calendar default text size */
line-height: 1.3;
overflow: visible !important; /* Allows tooltip popover to extend outside */
width: 100%;
max-width: 100%;
@@ -100,7 +100,7 @@ table.cal td {
.appointment-hours {
flex-shrink: 0;
color: #444;
font-size: 9px;
font-size: 0.85em; /* Slightly smaller than main text to keep layout balanced */
font-weight: bold;
margin-left: auto;
}
@@ -108,11 +108,11 @@ table.cal td {
/* Option B: Multi-line wrapping for details */
.appointment-detail {
color: #555;
font-size: 9px;
font-size: 0.9em; /* Matches calendar item body text */
white-space: normal;
overflow-wrap: anywhere;
word-break: break-word;
margin-top: 1px;
margin-top: 2px;
min-width: 0;
}
@@ -203,4 +203,47 @@ table.cal td {
.appointment-block .tip .buttons {
margin: 0;
text-align: right;
}
.calendar-badge {
display: inline-block;
width: 38px;
border: 1px solid #b8c0c8;
border-radius: 4px;
overflow: hidden;
text-align: center;
vertical-align: middle;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
margin-right: 8px;
line-height: 1;
background: #fff;
}
.calendar-badge .month {
background-color: #c22b2b; /* Redmine primary red tone */
color: #ffffff;
font-size: 9px;
font-weight: bold;
padding: 3px 0 2px 0;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.calendar-badge .day {
color: #333333;
font-size: 16px;
font-weight: bold;
padding: 4px 0 3px 0;
}
.appointment-title {
vertical-align: middle;
}
.appointment-dates {
font-size: 70%;
color: #666;
margin-left: 8px;
font-weight: normal;
vertical-align: middle;
}
@@ -15,8 +15,7 @@ class CreateCustomerAppointments < ActiveRecord::Migration[7.0]
t.text :subject, null: false
t.text :description, null: false
t.datetime :start_date, null: false
t.datetime :end_date
t.datetime :date, null: false
t.integer :duration, default: 1
t.integer :estimated_hours, default: 1
@@ -31,7 +30,7 @@ class CreateCustomerAppointments < ActiveRecord::Migration[7.0]
end
add_index :customer_appointments, :start_date
add_index :customer_appointments, :date
end
end