Skip to content

Commit b437cbf

Browse files
authored
Merge pull request #2687 from themeum/strict-mode-tooltip
Strict mode completion button tooltip added
2 parents f1b670a + 2d27e9e commit b437cbf

5 files changed

Lines changed: 118 additions & 105 deletions

File tree

assets/core/scss/mixins/_buttons.scss

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,12 +41,12 @@
4141

4242
&:disabled,
4343
&.disabled {
44-
color: $tutor-text-disabled;
44+
color: $tutor-text-subdued;
4545
cursor: not-allowed;
4646
pointer-events: none;
4747

4848
svg:not([class]) {
49-
color: $tutor-icon-disabled;
49+
color: $tutor-icon-subdued;
5050
}
5151
}
5252
}
@@ -103,7 +103,6 @@
103103
&:disabled,
104104
&.disabled {
105105
background-color: $tutor-button-disabled;
106-
color: $tutor-text-brand;
107106
--tutor-button-border-shadow: #{$tutor-button-primary-soft-border-shadow-disabled};
108107
}
109108
} @else if $variant == destructive {
@@ -130,7 +129,6 @@
130129
&:disabled,
131130
&.disabled {
132131
background-color: $tutor-button-disabled;
133-
color: $tutor-text-primary-inverse;
134132
--tutor-button-border-shadow: #{$tutor-button-destructive-border-shadow-disabled};
135133
}
136134
} @else if $variant == destructive-soft {

classes/Course.php

Lines changed: 108 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,14 @@
2222
use Tutor\Models\QuizModel;
2323
use Tutor\Helpers\HttpHelper;
2424
use Tutor\Models\CourseModel;
25+
use Tutor\Components\Tooltip;
2526
use Tutor\Ecommerce\Ecommerce;
2627
use Tutor\Helpers\DateTimeHelper;
2728
use Tutor\Traits\JsonResponse;
2829
use Tutor\Helpers\ValidationHelper;
2930
use Tutor\Models\EnrollmentModel;
3031
use Tutor\Options_V2;
32+
use TUTOR_ASSIGNMENTS\Assignments;
3133

3234
/**
3335
* Course Class
@@ -1833,7 +1835,7 @@ private function save_course_content_order( $sort_order = array() ) {
18331835

18341836
$i = 0;
18351837
foreach ( $sort_order as $topic ) {
1836-
$i++;
1838+
++$i;
18371839
$wpdb->update(
18381840
$wpdb->posts,
18391841
array( 'menu_order' => $i ),
@@ -2879,116 +2881,116 @@ public function remove_price_if_enrolled( $html ) {
28792881
}
28802882

28812883
/**
2882-
* Check if all lessons and quizzes done before mark course complete.
2884+
* Get course completion missing requirements message.
28832885
*
2884-
* @since 1.5.8
2886+
* @since 4.0.0
28852887
*
2886-
* @param string $html HTML string.
2887-
* @return string
2888+
* @param int $course_id Course ID.
2889+
* @param int $user_id User ID.
2890+
*
2891+
* @return string|null
28882892
*/
2889-
public function tutor_lms_hide_course_complete_btn( $html ) {
2893+
public static function get_course_completion_restrict_msg( $course_id = 0, $user_id = 0 ) {
2894+
$course_id = tutor_utils()->get_post_id( $course_id );
2895+
$user_id = tutor_utils()->get_user_id( $user_id );
28902896

2891-
$completion_mode = tutor_utils()->get_option( 'course_completion_process' );
2892-
if ( 'strict' !== $completion_mode ) {
2893-
return $html;
2897+
if ( 'strict' !== tutor_utils()->get_option( 'course_completion_process' ) ) {
2898+
return null;
28942899
}
28952900

2896-
$completed_lesson = tutor_utils()->get_completed_lesson_count_by_course();
2897-
$lesson_count = tutor_utils()->get_lesson_count_by_course();
2901+
$completed_lessons = tutor_utils()->get_completed_lesson_count_by_course( $course_id, $user_id );
2902+
$total_lessons = tutor_utils()->get_lesson_count_by_course( $course_id );
28982903

2899-
if ( $completed_lesson < $lesson_count ) {
2900-
return '<div class="tutor-alert tutor-warning tutor-mt-28">
2901-
<div class="tutor-alert-text">
2902-
<span class="tutor-alert-icon tutor-fs-4 tutor-icon-circle-info tutor-mr-12"></span>
2903-
<span>' . __( 'Complete all lessons to mark this course as complete', 'tutor' ) . '</span>
2904-
</div>
2905-
</div>';
2904+
if ( $completed_lessons < $total_lessons ) {
2905+
return __( 'Complete all lessons to mark this course as complete', 'tutor' );
29062906
}
29072907

2908-
$quizzes = array();
2909-
$assignments = array();
2910-
2911-
$course_contents = tutor_utils()->get_course_contents_by_id();
2912-
if ( tutor_utils()->count( $course_contents ) ) {
2913-
foreach ( $course_contents as $content ) {
2914-
if ( 'tutor_quiz' === $content->post_type ) {
2915-
$quizzes[] = $content;
2916-
}
2917-
if ( 'tutor_assignments' === $content->post_type ) {
2918-
$assignments[] = $content;
2919-
}
2920-
}
2921-
}
2908+
$course_contents = tutor_utils()->get_course_contents_by_id( $course_id );
29222909

2923-
$required_assignment_pass = 0;
2910+
$required_quiz_pass_count = 0;
2911+
$required_assignment_pass_count = 0;
29242912

2925-
foreach ( $assignments as $row ) {
2913+
$is_assignment_addon_enabled = tutor_utils()->is_addon_enabled( 'tutor-assignments' );
29262914

2927-
$assignment_submission = tutor_utils()->is_assignment_submitted( $row->ID );
2928-
$is_reviewed_by_instructor = ! count( $assignment_submission )
2929-
? false
2930-
: get_comment_meta( $assignment_submission[0]->comment_ID, 'evaluate_time', true );
2915+
foreach ( $course_contents as $content ) {
29312916

2932-
if ( $assignment_submission && $is_reviewed_by_instructor ) {
2933-
$pass_mark = tutor_utils()->get_assignment_option( $row->ID, 'pass_mark' );
2934-
$has_passed = false;
2935-
foreach ( $assignment_submission as $submission ) {
2936-
$given_mark = (int) get_comment_meta( $submission->comment_ID, 'assignment_mark', true );
2937-
if ( $given_mark >= $pass_mark ) {
2938-
$has_passed = true;
2939-
break;
2940-
}
2917+
if ( tutor()->quiz_post_type === $content->post_type ) {
2918+
if ( ! QuizModel::is_quiz_passed( $content->ID, $user_id ) ) {
2919+
++$required_quiz_pass_count;
29412920
}
2942-
if ( ! $has_passed ) {
2943-
$required_assignment_pass++;
2921+
}
2922+
2923+
if ( $is_assignment_addon_enabled && tutor()->assignment_post_type === $content->post_type ) {
2924+
if ( ! Assignments::is_assignment_passed( $content->ID, $user_id ) ) {
2925+
++$required_assignment_pass_count;
29442926
}
2945-
} else {
2946-
$required_assignment_pass++;
29472927
}
29482928
}
29492929

2950-
$is_quiz_pass = true;
2951-
$required_quiz_pass = 0;
2930+
if ( ! $required_quiz_pass_count && ! $required_assignment_pass_count ) {
2931+
return null;
2932+
}
29522933

2953-
if ( tutor_utils()->count( $quizzes ) ) {
2954-
foreach ( $quizzes as $quiz ) {
2934+
return self::get_course_completion_requirement_message(
2935+
$required_quiz_pass_count,
2936+
$required_assignment_pass_count
2937+
);
2938+
}
29552939

2956-
$attempt = tutor_utils()->get_quiz_attempt( $quiz->ID );
2957-
if ( $attempt ) {
2958-
$passing_grade = tutor_utils()->get_quiz_option( $quiz->ID, 'passing_grade', 0 );
2959-
$earned_percentage = QuizModel::calculate_attempt_earned_percentage( $attempt );
2940+
/**
2941+
* Build missing course completion requirements message.
2942+
*
2943+
* @since 4.0.0
2944+
*
2945+
* @param int $quiz_count Total quiz count.
2946+
* @param int $assignment_count Total assignment count.
2947+
*
2948+
* @return string
2949+
*/
2950+
private static function get_course_completion_requirement_message( $quiz_count, $assignment_count ) {
2951+
$quiz_label = _n( 'quiz', 'quizzes', $quiz_count, 'tutor' );
2952+
$assignment_label = _n( 'assignment', 'assignments', $assignment_count, 'tutor' );
29602953

2961-
if ( $earned_percentage < $passing_grade ) {
2962-
$required_quiz_pass++;
2963-
$is_quiz_pass = false;
2964-
}
2965-
} else {
2966-
$required_quiz_pass++;
2967-
$is_quiz_pass = false;
2968-
}
2969-
}
2954+
if ( $quiz_count && ! $assignment_count ) {
2955+
return sprintf(
2956+
/* translators: %1$s: quiz count; %2$s: quiz label */
2957+
__( 'You have to pass %1$s %2$s to complete this course.', 'tutor' ),
2958+
$quiz_count,
2959+
$quiz_label
2960+
);
29702961
}
29712962

2972-
if ( ! $is_quiz_pass || $required_assignment_pass > 0 ) {
2973-
$_msg = '';
2974-
$quiz_str = _n( 'quiz', 'quizzes', $required_quiz_pass, 'tutor' );
2975-
$assignment_str = _n( 'assignment', 'assignments', $required_assignment_pass, 'tutor' );
2976-
2977-
if ( ! $is_quiz_pass && 0 == $required_assignment_pass ) {
2978-
/* translators: %1$s: number of quiz/assignment pass required; %2$s: quiz/assignment string */
2979-
$_msg = sprintf( __( 'You have to pass %1$s %2$s to complete this course.', 'tutor' ), $required_quiz_pass, $quiz_str );
2980-
}
2963+
if ( ! $quiz_count && $assignment_count ) {
2964+
return sprintf(
2965+
/* translators: %1$s: assignment count; %2$s: assignment label */
2966+
__( 'You have to pass %1$s %2$s to complete this course.', 'tutor' ),
2967+
$assignment_count,
2968+
$assignment_label
2969+
);
2970+
}
29812971

2982-
if ( $is_quiz_pass && $required_assignment_pass > 0 ) {
2983-
//phpcs:ignore
2984-
$_msg = sprintf( __( 'You have to pass %1$s %2$s to complete this course.', 'tutor' ), $required_assignment_pass, $assignment_str );
2985-
}
2972+
return sprintf(
2973+
/* translators: %1$s: quiz count; %2$s: quiz label; %3$s: assignment count; %4$s: assignment label */
2974+
__( 'You have to pass %1$s %2$s and %3$s %4$s to complete this course.', 'tutor' ),
2975+
$quiz_count,
2976+
$quiz_label,
2977+
$assignment_count,
2978+
$assignment_label
2979+
);
2980+
}
29862981

2987-
if ( ! $is_quiz_pass && $required_assignment_pass > 0 ) {
2988-
/* translators: %1$s: number of quiz pass required; %2$s: quiz string; %3$s: number of assignment pass required; %4$s: assignment string */
2989-
$_msg = sprintf( __( 'You have to pass %1$s %2$s and %3$s %4$s to complete this course.', 'tutor' ), $required_quiz_pass, $quiz_str, $required_assignment_pass, $assignment_str );
2990-
}
2982+
/**
2983+
* Check if all lessons and quizzes done before mark course complete.
2984+
*
2985+
* @since 1.5.8
2986+
*
2987+
* @param string $html HTML string.
2988+
* @return string
2989+
*/
2990+
public function tutor_lms_hide_course_complete_btn( $html ) {
2991+
$_msg = self::get_course_completion_restrict_msg();
29912992

2993+
if ( $_msg ) {
29922994
return '<div class="tutor-alert tutor-warning tutor-mt-28">
29932995
<div class="tutor-alert-text">
29942996
<span class="tutor-alert-icon tutor-fs-4 tutor-icon-circle-info tutor-mr-12"></span>
@@ -3511,17 +3513,24 @@ public static function get_complete_modal_content( float $course_progress = 0 ):
35113513
* @param int $course_id The ID of the course.
35123514
* @param float $course_progress The current completion percentage of the course.
35133515
* @param string $size The button size.
3516+
* @param string $tooltip Optional. Tooltip message.
3517+
* @param bool $block Optional. Whether the button is full-width.
35143518
*
35153519
* @return void
35163520
*/
3517-
public static function render_course_complete_btn( string $modal_id, int $course_id, float $course_progress = 0, string $size = Size::MEDIUM ): void {
3521+
public static function render_course_complete_btn( string $modal_id, int $course_id, float $course_progress = 0, string $size = Size::MEDIUM, string $tooltip = '', bool $block = false ): void {
35183522
$button = Button::make()
35193523
->variant( Variant::PRIMARY_SOFT )
35203524
->label( __( 'Complete the Course', 'tutor' ) )
35213525
->icon( Icon::TICK_MARK )
35223526
->size( $size )
3527+
->block( $block )
35233528
->attr( 'type', 'button' );
35243529

3530+
if ( ! empty( $tooltip ) ) {
3531+
$button->disabled();
3532+
}
3533+
35253534
if ( $course_progress < 100 ) {
35263535
$button->attr( '@click', "TutorCore.modal.showModal('{$modal_id}')" );
35273536
} else {
@@ -3530,7 +3539,16 @@ public static function render_course_complete_btn( string $modal_id, int $course
35303539
$button->attr( ':disabled', 'courseCompleteMutation?.isPending' );
35313540
}
35323541

3533-
$button->render();
3542+
if ( ! empty( $tooltip ) ) {
3543+
Tooltip::make()
3544+
->content( $tooltip )
3545+
->placement( Tooltip::PLACEMENT_BOTTOM )
3546+
->arrow( Tooltip::ARROW_CENTER )
3547+
->trigger_element( $button->get() )
3548+
->render();
3549+
} else {
3550+
$button->render();
3551+
}
35343552
}
35353553

35363554
/**
@@ -3540,15 +3558,17 @@ public static function render_course_complete_btn( string $modal_id, int $course
35403558
*
35413559
* @param string $modal_id Modal id.
35423560
* @param string $size The button size.
3561+
* @param bool $block Optional. Whether the button is full-width.
35433562
*
35443563
* @return void
35453564
*/
3546-
public static function render_course_retake_btn( string $modal_id, string $size = Size::MEDIUM ): void {
3565+
public static function render_course_retake_btn( string $modal_id, string $size = Size::MEDIUM, bool $block = false ): void {
35473566
Button::make()
35483567
->variant( Variant::PRIMARY_SOFT )
35493568
->label( __( 'Retake this Course', 'tutor' ) )
35503569
->icon( Icon::RELOAD_4 )
35513570
->size( $size )
3571+
->block( $block )
35523572
->attr( 'type', 'button' )
35533573
->attr( '@click', "TutorCore.modal.showModal('{$modal_id}')" )
35543574
->render();

components/Tooltip.php

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -261,17 +261,10 @@ public function get(): string {
261261
// Prepare x-data dynamic config.
262262
$x_data = sprintf( 'tutorTooltip(%s)', wp_json_encode( $config ) );
263263

264-
// Wrap the trigger element.
265-
// We use str_replace to inject x-ref="trigger" into the trigger element if possible,
266-
// or we can expect the user to provide it. But to be helpful, let's inject it.
267264
$trigger_html = $this->trigger_element;
268-
if ( ! empty( $trigger_html ) && false === strpos( $trigger_html, 'x-ref="trigger"' ) ) {
269-
// Find the first tag and add x-ref="trigger".
270-
$trigger_html = preg_replace( '/<([a-z0-9]+)/i', '<$1 x-ref="trigger"', $trigger_html, 1 );
271-
}
272265

273266
$this->component_string = sprintf(
274-
'<div x-data="%1$s" class="tutor-tooltip-wrap %2$s" %3$s>
267+
'<div x-data="%1$s" x-ref="trigger" class="tutor-tooltip-wrap %2$s" %3$s>
275268
%4$s
276269
<template x-teleport="body">
277270
<div x-ref="content" x-show="open" x-cloak x-transition class="tutor-tooltip">

templates/learning-area/components/header.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,9 @@
3838

3939
<div class="tutor-flex tutor-gap-2 tutor-items-center tutor-ml-auto tutor-pr-4 tutor-whitespace-nowrap tutor-md-hidden">
4040
<?php
41-
if ( $tutor_can_complete_course ) {
42-
Course::render_course_complete_btn( $course_complete_modal_id, $tutor_course_id, $tutor_course_progress, Size::SMALL );
41+
$incomplete_msg = Course::get_course_completion_restrict_msg( $tutor_course_id, $current_user_id );
42+
if ( $tutor_can_complete_course || $incomplete_msg ) {
43+
Course::render_course_complete_btn( $course_complete_modal_id, $tutor_course_id, $tutor_course_progress, Size::SMALL, $incomplete_msg ?? '' );
4344
}
4445
if ( $tutor_can_retake_course ) {
4546
Course::render_course_retake_btn( $course_retake_modal_id, Size::SMALL );

templates/learning-area/components/sidebar.php

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -257,11 +257,12 @@ class="tutor-learning-pages-item <?php echo esc_attr( $active_class ); ?>"
257257
</div>
258258
<div class="tutor-hidden tutor-md-flex tutor-flex-column tutor-gap-2">
259259
<?php
260-
if ( $tutor_can_complete_course ) {
261-
Course::render_course_complete_btn( $course_complete_modal_id, $tutor_course_id, $tutor_course_progress );
260+
$incomplete_msg = Course::get_course_completion_restrict_msg( $tutor_course_id, $current_user_id );
261+
if ( $tutor_can_complete_course || $incomplete_msg ) {
262+
Course::render_course_complete_btn( $course_complete_modal_id, $tutor_course_id, $tutor_course_progress, Size::MEDIUM, $incomplete_msg ?? '', true );
262263
}
263264
if ( $tutor_can_retake_course ) {
264-
Course::render_course_retake_btn( $course_retake_modal_id );
265+
Course::render_course_retake_btn( $course_retake_modal_id, Size::MEDIUM, true );
265266
}
266267
?>
267268
</div>

0 commit comments

Comments
 (0)