(function ($) { $(function () { // http://davidwalsh.name/javascript-debounce-function function debounce(func, wait, immediate) { var timeout; return function () { var context = this, args = arguments; var later = function () { timeout = null; if (!immediate) func.apply(context, args); }; var callNow = immediate && !timeout; clearTimeout(timeout); timeout = setTimeout(later, wait); if (callNow) func.apply(context, args); }; }; /*____________________________________________________________________________________*/ class People{ constructor(selector, template, data){ this.selector = selector; this.data = data; this.template = template; // this.sample_people = { // login: '01515b52-6936-46b2-a000-9ad4cd7a5b50', // firstname: "first", // lastname: "last", // phone: '041122221', // email: 'abc@gmail.com', // pay: 0, // hour: 12, // OT: 3, // petrol: 50, // rating: 1, // }; this.load_data(this.data); } load_data(data){ var template = $(this.template).html(); var html = Mustache.render(template, data); $(this.selector).html(html); //save it $(this.selector).data({obj:this, data:data}); //draw rating star this.set_ratings(this.data.rating); this.set_unconfirmed_job(this.data.unconfirmedjob); } set_ratings(num){ for (var i=1; i<= 5; i++){ if (i <=num){ $(this.selector + " div[name='rating'] span:nth-child(" +i+ ")").addClass('checked'); }else{ $(this.selector + " div[name='rating'] span:nth-child(" +i+ ")").removeClass('checked'); } } this.data.rating = num; } set_unconfirmed_job(num){ if( num == 0 ) $(this.selector + " span[name='badge']").hide(); else $(this.selector + " span[name='badge']").show(); this.data.unconfirmedjob = num; } reset_summary() { this.summary = { wages : 0, normal_hour : 0, ot_hour : 0, petrol : 0, }; this.update_summary_in_gui(); } add_payment_summary(ps) { //{ot: false, hour: "2.67", money: "76.90"} this.summary.wages += ps.money; if (! ps.ot ) this.summary.normal_hour += ps.hour; else this.summary.ot_hour += ps.hour; this.update_summary_in_gui(); } update_summary_in_gui() { var msg = '$' + this.summary.wages.toFixed(2); $(this.selector).find('div[name="wages"]').html(msg); msg = this.summary.normal_hour.toFixed(2) + '+' +this.summary.ot_hour.toFixed(2) + 'hr'; $(this.selector).find('div[name="hours"]').html(msg); msg = 'petrol:' + this.summary.petrol.toFixed(2) + 'km'; $(this.selector).find('div[name="petrol"]').html(msg); } }//end of class People function bts_staff_html(data){ var template = $('#staff_item').html(); var head = '
'; r = head + '
' ; return r; } function bts_client_html(data){ var template = $('#client_item').html(); var head = '
'; r = head + '
' ; return r; } function sample_staff(){ for (var i=1; i<100; i++){ var sample_people = { login: '01515b52-6936-46b2-a000-9ad4cd7a5b50' +i, firstname: "first"+i, lastname: "last", mobile: '041122221' +i, email: 'abc@gmail.com' + i, wages: 0, hour: i, OT: 3, petrol: 50 +i, rating: Math.floor(Math.random() * Math.floor(5)), unconfirmedjob: Math.floor(Math.random() * Math.floor(30)), }; var html = bts_staff_html(sample_people); jQuery('div.stafflist').append(html); new People("#p" + sample_people.login, sample_people); } } function list_staff() { show_loading_staff(); $('div.stafflist div.peopleitem').remove(); $.post(bts().ajax_url, { // POST request _ajax_nonce: bts().nonce, // nonce action: "list_staff", // action }).done(function(response, status, xhr){ if (response.status =='success'){ bts().staff = response.users; response.users.forEach(function(u){ var html = bts_staff_html(u); jQuery('div.stafflist').append(html); new People("#p" + u.login,'#staff_item', u); }); hide_loading_staff(); calculate_total_hour_and_money(); }else{ alert('error getting staff list'); } }); } function list_clients() { show_loading_client(); $('div.clientlist div.peopleitem').remove(); //clear it $.post(bts().ajax_url, { // POST request _ajax_nonce: bts().nonce, // nonce action: "list_client", // action }, function(response, status, xhr){ if (response.status =='success'){ bts().client = response.users; response.users.forEach(function(u){ hide_loading_client(); var html = bts_client_html(u); jQuery('div.clientlist').append(html); new People("#p" + u.login, '#client_item' ,u); }); }else{ alert('error getting Client list'); } }); } function show_loading_staff(){ jQuery('div.stafflist img').attr('src', bts().load_user_img).show(); } function show_loading_client(){ jQuery('div.clientlist img').attr('src', bts().load_user_img).show(); } function hide_loading_staff(){ jQuery('div.stafflist img').hide(); } function hide_loading_client(){ jQuery('div.clientlist img').hide(); } function show_loading_jobs(){ jQuery('div.workspace img').attr('src', bts().load_job_img).show(); } function hide_loading_jobs(){ jQuery('div.workspace img').hide(); } function xero(t){ if (t) $('div.xero i').show(); else $('div.xero i').hide(); } function wifi(t){ if (t) $('div.wifi i').show(); else $('div.wifi i').hide(); } function csv(t){ if (t) $('div.csv i').show(); else $('div.csv i').hide(); } function init_user_search(){ $('div.b_search input').keyup(debounce(function(e){ filter_user(e.target); }, 500)); } function filter_user(input){ var value = $(input).attr('value'); value = value.toLowerCase(); var selector = get_selector_for_filter_people(input); $.each( $(selector).find('div.peopleitem'), function(index, e){ //uncheck everyone $(e).find('input[type="checkbox"]').prop('checked', false); var html = $(e).find('div[name="title"] a').html(); html = html.toLowerCase(); if (-1 != html.indexOf(value)){//we find it; $(e).show(); }else{ $(e).hide(); } }); } function get_selector_for_filter_people(input){ var selector=''; var role = $(input).attr('placeholder'); if (role == 'staff') //we filter staff selector = 'div.stafflist'; else if (role = 'client') selector = 'div.clientlist'; return selector; } $(document).on('click', 'div.divTableHead.bdelete', function(){ add_new_empty_job(); }); function add_new_empty_job(){ var o = new Job({empty:true}); $('div.workspace').append(o.el); o.el.get(0).scrollIntoView(); dtp_init(); } $(document).on('click', 'div[name="copyschedule"]', function(e){ e.stopPropagation(); add_new_empty_job(); }); $(document).on('click', 'div.divTableCell.bdelete', function(){ var job = $(this).closest('.divTable').data().job; var el = $(this).closest('div.divTable'); if ( job.get_job_id() == '') el.remove(); else{ if (confirm('delete this job?')){ $.post(bts().ajax_url, { // POST request _ajax_nonce: bts().nonce, // nonce action: "delete_job", // action jobid: job.data.id, }, function(response, status, xhr){ if (response.status=='success'){ el.addClass('blink_me'); el.fadeOut(900); setTimeout(function(){ el.remove(); }, 900); }else{ alert( 'error saving data, please check your network'); } }); } } }); $(document).on('mouseenter', 'div.divTableCell', function(){ $(this).closest('div.divTable').addClass('highlight'); }); $(document).on('mouseleave', 'div.divTableCell', function(){ $(this).closest('div.divTable').removeClass('highlight'); }); $(document).on('click', 'div.workspace span.ticon.ticon-save', function(){ var table = $(this).closest('div.divTable'); table.data().job.do_save_record(); }); $(document).on('click', '.divTableHeading span.ticon.ticon-save', function(){ //save all $('div.workspace span.ticon.ticon-save').each(function (i,e){ if ($(this).is(":visible")) $(this).trigger('click'); }); }); $(document).on('click', 'span.ticon.ticon-copy', function(){ if (!confirm("make a copy of this job?")) return; var table = $(this).closest('div.divTable'); var job = table.data().job; var newj = clone_data_create_new_job(job.get_record_from_ui()); $('div.workspace').append(newj.el); newj.el.get(0).scrollIntoView();//make sure it's visible; newj.mark_highlight_me(1000);//for 1 second; dtp_init(); }); class Job{ //save data for the record, and display it as GUI constructor(data){ var html = jQuery("#job_item").html(); this.el = $(html); //jQuery('div.workspace').append(this.el); this.load_data(data); this.init_start_rating(); } init_start_rating(){ var self = this; this.el.find("div.brating span").click(function(){ var r = $(this).attr('data-rating'); self.mark_dirty(); self.set_rating(r); }) this.el.find("div.brating").mouseenter(function(){ //change to all hollow star $(this).find('span').html('☆'); }); this.el.find("div.brating").mouseleave(function(){ self.set_rating(self.data.rating); }); } load_data(data) { //save to html element this.data = data; this.el.data({job:this, data:data}); //draw GUI this.clear_err_msg(); this.set_job_id(data.id); this.set_tos(data.tos); this.set_start(data.start); this.set_finish(data.finish); this.set_rate(data.rate); this.set_staff(data.staff); this.set_client(data.client); this.set_ack(data.ack); this.set_rating(data.rating); //draw GUI by other this.mark_dirty_on_new_record(data); this.mark_week_color(); this.validate(); //also triggers mark errors } get_job_id(){ return this.el.find('input[name="id"]').attr('value'); } set_job_id(val){ return this.el.find('input[name="id"]').attr('value', val); } get_tos() { return this.el.find('div.btos select').children("option:selected").val(); } set_tos(val) { if (typeof(val) =="undefined") return; this.el.find('div.btos select option[value="'+val+'"]').prop('selected',true); } get_start(){ return this.el.find('div.bstart input').attr('value'); } set_start(val) { if (typeof(val) =="undefined") return; this.el.find('div.bstart input').attr('value', val); } get_finish() { return this.el.find('div.bfinish input').attr('value'); } set_finish(val) { if (typeof(val) == "undefined") return; this.el.find('div.bfinish input').attr('value', val); } get_rate() { return this.el.find('div.brate select').children("option:selected").val(); } set_rate(val) { if (typeof(val) =="undefined") return; this.el.find('div.brate select option[value="'+val+'"]').prop('selected',true); } get_staff() { return this.el.find('div.bstaff select').children("option:selected").val(); } set_staff(val) { if (typeof(val) =="undefined") return; this.el.find('div.bstaff select option[value="'+val+'"]').prop('selected',true); } get_client() { return this.el.find('div.bclient select').children("option:selected").val(); } set_client(val) { if (typeof(val) =="undefined") return; this.el.find('div.bclient select option[value="'+val+'"]').prop('selected',true); } get_ack() { return this.el.find('div.bconfirmed input:checked').length > 0; } set_ack(val) { if (typeof(val) =="undefined") return; return this.el.find('div.bconfirmed input').prop('checked', val!=0); } get_rating(){ var count =0; this.el.find('div.brating span').each(function(i,e){ if ($(e).html()=='★') count +=1; }); return count; } set_rating(num){ if (!(1 <= num && num <=5)) return; this.el.find('div.brating span').each(function(i,e){ var rating = $(e).attr('data-rating'); var rating = parseInt(rating); if (rating <= num) $(e).html('★'); else $(e).html('☆'); }); } get_record_from_ui(){ var record = {}; record.id = this.get_job_id(); record.tos = this.get_tos(); record.start = this.get_start(); record.finish = this.get_finish(); record.rate = this.get_rate(); record.staff = this.get_staff(); record.client = this.get_client(); record.ack = this.get_ack(); record.rating = this.get_rating(); return record; } do_save_record(){ var self = this; $.post(bts().ajax_url, { // POST request _ajax_nonce: bts().nonce, // nonce action: "save_job", // action record: this.get_record_from_ui(), }, function(response, status, xhr){ if (response.status=='success'){ self.load_data(response.newdata); self.mark_saved(); self.mark_old(); }else{ alert( 'error saving data, please check your network'); } }); } mark_dirty_on_new_record(data){ if (typeof(data.id) === 'undefined' || data.id == ''){ this.mark_dirty(); this.mark_new(); } else{ this.mark_saved(); } } mark_dirty() //need save { var d = this.el.find('.bsave'); d.removeClass('saved'); d.addClass('blink_me'); setTimeout(function(){ d.removeClass('blink_me'); d.removeClass('saved'); },1000); } mark_saved() { var d = this.el.find('.bsave'); d.addClass('blink_me'); setTimeout(function(){ d.removeClass('blink_me'); d.addClass('saved'); },1000); } //newly created empty record mark_new() { this.el.addClass('emptyrecord'); } mark_old() { this.el.removeClass('emptyrecord'); } mark_highlight_me(ms){ this.el.addClass('blink_me'); this.el.addClass('highlight'); this.el.addClass('newcopy'); var self = this; setTimeout(function(){ self.el.removeClass('blink_me'); self.el.removeClass('highlight'); self.el.removeClass('newcopy'); },ms); } is_start_valid(){ var s = this.get_start(); return is_valid_date_str(s); } is_finish_valid(){ var f = this.get_finish(); if (!is_valid_date_str(f)) return false; } is_finish_resonable(){ var f = this.get_finish(); if (!is_valid_date_str(f)) return false; var s = this.get_start(); s = new Date(s); f = new Date(f); return (s < f); } validate() { var ok_time = this.validate_start() && this.validate_finish(); //finish might not be executed, if start is wrong var ok_tos = this.validate_tos(); //make sure this validate is executed; var ok_rate = this.validate_rate() ; //make sure this validate is executed var ok = ok_time && ok_tos && ok_rate; if (ok){ this.el.removeClass('invalidjob'); }else{ this.el.addClass('invalidjob'); } return ok; } validate_start(){ var str = this.get_start(); if ( is_valid_date_str(str) ){ this.mark_start_valid(); this.set_err_msg_start(''); return true; }else{ this.mark_start_invalid(); this.set_err_msg_start('wrong date'); return false; } } validate_finish() { var str = this.get_finish(); if (! is_valid_date_str(str)){ this.set_err_msg_finish('wrong date'); this.mark_finish_invalid(); return false; } if (!this.is_finish_resonable()){ this.set_err_msg_finish("older than start") this.mark_finish_invalid(); return false; } this.mark_finish_valid(); this.set_err_msg_finish(''); return true; } validate_rate() { var rate_info = this.get_rate_info_by_id(this.get_rate()); if ( rate_info.RatePerUnit <= 0){ this.set_err_msg_rate('bad rate'); this.mark_rate_invalid(); return false; } // if (this.get_rate() != this.data.rate){ // this.set_err_msg_rate('rate@Xero inactive ' + this.data.rate); // this.mark_rate_invalid(); // this.mark_dirty(); // return false; // } this.set_err_msg_rate(''); this.mark_rate_valid(); return true; } validate_tos(){ // if (this.get_tos() != this.data.tos){ // this.set_err_msg_tos('require NDIS ' + this.data.tos); // this.mark_tos_invalid(); // this.mark_dirty(); // console.log('tos mark dirty'); // return false; // } this.set_err_msg_tos(''); this.mark_tos_valid(); return true; } clear_err_msg(){ this.el.find('.divTableRow.errmsg > div').html(''); } set_err_msg_start(str) { this.el.find('div.bstart_err').html(str); } set_err_msg_finish(str) { this.el.find('div.bfinish_err').html(str); } set_err_msg_rate(str) { this.el.find('div.brate_err').html(str); } set_err_msg_save(str) { this.el.find('div.bsave_err').html(str); } set_err_msg_tos(str) { this.el.find('div.btos_err').html(str); } mark_tos_valid(){ this.el.find('div.btos select').removeClass('invalid'); } mark_tos_invalid(){ this.el.find('div.btos select').addClass('invalid'); } mark_start_valid(){ this.el.find('div.bstart input').removeClass('invalid'); } mark_start_invalid(){ this.el.find('div.bstart input').addClass('invalid'); } mark_finish_valid(){ this.el.find('div.bfinish input').removeClass('invalid'); } mark_finish_invalid(){ this.el.find('div.bfinish input').addClass('invalid'); } mark_rate_valid(){ this.el.find('div.brate select').removeClass('invalid'); } mark_rate_invalid(){ this.el.find('div.brate select').addClass('invalid'); } mark_week_color(){ this.el.find('div.brating').removeClass('week1color'); this.el.find('div.brating').removeClass('week2color'); if (this.is_week1()){ this.el.find('div.brating').addClass('week1color'); }else if (this.is_week2()){ this.el.find('div.brating').addClass('week2color'); } } is_week1() { var w1_begin = new Date($('span[name="w1d1"]').data().date) ; var w1_end = new Date($('span[name="w1d7"]').data().date); w1_begin.setHours(0,0,0,0); w1_end.setHours(23,59,59); //console.log("week1 begin %o, end %o", w1_begin, w1_end); //w1_end = new Date (w1_end.setDate(w1_end.getDate()+1)); //from 00:00 to 23:59; var me = new Date(this.data.start); return (w1_begin <= me && me <= w1_end ); } is_week2() { var w2_begin = new Date($('span[name="w2d1"]').data().date); var w2_end = new Date($('span[name="w2d7"]').data().date); w2_begin.setHours(0,0,0,0); w2_end.setHours(23,59,59); var me = new Date(this.data.start); return (w2_begin <= me && me <= w2_end ); } get_payment_summary(){ var result ={}; result.ot = this.get_is_high_pay(); result.hour = this.get_working_duration(); result.money = this.get_wages(); return result; } get_is_high_pay() { var rate_info = this.get_rate_info_by_id(this.get_rate()); return this.is_high_pay_hour(rate_info); } get_working_duration() { //finish - start var f = new Date(this.get_finish()); var s = new Date(this.get_start()); var diff = f.getTime() - s.getTime(); var hours = Math.floor(diff / 1000 / 60 / 60); diff -= hours * 1000 * 60 * 60; var minutes = Math.floor(diff / 1000 / 60); var minute_to_hour = minutes/60; return (hours + minute_to_hour); } get_wages(){ var hour = this.get_working_duration(); var rate_info = this.get_rate_info_by_id(this.get_rate()); return hour * rate_info.RatePerUnit; } get_rate_info_by_id(id){ var rate_info = {}; var rates = bts().earnings_rate; for(var i =0; i< rates.length; i++){ var r = rates[i]; if(r.EarningsRateID == id){ rate_info = $.extend(true,{}, r);//make a copy break; } } return rate_info; } is_high_pay_hour(rate_info){ var keywords =bts().high_pay_keywords; var found = false; keywords.forEach(function(e){ if (-1 != rate_info.Name.toLowerCase().indexOf(e.toLowerCase()) ) found = true; }); return found; } }//end of class Job //global GUI summary function get_wages() { var txt = $('div.wages div').html(); return parseInt(txt); } function set_wages(num){ $('div.wages div').html(num); } function set_working_hours(num){ $('input#woh').attr('value', num); } function get_working_hours(){ var txt = $('input#woh').attr('value'); return parseFloat(txt); } //modal box function set_modal_title(selector, title){ var s = 'div.bts_'+ selector +' .ult_modal-title'; $(s).html(title); } function set_modal_content(selector, content){ var s = 'div.bts_'+ selector +' div.ult_modal-body.ult-html'; $(s).html(content); } function open_modal (selector){ var s='div.bts_'+selector+'_button'; $(s).trigger('click'); } // setTimeout(function(){ // set_modal_title('warning', 'suck title'); // set_modal_content('warning', 'fucking details'); // //open_modal('warning'); // }, 1000); // // setTimeout(function(){ // set_modal_title('error', 'error title'); // set_modal_content('error', 'error details'); // //open_modal('error'); // }, 5000); $(document).on('mouseenter', 'div.week1 div', function(){ $(this).addClass('blink_me'); get_week2_partner(this).addClass('blink_me'); blink_same_date_by_div(this); }); $(document).on('mouseleave', 'div.week1 div', function(){ $(this).removeClass('blink_me'); get_week2_partner(this).removeClass('blink_me'); unblink_all_date(); }); function get_week2_partner(div){ var index = $(div).index()+1; return $('div.week2 div:nth-child('+index+')'); } function init_weekdays(){ var curr = new Date; // get current date init_weekdays_by_anchor(curr, true); return; } function init_weekdays_by_anchor(anchor, is_week1){ var curr = new Date(anchor); // get the date; if (!is_week1){ //it is week2, shift for 7 days; curr.setDate(curr.getDate() -7); //curr will be changed; } var first = curr.getDate() - curr.getDay() + 1; //+1 we want Mon as first var last = first + 6; // last day is the first day + 6 if (curr.getDay() == 0 ){// it's Sunday; last = curr.getDate(); first = last - 6; } var pos = 1; //first lot for (var i=first; i<=last; i++) { var now = new Date(curr); var d1 = new Date(now.setDate(i)); now = new Date(curr); var d2 = new Date(now.setDate(i+7)); set_day_number(1,pos, d1); //week 1 set_day_number(2,pos, d2); //week 2 pos +=1; } } function set_day_number(week, index, date){ var selector = 'span[name="w'+week+'d'+index+'"]'; $(selector).html(date.getDate()); $(selector).data({date:date}); //console.log('set w%d-d%d %o', week,index,date); } function set_today(){ var selector = 'div.sheettitle span[name="today"]'; var curr = new Date; $(selector).html(format_date(curr)); } Date.prototype.get_week_number = function(){ var d = new Date(Date.UTC(this.getFullYear(), this.getMonth(), this.getDate())); var dayNum = d.getUTCDay() || 7; d.setUTCDate(d.getUTCDate() + 4 - dayNum); var yearStart = new Date(Date.UTC(d.getUTCFullYear(),0,1)); return Math.ceil((((d - yearStart) / 86400000) + 1)/7) }; function set_week_number(){ var date = $('span[name="w1d1"]').data().date; //console.log("date %o", date); var num = date.get_week_number(); $('div.weekly span[name="week1"]').html(num); $('div.weekly span[name="week2"]').html(num+1); set_week_boundry(); } function set_week_boundry() { var date = $('span[name="w1d1"]').data().date; $('#week1b').attr('value', format_date(date)); var date = $('span[name="w2d7"]').data().date; $('#week2b').attr('value', format_date(date)); } function number_of_unsaved_job(){ var count =0; var total_job = $('div.bsave').length -1;//remove table header var total_saved = $('div.bsave.saved').length; var empty = $('div.emptyrecord').length; count = total_job - total_saved - empty; return count; } $('div.prevweek.left').click(function(){ if (number_of_unsaved_job() > 0){ if(!confirm("you have unsaved jobs, proceed will lost them")) return; } $('div.weekdays span.weekday').each(function(i, e){ var date = $(e).data().date; var newdate = new Date(date.setDate(date.getDate() -7 )); $(e).html(newdate.getDate()); $(e).data({data:newdate}); }); set_week_number(); debounced_load_timesheet(); }); $('div.nextweek.right').click(function(){ if (number_of_unsaved_job() > 0){ if(!confirm("you have unsaved jobs,proceed will lost them")) return; } $('div.weekdays span.weekday').each(function(i, e){ var date = $(e).data().date; var newdate = new Date(date.setDate(date.getDate() +7 )); $(e).html(newdate.getDate()); $(e).data({data:newdate}); }); set_week_number(); debounced_load_timesheet(); }); $('div.weekly div.weekname.prev >input ').click(function(e){ e.stopPropagation(); }); $('div.weekly div.weekname.prev >input ').change(function(e){ var date = $('#week1b').attr('value'); init_weekdays_by_anchor(date, true); set_week_number(); debounced_load_timesheet(); }); $('div.weekly div.weekname.prev').click(function(){ if (!confirm ('copy entire week to next week? ')) return; var jobs = []; var job_els =[]; $('div.week1 >div').each(function(i,e){ var date = new Date($(e).find('span.weekday').data().date); var strDate = format_date(date); //yyyy-mm-dd $('div.bstart input').each(function(i,e){ var value = $(e).attr('value'); if( -1 != value.indexOf(strDate) ) //found { var el = $(e).closest('div.divTable'); if (el.is(":visible")){ var j = el.data().job; var newj = clone_data_create_new_job(j.get_record_from_ui(),7);//add 7 days job_els.push(newj.el); } } }); }); show_jobs(job_els); debounced_calculate(); }); $('div.weekly div.weekname.next > input').click(function(e){ e.stopPropagation(); }); $('div.weekly div.weekname.next >input ').change(function(e){ e.stopPropagation(); var date = $('#week2b').attr('value'); init_weekdays_by_anchor(date, false); set_week_number(); debounced_load_timesheet(); }); $('div.weekly div.weekname.next').click(function(e){ $(e).find('input').trigger('click'); }); $('div.week1 > div').click(function(e){ e.stopPropagation(); if ($('div.bstart input.blink_me').length == 0){ alert("nothing to copy"); return; } if (!confirm ('copy to next week')) return; var jobs_el = []; $('div.bstart input.blink_me').each(function(i,e){ var r = copy_single_day_to_next_week(e); if (r != false) jobs_el.push(r.el); }); show_jobs(jobs_el); unblink_all_date(); }); $('div.week1,div.week2').click(function(e){ e.stopPropagation(); $(this).toggleClass('filtered'); do_filter_workspace(); }); function copy_single_day_to_next_week(el){ var tb = $(el).closest('div.divTable'); if (tb.is(':visible')){ var j = $(tb).data().job; var newj = clone_data_create_new_job(j.get_record_from_ui() , 7); // +7 days return newj; } return false; } function clone_data_create_new_job(val, num_of_shifted_days){ var data = $.extend(true, {}, val);//make a copy num_of_shifted_days = typeof num_of_shifted_days !=='undefined'? num_of_shifted_days: 0;// 0 days //reset data.id=''; data.ack = 0; data.rating = 0; if (is_valid_date_str(data.start)){ var s = new Date(data.start); var s1 = s.getDate() + num_of_shifted_days; s = new Date(s.setDate(s1)); data.start = format_date_time(s); } if (is_valid_date_str(data.finish)){ var f = new Date(data.finish); var f1 = f.getDate() + num_of_shifted_days; f = new Date(f.setDate(f1)); data.finish = format_date_time(f); } var newj = new Job(data); return newj; } function is_valid_date_str(val){ var d = new Date(val); if (d.toString()== 'Invalid Date') return false; return true; } function blink_same_date_by_div(div){ var date = new Date($(div).find('span.weekday').data().date); blink_same_date(date); } function blink_same_date(date){ var strDate = format_date(date); //yyyy-mm-dd var els=[]; unblink_all_date(); $('div.bstart input').each(function(i,e){ if ( $(e).is(":visible") ){ var value = $(e).attr('value'); if( -1 != value.indexOf(strDate) ) //found { els.push(e); $(e).addClass('blink_me'); } } }); } function unblink_all_date(){ $('div.bstart input').removeClass('blink_me'); } $('div.sheettitle h1 span').click(function(){ reset_title_to_today(); load_timesheet(); }); function reset_title_to_today(){ set_today(); init_weekdays(); set_week_number(); } var debounced_load_timesheet = debounce(load_timesheet,1000); function load_timesheet() { clear_workspace(); var first = $('span[name="w1d1"]').data().date; var last = $('span[name="w2d7"]').data().date; $.post(bts().ajax_url, { // POST request _ajax_nonce: bts().nonce, // nonce action: "list_job", // action start: format_date(first), finish: format_date(last), }, function(response, status, xhr){ if (response.status =='success'){ var job_els = []; response.jobs.forEach(function(job){ //console.log('loading job... %o', job); var o = new Job(job); job_els.push(o.el); }); show_jobs(job_els, 'in-ajax=true'); //filter it if reqired debounced_filter_workspace(); }else{ alert('error loading job'); } hide_loading_jobs(); }); } function show_jobs(job_els, in_ajax){ if (job_els.length >0){ $('div.workspace').append(job_els); job_els[0].get(0).scrollIntoView(); console.log('loading ... %d jobs', job_els.length); } if (typeof in_ajax =='undefined') dtp_init(); } function format_date(date){ var dd = date.getDate(); var mm = date.getMonth() + 1; //January is 0! var yyyy = date.getFullYear(); if (dd < 10) { dd = '0' + dd; } if (mm < 10) { mm = '0' + mm; } return yyyy + '-' + mm + '-' +dd ; } function format_date_time(date){ var strdate = format_date(date); var hh = date.getHours(); if (hh<10){ hh= '0' + hh; } var mm = date.getMinutes(); if (mm<10){ mm='0' + mm; } return strdate + ' ' + hh + ":" + mm; } function clear_workspace()//clear all timesheet jobs { $('div.workspace > div.divTable').remove(); //clear datetime picker $('div.xdsoft_datetimepicker').remove(); // show_loading_jobs(); } $('div.workinghours').click(function(){ $('div.bts_message_button').trigger('click'); }); $('button[name="confirmschedule"]').click(function(){ if (!confirm('sending email to each staff for their job arrangement?')) return; $('div.bts_message .ult-overlay-close-inside').hide(); $('div.bts_message_button').trigger('click'); setTimeout(do_email_jobs, 2000);//2 seconds for dialog to popup }); $('button[name="confirmschedule"]').mouseenter(function(){ $('div.week2').addClass('blink_me'); }) $('button[name="confirmschedule"]').mouseleave(function(){ $('div.week2').removeClass('blink_me'); }) var debounced_filter_workspace = debounce(do_filter_workspace, 1000); $(document).on('click','div.userlist', debounced_filter_workspace); function do_filter_workspace(){ var staffs =[]; $('div.stafflist div.peopleitem :checked').each(function(i, e){ if ($(e).parent().is(':visible')){ var id = $(e).parent().attr('data-id'); //console.log("%o, id=%s", e, id); staffs.push(id.substring(1)); } }); var clients =[]; $('div.clientlist div.peopleitem :checked').each(function(i, e){ if ($(e).parent().is(':visible')){ var id = $(e).parent().attr('data-id'); //console.log("%o, id=%s", e, id); clients.push(id.substring(1)); } }); filter_workspace(staffs, clients); filter_workspace_by_weeks(); debounced_calculate(); } function filter_workspace(staffs, clients){ //if both array is empty if( (staffs === undefined || staffs.length ==0) && (clients===undefined || clients.length ==0)){ //show all $('div.workspace div.divTable').show(); return; } //if staffs is empty, we only filter by client if (staffs === undefined || staffs.length ==0){ filter_workspace_by_client(clients); return; } //if clients is empty, we only filter by staff if (clients===undefined || clients.length ==0){ filter_workspace_by_staff(staffs); return; } //filter by both filter_workspace_by_both(staffs, clients); } function filter_workspace_by_staff(staffs) { //filter some of them; $('div.workspace div.divTable').each(function(i,e){ var job = $(e).data().job; var s = job.get_staff(); if (staffs.indexOf(s) ==-1) $(this).fadeOut(); else $(this).fadeIn(); }); } function filter_workspace_by_client(clients) { //filter some of them; $('div.workspace div.divTable').each(function(i,e){ var job = $(e).data().job; var c = job.get_client(); if (clients.indexOf(c) ==-1) $(this).fadeOut(); else $(this).fadeIn(); }); } function filter_workspace_by_both(staffs, clients) { //filter some of them; $('div.workspace div.divTable').each(function(i,e){ var job = $(e).data().job; var s = job.get_staff(); var c = job.get_client(); if (staffs.indexOf(s) ==-1 || clients.indexOf(c) ==-1) $(this).fadeOut(); else $(this).fadeIn(); }); } function filter_workspace_by_weeks(){ var hide_week1 = $('div.week1').hasClass('filtered'); var hide_week2 = $('div.week2').hasClass('filtered'); if (hide_week1 && hide_week2 ){ alert("You are hiding both weeks"); } $('div.workspace div.divTable').each(function(i,e){ var job = $(e).data().job; if ((hide_week1 && job.is_week1()) || (hide_week2 && job.is_week2()) ){ $(e).fadeOut(); } }); } var debounced_calculate = debounce(calculate_total_hour_and_money, 2000); function calculate_total_hour_and_money() { //init pays for all staff; var pays={ total: 0, hours: 0, }; $('.stafflist > div.peopleitem').each(function(i,e){ var people = $(this).data().obj; people.reset_summary(); }); $('div.workspace > .divTable').each(function(i,e){ if (! $(e).is(':visible')) return; var job = $(e).data().job; //class Job if (typeof job === 'undefined') return; var ps = job.get_payment_summary(); pays.total += ps.money; pays.hours += ps.hour; var staff = job.get_staff(); var people = find_staff(staff); //class People if (people !=false) people.add_payment_summary(ps); }); set_wages(pays.total.toFixed(2)); set_working_hours(pays.hours.toFixed(2)); } function find_staff(login) { var d = $('#p'+login).data(); if (typeof d === 'undefined') return false; return $('#p'+login).data().obj; } $(document).on('change', '.divTableRow select, .divTableRow input', function() { var job = $(this).closest('.divTable').data().job; job.validate(); job.mark_dirty(); debounced_calculate(); }); function init_ts(){ show_loading_jobs(); list_staff(); list_clients(); xero(false); wifi(false); csv(false); init_user_search(); //ajax_earning_rate(); reset_title_to_today(); load_timesheet(); } function do_email_jobs() { var selector = 'div.bts_message div.ult_modal-body'; $(selector).html('Analysis staff jobs ... ok'); var staff = bts().staff.slice(0);//copy this array; var s = staff.pop(); //week2 start var w2_begin = new Date($('span[name="w2d1"]').data().date); var w2_end = new Date($('span[name="w2d7"]').data().date); var start = format_date(w2_begin); var finish = format_date(w2_end); function do_staff(){ var el = $('

Checking ' + s.firstname + "....

"); $(selector).append(el); el[0].scrollIntoView(); $.post(bts().ajax_url, { // POST request _ajax_nonce: bts().nonce, // nonce action: "email_job", // action staff : s.login, start : start, finish: finish, }, function(response, status, xhr){ if (response.status == 'success'){ if (response.sent){ el.append('' + response.emailstatus + ''); }else{ el.append('' + response.emailstatus + ''); } }else{ el.append(' Error[' + response.error + ' ...]'); } }).fail(function(){ el.append('' + 'Network Error occured' + ''); //clear staff pending list, stop further processing s = []; }).always(function(){//next staff if (staff.length >0){ s = staff.pop(); setTimeout(do_staff, 100); //a short delay makes it looks nice }else{ $('div.bts_message .ult-overlay-close-inside').show(); $('div.bts_message .ult-overlay-close-inside').addClass('blink_me'); $('div.week2').removeClass('blink_me'); $(selector).append('All staff confirmed! '); } }); } //execute do_staff(); } // function ajax_earning_rate(){ // $.post(bts().ajax_url, { // POST request // _ajax_nonce: bts().nonce, // nonce // action: "earnings_rate", // action // }, function(response, status, xhr){ // bts().earnings_rate = response; // console.log("%o", bts().earnings_rate); // }); // } $( ".boundary_datepicker" ).datepicker(); $( ".boundary_datepicker" ).datepicker("option", "dateFormat", "yy-mm-dd"); init_ts(); /*________________________________________________________________________*/ }); })(jQuery); /*______________scrolling______________________________________________*/ jQuery(document).ready(function(){ var timeoutid =0; jQuery('button.peoplelist[name="down"]').mousedown(function(){ var button = this; timeoutid = setInterval(function(){ //console.log("down scrotop %d ", jQuery(button).parent().find(".userlist").get(0).scrollTop ); jQuery(button).parent().find(".userlist").get(0).scrollTop +=240; }, 100); }).on('mouseup mouseleave', function(){ clearTimeout(timeoutid); }); jQuery('button.peoplelist[name="up"]').mousedown(function(){ var button = this; timeoutid = setInterval(function(){ //console.log("up scrotop %d ", jQuery(button).parent().find(".userlist").get(0).scrollTop ); jQuery(button).parent().find(".userlist").get(0).scrollTop -=240; }, 100); }).on('mouseup mouseleave', function(){ clearTimeout(timeoutid); }); });