From 3f14d68912b80a10df752acae1b7b425a3f5c403 Mon Sep 17 00:00:00 2001 From: patrick Date: Thu, 1 Aug 2019 03:41:39 +1000 Subject: [PATCH] customer can feedbacn and url is produced from command line --- UserJob.php | 49 +++++-- css/feedback_card.css | 142 ++++++++++++++++++++ html/feedback_card.html | 41 ++++++ img/circle.png | Bin 0 -> 23089 bytes js/feedback_card.js | 282 ++++++++++++++++++++++++++++++++++++++++ ts.php | 162 ++++++++++++++++++++++- 6 files changed, 662 insertions(+), 14 deletions(-) create mode 100644 css/feedback_card.css create mode 100644 html/feedback_card.html create mode 100644 img/circle.png create mode 100644 js/feedback_card.js diff --git a/UserJob.php b/UserJob.php index 89af4d2..deffea0 100644 --- a/UserJob.php +++ b/UserJob.php @@ -17,17 +17,9 @@ class UserJob{ global $wpdb; $this->db = $wpdb; $this->table_name = $wpdb->prefix . 'acare_ts'; - - $this->jobs = $this->list_jobs("2019-07-01", "2019-07-14"); } - private function is_staff() - { - $roles = get_userdata($this->user->ID)->roles; - return $roles == 'staff'; - } - - public function list_jobs($start, $finish){ + public function list_jobs_by_staff($start, $finish){ $response = array( 'status'=>'success', 'jobs' => [], @@ -67,6 +59,45 @@ class UserJob{ return $response; } + public function list_jobs_by_client($start, $finish){ + $response = array( + 'status'=>'success', + 'jobs' => [], + 'client_name'=>$this->user->display_name, + 'job_count' => 0. + ); + $sql = "SELECT * FROM $this->table_name WHERE start>='%s' and start <='%s' and client='%s' order by start ASC"; + //$query = $this->db->prepare ($sql, array($start, $finish, $this->user->user_login)); + $query = $this->db->prepare ($sql, array($start, $finish, "593d3253-07d0-40a7-8b8e-1a5df05a56db")); + $jobs = $this->db->get_results($query); + $response['job_count'] = count($jobs); + //$response['sql'] = $query; + if ($this->db->last_error == ""){ + $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' => (int) $s->rating, + //descriptions + 'rate_str'=> $this->get_rate_str($s->rate), + 'tos_str'=> $this->get_tos_str($s->tos), + 'staff_name' => $this->get_display_name($s->staff), + ); + } + + }else{ + $response['status'] = 'error'; + $response['err'] = $this->db->last_error; + } + return $response; + } private function get_rate_str($earnings_rate_id) { diff --git a/css/feedback_card.css b/css/feedback_card.css new file mode 100644 index 0000000..a06e526 --- /dev/null +++ b/css/feedback_card.css @@ -0,0 +1,142 @@ +@CHARSET "UTF-8"; +.card { + /* Add shadows to create the "card" effect */ + box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2); + transition: 0.3s; +} + +/* On mouse-over, add a deeper shadow */ +.card:hover { + box-shadow: 0 8px 16px 0 rgba(0,0,0,0.2); +/* Permalink - use to edit and share this gradient: https://colorzilla.com/gradient-editor/#d6f9ff+0,9ee8fa+100;Blue+3D */ +background: rgb(214,249,255); /* Old browsers */ +background: -moz-linear-gradient(top, rgba(214,249,255,1) 0%, rgba(158,232,250,1) 100%); /* FF3.6-15 */ +background: -webkit-linear-gradient(top, rgba(214,249,255,1) 0%,rgba(158,232,250,1) 100%); /* Chrome10-25,Safari5.1-6 */ +background: linear-gradient(to bottom, rgba(214,249,255,1) 0%,rgba(158,232,250,1) 100%); /* W3C, IE10+, FF16+, Chrome26+, Opera12+, Safari7+ */ +filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#d6f9ff', endColorstr='#9ee8fa',GradientType=0 ); /* IE6-9 */ + +} + +/* Add some padding inside the card container */ +.card .container { + padding: 2px 0px; + min-height:300px; + position: relative; +} + +.card .container.rated { + background: url('../img/circle.png') no-repeat center; + background-size: contain; + +} + +.card img{ + width:100%; +} + +.card .ratecontainer{ + display : inline-block; + position : relative; + text-align: center; + width: 100%; + position:absolute; + bottom: 5px; +} + +.card .container p, +.card .container h1{ + margin-top:5px; + margin-bottom:5px; + margin-left:16px; + margin-right:16px; +} +.card .container h1{ + font-weight:900; + min-height:100px; + max-height:100px; +} + +.day_of_week{ + font-weight:900; + font-size: 5em; + text-align: center; + background-color:dimgrey; + color:white; + text-shadow: 0 0 10px #0e0606; +} + +.job_start, +.job_finish { + display:inline-block; + font-weight:900; + width: 50%; + font-size:3em; + background-color:grey; + color:white; + margin:0px; + padding:0px; + text-align:center; + box-shadow:0 0 2px black inset; + text-shadow: 0 0 10px #0e0606; +} + +.job_time{ + box-shadow:0 0 2px white inset; +} + +.job_day_of_week{ + position: absolute; + top: 1px; + color: white; + right: 20px; + font-size: 1em; + font-weight: bolder; + border-left: 1px dotted white; + border-bottom: 1px dotted white; + padding: 0 10px 0 10px; +} + + + +.rate { + float: left; + height: 46px; + padding: 0 10px; + display: block; +} +.rate:not(:checked) > input { + position:absolute; + /* top:-9999px; */ + visibility:hidden; +} +.rate:not(:checked) > label { + float:right; + width:1em; + overflow:hidden; + white-space:nowrap; + cursor:pointer; + font-size: 2.6em; + color:#ccc; +} +.rate:not(:checked) > label:before { + content: '★ '; +} +.rate > input:checked ~ label { + color: #ffc700; +} +.rate:not(:checked) > label:hover, +.rate:not(:checked) > label:hover ~ label { + color: #deb217; +} +.rate > input:checked + label:hover, +.rate > input:checked + label:hover ~ label, +.rate > input:checked ~ label:hover, +.rate > input:checked ~ label:hover ~ label, +.rate > label:hover ~ input:checked ~ label { + color: #c59b08; +} + +.ult_modal-body{ + height:60vh; + width:80vw; +} \ No newline at end of file diff --git a/html/feedback_card.html b/html/feedback_card.html new file mode 100644 index 0000000..df943be --- /dev/null +++ b/html/feedback_card.html @@ -0,0 +1,41 @@ +{{#jobs}} +
+
+
+
+
+
+
+
{{hl_start_date}}
+
{{hl_start}}
{{hl_finish}}
+
{{start_day}}
+
+
+

+ {{staff_name}} +

+

{{start}} {{start_day}}

+

{{finish}} {{finish_day}}

+

{{tos_str}}

+
+
+ + + + + + + + + + +
+
+
+
+
+
+
+
+
+{{/jobs}} \ No newline at end of file diff --git a/img/circle.png b/img/circle.png new file mode 100644 index 0000000000000000000000000000000000000000..dc7ef1649f0a147d3dcc128243d8e4afde4c8059 GIT binary patch literal 23089 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 z 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 literal 0 HcmV?d00001 diff --git a/js/feedback_card.js b/js/feedback_card.js new file mode 100644 index 0000000..a44cf35 --- /dev/null +++ b/js/feedback_card.js @@ -0,0 +1,282 @@ +(function ($) { + $(function () { +/*_____________________________________________*/ + var template = $('#bts_feedback_card').html(); + for (var i=0;i<1;i++){ + var data = {id: i}; + var h = Mustache.render(template, data); + $("#workspace").after(h); + } + + $('input').click(function(){ + var d = $(this).closest('div.rate').attr('data-job-id'); + alert('job id =' + d + ' ' + $(this).attr('value')); + }); + + + function get_my_jobs(){ + $.post(bts().ajax_url, { // POST request + _ajax_nonce: bts().nonce, // nonce + action: "list_job_by_client", // action + start: get_start_date(), + finish: get_finish_date(), + }, function(response, status, xhr){ + if (response.status == "success"){ + pre_process(response); + load_client_jobs(response); + }else{ + display_error(response); + } + }); + } + + //add extra info to response.jobs + function pre_process(response) + { + var newjobs = []; + $.each(response.jobs, function(idx, val){ + + val.hl_start_date = get_hl_start_date(val.start); + val.hl_start = get_hl_start(val.start); + val.hl_finish = get_hl_finish(val.finish); + + val.checked_1 = get_checked(1, val.rating); + val.checked_2 = get_checked(2, val.rating); + val.checked_3 = get_checked(3, val.rating); + val.checked_4 = get_checked(4, val.rating); + val.checked_5 = get_checked(5, val.rating); + + if (val.rating >=1 && val.rating<=5){ + val.rated= 'rated'; + } + + val.start_day = get_weekday_name(val.start); + val.finish_day = get_weekday_name(val.finish); + newjobs.push(val); + }); + response.jobs = newjobs; + } + + function get_hl_start_date(start) + { + var s = new Date(start); + dd = s.getDate(); + if (dd< 10) + dd = "0" + dd; + m = s.getMonth() + 1; + return dd +"/" + m; + } + function get_hl_start(start) + { + return get_hh_mm(start); + } + function get_hl_finish(finish) + { + return get_hh_mm(finish); + } + function get_hh_mm(date){ + var s = new Date(date); + var hh = s.getHours(); + var mm = s.getMinutes(); + if (hh<10) + hh = "0" + hh; + if (mm<10) + mm = "0" + mm; + return hh +":"+ mm ; + + } + + function get_checked(idx, rating) + { + if ( idx == rating) + return "checked"; + else + return ""; + } + + function load_client_jobs(response) + { + set_user_name_at_summary(response.client_name); + var template = $('#bts_feedback_card').html(); + var html = Mustache.render(template, response); + $("#workspace").after(html); + } + + function set_user_name_at_summary(name){ + var title = ''; + if ( typeof name != 'undefined' && name != "") + title = name + "'s Schedule"; + else + title = "Service Schedule"; + $('.bts_client_name span').html(title); + } + + function display_error() + { + err_message_box("Network Error", "Your Jobs for this week cannot be loaded, please try again later. For urgent job arrangement please contact Helen directly."); + } + + function get_weekday_name(dateString) + { + var days = ['Sun', 'Mon', 'Tue', 'Wed', 'Thur', 'Fri', 'Sat']; + var d = new Date(dateString); + var dayName = days[d.getDay()]; + return dayName; + } + + function format_date(date){ + var dd = date.getDate(); + var mm = date.getMonth() + 1; //January is 0! + var hh = date.getHours(); + var ii = date.getMinutes(); + var ss = date.getSeconds(); + var yyyy = date.getFullYear(); + + if (dd < 10) { + dd = '0' + dd; + } + if (mm < 10) { + mm = '0' + mm; + } + if (hh< 10){ + hh = '0' + hh; + } + if (ii < 10){ + ii = '0' + ii; + } + + if (ss <10 ){ + ss = '0' + ss; + } + return yyyy + '-' + mm + '-' +dd + " " +hh +":" + ii + ":" + ss; + } + + function format_date_only(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 get_this_week_start(){ + var curr = new Date; // get current date + // First day is the day of the month - the day of the week + var first = curr.getDate() - curr.getDay() + 1; //+1 we want Mon as first + var last = first + 6; // last day is the first day + 6 + + var firstday = new Date(curr.setDate(first)); //Mon + firstday.setHours(0,0,0); + return format_date(firstday); + } + + function get_this_week_end(){ + var curr = new Date; // get current date + // First day is the day of the month - the day of the week + var first = curr.getDate() - curr.getDay() + 1; //+1 we want Mon as first + var last = first + 6; // last day is the first day + 6 + var lastday = new Date(curr.setDate(last)); //Sat + lastday.setHours(23,59,59); + return format_date(lastday); + } + + function get_start_date() + { + var b=feedback_card; + if (b.bts_job_start != '') + return b.bts_job_start + " 00:00:00"; + else + return get_this_week_start(); + } + function get_finish_date() + { + var b=feedback_card; + if (b.bts_job_finish != '') + return b.bts_job_finish +" 23:59:59"; + else + return get_this_week_end(); + } + + function info_message_box(title, message) + { + message_box('.job_ok_box', title, message); + } + + function err_message_box(title, message) + { + message_box('.job_error_box', title, message); + } + + function message_box(selector, title,message) + { + set_modal_title(selector, title); + set_modal_message(selector, message); + $(selector + '_trigger').trigger('click'); + } + + function set_modal_title(selector, title) + { + var el = selector + ' .ult_modal-title '; + $(el).html(title); + } + + function set_modal_message(selector, msg) + { + var el = selector + ' .ult_modal-body '; + $(el).html(msg); + } + + + function do_update_ack(id, rating) + { + $.post(bts().ajax_url, { // POST request + _ajax_nonce: bts().nonce, // nonce + action: "client_ack_job", // action + job_id: id, + rating: rating, + }, function(response, status, xhr){ + if (response.status == "success"){ + display_job_ack(id, response.rating); + }else{ + console.warn("%o", response); + clear_job_ack(id); + } + }); + } + + function clear_job_ack(id) + { + display_job_ack(id, 0); //clear it + } + function display_job_ack(id, rating) + { + for (var i=1; i<=5; i++){ + var selector = 'star' + i + '_' + id; + $(selector).prop('checked',(rating == i)); + } + if (rating >=1 && rating <=5){ + $('#container_' + id).addClass('rated'); + }else{ + $('#container_' + id).removeClass('rated'); + } + } + + $(document).on('click', '.card input[type="radio"]', function(){ + var job_id = $(this).closest('div.rate').attr('data-job-id'); + var rating = $(this).attr('value'); + do_update_ack(job_id, rating); + }); + + + get_my_jobs(); + +/*_____________________________________________*/ + }); +})(jQuery); + diff --git a/ts.php b/ts.php index 61d6d74..eebc770 100644 --- a/ts.php +++ b/ts.php @@ -46,6 +46,7 @@ class AcareOffice{ add_shortcode( 'bts_select_client', array($this, 'bts_select_client')); add_shortcode( 'bts_type_of_service', array($this, 'bts_type_of_service')); add_shortcode( 'bts_staff_job_summary', array($this, 'bts_staff_job_summary')); + add_shortcode( 'bts_feedback_card', array($this, 'bts_feedback_card')); //user profile page add_shortcode( 'bts_user_name', array($this,'bts_user_name')); @@ -67,6 +68,13 @@ class AcareOffice{ add_action('wp_ajax_staff_ack_job', array($this,'staff_ack_job' )); add_action('wp_ajax_nopriv_staff_ack_job', array($this,'staff_ack_job' )); + add_action('wp_ajax_list_job_by_client', array($this,'list_job_by_client' )); + add_action('wp_ajax_nopriv_list_job_by_client', array($this,'list_job_by_client' )); + + add_action('wp_ajax_client_ack_job', array($this,'client_ack_job' )); + add_action('wp_ajax_nopriv_client_ack_job', array($this,'client_ack_job' )); + + // hook add_rewrite_rules function into rewrite_rules_array add_filter('rewrite_rules_array', array($this,'my_add_rewrite_rules')); // hook add_query_vars function into query_vars @@ -173,6 +181,12 @@ class AcareOffice{ 'task/([^/]+)/week-([^/]+)/?$' => 'index.php?pagename=task&bts_user_id=$matches[1]&bts_week_id=$matches[2]', 'task/([^/]+)/start-([^/]+)/finish-([^/]+)/?$' => 'index.php?pagename=task&bts_user_id=$matches[1]&bts_job_start=$matches[2]&bts_job_finish=$matches[3]', + 'feedback_card/week-([^/]+)/?$' => 'index.php?pagename=feedback_card&bts_week_id=$matches[1]', + 'feedback_card/start-([^/]+)/finish-([^/]+)/?$' => 'index.php?pagename=feedback_card&bts_job_start=$matches[1]&bts_job_finish=$matches[2]', + 'feedback_card/([^/]+)/?$' => 'index.php?pagename=feedback_card&bts_user_id=$matches[1]', + 'feedback_card/([^/]+)/week-([^/]+)/?$' => 'index.php?pagename=feedback_card&bts_user_id=$matches[1]&bts_week_id=$matches[2]', + 'feedback_card/([^/]+)/start-([^/]+)/finish-([^/]+)/?$' => 'index.php?pagename=feedback_card&bts_user_id=$matches[1]&bts_job_start=$matches[2]&bts_job_finish=$matches[3]', + ); $aRules = $aNewRules + $aRules; return $aRules; @@ -190,6 +204,10 @@ class AcareOffice{ break; case 'time-sheets': $this->cauth_time_sheet(); + break; + case 'feedback_card': + $this->cauth_feedback_card(); + break; } } @@ -237,6 +255,43 @@ class AcareOffice{ } } + private function cauth_feedback_card(){ + $login = get_query_var( 'bts_user_id' ); + $this->bts_job_start = get_query_var( 'bts_job_start' ); + $this->bts_job_finish = get_query_var( 'bts_job_finish' ); + $this->bts_week_id = get_query_var('bts_week_id'); + + $redirect_url = $this->get_redirect_url_for_feedback_card(); + + if ($login != "")//perform autologin, and redirect + { + $client = get_user_by('login', $login); + if ($this->is_client($client)){//is valid client; + $current = wp_get_current_user(); + if($current->ID != $client->ID){ + wp_logout(); + wp_set_current_user($client->ID, $client->display_name); //this is a must + wp_set_auth_cookie($client->ID, true);//only with this, wordpress calls login + redirect and lost week-%d + } + } + wp_redirect($redirect_url); + return; + } + + //no auto login is required if reach here. + $current = wp_get_current_user(); + if ($this->is_admin($current)){ + wp_redirect("/time-sheets/"); + return; + } + if (!$this->is_client($current) && ! $this->is_admin($current)) + { + wp_logout(); + wp_redirect("/login/"); + return; + } + } + private function get_week_id() { $week = get_query_var( 'bts_week_id' ); @@ -263,6 +318,15 @@ class AcareOffice{ return '/task/'; } + private function get_redirect_url_for_feedback_card() + { + if ($this->bts_week_id != "") + return "/feedback_card/week-" . $this->bts_week_id . "/"; + if ($this->bts_job_start!="" && $this->bts_job_finish !="") + return "/feedback_card/start-" . $this->bts_job_start . "/finish-" .$this->bts_job_finish . "/"; + return '/feedback_card/'; + } + private function cauth_time_sheet() { @@ -296,6 +360,7 @@ class AcareOffice{ $this->register_bts_js(); $this->register_timesheet_js_css(); $this->register_task_js_css(); + $this->register_feedback_card_js_css(); } private function register_bts_js() { @@ -348,6 +413,29 @@ class AcareOffice{ ) ); } + private function register_feedback_card_js_css() + { + global $pagename; + if ($pagename != 'feedback_card'){ + return; + } + + $this->bts_job_start = get_query_var( 'bts_job_start' ); + $this->bts_job_finish = get_query_var( 'bts_job_finish' ); + $this->bts_week_id = get_query_var('bts_week_id'); + + wp_enqueue_style( 'feedback_card', plugins_url('css/feedback_card.css', __FILE__)); + wp_enqueue_script( 'feedback_card', plugins_url('js/feedback_card.js', __FILE__), array( 'jquery' , 'bts' )); + wp_enqueue_script('mustache', plugins_url('js/mustache.min.js', __FILE__), array('jquery')); + + wp_localize_script('feedback_card','feedback_card',array( + 'ajax_url' => admin_url( 'admin-ajax.php' ), + 'nonce' => wp_create_nonce('feedback_card'), + 'week_id' => $this->bts_week_id, + 'bts_job_start' => $this->bts_job_start, + 'bts_job_finish' => $this->bts_job_finish, + ) ); + } public function sync_users() { @@ -370,7 +458,7 @@ class AcareOffice{ $users = get_users(array('role' => 'staff')); foreach ($users as $u){ $n = new UserJob($u->user_login); - $resp = $n->list_jobs("2019-07-22 00:00:00", "2019-07-28 23:59:59"); + $resp = $n->list_jobs_by_staff("2019-07-22 00:00:00", "2019-07-28 23:59:59"); if ($resp['status']=='success' && $resp['job_count'] >0 ){ if( $u->user_login != "9aa3308e-cc19-4c21-a110-f2c6abec4337" ) continue; @@ -460,6 +548,12 @@ class AcareOffice{ "; return $result; } + + public function bts_feedback_card($attr) + { + return $this->template('bts_feedback_card', 'feedback_card.html'); + } + //generate template based on html file private function template($id, $file) { @@ -711,7 +805,7 @@ class AcareOffice{ } public function list_job_by_staff() { - //check_ajax_referer('acaresydney'); + check_ajax_referer('acaresydney'); $start = $_POST['start']; $finish = $_POST['finish']; @@ -719,9 +813,9 @@ class AcareOffice{ //$finish="2019-07-14 23:59:59"; $user = wp_get_current_user();// should be staff; - if ( $this->is_staff($user) ){ + if ( $this->is_staff($user) || $this->is_admin($user) ){ $n = new UserJob($user->user_login); - $response = $n->list_jobs($start, $finish); + $response = $n->list_jobs_by_staff($start, $finish); wp_send_json($response); }else{ $response = array( @@ -734,11 +828,38 @@ class AcareOffice{ wp_die(); } + public function list_job_by_client() + { + check_ajax_referer('acaresydney'); + $start = $_POST['start']; + $finish = $_POST['finish']; + + //$start="2019-07-01 00:00:00"; + //$finish="2019-07-14 23:59:59"; + + $user = wp_get_current_user();// should be staff; + if ( $this->is_client($user) || $this->is_admin($user) ){ + $n = new UserJob($user->user_login); + $response = $n->list_jobs_by_client($start, $finish); + wp_send_json($response); + }else{ + $response = array( + 'status' => 'error', + 'errmsg' => 'invalid access', + 'user' => $user, + ); + wp_send_json($response); + } + wp_die(); + } private function is_staff($user) { return ($user->ID !=0 && in_array('staff', $user->roles)); } - + private function is_client($user) + { + return ($user->ID !=0 && in_array('client', $user->roles)); + } private function is_admin($user) { $allowed_roles = array('administrator', 'acare_owner'); @@ -793,6 +914,36 @@ class AcareOffice{ $err .= $this->db->last_error; } return $err; + } + public function client_ack_job() + { + check_ajax_referer('acaresydney'); + $job_id = $_POST['job_id']; + $rating = $_POST['rating']; + + $response = array( + 'status'=>'success', + ); + $sql= "UPDATE $this->table_name SET rating=%d WHERE id = %d ; "; + $sql= $this->db->prepare($sql, array($rating, $job_id)); + + $result = $this->db->get_results($sql); + $response['rating'] = (int) $rating; + if ($this->db->last_error !='') + { + $response['status']= 'error'; + $response['err_msg']= $this->db->last_error; + $response['rating'] = 0; + } + wp_send_json($response); + } + + public function feedback_url() + { + $users = get_users(array('role'=>'client')); + foreach($users as $u){ + echo sprintf("%s:\t https://acaresydney.com.au/feedback_card/%s/\n", $u->display_name, $u->user_login); + } } } @@ -801,6 +952,7 @@ $bb = new AcareOffice(); if ( defined( 'WP_CLI' ) && WP_CLI ) { \WP_CLI::add_command( 'sync_users', array($bb, 'sync_user_cli')); \WP_CLI::add_command( 'email_jobs', array($bb, 'email_jobs')); + \WP_CLI::add_command( 'feedback_url', array($bb, 'feedback_url')); } //$bb->class_loader();