updated lot of features

This commit is contained in:
rulingcom 2024-07-11 15:42:16 +08:00
parent 4d02ff8729
commit 7080cf7d4d
12 changed files with 420 additions and 211 deletions

View File

@ -104,8 +104,7 @@ window.getDateString = function(date, format,is_chinese) {
}
return formattedDate;
};
var Calendar = function(dom,property_id,currentView,display_hire_event){
var Calendar = function(dom, property_id, valid_range, currentView, display_hire_event){
var c = this;
display_hire_event = (display_hire_event == undefined ? true : display_hire_event);
this.title = $("#current_title");
@ -136,6 +135,7 @@ var Calendar = function(dom,property_id,currentView,display_hire_event){
editable: false,
selectable: true,
width: "100%",
validRange: valid_range,
events: function(args, success_callback, fail_callback) {
var start = args.start;
var end = args.end;
@ -276,6 +276,10 @@ var Calendar = function(dom,property_id,currentView,display_hire_event){
if(c.currentView == "agenda"){toggleViews("agenda");loadeventsonviewchange = true;}
};
this.destroy = function () {
c.calendar_dom.fullCalendar("destroy");
}
this.renderEvent = function(eventStick){
if(eventStick.recurring === true)
c.calendar_dom.calendar.refetchEvents();

View File

@ -22,6 +22,12 @@ class PropertyHiresController < ApplicationController
{
"properties" => data,
"headers" => headers,
"extras" => {
"first_property_id" => data.first["id"]
},
"manage_booking_btn" => (OrbitHelper.current_user.nil? ? false : true),
"manage_booking" => t("property_hire.manage_booking"),
"manage_booking_url" => "/" + OrbitHelper.get_site_locale.to_s + "/admin/property_hires/my_bookings",
"total_pages" => (properties.total_pages rescue 1)
}
end
@ -29,32 +35,31 @@ class PropertyHiresController < ApplicationController
def index_data(properties, url)
data = properties.collect do |property|
actions = []
url_to_show = "#{url}/#{property.to_param}"
url_to_show = "#{url}/#{property.to_param}?method=hire"
hire_url = nil
if property.can_be_hired_frontend
hire_url = url_to_show + "?method=hire"
if property.can_be_hired_frontend && property.can_reserve
hire_url = url_to_show
actions << {
"text" => t("property_hire.hire"),
"btn-class" => "btn-primary",
"link" => hire_url
}
end
if !property.disable_view_calendar_page && property.can_be_show_frontend
if !property.disable_view_calendar_page && property.can_be_show_frontend && property.can_reserve
actions << {
"text" => t("property_hire.view_calendar"),
"btn-class" => "btn-info",
"link" => url_to_show + "?method=view_calendar"
"link" => url_to_show
}
end
if property.disable_content_page
if hire_url
url_to_show = hire_url
elsif !property.disable_view_calendar_page && property.can_be_show_frontend
url_to_show += "?method=view_calendar"
end
end
{
"title" => property.title,
"id" => property.id.to_s,
"image" => (property.image.url.blank? ? '" style="display: none;' : property.image.url),
"image-thumb" => (property.image.thumb.url.blank? ? '" style="display: none;' : property.image.thumb.url),
"url_to_show" => url_to_show,
@ -65,7 +70,7 @@ class PropertyHiresController < ApplicationController
end
def widget
properties = Property.filter_by_widget_categories.sort_order
properties = Property.filter_by_widget_categories.sort_order.can_display
url = OrbitHelper.get_current_widget.get_read_more_page_url
data = index_data(properties, url)
headers = [
@ -357,8 +362,11 @@ class PropertyHiresController < ApplicationController
events = events.map{|e| e.as_json}
allevents = events.inject(re, :<<)
allevents = allevents.sort_by{|e| e[:start]}
Rails.logger.info allevents
@need_check_events = allevents.map{|e| [e[:date],e[:s_id]]}
if property.set_availability && params[:display_hire_event]
@special_unavailable_dates = property.special_unavailable_dates.map{|dt| Date.parse(dt)}
if property.set_availability && params[:display_hire_event] == "true"
check_setting = property.set_unavailibility && (property.property_day_settings.where(:enable=>false).count != 0)
@check_start_time = property.start_time.blank? ? "00:00" : property.start_time
@check_end_time = property.end_time.blank? ? "24:00" : property.end_time
@ -379,8 +387,14 @@ class PropertyHiresController < ApplicationController
get_end_time = [time_now + (property.can_hire_before_months).send("month"),edt].min
end
end
if property.can_reserve
allevents += generate_all_reserve_buttons(get_start_time,get_end_time,all_day_settings,check_setting)
end
end
end
if @special_unavailable_dates.count > 0
allevents += special_unavailable_dates_labels(property)
end
end
end
@ -389,8 +403,20 @@ class PropertyHiresController < ApplicationController
format.json { render json: allevents.to_json }
end
end
def special_unavailable_dates_labels(property)
events = []
@special_unavailable_dates.each_with_index do |dt, idx|
events << {:title=>property.special_unavailable_dates_title[idx][OrbitHelper.get_site_locale], :start=>dt.to_s, :end => (dt + 1.day).to_s, :allDay => true, :color => "#d33535", :classNames=>["special_unavailable_btn"], :note => ""}
end
events
end
def reserve_calendar_event(date,title,allow_times)
available = true
if @special_unavailable_dates.include?(date)
available = false
end
if @check_setting && allow_times.select{|a| !a[5]}.count != 0
available = (date > @check_end_date rescue false) || (date < @check_start_date rescue false)
unless available
@ -556,8 +582,3 @@ class PropertyHiresController < ApplicationController
end
end

View File

@ -53,9 +53,11 @@ class PHire
if options[:recurring]
recurring = options[:recurring]
end
title = startt.strftime("%H:%M") + " ~ " + endt.strftime("%H:%M") + " " + self.hiring_person_name
{
:id => self.id.to_s,
:title => (self.reason_for_hire.to_s + " "+ self.tmp_reason_for_hire.to_s).html_safe,
# :title => (self.reason_for_hire.to_s + " "+ self.tmp_reason_for_hire.to_s).html_safe,
:title => title,
:hiring_person_id => self.hiring_person_id,
:hiring_person_name => self.hiring_person_name,
:note => self.note_for_hire || "",

View File

@ -26,6 +26,11 @@ class Property
field :owner_phone
field :price
field :other_location
field :p_hire_start_time, type: DateTime
field :p_hire_end_time, type: DateTime
field :p_open_start_time, type: DateTime
field :p_open_end_time, type: DateTime
field :recurring_enable, type: Boolean, :default => false
mount_uploader :image, ImageUploader
@ -36,6 +41,8 @@ class Property
field :start_time
field :end_time
field :weekdays, type: Array, default: []
field :special_unavailable_dates, type: Array, default: []
field :special_unavailable_dates_title, type: Array, default: []
field :start_date, type: DateTime
field :end_date, type: DateTime
field :description, :localize => true
@ -77,7 +84,8 @@ class Property
accepts_nested_attributes_for :property_files, :allow_destroy => true
has_many :property_links, :autosave => true, :dependent => :destroy
accepts_nested_attributes_for :property_links, :allow_destroy => true
scope :sort_order, ->{order_by([:order_position,:asc],[:created_at,:desc])}
scope :sort_order, ->{order_by([:created_at,:desc],[:order_position,:asc])}
scope :can_display, ->{any_of({:p_hire_start_time.lt=>Time.now, :p_hire_end_time.gt=>Time.now},{:p_hire_start_time.lt=>Time.now, :p_hire_end_time=>nil},{:p_hire_start_time=>nil, :p_hire_end_time=>nil})}
WEEKDAYS = [
"Sunday",
"Monday",
@ -133,6 +141,13 @@ class Property
after_save do
self.change_day_setting_status
end
def can_reserve
start_time = self.p_hire_start_time || Time.now
end_time = self.p_hire_end_time || Time.now
return Time.now >= start_time && end_time >= Time.now
end
def p_hire_fields_enabled
self.p_hire_fields.where(disabled: false)
end
@ -255,6 +270,9 @@ class Property
message += hint1
end
end
if property.special_unavailable_dates.count > 1
message += " And on " + property.special_unavailable_dates.join(", ")
end
if property.need_hire_before != 0
if message != ""
message += "<br>"
@ -291,6 +309,13 @@ class Property
if self.need_hire_before != 0
return 3 if (time_now + (self.need_hire_before).send(self.need_hire_before_unit) > stime)
end
self.special_unavailable_dates.each do |dt|
unavailable_date = Date.parse(dt)
cd = (stime..etime) & (unavailable_date..unavailable_date)
if !cd.nil?
return 0
end
end
startt = self.start_date.nil? ? stime : self.start_date
endt = self.end_date.nil? ? etime : self.end_date
available = 1 if (startt > stime && endt > etime)

View File

@ -132,9 +132,35 @@
</div>
</div>
<div class="control-group">
<%= f.label :can_be_hired, t("property_hire.can_be_hired"), :class => "control-label muted" %>
<%= f.label :p_hire_start_time, t("property_hire.p_hire_start_time"), :class => "control-label muted" %>
<div class="controls">
<%= f.check_box :can_be_hired %>
<%= f.datetime_picker :p_hire_start_time, :picker_type => "date", :no_label => true, :new_record => @property.new_record?, :data=>{"picker-type" => "range", "range" => "start"}, :format => "yyyy/MM/dd hh:mm" %>
</div>
</div>
<div class="control-group">
<%= f.label :p_hire_end_time, t("property_hire.p_hire_end_time"), :class => "control-label muted" %>
<div class="controls">
<%= f.datetime_picker :p_hire_end_time, :picker_type => "date", :no_label => true, :new_record => @property.new_record?, :data=>{"picker-type" => "range", "range" => "end"}, :format => "yyyy/MM/dd hh:mm" %>
</div>
</div>
<div class="control-group">
<%= f.label :recurring_enable, t("property_hire.recurring_enable"), :class => "control-label muted" %>
<div class="controls">
<%= f.check_box :recurring_enable %>
</div>
</div>
<div id="open-time" >
<div class="control-group">
<%= f.label :p_open_start_time, t("property_hire.p_open_start_time"), :class => "control-label muted" %>
<div class="controls">
<%= f.datetime_picker :p_open_start_time, :picker_type => "date", :no_label => true, :new_record => @property.new_record?, :data=>{"picker-type" => "range", "range" => "start"}, :format => "yyyy/MM/dd" %>
</div>
</div>
<div class="control-group">
<%= f.label :p_open_end_time, t("property_hire.p_open_end_time"), :class => "control-label muted" %>
<div class="controls">
<%= f.datetime_picker :p_open_end_time, :picker_type => "date", :no_label => true, :new_record => @property.new_record?, :data=>{"picker-type" => "range", "range" => "end"}, :format => "yyyy/MM/dd" %>
</div>
</div>
</div>
<div class="control-group">
@ -371,6 +397,35 @@
<% end %>
</div>
</div>
<div class="control-group">
<label class="control-label muted"><%=t("property_hire.special_unavailable_date")%></label>
<div class="controls" id="special_unavailable_date_holder">
<% @property.special_unavailable_dates.each_with_index do |dt, idx| %>
<div class="temp_date_holder" style="margin-bottom:5px;">
<div class="date_picker input-append" style="margin-bottom:3px;">
<input placeholder="yyyy/MM/dd" class="input-large" data-format="yyyy/MM/dd" type="text" name="property[special_unavailable_dates][]" title="yyyy/MM/dd" autocomplete="off" value="<%= dt %>">
<span class="add-on clearDate"><i class="icons-cross-3"></i></span>
<span class="add-on deleteDate"><i class="icon-trash"></i></span>
</div>
<div class="tab-panel">
<div class="tab-content active" id="special_unavailable_title_<%= idx %>_en">
<input type="text" name="property[special_unavailable_dates_title][][en]" value="<%= @property.special_unavailable_dates_title[idx]["en"] %>">
</div>
<div class="tab-content" id="special_unavailable_title_<%= idx %>_zh_tw">
<input type="text" name="property[special_unavailable_dates_title][][zh_tw]" value="<%= @property.special_unavailable_dates_title[idx]["zh_tw"] %>">
</div>
<div class="btn-group" data-toggle="buttons-radio">
<a data-toggle="tab" class="btn active" for="en" href="#special_unavailable_title_<%= idx %>_en" aria-expanded="true" aria-pressed="true"><%= t("en") %></a>
<a data-toggle="tab" class="btn" for="zh_tw" href="#special_unavailable_title_<%= idx %>_zh_tw" aria-expanded="true" aria-pressed="true"><%= t("zh_tw") %></a>
</div>
</div>
</div>
<% end %>
</div>
<div class="controls">
<button class="primary" id="add_special_unavailable_date">Add</button>
</div>
</div>
<div class="control-group">
<%= f.label :start_date, t("property_hire.start_date"), :class => "control-label muted" %>
<div class="controls">
@ -900,6 +955,55 @@
$(this).parents('.image_group').remove();
}
});
// $(document).on("click", "#property_can_be_hired", function () {
// if($(this).is(":checked")){
// $("#open-time").attr("class","show");
// }else{
// $("#open-time").attr("class","hide");
// $("#open-time").find("input").val("");
// }
// })
var special_unavailable_title_counter = <%= @property.special_unavailable_dates.count %>;
$(document).on("click","#add_special_unavailable_date", function(){
var datepicker = $('<div class="date_picker input-append" style="margin-bottom:3px;"> \
<input placeholder="yyyy/MM/dd" class="input-large" data-format="yyyy/MM/dd" type="text" name="property[special_unavailable_dates][]" title="yyyy/MM/dd" autocomplete="off"> \
<span class="add-on clearDate"><i class="icons-cross-3"></i></span> \
<span class="add-on deleteDate"><i class="icon-trash"></i></span> \
</div>');
var id = "special_unavailable_title_" + special_unavailable_title_counter;
var title = $('<div class="tab-panel"> \
<div class="tab-content active" id="' + id + '_en"> \
<input type="text" name="property[special_unavailable_dates_title][][en]" value=""> \
</div> \
<div class="tab-content" id="' + id + '_zh_tw"> \
<input type="text" name="property[special_unavailable_dates_title][][zh_tw]" value=""> \
</div> \
<div class="btn-group" data-toggle="buttons-radio"> \
<a data-toggle="tab" class="btn active" for="en" href="#' + id + '_en" aria-expanded="true" aria-pressed="true"><%= t("en") %></a> \
<a data-toggle="tab" class="btn" for="zh_tw" href="#' + id + '_zh_tw" aria-expanded="true" aria-pressed="true"><%= t("zh_tw") %></a> \
</div> \
</div>');
datepicker.find('input').datepicker({
dateFormat : "yy/mm/dd"
});
var html = $('<div class="temp_date_holder" style="margin-bottom:5px;"></div>');
html.append(datepicker);
html.append(title);
$("#special_unavailable_date_holder").append(html);
special_unavailable_title_counter++;
return false;
})
$(document).on("click","#special_unavailable_date_holder .clearDate", function (params) {
$(this).parents('.default_picker,.time_picker,.date_picker').eq(-1).find('input').val('')
$(this).parents('.default_picker,.time_picker,.date_picker').eq(-1).find('input').trigger('change')
})
$(document).on("click","#special_unavailable_date_holder .deleteDate", function (params) {
$(this).parents('#special_unavailable_date_holder .temp_date_holder').eq(-1).remove();
})
</script>

View File

@ -32,7 +32,7 @@
<%= property.get_location_name %>
</td>
<td>
<% if property.can_be_hired %>
<% if property.can_reserve %>
<span class="badge badge-success">Yes</span>
<% else %>
<span class="badge badge-important">No</span>

View File

@ -33,7 +33,11 @@
<% end %>
</td>
<td>
<%
=begin%>
<a href="<%= show_booking_details_admin_property_hire_path(p_hire, :page => params[:page]) %>" class="btn btn-info">View</a>
<%
=end%>
<a href="<%= delete_booking_details_admin_property_hire_path(p_hire, :page => params[:page]) %>" class="btn btn-danger" data-method="delete" data-confirm="Are you sure?">Delete</a>
</td>
</tr>

View File

@ -23,6 +23,7 @@
input_col -= 2
end
%>
<style type="text/css">
.full-size-img img {
width: 100%;
@ -171,7 +172,7 @@
margin-left: 0;
}
</style>
<% if !property.can_be_hired_frontend %>
<% if !property.can_be_hired %>
<script type="text/javascript">
alert("This property is unavailable for hire.");
window.location.href = "<%= "/" + I18n.locale.to_s + url %>";
@ -319,7 +320,14 @@
<div id="event_quick_view" class="modal" style="width: 300px; display:none; margin:0 0 0 0;"></div>
<script type="text/javascript">
var property_id = "<%= property.id.to_s %>";
var calendar = new Calendar("#calendar",property_id);
var valid_range = {}
<% if property.p_open_start_time %>
valid_range["start"] = "<%= property.p_open_start_time.strftime("%Y-%m-%d") %>"
<% end %>
<% if property.p_open_end_time %>
valid_range["end"] = "<%= (property.p_open_end_time + 1.day).strftime("%Y-%m-%d") %>"
<% end %>
var calendar = new Calendar("#calendar", property_id, valid_range);
function pick_hire_date(date,allow_times){
if(window.processing_hire)
return;
@ -443,7 +451,8 @@
</script>
<% end %>
<div class="col-lg-<%=right_col%>">
<%= form_for hire, :url => "/xhr/property_hires/make_booking", html: { class: "form-horizontal", id: "hire_form" } do |f| %>
<% if property.can_reserve === true %>
<%= form_for hire, :url => "/xhr/property_hires/make_booking", html: { class: "form-horizontal", id: "hire_form" } do |f| %>
<% if property.set_availability %>
<div class="form-group">
<%= f.label :date, "*"+t("property_hire.date"), :class => "col-sm-#{label_col} control-label" %>
@ -475,7 +484,7 @@
<%= f.label :start_time, "*"+t("property_hire.start_time"), :class => "col-sm-#{label_col} control-label" %>
<% if property.calendar_type == 0 %>
<div class="col-sm-<%=input_col%>">
<%= f.datetime_picker :start_time, :no_label => true, :new_record => hire.new_record? && !recover,:class => "pull-left", :data=>{"picker-type" => "range", "range" => "start","fv-validation" => "required;", "fv-messages" => "Cannot be empty;"} %>
<%= f.datetime_picker :start_time, :no_label => true, :new_record => hire.new_record? && !recover, :class => "pull-left", :data=>{"picker-type" => "range", "range" => "start", "fv-validation" => "required;", "fv-messages" => "Cannot be empty;"} %>
<button type="button" id="pick_start_date" onclick="change_pick(this)" class="btn btn-primary btn-sm pull-left" style="margin-left: 1em;"><%=t("property_hire.pick_from_calendar")%></button>
</div>
<% end %>
@ -488,6 +497,7 @@
</div>
</div>
<% end %>
<% if property.recurring_enable %>
<!-- ############# recurring ############# -->
<div class="form-group">
<%= f.label :recurring, t("property_hire.recurring"), :class => "col-sm-#{label_col} control-label" %>
@ -513,7 +523,7 @@
</div>
</div>
</div>
<% end %>
<div class="form-group">
<div class="col-sm-offset-<%=label_col%> col-sm-<%=input_col%>">
<div id="property-avaialable-alert" style="margin-bottom: 5px; padding: 10px;<%= 'display: none;' unless recover %>" class="alert alert-success" role="alert"><%=t("property_hire.this_property_is_available",:default=>"<b>Hooray! </b>This property is available.").html_safe%></div>
@ -616,6 +626,7 @@
<input type="hidden" id="dates_validated" name="dates_validated" value="<%=recover ? 1 : 0 %>" data-fv-validation="checkForDates;" data-fv-messages="Please make sure first if dates are available.;">
</div>
</div>
<% end %>
<% end %>
</div>
<div class="clearfix"></div>
@ -627,6 +638,7 @@
if(timezone[0] != "-"){
timezone = "+" + timezone;
}
$("#p_hire_date").on("change",function(){
var _this = $(this);
var date = new Date(_this.val());
@ -783,4 +795,18 @@
}
})
</script>
<script>
$(document).ready(function(){
<% if property.p_hire_start_time %>
$("#p_hire_start_time").datepicker('option', 'minDate', new Date("<%= property.p_open_start_time.strftime("%Y-%m-%d") %>"));
$("#p_hire_end_time").datepicker('option', 'minDate', new Date("<%= property.p_open_start_time.strftime("%Y-%m-%d") %>"));
$("#p_hire_recurring_end_date").datepicker('option', 'minDate', new Date("<%= property.p_open_start_time.strftime("%Y-%m-%d") %>"));
<% end %>
<% if property.p_hire_end_time %>
$("#p_hire_start_time").datepicker('option', 'maxDate', new Date("<%= property.p_open_end_time.strftime("%Y-%m-%d") %>"));
$("#p_hire_end_time").datepicker('option', 'maxDate', new Date("<%= property.p_open_end_time.strftime("%Y-%m-%d") %>"));
$("#p_hire_recurring_end_date").datepicker('option', 'maxDate', new Date("<%= property.p_open_end_time.strftime("%Y-%m-%d") %>"));
<% end %>
})
</script>
<% end %>

View File

@ -1 +1,10 @@
<% OrbitHelper.render_css_in_head(["property_hire_fullcalendar.css","property_hire_calendar"]) %>
<script type="text/javascript" src="/assets/property_hire_fullcalendar.min.js"></script>
<script type="text/javascript" src="/assets/property_hire_calendar_frontend.js"></script>
<% data = action_data %>
<% if data["manage_booking_btn"] %>
<div class="pull-right">
<a href="<%= data["manage_booking_url"] %>" class="btn btn-primary" target="_blank"><%= data["manage_booking"] %>
</div>
<% end %>
<%= render_view %>

View File

@ -137,6 +137,10 @@ en:
set_unavailibility: Set Unavailability
limit_start_time: Limit start time
limit_end_time: Limit end time
p_hire_start_time: Start Date
p_hire_end_time: End Date
p_open_start_time: Open Date
p_open_end_time: Close Date
start_time: Start Time
end_time: End Time
weekdays: Unavailable days in a week
@ -175,3 +179,6 @@ en:
mobile_phone_of_contact_person: Mobile phone of contact person
contact_person_Email: Contact person Email
contact_person_department: Contact person department
special_unavailable_date: Special Unavailable Date
manage_booking: Manage Bookings
recurring_enable: Enable Recurring

View File

@ -164,6 +164,10 @@ zh_tw:
weekdays: 每週不開放預約日
start_date: 套用限制開始日期
end_date: 套用限制結束日期
p_hire_start_time: 上架日期
p_hire_end_time: 下架日期
p_open_start_time: 開放日期
p_open_end_time: 截止日期
description: Unavailability Description
unavailibility_note: Unavailability Note
property_location: Property Location
@ -197,3 +201,6 @@ zh_tw:
mobile_phone_of_contact_person: 聯絡人行動電話
contact_person_Email: 聯絡Email
contact_person_department: 聯絡人服務單位
special_unavailable_date: 特定不開放預約⽇
manage_booking: 管理我的預約
recurring_enable: 啟用週期性預約