diff --git a/assets/css/3rd-party/themes/course/learning-mode.scss b/assets/css/3rd-party/themes/course/learning-mode.scss index 83df2cd656..ce3f563116 100644 --- a/assets/css/3rd-party/themes/course/learning-mode.scss +++ b/assets/css/3rd-party/themes/course/learning-mode.scss @@ -1,3 +1,4 @@ +@import '~@wordpress/base-styles/breakpoints'; @import "questions"; @import "quiz"; @@ -250,19 +251,38 @@ body { } } -// Notice +/* Notices */ .sensei-course-theme-lesson-quiz-notice { font-family: var(--wp--preset--font-family--system); margin: 1.5rem 0; } +.sensei-course-theme-quiz-graded-notice { + &__text { + margin: 0 0 32px; + } + + .wp-block-button__link { + background-color: var(--wp--preset--color--background); + color: var(--wp--preset--color--primary); + } + + &__pending-grade:hover { + border-color: var(--wp--preset--color--background); + cursor: default; + } + + @media (min-width: $break-medium) { + border-radius: 4px; + } +} + /* Modern Template */ .sensei-modern .sensei-course-theme__sidebar:not(.sensei-course-theme__secondary-sidebar) { border: 1px solid var(--sensei-text-color); border-radius: 4px; } - .learning-mode-full-width .wp-block-sensei-lms-course-theme-course-progress-counter { opacity: 1; } diff --git a/assets/css/learning-mode-compat.scss b/assets/css/learning-mode-compat.scss index c06b4b7c77..57b620cb12 100644 --- a/assets/css/learning-mode-compat.scss +++ b/assets/css/learning-mode-compat.scss @@ -177,12 +177,14 @@ $breakpoint: 782px; &.is-link, &.wp-block-button > .wp-block-button__link { border-radius: 2px; + box-sizing: border-box; + display: inline-block; font-weight: 400; + height: 100%; + justify-content: center; padding: 0.83em 1.11em; text-decoration: none; - height: 100%; width: 100%; // Fix the animation issue. - justify-content: center; @media screen and (max-width: $breakpoint) { padding: 0.83em 0.556em; @@ -208,7 +210,7 @@ $breakpoint: 782px; background-color: var(--sensei-secondary-color); color: var(--sensei-button-text-color); - &:hover { + &:not(.sensei-course-theme-quiz-graded-notice__pending-grade):hover { color: var(--sensei-button-fill-hover-color); background-color: var(--sensei-primary-color); border-color: var(--sensei-primary-color); @@ -294,3 +296,17 @@ $breakpoint: 782px; } } } + +/* Quiz Notice */ +.sensei-course-theme-quiz-graded-notice { + &__title { + font-size: 24px; + font-weight: 700; + line-height: normal; + } + + &__text { + font-size: 18px; + line-height: normal; + } +} diff --git a/assets/css/notices.scss b/assets/css/notices.scss index e668ba059c..1a91378e74 100644 --- a/assets/css/notices.scss +++ b/assets/css/notices.scss @@ -1,6 +1,5 @@ .sensei-lms-notice { background-color: #F6F7F7; - border: solid 1px #DCDCDE; margin-bottom: 21px; padding: 17px 26px; color: #1E1E1E; diff --git a/assets/css/sensei-course-theme/blocks/contact-teacher.scss b/assets/css/sensei-course-theme/blocks/contact-teacher.scss index ba44980728..79dced0706 100644 --- a/assets/css/sensei-course-theme/blocks/contact-teacher.scss +++ b/assets/css/sensei-course-theme/blocks/contact-teacher.scss @@ -68,10 +68,6 @@ } } -.sensei-contact-teacher-wrapper { - display: flex; -} - .sensei-contact-teacher-form { textarea { font-family: inherit; diff --git a/assets/css/sensei-course-theme/buttons.scss b/assets/css/sensei-course-theme/buttons.scss index e6e793287c..4cfba4161e 100644 --- a/assets/css/sensei-course-theme/buttons.scss +++ b/assets/css/sensei-course-theme/buttons.scss @@ -6,7 +6,6 @@ $breakpoint: 782px; gap: 12px; } - .sensei-course-theme__button, .sensei-course-theme__link, .sensei-course-theme .wp-block-button.is-style-outline > .wp-block-button__link { @@ -14,7 +13,7 @@ $breakpoint: 782px; height: 100%; justify-content: center; white-space: nowrap; - width: 100%; + width: auto; padding: 1rem 32px; line-height: 100%; diff --git a/assets/css/sensei-course-theme/notices.scss b/assets/css/sensei-course-theme/notices.scss index b5936fea24..c3caeec5b4 100644 --- a/assets/css/sensei-course-theme/notices.scss +++ b/assets/css/sensei-course-theme/notices.scss @@ -1,8 +1,5 @@ +@import '~@wordpress/base-styles/breakpoints'; @import '../notices'; -@import './quiz-graded'; - - -$mobile_break_point: 782px; body.sensei-course-theme { & > .sensei-message { @@ -10,13 +7,18 @@ body.sensei-course-theme { } } +/* All notices */ .sensei-course-theme .sensei-lms-notice { - background-color: rgba(125, 125, 125, 0.08); - border-color: var(--border-color); - color: inherit; - padding: 1.125rem 1.5rem; + background-color: var(--wp--preset--color--foreground, #f6f7f7); + color: var(--wp--preset--color--background, #1e1e1e); + padding: 24px; + + @media (min-width: $break-medium) { + padding-bottom: 24px; + } } +/* Quiz notice on lesson page */ .sensei-course-theme-lesson-quiz-notice { display: flex; flex-flow: wrap; @@ -54,8 +56,13 @@ body.sensei-course-theme { } &__action { - display: flex; align-items: center; + color: inherit; + display: flex; + + &:active { + background-color: inherit; + } } &__link-chevron { @@ -63,8 +70,7 @@ body.sensei-course-theme { height: 24px; } - @media screen and (max-width: ($mobile_break_point)) { - + @media screen and (max-width: $break-medium) { flex-wrap: nowrap; gap: 0; @@ -75,6 +81,67 @@ body.sensei-course-theme { } } +/* Quiz notice on quiz page */ +.sensei-course-theme-quiz-graded-notice { + /* --content-padding comes from mobile.scss */ + margin-left: calc(var(--content-padding) * -1); + margin-right: calc(var(--content-padding) * -1); + padding-bottom: 36px; + + @media (min-width: $break-medium) { + margin-left: 0; + margin-right: 0; + } + + &__title { + margin: 0 0 10px 0; + } + + &__text { + margin: 0 0 20px; + } + + &__actions { + align-items: center; + display: flex; + flex-direction: column; + gap: 16px; + + .wp-block-button__link { + display: inline-block; + } + + @media (min-width: $break-medium) { + flex-direction: row; + } + } + + &__pending-grade { + opacity: 0.6; + + .wp-block-button__link:hover { + cursor: default; + } + } + + &__reset-quiz-form { + margin-bottom: 0; + + .sensei-course-theme__button { + background-color: transparent; + border: none; + color: inherit; + font-family: var(--wp--preset--font-family--body-font); + font-size: 18px; + } + + @media (min-width: $break-medium) { + margin-left: auto; + } + } +} + +/* Locked lesson notice */ .sensei-course-theme-locked-lesson-notice { &__header { display: flex; diff --git a/assets/css/sensei-course-theme/quiz-graded.scss b/assets/css/sensei-course-theme/quiz-graded.scss deleted file mode 100644 index c940e7da9a..0000000000 --- a/assets/css/sensei-course-theme/quiz-graded.scss +++ /dev/null @@ -1,28 +0,0 @@ -.sensei-course-theme-quiz-graded-notice { - padding-bottom: 36px; - - &__title { - font-size: 30px; - font-weight: 700; - line-height: 1.2; - margin: 12px 0; - } - - &__text { - font-size: 16px; - line-height: 1.75; - margin: 24px 0; - } - - &__actions { - display: flex; - flex-direction: row; - justify-content: flex-start; - align-items: center; - gap: 24px; - } - - &__reset-quiz-form { - margin-bottom: 0; - } -} diff --git a/assets/css/sensei-course-theme/quiz.scss b/assets/css/sensei-course-theme/quiz.scss index 0e6d8a97ca..311927526a 100644 --- a/assets/css/sensei-course-theme/quiz.scss +++ b/assets/css/sensei-course-theme/quiz.scss @@ -202,16 +202,11 @@ $vertical-spacing-desktop: 80px; } .wp-block-sensei-lms-quiz-actions { - & > div:first-child.sensei-quiz-actions-secondary { flex-grow: 1; justify-content: end; } - .sensei-course-theme__button.is-primary { - width: auto; - } - button:disabled { cursor: not-allowed; pointer-events: none; diff --git a/changelog/update-awaiting-grade-notice b/changelog/update-awaiting-grade-notice new file mode 100644 index 0000000000..8c69f240db --- /dev/null +++ b/changelog/update-awaiting-grade-notice @@ -0,0 +1,4 @@ +Significance: minor +Type: changed + +Update style of "Awaiting Grade" notice in Learning Mode diff --git a/changelog/update-graded-notice b/changelog/update-graded-notice new file mode 100644 index 0000000000..94a7d70ff3 --- /dev/null +++ b/changelog/update-graded-notice @@ -0,0 +1,4 @@ +Significance: minor +Type: changed + +Update style of "Your Grade" notice in Learning Mode diff --git a/includes/class-sensei-quiz.php b/includes/class-sensei-quiz.php index bf5201c00e..0809f1d092 100755 --- a/includes/class-sensei-quiz.php +++ b/includes/class-sensei-quiz.php @@ -2502,7 +2502,7 @@ private static function maybe_get_button_html_for_quiz_footer( $lesson_id = null } $block = new Sensei_Block_Contact_Teacher(); - $button = self::get_primary_button_anchor_html( __( 'Contact teacher', 'sensei-lms' ), '#' ); + $button = self::get_primary_button_html( __( 'Contact teacher', 'sensei-lms' ), '#' ); return $block->render_contact_teacher_block( [], $button ); } @@ -2510,7 +2510,7 @@ private static function maybe_get_button_html_for_quiz_footer( $lesson_id = null $next_lesson_url = $prev_next_urls['next']['url'] ?? null; if ( $next_lesson_url ) { - return self::get_primary_button_anchor_html( __( 'Continue to next lesson', 'sensei-lms' ), $next_lesson_url ); + return self::get_primary_button_html( __( 'Continue to next lesson', 'sensei-lms' ), $next_lesson_url ); } return null; @@ -2519,17 +2519,36 @@ private static function maybe_get_button_html_for_quiz_footer( $lesson_id = null /** * Returns the HTML for a primary button anchor. * - * @param string $button_text The button text. - * @param string $url The URL. + * @param string $button_text The button text. + * @param string|null $url The URL. + * @param array $classes CSS classes to add to the button. * * @return string The HTML for the primary button anchor. */ - private static function get_primary_button_anchor_html( $button_text, $url ) { - return '' . - esc_html( $button_text ) . - ''; - } + public static function get_primary_button_html( $button_text, $url = null, $classes = [] ) { + $href = ''; + $classes = array_merge( + array( + 'wp-block-button__link', + 'wp-element-button', + 'sensei-course-theme__button', + 'is-primary', + ), + $classes + ); + if ( $url ) { + $href = ' href="' . esc_url( $url ) . '"'; + } + + return ( + '
+ ' . + esc_html( $button_text ) . + ' +
' + ); + } } /** diff --git a/includes/course-theme/class-sensei-course-theme-quiz.php b/includes/course-theme/class-sensei-course-theme-quiz.php index 5c9dfa785c..55c8cf4c4c 100644 --- a/includes/course-theme/class-sensei-course-theme-quiz.php +++ b/includes/course-theme/class-sensei-course-theme-quiz.php @@ -6,6 +6,8 @@ * @since 3.15.0 */ +use Sensei\Internal\Emails\Email_Repository; + if ( ! defined( 'ABSPATH' ) ) { exit; } @@ -57,6 +59,7 @@ public function init() { * @access private */ private function maybe_add_quiz_results_notice() { + $actions = []; $lesson_id = Sensei_Utils::get_current_lesson(); $quiz_id = Sensei()->lesson->lesson_quizzes( $lesson_id ); $user_id = get_current_user_id(); @@ -75,6 +78,7 @@ private function maybe_add_quiz_results_notice() { // Prepare title. $grade = Sensei_Quiz::get_user_quiz_grade( $lesson_id, $user_id ); $grade_rounded = Sensei_Utils::round( $grade, 2 ); + $reset_allowed = Sensei_Quiz::is_reset_allowed( $lesson_id ); $title = sprintf( // translators: The placeholder is the quiz grade. __( 'Your Grade: %1$s%%', 'sensei-lms' ), @@ -86,8 +90,34 @@ private function maybe_add_quiz_results_notice() { // Prepare message. $text = __( "You've passed the quiz and can continue to the next lesson.", 'sensei-lms' ); + if ( 'ungraded' === $quiz_progress->get_status() ) { - $text = __( 'Your answers have been submitted and your teacher will grade this quiz shortly.', 'sensei-lms' ); + $email_enabled = false; + $text = __( 'Your answers have been submitted and the quiz will be graded soon.', 'sensei-lms' ); + $actions[] = Sensei_Quiz::get_primary_button_html( + __( 'Pending teacher grade', 'sensei-lms' ), + null, + [ 'sensei-course-theme-quiz-graded-notice__pending-grade' ] + ); + + // New quiz graded email. + if ( Sensei()->feature_flags->is_enabled( 'email_customization' ) ) { + $repository = new Email_Repository(); + $quiz_graded_email = $repository->get( 'quiz_graded' ); + + if ( $quiz_graded_email && 'publish' === $quiz_graded_email->post_status ) { + $email_enabled = true; + } + } else { // Old quiz graded email. + if ( isset( Sensei()->settings->settings['email_learners'] ) && + in_array( 'learner-graded-quiz', (array) Sensei()->settings->settings['email_learners'], true ) ) { + $email_enabled = true; + } + } + + if ( $email_enabled ) { + $text .= __( ' You\'ll receive an email once it\'s ready to view.', 'sensei-lms' ); + } } elseif ( 'failed' === $quiz_progress->get_status() ) { $passmark = get_post_meta( $quiz_id, '_quiz_passmark', true ); $passmark_rounded = Sensei_Utils::round( $passmark, 2 ); @@ -97,19 +127,27 @@ private function maybe_add_quiz_results_notice() { $passmark_rounded, $grade_rounded ); + + // Display Contact Teacher button. + if ( ! $reset_allowed ) { + $block = new Sensei_Block_Contact_Teacher(); + $button = Sensei_Quiz::get_primary_button_html( __( 'Contact teacher', 'sensei-lms' ) ); + $actions[] = $block->render_contact_teacher_block( [], $button ); + } } - $actions = []; + // "Continue to next lesson" button. + if ( in_array( $quiz_progress->get_status(), [ 'complete', 'graded', 'passed' ], true ) ) { + $prev_next_urls = sensei_get_prev_next_lessons( $lesson_id ); + $next_lesson_url = $prev_next_urls['next']['url'] ?? null; + $actions[] = Sensei_Quiz::get_primary_button_html( __( 'Continue to next lesson', 'sensei-lms' ), $next_lesson_url ); + } - // Prepare reset quiz button. - $reset_allowed = Sensei_Quiz::is_reset_allowed( $lesson_id ); + // "Restart Quiz" button. if ( $reset_allowed ) { $actions[] = self::render_reset_quiz(); } - // Prepare contact teacher button. - $actions[] = self::render_contact_teacher(); - $notices = \Sensei_Context_Notices::instance( 'course_theme_quiz_grade' ); $notices->add_notice( 'course-theme-quiz-grade', $text, $title, $actions ); } @@ -132,14 +170,4 @@ private static function render_reset_quiz() { " ); } - - /** - * Renders the contact teacher button. - */ - private static function render_contact_teacher() { - $link = '' . __( 'Contact teacher', 'sensei-lms' ) . ''; - $block = new Sensei_Block_Contact_Teacher(); - return $block->render_contact_teacher_block( null, $link ); - } - } diff --git a/includes/course-theme/class-sensei-course-theme.php b/includes/course-theme/class-sensei-course-theme.php index 998b4ec86e..314e126333 100644 --- a/includes/course-theme/class-sensei-course-theme.php +++ b/includes/course-theme/class-sensei-course-theme.php @@ -165,7 +165,7 @@ public function load_theme() { add_filter( 'sensei_use_sensei_template', '__return_false' ); add_filter( 'body_class', [ $this, 'add_sensei_theme_body_class' ] ); - add_action( 'wp_enqueue_scripts', [ $this, 'enqueue_styles' ] ); + add_action( 'wp_enqueue_scripts', [ $this, 'enqueue_styles' ], 9 ); add_action( 'template_redirect', [ $this, 'admin_menu_init' ], 20 ); add_action( 'admin_init', [ $this, 'admin_menu_init' ], 20 ); diff --git a/templates/course-theme/quiz-grade-notice.php b/templates/course-theme/quiz-grade-notice.php index 4f0ce5705a..4974f03cf5 100644 --- a/templates/course-theme/quiz-grade-notice.php +++ b/templates/course-theme/quiz-grade-notice.php @@ -16,13 +16,13 @@ /** * Notices map to echo notices HTML. * - * @param array $notice + * @param array $notice Quiz grade notice. */ function sensei_quiz_grade_notices_map( $notice ) { ?>
-
+

diff --git a/tests/unit-tests/test-class-quiz.php b/tests/unit-tests/test-class-quiz.php index 9f96c7581b..1d9758e24a 100644 --- a/tests/unit-tests/test-class-quiz.php +++ b/tests/unit-tests/test-class-quiz.php @@ -2472,4 +2472,42 @@ public function testActionButtons_WhenQuizPassedButOnLessonPage_DoesNotShowTheNe /* Assert */ $this->assertStringNotContainsString( 'Continue to next lesson', $result ); } + + public function testGetPrimaryButtonHTML_DefaultParams_ContainsCorrectText() { + /* Arrange */ + $text = 'Click Me!'; + + /* Act */ + $html = Sensei()->quiz->get_primary_button_html( $text ); + + /* Assert */ + $this->assertStringContainsString( $text, $html ); + } + + public function testGetPrimaryButtonHTML_SomeParams_ContainsCorrectURL() { + /* Arrange */ + $url = 'https://example.com'; + + /* Act */ + $html = Sensei()->quiz->get_primary_button_html( 'Click Me', $url ); + + /* Assert */ + $this->assertStringContainsString( $url, $html ); + } + + public function testGetPrimaryButtonHTML_AllParams_ContainsCorrectClasses() { + /* Arrange */ + $classes = array( + 'abc', + 'def', + ); + + /* Act */ + $html = Sensei()->quiz->get_primary_button_html( 'Click Me', '', $classes ); + + /* Assert */ + foreach ( $classes as $class ) { + $this->assertStringContainsString( $class, $html ); + } + } }