Explorar el Código

customer can feedbacn and url is produced from command line

master
patrick hace 6 años
padre
commit
3f14d68912
Se han modificado 6 ficheros con 662 adiciones y 14 borrados
  1. +40
    -9
      UserJob.php
  2. +142
    -0
      css/feedback_card.css
  3. +41
    -0
      html/feedback_card.html
  4. BIN
      img/circle.png
  5. +282
    -0
      js/feedback_card.js
  6. +157
    -5
      ts.php

+ 40
- 9
UserJob.php Ver fichero

@@ -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)
{

+ 142
- 0
css/feedback_card.css Ver fichero

@@ -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;
}

+ 41
- 0
html/feedback_card.html Ver fichero

@@ -0,0 +1,41 @@
{{#jobs}}
<div class="wpb_column vc_column_container vc_col-lg-3" id="card_{{id}" data-job-id="{{id}}">
<div class="vc_column-inner ">
<div class="wpb_wrapper">
<div class="wpb_raw_code wpb_content_element wpb_raw_html">
<div class="wpb_wrapper">
<div class="card">
<div class='job_time'>
<div class='day_of_week' >{{hl_start_date}}</div>
<div class='job_start' >{{hl_start}}</div><div class='job_finish'>{{hl_finish}}</div>
<div class='job_day_of_week'>{{start_day}}</div>
</div>
<div class="container {{rated}}" id="container_{{id}}">
<h1>
<b>{{staff_name}}</b>
</h1>
<p name='start_datetime'>{{start}}<strong> {{start_day}}</strong></p>
<p name='finish_datetime'>{{finish}}<strong> {{finish_day}}</strong></p>
<p name='type_of_service'>{{tos_str}}</p>
<div class='ratecontainer' >
<div class="rate" data-job-id="{{id}}">
<input type="radio" id="star5_{{id}}" name="rate_group_{{id}}" value="5" {{checked_5}} />
<label for="star5_{{id}}" title="Best ">5 stars</label>
<input type="radio" id="star4_{{id}}" name="rate_group_{{id}}" value="4" {{checked_4}} />
<label for="star4_{{id}}" title="Better">4 stars</label>
<input type="radio" id="star3_{{id}}" name="rate_group_{{id}}" value="3" {{checked_3}} />
<label for="star3_{{id}}" title="Good">3 stars</label>
<input type="radio" id="star2_{{id}}" name="rate_group_{{id}}" value="2" {{checked_2}} />
<label for="star2_{{id}}" title="Standard">2 stars</label>
<input type="radio" id="star1_{{id}}" name="rate_group_{{id}}" value="1" {{checked_1}} />
<label for="star1_{{id}}" title="Bad">1 star</label>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{{/jobs}}

BIN
img/circle.png Ver fichero

Antes Después
Anchura: 512  |  Altura: 512  |  Tamaño: 23KB

+ 282
- 0
js/feedback_card.js Ver fichero

@@ -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 <strong>Helen</strong> 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);

+ 157
- 5
ts.php Ver fichero

@@ -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{
</span>";
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();

Cargando…
Cancelar
Guardar