| @@ -8,7 +8,12 @@ class Apiv1{ | |||
| $this->office = $office; | |||
| $this->job_table = $job_table; | |||
| add_shortcode( 'bts_jobv1_item', array($this, 'bts_jobv1_item')); | |||
| add_shortcode( 'bb_timesheet_canvas_v1', array($this, 'bb_timesheet_canvas_v1')); | |||
| add_shortcode( 'bts_jobv1_editor', array($this, 'bts_jobv1_editor')); | |||
| add_action('wp_ajax_list_jobv1', array($this,'list_job' )); | |||
| add_action('wp_ajax_delete_jobv1', array($this,'delete_jobv1' )); | |||
| } | |||
| @@ -19,6 +24,17 @@ class Apiv1{ | |||
| return $html; | |||
| } | |||
| public function bts_jobv1_editor($attr){ | |||
| $html =$this->template('jobv1_editor', 'jobv1_editor.html'); | |||
| $html = do_shortcode($html); | |||
| return $html; | |||
| } | |||
| public function bb_timesheet_canvas_v1($attr) | |||
| { | |||
| return file_get_contents(plugin_dir_path(__FILE__) . "/html/timesheet_canvas_v1.html"); | |||
| } | |||
| //generate template based on html file | |||
| private function template($id, $file) | |||
| { | |||
| @@ -43,7 +59,7 @@ class Apiv1{ | |||
| ); | |||
| $sql = "SELECT * FROM $this->job_table WHERE start>='%s' and start <='%s' order by start ASC ,staff ASC"; | |||
| $sql = "SELECT * FROM $this->job_table order by start ASC ,staff ASC"; | |||
| //$sql = "SELECT * FROM $this->job_table order by start ASC ,staff ASC"; | |||
| $query = $wpdb->prepare ($sql, array($start, $finish)); | |||
| $response['sql'] = $query; | |||
| $jobs = $wpdb->get_results($query); | |||
| @@ -69,4 +85,63 @@ class Apiv1{ | |||
| } | |||
| wp_send_json($response); | |||
| } | |||
| //ajax delete jobs | |||
| function delete_jobv1(){ | |||
| check_ajax_referer('acaresydney'); | |||
| $id = $_POST['jobid']; | |||
| $jobs = $_POST['jobs']; | |||
| if ($id != ''){ | |||
| $this->ajax_delete_single_job($id); | |||
| }else if (!empty($jobs)) { | |||
| $this->ajax_delete_multiple_jobs($jobs); | |||
| } | |||
| wp_die(); | |||
| } | |||
| private function ajax_delete_single_job($id) | |||
| { | |||
| global $wpdb; | |||
| //delete single job; | |||
| $result = $wpdb->delete($this->job_table, array('id'=> $id)); | |||
| $response=array( | |||
| 'status' => 'success', | |||
| 'id' => $id, | |||
| 'action'=> 'delete', | |||
| 'error' => $wpdb->last_error, | |||
| ); | |||
| if ($result == 1){ | |||
| wp_send_json($response); | |||
| }else{ | |||
| $response['status'] = 'error'; | |||
| $response['error'] = $this->db->last_error; | |||
| wp_send_json($response); | |||
| } | |||
| wp_die(); | |||
| } | |||
| private function ajax_delete_multiple_jobs($job_ids) | |||
| { | |||
| global $wpdb; | |||
| $ids = implode( ',', array_map( 'absint', $job_ids ) ); | |||
| $sql = "DELETE FROM $this->job_table WHERE ID IN($ids)" ; | |||
| $result = $wpdb->query( "DELETE FROM $this->job_table WHERE ID IN($ids)" ); | |||
| $response=array( | |||
| 'status' => 'success', | |||
| 'ids' => $job_ids, | |||
| 'action'=> 'delete', | |||
| 'deleted' => $result, | |||
| 'error' => $wpdb->last_error, | |||
| ); | |||
| if ($this->db->last_error == "" ){ | |||
| wp_send_json($response); | |||
| }else{ | |||
| $response['status'] = 'error'; | |||
| $response['error'] = $this->db->last_error; | |||
| wp_send_json($response); | |||
| } | |||
| wp_die(); | |||
| } | |||
| } | |||
| @@ -13,15 +13,13 @@ body { | |||
| } | |||
| @keyframes blinker { | |||
| 50% { | |||
| opacity: 0; | |||
| } | |||
| 50% { opacity: 0; } | |||
| } | |||
| @keyframes swing { | |||
| 0% { padding-left:0px; background-color:yellow;} | |||
| 50% { padding-left:10px; background-color: lightyellow;} | |||
| 100% { padding-left:0px; background-color:yellow;} | |||
| @keyframes flash { | |||
| 0% { padding-top:0px; background-color:yellow;} | |||
| 50% { padding-top:5px; color:red; background-color: lightyellow;} | |||
| 100% { padding-top:0px; background-color:yellow;} | |||
| } | |||
| .titlebar_gradient { | |||
| @@ -697,7 +695,7 @@ div.blueTable.emptyrecord { | |||
| } | |||
| .divTable.blueTable .divTableBody .divTableCell { | |||
| font-size: 15px; | |||
| /* font-size: 15px; */ | |||
| border-bottom: 1px lightgrey solid; | |||
| border-right: 1px lightgrey dotted; | |||
| vertical-align: middle; | |||
| @@ -718,7 +716,7 @@ div.blueTable.emptyrecord { | |||
| .divTable.blueTable .divTableHeading .divTableHead { | |||
| font-size: 15px; | |||
| font-weight: bold; | |||
| color: #FFFFFF; | |||
| color: #FFFFFF !important; | |||
| border-left: 2px solid #D0E4F5; | |||
| } | |||
| @@ -774,6 +772,23 @@ div.blueTable.emptyrecord { | |||
| background-color: lightyellow !important; | |||
| } | |||
| .jobTable.Editing{ | |||
| box-shadow: 0px 0px 10px green; | |||
| animation: flash 1s linear infinite; | |||
| } | |||
| .Editor{ | |||
| box-shadow: 0px 0px 10px green; | |||
| } | |||
| .Editor select{ | |||
| color:black !important; | |||
| } | |||
| .jobTable.Editing div, | |||
| .Editor div { | |||
| font-weight:900; | |||
| background-color: lightyellow !important; | |||
| } | |||
| .divTable.invalidjob.highlight { | |||
| box-shadow: 1px 1px 10px #f50202; | |||
| } | |||
| @@ -829,31 +844,38 @@ div.brate, | |||
| div.bstaff, | |||
| div.bclient, | |||
| div.bconfirmed, | |||
| div.bedit, | |||
| div.bsave, | |||
| div.brating, | |||
| div.bdelete { | |||
| width: 10%; | |||
| width: 5%; | |||
| height: 30px; | |||
| position:relative; | |||
| } | |||
| div.btos { | |||
| width: 20%; | |||
| width: 15%; | |||
| } | |||
| div.bstart, | |||
| div.bfinish { | |||
| width: 11%; | |||
| width: 10%; | |||
| } | |||
| div.bstaff, | |||
| div.bclient{ | |||
| width: 10%; | |||
| } | |||
| div.brate { | |||
| width: 10%; | |||
| max-width: 20px; | |||
| } | |||
| div.btos.error, | |||
| div.brate.error{ | |||
| position:relative; | |||
| background-color: red !important; | |||
| animation: swing 1s linear infinite; | |||
| animation: flash 1s linear infinite; | |||
| } | |||
| div.error::after{ | |||
| position:absolute; | |||
| @@ -872,31 +894,33 @@ div.error::after{ | |||
| } | |||
| div.bdelete, | |||
| div.bedit, | |||
| div.bsave, | |||
| div.bconfirmed { | |||
| text-align: center; | |||
| width: 5%; | |||
| width: 3%; | |||
| } | |||
| div.brating { | |||
| width: 3%; | |||
| text-align: center; | |||
| cursor: pointer; | |||
| } | |||
| .brating { | |||
| unicode-bidi: bidi-override; | |||
| direction: rtl; | |||
| div.Editor div.brating{ | |||
| min-width:110px; | |||
| } | |||
| div.workspace .brating > span:hover:before, | |||
| div.workspace .brating > span:hover ~ span:before { | |||
| content: "\2605"; | |||
| position: absolute; | |||
| div.bedit{ | |||
| text-align:center; | |||
| cursor: pointer; | |||
| } | |||
| div.bsave span.ticon-copy { | |||
| display: none; | |||
| } | |||
| div.divTableHeading div.bsave span.ticon, | |||
| div.jobTable.saved div.bsave span.ticon-copy { | |||
| display: inline-block; | |||
| border: 3px solid orange; | |||
| @@ -936,7 +960,8 @@ div.jobTable.dirty div.bsave span{ | |||
| animation-name: blinker; | |||
| } | |||
| div.bdelete span.ticon-trash { | |||
| div.bdelete span.ticon-trash, | |||
| div.bedit span.ticon-edit { | |||
| display: inline-block; | |||
| border: 3px solid lightgrey; | |||
| padding: 5px; | |||
| @@ -944,11 +969,27 @@ div.bdelete span.ticon-trash { | |||
| color: red; | |||
| cursor: pointer; | |||
| } | |||
| div.bedit span.ticon-edit{ | |||
| color:blue; | |||
| } | |||
| div.workspace div > span:hover { | |||
| box-shadow: 0px 0px 10px black; | |||
| } | |||
| div.jobTable.to_be_deleted_duplicate{ | |||
| color: red; | |||
| } | |||
| div.jobTable.to_be_deleted_duplicate span.ticon-trash | |||
| { | |||
| animation: blinker 0.3s linear infinite; | |||
| } | |||
| div.jobTable.to_be_deleted_duplicate span.ticon-copy, | |||
| div.jobTable.to_be_deleted_duplicate span.ticon-edit{ | |||
| display:none !important; | |||
| } | |||
| div.divTableHeading div > span:hover { | |||
| cursor: pointer; | |||
| animation: blinker 0.3s linear infinite; | |||
| @@ -996,4 +1037,9 @@ div.divTable .invalid { | |||
| .bts_message .ult_modal-body .span { | |||
| font-weight: 900; | |||
| } | |||
| } | |||
| .xdsoft_datetimepicker{ | |||
| z-index: 16777272; /* above the modal box */ | |||
| } | |||
| @@ -3,16 +3,19 @@ | |||
| data-id="{{id}}" data-tos="{{tos}}" data-rate="{{rate}}" data-staff="{{staff}}" data-client="{{client}}"> | |||
| <div class="divTableBody"> | |||
| <div class="divTableRow"> | |||
| <div class="divTableCell btos"> | |||
| <div class="divTableCell btos {{#tos_err}}error{{/tos_err}}" title="{{tos_err}}"> | |||
| {{tos_name}} | |||
| </div> | |||
| <div class="divTableCell bstart">{{start}}</div> | |||
| <div class="divTableCell bfinish">{{finish}}</div> | |||
| <div class="divTableCell brate {{#non_hour}} error {{/non_hour}}" {{#non_hour}} title="{{brate_err}}" {{/non_hour}} >{{rate_name}}</div> | |||
| <div class="divTableCell bstaff">{{staff_name}}</div> | |||
| <div class="divTableCell brate {{#rate_non_hour}} error {{/rate_non_hour}}" {{#non_hour}} title="{{rate_err}}" {{/non_hour}} >{{rate_name}}</div> | |||
| <div class="divTableCell bstaff {{#staff_err}} error {{/staff_err}}" title="{{staff_err}}">{{staff_name}}</div> | |||
| <div class="divTableCell bclient {{#is_week1}}week1color{{/is_week1}} {{#is_week2}}week2color{{/is_week2}}">{{client_name}}</div> | |||
| <div class="divTableCell bconfirmed"><input name="ack" type=checkbox {{#is_confirmed}}checked{{/is_confirmed}} onclick="return false;"></div> | |||
| <div class="divTableCell brating">{{rating}}</div> | |||
| <div class="divTableCell bedit"> | |||
| <span class="ticon ticon-edit"></span> | |||
| </div> | |||
| <div class="divTableCell bdelete"> | |||
| <span class="ticon ticon-trash"></span> | |||
| </div> | |||
| @@ -22,16 +25,17 @@ | |||
| </div> | |||
| </div> | |||
| <div class="divTableRow errmsg"> | |||
| <div class="divTableCell btos_err"></div> | |||
| <div class="divTableCell bstart_err"></div> | |||
| <div class="divTableCell bfinish_err"></div> | |||
| <div class="divTableCell brate_err"></div> | |||
| <div class="divTableCell bstaff_err"></div> | |||
| <div class="divTableCell bclient_err"></div> | |||
| <div class="divTableCell bconfirmed_err"></div> | |||
| <div class="divTableCell brating_err"></div> | |||
| <div class="divTableCell bdelete_err"></div> | |||
| <div class="divTableCell bsave_err"></div> | |||
| <div class="divTableCell btos_err">{{tos_err}}</div> | |||
| <div class="divTableCell bstart_err">{{start_err}}</div> | |||
| <div class="divTableCell bfinish_err">{{finish_err}}</div> | |||
| <div class="divTableCell brate_err">{{rate_err}}</div> | |||
| <div class="divTableCell bstaff_err">{{staff_err}}</div> | |||
| <div class="divTableCell bclient_err">{{client_err}}</div> | |||
| <div class="divTableCell bconfirmed_err">{{ack_err}}</div> | |||
| <div class="divTableCell brating_err">{{rating_err}}</div> | |||
| <div class="divTableCell "></div> | |||
| <div class="divTableCell bdelete_err">{{delete_err}}</div> | |||
| <div class="divTableCell bsave_err">{{save_err}}</div> | |||
| </div> | |||
| </div> | |||
| @@ -0,0 +1,65 @@ | |||
| <div class="divTable Editor blueTable" id='editor_{{editorid}}' data-id="{{id}}"> | |||
| <div class="divTableBody"> | |||
| <div class="divTableRow"> | |||
| <div class="divTableCell btos">Type of Service </div> | |||
| <div class="divTableCell bstart">Start</div> | |||
| <div class="divTableCell bfinish">Finish</div> | |||
| <div class="divTableCell brate">Hourly Rate</div> | |||
| <div class="divTableCell bstaff">Staff</div> | |||
| <div class="divTableCell bclient">Client</div> | |||
| <div class="divTableCell bconfirmed">Ack</div> | |||
| <div class="divTableCell brating"> | |||
| <span class="ticon ticon-star"></span> | |||
| <span class="ticon ticon-star"></span> | |||
| <span class="ticon ticon-star"></span> | |||
| <span class="ticon ticon-star"></span> | |||
| <span class="ticon ticon-star"></span> | |||
| </div> | |||
| <div class="divTableCell bdelete"> | |||
| </div> | |||
| <div class="divTableCell bsave "> | |||
| </div> | |||
| </div> | |||
| <div class="divTableRow"> | |||
| <div class="divTableCell btos"> | |||
| [bts_type_of_service] | |||
| </div> | |||
| <div class="divTableCell bstart"><input class="datepicker" placeholder="2019-07-10 01:00" value=""></input></div> | |||
| <div class="divTableCell bfinish"><input class="datepicker" placeholder="2019-07-10 01:00" value=""></input></div> | |||
| <div class="divTableCell brate">[bts_rate_options]</div> | |||
| <div class="divTableCell bstaff">[bts_select_staff]</div> | |||
| <div class="divTableCell bclient">[bts_select_client]</div> | |||
| <div class="divTableCell bconfirmed"><input type=checkbox ></div> | |||
| <div class="divTableCell brating"> | |||
| <select> | |||
| <option value="5">5-Best</option> | |||
| <option value="4">4-Good</option> | |||
| <option value="3">3-Standard</option> | |||
| <option value="2">2-Bad</option> | |||
| <option value="1">1-Worst</option> | |||
| <option value="0">0-No Feedback</option> | |||
| </select> | |||
| </div> | |||
| <div class="divTableCell bdelete"> | |||
| <span class="ticon ticon-plus"></span> | |||
| </div> | |||
| <div class="divTableCell bsave "> | |||
| <span class="ticon ticon-save"></span> | |||
| </div> | |||
| </div> | |||
| <div class="divTableRow errmsg"> | |||
| <div class="divTableCell btos_err"> e tos | |||
| </div> | |||
| <div class="divTableCell bstart_err">es</div> | |||
| <div class="divTableCell bfinish_err">ef</div> | |||
| <div class="divTableCell brate_err">er</div> | |||
| <div class="divTableCell bstaff_err">estaf</div> | |||
| <div class="divTableCell bclient_err">ecli</div> | |||
| <div class="divTableCell bconfirmed_err">econfirm</div> | |||
| <div class="divTableCell brating_err">erat</div> | |||
| <div class="divTableCell bdelete_err">edel</div> | |||
| <div class="divTableCell bsave_err">eeave</div> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| @@ -0,0 +1,198 @@ | |||
| <div class='peoplebar left'> | |||
| <div class='b_search titlebar_gradient'> | |||
| <span class="ticon ticon-search"></span> | |||
| <input type="text" placeholder="staff"> | |||
| <span class="ticon ticon-times-circle-o"></span> | |||
| </div> | |||
| <button class='peoplelist' name='up'> | |||
| <span class="ticon ticon-angle-double-up"></span> | |||
| </button> | |||
| <div class="stafflist userlist"> | |||
| <img> | |||
| </div> | |||
| <button class='peoplelist' name='down'> | |||
| <span class="ticon ticon-angle-double-down"></span> | |||
| </button> | |||
| </div> | |||
| <div class='peoplebar right'> | |||
| <div class='b_search titlebar_gradient'> | |||
| <span class="ticon ticon-search"></span> | |||
| <input type="text" placeholder="client"> | |||
| <span class="ticon ticon-times-circle-o"></span> | |||
| </div> | |||
| <button class='peoplelist' name='up'> | |||
| <span class="ticon ticon-angle-double-up"></span> | |||
| </button> | |||
| <div class="clientlist userlist"> | |||
| <img> | |||
| </div> | |||
| <button class='peoplelist' name='down'> | |||
| <span class="ticon ticon-angle-double-down"></span> | |||
| </button> | |||
| </div> | |||
| <div class='timesheets'> | |||
| <div class='sheettitle titlebar_gradient'> | |||
| <h1>Web Office - Today:<span name='today'> Today </span> </h1> | |||
| </div> | |||
| <div class='sheetsheader'> | |||
| <div class='weekly'> | |||
| <div class='weekname prev'> | |||
| <input id='week1b' type=text class='boundary_datepicker' value="2019-07-01" placeholder="2019-07-01">Week | |||
| <span name='week1'>10</span> | |||
| <i class="ticon ticon-caret-right"></i> | |||
| </div> | |||
| <div class='copyprogress'> | |||
| <div name='copyschedule'> | |||
| Add a Job | |||
| <span class='ticon ticon-plus'></span> | |||
| </div> | |||
| </div> | |||
| <div class='weekname next'> | |||
| <i class="ticon ticon-caret-left"></i> | |||
| Week | |||
| <span name='week2'>11</span> | |||
| <input id='week2b' type=text class='boundary_datepicker' value="2019-07-01" placeholder="2019-07-01"> | |||
| </div> | |||
| <div class="weekdays"> | |||
| <div class='week1'> | |||
| <div class='week1color'> | |||
| <span name='w1n1'>Mon</span> | |||
| <br> | |||
| <span class="weekday" name='w1d1'>12</span> | |||
| </div> | |||
| <div class='week1color'> | |||
| <span name='w1n2'>Tue</span> | |||
| <br> | |||
| <span class="weekday" name='w1d2'>12</span> | |||
| </div> | |||
| <div class='week1color'> | |||
| <span name='w1n3'>Wed</span> | |||
| <br> | |||
| <span class="weekday" name='w1d3'>12</span> | |||
| </div> | |||
| <div class='week1color'> | |||
| <span name='w1n4'>Thu</span> | |||
| <br> | |||
| <span class="weekday" name='w1d4'>12</span> | |||
| </div> | |||
| <div class='week1color'> | |||
| <span name='w1n5'>Fri</span> | |||
| <br> | |||
| <span class="weekday" name='w1d5'>12</span> | |||
| </div> | |||
| <div class='week1color'> | |||
| <span name='w1n6'>Sat</span> | |||
| <br> | |||
| <span class="weekday" name='w1d6'>12</span> | |||
| </div> | |||
| <div class='week1color'> | |||
| <span name='w1n7'>Sun</span> | |||
| <br> | |||
| <span class="weekday" name='w1d7'>12</span> | |||
| </div> | |||
| </div> | |||
| <div class='week2'> | |||
| <div class='week2color'> | |||
| <span name='w2n1'>Mon</span> | |||
| <br> | |||
| <span class="weekday" name='w2d1'>12</span> | |||
| </div> | |||
| <div class='week2color'> | |||
| <span name='w2n2'>Tue</span> | |||
| <br> | |||
| <span class="weekday" name='w2d2'>12</span> | |||
| </div> | |||
| <div class='week2color'> | |||
| <span name='w2n3'>Wed</span> | |||
| <br> | |||
| <span class="weekday" name='w2d3'>12</span> | |||
| </div> | |||
| <div class='week2color'> | |||
| <span name='w2n4'>Thu</span> | |||
| <br> | |||
| <span class="weekday" name='w2d4'>12</span> | |||
| </div> | |||
| <div class='week2color'> | |||
| <span name='w2n5'>Fri</span> | |||
| <br> | |||
| <span class="weekday" name='w2d5'>12</span> | |||
| </div> | |||
| <div class='week2color'> | |||
| <span name='w2n6'>Sat</span> | |||
| <br> | |||
| <span class="weekday" name='w2d6'>12</span> | |||
| </div> | |||
| <div class='week2color'> | |||
| <span name='w2n7'>Sun</span> | |||
| <br> | |||
| <span class="weekday" name='w2d7'>12</span> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| <div class='prevweek left'> | |||
| <span class="ticon ticon-arrow-circle-left"></span> | |||
| </div> | |||
| <div class='nextweek right'> | |||
| <span class="ticon ticon-arrow-circle-right"></span> | |||
| </div> | |||
| <div class="sheettableheader"> | |||
| <div class="divTable blueTable"> | |||
| <div class="divTableHeading"> | |||
| <div class="divTableRow"> | |||
| <div class="divTableHead btos">Type of Service</div> | |||
| <div class="divTableHead bstart">Start</div> | |||
| <div class="divTableHead bfinish">Finish</div> | |||
| <div class="divTableHead brate">Hourly Rate</div> | |||
| <div class="divTableHead bstaff">Staff</div> | |||
| <div class="divTableHead bclient">Client</div> | |||
| <div class="divTableHead bconfirmed">Ack</div> | |||
| <div class="divTableHead brating"> | |||
| <span class="ticon ticon-star"></span> | |||
| </div> | |||
| <div class="divTableHead bedit"> | |||
| <span class="ticon ticon-edit"></span> | |||
| </div> | |||
| <div class="divTableHead bdelete"> | |||
| <span class="ticon ticon-trash"></span> | |||
| </div> | |||
| <div class="divTableHead bsave"> | |||
| <span class="ticon ticon-search"></span> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| <div class='workspace'> | |||
| <img src="#"> | |||
| </div> | |||
| <div class='statusbar titlebar_gradient'> | |||
| <a id='xeroc' href="/xeroc/" target="_blank"> | |||
| <div class='xero'> | |||
| <i class="ticon ticon-times"></i> | |||
| </div> | |||
| </a> | |||
| <div class='wifi'> | |||
| <i class="ticon ticon-times"></i> | |||
| </div> | |||
| <a id='ndiscsv' href="/ndiscsv/" target="_blank"> | |||
| <div class='csv'> | |||
| <i class="ticon ticon-times"></i> | |||
| </div> | |||
| </a> | |||
| <div class='wages'> | |||
| $ | |||
| <div name='number'> | |||
| 3214 | |||
| </div> | |||
| </div> | |||
| <div class='workinghours'> | |||
| <label for='woh'> Total Hours</label> | |||
| <input id="woh" type="text" value="1553.5" readonly> | |||
| </div> | |||
| <button name='confirmschedule'> | |||
| Confirm_Schedule | |||
| </button> | |||
| </div> | |||
| </div> | |||
| @@ -276,11 +276,83 @@ | |||
| return selector; | |||
| } | |||
| $(document).on('click', 'div.jobTable div.brate.error', function(){ | |||
| var msg = $(this).attr('title'); | |||
| if (msg != "") | |||
| alert(msg); | |||
| }); | |||
| $(document).on('click', 'div.divTableHead.bdelete', function(){ | |||
| add_new_empty_job(); | |||
| $(document).on('click', 'div.workspace div.bedit span.ticon-edit', function(){ | |||
| var el = $(this).closest('div.jobTable'); | |||
| el.addClass('Editing'); | |||
| var id = el.attr('data-id'); | |||
| do_edit_job(id); | |||
| }); | |||
| $(document).on('click', 'div.bts_editor div.ult-overlay-close', function(){ | |||
| $('.Editing').addClass('blink_me'); | |||
| setTimeout(function(){ | |||
| $(".Editing").removeClass('Editing blink_me'); | |||
| }, 1000); | |||
| }); | |||
| $(document).on('click', 'div.bts_editor div.bsave span.ticon-save', function(){ | |||
| close_editor(); | |||
| }); | |||
| function close_editor(){ | |||
| $('div.bts_editor div.ult-overlay-close').trigger('click'); | |||
| } | |||
| $(document).on('jobEditor:close', 'div.divTable.Editor', function(e,job){ | |||
| console.log('close_editor event %o', job); | |||
| }); | |||
| $(document).on('click', 'div.divTableHead.bdelete span.ticon-trash', function(){ | |||
| var len = $('div.jobTable.to_be_deleted_duplicate').length; | |||
| if (len <= 0){ | |||
| if (confirm("No duplicates to delete, trying to find duplicates?")){ | |||
| check_duplicate(); | |||
| } | |||
| return; | |||
| }else{ | |||
| if (!confirm("Delete " + len + " duplicates? ")) | |||
| return; | |||
| } | |||
| var ids = []; | |||
| $('div.jobTable.to_be_deleted_duplicate').each(function(){ | |||
| var id = $(this).attr('data-id'); | |||
| ids.push(id); | |||
| }); | |||
| $.post(bts().ajax_url, { // POST request | |||
| _ajax_nonce: bts().nonce, // nonce | |||
| action: "delete_jobv1", // action | |||
| jobs: ids, //delete multiple ids | |||
| }, function(response, status, xhr){ | |||
| if (response.status=='success'){ | |||
| $('div.jobTable.to_be_deleted_duplicate').each(function(){ | |||
| var id = $(this).attr('data-id'); | |||
| delete bts().job_map[id]; | |||
| $(this).get(0).scrollIntoView(); | |||
| fade_and_delete(this); | |||
| }); | |||
| debounced_calculate(); | |||
| }else{ | |||
| alert( 'error deleting duplicates:\n\nError:\n\n' + response.error + "\n\n"); | |||
| } | |||
| }); | |||
| }); | |||
| function fade_and_delete(el) | |||
| { | |||
| $(el).fadeOut(300); | |||
| setTimeout(function(){ | |||
| $(el).remove(); | |||
| },300); | |||
| } | |||
| function add_new_empty_job(){ | |||
| var o = new Job({empty:true}); | |||
| $('div.workspace').append(o.el); | |||
| @@ -354,31 +426,12 @@ | |||
| newj.mark_highlight_me(1000);//for 1 second; | |||
| dtp_init(); | |||
| }); | |||
| class Job{ //save data for the record, and display it as GUI | |||
| class Job{}; | |||
| class JobEditor{ //save data for the record, and display it as GUI | |||
| constructor(selector, data){ | |||
| this.el = $(selector); | |||
| //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); | |||
| }); | |||
| this.load_data(data); | |||
| this.init_event_handler(); | |||
| } | |||
| load_data(data) | |||
| @@ -404,9 +457,59 @@ | |||
| this.mark_week_color(); | |||
| this.validate(); //also triggers mark errors | |||
| } | |||
| init_event_handler(){ | |||
| var self = this; | |||
| this.el.find("div.btos select").change(function(){ | |||
| if ( self.validate_tos() ) { | |||
| self.data.tos = self.get_tos(); | |||
| } | |||
| }); | |||
| this.el.find("div.bstart input").change(function(){ | |||
| if (self.validate_start()){ | |||
| self.data.start = self.get_start(); | |||
| } | |||
| }); | |||
| this.el.find("div.bfinish input").change(function(){ | |||
| if (self.validate_finish()){ | |||
| self.data.finish = self.get_finish(); | |||
| } | |||
| }); | |||
| this.el.find("div.bstaff select").change(function(){ | |||
| if (self.validate_staff()){ | |||
| self.data.staff = self.get_staff(); | |||
| } | |||
| }); | |||
| this.el.find("div.bclient select").change(function(){ | |||
| if (self.validate_client()){ | |||
| self.data.client = self.get_client(); | |||
| } | |||
| }); | |||
| this.el.find("div.brate select").change(function(){ | |||
| if (self.validate_rate()){ | |||
| self.data.rate = self.get_rate(); | |||
| } | |||
| }); | |||
| this.el.find("div.bconfirmed input").change(function(){ | |||
| if(self.validate_ack()){ | |||
| self.data.ack = self.get_ack(); | |||
| } | |||
| }); | |||
| this.el.find("div.brating select").change(function(){ | |||
| if( self.validate_rating()){ | |||
| self.data.rating =self.get_rating(); | |||
| } | |||
| }); | |||
| this.el.find("div.bsave span.ticon-save").click(function(e){ | |||
| if ( self.validate() ){ | |||
| job_derive_attr(self.data); | |||
| self.el.trigger('jobEditor:close', self.data); | |||
| } | |||
| }); | |||
| } | |||
| get_job_id(){ | |||
| return this.el.find('input[name="id"]').attr('value'); | |||
| return this.el.attr('data-id'); | |||
| } | |||
| set_job_id(val){ | |||
| if (typeof val == 'undefined' || val == '') | |||
| @@ -420,34 +523,43 @@ | |||
| } | |||
| get_tos() | |||
| { | |||
| this.el.find('div.btos select').children("option:selected").val(); | |||
| return this.el.find('div.btos select').children("option:selected").val(); | |||
| } | |||
| set_tos(val) | |||
| { | |||
| if (typeof(val) =="undefined") | |||
| return; | |||
| this.el.find('input.tos_name').attr('value', bts().tos[val].tos_full_str); | |||
| this.el.find('div.btos select option[value="'+val+'"]').prop('selected',true); | |||
| if ( this.get_tos() != val ){ | |||
| var o = new Option("(missing:" + this.data.tos +")", this.data.tos); | |||
| this.el.find('div.btos select').prepend(o); | |||
| this.el.find('div.btos select option[value="'+this.data.tos+'"]').prop('selected',true); | |||
| } | |||
| } | |||
| get_start(){ | |||
| return this.el.find('div.bstart').html(); | |||
| return this.el.find('div.bstart input').attr('value'); | |||
| } | |||
| set_start(val) | |||
| { | |||
| this.el.find('div.bstart').html(val); | |||
| if (typeof(val) =="undefined") | |||
| return; | |||
| this.el.find('div.bstart input').attr('value', val); | |||
| } | |||
| get_finish() | |||
| { | |||
| return this.el.find('div.bfinish').html(); | |||
| return this.el.find('div.bfinish input').attr('value'); | |||
| } | |||
| set_finish(val) | |||
| { | |||
| if (typeof(val) == "undefined") | |||
| return; | |||
| this.el.find('div.bfinish').html(val); | |||
| if (typeof(val) == "undefined") | |||
| return; | |||
| this.el.find('div.bfinish input').attr('value', val); | |||
| } | |||
| get_rate() | |||
| { | |||
| return this.el.find('div.brate').children("option:selected").val(); | |||
| return this.el.find('div.brate select').children("option:selected").val(); | |||
| } | |||
| set_rate(val) | |||
| { | |||
| @@ -464,6 +576,12 @@ | |||
| if (typeof(val) =="undefined") | |||
| return; | |||
| this.el.find('div.bstaff select option[value="'+val+'"]').prop('selected',true); | |||
| if ( this.get_staff() != val ){ | |||
| var o = new Option("(missing:" + this.data.staff +")", this.data.staff); | |||
| this.el.find('div.bstaff select').prepend(o); | |||
| this.set_err_msg_tos('missing' + this.data.staff); | |||
| this.el.find('div.bstaff select option[value="'+this.data.staff+'"]').prop('selected',true); | |||
| } | |||
| } | |||
| get_client() | |||
| { | |||
| @@ -477,7 +595,7 @@ | |||
| } | |||
| get_ack() | |||
| { | |||
| return this.el.find('div.bconfirmed input:checked').length > 0; | |||
| return this.el.find('div.bconfirmed input:checked').length > 0? 1:0; | |||
| } | |||
| set_ack(val) | |||
| { | |||
| @@ -486,24 +604,12 @@ | |||
| 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; | |||
| return this.el.find('div.brating select').children("option:selected").val(); | |||
| } | |||
| set_rating(num){ | |||
| if (!(1 <= num && num <=5)) | |||
| if (!(0 <= 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('☆'); | |||
| }); | |||
| this.el.find('div.brating select option[value="'+num+'"]').prop('selected',true); | |||
| } | |||
| get_record_from_ui(){ | |||
| @@ -616,11 +722,13 @@ | |||
| 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_tos = this.validate_tos(); | |||
| var ok_time = this.validate_start() && this.validate_finish(); //finish might not be executed, if start is wrong | |||
| var ok_staff = this.validate_staff(); | |||
| var ok_client = this.validate_client(); | |||
| var ok_rate = this.validate_rate() ; //make sure this validate is executed | |||
| var ok = ok_time && ok_tos && ok_rate; | |||
| var ok = ok_tos && ok_time && ok_staff && ok_client && ok_rate; | |||
| if (ok){ | |||
| this.el.removeClass('invalidjob'); | |||
| }else{ | |||
| @@ -679,15 +787,28 @@ | |||
| } | |||
| 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(); | |||
| if ( typeof bts().tos[this.get_tos()] == 'undefined') { | |||
| this.set_err_msg_tos('missing ' + this.get_tos()); | |||
| return false; | |||
| }else{ | |||
| this.set_err_msg_tos(''); | |||
| return true; | |||
| } | |||
| } | |||
| validate_staff(){ | |||
| if ( typeof bts().staff_map[this.get_staff()] == 'undefined') { | |||
| this.set_err_msg_staff('missing ' + this.get_staff()); | |||
| return false; | |||
| }else{ | |||
| this.set_err_msg_staff(''); | |||
| return true; | |||
| } | |||
| } | |||
| validate_client(){ | |||
| return true; | |||
| } | |||
| validate_rating(){ | |||
| return true; | |||
| } | |||
| @@ -702,6 +823,14 @@ | |||
| { | |||
| this.el.find('div.bfinish_err').html(str); | |||
| } | |||
| set_err_msg_staff(str) | |||
| { | |||
| this.el.find('div.bstaff_err').html(str); | |||
| } | |||
| set_err_msg_client(str) | |||
| { | |||
| this.el.find('div.bclient_err').html(str); | |||
| } | |||
| set_err_msg_rate(str) | |||
| { | |||
| this.el.find('div.brate_err').html(str); | |||
| @@ -864,6 +993,18 @@ | |||
| $(s).trigger('click'); | |||
| } | |||
| function set_modal_data(selector, data){ | |||
| var s = 'div.bts_'+ selector; | |||
| $(s).data(data); | |||
| } | |||
| function get_modal_data(selector, data){ | |||
| var s = 'div.bts_'+ selector; | |||
| $(s).data(); | |||
| } | |||
| // setTimeout(function(){ | |||
| // set_modal_title('warning', 'suck title'); | |||
| // set_modal_content('warning', 'fucking details'); | |||
| @@ -1217,15 +1358,33 @@ | |||
| function job_derive_attr(e) | |||
| { | |||
| clear_non_derive_attr(e); | |||
| e.saved = true; | |||
| e.tos_name = bts().tos[e.tos].tos_full_str; | |||
| e.staff_name = bts().staff_map[e.staff].display_name; | |||
| if (typeof bts().tos[e.tos] != 'undefined'){ | |||
| e.tos_name = bts().tos[e.tos].tos_full_str; | |||
| }else{ | |||
| e.tos_name = "(deleted) "; | |||
| e.tos_err="Missing: " + e.tos; | |||
| } | |||
| if (typeof bts().staff_map[e.staff] != 'undefined'){ | |||
| e.staff_name = bts().staff_map[e.staff].display_name; | |||
| }else{ | |||
| e.staff_name = "(deleted) "; | |||
| e.staff_err="Missing: " + e.staff; | |||
| } | |||
| e.client_name = bts().client_map[e.client].display_name; | |||
| e.rate_name = bts().earnings_rate[e.rate].RatePerUnit + "-" + bts().earnings_rate[e.rate].Name; | |||
| if (! has_txt_hour( bts().earnings_rate[e.rate].TypeOfUnits )){ | |||
| e.non_hour = true; | |||
| e.brate_err = "Rate type is not Hours - Not allowed"; | |||
| e.rate_non_hour = true; | |||
| e.rate_err = `Rate unit must be ⟦ Hours ⟧ | |||
| Possible solution: | |||
| 1. Change it in Xero | |||
| 2. Delete this job`; | |||
| } | |||
| if (job_is_week1(e.start)){ | |||
| @@ -1238,6 +1397,22 @@ | |||
| e.is_confirmed = true; | |||
| } | |||
| } | |||
| function clear_non_derive_attr(e) | |||
| { | |||
| delete e.saved; | |||
| delete e.tos_name; | |||
| delete e.tos_err; | |||
| delete e.staff_name; | |||
| delete e.staff_err; | |||
| delete e.client_name; | |||
| delete e.client_err; | |||
| delete e.rate_name; | |||
| delete e.rate_err; | |||
| delete e.rate_non_hour; | |||
| delete e.is_week1; | |||
| delete e.is_week2; | |||
| delete e.is_confirmed; | |||
| } | |||
| function has_txt_hour(str){ | |||
| var s = str.toLowerCase(); | |||
| @@ -1646,8 +1821,7 @@ | |||
| function check_duplicate() | |||
| { | |||
| var count= 0; | |||
| var to_be_delete=[]; | |||
| var to_be_deleted=[]; | |||
| //loop through jobs | |||
| for(var id1 in bts().job_map){ | |||
| var job1 = bts().job_map[id1]; | |||
| @@ -1669,17 +1843,19 @@ | |||
| if (is_same_job(job1,job2)){ | |||
| job2.parent = job1.id; | |||
| job1.duplicates[id2] = job2; | |||
| console.warn("found: %s = %s", job1.id, job2.id); | |||
| count++; | |||
| to_be_delete.push(id2); | |||
| //console.warn("found: %s = %s", job1.id, job2.id); | |||
| to_be_deleted.push(id2); | |||
| } | |||
| } | |||
| } | |||
| console.log('all-done, found %d duplicates: %o', count, to_be_delete); | |||
| if (to_be_deleted.length == 0){ | |||
| alert("No duplicate found!"); | |||
| return; | |||
| } | |||
| bts().to_be_deleted_duplicate = to_be_deleted; | |||
| //console.log('all-done, found %d duplicates: %o', to_be_deleted.length, to_be_deleted); | |||
| mark_duplicate(to_be_deleted); | |||
| } | |||
| $('div.wages').click(check_duplicate); | |||
| function is_same_job(job1, job2) | |||
| { | |||
| if ( (job1.tos == job2.tos) && | |||
| @@ -1692,8 +1868,34 @@ | |||
| } | |||
| return false; | |||
| } | |||
| function mark_duplicate(ids) | |||
| { | |||
| ids.forEach(function(id){ | |||
| var selector = '#job_' +id; | |||
| $(selector).get(0).scrollIntoView(); | |||
| $(selector).addClass('to_be_deleted_duplicate'); | |||
| }); | |||
| } | |||
| function do_edit_job(id) | |||
| { | |||
| open_modal('editor'); | |||
| set_modal_title('editor', "Editing Job: " + id); | |||
| //make a copy of the job | |||
| var job_copy = $.extend({}, bts().job_map[id]); | |||
| job_copy.editorid = Math.floor(Math.random() * Math.floor(99999)); // a random number; | |||
| //set_modal_data('editor', {jobid: id, job_copy:job_copy}); | |||
| var html = $('#jobv1_editor').html(); | |||
| html = Mustache.render(html, job_copy); | |||
| set_modal_content('editor', html); | |||
| //update GUI | |||
| dtp_init(); | |||
| //init editor | |||
| new JobEditor('#editor_' + job_copy.editorid, job_copy); | |||
| } | |||
| $( ".boundary_datepicker" ).datepicker(); | |||
| $( ".boundary_datepicker" ).datepicker("option", "dateFormat", "yy-mm-dd"); | |||
| @@ -1719,6 +1921,12 @@ | |||
| init_ts(); | |||
| $('div.divTableHeading div.bsave span.ticon-search').click(do_test); | |||
| function do_test(){ | |||
| open_modal('editor'); | |||
| set_modal_title('editor', "title"); | |||
| set_modal_content('editor', $('div.workspace').html()); | |||
| } | |||
| /*________________________________________________________________________*/ | |||
| }); | |||
| @@ -1742,7 +1950,7 @@ jQuery(document).ready(function(){ | |||
| 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 ); | |||
| //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(){ | |||