mirror of
https://github.com/rickbarrette/redmine_qbo_calendar.git
synced 2026-10-03 20:40:43 -04:00
Refactor appointment model and views to use a single date field; update tooltip and calendar display for improved functionality
This commit is contained in:
1 parent
88a40b356c
commit
86533981bc
8 files changed
+66
-76
No files matched your search
@@ -41,8 +41,7 @@ class CustomerAppointmentsController < ApplicationController
|
|||||||
def new
|
def new
|
||||||
@appointment = CustomerAppointment.new
|
@appointment = CustomerAppointment.new
|
||||||
@appointment.project = @project
|
@appointment.project = @project
|
||||||
@appointment.start_date = (params[:start_date].to_date + 9.hours) if params[:start_date].present?
|
@appointment.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?
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def create
|
def create
|
||||||
@@ -89,8 +88,7 @@ class CustomerAppointmentsController < ApplicationController
|
|||||||
:description,
|
:description,
|
||||||
:status,
|
:status,
|
||||||
:user_id,
|
:user_id,
|
||||||
:start_date,
|
:date,
|
||||||
:end_date,
|
|
||||||
:estimated_hours,
|
:estimated_hours,
|
||||||
:estimate_id,
|
:estimate_id,
|
||||||
:duration
|
:duration
|
||||||
|
|||||||
@@ -17,8 +17,7 @@ class CustomerAppointment < ActiveRecord::Base
|
|||||||
belongs_to :estimate, optional: true
|
belongs_to :estimate, optional: true
|
||||||
|
|
||||||
validates :subject, presence: true
|
validates :subject, presence: true
|
||||||
validates :start_date, presence: true
|
validates :date, presence: true
|
||||||
validate :date_order
|
|
||||||
|
|
||||||
STATUSES = %w[
|
STATUSES = %w[
|
||||||
Scheduled
|
Scheduled
|
||||||
@@ -29,9 +28,15 @@ class CustomerAppointment < ActiveRecord::Base
|
|||||||
Cancelled
|
Cancelled
|
||||||
]
|
]
|
||||||
|
|
||||||
|
# Cast datetime to Date for Redmine Calendar compatibility
|
||||||
|
def start_date
|
||||||
|
date&.to_date
|
||||||
|
end
|
||||||
|
|
||||||
def due_date
|
def due_date
|
||||||
return end_date&.to_date if end_date.present?
|
return nil unless date
|
||||||
return start_date&.to_date
|
# Accounts for multi-day duration spanning across dates
|
||||||
|
start_date + ([duration.to_i, 1].max - 1).days
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.visible(user)
|
def self.visible(user)
|
||||||
@@ -40,15 +45,6 @@ class CustomerAppointment < ActiveRecord::Base
|
|||||||
|
|
||||||
private
|
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)
|
def log(msg)
|
||||||
Rails.logger.info "[Event] #{msg}"
|
Rails.logger.info "[Event] #{msg}"
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -24,10 +24,9 @@
|
|||||||
<%= f.collection_select :user_id, User.active.sorted, :id, :name, { include_blank: true }, { label: false } %>
|
<%= f.collection_select :user_id, User.active.sorted, :id, :name, { include_blank: true }, { label: false } %>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p><%= f.datetime_local_field :start_date %></p>
|
<p><%= f.datetime_local_field :date %></p>
|
||||||
<p><%= f.date_field :end_date, size: 10 %></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.number_field :duration, step: 1, size: 6, label: :label_duration %></p>
|
||||||
|
|
||||||
<p><%= f.select :status, CustomerAppointment::STATUSES, label: :field_status %></p>
|
<p><%= f.select :status, CustomerAppointment::STATUSES, label: :field_status %></p>
|
||||||
|
|||||||
@@ -57,7 +57,7 @@
|
|||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
<th><%= l(:label_end_date) %></th>
|
<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>
|
||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
|
|||||||
@@ -15,57 +15,12 @@
|
|||||||
|
|
||||||
<span class="appointment-dates">
|
<span class="appointment-dates">
|
||||||
(<%= format_date(@appointment.start_date) %>
|
(<%= format_date(@appointment.start_date) %>
|
||||||
<% if @appointment.end_date && @appointment.start_date != @appointment.end_date %>
|
<% if @appointment.duration > 1 %>
|
||||||
- <%= format_date(@appointment.end_date) %>
|
- <%= format_date(@appointment.due_date) %>
|
||||||
<% end %>)
|
<% end %>)
|
||||||
</span>
|
</span>
|
||||||
</h2>
|
</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="issue details">
|
||||||
<div class="attributes">
|
<div class="attributes">
|
||||||
<div class="splitcontent">
|
<div class="splitcontent">
|
||||||
|
|||||||
File renamed without changes.
@@ -23,8 +23,8 @@ table.cal td {
|
|||||||
background: #edf4ff;
|
background: #edf4ff;
|
||||||
border: 1px solid #c5d8f3;
|
border: 1px solid #c5d8f3;
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
font-size: 10px;
|
font-size: 0.9em; /* Matches Redmine calendar default text size */
|
||||||
line-height: 1.2;
|
line-height: 1.3;
|
||||||
overflow: visible !important; /* Allows tooltip popover to extend outside */
|
overflow: visible !important; /* Allows tooltip popover to extend outside */
|
||||||
width: 100%;
|
width: 100%;
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
@@ -100,7 +100,7 @@ table.cal td {
|
|||||||
.appointment-hours {
|
.appointment-hours {
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
color: #444;
|
color: #444;
|
||||||
font-size: 9px;
|
font-size: 0.85em; /* Slightly smaller than main text to keep layout balanced */
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
}
|
}
|
||||||
@@ -108,11 +108,11 @@ table.cal td {
|
|||||||
/* Option B: Multi-line wrapping for details */
|
/* Option B: Multi-line wrapping for details */
|
||||||
.appointment-detail {
|
.appointment-detail {
|
||||||
color: #555;
|
color: #555;
|
||||||
font-size: 9px;
|
font-size: 0.9em; /* Matches calendar item body text */
|
||||||
white-space: normal;
|
white-space: normal;
|
||||||
overflow-wrap: anywhere;
|
overflow-wrap: anywhere;
|
||||||
word-break: break-word;
|
word-break: break-word;
|
||||||
margin-top: 1px;
|
margin-top: 2px;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -203,4 +203,47 @@ table.cal td {
|
|||||||
.appointment-block .tip .buttons {
|
.appointment-block .tip .buttons {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
text-align: right;
|
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 :subject, null: false
|
||||||
t.text :description, null: false
|
t.text :description, null: false
|
||||||
|
|
||||||
t.datetime :start_date, null: false
|
t.datetime :date, null: false
|
||||||
t.datetime :end_date
|
|
||||||
t.integer :duration, default: 1
|
t.integer :duration, default: 1
|
||||||
t.integer :estimated_hours, default: 1
|
t.integer :estimated_hours, default: 1
|
||||||
|
|
||||||
@@ -31,7 +30,7 @@ class CreateCustomerAppointments < ActiveRecord::Migration[7.0]
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
add_index :customer_appointments, :start_date
|
add_index :customer_appointments, :date
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
Reference in new issue
Block a user