diff --git a/css/qsm-admin.css b/css/qsm-admin.css index 1e1cad638..438614d3d 100644 --- a/css/qsm-admin.css +++ b/css/qsm-admin.css @@ -3436,4 +3436,12 @@ input#preferred-date-format-custom { min-width: 520px; background: #cccccc36; border: 1px solid #ccc; +} + +.qsm-pointer-events-none { + pointer-events: none; +} + +.display-none-notice { + display: none; } \ No newline at end of file diff --git a/js/qsm-admin.js b/js/qsm-admin.js index dc7c58849..109549894 100644 --- a/js/qsm-admin.js +++ b/js/qsm-admin.js @@ -3957,3 +3957,122 @@ var import_button; qsmHandleOperatorChange('email-condition', 'condition-default-value'); }(jQuery)); + + +/** + * QSM - failed submission data table action + */ +(function ($) { + function submit_failed_submission_action_notice( res ) { + if ( 'object' !== typeof res || null === res || undefined === res.message ) { + return false; + } + let noticeEl = $( '#qmn-failed-submission-table-message' ); + if ( 0 < noticeEl.length ) { + let remove_notice_type_class = 'success' === res.status ? 'notice-error' : 'notice-success'; + noticeEl.removeClass( remove_notice_type_class ); + noticeEl.addClass( 'notice-'+res.status ); + noticeEl.html( + '
'+res.message+'
' + ); + noticeEl.show(); + noticeEl.fadeOut( 9999 ); + } + } + + function submit_failed_submission_action_form( formData, ) { + + // check for required data + if ( undefined === formData || null === formData || -1 == formData.quiz_action || 0 === formData.post_ids.length ) { + submit_failed_submission_action_notice( { + status:"error", + message:"Missing form action or data" + } ); + return false; + } + + // quiz action + formData.action = 'qsm_action_failed_submission_table'; + + // Disable conatiner for further any action + let containerDiv = $("#qmn-failed-submission-conatiner"); + containerDiv.toggleClass('qsm-pointer-events-none'); + + // Actiion one by one + formData.post_ids.forEach( post_id => { + formData.post_id = post_id; + let action_link_wrap = $( '#action-link-'+post_id ); + let action_link_html = action_link_wrap.html(); + action_link_wrap.html( 'processing...'); + $.ajax({ + type: 'POST', + url: ajaxurl, + data: formData, + success: function (response) { + // notice. + submit_failed_submission_action_notice( response.data ); + + // enable click pointer + containerDiv.removeClass('qsm-pointer-events-none'); + + // add success icon + if ( response.success ) { + action_link_wrap.html( '' ); + } else { + action_link_wrap.html( action_link_html ); + } + + // Remove row if trashed + if ( 'trash' === formData.quiz_action ) { + $( '#qsm-submission-row-'+post_id ).remove(); + } + + }, + error: function ( jqXHR, textStatus, errorThrown ) { + // undo action link + action_link_wrap.html( action_link_html ); + + // enable click pointer + containerDiv.removeClass('qsm-pointer-events-none'); + + // error notice + submit_failed_submission_action_notice( { + status:"error", + message:errorThrown + } ); + } + }); + }); + + } + + // Submit Form. + $( document ).on( 'submit', '#failed-submission-action-form', function( e ) { + e.preventDefault(); + let formData = { + qmnnonce: $('#failed-submission-action-form input[name="qmnnonce"]').val(), + post_ids: [], + quiz_action: $('#failed-submission-action-form #bulk-action-selector-top').val() + }; + // Select all checkboxes with the name attribute 'post_id[]' + let checkedCheckboxes = $('#failed-submission-action-form input[type="checkbox"][name="post_id[]"]:checked'); + + // Iterate over each checked checkbox + checkedCheckboxes.each(function() { + formData.post_ids.push( $(this).val() ); + }); + + submit_failed_submission_action_form( formData ); + } ); + + // On click retrieve link + $( document ).on( 'click', '.qmn-retrieve-failed-submission-link', function( e ) { + e.preventDefault(); + + submit_failed_submission_action_form( { + qmnnonce: $('#failed-submission-action-form input[name="qmnnonce"]').val(), + post_ids: [ $(this).attr('post-id') ], + quiz_action:'retrieve' + } ); + } ); +}(jQuery)); \ No newline at end of file diff --git a/php/admin/class-failed-submission.php b/php/admin/class-failed-submission.php index 889ee75c0..55bff3dfd 100644 --- a/php/admin/class-failed-submission.php +++ b/php/admin/class-failed-submission.php @@ -22,7 +22,7 @@ class QmnFailedSubmissions extends WP_List_Table { /** - * Holds meta_key name + * meta_key name which contain failed submission data * * @var object * @since 9.0.2 @@ -30,21 +30,56 @@ class QmnFailedSubmissions extends WP_List_Table { public $meta_key = '_qmn_log_result_insert_data'; /** - * Holds table_data + * Variable to check if ip is enable + * + * @var object + * @since 9.0.2 + */ + public $ip_enabled = false; + + /** + * table_data * * @var object * @since 9.0.2 */ private $table_data = array(); + + /** + * Error log post ids + * + * @var object + * @since 9.0.2 + */ + private $posts = array(); + + /** + * Current Tab + * + * @var object + * @since 9.0.2 + */ + private $current_tab = array(); + + public function __construct() { parent::__construct( array( 'plural' => 'submissions', 'singular' => 'submission', - 'ajax' => false, + 'ajax' => true, ) ); + $this->current_tab = ( empty( $_GET['tab'] ) || 'retrieve' == sanitize_key( $_GET['tab'] ) ) ? 'retrieve' : 'processed'; + + // Get settings. + $settings = (array) get_option( 'qmn-settings' ); + + // ip_collection value 1 means it's disabled. + if ( empty( $settings ) || ! isset( $settings['ip_collection'] ) || '1' != $settings['ip_collection'] ) { + $this->ip_enabled = true; + } } /** @@ -52,34 +87,38 @@ public function __construct() { */ public function prepare_items() { // QMN Error log. - $posts = get_posts( + $this->posts = get_posts( array( 'post_type' => 'qmn_log', 'meta_key' => $this->meta_key, - 'post_status' => 'publish', + 'post_status' => 'publish', 'fields' => 'ids', 'posts_per_page' => -1, ) ); - $posts = empty( $posts ) ? array() : $posts; - $per_page = 20; - if ( ! empty( $posts ) ) { + $this->posts = empty( $this->posts ) ? array() : $this->posts; + $per_page = 20; + if ( ! empty( $this->posts ) ) { $current_page = intval( $this->get_pagenum() ) - 1; $post_start_postion = $per_page * $current_page; - foreach ( $posts as $index => $postID ) { + foreach ( $this->posts as $index => $postID ) { + if ( $post_start_postion > $index || $index >= ( $post_start_postion + $per_page ) ) { continue; } + $data = get_post_meta( $postID, $this->meta_key, true ); if ( empty( $data ) ) { continue; } + $data = maybe_unserialize( $data ); - if ( ! is_array( $data ) || ! empty( $data['deleted'] ) || empty( $data['qmn_array_for_variables'] ) ) { + if ( ! is_array( $data ) || ( 'processed' == $this->current_tab && empty( $data['processed'] ) ) || ( 'retrieve' == $this->current_tab && ! empty( $data['processed'] ) ) || empty( $data['qmn_array_for_variables'] ) ) { continue; } + $data['qmn_array_for_variables']['post_id'] = $postID; $this->table_data[] = $data['qmn_array_for_variables']; } @@ -88,7 +127,7 @@ public function prepare_items() { // pagination. $this->set_pagination_args( array( - 'total_items' => count( $posts ), + 'total_items' => count( $this->posts ), 'per_page' => $per_page, ) ); @@ -111,14 +150,59 @@ public function prepare_items() { * @return array */ public function get_columns() { - return array( - 'cb' => '', - 'post_id' => __( 'ID', 'quiz-master-next' ), - 'quiz_name' => __( 'Quiz Name', 'quiz-master-next' ), - 'user_name' => __( 'Name', 'quiz-master-next' ), - 'user_email' => __( 'Email', 'quiz-master-next' ), - 'submission_action' => __( 'Action', 'quiz-master-next' ), + $columns = array( + 'cb' => '', + 'post_id' => __( 'ID', 'quiz-master-next' ), + 'quiz_name' => __( 'Quiz Name', 'quiz-master-next' ), + 'quiz_time' => __( 'Time', 'quiz-master-next' ), + 'user_name' => __( 'Name', 'quiz-master-next' ), + 'user_email' => __( 'Email', 'quiz-master-next' ), ); + + if ( $this->ip_enabled ) { + $columns['user_ip'] = __( 'IP Address', 'quiz-master-next' ); + } + + $columns['submission_action'] = __( 'Action', 'quiz-master-next' ); + + return $columns; + } + + /** + * Gets the list of views available on this table. + * + * @return array + */ + protected function get_views() { + $views = array( + 'retrieve' => array( + 'label' => __( 'Resubmit', 'quiz-master-next' ), + ), + 'processed' => array( + 'label' => __( 'Processed', 'quiz-master-next' ), + ), + ); + + $view_links = array(); + + foreach ( $views as $view_id => $view ) { + $view_links[ $view_id ] = '' . esc_html( $view['label'] ) . ''; + } + + return $view_links; + } + + /** + * Generates content for a single row of the table. + * + * @since 9.0.2 + * + * @param object|array $item The current item + */ + public function single_row( $submission ) { + echo '