diff --git a/Apiv1.php b/Apiv1.php
new file mode 100644
index 0000000..b18eed7
--- /dev/null
+++ b/Apiv1.php
@@ -0,0 +1,69 @@
+office = $office;
+ $this->job_table = $job_table;
+ add_shortcode( 'bts_jobv1_item', array($this, 'bts_jobv1_item'));
+ add_action('wp_ajax_list_jobv1', array($this,'list_job' ));
+ }
+
+
+ public function bts_jobv1_item($attr){
+ $html =$this->template('jobv1_item', 'jobv1.html');
+ //$html = str_replace('[bts-tos-options]', $this->bts_tos_options([]), $html);
+ $html = do_shortcode($html);
+ return $html;
+ }
+
+ //generate template based on html file
+ private function template($id, $file)
+ {
+ $text = '';
+ return $text;
+ }
+
+
+ //ajax browse job with different filters
+ function list_job(){
+ global $wpdb;
+ check_ajax_referer('acaresydney');
+ $start = $_POST['start'] . " 00:00:00";
+ $finish = $_POST['finish']. " 23:59:59";
+
+ $response = array(
+ 'status'=>'success',
+ 'jobs' => [],
+ );
+
+ //$sql = "SELECT * FROM $this->table_name WHERE start>='%s' and start <='%s' 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);
+
+ if (! empty($jobs)){
+ $response['status'] = 'success';
+ foreach( $jobs as $s){
+ $response['jobs'][] = array(
+ 'id' => $s->id,
+ 'tos' => $s->tos,
+ 'start'=> $s->start,
+ 'finish'=> $s->finish,
+ 'rate'=> $s->rate,
+ 'staff'=> $s->staff,
+ 'client'=> $s->client,
+ 'ack' => $s->ack,
+ 'rating' =>$s->rating,
+ );
+ }
+ }
+ wp_send_json($response);
+ wp_die();
+ }
+}
\ No newline at end of file
diff --git a/css/bts_office.css b/css/bts_office.css
new file mode 100644
index 0000000..b7fd08b
--- /dev/null
+++ b/css/bts_office.css
@@ -0,0 +1,946 @@
+html,
+body {
+ margin: 0px !important;
+ overflow: hidden;
+}
+
+.bts_hidden {
+ z-index: -1;
+}
+
+.blink_me {
+ animation: blinker 0.3s linear infinite;
+}
+
+@keyframes blinker {
+ 50% {
+ opacity: 0;
+ }
+}
+
+.titlebar_gradient {
+ /* Permalink - use to edit and share this gradient: https://colorzilla.com/gradient-editor/#f6e6b4+0,ed9017+100 */
+ background: rgb(246,230,180); /* Old browsers */
+ background: -moz-linear-gradient(top, rgba(246,230,180,1) 0%, rgba(237,144,23,1) 100%); /* FF3.6-15 */
+ background: -webkit-linear-gradient(top, rgba(246,230,180,1) 0%,rgba(237,144,23,1) 100%); /* Chrome10-25,Safari5.1-6 */
+ background: linear-gradient(to bottom, rgba(246,230,180,1) 0%,rgba(237,144,23,1) 100%); /* W3C, IE10+, FF16+, Chrome26+, Opera12+, Safari7+ */
+ filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#f6e6b4', endColorstr='#ed9017',GradientType=0 ); /* IE6-9 */
+}
+
+.sheettitle h1:hover {
+ text-decoration: underline;
+ font-weight: bolder;
+ cursor: pointer;
+ animation: blinker 1s linear infinite;
+}
+
+.timesheets {
+ width: calc(100vw - 300px);
+ height: 100vh;
+ margin: 0px;
+ padding: 0px;
+ left: 150px;
+ position: fixed;
+ background-color: red;
+ overflow: hidden;
+}
+
+.peoplebar {
+ position: fixed;
+ top: 0px;
+ width: 150px;
+ height: 100vh;
+ background: lightgrey;
+ overflow: hidden;
+}
+
+.peoplebar.left {
+ border-radius: 5px 0px 0px 0px;
+ left: 0px;
+}
+
+.peoplebar.right {
+ right: 0px;
+ border-radius: 0px 5px 0px 0px;
+}
+
+.timesheets .sheettitle {
+ padding-top: 8px;
+ text-align: center;
+ background-color: lightgrey;
+ height: 40px;
+ text-shadow: 1px 1px 1px #fcfcfc;
+}
+
+.timesheets .workspace {
+ height: calc(100vh - 190px);
+ background-color: white;
+ overflow-x: hidden;
+ overflow-y: scroll;
+}
+
+.timesheets .workspace img {
+ display: block;
+ margin-top: 140px;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+.timesheets .statusbar {
+ position: relative;
+ height: 40px;
+ background-color: ivory;
+ box-shadow: 1px 1px 10px black;
+}
+
+/* staff search bar*/
+.b_search {
+ position: relative;
+ height: 40px;
+}
+
+.b_search input {
+ margin-top: 5px;
+ padding-left: 20px;
+ padding-right: 20px;
+ border-radius: 20px;
+ box-shadow: 1px 1px 2px grey inset;
+ height: 30px;
+}
+
+.b_search .ticon-search {
+ position: absolute;
+ top: 15px;
+ left: 5px;
+}
+
+.b_search .ticon-times-circle-o {
+ position: absolute;
+ top: 15px;
+ right: 5px;
+}
+
+.peoplebar button {
+ width: 100%;
+ padding: 0px;
+ height: 20px;
+}
+
+.peoplebar .stafflist,
+.peoplebar .clientlist {
+ height: calc(100vh - 80px);
+ background-color: dimgrey;
+ overflow: hidden;
+ text-align: center;
+
+ /* scroll-behavior: smooth; */
+}
+
+.peopleitem {
+ position: relative;
+ margin-top: 10px;
+ margin-bottom: 10px;
+ height: 100px;
+ background: transparent;
+}
+
+/* hover box */
+div.peopleitem > label {
+ -webkit-perspective: 1000px;
+ perspective: 1000px;
+ -webkit-transform-style: preserve-3d;
+ transform-style: preserve-3d;
+ display: block;
+ width: 100%;
+ height: 100px;
+ position: absolute;
+ left: 50%;
+ top: 50%;
+ -webkit-transform: translate(-50%, -50%);
+ transform: translate(-50%, -50%);
+ cursor: pointer;
+}
+
+div.peopleitem .card {
+ position: relative;
+ height: 100%;
+ width: 95%;
+ margin: auto;
+ -webkit-transform-style: preserve-3d;
+ transform-style: preserve-3d;
+ -webkit-transition: all 600ms;
+ transition: all 600ms;
+ z-index: 20;
+ border: 1px solid black;
+ box-shadow: 1px 1px 10px black;
+}
+
+div.peopleitem .card > div {
+ position: absolute;
+ height: 100%;
+ width: 100%;
+ background: #FFF;
+ text-align: center;
+
+ /* line-height: 200px; */
+ -webkit-backface-visibility: hidden;
+ backface-visibility: hidden;
+ border-radius: 2px;
+}
+
+div.peopleitem .card .back {
+ background: #222;
+ color: #FFF;
+ -webkit-transform: rotateX(180deg);
+ transform: rotateX(180deg);
+}
+
+div.peopleitem label:hover .card {
+ -webkit-transform: rotateX(20deg);
+ transform: rotateX(20deg);
+ box-shadow: 0 20px 20px rgba(50,50,50,.2);
+}
+
+div.peopleitem input {
+ display: none;
+}
+
+div.peopleitem :checked + .card {
+ transform: rotateX(180deg);
+ -webkit-transform: rotateX(180deg);
+}
+
+div.peopleitem label:hover :checked + .card {
+ transform: rotateX(160deg);
+ -webkit-transform: rotateX(160deg);
+ box-shadow: 0 20px 20px rgba(255,255,255,.2);
+}
+
+/* end of hover box */
+.satusbar {
+ position: relative;
+}
+
+.statusbar * {
+ vertical-align: top;
+ text-shadow: 1px 1px 1px #fcfcfc;
+}
+
+.statusbar div {
+ position: relative;
+ display: inline;
+}
+
+.statusbar .xero {
+ width: 40px;
+ height: 100%;
+ margin-left: 5px;
+ margin-right: 5px;
+ display: inline-block;
+ background-color: white;
+ box-shadow: inset 0px 0px 2px dotted white;
+ border-radius: 100px;
+ background-image: url(../img/xero.png);
+ background-size: 40px;
+ box-shadow: 0px 0px 10px white;
+}
+
+.statusbar .wifi i,
+.statusbar .xero i,
+.statusbar .csv i {
+ font-size: 20px;
+ color: red;
+ position: absolute;
+ right: 0px;
+ top: -5px;
+}
+
+.statusbar .wifi {
+ width: 40px;
+ height: 100%;
+ margin-left: 0px;
+ margin-right: 5px;
+ display: inline-block;
+ background-color: white;
+ box-shadow: inset 0px 0px 2px black;
+ border-radius: 100px;
+ background-image: url(../img/wnet.png);
+ background-size: 40px;
+ box-shadow: 0px 0px 10px white;
+}
+
+.statusbar .csv {
+ width: 40px;
+ height: 100%;
+ margin-left: 0px;
+ margin-right: 5px;
+ display: inline-block;
+ background-color: white;
+ box-shadow: inset 0px 0px 2px black;
+ border-radius: 100px;
+ background-image: url(../img/csv.png);
+ background-size: 40px;
+ box-shadow: 0px 0px 10px white;
+}
+
+.statusbar .xero:hover,
+.statusbar .wifi:hover,
+.statusbar .csv:hover {
+ box-shadow: 0px 0px 3px black;
+}
+
+.statusbar .wages {
+ text-align: center;
+ width: 150px;
+ height: 100%;
+ display: inline-block;
+ background-color: transparent;
+ font-size: 24px;
+ font-weight: bold;
+ color: dimgrey;
+ border: 1px dotted white;
+ position: absolute;
+ right: 400px;
+}
+
+.statusbar .workinghours {
+ background-color: transparent;
+ width: 175px;
+ height: 100%;
+ display: inline-block;
+ position: absolute;
+ right: 220px;
+}
+
+.statusbar #woh:hover {
+ cursor: pointer;
+ animation: blinker 0.3s linear infinite;
+}
+
+.workinghours label {
+ transform: unset;
+ left: 0;
+ top: 0;
+ width: 50px;
+ height: 100%;
+ padding: 0.5em;
+ text-align: left;
+ display: inline-block;
+ color: #A974D;
+ font-weight: bolder;
+ line-height: 15px;
+ background-color: transparent;
+ margin-right: 0px;
+}
+
+.statusbar input {
+ margin: 0px;
+ width: 115px;
+ height: 100%;
+ display: inline-block;
+ font-size: 24px;
+ background: transparent;
+ text-align: center;
+}
+
+.statusbar button[name='confirmschedule'] {
+ margin-top: 5px;
+ margin-bottom: 5px ;
+ text-shadow: 0px 0px 2px black;
+ width: 200px ;
+ height: calc( 100% - 10px );
+ font-weight: bolder;
+ position: absolute;
+ right: 10px;
+}
+
+div.sheetsheader {
+ height: 110px;
+ background: darkorange;
+ position: relative;
+}
+
+div.prevweek {
+ display: inline-block;
+ height: 70px;
+ width: 40px;
+ font-size: 36px;
+ padding-top: 5px;
+ padding-left: 2px;
+ float: left;
+ background: darkorange;
+}
+
+div.prevweek span:hover,
+div.nextweek span:hover {
+ box-shadow: 1px 1px 10px black;
+ border-radius: 20px;
+ color: black;
+}
+
+div.nextweek {
+ display: inline-block;
+ height: 70px;
+ width: 40px;
+ font-size: 36px;
+ padding-top: 5px;
+ padding-left: 4px;
+ float: right;
+}
+
+div.weekly {
+ width: calc( 100% - 80px ) ;
+ display: inline-block;
+ background-color: black;
+ height: 70px;
+}
+
+div.weekly div {
+ margin: 0px;
+}
+
+div.weekly div.weekname {
+ position: relative;
+ width: 170px;
+ top: -5px;
+ border: 2px solid grey;
+ border-radius: 10px;
+ text-align: center;
+ color: white;
+
+ /* Permalink - use to edit and share this gradient: https://colorzilla.com/gradient-editor/#b5bdc8+0,828c95+36,28343b+100;Grey+Black+3D */
+ background: rgb(181,189,200); /* Old browsers */
+ background: -moz-linear-gradient(top, rgba(181,189,200,1) 0%, rgba(130,140,149,1) 36%, rgba(40,52,59,1) 100%); /* FF3.6-15 */
+ background: -webkit-linear-gradient(top, rgba(181,189,200,1) 0%,rgba(130,140,149,1) 36%,rgba(40,52,59,1) 100%); /* Chrome10-25,Safari5.1-6 */
+ background: linear-gradient(to bottom, rgba(181,189,200,1) 0%,rgba(130,140,149,1) 36%,rgba(40,52,59,1) 100%); /* W3C, IE10+, FF16+, Chrome26+, Opera12+, Safari7+ */
+ filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#b5bdc8', endColorstr='#28343b',GradientType=0 ); /* IE6-9 */
+}
+
+div.weekly div.weekname input{
+ width: 80px;
+ height: 20px;
+ border:0px;
+ background-color:transparent;
+ color: white;
+ padding-left:4px;
+ padding-right:4px;
+}
+
+div.weekly div.weekname input.hasDatepicker{
+ background-image:none
+}
+
+div.weekly div.weekname.prev {
+ position: absolute;
+ left: 100px;
+ z-index: 1;
+}
+
+div.weekly div.weekname.next {
+ position: absolute;
+ right: 100px;
+ z-index: 1;
+}
+
+div.weekly >div.weekname:hover,
+div.weekly div[name='copyschedule']:hover {
+ cursor: pointer;
+ box-shadow: 0px 0px 10px #2c87f0;
+}
+
+div.weekly div.copyprogress {
+ position: absolute;
+ display: inline-block;
+ width: calc(100% - 80px);
+ height: 15px;
+ top: 0px;
+ border-radius: 2px;
+ box-shadow: inset 1px 1px 2px black;
+ text-align: center;
+
+ /* Permalink - use to edit and share this gradient: https://colorzilla.com/gradient-editor/#fefcea+0,f1da36+100;Gold+3D */
+ background: rgb(254,252,234); /* Old browsers */
+ background: -moz-linear-gradient(top, rgba(254,252,234,1) 0%, rgba(241,218,54,1) 100%); /* FF3.6-15 */
+ background: -webkit-linear-gradient(top, rgba(254,252,234,1) 0%,rgba(241,218,54,1) 100%); /* Chrome10-25,Safari5.1-6 */
+ background: linear-gradient(to bottom, rgba(254,252,234,1) 0%,rgba(241,218,54,1) 100%); /* W3C, IE10+, FF16+, Chrome26+, Opera12+, Safari7+ */
+ filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#fefcea', endColorstr='#f1da36',GradientType=0 ); /* IE6-9 */
+}
+
+div.copyprogress div[name='copyschedule'] {
+ position: relative;
+ top: -5px;
+ width: 150px;
+ height: 25px;
+ padding: 0px;
+ border-radius: 10px;
+ margin: auto;
+ z-index: 1;
+ color: white;
+
+ /* Permalink - use to edit and share this gradient: https://colorzilla.com/gradient-editor/#b5bdc8+0,828c95+36,28343b+100;Grey+Black+3D */
+ background: rgb(181,189,200); /* Old browsers */
+ background: -moz-linear-gradient(top, rgba(181,189,200,1) 0%, rgba(130,140,149,1) 36%, rgba(40,52,59,1) 100%); /* FF3.6-15 */
+ background: -webkit-linear-gradient(top, rgba(181,189,200,1) 0%,rgba(130,140,149,1) 36%,rgba(40,52,59,1) 100%); /* Chrome10-25,Safari5.1-6 */
+ background: linear-gradient(to bottom, rgba(181,189,200,1) 0%,rgba(130,140,149,1) 36%,rgba(40,52,59,1) 100%); /* W3C, IE10+, FF16+, Chrome26+, Opera12+, Safari7+ */
+ filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#b5bdc8', endColorstr='#28343b',GradientType=0 ); /* IE6-9 */
+}
+
+#gotoweek {
+ width: 50%;
+ background-color: transparent;
+ border: 0px;
+ color: white;
+ font-weight: 900;
+}
+
+div.weekdays {
+ position: absolute;
+ top: 15px;
+ width: calc(100% - 80px);
+ height: 55px;
+ background-color: darkorange;
+ text-align: center;
+}
+
+div.week1,
+div.week2 {
+ display: inline-block;
+ width: 45%;
+ height: 55px;
+ background-color: darkorange;
+ text-align: justify;
+ border: 1px dashed lightgrey;
+ padding-left: 10px;
+ padding-right: 10px;
+}
+
+div.week1:hover,
+div.week2:Hover {
+ border-radius: 20px;
+ box-shadow: 0px 0px 2px #2c87f0 inset;
+ cursor: pointer;
+
+ /* Permalink - use to edit and share this gradient: https://colorzilla.com/gradient-editor/#ebf1f6+0,abd3ee+50,89c3eb+51,d5ebfb+100;Blue+Gloss+%234 */
+ background: rgb(235,241,246); /* Old browsers */
+ background: -moz-linear-gradient(top, rgba(235,241,246,1) 0%, rgba(171,211,238,1) 50%, rgba(137,195,235,1) 51%, rgba(213,235,251,1) 100%); /* FF3.6-15 */
+ background: -webkit-linear-gradient(top, rgba(235,241,246,1) 0%,rgba(171,211,238,1) 50%,rgba(137,195,235,1) 51%,rgba(213,235,251,1) 100%); /* Chrome10-25,Safari5.1-6 */
+ background: linear-gradient(to bottom, rgba(235,241,246,1) 0%,rgba(171,211,238,1) 50%,rgba(137,195,235,1) 51%,rgba(213,235,251,1) 100%); /* W3C, IE10+, FF16+, Chrome26+, Opera12+, Safari7+ */
+ filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#ebf1f6', endColorstr='#d5ebfb',GradientType=0 ); /* IE6-9 */
+}
+
+div.week1.filtered,
+div.week2.filtered {
+ border-radius: 20px;
+
+ /* background:white; */
+ /* Permalink - use to edit and share this gradient: https://colorzilla.com/gradient-editor/#ebf1f6+0,abd3ee+50,89c3eb+51,d5ebfb+100;Blue+Gloss+%234 */
+ background: rgb(235,241,246); /* Old browsers */
+ background: -moz-linear-gradient(top, rgba(235,241,246,1) 0%, rgba(171,211,238,1) 50%, rgba(137,195,235,1) 51%, rgba(213,235,251,1) 100%); /* FF3.6-15 */
+ background: -webkit-linear-gradient(top, rgba(235,241,246,1) 0%,rgba(171,211,238,1) 50%,rgba(137,195,235,1) 51%,rgba(213,235,251,1) 100%); /* Chrome10-25,Safari5.1-6 */
+ background: linear-gradient(to bottom, rgba(235,241,246,1) 0%,rgba(171,211,238,1) 50%,rgba(137,195,235,1) 51%,rgba(213,235,251,1) 100%); /* W3C, IE10+, FF16+, Chrome26+, Opera12+, Safari7+ */
+ filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#ebf1f6', endColorstr='#d5ebfb',GradientType=0 ); /* IE6-9 */
+}
+
+div.week1:after,
+div.week2:after {
+ content: '';
+ display: inline-block;
+ width: 100%;
+}
+
+div.week1 {
+ position: relative;
+ left: -10px;
+}
+
+div.week2 {
+ position: relative;
+ left: 10px;
+}
+
+div.week1 > div,
+div.week2 > div {
+ display: inline-block;
+ text-align: center;
+ width: 10%;
+ height: 40px;
+ margin-top: 5px;
+ font-weight: bolder;
+ border-radius: 10px;
+}
+
+div.week1 div:hover,
+div.week2 div:hover {
+ cursor: pointer;
+ box-shadow: 0px 0px 10px red;
+}
+
+div.week1 > div {
+ box-shadow: 0px 0px 10px white inset;
+}
+
+.week1color {
+ color: black;
+
+ /* Permalink - use to edit and share this gradient: https://colorzilla.com/gradient-editor/#ebe9f9+0,d8d0ef+50,cec7ec+51,c1bfea+100;Purple+3D+%231 */
+ background: #ebe9f9; /* Old browsers */
+ background: -moz-linear-gradient(top, #ebe9f9 0%, #d8d0ef 50%, #cec7ec 51%, #c1bfea 100%); /* FF3.6-15 */
+ background: -webkit-linear-gradient(top, #ebe9f9 0%,#d8d0ef 50%,#cec7ec 51%,#c1bfea 100%); /* Chrome10-25,Safari5.1-6 */
+ background: linear-gradient(to bottom, #ebe9f9 0%,#d8d0ef 50%,#cec7ec 51%,#c1bfea 100%); /* W3C, IE10+, FF16+, Chrome26+, Opera12+, Safari7+ */
+ filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#ebe9f9', endColorstr='#c1bfea',GradientType=0 ); /* IE6-9 */
+}
+
+div.week2 > div {
+ box-shadow: 0px 0px 10px white inset;
+}
+
+.week2color {
+ color: white;
+
+ /* Permalink - use to edit and share this gradient: https://colorzilla.com/gradient-editor/#627d4d+0,1f3b08+100;Olive+3D */
+ background: #627d4d; /* Old browsers */
+ background: -moz-linear-gradient(top, #627d4d 0%, #1f3b08 100%); /* FF3.6-15 */
+ background: -webkit-linear-gradient(top, #627d4d 0%,#1f3b08 100%); /* Chrome10-25,Safari5.1-6 */
+ background: linear-gradient(to bottom, #627d4d 0%,#1f3b08 100%); /* W3C, IE10+, FF16+, Chrome26+, Opera12+, Safari7+ */
+ filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#627d4d', endColorstr='#1f3b08',GradientType=0 ); /* IE6-9 */
+}
+
+div.assignment > div {
+ color: navy;
+ background-color: white;
+ font-size: 20px;
+ font-weight: lighter;
+ border: 1px dotted lightgrey;
+}
+
+/* peple item card*/
+.peopleitem div span.checked {
+ color: orange;
+}
+
+.peopleitem div.card div.front > div[name="title"] {
+ height: auto;
+ text-align: center;
+ background-color: lightgrey;
+}
+
+div.front > span[name='icon'] {
+ width: 100%;
+ height: 15px;
+ background-color: dimgrey;
+ color: white;
+}
+
+div.back > span.icon {
+ width: 100%;
+ background-color: lightgrey;
+ color: dimgrey;
+}
+
+div.front > span.badge,
+div.back > span.badge {
+ border-radius: 50%;
+ display: inline-block;
+ padding-left: 8px;
+ padding-right: 8px;
+ text-align: center;
+ position: absolute;
+ right: -5px;
+ top: -5px;
+}
+
+span.badge.blue {
+ color: #fff;
+ box-shadow: 1px 1px 10px black;
+ background-color: black;
+}
+
+span.badge.pink {
+ color: black;
+ box-shadow: 1px 1px 10px white;
+ background-color: white;
+}
+
+/* div table */
+div.blueTable {
+ border: 1px solid #1C6EA4;
+ background-color: white;
+ width: 100%;
+ text-align: left;
+ border-collapse: collapse;
+ border: 0px;
+}
+
+div.blueTable.emptyrecord {
+ background-color: #eeeeee;
+}
+
+.divTable.blueTable .divTableCell,
+.divTable.blueTable .divTableHead,
+ {
+ border: 1px solid #AAAAAA;
+ padding: 3px 2px;
+}
+
+.divTable.blueTable .divTableBody .divTableCell {
+ font-size: 15px;
+}
+
+.divTable.blueTable .divTableRow:nth-child(even) {
+ background: #D0E4F5;
+}
+
+.divTable.blueTable .divTableHeading {
+ background: #1C6EA4;
+ background: -moz-linear-gradient(top, #5592bb 0%, #327cad 66%, #1C6EA4 100%);
+ background: -webkit-linear-gradient(top, #5592bb 0%, #327cad 66%, #1C6EA4 100%);
+ background: linear-gradient(to bottom, #5592bb 0%, #327cad 66%, #1C6EA4 100%);
+ border-bottom: 2px solid #444444;
+}
+
+.divTable.blueTable .divTableHeading .divTableHead {
+ font-size: 15px;
+ font-weight: bold;
+ color: #FFFFFF;
+ border-left: 2px solid #D0E4F5;
+}
+
+.divTable.blueTable .divTableHeading .divTableHead:first-child {
+ border-left: none;
+}
+
+.blueTable .tableFootStyle {
+ font-size: 14px;
+ font-weight: bold;
+ color: #FFFFFF;
+ background: #D0E4F5;
+ background: -moz-linear-gradient(top, #dcebf7 0%, #d4e6f6 66%, #D0E4F5 100%);
+ background: -webkit-linear-gradient(top, #dcebf7 0%, #d4e6f6 66%, #D0E4F5 100%);
+ background: linear-gradient(to bottom, #dcebf7 0%, #d4e6f6 66%, #D0E4F5 100%);
+ border-top: 2px solid #444444;
+}
+
+.blueTable .tableFootStyle {
+ font-size: 14px;
+}
+
+.blueTable .tableFootStyle .links {
+ text-align: right;
+}
+
+.blueTable .tableFootStyle .links a {
+ display: inline-block;
+ background: #1C6EA4;
+ color: #FFFFFF;
+ padding: 2px 8px;
+ border-radius: 5px;
+}
+
+.blueTable.outerTableFooter {
+ border-top: none;
+}
+
+.blueTable.outerTableFooter .tableFootStyle {
+ padding: 3px 5px;
+}
+
+/* DivTable.com */
+.divTable {
+ display: table;
+ margin: 3px 0px 3px 0px;
+}
+
+.divTable.highlight {
+ box-shadow: 1px 1px 10px green;
+}
+
+.divTable.invalidjob.highlight {
+ box-shadow: 1px 1px 10px #f50202;
+}
+
+.divTable.highlight.newcopy {
+ box-shadow: 1px 1px 10px orange;
+ border: 5px orange solid;
+}
+
+.divTableRow {
+ display: table-row;
+}
+
+.divTableRow.errmsg {
+ background-color: white;
+ font-weight: bolder;
+ color: red;
+}
+
+.divTableHeading {
+ display: table-header-group;
+}
+
+.divTableCell,
+.divTableHead {
+ display: table-cell;
+}
+
+.divTableHeading {
+ display: table-header-group;
+}
+
+.divTableFoot {
+ display: table-footer-group;
+}
+
+.divTableBody {
+ display: table-row-group;
+}
+
+/* customized part of div table */
+div.sheettableheader {
+ margin-top: 0px;
+ height: 36px;
+ overflow-x: hidden;
+ overflow-y: scroll;
+}
+
+div.btos,
+div.bstart,
+div.bfinish,
+div.brate,
+div.bstaff,
+div.bclient,
+div.bconfirmed,
+div.bsave,
+div.brating,
+div.bdelete {
+ width: 10%;
+ height: 30px;
+}
+
+div.btos {
+ width: 20%;
+}
+
+div.bstart,
+div.bfinish {
+ width: 11%;
+}
+
+div.brate {
+ width: 10%;
+ max-width: 20px;
+}
+
+.divTable div > select {
+ width: 100%;
+ height: 100%;
+}
+
+div.bdelete,
+div.bsave,
+div.bconfirmed {
+ text-align: center;
+ width: 5%;
+}
+
+div.brating {
+ text-align: center;
+ cursor: pointer;
+}
+
+.brating {
+ unicode-bidi: bidi-override;
+ direction: rtl;
+}
+
+div.workspace .brating > span:hover:before,
+div.workspace .brating > span:hover ~ span:before {
+ content: "\2605";
+ position: absolute;
+}
+
+div.bsave span.ticon-copy {
+ display: none;
+}
+
+div.bsave span.ticon-save {
+ display: inline-block;
+ border: 3px solid lightgrey;
+ padding: 5px;
+ border-radius: 5px;
+ color: black;
+ cursor: pointer;
+}
+
+div.bsave.saved span.ticon-save {
+ display: none;
+}
+
+div.bsave.saved span.ticon-copy {
+ display: inline-block;
+ border: 3px solid orange;
+ padding: 5px;
+ border-radius: 20px;
+ color: orange;
+}
+
+div.bdelete span.ticon-trash {
+ display: inline-block;
+ border: 3px solid lightgrey;
+ padding: 5px;
+ border-radius: 5px;
+ color: red;
+ cursor: pointer;
+}
+
+div.workspace div > span:hover {
+ box-shadow: 0px 0px 10px black;
+}
+
+div.divTableHeading div > span:hover {
+ cursor: pointer;
+ animation: blinker 0.3s linear infinite;
+}
+
+/* short code for the table */
+div.btos select,
+div.bstart input,
+div.bfinish input {
+ width: 100%;
+ height: 98%;
+}
+
+div.divTable.validjob {
+ border: 0px solid white;
+}
+
+div.divTable.invalidjob {
+ border-left: 2px solid red;
+ border-right: 2px solid red;
+}
+
+div.divTable .invalid {
+ background-color: yellow;
+}
+
+/* end of div table */
+/* pop up message box */
+.bts_message .ult_modal-body {
+ height: 50vh;
+ overflow: scroll;
+}
+
+.bts_message .ult_modal-body .sent {
+ color: green;
+}
+
+.bts_message .ult_modal-body .nojob {
+ color: dimgrey;
+}
+
+.bts_message .ult_modal-body .error {
+ color: red;
+}
+
+.bts_message .ult_modal-body .span {
+ font-weight: 900;
+}
\ No newline at end of file
diff --git a/html/jobv1.html b/html/jobv1.html
new file mode 100644
index 0000000..48b671c
--- /dev/null
+++ b/html/jobv1.html
@@ -0,0 +1,38 @@
+
+
+
+
+
+ {{tos_name}}
+
+
{{start}}
+
{{finish}}
+
{{rate_name}}
+
{{staff_name}}
+
{{client_name}}
+
+
{{rating}}
+
+
+
+
+
+
+
+
+
+
e tos
+
+
es
+
ef
+
er
+
estaf
+
ecli
+
econfirm
+
erat
+
edel
+
eeave
+
+
+
+
\ No newline at end of file
diff --git a/js/bts_office.js b/js/bts_office.js
new file mode 100644
index 0000000..6d97123
--- /dev/null
+++ b/js/bts_office.js
@@ -0,0 +1,1528 @@
+(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("#jobv1_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;
+ return 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_jobv1", // 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");
+
+ $(document).on('click', 'div.clientlist div[name="title"] a', function(e){
+ e.preventDefault();
+ e.stopPropagation();
+ var id = $(this).closest('label.peopleitem').attr('data-id').substring(1);
+ var str = 'https://acaresydncy.com.au/feedback_card/' + id;
+ var name = $(this).html();
+ if ( confirm ("Email feedback link of : " + name + "\n\n\n" + str + "\n\n\n to helen@acaresydney.com.au?")){
+ $.post(bts().ajax_url, { // POST request
+ _ajax_nonce: bts().nonce, // nonce
+ action: "email_feedback_url", // action
+ client : id,
+ }, function(response, status, xhr){
+ //alert('please check your email on the phone and SMS the link to your client');
+ }).fail(function(){
+ alert('network error ');
+ });
+ }
+ });
+
+ 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);
+ });
+
+});
+
+
diff --git a/ts.php b/ts.php
index 25a47e6..fd1445c 100644
--- a/ts.php
+++ b/ts.php
@@ -22,14 +22,23 @@ class AcareOffice{
private $bts_week_id = 1; //week 1, we will try to calculate current week;
private $xero ;
private $db;
- private $table_name;
+ private $table_name; //default to job_table
+ private $job_table;
+ private $allowance_table;
private $addr_table;
+ private $ndis_table;
+ private $apiv1;
public function __construct() {
+ $this->setup_db_name();
+ $this->class_loader();
+ $this->apiv1 = new Apiv1($this, $this->job_table);
+
+
add_option( "acare_ts_db_version", "1.0" );
register_activation_hook( __FILE__, array($this, 'db_install') );
- add_action('init', array($this, 'class_loader'));
+ //add_action('init', array($this, 'class_loader'));
add_action('wp', array($this, 'check_auth'));
add_action('wp_enqueue_scripts', array($this, 'register_js_css'), 99);
@@ -61,6 +70,7 @@ class AcareOffice{
add_action('wp_ajax_list_client', array($this,'list_client' ));
add_action('wp_ajax_save_job', array($this,'save_job' ));
add_action('wp_ajax_list_job', array($this,'list_job' ));
+
add_action('wp_ajax_delete_job', array($this,'delete_job' ));
add_action('wp_ajax_email_job', array($this,'email_job' ));
add_action('wp_ajax_email_feedback_url', array($this,'email_feedback_url' ));
@@ -93,12 +103,18 @@ class AcareOffice{
add_filter('query_vars', array($this,'add_query_vars'));
+
+ }
+
+ private function setup_db_name()
+ {
global $wpdb;
$this->db = $wpdb;
- $this->table_name = $wpdb->prefix . 'acare_ts';
+ $this->table_name = $wpdb->prefix . 'acare_ts'; //for backward compatability;
+ $this->job_table = $wpdb->prefix . 'acare_ts';
+ $this->allowance_table = $wpdb->prefix . 'acare_allowance';
$this->addr_table = $wpdb->prefix . 'acare_addr_distance';
$this->ndis_table = $wpdb->prefix . 'acare_ndis_price';
-
}
/**
@@ -144,7 +160,7 @@ class AcareOffice{
header("Content-Disposition:attachment; filename=$filename");
header("Content-Type: application/force-download");
//readfile(dirname(__FILE__) . "/img/circle.png");
- echo "fuck this file";
+ echo "content of this file";
exit();
}
@@ -398,6 +414,7 @@ class AcareOffice{
$this->bts_user_id = get_query_var( 'bts_user_id' ) ;
$this->register_bts_js();
$this->register_timesheet_js_css();
+ $this->register_office_js_css();
$this->register_task_js_css();
$this->register_feedback_card_js_css();
$this->register_xeroc_js_css();
@@ -439,6 +456,27 @@ class AcareOffice{
$url = plugins_url('jquery-ui-1.11.4.theme/jquery-ui.min.css', __FILE__);
wp_enqueue_style('jquery-ui-smoothness', $url, false, null);
}
+
+ private function register_office_js_css(){
+ global $pagename;
+ if ($pagename != 'office'){
+ return;
+ }
+ wp_enqueue_style( 'bts_office', plugins_url('css/bts_office.css', __FILE__));
+ wp_enqueue_script( 'bts_office', plugins_url('js/bts_office.js', __FILE__), array( 'jquery' , 'bts' ));
+ wp_enqueue_script('mustache', plugins_url('js/mustache.min.js', __FILE__), array('jquery'));
+
+ global $wp_scripts;
+ wp_enqueue_script('jquery-ui-datepicker');
+ // get registered script object for jquery-ui
+ //$ui = $wp_scripts->query('jquery-ui-core');
+ // tell WordPress to load the Smoothness theme from Google CDN
+ //$protocol = is_ssl() ? 'https' : 'http';
+ // $url = "$protocol://ajax.googleapis.com/ajax/libs/jqueryui/{$ui->ver}/themes/smoothness/jquery-ui.min.css";
+ $url = plugins_url('jquery-ui-1.11.4.theme/jquery-ui.min.css', __FILE__);
+ wp_enqueue_style('jquery-ui-smoothness', $url, false, null);
+ }
+
private function register_task_js_css(){
global $pagename;