Update fullcalendar from 1.6.1 to 5.8.0.
Add calendar to backedend show page. Add calendar to frontend hire page. Add error message description when hiring property. Add backend edit hire page.
This commit is contained in:
parent
c9f424b30d
commit
24f93f7630
|
@ -1,8 +1,112 @@
|
|||
var Calendar = function(dom,property_id){
|
||||
window.auto_close_popup = false;
|
||||
$.fn.fullCalendar = function(args){
|
||||
var self = this[0]
|
||||
if(!self.calendar_args)
|
||||
self.calendar_args = args;
|
||||
else
|
||||
args = Object.assign(self.calendar_args, args);
|
||||
var calendar = new FullCalendar.Calendar(self,args);
|
||||
calendar.render();
|
||||
$(window).on("load",function(){
|
||||
calendar.render();
|
||||
})
|
||||
this.calendar = calendar;
|
||||
self.calendar = calendar;
|
||||
$.fullCalendar = calendar;
|
||||
return calendar;
|
||||
};
|
||||
function correct_date(date){
|
||||
var new_date = new Date();
|
||||
new_date.setTime(date.getTime() + date.getTimezoneOffset() * 60 * 1000);
|
||||
return new_date;
|
||||
}
|
||||
FullCalendar.Calendar.prototype.get_all_events = function(){
|
||||
this.currentData.all_events = [];
|
||||
var all_events = this.currentData.all_events;
|
||||
if(this.currentData.eventStore && this.currentData.eventStore.instances){
|
||||
var instances = this.currentData.eventStore.instances;
|
||||
Object.keys(instances).forEach(function(k){
|
||||
var instance = instances[k];
|
||||
var range = Object.assign({},instance.range);
|
||||
range.start = correct_date(range.start);
|
||||
range.end = correct_date(range.end);
|
||||
all_events.push(range);
|
||||
})
|
||||
}
|
||||
return this.currentData.all_events;
|
||||
}
|
||||
FullCalendar.Calendar.prototype.isAnOverlapEvent = function(eventStartDay, eventEndDay){
|
||||
eventStartDay = eventStartDay || eventEndDay;
|
||||
eventEndDay = eventEndDay || eventStartDay;
|
||||
if((typeof(eventStartDay)).toLowerCase() == "string")
|
||||
eventStartDay = new Date(eventStartDay);
|
||||
if((typeof(eventEndDay)).toLowerCase() == "string")
|
||||
eventEndDay = new Date(eventEndDay);
|
||||
var events = this.get_all_events();
|
||||
for (var i = 0; i < events.length; i++) {
|
||||
var eventA = events[i];
|
||||
// start-time in between any of the events
|
||||
if (eventStartDay >= eventA.start && eventStartDay <= eventA.end) {
|
||||
return true;
|
||||
}
|
||||
//end-time in between any of the events
|
||||
if (eventEndDay >= eventA.start && eventEndDay <= eventA.end) {
|
||||
return true;
|
||||
}
|
||||
//any of the events in between/on the start-time and end-time
|
||||
if (eventStartDay <= eventA.start && eventEndDay >= eventA.end) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
window.is_chinese = ( I18n && I18n.locale.indexOf('zh') != -1 );
|
||||
window.datetime_format = is_chinese ? 'y M d h:m b' : 'd M, y h:m b';
|
||||
window.date_format = is_chinese ? 'y M d' : 'd M, y';
|
||||
window.time_format = "h:m b";
|
||||
window.date_time_str_format = 'y/MM/d H:m';
|
||||
window.short_day = (is_chinese ? "d (w)" : "w d")
|
||||
window.short_date = (is_chinese ? "M d (w)" : "w d, M")
|
||||
window.getDateString = function(date, format,is_chinese) {
|
||||
var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
|
||||
var week_days = ['Sun','Mon','Tue','Wed','Thu','Fri','Sat'];
|
||||
if(is_chinese){
|
||||
months = [];
|
||||
for(var i=0;i<12;i++){
|
||||
months.push((i+1)+"月");
|
||||
}
|
||||
week_days = ["週日","週一","週二","週三","週四","週五","週六"]
|
||||
}
|
||||
var getPaddedComp = function(comp) {
|
||||
return ((parseInt(comp) < 10) ? ('0' + comp) : comp)
|
||||
},
|
||||
formattedDate = format,
|
||||
o = {
|
||||
"y+": date.getFullYear() + (is_chinese ? "年" : ""), // year
|
||||
"MM+": getPaddedComp(date.getMonth() + 1), //raw month
|
||||
"M+": months[date.getMonth()], //month
|
||||
"d+": (is_chinese ? (date.getDate() + "日") : getPaddedComp(date.getDate())), //day
|
||||
"w+": week_days[date.getDay()], //weekday
|
||||
"h+": getPaddedComp((date.getHours() > 12) ? date.getHours() % 12 : date.getHours()), //hour
|
||||
"H+": getPaddedComp(date.getHours()), //hour
|
||||
"m+": getPaddedComp(date.getMinutes()), //minute
|
||||
"s+": getPaddedComp(date.getSeconds()), //second
|
||||
"S+": getPaddedComp(date.getMilliseconds()), //millisecond,
|
||||
"b+": (date.getHours() >= 12) ? 'PM' : 'AM'
|
||||
};
|
||||
|
||||
for (var k in o) {
|
||||
if (new RegExp("(" + k + ")").test(format)) {
|
||||
formattedDate = formattedDate.replace(RegExp.$1, o[k]);
|
||||
}
|
||||
}
|
||||
return formattedDate;
|
||||
};
|
||||
var Calendar = function(dom,property_id,currentView){
|
||||
|
||||
c = this;
|
||||
this.title = $("#current_title");
|
||||
this.calendar = $(dom);
|
||||
this.calendar_dom = $(dom);
|
||||
this.nextBtn = $("#next_month_btn");
|
||||
this.prevBtn = $("#prev_month_btn");
|
||||
this.todayBtn = $("#today_btn");
|
||||
|
@ -11,7 +115,7 @@ var Calendar = function(dom,property_id){
|
|||
this.dialog = new EventDialog(c);
|
||||
this.loading = $('#calendar-loading');
|
||||
this.agenda_space = $("#calendar_agenda");
|
||||
this.currentView = "month";
|
||||
this.currentView = currentView || "dayGridMonth";
|
||||
this.property_id = property_id;
|
||||
this.navigation = $("#navigation");
|
||||
this.rangeSelection = $("#range_selection");
|
||||
|
@ -22,43 +126,89 @@ var Calendar = function(dom,property_id){
|
|||
var d = date.getDate();
|
||||
var m = date.getMonth();
|
||||
var y = date.getFullYear();
|
||||
var dview = (c.currentView == "agenda" ? "month" : c.currentView);
|
||||
c.calendar.fullCalendar({
|
||||
var dview = (c.currentView == "agenda" ? "dayGridMonth" : c.currentView);
|
||||
c.calendar_dom.css("overflow","visible");
|
||||
c.calendar_dom.fullCalendar({
|
||||
themeSystem: 'bootstrap',
|
||||
editable: false,
|
||||
selectable: false,
|
||||
events: "/xhr/property_hires/get_bookings?property_id="+c.property_id,
|
||||
header: false,
|
||||
default: dview,
|
||||
height: $("body").height() - 141,
|
||||
selectable: true,
|
||||
width: "100%",
|
||||
events: function(args, success_callback, fail_callback) {
|
||||
var start = args.start;
|
||||
var end = args.end;
|
||||
$.ajax({
|
||||
url: "/xhr/property_hires/get_bookings?property_id="+c.property_id,
|
||||
dataType: 'json',
|
||||
type: 'GET',
|
||||
data: {
|
||||
start: Math.round(start.getTime() / 1000),
|
||||
end: Math.round(end.getTime() / 1000),
|
||||
_: Date.now()
|
||||
},
|
||||
success: function(json) {
|
||||
// json = json.map(function(obj){
|
||||
// obj.start = new Date(obj.start).toJSON();
|
||||
// obj.end = new Date(obj.end).toJSON();
|
||||
// return obj;
|
||||
// })
|
||||
success_callback(json);
|
||||
}
|
||||
});
|
||||
},
|
||||
// events: 'https://fullcalendar.io/demo-events.json',
|
||||
headerToolbar: false,
|
||||
fixedWeekCount: false,
|
||||
initialView: dview,
|
||||
loading: function(bool) {
|
||||
if (bool) c.loading.css("left",($(window).width()/2 - 60) + "px").show();
|
||||
if (bool) c.loading.show();
|
||||
else c.loading.hide();
|
||||
if(this.currentData)
|
||||
$('#current_title').html(this.currentData.viewTitle);
|
||||
},
|
||||
windowResize : function(view){
|
||||
view.setHeight($("body").height() - 141);
|
||||
c.calendar.fullCalendar("refetchEvents");
|
||||
c.calendar_dom.calendar.refetchEvents();
|
||||
},
|
||||
viewDisplay: function(view) {
|
||||
c.title.html(view.title);
|
||||
},
|
||||
eventTimeFormat: { hour12: true, hour: '2-digit', minute: '2-digit', omitZeroMinute: true, meridiem: 'narrow' },
|
||||
eventClick: function(calEvent, e, view) {
|
||||
if(calEvent.jsEvent && !e){
|
||||
e = {"originalEvent": calEvent.jsEvent}
|
||||
}
|
||||
c.dialog.dismiss();
|
||||
c.dialog.inflate(calEvent);
|
||||
c.dialog.show({"x":e.originalEvent.clientX,"y":e.originalEvent.clientY});
|
||||
}
|
||||
},
|
||||
dateClick: function(ev) {
|
||||
var calendar = this;
|
||||
var calendar_dom = $(this.el);
|
||||
if(c.calendar_dom.hasClass("active_picker")){
|
||||
var date = ev.date,
|
||||
date_str = getDateString(date,date_time_str_format),
|
||||
day_element = ev.dayEl,
|
||||
jsEvent = ev.jsEvent;
|
||||
var time_str = date_str.split(" ")[1];
|
||||
var date_str = date_str.split(" ")[0];
|
||||
calendar_dom.trigger("init_time",[time_str]);
|
||||
calendar_dom.trigger("select_time",[date_str]);
|
||||
}
|
||||
},
|
||||
views: {
|
||||
dayGridMonth: {
|
||||
dayMaxEvents: true
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
c.nextBtn.click(function(){
|
||||
c.dialog.dismiss();
|
||||
c.calendar.fullCalendar('next');
|
||||
c.calendar_dom.calendar.next();
|
||||
});
|
||||
c.prevBtn.click(function(){
|
||||
c.dialog.dismiss();
|
||||
c.calendar.fullCalendar('prev');
|
||||
c.calendar_dom.calendar.prev();
|
||||
});
|
||||
c.todayBtn.click(function(){
|
||||
c.dialog.dismiss();
|
||||
c.calendar.fullCalendar('today');
|
||||
c.calendar_dom.calendar.today();
|
||||
});
|
||||
c.modeBtns.click(function(){
|
||||
c.dialog.dismiss();
|
||||
|
@ -69,7 +219,7 @@ var Calendar = function(dom,property_id){
|
|||
if(c.currentView == "agenda")
|
||||
agendaView.refresh();
|
||||
else
|
||||
c.calendar.fullCalendar("refetchEvents");
|
||||
c.calendar_dom.calendar.refetchEvents();
|
||||
});
|
||||
|
||||
var toggleViews = function(view){
|
||||
|
@ -85,7 +235,7 @@ var Calendar = function(dom,property_id){
|
|||
// $("#sec3").addClass("span4").removeClass("span5");
|
||||
agendaView.hide();
|
||||
}
|
||||
c.calendar.fullCalendar('changeView',view);
|
||||
c.calendar_dom.calendar.changeView(view);
|
||||
}else{
|
||||
// $("#sec1").addClass("span7").removeClass("span3");
|
||||
$("#sec2").hide();
|
||||
|
@ -94,19 +244,25 @@ var Calendar = function(dom,property_id){
|
|||
}
|
||||
c.currentView = view;
|
||||
if(loadeventsonviewchange){
|
||||
c.calendar.fullCalendar("refetchEvents");
|
||||
c.calendar_dom.calendar.refetchEvents();
|
||||
loadeventsonviewchange = false;
|
||||
}
|
||||
if(c.calendar_dom.calendar.currentData){
|
||||
var viewTitle = c.calendar_dom.calendar.currentData.viewTitle;
|
||||
if(view == "timeGridDay" && $('.fc-col-header-cell-cushion ').text() != "")
|
||||
viewTitle = $('.fc-col-header-cell-cushion ').text() + ', ' + viewTitle;
|
||||
$('#current_title').html(viewTitle);
|
||||
}
|
||||
c.calendar_dom.calendar.render(); //Rerender to fix layout
|
||||
};
|
||||
if(c.currentView == "agenda"){toggleViews("agenda");loadeventsonviewchange = true;}
|
||||
|
||||
};
|
||||
|
||||
this.renderEvent = function(eventStick){
|
||||
if(eventStick.recurring === true)
|
||||
c.calendar.fullCalendar("refetchEvents");
|
||||
c.calendar_dom.calendar.refetchEvents();
|
||||
else
|
||||
c.calendar.fullCalendar("renderEvent",eventStick);
|
||||
c.calendar_dom.calendar.renderEvent(eventStick);
|
||||
};
|
||||
|
||||
|
||||
|
@ -120,31 +276,48 @@ var EventDialog = function(calendar,event){
|
|||
var event_quick_view = null;
|
||||
var template = "";
|
||||
var _this_event = null;
|
||||
var month_names = ["Jan","Feb","March","April","May","June","July","Aug","Sep","Oct","Nov","Dec"];
|
||||
this.inflate = function(_event){
|
||||
if(!_event) throw new UserException("EventStick can't be null!");
|
||||
_event.allDay = _event.event.allDay;
|
||||
_event._start = _event.event.start;
|
||||
_event._end = (_event.event.end ? _event.event.end : _event.event.start);
|
||||
// var start_date = getDateString(_event._start,date_format);
|
||||
// var end_date = getDateString(_event._end,date_format);
|
||||
if(_event._end - _event._start > 86400 * 1000){
|
||||
_event.allDay = true;
|
||||
}
|
||||
_event.title = _event.event.title;
|
||||
_event.hiring_person_name = _event.event.extendedProps.hiring_person_name;
|
||||
_event.error_message = _event.event.extendedProps.error_message;
|
||||
if(!_event.hiring_person_name)
|
||||
_event.hiring_person_name = "";
|
||||
_event.note = _event.event.extendedProps.note;
|
||||
_this_event = _event;
|
||||
var start_time = "",
|
||||
end_time = "",
|
||||
time_string = null;
|
||||
|
||||
end_time = "",
|
||||
time_string = null;
|
||||
if(_event.allDay) {
|
||||
start_time = $.fullCalendar.formatDate(_event._start,"MMM dd, yyyy");
|
||||
start_time = getDateString(_event._start,datetime_format, is_chinese);
|
||||
if(_event._end)
|
||||
end_time = $.fullCalendar.formatDate(_event._end,"MMM dd, yyyy");
|
||||
time_string = (_event._start === _event._end || !_event._end ? "<p class='start-date'><i class='icons-calendar' /> " + start_time + "</p>" : "<i class='icons-calendar' /> " + start_time + " <i class='icons-arrow-right-5' /> " + end_time + "");
|
||||
end_time = getDateString(_event._end,datetime_format, is_chinese);
|
||||
time_string = (_event._start === _event._end || !_event._end ? "<p class='start-date'><i class='icons-calendar' /></i>" + start_time + "</p>" : "<i class='icons-calendar' /></i>" + start_time + "<br><i class='icons-arrow-right-5' /></i>" + end_time + "");
|
||||
} else {
|
||||
var sh = _event._start.getHours() > 12 ? _event._start.getHours() - 12 : _event._start.getHours(),
|
||||
eh = _event._end.getHours() > 12 ? _event._end.getHours() - 12 : _event._end.getHours(),
|
||||
sm = _event._start.getMinutes() < 10 ? '0' + _event._start.getMinutes() : _event._start.getMinutes(),
|
||||
em = _event._end.getMinutes() < 10 ? '0' + _event._end.getMinutes() : _event._end.getMinutes(),
|
||||
stime = _event._start.getHours() > 12 ? sh + ':' + sm + " PM" : sh + ':' + sm + " AM",
|
||||
etime = _event._end.getHours() > 12 ? eh + ':' + em + " PM" : eh + ':' + em + " AM",
|
||||
same = (_event._start.getDate() == _event._end.getDate() && _event._start.getMonth() == _event._end.getMonth() && _event._start.getFullYear() == _event._end.getFullYear());
|
||||
start_time = month_names[_event._start.getMonth()] + " " + _event._start.getDate() + ", " + _event._start.getFullYear();
|
||||
end_time = month_names[_event._end.getMonth()] + " " + _event._end.getDate() + ", " + _event._end.getFullYear();
|
||||
|
||||
time_string = (same ? "<p class='date'><i class='icons-calendar' /> " + start_time + "</p><p class='time'><i class='icons-clock' /> " + stime + " <i class='icons-arrow-right-5' /> " + etime : "<p class='start-date'><i class='icons-arrow-right-2' /> " + start_time + "<span class='pull-right'>" + stime + "</span></p><p class='end-date'><i class='icons-arrow-left-2' /> " + end_time + "<span class='pull-right'>" + etime + "</p>");
|
||||
start_time = getDateString(_event._start,date_format, is_chinese);
|
||||
end_time = getDateString(_event._end,date_format, is_chinese);
|
||||
var stime = getDateString(_event._start,time_format, is_chinese),
|
||||
etime = getDateString(_event._end,time_format, is_chinese),
|
||||
same = (start_time == end_time);
|
||||
if( same ){
|
||||
time_string = "<p class='date'><i class='icons-calendar' /></i> " +
|
||||
start_time +
|
||||
"</p><p class='time'><i class='icons-clock' /></i> " + stime +
|
||||
" <i class='icons-arrow-right-5' /></i> " + etime ;
|
||||
}else{
|
||||
time_string = "<i class='icons-calendar' /></i><span class='start-date'>" + start_time + " " + stime +
|
||||
"</span><br><i class='icons-arrow-right-5' /></i><span class='end-date'>" +
|
||||
end_time + " " + etime + "</span>"
|
||||
}
|
||||
// time_string = (same ? "<p class='date'><i class='icons-calendar' /> " + start_time + "</p><p class='time'><i class='icons-clock' /> " + stime + " <i class='icons-arrow-right-5' /> " + etime : "<p class='start-date'><i class='icons-arrow-right-2' /> " + start_time + "<span class='pull-right'>" + stime + "</span></p><p class='end-date'><i class='icons-arrow-left-2' /> " + end_time + "<span class='pull-right'>" + etime + "</p>");
|
||||
}
|
||||
event_quick_view = $('<div class="calendar-modal" style="display:none;"></div>');
|
||||
template = '<div class="modal-content">' +
|
||||
|
@ -154,6 +327,7 @@ var EventDialog = function(calendar,event){
|
|||
'</div>' +
|
||||
'<div class="modal-body">' +
|
||||
'<div class="event_summary">' + time_string + '</br>' + _event.hiring_person_name + '</div>' + _event.note +
|
||||
(_event.error_message ? ("<br><span style=\"color: #FC4040;\">" + _event.error_message + "</span>") : "")
|
||||
'</div>' +
|
||||
'<div class="modal-footer" />' +
|
||||
'</div>';
|
||||
|
@ -161,6 +335,7 @@ var EventDialog = function(calendar,event){
|
|||
|
||||
|
||||
this.show = function(pos){
|
||||
event_quick_view.css({width: '',height: ''});
|
||||
if(pos){
|
||||
var pos = getPosition(pos);
|
||||
event_quick_view.css({"left":pos.x+"px","top":pos.y+"px"});
|
||||
|
@ -169,6 +344,38 @@ var EventDialog = function(calendar,event){
|
|||
event_quick_view.find(".event-close-btn").one("click",function(){_t.dismiss();});
|
||||
event_quick_view.find("a.delete").one("click",function(){calendar.deleteEvent(_this_event.delete_url,_this_event._id);return false;});
|
||||
event_quick_view.find("a.edit").one("click",function(){calendar.editEvent(_this_event.edit_url,_this_event.allDay);return false;});
|
||||
var window_width = $(window).width(),
|
||||
window_height = $(window).height();
|
||||
var offset = event_quick_view.offset();
|
||||
var dialog_width = event_quick_view.width(),
|
||||
dialog_height = event_quick_view.height();
|
||||
var new_offset = Object.assign({},offset);
|
||||
var need_redisplay = false;
|
||||
var new_width = null, new_height = null;
|
||||
var padding = 20;
|
||||
if(offset.left + dialog_width > window_width){
|
||||
new_offset.left = window_width - dialog_width - padding;
|
||||
need_redisplay = true;
|
||||
}
|
||||
if(new_offset.left < padding){
|
||||
new_width = dialog_width - (padding - new_offset.left);
|
||||
new_offset.left = padding;
|
||||
need_redisplay = true;
|
||||
}
|
||||
if(offset.top + dialog_height > window_height){
|
||||
new_offset.top = window_height - dialog_height - padding;
|
||||
need_redisplay = true;
|
||||
}
|
||||
if(new_offset.top < padding){
|
||||
new_height = dialog_height - (padding - new_offset.top);
|
||||
new_offset.top = padding;
|
||||
need_redisplay = true;
|
||||
}
|
||||
if(need_redisplay){
|
||||
event_quick_view.offset(new_offset);
|
||||
event_quick_view.width(new_width);
|
||||
event_quick_view.height(new_height);
|
||||
}
|
||||
}
|
||||
|
||||
this.dismiss = function(){
|
||||
|
@ -238,6 +445,7 @@ var AgendaView = function(calendar){
|
|||
'<th>Date</th>' +
|
||||
'<th>Time</th>' +
|
||||
'<th>Events</th>' +
|
||||
'<th>Borrower</th>' +
|
||||
'</tr>' +
|
||||
'</thead>' +
|
||||
'<tbody>' +
|
||||
|
@ -250,11 +458,9 @@ var AgendaView = function(calendar){
|
|||
|
||||
var head_template = '<div>' +
|
||||
'<label>From</label>' +
|
||||
'<select name="start_month" class="form-control input-sm" />' +
|
||||
'<select name="start_year" class="form-control input-sm" />' +
|
||||
'<input class="input-large" id="agenda_start" placeholder="YYYY/MM" type="text" value="'+start_year+'/'+('0'+(start_month+1)).substr(-2,2)+'" title="YYYY/MM" autocomplete="off">'+
|
||||
'<label>To</label>' +
|
||||
'<select name="end_month" class="form-control input-sm" />' +
|
||||
'<select name="end_year" class="form-control input-sm" />' +
|
||||
'<input class="input-large" id="agenda_end" placeholder="YYYY/MM" type="text" value="'+end_year+'/'+('0'+(end_month+1)).substr(-2,2)+'" title="YYYY/MM" autocomplete="off">'+
|
||||
'<button id="show_events" class="btn btn-sm bt-filter btn-primary">Show Events</button>' +
|
||||
'</div>';
|
||||
|
||||
|
@ -264,6 +470,7 @@ var AgendaView = function(calendar){
|
|||
'<td>' +
|
||||
'<div class="event" />' +
|
||||
'</td>' +
|
||||
'<td class="Borrower">'+
|
||||
'</tr>';
|
||||
// var month_template = '<div class="span4"><h4></h4><div class="tiny_calendar"><table class="table"><tbody><tr><th class="week_title">Sun</th><th class="week_title">Mon</th><th class="week_title">Tue</th><th class="week_title">Wed</th><th class="week_title">Thu</th><th class="week_title">Fri</th><th class="week_title">Sat</th></tr></tbody></table></div></div>';
|
||||
|
||||
|
@ -282,7 +489,7 @@ var AgendaView = function(calendar){
|
|||
|
||||
this.inflate = function(forceInflation){
|
||||
loading(true);
|
||||
_calendar.calendar.hide();
|
||||
_calendar.calendar_dom.hide();
|
||||
_calendar.navigation.hide();
|
||||
|
||||
if(!forceInflation){
|
||||
|
@ -299,10 +506,12 @@ var AgendaView = function(calendar){
|
|||
_calendar.rangeSelection.append(renderHead().html()).show();
|
||||
_calendar.rangeSelection.find("button#show_events").click(function(){
|
||||
show_event_clicked = true;
|
||||
start_month = parseInt($("select[name=start_month]").val());
|
||||
end_month = parseInt($("select[name=end_month]").val());
|
||||
start_year = parseInt($("select[name=start_year]").val());
|
||||
end_year = parseInt($("select[name=end_year]").val());
|
||||
var starts = $("#agenda_start").val().split("/"),
|
||||
ends = $("#agenda_end").val().split("/");
|
||||
start_month = parseInt(starts[1]) - 1;
|
||||
end_month = parseInt(ends[1]) - 1;
|
||||
start_year = parseInt(starts[0]);
|
||||
end_year = parseInt(ends[0]);
|
||||
av.inflate(true);
|
||||
})
|
||||
}
|
||||
|
@ -336,7 +545,7 @@ var AgendaView = function(calendar){
|
|||
_calendar.rangeSelection.hide();
|
||||
agenda_space.hide();
|
||||
_calendar.navigation.show();
|
||||
_calendar.calendar.show();
|
||||
_calendar.calendar_dom.show();
|
||||
}
|
||||
|
||||
this.show = function(){
|
||||
|
@ -347,7 +556,7 @@ var AgendaView = function(calendar){
|
|||
return x.clone();
|
||||
}
|
||||
var eventsManager = function(){
|
||||
var url = "/xhr/calendars/agenda",
|
||||
var url = "/xhr/property_hires/get_bookings?property_id="+_calendar.property_id,
|
||||
sd = new Date(start_year,start_month,1),
|
||||
ed = new Date(end_year,end_month+1,0),
|
||||
usd = Math.round(sd/1000),
|
||||
|
@ -355,9 +564,39 @@ var AgendaView = function(calendar){
|
|||
$.ajax({
|
||||
type : "get",
|
||||
url : url,
|
||||
data : {"agenda_start":sd.toLocaleString(),"agenda_end":ed.toLocaleString(),"page_id" : _calendar.page_id,"unix_start":usd,"unix_end":ued},
|
||||
dataType : "json",
|
||||
data : {"agenda_start":sd.toLocaleString(),"agenda_end":ed.toLocaleString(),"page_id" : _calendar.page_id,"start":usd,"end":ued},
|
||||
success : function(data){
|
||||
$.each(data.events,function(i,e){
|
||||
$("#agenda_start,#agenda_end").datepicker({
|
||||
dateFormat: "yy/mm",
|
||||
onChangeMonthYear: function( year, month, inst ){
|
||||
$(this).val($.datepicker.formatDate('yy/mm', new Date(year, month-1, 1)));
|
||||
},
|
||||
gotoCurrent: true
|
||||
});
|
||||
$("#agenda_start,#agenda_end").on("focus",function(){
|
||||
var input = this;
|
||||
var inst = $(this).data("datepicker");
|
||||
var year_month = $(input).val().split("/");
|
||||
if(year_month.length == 2){
|
||||
inst.selectedYear = parseInt(year_month[0]);
|
||||
inst.selectedMonth = parseInt(year_month[1]) - 1;
|
||||
inst.drawYear = inst.selectedYear;
|
||||
inst.drawMonth = inst.selectedMonth;
|
||||
inst.currentYear = inst.selectedYear;
|
||||
inst.currentMonth = inst.selectedMonth;
|
||||
}
|
||||
$.datepicker._updateDatepicker(inst);
|
||||
})
|
||||
$("#agenda_start,#agenda_end").focus(function () {
|
||||
$(".ui-datepicker-calendar").hide();
|
||||
$("#ui-datepicker-div").position({
|
||||
my: "center top",
|
||||
at: "center bottom",
|
||||
of: $(this)
|
||||
});
|
||||
});
|
||||
$.each(data,function(i,e){
|
||||
var ed = eventDom(e),
|
||||
s = new Date(e.start),
|
||||
e = new Date(e.end),
|
||||
|
@ -414,14 +653,16 @@ var AgendaView = function(calendar){
|
|||
var e_t = $(event_template),
|
||||
s = new Date(event.start),
|
||||
e = new Date(event.end),
|
||||
dateFormat = "";
|
||||
dateFormat = "",
|
||||
hiring_person_name = event.hiring_person_name;
|
||||
if(s.getDate() == e.getDate() && s.getMonth() == s.getMonth() && e.getFullYear() == e.getFullYear())
|
||||
dateFormat = $.fullCalendar.formatDate(s, "ddd dd");
|
||||
dateFormat = getDateString(s, short_day,is_chinese);
|
||||
else
|
||||
dateFormat = $.fullCalendar.formatDates(s, e, "ddd dd, MMM - {ddd dd, MMM}");
|
||||
dateFormat = getDateString(s,short_date,is_chinese) + ' - ' + getDateString(e,short_date,is_chinese);
|
||||
e_t.find("td:first").text(dateFormat);
|
||||
e_t.find("td.event_time").text((event.allDay ? "All Day" : $.fullCalendar.formatDate(s, "hh:mm")));
|
||||
e_t.find("td.event_time").text((event.allDay ? "All Day" : (getDateString(s, "h:m b")+"~"+getDateString(e, "h:m b"))));
|
||||
e_t.find("div.event").text(event.title).css("color",event.color);
|
||||
e_t.find("td.Borrower").text(hiring_person_name);
|
||||
return e_t;
|
||||
}
|
||||
|
||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -1,3 +1,11 @@
|
|||
#calendar.active_picker .fc-scrollgrid-sync-inner,#calendar.active_picker .fc-timegrid-slot{
|
||||
cursor: pointer;
|
||||
}
|
||||
#calendar.active_picker{
|
||||
.fc-scrollgrid-sync-inner:hover, .fc-timegrid-slot:hover{
|
||||
background: var(--fc-highlight-color, rgba(188, 232, 241, 0.3));
|
||||
}
|
||||
}
|
||||
/* orbit calendar */
|
||||
#orbit_calendar {
|
||||
transition: all 0.3s ease;
|
||||
|
@ -96,7 +104,9 @@
|
|||
& > * {
|
||||
margin: 0 5px;
|
||||
}
|
||||
|
||||
& > select {
|
||||
height: 3em;
|
||||
}
|
||||
@media screen and (max-width: 479px) {
|
||||
margin-right: 0;
|
||||
|
||||
|
@ -253,6 +263,9 @@
|
|||
.event_list td {
|
||||
padding: 0;
|
||||
}
|
||||
.event_list th {
|
||||
width: 25%;
|
||||
}
|
||||
}
|
||||
|
||||
.event_holder {
|
||||
|
@ -627,8 +640,9 @@
|
|||
}
|
||||
|
||||
#calendar-loading {
|
||||
position: absolute;
|
||||
top: 40%;
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
z-index: 10;
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
|
@ -641,6 +655,7 @@
|
|||
background-position: center 20px;
|
||||
background-size: 50%;
|
||||
box-shadow: 0 0 25px 0 rgba(0, 0, 0, 0.2);
|
||||
transform: translate(-50%, -50%);
|
||||
|
||||
&:after {
|
||||
content: "Loading...";
|
||||
|
@ -691,7 +706,7 @@
|
|||
|
||||
.calendar-modal {
|
||||
position: fixed;
|
||||
z-index: 1050;
|
||||
z-index: 10000;
|
||||
width: 300px;
|
||||
margin: 0;
|
||||
font-size: 12px;
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -24,7 +24,14 @@ class Admin::PropertyHiresController < OrbitAdminController
|
|||
@locations = PropertyLocation.all.desc(:created_at).collect{|loc| [loc.title, loc.id.to_s]}
|
||||
@locations << ["Other", "other_location"]
|
||||
end
|
||||
|
||||
def edit_hire
|
||||
@phire = PHire.find(params[:id])
|
||||
end
|
||||
def update_hire
|
||||
@phire = PHire.find(params[:id])
|
||||
@phire.update_attributes(phire_params)
|
||||
redirect_to admin_property_hire_path(:id=>@phire.property)
|
||||
end
|
||||
def edit
|
||||
@property = Property.where(:uid => params[:id].split("-").last).first rescue nil
|
||||
create_set (true)
|
||||
|
@ -178,7 +185,9 @@ class Admin::PropertyHiresController < OrbitAdminController
|
|||
def location_params
|
||||
params.require(:property_location).permit!
|
||||
end
|
||||
|
||||
def phire_params
|
||||
params.require(:p_hire).permit!
|
||||
end
|
||||
def property_params
|
||||
prop = params.require(:property).permit!
|
||||
prop.delete(:property_location) if prop[:property_location] == "other"
|
||||
|
|
|
@ -214,7 +214,7 @@ class PropertyHiresController < ApplicationController
|
|||
end
|
||||
end
|
||||
respond_to do |format|
|
||||
format.html # index.html.erb
|
||||
format.html { render json: allevents.to_json }# index.html.erb
|
||||
format.json { render json: allevents.to_json }
|
||||
end
|
||||
end
|
||||
|
|
|
@ -2,32 +2,63 @@ module Admin::PropertyHiresHelper
|
|||
|
||||
def check_for_availability(stime, etime, pid, interval=nil, recurring_end_date=nil)
|
||||
property = Property.find(pid)
|
||||
return {"success" => false, "msg" => "Values are not ok."} if property.nil? || stime.blank? || etime.blank?
|
||||
return {"success" => false, "msg" => I18n.t("property_hire.values_are_not_ok",:default=>"Values are not ok.")} if property.nil? || stime.blank? || etime.blank?
|
||||
timezone = (params[:timezone] rescue nil)
|
||||
timezone = timezone ? timezone : Time.zone.to_s
|
||||
if !stime.blank?
|
||||
stime = DateTime.parse(stime + Time.zone.to_s) rescue nil
|
||||
stime = DateTime.parse(stime + timezone) rescue nil
|
||||
else
|
||||
stime = nil
|
||||
end
|
||||
if !etime.blank?
|
||||
etime = DateTime.parse(etime + Time.zone.to_s) rescue nil
|
||||
etime = DateTime.parse(etime + timezone) rescue nil
|
||||
else
|
||||
etime = nil
|
||||
end
|
||||
if !recurring_end_date.blank?
|
||||
recurring_end_date = DateTime.parse(recurring_end_date + Time.zone.to_s) rescue nil
|
||||
recurring_end_date = DateTime.parse(recurring_end_date + timezone) rescue nil
|
||||
begin
|
||||
interval_time = 1.send(interval)
|
||||
tmp_date = recurring_end_date - interval_time
|
||||
if tmp_date < etime
|
||||
I18n.with_locale(params[:locale]) do
|
||||
interval_str= I18n.t("property_hire.1_#{interval}","1 #{interval}")
|
||||
default_msg = "Recurring end date must exceed hire end time than #{interval_str}!"
|
||||
msg = I18n.t("property_hire.recurring_end_date_must_exceed_time",{:time=>interval_str,:default=>default_msg})
|
||||
return {"success" => false, "msg" => msg}
|
||||
end
|
||||
end
|
||||
rescue
|
||||
end
|
||||
else
|
||||
recurring_end_date = nil
|
||||
end
|
||||
data = {}
|
||||
return {"success" => false, "msg" => "Starting time cannot be greater than ending time."} if stime > etime
|
||||
if property.is_available_for_hire?(stime, etime, interval, recurring_end_date)
|
||||
if property.not_yet_hired?(stime, etime, interval, recurring_end_date)
|
||||
if stime > etime
|
||||
I18n.with_locale(params[:locale]) do
|
||||
return {"success" => false, "msg" => I18n.t("property_hire.starting_time_cannot_be_greater_than_ending_time")}
|
||||
end
|
||||
end
|
||||
available_flag = property.is_available_for_hire?(stime, etime, interval, recurring_end_date)
|
||||
if available_flag
|
||||
if property.not_yet_hired?(stime, etime, interval, recurring_end_date,params[:phire_id])
|
||||
data = {"success" => true}
|
||||
else
|
||||
data = {"success" => false, "msg" => "Property is already hired during this time."}
|
||||
I18n.with_locale(params[:locale]) do
|
||||
data = {"success" => false, "msg" => I18n.t("property_hire.property_is_already_hired_during_this_time")}
|
||||
end
|
||||
end
|
||||
else
|
||||
data = {"success" => false, "msg" => "Property is unavailable during this time."}
|
||||
I18n.with_locale(params[:locale]) do
|
||||
msg = I18n.t("property_hire.property_is_unavailable_during_this_time")
|
||||
if available_flag.nil?
|
||||
can_hire_date = stime - (property.can_hire_before_months).month
|
||||
msg += ("<br>" + I18n.t("property_hire.please_hire_after_date",{:date=>"{#{can_hire_date.utc.to_json.gsub('"','')}}"}))
|
||||
else
|
||||
msg += ("<br>" + property.render_unavailable_message)
|
||||
end
|
||||
data = {"success" => false, "msg" => msg}
|
||||
end
|
||||
end
|
||||
return data
|
||||
end
|
||||
|
|
|
@ -34,10 +34,11 @@ class PHire
|
|||
:hiring_person_id => self.hiring_person_id,
|
||||
:hiring_person_name => self.hiring_person_name,
|
||||
:note => self.note_for_hire || "",
|
||||
:start => self.start_time.rfc822,
|
||||
:end => self.end_time.rfc822,
|
||||
:allDay => false,
|
||||
:color => "#FC4040"
|
||||
:start => self.start_time.to_json.gsub('"',''),
|
||||
:end => self.end_time.to_json.gsub('"',''),
|
||||
:allDay => (self.end_time - self.start_time >= 1),
|
||||
:color => (self.passed ? "#3788d8" : "#FC4040"),
|
||||
:error_message => (self.passed ? nil : "Not approved")
|
||||
}
|
||||
end
|
||||
|
||||
|
@ -87,7 +88,7 @@ class PHire
|
|||
next if !((startt..endt) & (@start_date..@end_date)).blank?
|
||||
end
|
||||
if @start_date < re.recurring_end_date
|
||||
@recurring << {:id => re.id.to_s, :hiring_person_name => re.hirer_name ,:title=>re.reason_for_hire, :note=>re.reason_for_hire, :start=>@start_date, :end => @end_date, :allDay => false, :recurring => re.recurring, :color => "#FC4040"}
|
||||
@recurring << {:id => re.id.to_s, :hiring_person_name => re.hirer_name ,:title=>re.reason_for_hire, :note=>re.reason_for_hire, :start=>@start_date, :end => @end_date, :allDay => (re.end_time - re.start_time >= 1), :recurring => re.recurring, :color => (re.passed ? "#3788d8" : "#FC4040"), :error_message => (re.passed ? nil : "Not approved")}
|
||||
end
|
||||
end
|
||||
when "month"
|
||||
|
|
|
@ -21,7 +21,7 @@ class Property
|
|||
mount_uploader :image, ImageUploader
|
||||
|
||||
# unavailibility fields
|
||||
|
||||
field :can_hire_before_months, type: Integer, default: 0
|
||||
field :set_unavailibility, type: Boolean, default: false
|
||||
field :start_time
|
||||
field :end_time
|
||||
|
@ -54,7 +54,79 @@ class Property
|
|||
"Friday",
|
||||
"Saturday"
|
||||
]
|
||||
|
||||
def render_unavailable_message
|
||||
message = ""
|
||||
property = self
|
||||
weekdays_options = self.class::WEEKDAYS
|
||||
weekdays_options = weekdays_options.map do |weekday|
|
||||
trans = I18n.t("property_hire.#{weekday}", :default=>'')
|
||||
if trans != ""
|
||||
trans
|
||||
else
|
||||
weekday
|
||||
end
|
||||
end
|
||||
if property.set_unavailibility
|
||||
if property.weekdays.length > 0
|
||||
translation_missing = (I18n.t('property_hire.unavailable_hint1', {:default => ''}) == "")
|
||||
str1 = (!property.start_date.nil? ? (I18n.t("property_hire.from",:default=>" from ") + property.start_date.strftime("%Y-%m-%d")) : "")
|
||||
str2 = (!property.end_date.nil? ? (I18n.t("property_hire.to",:default=>" to ") + property.end_date.strftime("%Y-%m-%d")) : "")
|
||||
if str1 == "" && str2 != ""
|
||||
str1 = I18n.t("property_hire.from_now_on")
|
||||
end
|
||||
if str1 != "" || str2 != ""
|
||||
str2 += I18n.t("property_hire.of",:default=>"")
|
||||
else
|
||||
str2 += I18n.t("property_hire.at",:default=>"")
|
||||
end
|
||||
week_str = ""
|
||||
if translation_missing
|
||||
week_str += "every "
|
||||
else
|
||||
week_str += I18n.t("property_hire.every")
|
||||
end
|
||||
dot_trans = I18n.t("property_hire.dot",:default=>", ")
|
||||
property.weekdays.each_with_index do |d,i|
|
||||
if i < (property.weekdays.count - 1)
|
||||
week_str += (weekdays_options[d.to_i] + dot_trans)
|
||||
else
|
||||
week_str += weekdays_options[d.to_i]
|
||||
end
|
||||
end
|
||||
str3 = ""
|
||||
if property.end_time.blank?
|
||||
if property.start_time.blank?
|
||||
str3 = "." if translation_missing
|
||||
else
|
||||
str3 = I18n.t("property_hire.from_time",{:time=>property.start_time,:default=>" from #{property.start_time}."})
|
||||
end
|
||||
else
|
||||
if I18n.locale.to_s != "zh_tw"
|
||||
str3 = " between #{property.start_time} & #{property.end_time}."
|
||||
else
|
||||
str3 = I18n.t("property_hire.time1_to_time2",{:time1=>property.start_time,:time2=>property.end_time})
|
||||
end
|
||||
end
|
||||
if str3 != ""
|
||||
str3 = I18n.t("property_hire.of",:default=>"") + str3
|
||||
end
|
||||
hint1 = I18n.t('property_hire.unavailable_hint1', {:str1=>str1,:str2=>str2,:week_str=>week_str,:str3=>str3, :default => ''})
|
||||
if hint1 == ""
|
||||
message += "This property is unavaliable#{str1}#{str2} #{week_str}#{str3}"
|
||||
else
|
||||
message += hint1
|
||||
end
|
||||
end
|
||||
if property.can_hire_before_months != 0
|
||||
if message != ""
|
||||
message += "<br>"
|
||||
end
|
||||
default_msg = "This property is unavaliable to hire before #{property.can_hire_before_months} month ago."
|
||||
message += I18n.t("property_hire.unavailable_hint2",{:month=>property.can_hire_before_months,:default=>default_msg})
|
||||
end
|
||||
end
|
||||
return message.html_safe
|
||||
end
|
||||
def get_location_name
|
||||
return self.property_location.nil? ? self.other_location : self.property_location.title
|
||||
end
|
||||
|
@ -66,11 +138,14 @@ class Property
|
|||
def is_available_for_hire?(stime, etime, interval = nil, recurring_end_date = nil)
|
||||
available = false
|
||||
return true if self.set_unavailibility == false
|
||||
return true if self.weekdays.empty?
|
||||
available = true if !self.start_date.nil? && (self.start_date > stime && self.start_date > etime)
|
||||
available = true if !self.end_date.nil? && self.end_date < stime
|
||||
startt = self.start_date.nil? ? self.created_at : self.start_date
|
||||
endt = self.end_date.nil? && !startt.nil? ? (startt + 5.years) : self.end_date
|
||||
return true if self.weekdays.empty? && self.can_hire_before_months == 0
|
||||
if self.can_hire_before_months != 0
|
||||
return nil if (((stime - Time.now.to_datetime) * 1.day) > (self.can_hire_before_months).month)
|
||||
end
|
||||
startt = self.start_date.nil? ? stime : self.start_date
|
||||
endt = self.end_date.nil? ? etime : self.end_date
|
||||
available = true if (startt > stime && endt > etime)
|
||||
available = true if (endt < stime)
|
||||
weekdays = self.weekdays.collect{|w| w.to_i}
|
||||
if !startt.nil?
|
||||
if !available
|
||||
|
@ -83,8 +158,8 @@ class Property
|
|||
time_weekdays.uniq!
|
||||
weekdays = weekdays & time_weekdays
|
||||
return true if weekdays.blank?
|
||||
startt = DateTime.parse(stime.strftime("%Y-%m-%d " + self.start_time + Time.zone.to_s))
|
||||
endt = DateTime.parse(etime.strftime("%Y-%m-%d " + self.end_time + Time.zone.to_s))
|
||||
startt = DateTime.parse(stime.strftime("%Y-%m-%d " + (self.start_time.blank? ? "00:00" : self.start_time) + Time.zone.to_s))
|
||||
endt = DateTime.parse(etime.strftime("%Y-%m-%d " + (self.end_time.blank? ? "23:59" : self.end_time) + Time.zone.to_s))
|
||||
common_dates = (startt..endt) & (stime..etime)
|
||||
available = common_dates.nil?
|
||||
end
|
||||
|
@ -119,17 +194,21 @@ class Property
|
|||
end
|
||||
end
|
||||
|
||||
def not_yet_hired?(stime, etime, interval, recurring_end_date)
|
||||
def not_yet_hired?(stime, etime, interval, recurring_end_date,phire_id=nil)
|
||||
phires = self.p_hires
|
||||
bookings_count = phires.where(:start_time.lte => stime,:end_time.gte => stime,:recurring => false).count
|
||||
+ phires.where(:start_time.gte => stime,:end_time.lte => etime,:recurring => false).count
|
||||
+phires.where(:start_time.lte => etime,:end_time.gte => etime,:recurring => false).count
|
||||
stime = stime.utc
|
||||
etime = etime.utc
|
||||
bookings_count = phires.where(:start_time.lte => stime,:end_time.gte => stime,:recurring => false,:id.ne=>phire_id).count
|
||||
+ phires.where(:start_time.gte => stime,:end_time.lte => etime,:recurring => false,:id.ne=>phire_id).count
|
||||
+phires.where(:start_time.lte => etime,:end_time.gte => etime,:recurring => false,:id.ne=>phire_id).count
|
||||
available = true
|
||||
if bookings_count != 0
|
||||
available = false
|
||||
end
|
||||
puts ["phire_id",phire_id]
|
||||
if available
|
||||
bookings = phires.where(:recurring_end_date.gte => stime, :recurring => true) + phires.where(:recurring => false,:recurring_end_date => nil) + phires.where(:recurring => false,:recurring_end_date.gte => stime)
|
||||
recurring_bookings = phires.where(:recurring_end_date.gte => stime, :recurring => true,:id.ne=>phire_id)
|
||||
bookings = phires.where(:recurring => false,:recurring_end_date => nil)
|
||||
case interval
|
||||
when 'week'
|
||||
d_step = 1.week
|
||||
|
@ -138,53 +217,50 @@ class Property
|
|||
else
|
||||
d_step = 0
|
||||
end
|
||||
bookings.each do |booking|
|
||||
stime_tp = stime
|
||||
etime_tp = etime
|
||||
if true#d_step != 0
|
||||
bookings += recurring_bookings
|
||||
end
|
||||
bookings.each_with_index do |booking,i|
|
||||
stime_tp = stime.clone
|
||||
etime_tp = etime.clone
|
||||
b_interval = booking.recurring_interval
|
||||
if (b_interval == 'month' || b_interval == 'week') && booking.recurring_end_date.nil?
|
||||
b_recurring_end_date = booking.recurring_end_date ? booking.recurring_end_date.utc : nil
|
||||
b_sdata = booking.start_time.utc
|
||||
b_edata = booking.end_time.utc
|
||||
b_delta = b_edata - b_sdata
|
||||
if (b_interval == 'month' || b_interval == 'week') && (booking.recurring_end_date.nil? || !booking.recurring)
|
||||
b_interval = nil
|
||||
end
|
||||
while true
|
||||
if b_interval == 'month'
|
||||
diff_month = booking.end_time.month - booking.start_time.month
|
||||
diff_month = diff_month + 12 if diff_month < 0
|
||||
e_month = stime_tp.month + diff_month
|
||||
e_year = stime_tp.year + (booking.end_time.year-booking.start_time.year)
|
||||
e_month = e_month - 12 if e_month >12
|
||||
b_sdata = Time.local(stime_tp.year,stime_tp.month,booking.start_time.day,booking.start_time.hour,booking.start_time.minute).to_datetime
|
||||
b_edata = Time.local(e_year,e_month,booking.end_time.day,booking.end_time.hour,booking.end_time.minute).to_datetime
|
||||
elsif b_interval == 'week'
|
||||
diff_day = booking.end_time - booking.start_time
|
||||
if (booking.end_time.wday <= booking.start_time.wday && diff_day>1) || diff_day > 7
|
||||
over_one_week = true
|
||||
b_datas = []
|
||||
if b_interval.present?
|
||||
b_interval = (1).send(b_interval)
|
||||
b_datas = (b_edata..b_recurring_end_date).step(b_interval).to_a
|
||||
b_datas = b_datas.map{|b_end| [b_end-b_delta,b_end]}
|
||||
start_index = b_datas.count
|
||||
b_datas.each_with_index do |(b_start,b_end),i|
|
||||
if b_start >= stime_tp || b_end <= etime_tp
|
||||
start_index = i
|
||||
break
|
||||
end
|
||||
b_sdata_tp = stime_tp - stime_tp.wday.day + booking.start_time.wday.day
|
||||
b_sdata = Time.local(b_sdata_tp.year,b_sdata_tp.month,b_sdata_tp.day,booking.start_time.hour,booking.start_time.minute).to_datetime
|
||||
if over_one_week && etime_tp.wday <= booking.start_time.wday
|
||||
b_sdata = b_sdata - 7.day
|
||||
end
|
||||
now_diff_day = etime_tp - stime_tp
|
||||
if (etime_tp.wday <= stime_tp.wday && now_diff_day>1) || now_diff_day > 7
|
||||
b_sdata = b_sdata + 7.day
|
||||
end
|
||||
b_edata_tp = b_sdata + (booking.end_time - booking.start_time).to_i.day
|
||||
b_edata = Time.local(b_edata_tp.year,b_edata_tp.month,b_edata_tp.day,booking.end_time.hour,booking.end_time.minute).to_datetime
|
||||
else
|
||||
b_sdata = booking.start_time
|
||||
b_edata = booking.end_time
|
||||
end
|
||||
b_datas = b_datas[start_index..-1].to_a.map{|b_start,b_end| (b_start..b_end)}
|
||||
else
|
||||
b_datas = [b_sdata..b_edata]
|
||||
end
|
||||
while b_datas.present?
|
||||
sdata = stime_tp
|
||||
edata = etime_tp
|
||||
if etime_tp > booking.start_time
|
||||
if (sdata <= b_sdata && edata >= b_sdata) || (sdata >= b_sdata && edata <= b_edata) || (sdata <= b_edata && edata >= b_edata)
|
||||
available = false
|
||||
end
|
||||
end
|
||||
available = b_datas.find{|b_range| b_range & (stime_tp..etime_tp)}.nil?
|
||||
stime_tp = stime_tp + d_step
|
||||
etime_tp = etime_tp + d_step
|
||||
break if recurring_end_date.blank? || d_step==0 || recurring_end_date < stime_tp
|
||||
end
|
||||
break if !available || recurring_end_date.blank? || d_step==0
|
||||
start_index = b_datas.find_index{|b_range| b_range.first >= stime_tp}
|
||||
if start_index
|
||||
b_datas = b_datas[start_index..-1]
|
||||
else
|
||||
b_datas = []
|
||||
end
|
||||
end
|
||||
break if available == false
|
||||
end
|
||||
end
|
||||
|
|
|
@ -245,42 +245,20 @@
|
|||
<div id="set_unavailibility_div" style="display: none;">
|
||||
<% end %>
|
||||
<div class="control-group">
|
||||
<%= f.label :start_time, t("property_hire.start_time"), :class => "control-label muted" %>
|
||||
<%= f.label :can_hire_before_months, t("property_hire.how_many_months_ago_can_be_hired"), :class => "control-label muted" %>
|
||||
<div class="controls">
|
||||
<%= f.datetime_picker :start_time, :picker_type => "time", :no_label => true, :new_record => @property.new_record?, :value => (Time.parse(@property.start_time) rescue "") %>
|
||||
<%= f.select :can_hire_before_months, options_for_select([[t("property_hire.no_limit"),0]] + (1..12).to_a.map{|month| [t("property_hire.month", month: month), month]},f.object.can_hire_before_months) %>
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<%= f.label :end_time, t("property_hire.end_time"), :class => "control-label muted" %>
|
||||
<div class="controls">
|
||||
<%= f.datetime_picker :end_time, :picker_type => "time", :no_label => true, :new_record => @property.new_record?, :value => (Time.parse(@property.end_time) rescue "") %>
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label class="control-label muted">Weekdays</label>
|
||||
<label class="control-label muted"><%=t("property_hire.weekdays").html_safe%></label>
|
||||
<div class="controls">
|
||||
<% weekdays = @property.weekdays rescue [] %>
|
||||
<label for="sunday">
|
||||
<input id="sunday" type="checkbox" name="property[weekdays][]" value="0" <%= weekdays.include?("0") ? "checked=checked" : "" %> /> Sunday
|
||||
</label>
|
||||
<label for="monday">
|
||||
<input id="monday" type="checkbox" name="property[weekdays][]" value="1" <%= weekdays.include?("1") ? "checked=checked" : "" %> /> Monday
|
||||
</label>
|
||||
<label for="tuesday">
|
||||
<input id="tuesday" type="checkbox" name="property[weekdays][]" value="2" <%= weekdays.include?("2") ? "checked=checked" : "" %> /> Tuesday
|
||||
</label>
|
||||
<label for="wednesday">
|
||||
<input id="wednesday" type="checkbox" name="property[weekdays][]" value="3" <%= weekdays.include?("3") ? "checked=checked" : "" %> /> Wednesday
|
||||
</label>
|
||||
<label for="thursday">
|
||||
<input id="thursday" type="checkbox" name="property[weekdays][]" value="4" <%= weekdays.include?("4") ? "checked=checked" : "" %> /> Thursday
|
||||
</label>
|
||||
<label for="friday">
|
||||
<input id="friday" type="checkbox" name="property[weekdays][]" value="5" <%= weekdays.include?("5") ? "checked=checked" : "" %> /> Friday
|
||||
</label>
|
||||
<label for="saturday">
|
||||
<input id="saturday" type="checkbox" name="property[weekdays][]" value="6" <%= weekdays.include?("6") ? "checked=checked" : "" %> /> Saturday
|
||||
</label>
|
||||
<% Property::WEEKDAYS.each_with_index do |weekday,i| %>
|
||||
<label for="<%=weekday%>">
|
||||
<input id="<%=weekday%>" type="checkbox" name="property[weekdays][]" value="<%=i%>" <%= weekdays.include?(i.to_s) ? "checked=checked" : "" %> /> <% trans = t("property_hire.#{weekday}") %><%= (trans.class == ActiveSupport::SafeBuffer ? weekday : trans) %>
|
||||
</label>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
|
@ -295,6 +273,18 @@
|
|||
<%= f.datetime_picker :end_date, :picker_type => "date", :no_label => true, :new_record => @property.new_record?, :data=>{"picker-type" => "range", "range" => "end"}, :format => "yyyy/MM/dd" %>
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<%= f.label :start_time, t("property_hire.limit_start_time"), :class => "control-label muted" %>
|
||||
<div class="controls">
|
||||
<%= f.datetime_picker :start_time, :picker_type => "time", :no_label => true, :new_record => @property.new_record?, :value => (Time.parse(@property.start_time) rescue "") %>
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<%= f.label :end_time, t("property_hire.limit_end_time"), :class => "control-label muted" %>
|
||||
<div class="controls">
|
||||
<%= f.datetime_picker :end_time, :picker_type => "time", :no_label => true, :new_record => @property.new_record?, :value => (Time.parse(@property.end_time) rescue "") %>
|
||||
</div>
|
||||
</div>
|
||||
<% @site_in_use_locales.each do |locale| %>
|
||||
<%= f.fields_for :description_translations do |f| %>
|
||||
<div class="control-group">
|
||||
|
|
|
@ -0,0 +1,496 @@
|
|||
<style type="text/css">
|
||||
* {
|
||||
-webkit-box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.row{
|
||||
margin-left: 0;
|
||||
}
|
||||
.form-group {
|
||||
margin-bottom: 0.9375em;
|
||||
clear: both;
|
||||
}
|
||||
@media (min-width:768px){
|
||||
.modal-content {
|
||||
-webkit-box-shadow: 0 0.3125em 0.9375em rgb(0 0 0 / 50%);
|
||||
box-shadow: 0 0.3125em 0.9375em rgb(0 0 0 / 50%);
|
||||
}
|
||||
.col-sm-offset-2 {
|
||||
margin-left: 16.66666667%;
|
||||
}
|
||||
.form-horizontal .control-label {
|
||||
padding-top: 0.4375em;
|
||||
margin-bottom: 0;
|
||||
width: auto;
|
||||
text-align: right;
|
||||
}
|
||||
[class*="col-sm"],[class*="col-md"]{
|
||||
float: left;
|
||||
position: relative;
|
||||
min-height: 0.0625em;
|
||||
padding-right: 0.9375em;
|
||||
padding-left: 0.9375em;
|
||||
}
|
||||
.form-horizontal .col-sm-2 {
|
||||
width: 16.66666667%;
|
||||
}
|
||||
.form-horizontal .col-sm-5 {
|
||||
width: 41.66666667%;
|
||||
}
|
||||
.form-horizontal .col-sm-10 {
|
||||
width: 83.33333333%;
|
||||
}
|
||||
.form-horizontal .col-md-4 > * {
|
||||
padding: 0 0.5em;
|
||||
}
|
||||
.form-horizontal .col-md-8 > * {
|
||||
padding: 0 1em;
|
||||
}
|
||||
.form-horizontal .col-md-4{
|
||||
width: 33.3%;
|
||||
}
|
||||
.form-horizontal .col-md-8{
|
||||
width: 66.6%;
|
||||
}
|
||||
}
|
||||
.modal-content {
|
||||
position: relative;
|
||||
background-color: #fff;
|
||||
-webkit-background-clip: padding-box;
|
||||
background-clip: padding-box;
|
||||
border: 0.0625em solid #999;
|
||||
border: 0.0625em solid rgba(0,0,0,.2);
|
||||
border-radius: 0.375em;
|
||||
outline: 0;
|
||||
-webkit-box-shadow: 0 0.1875em 0.5625em rgb(0 0 0 / 50%);
|
||||
box-shadow: 0 0.1875em 0.5625em rgb(0 0 0 / 50%);
|
||||
}
|
||||
.modal-header {
|
||||
padding: 0.9375em;
|
||||
border-bottom: 0.0625em solid #e5e5e5;
|
||||
}
|
||||
.modal-body {
|
||||
position: relative;
|
||||
padding: 0.9375em;
|
||||
max-height: 400px;
|
||||
overflow: initial;
|
||||
}
|
||||
</style>
|
||||
<%= content_for :page_specific_css do %>
|
||||
<% ["basic/bootstrap-datetimepicker.css","property_hire_fullcalendar.css","property_hire_calendar"].each do |css| %>
|
||||
<%= stylesheet_link_tag css %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
<script src="/assets/javascripts/validator.js"></script>
|
||||
<script src="https://polyfill.io/v3/polyfill.min.js?features=Intl.DateTimeFormat,Intl.DateTimeFormat.~locale.en,Intl.NumberFormat.~locale.en"></script>
|
||||
<script type="text/javascript" src="/assets/property_hire_fullcalendar.min.js"></script>
|
||||
<script type="text/javascript" src="/assets/property_hire_calendar_frontend.js"></script>
|
||||
<%
|
||||
hire = @phire
|
||||
property = @phire.property
|
||||
%>
|
||||
<h3><%= property.title %></h3>
|
||||
<% if session["hire-save-msg"].present? %>
|
||||
<div id="property-unavaialable-alert" class="alert alert-danger" role="alert"><b>Sorry! </b><span> <%= session["hire-save-msg"] %></span></div>
|
||||
<% session.delete("hire-save-msg") %>
|
||||
<% end %>
|
||||
<div id="orbit_calendar">
|
||||
<div id="sec1">
|
||||
<div class="btn-toolbar" id="navigation">
|
||||
<div id="calendar-nav">
|
||||
<div class="btn-group">
|
||||
<button class="btn btn-default btn-sm" id="prev_month_btn">
|
||||
<i class="icon-chevron-left"></i>
|
||||
</button>
|
||||
<button class="btn btn-default btn-sm" id="next_month_btn">
|
||||
<i class="icon-chevron-right"></i>
|
||||
</button>
|
||||
<button class="btn btn-default btn-sm" id="today_btn">Today</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-inline" id="range_selection"></div>
|
||||
</div>
|
||||
<div id='sec3' class="btn-toolbar">
|
||||
<div class="btn-group calendar_mode">
|
||||
<button class="btn btn-default mode_switch btn-sm" data-mode="timeGridDay" >day</button>
|
||||
<button class="btn btn-default mode_switch btn-sm" data-mode="timeGridWeek" >week</button>
|
||||
<button class="btn btn-default active mode_switch btn-sm" data-mode="dayGridMonth" >month</button>
|
||||
</div>
|
||||
<button id="refresh_btn" class="btn btn-default btn-sm">
|
||||
<i class="icons-cycle"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div id="view_holder">
|
||||
<h3 id="current_title" class="current_day_title"></h3>
|
||||
<div id="calendar"></div>
|
||||
<div id="calendar_agenda"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="event_quick_view" class="modal" style="width: 300px; display:none; margin:0 0 0 0;"></div>
|
||||
<div id="calendar-loading"></div>
|
||||
<script type="text/javascript">
|
||||
var property_id = "<%= property.id.to_s %>";
|
||||
var calendar = new Calendar("#calendar",property_id);
|
||||
function change_pick(target){
|
||||
if( $(target).attr("id") == "pick_recurring_end_date"){
|
||||
if($('#p_hire_recurring_interval').val() == ""){
|
||||
alert("<%=t("property_hire.please_select_recurring_interval")%>");
|
||||
$('#p_hire_recurring_interval').focus();
|
||||
return;
|
||||
}
|
||||
$("#calendar").data("recurring_interval", $('#p_hire_recurring_interval').val());
|
||||
}
|
||||
$("#hidden_timepicker").addClass("hide");
|
||||
$("#calendar").data("target","#"+$(target).attr("id"));
|
||||
$("#calendar").data("title", $(target).parents(".col-sm-10").prev("label").text().replace("*",""));
|
||||
$("#calendar").addClass("active_picker");
|
||||
document.getElementById("orbit_calendar").scrollIntoView();
|
||||
}
|
||||
$("#calendar").on("select_time",function(ev,date_str){
|
||||
$("#hidden_date").text(date_str);
|
||||
$("#hidden_title").text($("#calendar").data("title"));
|
||||
$('#hidden_timepicker .time_picker').addClass("pull-left");
|
||||
$("#hidden_timepicker").removeClass("hide");
|
||||
var target = $('#timepicker');
|
||||
var window_width = $(window).width();
|
||||
var window_height = $(window).height();
|
||||
var target_offset = target.offset();
|
||||
scrollTo(target_offset.left - window_width / 2, target_offset.top - window_height / 2);
|
||||
$('#timepicker').trigger('focus');
|
||||
})
|
||||
$("#calendar").on("init_time",function(ev,time_str){
|
||||
$('#timepicker').val(time_str);
|
||||
})
|
||||
function set_datetimepicker(){
|
||||
var date_time = $("#hidden_date").text() + " " + $('#timepicker').val();
|
||||
var start_date, end_date, interval = null, recurring_end_date = null;
|
||||
var target = $("#calendar").data("target");
|
||||
if(target == "#pick_start_date"){
|
||||
start_date = date_time;
|
||||
end_date = $("#p_hire_end_time").val();
|
||||
}else if(target == "#pick_end_date"){
|
||||
end_date = date_time;
|
||||
start_date = $("#p_hire_start_time").val();
|
||||
}else if(target == "#pick_recurring_end_date"){
|
||||
start_date = $("#p_hire_start_time").val();
|
||||
end_date = $("#p_hire_end_time").val();
|
||||
interval = $("#p_hire_recurring_interval").val();
|
||||
recurring_end_date = date_time;
|
||||
}
|
||||
end_date = (end_date == "" ? null : end_date);
|
||||
start_date = (start_date == "" ? null : start_date);
|
||||
if(start_date != null && end_date != null && $("#p_hire_start_time").val() != "" && $("#p_hire_end_time").val() != ""){
|
||||
if(start_date > end_date){
|
||||
if(target == "#pick_start_date"){
|
||||
end_date = start_date.split(" ")[0] + " " + end_date.split(" ")[1];
|
||||
$("#p_hire_end_time").val(end_date);
|
||||
}else{
|
||||
start_date = end_date.split(" ")[0] + " " + start_date.split(" ")[1];
|
||||
$("#p_hire_start_time").val(start_date);
|
||||
}
|
||||
}
|
||||
}
|
||||
console.log(start_date)
|
||||
var check_only = (start_date == null || end_date == null);
|
||||
if(check_available(start_date,end_date,interval,recurring_end_date,check_only)){
|
||||
var target = $($("#calendar").data("target"));
|
||||
target.prev().find("input").val(date_time);
|
||||
$("#hidden_timepicker").addClass("hide");
|
||||
$("#calendar").removeClass("active_picker");
|
||||
var window_width = $(window).width();
|
||||
var window_height = $(window).height();
|
||||
var target_offset = target.offset();
|
||||
scrollTo(target_offset.left - window_width / 2, target_offset.top - window_height / 2);
|
||||
}else{
|
||||
if(window.check_message !== ""){
|
||||
alert(window.check_message.replace(/<br>/g,"\n"));
|
||||
}else{
|
||||
alert('<%=t("property_hire.unavailability")%>');
|
||||
}
|
||||
}
|
||||
}
|
||||
function goto_calendar(){
|
||||
$("#hidden_timepicker").addClass("hide");
|
||||
var target = $("#calendar");
|
||||
var window_width = $(window).width();
|
||||
var window_height = $(window).height();
|
||||
var target_offset = target.offset();
|
||||
scrollTo(target_offset.left - window_width / 2, target_offset.top - window_height / 2);
|
||||
}
|
||||
</script>
|
||||
<div id="hidden_timepicker" class="hide">
|
||||
<span id="hidden_title" class="pull-left" style="margin-right: 1em;font-weight: bold;"></span>
|
||||
<div style="display: grid;">
|
||||
<span id="hidden_date" class="pull-left" style="margin-right: 1em;"></span>
|
||||
<%= fields_for :timepicker do |f|%>
|
||||
<%= f.time_picker :timepicker, :no_label => true, :new_record => hire.new_record?,:format=>"HH:mm", :class => "pull-left", :data=>{"picker-type" => "range", "range" => "end", "fv-validation" => "required;", "fv-messages" => "Cannot be empty;"} %>
|
||||
<% end %>
|
||||
<div class="pull-left btn-group" style="margin-top: 0.5em;">
|
||||
<button id="confirm_date" class="btn btn-primary btn-sm" style="margin-right: 0.5em;" onclick="set_datetimepicker()"><%=t("property_hire.confirm")%></button>
|
||||
<button id="cancel_date" class="btn btn-primary btn-sm" onclick="goto_calendar()"><%=t("property_hire.cancel")%></button>
|
||||
</div>
|
||||
</div>
|
||||
<div style="clear: both;"></div>
|
||||
<hr>
|
||||
</div>
|
||||
<%= form_for hire, :url => update_hire_admin_property_hire_path(hire), html: { class: "form-horizontal" } do |f| %>
|
||||
<div class="form-group">
|
||||
<%= f.label :start_time, "*"+t("property_hire.start_time"), :class => "col-sm-2 control-label" %>
|
||||
<div class="col-sm-10">
|
||||
<%= f.datetime_picker :start_time, :no_label => true, :new_record => hire.new_record?,: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>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<%= f.label :end_time, "*"+t("property_hire.end_time"), :class => "col-sm-2 control-label" %>
|
||||
<div class="col-sm-10">
|
||||
<%= f.datetime_picker :end_time, :no_label => true, :new_record => hire.new_record?,:class => "pull-left", :data=>{"picker-type" => "range", "range" => "end", "fv-validation" => "required;", "fv-messages" => "Cannot be empty;"} %>
|
||||
<button type="button" id="pick_end_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>
|
||||
</div>
|
||||
<!-- ############# recurring ############# -->
|
||||
<div class="form-group">
|
||||
<%= f.label :recurring, t("property_hire.recurring"), :class => "col-sm-2 control-label" %>
|
||||
<div class="col-sm-1">
|
||||
<%= f.check_box :recurring %>
|
||||
</div>
|
||||
</div>
|
||||
<div id="recurring-block" <%= hire.recurring ? "" : "style=display:none;" %>>
|
||||
<div class="form-group">
|
||||
<%= f.label :recurring_interval, t("property_hire.recurring_interval"), :class => "col-sm-2 control-label" %>
|
||||
<div class="col-sm-1">
|
||||
<%= f.select :recurring_interval, PHire::INTERVALS.collect{|int| [t("property_hire.recurring_interval_types.#{int}"), int] }, {:prompt => t('property_hire.select_interval')}, {:data => {"fv-validation" => "requiredifrecurring;" , "fv-messages" => "Cannot be empty;"}} %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<%= f.label :recurring_end_date, "*"+t("property_hire.recurring_end_date"), :class => "col-sm-2 control-label" %>
|
||||
<div class="col-sm-10">
|
||||
<%= f.datetime_picker :recurring_end_date, :no_label => true, :new_record => hire.new_record?, :class=>"pull-left", :data=>{"fv-validation" => "requiredifrecurring;", "fv-messages" => "Cannot be empty;"} %>
|
||||
<button type="button" id="pick_recurring_end_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>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="col-sm-offset-2 col-sm-5">
|
||||
<div id="property-avaialable-alert" style="margin-bottom: 5px; padding: 10px; display: none;" class="alert alert-success" role="alert"><b>Hooray! </b>This property is available.</div>
|
||||
<div id="property-unavaialable-alert" style="margin-bottom: 5px; padding: 10px; display: none;" class="alert alert-danger" role="alert"><b>Sorry! </b><span> This property is available.</span></div>
|
||||
<div id="values-alert" style="margin-bottom: 5px; padding: 10px; display: none;" class="alert alert-warning" role="alert">
|
||||
<% hint1 = t("property_hire.please_select_recurring_interval_and_recurring_end_time",:default=>"") %>
|
||||
<% if hint1 == ""%>
|
||||
<b>Please! </b><span> Select an interval time and recurring event end date.</span>
|
||||
<% else %>
|
||||
<span><b><%=hint1%></b></span>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
<% if property.set_unavailibility %>
|
||||
<div class="col-sm-offset-2 col-sm-5">
|
||||
<b><%= t("property_hire.Unavailibility_Schedule") %></b>
|
||||
<div>
|
||||
<%= property.render_unavailable_message%>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="" class="col-sm-2 control-label"></label>
|
||||
<div class="col-sm-10">
|
||||
<a href="/xhr/property_hires/check_availability" id="check-avail-btn" class="btn btn-primary"><%= t('property_hire.check_availibility') %></a>
|
||||
<img style="display: none;" width="40" src="/assets/spin.gif" id="spinner" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<%= f.label :hiring_person_email, "*"+t("property_hire.hiring_person_email"), :class => "col-sm-2 control-label" %>
|
||||
<div class="col-sm-5">
|
||||
<%= f.text_field :hiring_person_email, :class => "form-control", :value => current_user.member_profile.email, :data => {"fv-validation" => "required;", "fv-messages" => "Cannot be empty;"} %>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<%= f.label :hiring_person_number, "*"+t("property_hire.hiring_person_number"), :class => "col-sm-2 control-label" %>
|
||||
<div class="col-sm-5">
|
||||
<%= f.text_field :hiring_person_number, :class => "form-control", :data => {"fv-validation" => "required;", "fv-messages" => "Cannot be empty;"} %>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<%= f.label :hiring_person_name, "*"+t("property_hire.hiring_person_name"), :class => "col-sm-2 control-label" %>
|
||||
<div class="col-sm-5">
|
||||
<%= f.text_field :hiring_person_name, :class => "form-control", :value => (current_user.name rescue ""), :data => {"fv-validation" => "required;", "fv-messages" => "Cannot be empty;"} %>
|
||||
<%= f.hidden_field :hiring_person_id, :value => (current_user.member_profile.id.to_s rescue "") %>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<%= f.label :reason_for_hire, "*"+t("property_hire.reason_for_hire"), :class => "col-sm-2 control-label" %>
|
||||
<div class="col-sm-5">
|
||||
<%= f.text_field :reason_for_hire, :class => "form-control", :data => {"fv-validation" => "required;", "fv-messages" => "Cannot be empty;"} %>
|
||||
</div>
|
||||
</div>
|
||||
<% if(property.enable_notes_selector rescue false) %>
|
||||
<% property.notes_selector.each do |index,sub_hash| %>
|
||||
<% name = sub_hash["name"][I18n.locale.to_s] %>
|
||||
<% name = sub_hash["name"].values.select{|v| v.present?}.first.to_s if name.blank? %>
|
||||
<% values = sub_hash["value"][I18n.locale.to_s] %>
|
||||
<% values = sub_hash["value"].values.select{|v| v.present?}.first.to_s if values.blank? %>
|
||||
<% type = sub_hash["type"] %>
|
||||
<div class="form-group">
|
||||
<%= f.label "notes_selector[#{index}]", name, :class => "col-sm-2 control-label" %>
|
||||
<div class="col-sm-5">
|
||||
<% values.each_with_index do |v,i| %>
|
||||
<label class="checkbox-inline">
|
||||
<input type="<%=type%>" name="p_hire[notes_selector][<%=index.to_s%>][]" value="<%=i%>" <%= (type=="radio" && i == 0) ? "checked=\"checked\"" : "" %>>
|
||||
<%=v%>
|
||||
</label>
|
||||
<% end %>
|
||||
<% if type == "checkbox" && (values.count > 1) %>
|
||||
<small class="help-block"><%= t("property_hire.checkbox_hint") %></small>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
<% else %>
|
||||
<div class="form-group">
|
||||
<%= f.label :note_for_hire, t("property_hire.note_for_hire"), :class => "col-sm-2 control-label" %>
|
||||
<div class="col-sm-5">
|
||||
<%= f.text_area :note_for_hire, :class => "form-control" %>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
<% fields_name = ["organization" ,"person_in_charge" , "tel_of_person_in_charge" , "department" , "contact_person" , "tel_of_contact_person" , "mobile_phone_of_contact_person" , "contact_person_Email" , "contact_person_department"] %>
|
||||
<% fields_name.each do |field_name| %>
|
||||
<% if(property[field_name]["enable"] == "1" rescue false) %>
|
||||
<% required = (property[field_name]["required"] == "true" rescue false) %>
|
||||
<div class="form-group">
|
||||
<%= f.label field_name, (required ? "*" : "") + t("property_hire.#{field_name}"), :class => "col-sm-2 control-label" %>
|
||||
<div class="col-sm-5">
|
||||
<% if required %>
|
||||
<%= f.text_field field_name, :class => "form-control", :data => {"fv-validation" => "required;", "fv-messages" => "Cannot be empty;"} %>
|
||||
<% else %>
|
||||
<%= f.text_field field_name, :class => "form-control" %>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
<% end %>
|
||||
<div class="form-group">
|
||||
<div class="col-sm-offset-2 col-sm-10">
|
||||
<%= f.submit t("property_hire.save"), :class => "btn btn-primary" %>
|
||||
<%= f.hidden_field :property_id, :value => property.id %>
|
||||
<input type="hidden" id="dates_validated" name="dates_validated" value="0" data-fv-validation="checkForDates;" data-fv-messages="Please make sure first if dates are available.;">
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
<div style="height: 50px;"></div>
|
||||
<script type="text/javascript">
|
||||
var property_id = "<%= property.id.to_s %>";
|
||||
var check_available = function(stime,etime,interval,recurring_end_date,check_only,property_id){
|
||||
var el = $("#check-avail-btn"),
|
||||
url = $("#check-avail-btn").attr("href"),
|
||||
spinner = $("#spinner");
|
||||
stime = stime || etime;
|
||||
etime = etime || stime;
|
||||
property_id = property_id || window.property_id;
|
||||
var timezone = new Date().toString().match(/([-\+][0-9]+)\s/)[1];
|
||||
data = {
|
||||
"stime": stime,
|
||||
"etime": etime,
|
||||
"property_id": property_id,
|
||||
"locale": "<%=I18n.locale%>",
|
||||
"timezone": timezone,
|
||||
"phire_id": "<%=hire.id%>"
|
||||
}
|
||||
data["interval"] = interval;
|
||||
data["recurring_end_date"] = recurring_end_date;
|
||||
var flag = false;
|
||||
window.check_message = "";
|
||||
$.ajax({
|
||||
"url" : url,
|
||||
"type" : "get",
|
||||
"data" : data,
|
||||
"dataType" : "json",
|
||||
"async": false
|
||||
}).done(function(data){
|
||||
if(data.success){
|
||||
$("#dates_validated").val("1");
|
||||
$("#property-unavaialable-alert").hide();
|
||||
flag = true;
|
||||
if(!check_only){
|
||||
$("#property-avaialable-alert").show();
|
||||
}
|
||||
}else{
|
||||
$("#dates_validated").val("0");
|
||||
$("#property-avaialable-alert").hide();
|
||||
window.check_message = data.msg;
|
||||
window.check_message = window.check_message.replace(/{(.*)}/,function(v){
|
||||
return getDateString(new Date(RegExp.$1),datetime_format,is_chinese);
|
||||
})
|
||||
if(!check_only){
|
||||
$("#property-unavaialable-alert").find("span").html(window.check_message);
|
||||
$("#property-unavaialable-alert").show();
|
||||
}
|
||||
}
|
||||
spinner.hide();
|
||||
el.show();
|
||||
})
|
||||
return flag;
|
||||
}
|
||||
$("#check-avail-btn").on("click",function(){
|
||||
var el = $(this),
|
||||
url = $(this).attr("href"),
|
||||
spinner = $("#spinner");
|
||||
$(".alert").hide();
|
||||
var stime = $("#p_hire_start_time").val(),
|
||||
etime = $("#p_hire_end_time").val();
|
||||
var interval = null, recurring_end_date = null, is_recurring = false;;
|
||||
if($("#p_hire_recurring").is(":checked")){
|
||||
is_recurring = true;
|
||||
interval = $("#p_hire_recurring_interval").val(),
|
||||
recurring_end_date = $("#p_hire_recurring_end_date").val();
|
||||
if(interval == "" || recurring_end_date == ""){
|
||||
$("#values-alert").show();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
spinner.show();
|
||||
el.hide();
|
||||
check_available(stime,etime,interval,recurring_end_date);
|
||||
return false;
|
||||
})
|
||||
|
||||
$("#unavailable-schedule").on("click",function(){
|
||||
|
||||
})
|
||||
|
||||
var hireForm = new FormValidator($("#new_p_hire"));
|
||||
hireForm.validate_functions.checkForDates = function(value,element){
|
||||
return value == "1";
|
||||
}
|
||||
hireForm.validate_functions.requiredifrecurring = function(value, element){
|
||||
if($("#p_hire_recurring").is(":checked")){
|
||||
return value != "";
|
||||
}else{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
$("#p_hire_recurring").on("click",function(){
|
||||
$("#dates_validated").val("0");
|
||||
$("#property-avaialable-alert").hide();
|
||||
$("#property-unavaialable-alert").hide();
|
||||
|
||||
if($(this).is(":checked")){
|
||||
$("#recurring-block").slideDown();
|
||||
}else{
|
||||
$("#recurring-block").slideUp();
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -1,4 +1,80 @@
|
|||
<%= csrf_meta_tag %>
|
||||
<div class="pull-right">
|
||||
<a href="?type=" class="btn <%= 'active' if params[:type] != 'Calendar' %>">Table</a>
|
||||
<a href="?type=Calendar" class="btn <%= 'active' if params[:type] == 'Calendar' %>">Calendar</a>
|
||||
</div>
|
||||
<hr>
|
||||
<% if params[:type] == "Calendar" %>
|
||||
<style type="text/css">
|
||||
.row{
|
||||
margin-left: 0;
|
||||
}
|
||||
@media (min-width:768px){
|
||||
.col-md-4 > * {
|
||||
padding: 0 0.5em;
|
||||
}
|
||||
.col-md-8 > * {
|
||||
padding: 0 1em;
|
||||
}
|
||||
.col-md-4{
|
||||
float: left;
|
||||
width: 33.3%;
|
||||
}
|
||||
.col-md-8{
|
||||
float: left;
|
||||
width: 66.6%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<%= content_for :page_specific_css do %>
|
||||
<% ["basic/bootstrap-datetimepicker.css","property_hire_fullcalendar.css","property_hire_calendar"].each do |css| %>
|
||||
<%= stylesheet_link_tag css %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
<script src="https://polyfill.io/v3/polyfill.min.js?features=Intl.DateTimeFormat,Intl.DateTimeFormat.~locale.en,Intl.NumberFormat.~locale.en"></script>
|
||||
<script type="text/javascript" src="/assets/property_hire_fullcalendar.min.js"></script>
|
||||
<script type="text/javascript" src="/assets/property_hire_calendar_frontend.js"></script>
|
||||
<div id="orbit_calendar">
|
||||
<div id="sec1">
|
||||
<div class="btn-toolbar" id="navigation">
|
||||
<div id="calendar-nav">
|
||||
<div class="btn-group">
|
||||
<button class="btn btn-default btn-sm" id="prev_month_btn">
|
||||
<i class="icon-chevron-left"></i>
|
||||
</button>
|
||||
<button class="btn btn-default btn-sm" id="next_month_btn">
|
||||
<i class="icon-chevron-right"></i>
|
||||
</button>
|
||||
<button class="btn btn-default btn-sm" id="today_btn">Today</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-inline" id="range_selection"></div>
|
||||
</div>
|
||||
<div id='sec3' class="btn-toolbar">
|
||||
<div class="btn-group calendar_mode">
|
||||
<button class="btn btn-default mode_switch btn-sm" data-mode="timeGridDay" >day</button>
|
||||
<button class="btn btn-default mode_switch btn-sm" data-mode="timeGridWeek" >week</button>
|
||||
<button class="btn btn-default mode_switch btn-sm" data-mode="dayGridMonth" >month</button>
|
||||
<button class="btn btn-default active mode_switch btn-sm" data-mode="agenda" >agenda</button>
|
||||
</div>
|
||||
<button id="refresh_btn" class="btn btn-default btn-sm">
|
||||
<i class="icons-cycle"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div id="view_holder">
|
||||
<h3 id="current_title" class="current_day_title"></h3>
|
||||
<div id="calendar"></div>
|
||||
<div id="calendar_agenda"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="event_quick_view" class="modal" style="width: 300px; display:none; margin:0 0 0 0;"></div>
|
||||
<div id="calendar-loading"></div>
|
||||
<script type="text/javascript">
|
||||
var property_id = "<%= @property.id.to_s %>";
|
||||
var calendar = new Calendar("#calendar",property_id,"agenda");
|
||||
</script>
|
||||
<% else %>
|
||||
<table class="table main-list">
|
||||
<thead>
|
||||
<tr class="sort-header">
|
||||
|
@ -31,6 +107,7 @@
|
|||
</td>
|
||||
<td>
|
||||
<% if can_edit_or_delete?(p_hire.property) %>
|
||||
<a href="<%= edit_hire_admin_property_hire_path(p_hire) %>" class="btn btn-info">Edit</a>
|
||||
<a href="<%= show_booking_details_admin_property_hire_path(p_hire, :page => params[:page]) %>" class="btn btn-info">View</a>
|
||||
<% if p_hire.passed %>
|
||||
<a href="<%= pass_booking_admin_property_hire_path(p_hire, :page => params[:page], :status => "reject", :ref => "index") %>" class="btn btn-warning">Reject</a>
|
||||
|
@ -47,4 +124,5 @@
|
|||
<div class="bottomnav clearfix">
|
||||
<a href="<%= admin_property_hires_path %>" class="btn btn-warning">Back</a>
|
||||
<%= content_tag(:div, paginate(@bookings), class: "pagination pagination-centered") %>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
|
@ -59,6 +59,7 @@
|
|||
</table>
|
||||
<a href="" onclick="window.history.back();return false;" class="btn btn-warning">Back</a>
|
||||
<% if can_edit_or_delete?(@booking.property) %>
|
||||
<a href="<%= edit_hire_admin_property_hire_path(@booking) %>" class="btn btn-info">Edit</a>
|
||||
<% if @booking.passed %>
|
||||
<a href="<%= pass_booking_admin_property_hire_path(@booking, :status => "reject") %>" class="btn btn-warning">Reject</a>
|
||||
<% else %>
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
<% OrbitHelper.render_css_in_head(["basic/bootstrap-datetimepicker.css"]) %>
|
||||
<%= javascript_include_tag "lib/bootstrap-datetimepicker" %>
|
||||
<%= javascript_include_tag "lib/datetimepicker/datetimepicker.js" %>
|
||||
<% OrbitHelper.render_css_in_head(["basic/bootstrap-datetimepicker.css","property_hire_fullcalendar.css","property_hire_calendar.scss"]) %>
|
||||
<%= javascript_include_tag "validator.js" %>
|
||||
<script src="https://polyfill.io/v3/polyfill.min.js?features=Intl.DateTimeFormat,Intl.DateTimeFormat.~locale.en,Intl.NumberFormat.~locale.en"></script>
|
||||
<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
|
||||
hire = data["hire"]
|
||||
|
@ -26,17 +27,159 @@
|
|||
<div id="property-unavaialable-alert" class="alert alert-danger" role="alert"><b>Sorry! </b><span> <%= session["hire-save-msg"] %></span></div>
|
||||
<% session.delete("hire-save-msg") %>
|
||||
<% end %>
|
||||
<div id="orbit_calendar">
|
||||
<div id="sec1">
|
||||
<div class="btn-toolbar" id="navigation">
|
||||
<div id="calendar-nav">
|
||||
<div class="btn-group">
|
||||
<button class="btn btn-default btn-sm" id="prev_month_btn">
|
||||
<i class="icon-chevron-left"></i>
|
||||
</button>
|
||||
<button class="btn btn-default btn-sm" id="next_month_btn">
|
||||
<i class="icon-chevron-right"></i>
|
||||
</button>
|
||||
<button class="btn btn-default btn-sm" id="today_btn">Today</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-inline" id="range_selection"></div>
|
||||
</div>
|
||||
<div id='sec3' class="btn-toolbar">
|
||||
<div class="btn-group calendar_mode">
|
||||
<button class="btn btn-default mode_switch btn-sm" data-mode="timeGridDay" >day</button>
|
||||
<button class="btn btn-default mode_switch btn-sm" data-mode="timeGridWeek" >week</button>
|
||||
<button class="btn btn-default active mode_switch btn-sm" data-mode="dayGridMonth" >month</button>
|
||||
</div>
|
||||
<button id="refresh_btn" class="btn btn-default btn-sm">
|
||||
<i class="icons-cycle"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div id="view_holder">
|
||||
<h3 id="current_title" class="current_day_title"></h3>
|
||||
<div id="calendar"></div>
|
||||
<div id="calendar_agenda"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="event_quick_view" class="modal" style="width: 300px; display:none; margin:0 0 0 0;"></div>
|
||||
<div id="calendar-loading"></div>
|
||||
<script type="text/javascript">
|
||||
var property_id = "<%= property.id.to_s %>";
|
||||
var calendar = new Calendar("#calendar",property_id);
|
||||
function change_pick(target){
|
||||
if( $(target).attr("id") == "pick_recurring_end_date"){
|
||||
if($('#p_hire_recurring_interval').val() == ""){
|
||||
alert("<%=t("property_hire.please_select_recurring_interval")%>");
|
||||
$('#p_hire_recurring_interval').focus();
|
||||
return;
|
||||
}
|
||||
$("#calendar").data("recurring_interval", $('#p_hire_recurring_interval').val());
|
||||
}
|
||||
$("#hidden_timepicker").addClass("hide");
|
||||
$("#calendar").data("target","#"+$(target).attr("id"));
|
||||
$("#calendar").data("title", $(target).parents(".col-sm-10").prev("label").text().replace("*",""));
|
||||
$("#calendar").addClass("active_picker");
|
||||
document.getElementById("main-content").scrollIntoView();
|
||||
}
|
||||
$("#calendar").on("select_time",function(ev,date_str){
|
||||
$("#hidden_date").text(date_str);
|
||||
$("#hidden_title").text($("#calendar").data("title"));
|
||||
$('#hidden_timepicker .time_picker').addClass("pull-left");
|
||||
$("#hidden_timepicker").removeClass("hide");
|
||||
var target = $('#timepicker');
|
||||
var window_width = $(window).width();
|
||||
var window_height = $(window).height();
|
||||
var target_offset = target.offset();
|
||||
scrollTo(target_offset.left - window_width / 2, target_offset.top - window_height / 2);
|
||||
$('#timepicker').trigger('focus');
|
||||
})
|
||||
$("#calendar").on("init_time",function(ev,time_str){
|
||||
$('#timepicker').val(time_str);
|
||||
})
|
||||
function set_datetimepicker(){
|
||||
var date_time = $("#hidden_date").text() + " " + $('#timepicker').val();
|
||||
var start_date, end_date, interval = null, recurring_end_date = null;
|
||||
var target = $("#calendar").data("target");
|
||||
if(target == "#pick_start_date"){
|
||||
start_date = date_time;
|
||||
end_date = $("#p_hire_end_time").val();
|
||||
}else if(target == "#pick_end_date"){
|
||||
end_date = date_time;
|
||||
start_date = $("#p_hire_start_time").val();
|
||||
}else if(target == "#pick_recurring_end_date"){
|
||||
start_date = $("#p_hire_start_time").val();
|
||||
end_date = $("#p_hire_end_time").val();
|
||||
interval = $("#p_hire_recurring_interval").val();
|
||||
recurring_end_date = date_time;
|
||||
}
|
||||
end_date = (end_date == "" ? null : end_date);
|
||||
start_date = (start_date == "" ? null : start_date);
|
||||
if(start_date != null && end_date != null && $("#p_hire_start_time").val() != "" && $("#p_hire_end_time").val() != ""){
|
||||
if(start_date > end_date){
|
||||
if(target == "#pick_start_date"){
|
||||
end_date = start_date.split(" ")[0] + " " + end_date.split(" ")[1];
|
||||
$("#p_hire_end_time").val(end_date);
|
||||
}else{
|
||||
start_date = end_date.split(" ")[0] + " " + start_date.split(" ")[1];
|
||||
$("#p_hire_start_time").val(start_date);
|
||||
}
|
||||
}
|
||||
}
|
||||
console.log(start_date)
|
||||
var check_only = (start_date == null || end_date == null);
|
||||
if(check_available(start_date,end_date,interval,recurring_end_date,check_only)){
|
||||
var target = $($("#calendar").data("target"));
|
||||
target.prev().find("input").val(date_time);
|
||||
$("#hidden_timepicker").addClass("hide");
|
||||
$("#calendar").removeClass("active_picker");
|
||||
var window_width = $(window).width();
|
||||
var window_height = $(window).height();
|
||||
var target_offset = target.offset();
|
||||
scrollTo(target_offset.left - window_width / 2, target_offset.top - window_height / 2);
|
||||
}else{
|
||||
if(window.check_message !== ""){
|
||||
alert(window.check_message.replace(/<br>/g,"\n"));
|
||||
}else{
|
||||
alert('<%=t("property_hire.unavailability")%>');
|
||||
}
|
||||
}
|
||||
}
|
||||
function goto_calendar(){
|
||||
$("#hidden_timepicker").addClass("hide");
|
||||
var target = $("#calendar");
|
||||
var window_width = $(window).width();
|
||||
var window_height = $(window).height();
|
||||
var target_offset = target.offset();
|
||||
scrollTo(target_offset.left - window_width / 2, target_offset.top - window_height / 2);
|
||||
}
|
||||
</script>
|
||||
<div id="hidden_timepicker" class="hide">
|
||||
<span id="hidden_title" class="pull-left" style="margin-right: 1em;font-weight: bold;"></span>
|
||||
<div style="display: grid;">
|
||||
<span id="hidden_date" class="pull-left" style="margin-right: 1em;"></span>
|
||||
<%= fields_for :timepicker do |f|%>
|
||||
<%= f.time_picker :timepicker, :no_label => true, :new_record => hire.new_record?,:format=>"HH:mm", :class => "pull-left", :data=>{"picker-type" => "range", "range" => "end", "fv-validation" => "required;", "fv-messages" => "Cannot be empty;"} %>
|
||||
<% end %>
|
||||
<div class="pull-left btn-group" style="margin-top: 0.5em;">
|
||||
<button id="confirm_date" class="btn btn-primary btn-sm" style="margin-right: 0.5em;" onclick="set_datetimepicker()"><%=t("property_hire.confirm")%></button>
|
||||
<button id="cancel_date" class="btn btn-primary btn-sm" onclick="goto_calendar()"><%=t("property_hire.cancel")%></button>
|
||||
</div>
|
||||
</div>
|
||||
<div style="clear: both;"></div>
|
||||
<hr>
|
||||
</div>
|
||||
<%= form_for hire, :url => "/xhr/property_hires/make_booking", html: { class: "form-horizontal" } do |f| %>
|
||||
<div class="form-group">
|
||||
<%= f.label :start_time, "*"+t("property_hire.start_time"), :class => "col-sm-2 control-label" %>
|
||||
<div class="col-sm-10">
|
||||
<%= f.datetime_picker :start_time, :no_label => true, :new_record => hire.new_record?, :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?,: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>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<%= f.label :end_time, "*"+t("property_hire.end_time"), :class => "col-sm-2 control-label" %>
|
||||
<div class="col-sm-10">
|
||||
<%= f.datetime_picker :end_time, :no_label => true, :new_record => hire.new_record?, :data=>{"picker-type" => "range", "range" => "end", "fv-validation" => "required;", "fv-messages" => "Cannot be empty;"} %>
|
||||
<%= f.datetime_picker :end_time, :no_label => true, :new_record => hire.new_record?,:class => "pull-left", :data=>{"picker-type" => "range", "range" => "end", "fv-validation" => "required;", "fv-messages" => "Cannot be empty;"} %>
|
||||
<button type="button" id="pick_end_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>
|
||||
</div>
|
||||
<!-- ############# recurring ############# -->
|
||||
|
@ -57,7 +200,8 @@
|
|||
<div class="form-group">
|
||||
<%= f.label :recurring_end_date, "*"+t("property_hire.recurring_end_date"), :class => "col-sm-2 control-label" %>
|
||||
<div class="col-sm-10">
|
||||
<%= f.datetime_picker :recurring_end_date, :no_label => true, :new_record => hire.new_record?, :data=>{"fv-validation" => "requiredifrecurring;", "fv-messages" => "Cannot be empty;"} %>
|
||||
<%= f.datetime_picker :recurring_end_date, :no_label => true, :new_record => hire.new_record?, :class=>"pull-left", :data=>{"fv-validation" => "requiredifrecurring;", "fv-messages" => "Cannot be empty;"} %>
|
||||
<button type="button" id="pick_recurring_end_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>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -66,21 +210,20 @@
|
|||
<div class="col-sm-offset-2 col-sm-5">
|
||||
<div id="property-avaialable-alert" style="margin-bottom: 5px; padding: 10px; display: none;" class="alert alert-success" role="alert"><b>Hooray! </b>This property is available.</div>
|
||||
<div id="property-unavaialable-alert" style="margin-bottom: 5px; padding: 10px; display: none;" class="alert alert-danger" role="alert"><b>Sorry! </b><span> This property is available.</span></div>
|
||||
<div id="values-alert" style="margin-bottom: 5px; padding: 10px; display: none;" class="alert alert-warning" role="alert"><b>Please! </b><span> Select an interval time and recurring event end date.</span></div>
|
||||
<div id="values-alert" style="margin-bottom: 5px; padding: 10px; display: none;" class="alert alert-warning" role="alert">
|
||||
<% hint1 = t("property_hire.please_select_recurring_interval_and_recurring_end_time",:default=>"") %>
|
||||
<% if hint1 == ""%>
|
||||
<b>Please! </b><span> Select an interval time and recurring event end date.</span>
|
||||
<% else %>
|
||||
<span><b><%=hint1%></b></span>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
<% if property.set_unavailibility %>
|
||||
<div class="col-sm-offset-2 col-sm-5">
|
||||
<b><%= t("property_hire.Unavailibility_Schedule") %></b>
|
||||
<div>
|
||||
This property is unavaliable <%= !property.start_date.nil? ? " from " + property.start_date.strftime("%Y-%m-%d") : "" %> <%= !property.end_date.nil? ? " to " + property.end_date.strftime("%Y-%m-%d") : "" %> every
|
||||
<% property.weekdays.each_with_index do |d,i| %>
|
||||
<% if i < (property.weekdays.count - 1) %>
|
||||
<%= Property::WEEKDAYS[d.to_i] + ", " %>
|
||||
<% else %>
|
||||
<%= Property::WEEKDAYS[d.to_i] %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
between <%= property.start_time %> & <%= property.end_time %>.
|
||||
<%= property.render_unavailable_message%>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
|
@ -176,45 +319,76 @@
|
|||
<div style="height: 50px;"></div>
|
||||
<script type="text/javascript">
|
||||
var property_id = "<%= property.id.to_s %>";
|
||||
var check_available = function(stime,etime,interval,recurring_end_date,check_only,property_id){
|
||||
var el = $("#check-avail-btn"),
|
||||
url = $("#check-avail-btn").attr("href"),
|
||||
spinner = $("#spinner");
|
||||
stime = stime || etime;
|
||||
etime = etime || stime;
|
||||
property_id = property_id || window.property_id;
|
||||
var timezone = new Date().toString().match(/([-\+][0-9]+)\s/)[1];
|
||||
data = {
|
||||
"stime": stime,
|
||||
"etime": etime,
|
||||
"property_id": property_id,
|
||||
"locale": "<%=I18n.locale%>",
|
||||
"timezone": timezone
|
||||
}
|
||||
data["interval"] = interval;
|
||||
data["recurring_end_date"] = recurring_end_date;
|
||||
var flag = false;
|
||||
window.check_message = "";
|
||||
$.ajax({
|
||||
"url" : url,
|
||||
"type" : "get",
|
||||
"data" : data,
|
||||
"dataType" : "json",
|
||||
"async": false
|
||||
}).done(function(data){
|
||||
if(data.success){
|
||||
$("#dates_validated").val("1");
|
||||
$("#property-unavaialable-alert").hide();
|
||||
flag = true;
|
||||
if(!check_only){
|
||||
$("#property-avaialable-alert").show();
|
||||
}
|
||||
}else{
|
||||
$("#dates_validated").val("0");
|
||||
$("#property-avaialable-alert").hide();
|
||||
window.check_message = data.msg;
|
||||
window.check_message = window.check_message.replace(/{(.*)}/,function(v){
|
||||
return getDateString(new Date(RegExp.$1),datetime_format,is_chinese);
|
||||
})
|
||||
if(!check_only){
|
||||
$("#property-unavaialable-alert").find("span").html(window.check_message);
|
||||
$("#property-unavaialable-alert").show();
|
||||
}
|
||||
}
|
||||
spinner.hide();
|
||||
el.show();
|
||||
})
|
||||
return flag;
|
||||
}
|
||||
$("#check-avail-btn").on("click",function(){
|
||||
var el = $(this),
|
||||
url = $(this).attr("href"),
|
||||
spinner = $("#spinner");
|
||||
|
||||
$(".alert").hide();
|
||||
data = {
|
||||
"stime" : $("#p_hire_start_time").val(),
|
||||
"etime" : $("#p_hire_end_time").val(),
|
||||
"property_id" : property_id
|
||||
}
|
||||
var stime = $("#p_hire_start_time").val(),
|
||||
etime = $("#p_hire_end_time").val();
|
||||
var interval = null, recurring_end_date = null, is_recurring = false;;
|
||||
if($("#p_hire_recurring").is(":checked")){
|
||||
var interval = $("#p_hire_recurring_interval").val(),
|
||||
recurring_end_date = $("#p_hire_recurring_end_date").val();
|
||||
is_recurring = true;
|
||||
interval = $("#p_hire_recurring_interval").val(),
|
||||
recurring_end_date = $("#p_hire_recurring_end_date").val();
|
||||
if(interval == "" || recurring_end_date == ""){
|
||||
$("#values-alert").show();
|
||||
return false;
|
||||
}
|
||||
data["interval"] = interval;
|
||||
data["recurring_end_date"] = recurring_end_date;
|
||||
}
|
||||
spinner.show();
|
||||
el.hide();
|
||||
$.ajax({
|
||||
"url" : url,
|
||||
"type" : "get",
|
||||
"data" : data,
|
||||
"dataType" : "json"
|
||||
}).done(function(data){
|
||||
if(data.success){
|
||||
$("#property-avaialable-alert").show();
|
||||
$("#dates_validated").val("1");
|
||||
}else{
|
||||
$("#property-unavaialable-alert").find("span").text(data.msg);
|
||||
$("#property-unavaialable-alert").show();
|
||||
}
|
||||
spinner.hide();
|
||||
el.show();
|
||||
})
|
||||
check_available(stime,etime,interval,recurring_end_date);
|
||||
return false;
|
||||
})
|
||||
|
||||
|
@ -235,6 +409,10 @@
|
|||
}
|
||||
|
||||
$("#p_hire_recurring").on("click",function(){
|
||||
$("#dates_validated").val("0");
|
||||
$("#property-avaialable-alert").hide();
|
||||
$("#property-unavaialable-alert").hide();
|
||||
|
||||
if($(this).is(":checked")){
|
||||
$("#recurring-block").slideDown();
|
||||
}else{
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
<% OrbitHelper.render_css_in_head(["property_hire_fullcalendar.css","property_hire_calendar.scss"]) %>
|
||||
<script src="https://polyfill.io/v3/polyfill.min.js?features=Intl.DateTimeFormat,Intl.DateTimeFormat.~locale.en,Intl.NumberFormat.~locale.en"></script>
|
||||
<script type="text/javascript" src="//code.jquery.com/ui/1.10.3/jquery-ui.js"></script>
|
||||
<script type="text/javascript" src="/assets/property_hire_fullcalendar.min.js"></script>
|
||||
<script type="text/javascript" src="/assets/property_hire_calendar_frontend.js"></script>
|
||||
|
@ -33,9 +34,9 @@
|
|||
</div>
|
||||
<div id='sec3' class="btn-toolbar">
|
||||
<div class="btn-group calendar_mode">
|
||||
<button class="btn btn-default mode_switch btn-sm" data-mode="agendaDay" >day</button>
|
||||
<button class="btn btn-default mode_switch btn-sm" data-mode="agendaWeek" >week</button>
|
||||
<button class="btn btn-default active mode_switch btn-sm" data-mode="month" >month</button>
|
||||
<button class="btn btn-default mode_switch btn-sm" data-mode="timeGridDay" >day</button>
|
||||
<button class="btn btn-default mode_switch btn-sm" data-mode="timeGridWeek" >week</button>
|
||||
<button class="btn btn-default active mode_switch btn-sm" data-mode="dayGridMonth" >month</button>
|
||||
</div>
|
||||
<button id="refresh_btn" class="btn btn-default btn-sm">
|
||||
<i class="icons-cycle"></i>
|
||||
|
|
|
@ -1,5 +1,16 @@
|
|||
en:
|
||||
property_hire:
|
||||
please_hire_after_date: "Please hire after %{date}!"
|
||||
property_is_unavailable_during_this_time: "Property is unavailable during this time."
|
||||
property_is_already_hired_during_this_time: "Property is already hired during this time."
|
||||
starting_time_cannot_be_greater_than_ending_time: "Starting time cannot be greater than ending time."
|
||||
please_select_recurring_interval: "Please select recurring interval!"
|
||||
confirm: Confirm
|
||||
cancel: Cancel
|
||||
pick_from_calendar: Pick from calendar
|
||||
how_many_months_ago_can_be_hired: "How many months ago can be hired?"
|
||||
month: "%{month} month"
|
||||
no_limit: No limit
|
||||
none: None
|
||||
checkbox_hint: You Can Select Mulitple Places
|
||||
add_choice: Add choice
|
||||
|
@ -51,9 +62,11 @@ en:
|
|||
owner_phone: Owner Phone
|
||||
price: Price
|
||||
set_unavailibility: Set Unavailability
|
||||
limit_start_time: Limit start time
|
||||
limit_end_time: Limit end time
|
||||
start_time: Start Time
|
||||
end_time: End Time
|
||||
weekdays: Weekdays
|
||||
weekdays: Unavailability weekdays
|
||||
start_date: From Date
|
||||
end_date: To Date
|
||||
description: Unavailability Description
|
||||
|
|
|
@ -1,5 +1,39 @@
|
|||
zh_tw:
|
||||
property_hire:
|
||||
recurring_end_date_must_exceed_time: "週期結束時間需超過借用結束時間%{time}!"
|
||||
1_week: "一週"
|
||||
1_month: "一個月"
|
||||
values_are_not_ok: "借用開始時間和結束時間不可為空"
|
||||
dot: " 、 "
|
||||
from: " 從 "
|
||||
to: " 到 "
|
||||
of: "的"
|
||||
at: "在"
|
||||
from_time: "從%{time}開始"
|
||||
from_now_on: "從現在起"
|
||||
every: 每個
|
||||
time1_to_time2: "%{time1}到%{time2}之間"
|
||||
unavailable_hint1: "此地點或設備%{str1}%{str2}%{week_str}%{str3}為不可借用。"
|
||||
unavailable_hint2: "此地點或設備在%{month}個月之前不可借用。"
|
||||
Sunday: 週日
|
||||
Monday: 週一
|
||||
Tuesday: 週二
|
||||
Wednesday: 週三
|
||||
Thursday: 週四
|
||||
Friday: 週五
|
||||
Saturday: 週六
|
||||
please_hire_after_date: "請在%{date}之後再借用!"
|
||||
property_is_unavailable_during_this_time: "該時段不可借用。"
|
||||
property_is_already_hired_during_this_time: "該時段已被借用,請再選擇其他時段!"
|
||||
starting_time_cannot_be_greater_than_ending_time: "借用開始時間不能超過借用結束時間!"
|
||||
please_select_recurring_interval: "請選擇借用週期!"
|
||||
please_select_recurring_interval_and_recurring_end_time: "請選擇借用週期和週期結束時間"
|
||||
confirm: 確認
|
||||
cancel: 取消
|
||||
pick_from_calendar: 從日曆上選擇
|
||||
how_many_months_ago_can_be_hired: 多少個月內才可被借用
|
||||
month: "%{month}月"
|
||||
no_limit: 無限制
|
||||
none: 無
|
||||
checkbox_hint: 可重複勾選
|
||||
add_choice: 新增選項
|
||||
|
@ -53,11 +87,11 @@ zh_tw:
|
|||
owner_phone: 管理人聯絡電話
|
||||
price: Price
|
||||
set_unavailibility: 設定為不可借用
|
||||
start_time: 借用開始時間
|
||||
end_time: 借用結束時間
|
||||
weekdays: Weekdays
|
||||
start_date: From Date
|
||||
end_date: To Date
|
||||
start_time: 可被借用開始時間
|
||||
end_time: 可被借用結束時間
|
||||
weekdays: 不可借用工作日
|
||||
start_date: 套用限制開始日期
|
||||
end_date: 套用限制結束日期
|
||||
description: Unavailability Description
|
||||
unavailibility_note: Unavailability Note
|
||||
property_location: Property Location
|
||||
|
@ -66,6 +100,8 @@ zh_tw:
|
|||
view_calendar: 查詢目前借用狀況
|
||||
image: Property Image
|
||||
actions: 操作
|
||||
limit_start_time: 限制開始時間
|
||||
limit_end_time: 限制結束時間
|
||||
start_time: 借用開始時間
|
||||
end_time: 借用結束時間
|
||||
hiring_person_email: 借用人電子信箱
|
||||
|
|
|
@ -14,6 +14,8 @@ Rails.application.routes.draw do
|
|||
get "show_booking_details"
|
||||
get "pass_booking"
|
||||
delete "delete_booking_details"
|
||||
get "edit_hire"
|
||||
patch "update_hire"
|
||||
end
|
||||
collection do
|
||||
get "my_bookings"
|
||||
|
|
Loading…
Reference in New Issue